1 : /* ***** BEGIN LICENSE BLOCK *****
2 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 : *
4 : * The contents of this file are subject to the Mozilla Public License Version
5 : * 1.1 (the "License"); you may not use this file except in compliance with
6 : * the License. You may obtain a copy of the License at
7 : * http://www.mozilla.org/MPL/
8 : *
9 : * Software distributed under the License is distributed on an "AS IS" basis,
10 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 : * for the specific language governing rights and limitations under the
12 : * License.
13 : *
14 : * The Original Code is mozilla.org code.
15 : *
16 : * The Initial Developer of the Original Code is
17 : * Dainis Jonitis, <Dainis_Jonitis@swh-t.lv>.
18 : * Portions created by the Initial Developer are Copyright (C) 2001
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : *
23 : * Alternatively, the contents of this file may be used under the terms of
24 : * either of the GNU General Public License Version 2 or later (the "GPL"),
25 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 : * in which case the provisions of the GPL or the LGPL are applicable instead
27 : * of those above. If you wish to allow use of your version of this file only
28 : * under the terms of either the GPL or the LGPL, and not to allow others to
29 : * use your version of this file under the terms of the MPL, indicate your
30 : * decision by deleting the provisions above and replace them with the notice
31 : * and other provisions required by the GPL or the LGPL. If you do not delete
32 : * the provisions above, a recipient may use your version of this file under
33 : * the terms of any one of the MPL, the GPL or the LGPL.
34 : *
35 : * ***** END LICENSE BLOCK ***** */
36 :
37 :
38 : #ifndef nsRegion_h__
39 : #define nsRegion_h__
40 :
41 :
42 : #include "nsRect.h"
43 : #include "nsPoint.h"
44 :
45 : class nsIntRegion;
46 :
47 : /**
48 : * Implementation of regions.
49 : * A region is represented as circular double-linked list of nsRegion::RgnRect structures.
50 : * Rectangles in this list do not overlap and are sorted by (y, x) coordinates.
51 : *
52 : * nsRegions use nscoord coordinates and nsRects.
53 : */
54 : class NS_GFX nsRegion
55 : {
56 : friend class nsRegionRectIterator;
57 : friend class RgnRectMemoryAllocator;
58 :
59 :
60 : // Special version of nsRect structure for speed optimizations in nsRegion code.
61 : // Most important functions could be made inline and be sure that passed rectangles
62 : // will always be non-empty.
63 : //
64 : // Do not add any new member variables to this structure!
65 : // Otherwise it will break casts from nsRect to nsRectFast, which expect data parts to be identical.
66 : struct nsRectFast : public nsRect
67 0 : {
68 0 : nsRectFast () {} // No need to call parent constructor to set default values
69 : nsRectFast (PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight) : nsRect (aX, aY, aWidth, aHeight) {}
70 : nsRectFast (const nsRect& aRect) : nsRect (aRect) {}
71 :
72 : // Override nsRect methods to make them inline. Do not check for emptiness.
73 : inline bool Contains (const nsRect& aRect) const;
74 : inline bool Intersects (const nsRect& aRect) const;
75 : inline bool IntersectRect (const nsRect& aRect1, const nsRect& aRect2);
76 : inline void UnionRect (const nsRect& aRect1, const nsRect& aRect2);
77 : };
78 :
79 :
80 : struct RgnRect : public nsRectFast
81 0 : {
82 : RgnRect* prev;
83 : RgnRect* next;
84 :
85 0 : RgnRect () {} // No need to call parent constructor to set default values
86 : RgnRect (PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight) : nsRectFast (aX, aY, aWidth, aHeight) {}
87 : RgnRect (const nsRectFast& aRect) : nsRectFast (aRect) {}
88 :
89 : void* operator new (size_t) CPP_THROW_NEW;
90 : void operator delete (void* aRect, size_t);
91 :
92 : RgnRect& operator = (const RgnRect& aRect) // Do not overwrite prev/next pointers
93 : {
94 : x = aRect.x;
95 : y = aRect.y;
96 : width = aRect.width;
97 : height = aRect.height;
98 : return *this;
99 : }
100 : };
101 :
102 :
103 : public:
104 0 : nsRegion () { Init (); }
105 0 : nsRegion (const nsRect& aRect) { Init (); Copy (aRect); }
106 0 : nsRegion (const nsRegion& aRegion) { Init (); Copy (aRegion); }
107 0 : ~nsRegion () { SetToElements (0); }
108 0 : nsRegion& operator = (const nsRect& aRect) { Copy (aRect); return *this; }
109 0 : nsRegion& operator = (const nsRegion& aRegion) { Copy (aRegion); return *this; }
110 :
111 :
112 : nsRegion& And (const nsRegion& aRgn1, const nsRegion& aRgn2);
113 : nsRegion& And (const nsRegion& aRegion, const nsRect& aRect);
114 0 : nsRegion& And (const nsRect& aRect, const nsRegion& aRegion)
115 : {
116 0 : return And (aRegion, aRect);
117 : }
118 0 : nsRegion& And (const nsRect& aRect1, const nsRect& aRect2)
119 : {
120 0 : nsRect TmpRect;
121 :
122 0 : TmpRect.IntersectRect (aRect1, aRect2);
123 0 : return Copy (TmpRect);
124 : }
125 :
126 : nsRegion& Or (const nsRegion& aRgn1, const nsRegion& aRgn2);
127 : nsRegion& Or (const nsRegion& aRegion, const nsRect& aRect);
128 : nsRegion& Or (const nsRect& aRect, const nsRegion& aRegion)
129 : {
130 : return Or (aRegion, aRect);
131 : }
132 0 : nsRegion& Or (const nsRect& aRect1, const nsRect& aRect2)
133 : {
134 0 : Copy (aRect1);
135 0 : return Or (*this, aRect2);
136 : }
137 :
138 : nsRegion& Xor (const nsRegion& aRgn1, const nsRegion& aRgn2);
139 : nsRegion& Xor (const nsRegion& aRegion, const nsRect& aRect);
140 : nsRegion& Xor (const nsRect& aRect, const nsRegion& aRegion)
141 : {
142 : return Xor (aRegion, aRect);
143 : }
144 : nsRegion& Xor (const nsRect& aRect1, const nsRect& aRect2)
145 : {
146 : Copy (aRect1);
147 : return Xor (*this, aRect2);
148 : }
149 :
150 : nsRegion& Sub (const nsRegion& aRgn1, const nsRegion& aRgn2);
151 : nsRegion& Sub (const nsRegion& aRegion, const nsRect& aRect);
152 0 : nsRegion& Sub (const nsRect& aRect, const nsRegion& aRegion)
153 : {
154 0 : return Sub (nsRegion (aRect), aRegion);
155 : }
156 : nsRegion& Sub (const nsRect& aRect1, const nsRect& aRect2)
157 : {
158 : Copy (aRect1);
159 : return Sub (*this, aRect2);
160 : }
161 :
162 : bool Contains (const nsRect& aRect) const;
163 : bool Contains (const nsRegion& aRgn) const;
164 : bool Intersects (const nsRect& aRect) const;
165 :
166 0 : void MoveBy (PRInt32 aXOffset, PRInt32 aYOffset)
167 : {
168 0 : MoveBy (nsPoint (aXOffset, aYOffset));
169 0 : }
170 : void MoveBy (nsPoint aPt);
171 0 : void SetEmpty ()
172 : {
173 0 : SetToElements (0);
174 0 : mBoundRect.SetRect (0, 0, 0, 0);
175 0 : }
176 :
177 0 : bool IsEmpty () const { return mRectCount == 0; }
178 : bool IsComplex () const { return mRectCount > 1; }
179 : bool IsEqual (const nsRegion& aRegion) const;
180 0 : PRUint32 GetNumRects () const { return mRectCount; }
181 0 : const nsRect& GetBounds () const { return mBoundRect; }
182 : // Converts this region from aFromAPP, an appunits per pixel ratio, to
183 : // aToAPP. This applies nsRect::ConvertAppUnitsRoundOut/In to each rect of
184 : // the region.
185 : nsRegion ConvertAppUnitsRoundOut (PRInt32 aFromAPP, PRInt32 aToAPP) const;
186 : nsRegion ConvertAppUnitsRoundIn (PRInt32 aFromAPP, PRInt32 aToAPP) const;
187 : nsRegion& ScaleRoundOut(float aXScale, float aYScale);
188 : nsRegion& ScaleInverseRoundOut(float aXScale, float aYScale);
189 : nsIntRegion ScaleToOutsidePixels (float aXScale, float aYScale, nscoord aAppUnitsPerPixel) const;
190 : nsIntRegion ToOutsidePixels (nscoord aAppUnitsPerPixel) const;
191 : nsIntRegion ToNearestPixels (nscoord aAppUnitsPerPixel) const;
192 :
193 : /**
194 : * Gets the largest rectangle contained in the region.
195 : * @param aContainingRect if non-empty, we choose a rectangle that
196 : * maximizes the area intersecting with aContainingRect (and break ties by
197 : * then choosing the largest rectangle overall)
198 : */
199 : nsRect GetLargestRectangle (const nsRect& aContainingRect = nsRect()) const;
200 :
201 : /**
202 : * Make sure the region has at most aMaxRects by adding area to it
203 : * if necessary. The simplified region will be a superset of the
204 : * original region. The simplified region's bounding box will be
205 : * the same as for the current region.
206 : */
207 : void SimplifyOutward (PRUint32 aMaxRects);
208 : /**
209 : * Make sure the region has at most aMaxRects by removing area from
210 : * it if necessary. The simplified region will be a subset of the
211 : * original region.
212 : */
213 : void SimplifyInward (PRUint32 aMaxRects);
214 : /**
215 : * Efficiently try to remove a rectangle from this region. The actual
216 : * area removed could be some sub-area contained by the rectangle
217 : * (even possibly nothing at all).
218 : *
219 : * We remove all rectangles that are contained by aRect.
220 : */
221 : void SimpleSubtract (const nsRect& aRect);
222 : /**
223 : * Efficiently try to remove a region from this region. The actual
224 : * area removed could be some sub-area contained by aRegion
225 : * (even possibly nothing at all).
226 : *
227 : * We remove all rectangles of this region that are contained by
228 : * a rectangle of aRegion.
229 : */
230 : void SimpleSubtract (const nsRegion& aRegion);
231 :
232 : /**
233 : * Initialize any static data associated with nsRegion.
234 : */
235 : static nsresult InitStatic();
236 :
237 : /**
238 : * Deinitialize static data.
239 : */
240 : static void ShutdownStatic();
241 :
242 : private:
243 : PRUint32 mRectCount;
244 : RgnRect* mCurRect;
245 : RgnRect mRectListHead;
246 : nsRectFast mBoundRect;
247 :
248 : void Init ();
249 : nsRegion& Copy (const nsRegion& aRegion);
250 : nsRegion& Copy (const nsRect& aRect);
251 : void InsertBefore (RgnRect* aNewRect, RgnRect* aRelativeRect);
252 : void InsertAfter (RgnRect* aNewRect, RgnRect* aRelativeRect);
253 : void SetToElements (PRUint32 aCount);
254 : RgnRect* Remove (RgnRect* aRect);
255 : void InsertInPlace (RgnRect* aRect, bool aOptimizeOnFly = false);
256 : inline void SaveLinkChain ();
257 : inline void RestoreLinkChain ();
258 : void Optimize ();
259 : void SubRegion (const nsRegion& aRegion, nsRegion& aResult) const;
260 : void SubRect (const nsRectFast& aRect, nsRegion& aResult, nsRegion& aCompleted) const;
261 : void SubRect (const nsRectFast& aRect, nsRegion& aResult) const
262 : { SubRect (aRect, aResult, aResult); }
263 : void Merge (const nsRegion& aRgn1, const nsRegion& aRgn2);
264 : void MoveInto (nsRegion& aDestRegion, const RgnRect* aStartRect);
265 : void MoveInto (nsRegion& aDestRegion)
266 : { MoveInto (aDestRegion, mRectListHead.next); }
267 : nsIntRegion ToPixels(nscoord aAppUnitsPerPixel, bool aOutsidePixels) const;
268 : };
269 :
270 :
271 :
272 : // Allow read-only access to region rectangles by iterating the list
273 :
274 : class NS_GFX nsRegionRectIterator
275 : {
276 : const nsRegion* mRegion;
277 : const nsRegion::RgnRect* mCurPtr;
278 :
279 : public:
280 0 : nsRegionRectIterator (const nsRegion& aRegion)
281 : {
282 0 : mRegion = &aRegion;
283 0 : mCurPtr = &aRegion.mRectListHead;
284 0 : }
285 :
286 0 : const nsRect* Next ()
287 : {
288 0 : mCurPtr = mCurPtr->next;
289 0 : return (mCurPtr != &mRegion->mRectListHead) ? mCurPtr : nsnull;
290 : }
291 :
292 : const nsRect* Prev ()
293 : {
294 : mCurPtr = mCurPtr->prev;
295 : return (mCurPtr != &mRegion->mRectListHead) ? mCurPtr : nsnull;
296 : }
297 :
298 : void Reset ()
299 : {
300 : mCurPtr = &mRegion->mRectListHead;
301 : }
302 : };
303 :
304 : /**
305 : * nsIntRegions use PRInt32 coordinates and nsIntRects.
306 : */
307 : class NS_GFX nsIntRegion
308 0 : {
309 : friend class nsIntRegionRectIterator;
310 :
311 : public:
312 0 : nsIntRegion () {}
313 0 : nsIntRegion (const nsIntRect& aRect) : mImpl (ToRect(aRect)) {}
314 0 : nsIntRegion (const nsIntRegion& aRegion) : mImpl (aRegion.mImpl) {}
315 0 : nsIntRegion& operator = (const nsIntRect& aRect) { mImpl = ToRect (aRect); return *this; }
316 0 : nsIntRegion& operator = (const nsIntRegion& aRegion) { mImpl = aRegion.mImpl; return *this; }
317 :
318 0 : bool operator==(const nsIntRegion& aRgn) const
319 : {
320 0 : return IsEqual(aRgn);
321 : }
322 :
323 0 : nsIntRegion& And (const nsIntRegion& aRgn1, const nsIntRegion& aRgn2)
324 : {
325 0 : mImpl.And (aRgn1.mImpl, aRgn2.mImpl);
326 0 : return *this;
327 : }
328 0 : nsIntRegion& And (const nsIntRegion& aRegion, const nsIntRect& aRect)
329 : {
330 0 : mImpl.And (aRegion.mImpl, ToRect (aRect));
331 0 : return *this;
332 : }
333 : nsIntRegion& And (const nsIntRect& aRect, const nsIntRegion& aRegion)
334 : {
335 : return And (aRegion, aRect);
336 : }
337 0 : nsIntRegion& And (const nsIntRect& aRect1, const nsIntRect& aRect2)
338 : {
339 0 : nsIntRect TmpRect;
340 :
341 0 : TmpRect.IntersectRect (aRect1, aRect2);
342 0 : mImpl = ToRect (TmpRect);
343 0 : return *this;
344 : }
345 :
346 0 : nsIntRegion& Or (const nsIntRegion& aRgn1, const nsIntRegion& aRgn2)
347 : {
348 0 : mImpl.Or (aRgn1.mImpl, aRgn2.mImpl);
349 0 : return *this;
350 : }
351 0 : nsIntRegion& Or (const nsIntRegion& aRegion, const nsIntRect& aRect)
352 : {
353 0 : mImpl.Or (aRegion.mImpl, ToRect (aRect));
354 0 : return *this;
355 : }
356 : nsIntRegion& Or (const nsIntRect& aRect, const nsIntRegion& aRegion)
357 : {
358 : return Or (aRegion, aRect);
359 : }
360 : nsIntRegion& Or (const nsIntRect& aRect1, const nsIntRect& aRect2)
361 : {
362 : mImpl = ToRect (aRect1);
363 : return Or (*this, aRect2);
364 : }
365 :
366 : nsIntRegion& Xor (const nsIntRegion& aRgn1, const nsIntRegion& aRgn2)
367 : {
368 : mImpl.Xor (aRgn1.mImpl, aRgn2.mImpl);
369 : return *this;
370 : }
371 : nsIntRegion& Xor (const nsIntRegion& aRegion, const nsIntRect& aRect)
372 : {
373 : mImpl.Xor (aRegion.mImpl, ToRect (aRect));
374 : return *this;
375 : }
376 : nsIntRegion& Xor (const nsIntRect& aRect, const nsIntRegion& aRegion)
377 : {
378 : return Xor (aRegion, aRect);
379 : }
380 : nsIntRegion& Xor (const nsIntRect& aRect1, const nsIntRect& aRect2)
381 : {
382 : mImpl = ToRect (aRect1);
383 : return Xor (*this, aRect2);
384 : }
385 :
386 0 : nsIntRegion& Sub (const nsIntRegion& aRgn1, const nsIntRegion& aRgn2)
387 : {
388 0 : mImpl.Sub (aRgn1.mImpl, aRgn2.mImpl);
389 0 : return *this;
390 : }
391 0 : nsIntRegion& Sub (const nsIntRegion& aRegion, const nsIntRect& aRect)
392 : {
393 0 : mImpl.Sub (aRegion.mImpl, ToRect (aRect));
394 0 : return *this;
395 : }
396 0 : nsIntRegion& Sub (const nsIntRect& aRect, const nsIntRegion& aRegion)
397 : {
398 0 : return Sub (nsIntRegion (aRect), aRegion);
399 : }
400 : nsIntRegion& Sub (const nsIntRect& aRect1, const nsIntRect& aRect2)
401 : {
402 : mImpl = ToRect (aRect1);
403 : return Sub (*this, aRect2);
404 : }
405 :
406 0 : bool Contains (const nsIntRect& aRect) const
407 : {
408 0 : return mImpl.Contains (ToRect (aRect));
409 : }
410 0 : bool Contains (const nsIntRegion& aRgn) const
411 : {
412 0 : return mImpl.Contains (aRgn.mImpl);
413 : }
414 0 : bool Intersects (const nsIntRect& aRect) const
415 : {
416 0 : return mImpl.Intersects (ToRect (aRect));
417 : }
418 :
419 0 : void MoveBy (PRInt32 aXOffset, PRInt32 aYOffset)
420 : {
421 0 : MoveBy (nsIntPoint (aXOffset, aYOffset));
422 0 : }
423 0 : void MoveBy (nsIntPoint aPt)
424 : {
425 0 : mImpl.MoveBy (aPt.x, aPt.y);
426 0 : }
427 0 : void SetEmpty ()
428 : {
429 0 : mImpl.SetEmpty ();
430 0 : }
431 :
432 0 : bool IsEmpty () const { return mImpl.IsEmpty (); }
433 : bool IsComplex () const { return mImpl.IsComplex (); }
434 0 : bool IsEqual (const nsIntRegion& aRegion) const
435 : {
436 0 : return mImpl.IsEqual (aRegion.mImpl);
437 : }
438 0 : PRUint32 GetNumRects () const { return mImpl.GetNumRects (); }
439 0 : nsIntRect GetBounds () const { return FromRect (mImpl.GetBounds ()); }
440 : nsRegion ToAppUnits (nscoord aAppUnitsPerPixel) const;
441 : nsIntRect GetLargestRectangle (const nsIntRect& aContainingRect = nsIntRect()) const
442 : {
443 : return FromRect (mImpl.GetLargestRectangle( ToRect(aContainingRect) ));
444 : }
445 :
446 : nsIntRegion& ScaleRoundOut (float aXScale, float aYScale)
447 : {
448 : mImpl.ScaleRoundOut(aXScale, aYScale);
449 : return *this;
450 : }
451 :
452 : /**
453 : * Make sure the region has at most aMaxRects by adding area to it
454 : * if necessary. The simplified region will be a superset of the
455 : * original region. The simplified region's bounding box will be
456 : * the same as for the current region.
457 : */
458 0 : void SimplifyOutward (PRUint32 aMaxRects)
459 : {
460 0 : mImpl.SimplifyOutward (aMaxRects);
461 0 : }
462 : /**
463 : * Make sure the region has at most aMaxRects by removing area from
464 : * it if necessary. The simplified region will be a subset of the
465 : * original region.
466 : */
467 : void SimplifyInward (PRUint32 aMaxRects)
468 : {
469 : mImpl.SimplifyInward (aMaxRects);
470 : }
471 : /**
472 : * Efficiently try to remove a rectangle from this region. The actual
473 : * area removed could be some sub-area contained by the rectangle
474 : * (even possibly nothing at all).
475 : *
476 : * We remove all rectangles that are contained by aRect.
477 : */
478 : void SimpleSubtract (const nsIntRect& aRect)
479 : {
480 : mImpl.SimpleSubtract (ToRect (aRect));
481 : }
482 : /**
483 : * Efficiently try to remove a region from this region. The actual
484 : * area removed could be some sub-area contained by aRegion
485 : * (even possibly nothing at all).
486 : *
487 : * We remove all rectangles of this region that are contained by
488 : * a rectangle of aRegion.
489 : */
490 : void SimpleSubtract (const nsIntRegion& aRegion)
491 : {
492 : mImpl.SimpleSubtract (aRegion.mImpl);
493 : }
494 :
495 : private:
496 : nsRegion mImpl;
497 :
498 0 : static nsRect ToRect(const nsIntRect& aRect)
499 : {
500 0 : return nsRect (aRect.x, aRect.y, aRect.width, aRect.height);
501 : }
502 0 : static nsIntRect FromRect(const nsRect& aRect)
503 : {
504 0 : return nsIntRect (aRect.x, aRect.y, aRect.width, aRect.height);
505 : }
506 : };
507 :
508 : class NS_GFX nsIntRegionRectIterator
509 : {
510 : nsRegionRectIterator mImpl;
511 : nsIntRect mTmp;
512 :
513 : public:
514 0 : nsIntRegionRectIterator (const nsIntRegion& aRegion) : mImpl (aRegion.mImpl) {}
515 :
516 0 : const nsIntRect* Next ()
517 : {
518 0 : const nsRect* r = mImpl.Next();
519 0 : if (!r)
520 0 : return nsnull;
521 0 : mTmp = nsIntRegion::FromRect (*r);
522 0 : return &mTmp;
523 : }
524 :
525 : const nsIntRect* Prev ()
526 : {
527 : const nsRect* r = mImpl.Prev();
528 : if (!r)
529 : return nsnull;
530 : mTmp = nsIntRegion::FromRect (*r);
531 : return &mTmp;
532 : }
533 :
534 : void Reset ()
535 : {
536 : mImpl.Reset ();
537 : }
538 : };
539 :
540 : #endif
|