Back to index

lightning-sunbird  0.9+nobinonly
nsRegion.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is mozilla.org code.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Dainis Jonitis, <Dainis_Jonitis@swh-t.lv>.
00018  * Portions created by the Initial Developer are Copyright (C) 2001
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either of the GNU General Public License Version 2 or later (the "GPL"),
00025  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 #include "prlock.h"
00038 #include "nsRegion.h"
00039 #include "nsISupportsImpl.h"
00040 
00041 
00042 #define MIN_INT32 (-PR_INT32 (0x7FFFFFFF) - 1)
00043 #define MAX_INT32 (PR_INT32 (0x7FFFFFFF))
00044 
00045 
00046 // Fast inline analogues of nsRect methods for nsRegion::nsRectFast.
00047 // Check for emptiness is not required - it is guaranteed by caller.
00048 
00049 inline PRBool nsRegion::nsRectFast::Contains (const nsRect& aRect) const
00050 {
00051   return (PRBool) ((aRect.x >= x) && (aRect.y >= y) &&
00052                    (aRect.XMost () <= XMost ()) && (aRect.YMost () <= YMost ()));
00053 }
00054 
00055 inline PRBool nsRegion::nsRectFast::Intersects (const nsRect& aRect) const
00056 {
00057   return (PRBool) ((x < aRect.XMost ()) && (y < aRect.YMost ()) &&
00058                    (aRect.x < XMost ()) && (aRect.y < YMost ()));
00059 }
00060 
00061 inline PRBool nsRegion::nsRectFast::IntersectRect (const nsRect& aRect1, const nsRect& aRect2)
00062 {
00063   const nscoord xmost = PR_MIN (aRect1.XMost (), aRect2.XMost ());
00064   x = PR_MAX (aRect1.x, aRect2.x);
00065   width = xmost - x;
00066   if (width <= 0) return PR_FALSE;
00067 
00068   const nscoord ymost = PR_MIN (aRect1.YMost (), aRect2.YMost ());
00069   y = PR_MAX (aRect1.y, aRect2.y);
00070   height = ymost - y;
00071   if (height <= 0) return PR_FALSE;
00072 
00073   return PR_TRUE;
00074 }
00075 
00076 inline void nsRegion::nsRectFast::UnionRect (const nsRect& aRect1, const nsRect& aRect2)
00077 {
00078   const nscoord xmost = PR_MAX (aRect1.XMost (), aRect2.XMost ());
00079   const nscoord ymost = PR_MAX (aRect1.YMost (), aRect2.YMost ());
00080   x = PR_MIN (aRect1.x, aRect2.x);
00081   y = PR_MIN (aRect1.y, aRect2.y);
00082   width  = xmost - x;
00083   height = ymost - y;
00084 }
00085 
00086 
00087 
00088 // Custom memory allocator for nsRegion::RgnRect structures.
00089 // Entries are allocated from global memory pool.
00090 // Memory pool can grow in size, but it can't shrink.
00091 
00092 #define INIT_MEM_CHUNK_ENTRIES 100
00093 #define INCR_MEM_CHUNK_ENTRIES 100
00094 
00095 class RgnRectMemoryAllocator
00096 {
00097   nsRegion::RgnRect*  mFreeListHead;
00098   PRUint32  mFreeEntries;
00099   void*     mChunkListHead;
00100 #if 0
00101   PRLock*   mLock;
00102 
00103   void InitLock ()    { mLock = PR_NewLock (); }
00104   void DestroyLock () { PR_DestroyLock (mLock); }
00105   void Lock ()        { PR_Lock   (mLock); }
00106   void Unlock ()      { PR_Unlock (mLock); }
00107 #elif defined (DEBUG)
00108   NS_DECL_OWNINGTHREAD
00109 
00110   void InitLock ()    { NS_ASSERT_OWNINGTHREAD (RgnRectMemoryAllocator); }
00111   void DestroyLock () { NS_ASSERT_OWNINGTHREAD (RgnRectMemoryAllocator); }
00112   void Lock ()        { NS_ASSERT_OWNINGTHREAD (RgnRectMemoryAllocator); }
00113   void Unlock ()      { NS_ASSERT_OWNINGTHREAD (RgnRectMemoryAllocator); }
00114 #else
00115   void InitLock ()    { }
00116   void DestroyLock () { }
00117   void Lock ()        { }
00118   void Unlock ()      { }
00119 #endif
00120 
00121   void* AllocChunk (PRUint32 aEntries, void* aNextChunk, nsRegion::RgnRect* aTailDest)
00122   {
00123     PRUint8* pBuf = new PRUint8 [aEntries * sizeof (nsRegion::RgnRect) + sizeof (void*)];
00124     *NS_REINTERPRET_CAST (void**, pBuf) = aNextChunk;
00125     nsRegion::RgnRect* pRect = NS_REINTERPRET_CAST (nsRegion::RgnRect*, pBuf + sizeof (void*));
00126 
00127     for (PRUint32 cnt = 0 ; cnt < aEntries - 1 ; cnt++)
00128       pRect [cnt].next = &pRect [cnt + 1];
00129 
00130     pRect [aEntries - 1].next = aTailDest;
00131 
00132     return pBuf;
00133   }
00134 
00135   void FreeChunk (void* aChunk) {  delete [] (PRUint8 *) aChunk;  }
00136   void* NextChunk (void* aThisChunk) const { return *NS_STATIC_CAST (void**, aThisChunk); }
00137 
00138   nsRegion::RgnRect* ChunkHead (void* aThisChunk) const
00139   {   return NS_REINTERPRET_CAST (nsRegion::RgnRect*, NS_STATIC_CAST (PRUint8*, aThisChunk) + sizeof (void*));  }
00140 
00141 public:
00142   RgnRectMemoryAllocator (PRUint32 aNumOfEntries);
00143  ~RgnRectMemoryAllocator ();
00144 
00145   nsRegion::RgnRect* Alloc ();
00146   void Free (nsRegion::RgnRect* aRect);
00147 };
00148 
00149 
00150 RgnRectMemoryAllocator::RgnRectMemoryAllocator (PRUint32 aNumOfEntries)
00151 {
00152   InitLock ();
00153   mChunkListHead = AllocChunk (aNumOfEntries, nsnull, nsnull);
00154   mFreeEntries   = aNumOfEntries;
00155   mFreeListHead  = ChunkHead (mChunkListHead);
00156 }
00157 
00158 RgnRectMemoryAllocator::~RgnRectMemoryAllocator ()
00159 {
00160   while (mChunkListHead)
00161   {
00162     void* tmp = mChunkListHead;
00163     mChunkListHead = NextChunk (mChunkListHead);
00164     FreeChunk (tmp);
00165   }
00166 
00167 #if 0
00168   /*
00169    * As a static object this class outlives any library which would implement
00170    * locking. So we intentionally leak the 'lock'.
00171    *
00172    * Currently RgnRectMemoryAllocator is only used from the primary thread,
00173    * so we aren't using a lock which means that there is no lock to leak.
00174    * If we ever switch to multiple GUI threads (e.g. one per window),
00175    * we'd probably use one allocator per window-thread to avoid the
00176    * locking overhead and just require consumers not to pass regions
00177    * across threads/windows, which would be a reasonable restriction
00178    * because they wouldn't be useful outside their window.
00179    */
00180   DestroyLock ();
00181 #endif
00182 }
00183 
00184 nsRegion::RgnRect* RgnRectMemoryAllocator::Alloc ()
00185 {
00186   Lock ();
00187 
00188   if (mFreeEntries == 0)
00189   {
00190     mChunkListHead = AllocChunk (INCR_MEM_CHUNK_ENTRIES, mChunkListHead, mFreeListHead);
00191     mFreeEntries   = INCR_MEM_CHUNK_ENTRIES;
00192     mFreeListHead  = ChunkHead (mChunkListHead);
00193   }
00194 
00195   nsRegion::RgnRect* tmp = mFreeListHead;
00196   mFreeListHead = mFreeListHead->next;
00197   mFreeEntries--;
00198   Unlock ();
00199 
00200   return tmp;
00201 }
00202 
00203 void RgnRectMemoryAllocator::Free (nsRegion::RgnRect* aRect)
00204 {
00205   Lock ();
00206   mFreeEntries++;
00207   aRect->next = mFreeListHead;
00208   mFreeListHead = aRect;
00209   Unlock ();
00210 }
00211 
00212 
00213 // Global pool for nsRegion::RgnRect allocation
00214 static RgnRectMemoryAllocator gRectPool (INIT_MEM_CHUNK_ENTRIES);
00215 
00216 
00217 inline void* nsRegion::RgnRect::operator new (size_t) CPP_THROW_NEW
00218 {
00219   return gRectPool.Alloc ();
00220 }
00221 
00222 inline void nsRegion::RgnRect::operator delete (void* aRect, size_t)
00223 {
00224   gRectPool.Free (NS_STATIC_CAST (RgnRect*, aRect));
00225 }
00226 
00227 
00228 
00229 void nsRegion::Init()
00230 {
00231   mRectListHead.prev = mRectListHead.next = &mRectListHead;
00232   mCurRect = &mRectListHead;
00233   mRectCount = 0;
00234   mBoundRect.SetRect (0, 0, 0, 0);
00235 }
00236 
00237 inline void nsRegion::InsertBefore (RgnRect* aNewRect, RgnRect* aRelativeRect)
00238 {
00239   aNewRect->prev = aRelativeRect->prev;
00240   aNewRect->next = aRelativeRect;
00241   aRelativeRect->prev->next = aNewRect;
00242   aRelativeRect->prev = aNewRect;
00243   mCurRect = aNewRect;
00244   mRectCount++;
00245 }
00246 
00247 inline void nsRegion::InsertAfter (RgnRect* aNewRect, RgnRect* aRelativeRect)
00248 {
00249   aNewRect->prev = aRelativeRect;
00250   aNewRect->next = aRelativeRect->next;
00251   aRelativeRect->next->prev = aNewRect;
00252   aRelativeRect->next = aNewRect;
00253   mCurRect = aNewRect;
00254   mRectCount++;
00255 }
00256 
00257 
00258 // Adjust the number of rectangles in region.
00259 // Content of rectangles should be changed by caller.
00260 
00261 void nsRegion::SetToElements (PRUint32 aCount)
00262 {
00263   if (mRectCount < aCount)        // Add missing rectangles
00264   {
00265     PRUint32 InsertCount = aCount - mRectCount;
00266     mRectCount = aCount;
00267     RgnRect* pPrev = &mRectListHead;
00268     RgnRect* pNext = mRectListHead.next;
00269 
00270     while (InsertCount--)
00271     {
00272       mCurRect = new RgnRect;
00273       mCurRect->prev = pPrev;
00274       pPrev->next = mCurRect;
00275       pPrev = mCurRect;
00276     }
00277 
00278     pPrev->next = pNext;
00279     pNext->prev = pPrev;
00280   } else
00281   if (mRectCount > aCount)        // Remove unnecessary rectangles
00282   {
00283     PRUint32 RemoveCount = mRectCount - aCount;
00284     mRectCount = aCount;
00285     mCurRect = mRectListHead.next;
00286 
00287     while (RemoveCount--)
00288     {
00289       RgnRect* tmp = mCurRect;
00290       mCurRect = mCurRect->next;
00291       delete tmp;
00292     }
00293 
00294     mRectListHead.next = mCurRect;
00295     mCurRect->prev = &mRectListHead;
00296   }
00297 }
00298 
00299 
00300 // Save the entire chain of linked elements in 'prev' field of the RgnRect structure.
00301 // After that forward-only iterations using 'next' field could still be used.
00302 // Some elements from forward-only chain could be temporarily removed to optimize inner loops.
00303 // The original double linked state could be restored by call to RestoreLinkChain ().
00304 // Both functions despite size can be inline because they are called only from one function.
00305 
00306 inline void nsRegion::SaveLinkChain ()
00307 {
00308   RgnRect* pRect = &mRectListHead;
00309 
00310   do
00311   {
00312     pRect->prev = pRect->next;
00313     pRect = pRect->next;
00314   } while (pRect != &mRectListHead);
00315 }
00316 
00317 
00318 inline void nsRegion::RestoreLinkChain ()
00319 {
00320   RgnRect* pPrev = &mRectListHead;
00321   RgnRect* pRect = mRectListHead.next = mRectListHead.prev;
00322 
00323   while (pRect != &mRectListHead)
00324   {
00325     pRect->next = pRect->prev;
00326     pRect->prev = pPrev;
00327     pPrev = pRect;
00328     pRect = pRect->next;
00329   }
00330 
00331   mRectListHead.prev = pPrev;
00332 }
00333 
00334 
00335 // Insert node in right place of sorted list
00336 // If necessary then bounding rectangle could be updated and rectangle combined
00337 // with neighbour rectangles. This is usually done in Optimize ()
00338 
00339 void nsRegion::InsertInPlace (RgnRect* aRect, PRBool aOptimizeOnFly)
00340 {
00341   if (mRectCount == 0)
00342     InsertAfter (aRect, &mRectListHead);
00343   else
00344   {
00345     if (aRect->y > mCurRect->y)
00346     {
00347       mRectListHead.y = MAX_INT32;
00348 
00349       while (aRect->y > mCurRect->next->y)
00350         mCurRect = mCurRect->next;
00351 
00352       while (aRect->y == mCurRect->next->y && aRect->x > mCurRect->next->x)
00353         mCurRect = mCurRect->next;
00354 
00355       InsertAfter (aRect, mCurRect);
00356     } else
00357     if (aRect->y < mCurRect->y)
00358     {
00359       mRectListHead.y = MIN_INT32;
00360 
00361       while (aRect->y < mCurRect->prev->y)
00362         mCurRect = mCurRect->prev;
00363 
00364       while (aRect->y == mCurRect->prev->y && aRect->x < mCurRect->prev->x)
00365         mCurRect = mCurRect->prev;
00366 
00367       InsertBefore (aRect, mCurRect);
00368     } else
00369     {
00370       if (aRect->x > mCurRect->x)
00371       {
00372         mRectListHead.y = MAX_INT32;
00373 
00374         while (aRect->y == mCurRect->next->y && aRect->x > mCurRect->next->x)
00375           mCurRect = mCurRect->next;
00376 
00377         InsertAfter (aRect, mCurRect);
00378       } else
00379       {
00380         mRectListHead.y = MIN_INT32;
00381 
00382         while (aRect->y == mCurRect->prev->y && aRect->x < mCurRect->prev->x)
00383           mCurRect = mCurRect->prev;
00384 
00385         InsertBefore (aRect, mCurRect);
00386       }
00387     }
00388   }
00389 
00390 
00391   if (aOptimizeOnFly)
00392   {
00393     if (mRectCount == 1)
00394       mBoundRect = *mCurRect;
00395     else
00396     {
00397       mBoundRect.UnionRect (mBoundRect, *mCurRect);
00398 
00399       // Check if we can go left or up before starting to combine rectangles
00400       if ((mCurRect->y == mCurRect->prev->y && mCurRect->height == mCurRect->prev->height &&
00401            mCurRect->x == mCurRect->prev->XMost ()) ||
00402           (mCurRect->x == mCurRect->prev->x && mCurRect->width == mCurRect->prev->width &&
00403            mCurRect->y == mCurRect->prev->YMost ()) )
00404         mCurRect = mCurRect->prev;
00405 
00406       // Try to combine with rectangle on right side
00407       while (mCurRect->y == mCurRect->next->y && mCurRect->height == mCurRect->next->height &&
00408              mCurRect->XMost () == mCurRect->next->x)
00409       {
00410         mCurRect->width += mCurRect->next->width;
00411         delete Remove (mCurRect->next);
00412       }
00413 
00414       // Try to combine with rectangle under this one
00415       while (mCurRect->x == mCurRect->next->x && mCurRect->width == mCurRect->next->width &&
00416              mCurRect->YMost () == mCurRect->next->y)
00417       {
00418         mCurRect->height += mCurRect->next->height;
00419         delete Remove (mCurRect->next);
00420       }
00421     }
00422   }
00423 }
00424 
00425 
00426 nsRegion::RgnRect* nsRegion::Remove (RgnRect* aRect)
00427 {
00428   aRect->prev->next = aRect->next;
00429   aRect->next->prev = aRect->prev;
00430   mRectCount--;
00431 
00432   if (mCurRect == aRect)
00433     mCurRect = (aRect->next != &mRectListHead) ? aRect->next : aRect->prev;
00434 
00435   return aRect;
00436 }
00437 
00438 
00439 // Try to reduce the number of rectangles in complex region by combining with
00440 // surrounding ones on right and bottom sides of each rectangle in list.
00441 // Update bounding rectangle
00442 
00443 void nsRegion::Optimize ()
00444 {
00445   if (mRectCount == 0)
00446     mBoundRect.SetRect (0, 0, 0, 0);
00447   else
00448   {
00449     RgnRect* pRect = mRectListHead.next;
00450     PRInt32 xmost = mRectListHead.prev->XMost ();
00451     PRInt32 ymost = mRectListHead.prev->YMost ();
00452     mBoundRect.x = mRectListHead.next->x;
00453     mBoundRect.y = mRectListHead.next->y;
00454 
00455     while (pRect != &mRectListHead)
00456     {
00457       // Try to combine with rectangle on right side
00458       while (pRect->y == pRect->next->y && pRect->height == pRect->next->height &&
00459              pRect->XMost () == pRect->next->x)
00460       {
00461         pRect->width += pRect->next->width;
00462         delete Remove (pRect->next);
00463       }
00464 
00465       // Try to combine with rectangle under this one
00466       while (pRect->x == pRect->next->x && pRect->width == pRect->next->width &&
00467              pRect->YMost () == pRect->next->y)
00468       {
00469         pRect->height += pRect->next->height;
00470         delete Remove (pRect->next);
00471       }
00472 
00473       // Determine bound rectangle. Use fact that rectangles are sorted.
00474       if (pRect->x < mBoundRect.x) mBoundRect.x = pRect->x;
00475       if (pRect->XMost () > xmost) xmost = pRect->XMost ();
00476       if (pRect->YMost () > ymost) ymost = pRect->YMost ();
00477 
00478       pRect = pRect->next;
00479     }
00480 
00481     mBoundRect.width  = xmost - mBoundRect.x;
00482     mBoundRect.height = ymost - mBoundRect.y;
00483   }
00484 }
00485 
00486 
00487 // Move rectangles starting from 'aStartRect' till end of the list to the destionation region.
00488 // Important for temporary objects - instead of copying rectangles with Merge () and then
00489 // emptying region in destructor they could be moved to destination region in one step.
00490 
00491 void nsRegion::MoveInto (nsRegion& aDestRegion, const RgnRect* aStartRect)
00492 {
00493   RgnRect* pRect = NS_CONST_CAST (RgnRect*, aStartRect);
00494   RgnRect* pPrev = pRect->prev;
00495 
00496   while (pRect != &mRectListHead)
00497   {
00498     RgnRect* next = pRect->next;
00499     aDestRegion.InsertInPlace (pRect);
00500 
00501     mRectCount--;
00502     pRect = next;
00503   }
00504 
00505   pPrev->next = &mRectListHead;
00506   mRectListHead.prev = pPrev;
00507   mCurRect = mRectListHead.next;
00508 }
00509 
00510 
00511 // Merge two non-overlapping regions into one.
00512 // Automatically optimize region by calling Optimize ()
00513 
00514 void nsRegion::Merge (const nsRegion& aRgn1, const nsRegion& aRgn2)
00515 {
00516   if (aRgn1.mRectCount == 0)            // Region empty. Result is equal to other region
00517     Copy (aRgn2);
00518   else
00519   if (aRgn2.mRectCount == 0)            // Region empty. Result is equal to other region
00520     Copy (aRgn1);
00521   if (aRgn1.mRectCount == 1)            // Region is single rectangle. Optimize on fly
00522   {
00523     RgnRect* TmpRect = new RgnRect (*aRgn1.mRectListHead.next);
00524     Copy (aRgn2);
00525     InsertInPlace (TmpRect, PR_TRUE);
00526   } else
00527   if (aRgn2.mRectCount == 1)            // Region is single rectangle. Optimize on fly
00528   {
00529     RgnRect* TmpRect = new RgnRect (*aRgn2.mRectListHead.next);
00530     Copy (aRgn1);
00531     InsertInPlace (TmpRect, PR_TRUE);
00532   } else
00533   {
00534     const nsRegion* pCopyRegion, *pInsertRegion;
00535 
00536     // Determine which region contains more rectangles. Copy the larger one
00537     if (aRgn1.mRectCount >= aRgn2.mRectCount)
00538     {
00539       pCopyRegion = &aRgn1;
00540       pInsertRegion = &aRgn2;
00541     } else
00542     {
00543       pCopyRegion = &aRgn2;
00544       pInsertRegion = &aRgn1;
00545     }
00546 
00547     if (pInsertRegion == this)          // Do merge in-place
00548       pInsertRegion = pCopyRegion;
00549     else
00550       Copy (*pCopyRegion);
00551 
00552     const RgnRect* pSrcRect = pInsertRegion->mRectListHead.next;
00553 
00554     while (pSrcRect != &pInsertRegion->mRectListHead)
00555     {
00556       InsertInPlace (new RgnRect (*pSrcRect));
00557 
00558       pSrcRect = pSrcRect->next;
00559     }
00560 
00561     Optimize ();
00562   }
00563 }
00564 
00565 
00566 nsRegion& nsRegion::Copy (const nsRegion& aRegion)
00567 {
00568   if (&aRegion == this)
00569     return *this;
00570 
00571   if (aRegion.mRectCount == 0)
00572     SetEmpty ();
00573   else
00574   {
00575     SetToElements (aRegion.mRectCount);
00576 
00577     const RgnRect* pSrc = aRegion.mRectListHead.next;
00578     RgnRect* pDest = mRectListHead.next;
00579 
00580     while (pSrc != &aRegion.mRectListHead)
00581     {
00582       *pDest = *pSrc;
00583 
00584       pSrc  = pSrc->next;
00585       pDest = pDest->next;
00586     }
00587 
00588     mCurRect = mRectListHead.next;
00589     mBoundRect = aRegion.mBoundRect;
00590   }
00591 
00592   return *this;
00593 }
00594 
00595 
00596 nsRegion& nsRegion::Copy (const nsRect& aRect)
00597 {
00598   if (aRect.IsEmpty ())
00599     SetEmpty ();
00600   else
00601   {
00602     SetToElements (1);
00603     *mRectListHead.next = NS_STATIC_CAST (const RgnRect&, aRect);
00604     mBoundRect = NS_STATIC_CAST (const nsRectFast&, aRect);
00605   }
00606 
00607   return *this;
00608 }
00609 
00610 
00611 nsRegion& nsRegion::And (const nsRegion& aRgn1, const nsRegion& aRgn2)
00612 {
00613   if (&aRgn1 == &aRgn2)                                       // And with self
00614     Copy (aRgn1);
00615   else
00616   if (aRgn1.mRectCount == 0 || aRgn2.mRectCount == 0)         // If either region is empty then result is empty
00617     SetEmpty ();
00618   else
00619   {
00620     nsRectFast TmpRect;
00621 
00622     if (aRgn1.mRectCount == 1 && aRgn2.mRectCount == 1)       // Intersect rectangle with rectangle
00623     {
00624       TmpRect.IntersectRect (*aRgn1.mRectListHead.next, *aRgn2.mRectListHead.next);
00625       Copy (TmpRect);
00626     } else
00627     {
00628       if (!aRgn1.mBoundRect.Intersects (aRgn2.mBoundRect))    // Regions do not intersect
00629         SetEmpty ();
00630       else
00631       {
00632         // Region is simple rectangle and it fully overlays other region
00633         if (aRgn1.mRectCount == 1 && aRgn1.mBoundRect.Contains (aRgn2.mBoundRect))
00634           Copy (aRgn2);
00635         else
00636         // Region is simple rectangle and it fully overlays other region
00637         if (aRgn2.mRectCount == 1 && aRgn2.mBoundRect.Contains (aRgn1.mBoundRect))
00638           Copy (aRgn1);
00639         else
00640         {
00641           nsRegion TmpRegion;
00642           nsRegion* pSrcRgn1 = NS_CONST_CAST (nsRegion*, &aRgn1);
00643           nsRegion* pSrcRgn2 = NS_CONST_CAST (nsRegion*, &aRgn2);
00644 
00645           if (&aRgn1 == this)     // Copy region if it is both source and result
00646           {
00647             TmpRegion.Copy (aRgn1);
00648             pSrcRgn1 = &TmpRegion;
00649           }
00650 
00651           if (&aRgn2 == this)     // Copy region if it is both source and result
00652           {
00653             TmpRegion.Copy (aRgn2);
00654             pSrcRgn2 = &TmpRegion;
00655           }
00656 
00657           // For outer loop prefer region for which at least one rectangle is below other's bound rectangle
00658           if (pSrcRgn2->mRectListHead.prev->y >= pSrcRgn1->mBoundRect.YMost ())
00659           {
00660             nsRegion* Tmp = pSrcRgn1;
00661             pSrcRgn1 = pSrcRgn2;
00662             pSrcRgn2 = Tmp;
00663           }
00664 
00665 
00666           SetToElements (0);
00667           pSrcRgn2->SaveLinkChain ();
00668 
00669           pSrcRgn1->mRectListHead.y = MAX_INT32;
00670           pSrcRgn2->mRectListHead.y = MAX_INT32;
00671 
00672           for (RgnRect* pSrcRect1 = pSrcRgn1->mRectListHead.next ;
00673                pSrcRect1->y < pSrcRgn2->mBoundRect.YMost () ; pSrcRect1 = pSrcRect1->next)
00674           {
00675             if (pSrcRect1->Intersects (pSrcRgn2->mBoundRect))   // Rectangle intersects region. Process each rectangle
00676             {
00677               RgnRect* pPrev2 = &pSrcRgn2->mRectListHead;
00678 
00679               for (RgnRect* pSrcRect2 = pSrcRgn2->mRectListHead.next ;
00680                    pSrcRect2->y < pSrcRect1->YMost () ; pSrcRect2 = pSrcRect2->next)
00681               {
00682                 if (pSrcRect2->YMost () <= pSrcRect1->y)        // Rect2's bottom is above the top of Rect1.
00683                 {                                               // No successive rectangles in Rgn1 can intersect it.
00684                   pPrev2->next = pSrcRect2->next;               // Remove Rect2 from Rgn2's checklist
00685                   continue;
00686                 }
00687 
00688                 if (pSrcRect1->Contains (*pSrcRect2))           // Rect1 fully overlays Rect2.
00689                 {                                               // No any other rectangle in Rgn1 can intersect it.
00690                   pPrev2->next = pSrcRect2->next;               // Remove Rect2 from Rgn2's checklist
00691                   InsertInPlace (new RgnRect (*pSrcRect2));
00692                   continue;
00693                 }
00694 
00695 
00696                 if (TmpRect.IntersectRect (*pSrcRect1, *pSrcRect2))
00697                   InsertInPlace (new RgnRect (TmpRect));
00698 
00699                 pPrev2 = pSrcRect2;
00700               }
00701             }
00702           }
00703 
00704           pSrcRgn2->RestoreLinkChain ();
00705           Optimize ();
00706         }
00707       }
00708     }
00709   }
00710 
00711   return *this;
00712 }
00713 
00714 
00715 nsRegion& nsRegion::And (const nsRegion& aRegion, const nsRect& aRect)
00716 {
00717   // If either region or rectangle is empty then result is empty
00718   if (aRegion.mRectCount == 0 || aRect.IsEmpty ())
00719     SetEmpty ();
00720   else                            // Intersect region with rectangle
00721   {
00722     const nsRectFast& aRectFast = NS_STATIC_CAST (const nsRectFast&, aRect);
00723     nsRectFast TmpRect;
00724 
00725     if (aRegion.mRectCount == 1)  // Intersect rectangle with rectangle
00726     {
00727       TmpRect.IntersectRect (*aRegion.mRectListHead.next, aRectFast);
00728       Copy (TmpRect);
00729     } else                        // Intersect complex region with rectangle
00730     {
00731       if (!aRectFast.Intersects (aRegion.mBoundRect))   // Rectangle does not intersect region
00732         SetEmpty ();
00733       else
00734       {
00735         if (aRectFast.Contains (aRegion.mBoundRect))    // Rectangle fully overlays region
00736           Copy (aRegion);
00737         else
00738         {
00739           nsRegion TmpRegion;
00740           nsRegion* pSrcRegion = NS_CONST_CAST (nsRegion*, &aRegion);
00741 
00742           if (&aRegion == this)   // Copy region if it is both source and result
00743           {
00744             TmpRegion.Copy (aRegion);
00745             pSrcRegion = &TmpRegion;
00746           }
00747 
00748           SetToElements (0);
00749           pSrcRegion->mRectListHead.y = MAX_INT32;
00750 
00751           for (const RgnRect* pSrcRect = pSrcRegion->mRectListHead.next ;
00752                pSrcRect->y < aRectFast.YMost () ; pSrcRect = pSrcRect->next)
00753           {
00754             if (TmpRect.IntersectRect (*pSrcRect, aRectFast))
00755               InsertInPlace (new RgnRect (TmpRect));
00756           }
00757 
00758           Optimize ();
00759         }
00760       }
00761     }
00762   }
00763 
00764   return *this;
00765 }
00766 
00767 
00768 nsRegion& nsRegion::Or (const nsRegion& aRgn1, const nsRegion& aRgn2)
00769 {
00770   if (&aRgn1 == &aRgn2)                 // Or with self
00771     Copy (aRgn1);
00772   else
00773   if (aRgn1.mRectCount == 0)            // Region empty. Result is equal to other region
00774     Copy (aRgn2);
00775   else
00776   if (aRgn2.mRectCount == 0)            // Region empty. Result is equal to other region
00777     Copy (aRgn1);
00778   else
00779   {
00780     if (!aRgn1.mBoundRect.Intersects (aRgn2.mBoundRect))  // Regions do not intersect
00781       Merge (aRgn1, aRgn2);
00782     else
00783     {
00784       // Region is simple rectangle and it fully overlays other region
00785       if (aRgn1.mRectCount == 1 && aRgn1.mBoundRect.Contains (aRgn2.mBoundRect))
00786         Copy (aRgn1);
00787       else
00788       // Region is simple rectangle and it fully overlays other region
00789       if (aRgn2.mRectCount == 1 && aRgn2.mBoundRect.Contains (aRgn1.mBoundRect))
00790         Copy (aRgn2);
00791       else
00792       {
00793         nsRegion TmpRegion;
00794         aRgn1.SubRegion (aRgn2, TmpRegion);               // Get only parts of region which not overlap the other region
00795         Copy (aRgn2);
00796         TmpRegion.MoveInto (*this);
00797         Optimize ();
00798       }
00799     }
00800   }
00801 
00802   return *this;
00803 }
00804 
00805 
00806 nsRegion& nsRegion::Or (const nsRegion& aRegion, const nsRect& aRect)
00807 {
00808   if (aRegion.mRectCount == 0)          // Region empty. Result is equal to rectangle
00809     Copy (aRect);
00810   else
00811   if (aRect.IsEmpty ())                 // Rectangle is empty. Result is equal to region
00812     Copy (aRegion);
00813   else
00814   {
00815     const nsRectFast& aRectFast = NS_STATIC_CAST (const nsRectFast&, aRect);
00816 
00817     if (!aRectFast.Intersects (aRegion.mBoundRect))     // Rectangle does not intersect region
00818     {
00819       Copy (aRegion);
00820       InsertInPlace (new RgnRect (aRectFast), PR_TRUE);
00821     } else
00822     {
00823       // Region is simple rectangle and it fully overlays rectangle
00824       if (aRegion.mRectCount == 1 && aRegion.mBoundRect.Contains (aRectFast))
00825         Copy (aRegion);
00826       else
00827       if (aRectFast.Contains (aRegion.mBoundRect))      // Rectangle fully overlays region
00828         Copy (aRectFast);
00829       else
00830       {
00831         aRegion.SubRect (aRectFast, *this);             // Exclude from region parts that overlap the rectangle
00832         InsertInPlace (new RgnRect (aRectFast));
00833         Optimize ();
00834       }
00835     }
00836   }
00837 
00838   return *this;
00839 }
00840 
00841 
00842 nsRegion& nsRegion::Xor (const nsRegion& aRgn1, const nsRegion& aRgn2)
00843 {
00844   if (&aRgn1 == &aRgn2)                 // Xor with self
00845     SetEmpty ();
00846   else
00847   if (aRgn1.mRectCount == 0)            // Region empty. Result is equal to other region
00848     Copy (aRgn2);
00849   else
00850   if (aRgn2.mRectCount == 0)            // Region empty. Result is equal to other region
00851     Copy (aRgn1);
00852   else
00853   {
00854     if (!aRgn1.mBoundRect.Intersects (aRgn2.mBoundRect))      // Regions do not intersect
00855       Merge (aRgn1, aRgn2);
00856     else
00857     {
00858       // Region is simple rectangle and it fully overlays other region
00859       if (aRgn1.mRectCount == 1 && aRgn1.mBoundRect.Contains (aRgn2.mBoundRect))
00860       {
00861         aRgn1.SubRegion (aRgn2, *this);
00862         Optimize ();
00863       } else
00864       // Region is simple rectangle and it fully overlays other region
00865       if (aRgn2.mRectCount == 1 && aRgn2.mBoundRect.Contains (aRgn1.mBoundRect))
00866       {
00867         aRgn2.SubRegion (aRgn1, *this);
00868         Optimize ();
00869       } else
00870       {
00871         nsRegion TmpRegion;
00872         aRgn1.SubRegion (aRgn2, TmpRegion);
00873         aRgn2.SubRegion (aRgn1, *this);
00874         TmpRegion.MoveInto (*this);
00875         Optimize ();
00876       }
00877     }
00878   }
00879 
00880   return *this;
00881 }
00882 
00883 
00884 nsRegion& nsRegion::Xor (const nsRegion& aRegion, const nsRect& aRect)
00885 {
00886   if (aRegion.mRectCount == 0)          // Region empty. Result is equal to rectangle
00887     Copy (aRect);
00888   else
00889   if (aRect.IsEmpty ())                 // Rectangle is empty. Result is equal to region
00890     Copy (aRegion);
00891   else
00892   {
00893     const nsRectFast& aRectFast = NS_STATIC_CAST (const nsRectFast&, aRect);
00894 
00895     if (!aRectFast.Intersects (aRegion.mBoundRect))     // Rectangle does not intersect region
00896     {
00897       Copy (aRegion);
00898       InsertInPlace (new RgnRect (aRectFast), PR_TRUE);
00899     } else
00900     {
00901       // Region is simple rectangle and it fully overlays rectangle
00902       if (aRegion.mRectCount == 1 && aRegion.mBoundRect.Contains (aRectFast))
00903       {
00904         aRegion.SubRect (aRectFast, *this);
00905         Optimize ();
00906       } else
00907       if (aRectFast.Contains (aRegion.mBoundRect))      // Rectangle fully overlays region
00908       {
00909         nsRegion TmpRegion;
00910         TmpRegion.Copy (aRectFast);
00911         TmpRegion.SubRegion (aRegion, *this);
00912         Optimize ();
00913       } else
00914       {
00915         nsRegion TmpRegion;
00916         TmpRegion.Copy (aRectFast);
00917         TmpRegion.SubRegion (aRegion, TmpRegion);
00918         aRegion.SubRect (aRectFast, *this);
00919         TmpRegion.MoveInto (*this);
00920         Optimize ();
00921       }
00922     }
00923   }
00924 
00925   return *this;
00926 }
00927 
00928 
00929 nsRegion& nsRegion::Sub (const nsRegion& aRgn1, const nsRegion& aRgn2)
00930 {
00931   if (&aRgn1 == &aRgn2)         // Sub from self
00932     SetEmpty ();
00933   else
00934   if (aRgn1.mRectCount == 0)    // If source is empty then result is empty, too
00935     SetEmpty ();
00936   else
00937   if (aRgn2.mRectCount == 0)    // Nothing to subtract
00938     Copy (aRgn1);
00939   else
00940   {
00941     if (!aRgn1.mBoundRect.Intersects (aRgn2.mBoundRect))   // Regions do not intersect
00942       Copy (aRgn1);
00943     else
00944     {
00945       aRgn1.SubRegion (aRgn2, *this);
00946       Optimize ();
00947     }
00948   }
00949 
00950   return *this;
00951 }
00952 
00953 
00954 nsRegion& nsRegion::Sub (const nsRegion& aRegion, const nsRect& aRect)
00955 {
00956   if (aRegion.mRectCount == 0)    // If source is empty then result is empty, too
00957     SetEmpty ();
00958   else
00959   if (aRect.IsEmpty ())           // Nothing to subtract
00960     Copy (aRegion);
00961   else
00962   {
00963     const nsRectFast& aRectFast = NS_STATIC_CAST (const nsRectFast&, aRect);
00964 
00965     if (!aRectFast.Intersects (aRegion.mBoundRect))   // Rectangle does not intersect region
00966       Copy (aRegion);
00967     else
00968     {
00969       if (aRectFast.Contains (aRegion.mBoundRect))    // Rectangle fully overlays region
00970         SetEmpty ();
00971       else
00972       {
00973         aRegion.SubRect (aRectFast, *this);
00974         Optimize ();
00975       }
00976     }
00977   }
00978 
00979   return *this;
00980 }
00981 
00982 
00983 // Subtract region from current region.
00984 // Both regions are non-empty and they intersect each other.
00985 // Result could be empty region if aRgn2 is rectangle that fully overlays aRgn1.
00986 // Optimize () is not called on exit (bound rectangle is not updated).
00987 
00988 void nsRegion::SubRegion (const nsRegion& aRegion, nsRegion& aResult) const
00989 {
00990   if (aRegion.mRectCount == 1)    // Subtract simple rectangle
00991   {
00992     if (aRegion.mBoundRect.Contains (mBoundRect))
00993       aResult.SetEmpty ();
00994     else
00995       SubRect (*aRegion.mRectListHead.next, aResult);
00996   } else
00997   {
00998     nsRegion TmpRegion, CompletedRegion;
00999     const nsRegion* pSubRgn = &aRegion;
01000 
01001     if (&aResult == &aRegion)     // Copy region if it is both source and result
01002     {
01003       TmpRegion.Copy (aRegion);
01004       pSubRgn = &TmpRegion;
01005     }
01006 
01007     const RgnRect* pSubRect = pSubRgn->mRectListHead.next;
01008 
01009     SubRect (*pSubRect, aResult, CompletedRegion);
01010     pSubRect = pSubRect->next;
01011 
01012     while (pSubRect != &pSubRgn->mRectListHead)
01013     {
01014       aResult.SubRect (*pSubRect, aResult, CompletedRegion);
01015       pSubRect = pSubRect->next;
01016     }
01017 
01018     CompletedRegion.MoveInto (aResult);
01019   }
01020 }
01021 
01022 
01023 // Subtract rectangle from current region.
01024 // Both region and rectangle are non-empty and they intersect each other.
01025 // Result could be empty region if aRect fully overlays aRegion.
01026 // Could be called repeatedly with 'this' as input and result - bound rectangle is not known.
01027 // Optimize () is not called on exit (bound rectangle is not updated).
01028 //
01029 // aCompleted is filled with rectangles which are already checked and could be safely
01030 // removed from further examination in case aRect rectangles come from ordered list.
01031 // aCompleted is not automatically emptied. aCompleted and aResult could be the same region.
01032 
01033 void nsRegion::SubRect (const nsRectFast& aRect, nsRegion& aResult, nsRegion& aCompleted) const
01034 {
01035   nsRegion TmpRegion;
01036   const nsRegion* pSrcRegion = this;
01037 
01038   if (&aResult == this)           // Copy region if it is both source and result
01039   {
01040     TmpRegion.Copy (*this);
01041     pSrcRegion = &TmpRegion;
01042   }
01043 
01044   aResult.SetToElements (0);
01045 
01046   (NS_CONST_CAST (nsRegion*, pSrcRegion))->mRectListHead.y = MAX_INT32;
01047   const RgnRect* pSrcRect = pSrcRegion->mRectListHead.next;
01048 
01049   for ( ; pSrcRect->y < aRect.YMost () ; pSrcRect = pSrcRect->next)
01050   {
01051     nsRectFast TmpRect;
01052 
01053     // If bottom of current rectangle is above the top of aRect then this rectangle
01054     // could be moved to aCompleted region. Successive aRect rectangles from ordered
01055     // list do not have to check this rectangle again.
01056     if (pSrcRect->YMost () <= aRect.y)
01057     {
01058       aCompleted.InsertInPlace (new RgnRect (*pSrcRect));
01059       continue;
01060     }
01061 
01062     if (!TmpRect.IntersectRect (*pSrcRect, aRect))
01063       aResult.InsertInPlace (new RgnRect (*pSrcRect));
01064     else
01065     {
01066       // Rectangle A. Subtract from this rectangle B
01067       const nscoord ax  = pSrcRect->x;
01068       const nscoord axm = pSrcRect->XMost ();
01069       const nscoord aw  = pSrcRect->width;
01070       const nscoord ay  = pSrcRect->y;
01071       const nscoord aym = pSrcRect->YMost ();
01072       const nscoord ah  = pSrcRect->height;
01073       // Rectangle B. Subtract this from rectangle A
01074       const nscoord bx  = aRect.x;
01075       const nscoord bxm = aRect.XMost ();
01076       const nscoord by  = aRect.y;
01077       const nscoord bym = aRect.YMost ();
01078       // Rectangle I. Area where rectangles A and B intersect
01079       const nscoord ix  = TmpRect.x;
01080       const nscoord ixm = TmpRect.XMost ();
01081       const nscoord iy  = TmpRect.y;
01082       const nscoord iym = TmpRect.YMost ();
01083       const nscoord ih  = TmpRect.height;
01084 
01085       // There are 16 combinations how rectangles could intersect
01086 
01087       if (bx <= ax && by <= ay)
01088       {
01089         if (bxm < axm && bym < aym)     // 1.
01090         {
01091           aResult.InsertInPlace (new RgnRect (ixm, ay, axm - ixm, ih));
01092           aResult.InsertInPlace (new RgnRect (ax, iym, aw, aym - iym));
01093         } else
01094         if (bxm >= axm && bym < aym)    // 2.
01095         {
01096           aResult.InsertInPlace (new RgnRect (ax, iym, aw, aym - iym));
01097         } else
01098         if (bxm < axm && bym >= aym)    // 3.
01099         {
01100           aResult.InsertInPlace (new RgnRect (ixm, ay, axm - ixm, ah));
01101         } else
01102         if (*pSrcRect == aRect)         // 4. subset
01103         {                               // Current rectangle is equal to aRect
01104           break;                        // No any other rectangle in region can intersect it
01105         }
01106       } else
01107       if (bx > ax && by <= ay)
01108       {
01109         if (bxm < axm && bym < aym)     // 5.
01110         {
01111           aResult.InsertInPlace (new RgnRect (ax, ay, ix - ax, ih));
01112           aResult.InsertInPlace (new RgnRect (ixm, ay, axm - ixm, ih));
01113           aResult.InsertInPlace (new RgnRect (ax, iym, aw, aym - iym));
01114         } else
01115         if (bxm >= axm && bym < aym)    // 6.
01116         {
01117           aResult.InsertInPlace (new RgnRect (ax, ay, ix - ax, ih));
01118           aResult.InsertInPlace (new RgnRect (ax, iym, aw, aym - iym));
01119         } else
01120         if (bxm < axm && bym >= aym)    // 7.
01121         {
01122           aResult.InsertInPlace (new RgnRect (ax, ay, ix - ax, ah));
01123           aResult.InsertInPlace (new RgnRect (ixm, ay, axm - ixm, ah));
01124         } else
01125         if (bxm >= axm && bym >= aym)   // 8.
01126         {
01127           aResult.InsertInPlace (new RgnRect (ax, ay, ix - ax, ah));
01128         }
01129       } else
01130       if (bx <= ax && by > ay)
01131       {
01132         if (bxm < axm && bym < aym)     // 9.
01133         {
01134           aResult.InsertInPlace (new RgnRect (ax, ay, aw, iy - ay));
01135           aResult.InsertInPlace (new RgnRect (ixm, iy, axm - ixm, ih));
01136           aResult.InsertInPlace (new RgnRect (ax, iym, aw, aym - iym));
01137         } else
01138         if (bxm >= axm && bym < aym)    // 10.
01139         {
01140           aResult.InsertInPlace (new RgnRect (ax, ay, aw, iy - ay));
01141           aResult.InsertInPlace (new RgnRect (ax, iym, aw, aym - iym));
01142         } else
01143         if (bxm < axm && bym >= aym)    // 11.
01144         {
01145           aResult.InsertInPlace (new RgnRect (ax, ay, aw, iy - ay));
01146           aResult.InsertInPlace (new RgnRect (ixm, iy, axm - ixm, ih));
01147         } else
01148         if (bxm >= axm && bym >= aym)   // 12.
01149         {
01150           aResult.InsertInPlace (new RgnRect (ax, ay, aw, iy - ay));
01151         }
01152       } else
01153       if (bx > ax && by > ay)
01154       {
01155         if (bxm < axm && bym < aym)     // 13.
01156         {
01157           aResult.InsertInPlace (new RgnRect (ax, ay, aw, iy - ay));
01158           aResult.InsertInPlace (new RgnRect (ax, iy, ix - ax, ih));
01159           aResult.InsertInPlace (new RgnRect (ixm, iy, axm - ixm, ih));
01160           aResult.InsertInPlace (new RgnRect (ax, iym, aw, aym - iym));
01161 
01162           // Current rectangle fully overlays aRect. No any other rectangle can intersect it.
01163           break;
01164         } else
01165         if (bxm >= axm && bym < aym)    // 14.
01166         {
01167           aResult.InsertInPlace (new RgnRect (ax, ay, aw, iy - ay));
01168           aResult.InsertInPlace (new RgnRect (ax, iy, ix - ax, ih));
01169           aResult.InsertInPlace (new RgnRect (ax, iym, aw, aym - iym));
01170         } else
01171         if (bxm < axm && bym >= aym)    // 15.
01172         {
01173           aResult.InsertInPlace (new RgnRect (ax, ay, aw, iy - ay));
01174           aResult.InsertInPlace (new RgnRect (ax, iy, ix - ax, ih));
01175           aResult.InsertInPlace (new RgnRect (ixm, iy, axm - ixm, ih));
01176         } else
01177         if (bxm >= axm && bym >= aym)   // 16.
01178         {
01179           aResult.InsertInPlace (new RgnRect (ax, ay, aw, iy - ay));
01180           aResult.InsertInPlace (new RgnRect (ax, iy, ix - ax, ih));
01181         }
01182       }
01183     }
01184   }
01185 
01186   // Just copy remaining rectangles in region which are below aRect and can't intersect it.
01187   // If rectangles are in temporary region then they could be moved.
01188   if (pSrcRegion == &TmpRegion)
01189     TmpRegion.MoveInto (aResult, pSrcRect);
01190   else
01191   {
01192     while (pSrcRect != &pSrcRegion->mRectListHead)
01193     {
01194       aResult.InsertInPlace (new RgnRect (*pSrcRect));
01195       pSrcRect = pSrcRect->next;
01196     }
01197   }
01198 }
01199 
01200 
01201 PRBool nsRegion::IsEqual (const nsRegion& aRegion) const
01202 {
01203   if (mRectCount == 0)
01204     return (aRegion.mRectCount == 0) ? PR_TRUE : PR_FALSE;
01205 
01206   if (aRegion.mRectCount == 0)
01207     return (mRectCount == 0) ? PR_TRUE : PR_FALSE;
01208 
01209   if (mRectCount == 1 && aRegion.mRectCount == 1) // Both regions are simple rectangles
01210     return (*mRectListHead.next == *aRegion.mRectListHead.next);
01211   else                                            // At least one is complex region.
01212   {
01213     if (mBoundRect != aRegion.mBoundRect)         // If regions are equal then bounding rectangles should match
01214       return PR_FALSE;
01215     else
01216     {
01217       nsRegion TmpRegion;
01218       TmpRegion.Xor (*this, aRegion);             // Get difference between two regions
01219 
01220       return (TmpRegion.mRectCount == 0);
01221     }
01222   }
01223 }
01224 
01225 
01226 void nsRegion::MoveBy (nsPoint aPt)
01227 {
01228   if (aPt.x || aPt.y)
01229   {
01230     RgnRect* pRect = mRectListHead.next;
01231 
01232     while (pRect != &mRectListHead)
01233     {
01234       pRect->MoveBy (aPt.x, aPt.y);
01235       pRect = pRect->next;
01236     }
01237 
01238     mBoundRect.MoveBy (aPt.x, aPt.y);
01239   }
01240 }
01241 
01242 void nsRegion::SimplifyOutward (PRUint32 aMaxRects)
01243 {
01244   NS_ASSERTION(aMaxRects >= 1, "Invalid max rect count");
01245   
01246   if (mRectCount <= aMaxRects)
01247     return;
01248 
01249   *this = GetBounds();
01250 }
01251 
01252 void nsRegion::SimplifyInward (PRUint32 aMaxRects)
01253 {
01254   NS_ASSERTION(aMaxRects >= 1, "Invalid max rect count");
01255 
01256   if (mRectCount <= aMaxRects)
01257     return;
01258 
01259   SetEmpty();
01260 }