~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/gfx/src/nsRegion.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * The contents of this file are subject to the Mozilla Public
 
3
 * License Version 1.1 (the "License"); you may not use this file
 
4
 * except in compliance with the License. You may obtain a copy of
 
5
 * the License at http://www.mozilla.org/MPL/
 
6
 *
 
7
 * Software distributed under the License is distributed on an "AS
 
8
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 
9
 * implied. See the License for the specific language governing
 
10
 * rights and limitations under the License.
 
11
 *
 
12
 * The Original Code is mozilla.org code.
 
13
 *
 
14
 * The Initial Developer of the Original Code is Dainis Jonitis,
 
15
 * <Dainis_Jonitis@swh-t.lv>.  Portions created by Dainis Jonitis are
 
16
 * Copyright (C) 2001 Dainis Jonitis. All Rights Reserved.
 
17
 *
 
18
 * Contributor(s):
 
19
 */
 
20
 
 
21
#include "prlock.h"
 
22
#include "nsRegion.h"
 
23
#include "nsISupportsImpl.h"
 
24
 
 
25
 
 
26
#define MIN_INT32 (-PR_INT32 (0x7FFFFFFF) - 1)
 
27
#define MAX_INT32 (PR_INT32 (0x7FFFFFFF))
 
28
 
 
29
 
 
30
// Fast inline analogues of nsRect methods for nsRegion::nsRectFast.
 
31
// Check for emptiness is not required - it is guaranteed by caller.
 
32
 
 
33
inline PRBool nsRegion::nsRectFast::Contains (const nsRect& aRect) const
 
34
{
 
35
  return (PRBool) ((aRect.x >= x) && (aRect.y >= y) &&
 
36
                   (aRect.XMost () <= XMost ()) && (aRect.YMost () <= YMost ()));
 
37
}
 
38
 
 
39
inline PRBool nsRegion::nsRectFast::Intersects (const nsRect& aRect) const
 
40
{
 
41
  return (PRBool) ((x < aRect.XMost ()) && (y < aRect.YMost ()) &&
 
42
                   (aRect.x < XMost ()) && (aRect.y < YMost ()));
 
43
}
 
44
 
 
45
inline PRBool nsRegion::nsRectFast::IntersectRect (const nsRect& aRect1, const nsRect& aRect2)
 
46
{
 
47
  const nscoord xmost = PR_MIN (aRect1.XMost (), aRect2.XMost ());
 
48
  x = PR_MAX (aRect1.x, aRect2.x);
 
49
  width = xmost - x;
 
50
  if (width <= 0) return PR_FALSE;
 
51
 
 
52
  const nscoord ymost = PR_MIN (aRect1.YMost (), aRect2.YMost ());
 
53
  y = PR_MAX (aRect1.y, aRect2.y);
 
54
  height = ymost - y;
 
55
  if (height <= 0) return PR_FALSE;
 
56
 
 
57
  return PR_TRUE;
 
58
}
 
59
 
 
60
inline void nsRegion::nsRectFast::UnionRect (const nsRect& aRect1, const nsRect& aRect2)
 
61
{
 
62
  const nscoord xmost = PR_MAX (aRect1.XMost (), aRect2.XMost ());
 
63
  const nscoord ymost = PR_MAX (aRect1.YMost (), aRect2.YMost ());
 
64
  x = PR_MIN (aRect1.x, aRect2.x);
 
65
  y = PR_MIN (aRect1.y, aRect2.y);
 
66
  width  = xmost - x;
 
67
  height = ymost - y;
 
68
}
 
69
 
 
70
 
 
71
 
 
72
// Custom memory allocator for nsRegion::RgnRect structures.
 
73
// Entries are allocated from global memory pool.
 
74
// Memory pool can grow in size, but it can't shrink.
 
75
 
 
76
#define INIT_MEM_CHUNK_ENTRIES 100
 
77
#define INCR_MEM_CHUNK_ENTRIES 100
 
78
 
 
79
class RgnRectMemoryAllocator
 
80
{
 
81
  nsRegion::RgnRect*  mFreeListHead;
 
82
  PRUint32  mFreeEntries;
 
83
  void*     mChunkListHead;
 
84
#if 0
 
85
  PRLock*   mLock;
 
86
 
 
87
  void InitLock ()    { mLock = PR_NewLock (); }
 
88
  void DestroyLock () { PR_DestroyLock (mLock); }
 
89
  void Lock ()        { PR_Lock   (mLock); }
 
90
  void Unlock ()      { PR_Unlock (mLock); }
 
91
#elif defined (DEBUG)
 
92
  NS_DECL_OWNINGTHREAD
 
93
 
 
94
  void InitLock ()    { NS_ASSERT_OWNINGTHREAD (RgnRectMemoryAllocator); }
 
95
  void DestroyLock () { NS_ASSERT_OWNINGTHREAD (RgnRectMemoryAllocator); }
 
96
  void Lock ()        { NS_ASSERT_OWNINGTHREAD (RgnRectMemoryAllocator); }
 
97
  void Unlock ()      { NS_ASSERT_OWNINGTHREAD (RgnRectMemoryAllocator); }
 
98
#else
 
99
  void InitLock ()    { }
 
100
  void DestroyLock () { }
 
101
  void Lock ()        { }
 
102
  void Unlock ()      { }
 
103
#endif
 
104
 
 
105
  void* AllocChunk (PRUint32 aEntries, void* aNextChunk, nsRegion::RgnRect* aTailDest)
 
106
  {
 
107
    PRUint8* pBuf = new PRUint8 [aEntries * sizeof (nsRegion::RgnRect) + sizeof (void*)];
 
108
    *NS_REINTERPRET_CAST (void**, pBuf) = aNextChunk;
 
109
    nsRegion::RgnRect* pRect = NS_REINTERPRET_CAST (nsRegion::RgnRect*, pBuf + sizeof (void*));
 
110
 
 
111
    for (PRUint32 cnt = 0 ; cnt < aEntries - 1 ; cnt++)
 
112
      pRect [cnt].next = &pRect [cnt + 1];
 
113
 
 
114
    pRect [aEntries - 1].next = aTailDest;
 
115
 
 
116
    return pBuf;
 
117
  }
 
118
 
 
119
  void FreeChunk (void* aChunk) {  delete [] (PRUint8 *) aChunk;  }
 
120
  void* NextChunk (void* aThisChunk) const { return *NS_STATIC_CAST (void**, aThisChunk); }
 
121
 
 
122
  nsRegion::RgnRect* ChunkHead (void* aThisChunk) const
 
123
  {   return NS_REINTERPRET_CAST (nsRegion::RgnRect*, NS_STATIC_CAST (PRUint8*, aThisChunk) + sizeof (void*));  }
 
124
 
 
125
public:
 
126
  RgnRectMemoryAllocator (PRUint32 aNumOfEntries);
 
127
 ~RgnRectMemoryAllocator ();
 
128
 
 
129
  nsRegion::RgnRect* Alloc ();
 
130
  void Free (nsRegion::RgnRect* aRect);
 
131
};
 
132
 
 
133
 
 
134
RgnRectMemoryAllocator::RgnRectMemoryAllocator (PRUint32 aNumOfEntries)
 
135
{
 
136
  InitLock ();
 
137
  mChunkListHead = AllocChunk (aNumOfEntries, nsnull, nsnull);
 
138
  mFreeEntries   = aNumOfEntries;
 
139
  mFreeListHead  = ChunkHead (mChunkListHead);
 
140
}
 
141
 
 
142
RgnRectMemoryAllocator::~RgnRectMemoryAllocator ()
 
143
{
 
144
  while (mChunkListHead)
 
145
  {
 
146
    void* tmp = mChunkListHead;
 
147
    mChunkListHead = NextChunk (mChunkListHead);
 
148
    FreeChunk (tmp);
 
149
  }
 
150
 
 
151
#if 0
 
152
  /*
 
153
   * As a static object this class outlives any library which would implement
 
154
   * locking. So we intentionally leak the 'lock'.
 
155
   *
 
156
   * Currently RgnRectMemoryAllocator is only used from the primary thread,
 
157
   * so we aren't using a lock which means that there is no lock to leak.
 
158
   * If we ever switch to multiple GUI threads (e.g. one per window),
 
159
   * we'd probably use one allocator per window-thread to avoid the
 
160
   * locking overhead and just require consumers not to pass regions
 
161
   * across threads/windows, which would be a reasonable restriction
 
162
   * because they wouldn't be useful outside their window.
 
163
   */
 
164
  DestroyLock ();
 
165
#endif
 
166
}
 
167
 
 
168
nsRegion::RgnRect* RgnRectMemoryAllocator::Alloc ()
 
169
{
 
170
  Lock ();
 
171
 
 
172
  if (mFreeEntries == 0)
 
173
  {
 
174
    mChunkListHead = AllocChunk (INCR_MEM_CHUNK_ENTRIES, mChunkListHead, mFreeListHead);
 
175
    mFreeEntries   = INCR_MEM_CHUNK_ENTRIES;
 
176
    mFreeListHead  = ChunkHead (mChunkListHead);
 
177
  }
 
178
 
 
179
  nsRegion::RgnRect* tmp = mFreeListHead;
 
180
  mFreeListHead = mFreeListHead->next;
 
181
  mFreeEntries--;
 
182
  Unlock ();
 
183
 
 
184
  return tmp;
 
185
}
 
186
 
 
187
void RgnRectMemoryAllocator::Free (nsRegion::RgnRect* aRect)
 
188
{
 
189
  Lock ();
 
190
  mFreeEntries++;
 
191
  aRect->next = mFreeListHead;
 
192
  mFreeListHead = aRect;
 
193
  Unlock ();
 
194
}
 
195
 
 
196
 
 
197
// Global pool for nsRegion::RgnRect allocation
 
198
static RgnRectMemoryAllocator gRectPool (INIT_MEM_CHUNK_ENTRIES);
 
199
 
 
200
 
 
201
inline void* nsRegion::RgnRect::operator new (size_t) CPP_THROW_NEW
 
202
{
 
203
  return gRectPool.Alloc ();
 
204
}
 
205
 
 
206
inline void nsRegion::RgnRect::operator delete (void* aRect, size_t)
 
207
{
 
208
  gRectPool.Free (NS_STATIC_CAST (RgnRect*, aRect));
 
209
}
 
210
 
 
211
 
 
212
 
 
213
void nsRegion::Init()
 
214
{
 
215
  mRectListHead.prev = mRectListHead.next = &mRectListHead;
 
216
  mCurRect = &mRectListHead;
 
217
  mRectCount = 0;
 
218
  mBoundRect.SetRect (0, 0, 0, 0);
 
219
}
 
220
 
 
221
inline void nsRegion::InsertBefore (RgnRect* aNewRect, RgnRect* aRelativeRect)
 
222
{
 
223
  aNewRect->prev = aRelativeRect->prev;
 
224
  aNewRect->next = aRelativeRect;
 
225
  aRelativeRect->prev->next = aNewRect;
 
226
  aRelativeRect->prev = aNewRect;
 
227
  mCurRect = aNewRect;
 
228
  mRectCount++;
 
229
}
 
230
 
 
231
inline void nsRegion::InsertAfter (RgnRect* aNewRect, RgnRect* aRelativeRect)
 
232
{
 
233
  aNewRect->prev = aRelativeRect;
 
234
  aNewRect->next = aRelativeRect->next;
 
235
  aRelativeRect->next->prev = aNewRect;
 
236
  aRelativeRect->next = aNewRect;
 
237
  mCurRect = aNewRect;
 
238
  mRectCount++;
 
239
}
 
240
 
 
241
 
 
242
// Adjust the number of rectangles in region.
 
243
// Content of rectangles should be changed by caller.
 
244
 
 
245
void nsRegion::SetToElements (PRUint32 aCount)
 
246
{
 
247
  if (mRectCount < aCount)        // Add missing rectangles
 
248
  {
 
249
    PRUint32 InsertCount = aCount - mRectCount;
 
250
    mRectCount = aCount;
 
251
    RgnRect* pPrev = &mRectListHead;
 
252
    RgnRect* pNext = mRectListHead.next;
 
253
 
 
254
    while (InsertCount--)
 
255
    {
 
256
      mCurRect = new RgnRect;
 
257
      mCurRect->prev = pPrev;
 
258
      pPrev->next = mCurRect;
 
259
      pPrev = mCurRect;
 
260
    }
 
261
 
 
262
    pPrev->next = pNext;
 
263
    pNext->prev = pPrev;
 
264
  } else
 
265
  if (mRectCount > aCount)        // Remove unnecessary rectangles
 
266
  {
 
267
    PRUint32 RemoveCount = mRectCount - aCount;
 
268
    mRectCount = aCount;
 
269
    mCurRect = mRectListHead.next;
 
270
 
 
271
    while (RemoveCount--)
 
272
    {
 
273
      RgnRect* tmp = mCurRect;
 
274
      mCurRect = mCurRect->next;
 
275
      delete tmp;
 
276
    }
 
277
 
 
278
    mRectListHead.next = mCurRect;
 
279
    mCurRect->prev = &mRectListHead;
 
280
  }
 
281
}
 
282
 
 
283
 
 
284
// Save the entire chain of linked elements in 'prev' field of the RgnRect structure.
 
285
// After that forward-only iterations using 'next' field could still be used.
 
286
// Some elements from forward-only chain could be temporarily removed to optimize inner loops.
 
287
// The original double linked state could be restored by call to RestoreLinkChain ().
 
288
// Both functions despite size can be inline because they are called only from one function.
 
289
 
 
290
inline void nsRegion::SaveLinkChain ()
 
291
{
 
292
  RgnRect* pRect = &mRectListHead;
 
293
 
 
294
  do
 
295
  {
 
296
    pRect->prev = pRect->next;
 
297
    pRect = pRect->next;
 
298
  } while (pRect != &mRectListHead);
 
299
}
 
300
 
 
301
 
 
302
inline void nsRegion::RestoreLinkChain ()
 
303
{
 
304
  RgnRect* pPrev = &mRectListHead;
 
305
  RgnRect* pRect = mRectListHead.next = mRectListHead.prev;
 
306
 
 
307
  while (pRect != &mRectListHead)
 
308
  {
 
309
    pRect->next = pRect->prev;
 
310
    pRect->prev = pPrev;
 
311
    pPrev = pRect;
 
312
    pRect = pRect->next;
 
313
  }
 
314
 
 
315
  mRectListHead.prev = pPrev;
 
316
}
 
317
 
 
318
 
 
319
// Insert node in right place of sorted list
 
320
// If necessary then bounding rectangle could be updated and rectangle combined
 
321
// with neighbour rectangles. This is usually done in Optimize ()
 
322
 
 
323
void nsRegion::InsertInPlace (RgnRect* aRect, PRBool aOptimizeOnFly)
 
324
{
 
325
  if (mRectCount == 0)
 
326
    InsertAfter (aRect, &mRectListHead);
 
327
  else
 
328
  {
 
329
    if (aRect->y > mCurRect->y)
 
330
    {
 
331
      mRectListHead.y = MAX_INT32;
 
332
 
 
333
      while (aRect->y > mCurRect->next->y)
 
334
        mCurRect = mCurRect->next;
 
335
 
 
336
      while (aRect->y == mCurRect->next->y && aRect->x > mCurRect->next->x)
 
337
        mCurRect = mCurRect->next;
 
338
 
 
339
      InsertAfter (aRect, mCurRect);
 
340
    } else
 
341
    if (aRect->y < mCurRect->y)
 
342
    {
 
343
      mRectListHead.y = MIN_INT32;
 
344
 
 
345
      while (aRect->y < mCurRect->prev->y)
 
346
        mCurRect = mCurRect->prev;
 
347
 
 
348
      while (aRect->y == mCurRect->prev->y && aRect->x < mCurRect->prev->x)
 
349
        mCurRect = mCurRect->prev;
 
350
 
 
351
      InsertBefore (aRect, mCurRect);
 
352
    } else
 
353
    {
 
354
      if (aRect->x > mCurRect->x)
 
355
      {
 
356
        mRectListHead.y = MAX_INT32;
 
357
 
 
358
        while (aRect->y == mCurRect->next->y && aRect->x > mCurRect->next->x)
 
359
          mCurRect = mCurRect->next;
 
360
 
 
361
        InsertAfter (aRect, mCurRect);
 
362
      } else
 
363
      {
 
364
        mRectListHead.y = MIN_INT32;
 
365
 
 
366
        while (aRect->y == mCurRect->prev->y && aRect->x < mCurRect->prev->x)
 
367
          mCurRect = mCurRect->prev;
 
368
 
 
369
        InsertBefore (aRect, mCurRect);
 
370
      }
 
371
    }
 
372
  }
 
373
 
 
374
 
 
375
  if (aOptimizeOnFly)
 
376
  {
 
377
    if (mRectCount == 1)
 
378
      mBoundRect = *mCurRect;
 
379
    else
 
380
    {
 
381
      mBoundRect.UnionRect (mBoundRect, *mCurRect);
 
382
 
 
383
      // Check if we can go left or up before starting to combine rectangles
 
384
      if ((mCurRect->y == mCurRect->prev->y && mCurRect->height == mCurRect->prev->height &&
 
385
           mCurRect->x == mCurRect->prev->XMost ()) ||
 
386
          (mCurRect->x == mCurRect->prev->x && mCurRect->width == mCurRect->prev->width &&
 
387
           mCurRect->y == mCurRect->prev->YMost ()) )
 
388
        mCurRect = mCurRect->prev;
 
389
 
 
390
      // Try to combine with rectangle on right side
 
391
      while (mCurRect->y == mCurRect->next->y && mCurRect->height == mCurRect->next->height &&
 
392
             mCurRect->XMost () == mCurRect->next->x)
 
393
      {
 
394
        mCurRect->width += mCurRect->next->width;
 
395
        delete Remove (mCurRect->next);
 
396
      }
 
397
 
 
398
      // Try to combine with rectangle under this one
 
399
      while (mCurRect->x == mCurRect->next->x && mCurRect->width == mCurRect->next->width &&
 
400
             mCurRect->YMost () == mCurRect->next->y)
 
401
      {
 
402
        mCurRect->height += mCurRect->next->height;
 
403
        delete Remove (mCurRect->next);
 
404
      }
 
405
    }
 
406
  }
 
407
}
 
408
 
 
409
 
 
410
nsRegion::RgnRect* nsRegion::Remove (RgnRect* aRect)
 
411
{
 
412
  aRect->prev->next = aRect->next;
 
413
  aRect->next->prev = aRect->prev;
 
414
  mRectCount--;
 
415
 
 
416
  if (mCurRect == aRect)
 
417
    mCurRect = (aRect->next != &mRectListHead) ? aRect->next : aRect->prev;
 
418
 
 
419
  return aRect;
 
420
}
 
421
 
 
422
 
 
423
// Try to reduce the number of rectangles in complex region by combining with
 
424
// surrounding ones on right and bottom sides of each rectangle in list.
 
425
// Update bounding rectangle
 
426
 
 
427
void nsRegion::Optimize ()
 
428
{
 
429
  if (mRectCount == 0)
 
430
    mBoundRect.SetRect (0, 0, 0, 0);
 
431
  else
 
432
  {
 
433
    RgnRect* pRect = mRectListHead.next;
 
434
    PRInt32 xmost = mRectListHead.prev->XMost ();
 
435
    PRInt32 ymost = mRectListHead.prev->YMost ();
 
436
    mBoundRect.x = mRectListHead.next->x;
 
437
    mBoundRect.y = mRectListHead.next->y;
 
438
 
 
439
    while (pRect != &mRectListHead)
 
440
    {
 
441
      // Try to combine with rectangle on right side
 
442
      while (pRect->y == pRect->next->y && pRect->height == pRect->next->height &&
 
443
             pRect->XMost () == pRect->next->x)
 
444
      {
 
445
        pRect->width += pRect->next->width;
 
446
        delete Remove (pRect->next);
 
447
      }
 
448
 
 
449
      // Try to combine with rectangle under this one
 
450
      while (pRect->x == pRect->next->x && pRect->width == pRect->next->width &&
 
451
             pRect->YMost () == pRect->next->y)
 
452
      {
 
453
        pRect->height += pRect->next->height;
 
454
        delete Remove (pRect->next);
 
455
      }
 
456
 
 
457
      // Determine bound rectangle. Use fact that rectangles are sorted.
 
458
      if (pRect->x < mBoundRect.x) mBoundRect.x = pRect->x;
 
459
      if (pRect->XMost () > xmost) xmost = pRect->XMost ();
 
460
      if (pRect->YMost () > ymost) ymost = pRect->YMost ();
 
461
 
 
462
      pRect = pRect->next;
 
463
    }
 
464
 
 
465
    mBoundRect.width  = xmost - mBoundRect.x;
 
466
    mBoundRect.height = ymost - mBoundRect.y;
 
467
  }
 
468
}
 
469
 
 
470
 
 
471
// Move rectangles starting from 'aStartRect' till end of the list to the destionation region.
 
472
// Important for temporary objects - instead of copying rectangles with Merge () and then
 
473
// emptying region in destructor they could be moved to destination region in one step.
 
474
 
 
475
void nsRegion::MoveInto (nsRegion& aDestRegion, const RgnRect* aStartRect)
 
476
{
 
477
  RgnRect* pRect = NS_CONST_CAST (RgnRect*, aStartRect);
 
478
  RgnRect* pPrev = pRect->prev;
 
479
 
 
480
  while (pRect != &mRectListHead)
 
481
  {
 
482
    RgnRect* next = pRect->next;
 
483
    aDestRegion.InsertInPlace (pRect);
 
484
 
 
485
    mRectCount--;
 
486
    pRect = next;
 
487
  }
 
488
 
 
489
  pPrev->next = &mRectListHead;
 
490
  mRectListHead.prev = pPrev;
 
491
  mCurRect = mRectListHead.next;
 
492
}
 
493
 
 
494
 
 
495
// Merge two non-overlapping regions into one.
 
496
// Automatically optimize region by calling Optimize ()
 
497
 
 
498
void nsRegion::Merge (const nsRegion& aRgn1, const nsRegion& aRgn2)
 
499
{
 
500
  if (aRgn1.mRectCount == 0)            // Region empty. Result is equal to other region
 
501
    Copy (aRgn2);
 
502
  else
 
503
  if (aRgn2.mRectCount == 0)            // Region empty. Result is equal to other region
 
504
    Copy (aRgn1);
 
505
  if (aRgn1.mRectCount == 1)            // Region is single rectangle. Optimize on fly
 
506
  {
 
507
    RgnRect* TmpRect = new RgnRect (*aRgn1.mRectListHead.next);
 
508
    Copy (aRgn2);
 
509
    InsertInPlace (TmpRect, PR_TRUE);
 
510
  } else
 
511
  if (aRgn2.mRectCount == 1)            // Region is single rectangle. Optimize on fly
 
512
  {
 
513
    RgnRect* TmpRect = new RgnRect (*aRgn2.mRectListHead.next);
 
514
    Copy (aRgn1);
 
515
    InsertInPlace (TmpRect, PR_TRUE);
 
516
  } else
 
517
  {
 
518
    const nsRegion* pCopyRegion, *pInsertRegion;
 
519
 
 
520
    // Determine which region contains more rectangles. Copy the larger one
 
521
    if (aRgn1.mRectCount >= aRgn2.mRectCount)
 
522
    {
 
523
      pCopyRegion = &aRgn1;
 
524
      pInsertRegion = &aRgn2;
 
525
    } else
 
526
    {
 
527
      pCopyRegion = &aRgn2;
 
528
      pInsertRegion = &aRgn1;
 
529
    }
 
530
 
 
531
    if (pInsertRegion == this)          // Do merge in-place
 
532
      pInsertRegion = pCopyRegion;
 
533
    else
 
534
      Copy (*pCopyRegion);
 
535
 
 
536
    const RgnRect* pSrcRect = pInsertRegion->mRectListHead.next;
 
537
 
 
538
    while (pSrcRect != &pInsertRegion->mRectListHead)
 
539
    {
 
540
      InsertInPlace (new RgnRect (*pSrcRect));
 
541
 
 
542
      pSrcRect = pSrcRect->next;
 
543
    }
 
544
 
 
545
    Optimize ();
 
546
  }
 
547
}
 
548
 
 
549
 
 
550
nsRegion& nsRegion::Copy (const nsRegion& aRegion)
 
551
{
 
552
  if (&aRegion == this)
 
553
    return *this;
 
554
 
 
555
  if (aRegion.mRectCount == 0)
 
556
    SetEmpty ();
 
557
  else
 
558
  {
 
559
    SetToElements (aRegion.mRectCount);
 
560
 
 
561
    const RgnRect* pSrc = aRegion.mRectListHead.next;
 
562
    RgnRect* pDest = mRectListHead.next;
 
563
 
 
564
    while (pSrc != &aRegion.mRectListHead)
 
565
    {
 
566
      *pDest = *pSrc;
 
567
 
 
568
      pSrc  = pSrc->next;
 
569
      pDest = pDest->next;
 
570
    }
 
571
 
 
572
    mCurRect = mRectListHead.next;
 
573
    mBoundRect = aRegion.mBoundRect;
 
574
  }
 
575
 
 
576
  return *this;
 
577
}
 
578
 
 
579
 
 
580
nsRegion& nsRegion::Copy (const nsRect& aRect)
 
581
{
 
582
  if (aRect.IsEmpty ())
 
583
    SetEmpty ();
 
584
  else
 
585
  {
 
586
    SetToElements (1);
 
587
    *mRectListHead.next = NS_STATIC_CAST (const RgnRect&, aRect);
 
588
    mBoundRect = NS_STATIC_CAST (const nsRectFast&, aRect);
 
589
  }
 
590
 
 
591
  return *this;
 
592
}
 
593
 
 
594
 
 
595
nsRegion& nsRegion::And (const nsRegion& aRgn1, const nsRegion& aRgn2)
 
596
{
 
597
  if (&aRgn1 == &aRgn2)                                       // And with self
 
598
    Copy (aRgn1);
 
599
  else
 
600
  if (aRgn1.mRectCount == 0 || aRgn2.mRectCount == 0)         // If either region is empty then result is empty
 
601
    SetEmpty ();
 
602
  else
 
603
  {
 
604
    nsRectFast TmpRect;
 
605
 
 
606
    if (aRgn1.mRectCount == 1 && aRgn2.mRectCount == 1)       // Intersect rectangle with rectangle
 
607
    {
 
608
      TmpRect.IntersectRect (*aRgn1.mRectListHead.next, *aRgn2.mRectListHead.next);
 
609
      Copy (TmpRect);
 
610
    } else
 
611
    {
 
612
      if (!aRgn1.mBoundRect.Intersects (aRgn2.mBoundRect))    // Regions do not intersect
 
613
        SetEmpty ();
 
614
      else
 
615
      {
 
616
        // Region is simple rectangle and it fully overlays other region
 
617
        if (aRgn1.mRectCount == 1 && aRgn1.mBoundRect.Contains (aRgn2.mBoundRect))
 
618
          Copy (aRgn2);
 
619
        else
 
620
        // Region is simple rectangle and it fully overlays other region
 
621
        if (aRgn2.mRectCount == 1 && aRgn2.mBoundRect.Contains (aRgn1.mBoundRect))
 
622
          Copy (aRgn1);
 
623
        else
 
624
        {
 
625
          nsRegion TmpRegion;
 
626
          nsRegion* pSrcRgn1 = NS_CONST_CAST (nsRegion*, &aRgn1);
 
627
          nsRegion* pSrcRgn2 = NS_CONST_CAST (nsRegion*, &aRgn2);
 
628
 
 
629
          if (&aRgn1 == this)     // Copy region if it is both source and result
 
630
          {
 
631
            TmpRegion.Copy (aRgn1);
 
632
            pSrcRgn1 = &TmpRegion;
 
633
          }
 
634
 
 
635
          if (&aRgn2 == this)     // Copy region if it is both source and result
 
636
          {
 
637
            TmpRegion.Copy (aRgn2);
 
638
            pSrcRgn2 = &TmpRegion;
 
639
          }
 
640
 
 
641
          // For outer loop prefer region for which at least one rectangle is below other's bound rectangle
 
642
          if (pSrcRgn2->mRectListHead.prev->y >= pSrcRgn1->mBoundRect.YMost ())
 
643
          {
 
644
            nsRegion* Tmp = pSrcRgn1;
 
645
            pSrcRgn1 = pSrcRgn2;
 
646
            pSrcRgn2 = Tmp;
 
647
          }
 
648
 
 
649
 
 
650
          SetToElements (0);
 
651
          pSrcRgn2->SaveLinkChain ();
 
652
 
 
653
          pSrcRgn1->mRectListHead.y = MAX_INT32;
 
654
          pSrcRgn2->mRectListHead.y = MAX_INT32;
 
655
 
 
656
          for (RgnRect* pSrcRect1 = pSrcRgn1->mRectListHead.next ;
 
657
               pSrcRect1->y < pSrcRgn2->mBoundRect.YMost () ; pSrcRect1 = pSrcRect1->next)
 
658
          {
 
659
            if (pSrcRect1->Intersects (pSrcRgn2->mBoundRect))   // Rectangle intersects region. Process each rectangle
 
660
            {
 
661
              RgnRect* pPrev2 = &pSrcRgn2->mRectListHead;
 
662
 
 
663
              for (RgnRect* pSrcRect2 = pSrcRgn2->mRectListHead.next ;
 
664
                   pSrcRect2->y < pSrcRect1->YMost () ; pSrcRect2 = pSrcRect2->next)
 
665
              {
 
666
                if (pSrcRect2->YMost () <= pSrcRect1->y)        // Rect2's bottom is above the top of Rect1.
 
667
                {                                               // No successive rectangles in Rgn1 can intersect it.
 
668
                  pPrev2->next = pSrcRect2->next;               // Remove Rect2 from Rgn2's checklist
 
669
                  continue;
 
670
                }
 
671
 
 
672
                if (pSrcRect1->Contains (*pSrcRect2))           // Rect1 fully overlays Rect2.
 
673
                {                                               // No any other rectangle in Rgn1 can intersect it.
 
674
                  pPrev2->next = pSrcRect2->next;               // Remove Rect2 from Rgn2's checklist
 
675
                  InsertInPlace (new RgnRect (*pSrcRect2));
 
676
                  continue;
 
677
                }
 
678
 
 
679
 
 
680
                if (TmpRect.IntersectRect (*pSrcRect1, *pSrcRect2))
 
681
                  InsertInPlace (new RgnRect (TmpRect));
 
682
 
 
683
                pPrev2 = pSrcRect2;
 
684
              }
 
685
            }
 
686
          }
 
687
 
 
688
          pSrcRgn2->RestoreLinkChain ();
 
689
          Optimize ();
 
690
        }
 
691
      }
 
692
    }
 
693
  }
 
694
 
 
695
  return *this;
 
696
}
 
697
 
 
698
 
 
699
nsRegion& nsRegion::And (const nsRegion& aRegion, const nsRect& aRect)
 
700
{
 
701
  // If either region or rectangle is empty then result is empty
 
702
  if (aRegion.mRectCount == 0 || aRect.IsEmpty ())
 
703
    SetEmpty ();
 
704
  else                            // Intersect region with rectangle
 
705
  {
 
706
    const nsRectFast& aRectFast = NS_STATIC_CAST (const nsRectFast&, aRect);
 
707
    nsRectFast TmpRect;
 
708
 
 
709
    if (aRegion.mRectCount == 1)  // Intersect rectangle with rectangle
 
710
    {
 
711
      TmpRect.IntersectRect (*aRegion.mRectListHead.next, aRectFast);
 
712
      Copy (TmpRect);
 
713
    } else                        // Intersect complex region with rectangle
 
714
    {
 
715
      if (!aRectFast.Intersects (aRegion.mBoundRect))   // Rectangle does not intersect region
 
716
        SetEmpty ();
 
717
      else
 
718
      {
 
719
        if (aRectFast.Contains (aRegion.mBoundRect))    // Rectangle fully overlays region
 
720
          Copy (aRegion);
 
721
        else
 
722
        {
 
723
          nsRegion TmpRegion;
 
724
          nsRegion* pSrcRegion = NS_CONST_CAST (nsRegion*, &aRegion);
 
725
 
 
726
          if (&aRegion == this)   // Copy region if it is both source and result
 
727
          {
 
728
            TmpRegion.Copy (aRegion);
 
729
            pSrcRegion = &TmpRegion;
 
730
          }
 
731
 
 
732
          SetToElements (0);
 
733
          pSrcRegion->mRectListHead.y = MAX_INT32;
 
734
 
 
735
          for (const RgnRect* pSrcRect = pSrcRegion->mRectListHead.next ;
 
736
               pSrcRect->y < aRectFast.YMost () ; pSrcRect = pSrcRect->next)
 
737
          {
 
738
            if (TmpRect.IntersectRect (*pSrcRect, aRectFast))
 
739
              InsertInPlace (new RgnRect (TmpRect));
 
740
          }
 
741
 
 
742
          Optimize ();
 
743
        }
 
744
      }
 
745
    }
 
746
  }
 
747
 
 
748
  return *this;
 
749
}
 
750
 
 
751
 
 
752
nsRegion& nsRegion::Or (const nsRegion& aRgn1, const nsRegion& aRgn2)
 
753
{
 
754
  if (&aRgn1 == &aRgn2)                 // Or with self
 
755
    Copy (aRgn1);
 
756
  else
 
757
  if (aRgn1.mRectCount == 0)            // Region empty. Result is equal to other region
 
758
    Copy (aRgn2);
 
759
  else
 
760
  if (aRgn2.mRectCount == 0)            // Region empty. Result is equal to other region
 
761
    Copy (aRgn1);
 
762
  else
 
763
  {
 
764
    if (!aRgn1.mBoundRect.Intersects (aRgn2.mBoundRect))  // Regions do not intersect
 
765
      Merge (aRgn1, aRgn2);
 
766
    else
 
767
    {
 
768
      // Region is simple rectangle and it fully overlays other region
 
769
      if (aRgn1.mRectCount == 1 && aRgn1.mBoundRect.Contains (aRgn2.mBoundRect))
 
770
        Copy (aRgn1);
 
771
      else
 
772
      // Region is simple rectangle and it fully overlays other region
 
773
      if (aRgn2.mRectCount == 1 && aRgn2.mBoundRect.Contains (aRgn1.mBoundRect))
 
774
        Copy (aRgn2);
 
775
      else
 
776
      {
 
777
        nsRegion TmpRegion;
 
778
        aRgn1.SubRegion (aRgn2, TmpRegion);               // Get only parts of region which not overlap the other region
 
779
        Copy (aRgn2);
 
780
        TmpRegion.MoveInto (*this);
 
781
        Optimize ();
 
782
      }
 
783
    }
 
784
  }
 
785
 
 
786
  return *this;
 
787
}
 
788
 
 
789
 
 
790
nsRegion& nsRegion::Or (const nsRegion& aRegion, const nsRect& aRect)
 
791
{
 
792
  if (aRegion.mRectCount == 0)          // Region empty. Result is equal to rectangle
 
793
    Copy (aRect);
 
794
  else
 
795
  if (aRect.IsEmpty ())                 // Rectangle is empty. Result is equal to region
 
796
    Copy (aRegion);
 
797
  else
 
798
  {
 
799
    const nsRectFast& aRectFast = NS_STATIC_CAST (const nsRectFast&, aRect);
 
800
 
 
801
    if (!aRectFast.Intersects (aRegion.mBoundRect))     // Rectangle does not intersect region
 
802
    {
 
803
      Copy (aRegion);
 
804
      InsertInPlace (new RgnRect (aRectFast), PR_TRUE);
 
805
    } else
 
806
    {
 
807
      // Region is simple rectangle and it fully overlays rectangle
 
808
      if (aRegion.mRectCount == 1 && aRegion.mBoundRect.Contains (aRectFast))
 
809
        Copy (aRegion);
 
810
      else
 
811
      if (aRectFast.Contains (aRegion.mBoundRect))      // Rectangle fully overlays region
 
812
        Copy (aRectFast);
 
813
      else
 
814
      {
 
815
        aRegion.SubRect (aRectFast, *this);             // Exclude from region parts that overlap the rectangle
 
816
        InsertInPlace (new RgnRect (aRectFast));
 
817
        Optimize ();
 
818
      }
 
819
    }
 
820
  }
 
821
 
 
822
  return *this;
 
823
}
 
824
 
 
825
 
 
826
nsRegion& nsRegion::Xor (const nsRegion& aRgn1, const nsRegion& aRgn2)
 
827
{
 
828
  if (&aRgn1 == &aRgn2)                 // Xor with self
 
829
    SetEmpty ();
 
830
  else
 
831
  if (aRgn1.mRectCount == 0)            // Region empty. Result is equal to other region
 
832
    Copy (aRgn2);
 
833
  else
 
834
  if (aRgn2.mRectCount == 0)            // Region empty. Result is equal to other region
 
835
    Copy (aRgn1);
 
836
  else
 
837
  {
 
838
    if (!aRgn1.mBoundRect.Intersects (aRgn2.mBoundRect))      // Regions do not intersect
 
839
      Merge (aRgn1, aRgn2);
 
840
    else
 
841
    {
 
842
      // Region is simple rectangle and it fully overlays other region
 
843
      if (aRgn1.mRectCount == 1 && aRgn1.mBoundRect.Contains (aRgn2.mBoundRect))
 
844
      {
 
845
        aRgn1.SubRegion (aRgn2, *this);
 
846
        Optimize ();
 
847
      } else
 
848
      // Region is simple rectangle and it fully overlays other region
 
849
      if (aRgn2.mRectCount == 1 && aRgn2.mBoundRect.Contains (aRgn1.mBoundRect))
 
850
      {
 
851
        aRgn2.SubRegion (aRgn1, *this);
 
852
        Optimize ();
 
853
      } else
 
854
      {
 
855
        nsRegion TmpRegion;
 
856
        aRgn1.SubRegion (aRgn2, TmpRegion);
 
857
        aRgn2.SubRegion (aRgn1, *this);
 
858
        TmpRegion.MoveInto (*this);
 
859
        Optimize ();
 
860
      }
 
861
    }
 
862
  }
 
863
 
 
864
  return *this;
 
865
}
 
866
 
 
867
 
 
868
nsRegion& nsRegion::Xor (const nsRegion& aRegion, const nsRect& aRect)
 
869
{
 
870
  if (aRegion.mRectCount == 0)          // Region empty. Result is equal to rectangle
 
871
    Copy (aRect);
 
872
  else
 
873
  if (aRect.IsEmpty ())                 // Rectangle is empty. Result is equal to region
 
874
    Copy (aRegion);
 
875
  else
 
876
  {
 
877
    const nsRectFast& aRectFast = NS_STATIC_CAST (const nsRectFast&, aRect);
 
878
 
 
879
    if (!aRectFast.Intersects (aRegion.mBoundRect))     // Rectangle does not intersect region
 
880
    {
 
881
      Copy (aRegion);
 
882
      InsertInPlace (new RgnRect (aRectFast), PR_TRUE);
 
883
    } else
 
884
    {
 
885
      // Region is simple rectangle and it fully overlays rectangle
 
886
      if (aRegion.mRectCount == 1 && aRegion.mBoundRect.Contains (aRectFast))
 
887
      {
 
888
        aRegion.SubRect (aRectFast, *this);
 
889
        Optimize ();
 
890
      } else
 
891
      if (aRectFast.Contains (aRegion.mBoundRect))      // Rectangle fully overlays region
 
892
      {
 
893
        nsRegion TmpRegion;
 
894
        TmpRegion.Copy (aRectFast);
 
895
        TmpRegion.SubRegion (aRegion, *this);
 
896
        Optimize ();
 
897
      } else
 
898
      {
 
899
        nsRegion TmpRegion;
 
900
        TmpRegion.Copy (aRectFast);
 
901
        TmpRegion.SubRegion (aRegion, TmpRegion);
 
902
        aRegion.SubRect (aRectFast, *this);
 
903
        TmpRegion.MoveInto (*this);
 
904
        Optimize ();
 
905
      }
 
906
    }
 
907
  }
 
908
 
 
909
  return *this;
 
910
}
 
911
 
 
912
 
 
913
nsRegion& nsRegion::Sub (const nsRegion& aRgn1, const nsRegion& aRgn2)
 
914
{
 
915
  if (&aRgn1 == &aRgn2)         // Sub from self
 
916
    SetEmpty ();
 
917
  else
 
918
  if (aRgn1.mRectCount == 0)    // If source is empty then result is empty, too
 
919
    SetEmpty ();
 
920
  else
 
921
  if (aRgn2.mRectCount == 0)    // Nothing to subtract
 
922
    Copy (aRgn1);
 
923
  else
 
924
  {
 
925
    if (!aRgn1.mBoundRect.Intersects (aRgn2.mBoundRect))   // Regions do not intersect
 
926
      Copy (aRgn1);
 
927
    else
 
928
    {
 
929
      aRgn1.SubRegion (aRgn2, *this);
 
930
      Optimize ();
 
931
    }
 
932
  }
 
933
 
 
934
  return *this;
 
935
}
 
936
 
 
937
 
 
938
nsRegion& nsRegion::Sub (const nsRegion& aRegion, const nsRect& aRect)
 
939
{
 
940
  if (aRegion.mRectCount == 0)    // If source is empty then result is empty, too
 
941
    SetEmpty ();
 
942
  else
 
943
  if (aRect.IsEmpty ())           // Nothing to subtract
 
944
    Copy (aRegion);
 
945
  else
 
946
  {
 
947
    const nsRectFast& aRectFast = NS_STATIC_CAST (const nsRectFast&, aRect);
 
948
 
 
949
    if (!aRectFast.Intersects (aRegion.mBoundRect))   // Rectangle does not intersect region
 
950
      Copy (aRegion);
 
951
    else
 
952
    {
 
953
      if (aRectFast.Contains (aRegion.mBoundRect))    // Rectangle fully overlays region
 
954
        SetEmpty ();
 
955
      else
 
956
      {
 
957
        aRegion.SubRect (aRectFast, *this);
 
958
        Optimize ();
 
959
      }
 
960
    }
 
961
  }
 
962
 
 
963
  return *this;
 
964
}
 
965
 
 
966
 
 
967
// Subtract region from current region.
 
968
// Both regions are non-empty and they intersect each other.
 
969
// Result could be empty region if aRgn2 is rectangle that fully overlays aRgn1.
 
970
// Optimize () is not called on exit (bound rectangle is not updated).
 
971
 
 
972
void nsRegion::SubRegion (const nsRegion& aRegion, nsRegion& aResult) const
 
973
{
 
974
  if (aRegion.mRectCount == 1)    // Subtract simple rectangle
 
975
  {
 
976
    if (aRegion.mBoundRect.Contains (mBoundRect))
 
977
      aResult.SetEmpty ();
 
978
    else
 
979
      SubRect (*aRegion.mRectListHead.next, aResult);
 
980
  } else
 
981
  {
 
982
    nsRegion TmpRegion, CompletedRegion;
 
983
    const nsRegion* pSubRgn = &aRegion;
 
984
 
 
985
    if (&aResult == &aRegion)     // Copy region if it is both source and result
 
986
    {
 
987
      TmpRegion.Copy (aRegion);
 
988
      pSubRgn = &TmpRegion;
 
989
    }
 
990
 
 
991
    const RgnRect* pSubRect = pSubRgn->mRectListHead.next;
 
992
 
 
993
    SubRect (*pSubRect, aResult, CompletedRegion);
 
994
    pSubRect = pSubRect->next;
 
995
 
 
996
    while (pSubRect != &pSubRgn->mRectListHead)
 
997
    {
 
998
      aResult.SubRect (*pSubRect, aResult, CompletedRegion);
 
999
      pSubRect = pSubRect->next;
 
1000
    }
 
1001
 
 
1002
    CompletedRegion.MoveInto (aResult);
 
1003
  }
 
1004
}
 
1005
 
 
1006
 
 
1007
// Subtract rectangle from current region.
 
1008
// Both region and rectangle are non-empty and they intersect each other.
 
1009
// Result could be empty region if aRect fully overlays aRegion.
 
1010
// Could be called repeatedly with 'this' as input and result - bound rectangle is not known.
 
1011
// Optimize () is not called on exit (bound rectangle is not updated).
 
1012
//
 
1013
// aCompleted is filled with rectangles which are already checked and could be safely
 
1014
// removed from further examination in case aRect rectangles come from ordered list.
 
1015
// aCompleted is not automatically emptied. aCompleted and aResult could be the same region.
 
1016
 
 
1017
void nsRegion::SubRect (const nsRectFast& aRect, nsRegion& aResult, nsRegion& aCompleted) const
 
1018
{
 
1019
  nsRegion TmpRegion;
 
1020
  const nsRegion* pSrcRegion = this;
 
1021
 
 
1022
  if (&aResult == this)           // Copy region if it is both source and result
 
1023
  {
 
1024
    TmpRegion.Copy (*this);
 
1025
    pSrcRegion = &TmpRegion;
 
1026
  }
 
1027
 
 
1028
  aResult.SetToElements (0);
 
1029
 
 
1030
  (NS_CONST_CAST (nsRegion*, pSrcRegion))->mRectListHead.y = MAX_INT32;
 
1031
  const RgnRect* pSrcRect = pSrcRegion->mRectListHead.next;
 
1032
 
 
1033
  for ( ; pSrcRect->y < aRect.YMost () ; pSrcRect = pSrcRect->next)
 
1034
  {
 
1035
    nsRectFast TmpRect;
 
1036
 
 
1037
    // If bottom of current rectangle is above the top of aRect then this rectangle
 
1038
    // could be moved to aCompleted region. Successive aRect rectangles from ordered
 
1039
    // list do not have to check this rectangle again.
 
1040
    if (pSrcRect->YMost () <= aRect.y)
 
1041
    {
 
1042
      aCompleted.InsertInPlace (new RgnRect (*pSrcRect));
 
1043
      continue;
 
1044
    }
 
1045
 
 
1046
    if (!TmpRect.IntersectRect (*pSrcRect, aRect))
 
1047
      aResult.InsertInPlace (new RgnRect (*pSrcRect));
 
1048
    else
 
1049
    {
 
1050
      // Rectangle A. Subtract from this rectangle B
 
1051
      const nscoord ax  = pSrcRect->x;
 
1052
      const nscoord axm = pSrcRect->XMost ();
 
1053
      const nscoord aw  = pSrcRect->width;
 
1054
      const nscoord ay  = pSrcRect->y;
 
1055
      const nscoord aym = pSrcRect->YMost ();
 
1056
      const nscoord ah  = pSrcRect->height;
 
1057
      // Rectangle B. Subtract this from rectangle A
 
1058
      const nscoord bx  = aRect.x;
 
1059
      const nscoord bxm = aRect.XMost ();
 
1060
      const nscoord by  = aRect.y;
 
1061
      const nscoord bym = aRect.YMost ();
 
1062
      // Rectangle I. Area where rectangles A and B intersect
 
1063
      const nscoord ix  = TmpRect.x;
 
1064
      const nscoord ixm = TmpRect.XMost ();
 
1065
      const nscoord iy  = TmpRect.y;
 
1066
      const nscoord iym = TmpRect.YMost ();
 
1067
      const nscoord ih  = TmpRect.height;
 
1068
 
 
1069
      // There are 16 combinations how rectangles could intersect
 
1070
 
 
1071
      if (bx <= ax && by <= ay)
 
1072
      {
 
1073
        if (bxm < axm && bym < aym)     // 1.
 
1074
        {
 
1075
          aResult.InsertInPlace (new RgnRect (ixm, ay, axm - ixm, ih));
 
1076
          aResult.InsertInPlace (new RgnRect (ax, iym, aw, aym - iym));
 
1077
        } else
 
1078
        if (bxm >= axm && bym < aym)    // 2.
 
1079
        {
 
1080
          aResult.InsertInPlace (new RgnRect (ax, iym, aw, aym - iym));
 
1081
        } else
 
1082
        if (bxm < axm && bym >= aym)    // 3.
 
1083
        {
 
1084
          aResult.InsertInPlace (new RgnRect (ixm, ay, axm - ixm, ah));
 
1085
        } else
 
1086
        if (*pSrcRect == aRect)         // 4. subset
 
1087
        {                               // Current rectangle is equal to aRect
 
1088
          break;                        // No any other rectangle in region can intersect it
 
1089
        }
 
1090
      } else
 
1091
      if (bx > ax && by <= ay)
 
1092
      {
 
1093
        if (bxm < axm && bym < aym)     // 5.
 
1094
        {
 
1095
          aResult.InsertInPlace (new RgnRect (ax, ay, ix - ax, ih));
 
1096
          aResult.InsertInPlace (new RgnRect (ixm, ay, axm - ixm, ih));
 
1097
          aResult.InsertInPlace (new RgnRect (ax, iym, aw, aym - iym));
 
1098
        } else
 
1099
        if (bxm >= axm && bym < aym)    // 6.
 
1100
        {
 
1101
          aResult.InsertInPlace (new RgnRect (ax, ay, ix - ax, ih));
 
1102
          aResult.InsertInPlace (new RgnRect (ax, iym, aw, aym - iym));
 
1103
        } else
 
1104
        if (bxm < axm && bym >= aym)    // 7.
 
1105
        {
 
1106
          aResult.InsertInPlace (new RgnRect (ax, ay, ix - ax, ah));
 
1107
          aResult.InsertInPlace (new RgnRect (ixm, ay, axm - ixm, ah));
 
1108
        } else
 
1109
        if (bxm >= axm && bym >= aym)   // 8.
 
1110
        {
 
1111
          aResult.InsertInPlace (new RgnRect (ax, ay, ix - ax, ah));
 
1112
        }
 
1113
      } else
 
1114
      if (bx <= ax && by > ay)
 
1115
      {
 
1116
        if (bxm < axm && bym < aym)     // 9.
 
1117
        {
 
1118
          aResult.InsertInPlace (new RgnRect (ax, ay, aw, iy - ay));
 
1119
          aResult.InsertInPlace (new RgnRect (ixm, iy, axm - ixm, ih));
 
1120
          aResult.InsertInPlace (new RgnRect (ax, iym, aw, aym - iym));
 
1121
        } else
 
1122
        if (bxm >= axm && bym < aym)    // 10.
 
1123
        {
 
1124
          aResult.InsertInPlace (new RgnRect (ax, ay, aw, iy - ay));
 
1125
          aResult.InsertInPlace (new RgnRect (ax, iym, aw, aym - iym));
 
1126
        } else
 
1127
        if (bxm < axm && bym >= aym)    // 11.
 
1128
        {
 
1129
          aResult.InsertInPlace (new RgnRect (ax, ay, aw, iy - ay));
 
1130
          aResult.InsertInPlace (new RgnRect (ixm, iy, axm - ixm, ih));
 
1131
        } else
 
1132
        if (bxm >= axm && bym >= aym)   // 12.
 
1133
        {
 
1134
          aResult.InsertInPlace (new RgnRect (ax, ay, aw, iy - ay));
 
1135
        }
 
1136
      } else
 
1137
      if (bx > ax && by > ay)
 
1138
      {
 
1139
        if (bxm < axm && bym < aym)     // 13.
 
1140
        {
 
1141
          aResult.InsertInPlace (new RgnRect (ax, ay, aw, iy - ay));
 
1142
          aResult.InsertInPlace (new RgnRect (ax, iy, ix - ax, ih));
 
1143
          aResult.InsertInPlace (new RgnRect (ixm, iy, axm - ixm, ih));
 
1144
          aResult.InsertInPlace (new RgnRect (ax, iym, aw, aym - iym));
 
1145
 
 
1146
          // Current rectangle fully overlays aRect. No any other rectangle can intersect it.
 
1147
          break;
 
1148
        } else
 
1149
        if (bxm >= axm && bym < aym)    // 14.
 
1150
        {
 
1151
          aResult.InsertInPlace (new RgnRect (ax, ay, aw, iy - ay));
 
1152
          aResult.InsertInPlace (new RgnRect (ax, iy, ix - ax, ih));
 
1153
          aResult.InsertInPlace (new RgnRect (ax, iym, aw, aym - iym));
 
1154
        } else
 
1155
        if (bxm < axm && bym >= aym)    // 15.
 
1156
        {
 
1157
          aResult.InsertInPlace (new RgnRect (ax, ay, aw, iy - ay));
 
1158
          aResult.InsertInPlace (new RgnRect (ax, iy, ix - ax, ih));
 
1159
          aResult.InsertInPlace (new RgnRect (ixm, iy, axm - ixm, ih));
 
1160
        } else
 
1161
        if (bxm >= axm && bym >= aym)   // 16.
 
1162
        {
 
1163
          aResult.InsertInPlace (new RgnRect (ax, ay, aw, iy - ay));
 
1164
          aResult.InsertInPlace (new RgnRect (ax, iy, ix - ax, ih));
 
1165
        }
 
1166
      }
 
1167
    }
 
1168
  }
 
1169
 
 
1170
  // Just copy remaining rectangles in region which are below aRect and can't intersect it.
 
1171
  // If rectangles are in temporary region then they could be moved.
 
1172
  if (pSrcRegion == &TmpRegion)
 
1173
    TmpRegion.MoveInto (aResult, pSrcRect);
 
1174
  else
 
1175
  {
 
1176
    while (pSrcRect != &pSrcRegion->mRectListHead)
 
1177
    {
 
1178
      aResult.InsertInPlace (new RgnRect (*pSrcRect));
 
1179
      pSrcRect = pSrcRect->next;
 
1180
    }
 
1181
  }
 
1182
}
 
1183
 
 
1184
 
 
1185
PRBool nsRegion::IsEqual (const nsRegion& aRegion) const
 
1186
{
 
1187
  if (mRectCount == 0)
 
1188
    return (aRegion.mRectCount == 0) ? PR_TRUE : PR_FALSE;
 
1189
 
 
1190
  if (aRegion.mRectCount == 0)
 
1191
    return (mRectCount == 0) ? PR_TRUE : PR_FALSE;
 
1192
 
 
1193
  if (mRectCount == 1 && aRegion.mRectCount == 1) // Both regions are simple rectangles
 
1194
    return (*mRectListHead.next == *aRegion.mRectListHead.next);
 
1195
  else                                            // At least one is complex region.
 
1196
  {
 
1197
    if (mBoundRect != aRegion.mBoundRect)         // If regions are equal then bounding rectangles should match
 
1198
      return PR_FALSE;
 
1199
    else
 
1200
    {
 
1201
      nsRegion TmpRegion;
 
1202
      TmpRegion.Xor (*this, aRegion);             // Get difference between two regions
 
1203
 
 
1204
      return (TmpRegion.mRectCount == 0);
 
1205
    }
 
1206
  }
 
1207
}
 
1208
 
 
1209
 
 
1210
void nsRegion::MoveBy (PRInt32 aXOffset, PRInt32 aYOffset)
 
1211
{
 
1212
  if (aXOffset || aYOffset)
 
1213
  {
 
1214
    RgnRect* pRect = mRectListHead.next;
 
1215
 
 
1216
    while (pRect != &mRectListHead)
 
1217
    {
 
1218
      pRect->MoveBy (aXOffset, aYOffset);
 
1219
      pRect = pRect->next;
 
1220
    }
 
1221
 
 
1222
    mBoundRect.MoveBy (aXOffset, aYOffset);
 
1223
  }
 
1224
}