Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef nsRegion_h__
7 #define nsRegion_h__
9 #include <stddef.h> // for size_t
10 #include <stdint.h> // for uint32_t, uint64_t
11 #include <sys/types.h> // for int32_t
12 #include "gfxCore.h" // for NS_GFX
13 #include "nsCoord.h" // for nscoord
14 #include "nsError.h" // for nsresult
15 #include "nsPoint.h" // for nsIntPoint, nsPoint
16 #include "nsRect.h" // for nsIntRect, nsRect
17 #include "nsMargin.h" // for nsIntMargin
18 #include "nsStringGlue.h" // for nsCString
19 #include "xpcom-config.h" // for CPP_THROW_NEW
21 class nsIntRegion;
23 #include "pixman.h"
25 /* For information on the internal representation look at pixman-region.c
26 *
27 * This replaces an older homebrew implementation of nsRegion. The
28 * representation used here may use more rectangles than nsRegion however, the
29 * representation is canonical. This means that there's no need for an
30 * Optimize() method because for a paticular region there is only one
31 * representation. This means that nsIntRegion will have more predictable
32 * performance characteristics than the old nsRegion and should not become
33 * degenerate.
34 *
35 * The pixman region code originates from X11 which has spread to a variety of
36 * projects including Qt, Gtk, Wine. It should perform reasonably well.
37 */
39 class nsRegionRectIterator;
41 class nsRegion
42 {
44 friend class nsRegionRectIterator;
46 public:
47 nsRegion () { pixman_region32_init(&mImpl); }
48 nsRegion (const nsRect& aRect) { pixman_region32_init_rect(&mImpl,
49 aRect.x,
50 aRect.y,
51 aRect.width,
52 aRect.height); }
53 nsRegion (const nsRegion& aRegion) { pixman_region32_init(&mImpl); pixman_region32_copy(&mImpl,aRegion.Impl()); }
54 ~nsRegion () { pixman_region32_fini(&mImpl); }
55 nsRegion& operator = (const nsRect& aRect) { Copy (aRect); return *this; }
56 nsRegion& operator = (const nsRegion& aRegion) { Copy (aRegion); return *this; }
57 bool operator==(const nsRegion& aRgn) const
58 {
59 return IsEqual(aRgn);
60 }
62 void Swap(nsRegion* aOther)
63 {
64 pixman_region32_t tmp = mImpl;
65 mImpl = aOther->mImpl;
66 aOther->mImpl = tmp;
67 }
69 static
70 nsresult InitStatic()
71 {
72 return NS_OK;
73 }
75 static
76 void ShutdownStatic() {}
78 nsRegion& And(const nsRegion& aRgn1, const nsRegion& aRgn2)
79 {
80 pixman_region32_intersect(&mImpl, aRgn1.Impl(), aRgn2.Impl());
81 return *this;
82 }
83 nsRegion& And(const nsRect& aRect, const nsRegion& aRegion)
84 {
85 return And(aRegion, aRect);
86 }
87 nsRegion& And(const nsRegion& aRegion, const nsRect& aRect)
88 {
89 pixman_region32_intersect_rect(&mImpl, aRegion.Impl(), aRect.x, aRect.y, aRect.width, aRect.height);
90 return *this;
91 }
92 nsRegion& And(const nsRect& aRect1, const nsRect& aRect2)
93 {
94 nsRect TmpRect;
96 TmpRect.IntersectRect(aRect1, aRect2);
97 return Copy(TmpRect);
98 }
100 nsRegion& Or(const nsRegion& aRgn1, const nsRegion& aRgn2)
101 {
102 pixman_region32_union(&mImpl, aRgn1.Impl(), aRgn2.Impl());
103 return *this;
104 }
105 nsRegion& Or(const nsRegion& aRegion, const nsRect& aRect)
106 {
107 pixman_region32_union_rect(&mImpl, aRegion.Impl(), aRect.x, aRect.y, aRect.width, aRect.height);
108 return *this;
109 }
110 nsRegion& Or(const nsRect& aRect, const nsRegion& aRegion)
111 {
112 return Or(aRegion, aRect);
113 }
114 nsRegion& Or(const nsRect& aRect1, const nsRect& aRect2)
115 {
116 Copy (aRect1);
117 return Or (*this, aRect2);
118 }
120 nsRegion& Xor(const nsRegion& aRgn1, const nsRegion& aRgn2)
121 {
122 // this could be implemented better if pixman had direct
123 // support for xoring regions.
124 nsRegion p;
125 p.Sub(aRgn1, aRgn2);
126 nsRegion q;
127 q.Sub(aRgn2, aRgn1);
128 return Or(p, q);
129 }
130 nsRegion& Xor(const nsRegion& aRegion, const nsRect& aRect)
131 {
132 return Xor(aRegion, nsRegion(aRect));
133 }
134 nsRegion& Xor(const nsRect& aRect, const nsRegion& aRegion)
135 {
136 return Xor(nsRegion(aRect), aRegion);
137 }
138 nsRegion& Xor(const nsRect& aRect1, const nsRect& aRect2)
139 {
140 return Xor(nsRegion(aRect1), nsRegion(aRect2));
141 }
143 nsRegion ToAppUnits (nscoord aAppUnitsPerPixel) const;
144 nsRegion& Sub(const nsRegion& aRgn1, const nsRegion& aRgn2)
145 {
146 pixman_region32_subtract(&mImpl, aRgn1.Impl(), aRgn2.Impl());
147 return *this;
148 }
149 nsRegion& Sub(const nsRegion& aRegion, const nsRect& aRect)
150 {
151 return Sub(aRegion, nsRegion(aRect));
152 }
153 nsRegion& Sub(const nsRect& aRect, const nsRegion& aRegion)
154 {
155 return Sub(nsRegion(aRect), aRegion);
156 }
157 nsRegion& Sub(const nsRect& aRect1, const nsRect& aRect2)
158 {
159 Copy(aRect1);
160 return Sub(*this, aRect2);
161 }
163 bool Contains (const nsRect& aRect) const
164 {
165 pixman_box32_t box = RectToBox(aRect);
166 return pixman_region32_contains_rectangle(Impl(), &box) == PIXMAN_REGION_IN;
167 }
168 bool Contains (const nsRegion& aRgn) const;
169 bool Intersects (const nsRect& aRect) const;
171 void MoveBy (int32_t aXOffset, int32_t aYOffset)
172 {
173 MoveBy (nsPoint (aXOffset, aYOffset));
174 }
175 void MoveBy (nsPoint aPt) { pixman_region32_translate(&mImpl, aPt.x, aPt.y); }
176 void SetEmpty ()
177 {
178 pixman_region32_clear(&mImpl);
179 }
181 nsRegion MovedBy(int32_t aXOffset, int32_t aYOffset) const
182 {
183 return MovedBy(nsPoint(aXOffset, aYOffset));
184 }
185 nsRegion MovedBy(const nsPoint& aPt) const
186 {
187 nsRegion copy(*this);
188 copy.MoveBy(aPt);
189 return copy;
190 }
192 nsRegion Intersect(const nsRegion& aOther) const
193 {
194 nsRegion intersection;
195 intersection.And(*this, aOther);
196 return intersection;
197 }
199 void Inflate(const nsMargin& aMargin);
201 nsRegion Inflated(const nsMargin& aMargin) const
202 {
203 nsRegion copy(*this);
204 copy.Inflate(aMargin);
205 return copy;
206 }
208 bool IsEmpty () const { return !pixman_region32_not_empty(Impl()); }
209 bool IsComplex () const { return GetNumRects() > 1; }
210 bool IsEqual (const nsRegion& aRegion) const
211 {
212 return pixman_region32_equal(Impl(), aRegion.Impl());
213 }
214 uint32_t GetNumRects () const { return pixman_region32_n_rects(Impl()); }
215 const nsRect GetBounds () const { return BoxToRect(mImpl.extents); }
216 uint64_t Area () const;
217 // Converts this region from aFromAPP, an appunits per pixel ratio, to
218 // aToAPP. This applies nsRect::ConvertAppUnitsRoundOut/In to each rect of
219 // the region.
220 nsRegion ConvertAppUnitsRoundOut (int32_t aFromAPP, int32_t aToAPP) const;
221 nsRegion ConvertAppUnitsRoundIn (int32_t aFromAPP, int32_t aToAPP) const;
222 nsRegion& ScaleRoundOut(float aXScale, float aYScale);
223 nsRegion& ScaleInverseRoundOut(float aXScale, float aYScale);
224 nsIntRegion ScaleToOutsidePixels (float aXScale, float aYScale, nscoord aAppUnitsPerPixel) const;
225 nsIntRegion ScaleToInsidePixels (float aXScale, float aYScale, nscoord aAppUnitsPerPixel) const;
226 nsIntRegion ScaleToNearestPixels (float aXScale, float aYScale, nscoord aAppUnitsPerPixel) const;
227 nsIntRegion ToOutsidePixels (nscoord aAppUnitsPerPixel) const;
228 nsIntRegion ToNearestPixels (nscoord aAppUnitsPerPixel) const;
230 /**
231 * Gets the largest rectangle contained in the region.
232 * @param aContainingRect if non-empty, we choose a rectangle that
233 * maximizes the area intersecting with aContainingRect (and break ties by
234 * then choosing the largest rectangle overall)
235 */
236 nsRect GetLargestRectangle (const nsRect& aContainingRect = nsRect()) const;
238 /**
239 * Make sure the region has at most aMaxRects by adding area to it
240 * if necessary. The simplified region will be a superset of the
241 * original region. The simplified region's bounding box will be
242 * the same as for the current region.
243 */
244 void SimplifyOutward (uint32_t aMaxRects);
245 /**
246 * Simplify the region by adding at most aThreshold area between spans of
247 * rects. The simplified region will be a superset of the original region.
248 * The simplified region's bounding box will be the same as for the current
249 * region.
250 */
251 void SimplifyOutwardByArea(uint32_t aThreshold);
252 /**
253 * Make sure the region has at most aMaxRects by removing area from
254 * it if necessary. The simplified region will be a subset of the
255 * original region.
256 */
257 void SimplifyInward (uint32_t aMaxRects);
259 nsCString ToString() const;
260 private:
261 pixman_region32_t mImpl;
263 nsIntRegion ToPixels(nscoord aAppUnitsPerPixel, bool aOutsidePixels) const;
265 nsRegion& Copy (const nsRegion& aRegion)
266 {
267 pixman_region32_copy(&mImpl, aRegion.Impl());
268 return *this;
269 }
271 nsRegion& Copy (const nsRect& aRect)
272 {
273 // pixman needs to distinguish between an empty region and a region
274 // with one rect so that it can return a different number of rectangles.
275 // Empty rect: data = empty_box
276 // 1 rect: data = null
277 // >1 rect: data = rects
278 if (aRect.IsEmpty()) {
279 pixman_region32_clear(&mImpl);
280 } else {
281 pixman_box32_t box = RectToBox(aRect);
282 pixman_region32_reset(&mImpl, &box);
283 }
284 return *this;
285 }
287 static inline pixman_box32_t RectToBox(const nsRect &aRect)
288 {
289 pixman_box32_t box = { aRect.x, aRect.y, aRect.XMost(), aRect.YMost() };
290 return box;
291 }
293 static inline pixman_box32_t RectToBox(const nsIntRect &aRect)
294 {
295 pixman_box32_t box = { aRect.x, aRect.y, aRect.XMost(), aRect.YMost() };
296 return box;
297 }
300 static inline nsRect BoxToRect(const pixman_box32_t &aBox)
301 {
302 return nsRect(aBox.x1, aBox.y1,
303 aBox.x2 - aBox.x1,
304 aBox.y2 - aBox.y1);
305 }
307 pixman_region32_t* Impl() const
308 {
309 return const_cast<pixman_region32_t*>(&mImpl);
310 }
312 };
315 class NS_GFX nsRegionRectIterator
316 {
317 const nsRegion* mRegion;
318 int i;
319 int n;
320 nsRect rect;
321 pixman_box32_t *boxes;
323 public:
324 nsRegionRectIterator (const nsRegion& aRegion)
325 {
326 mRegion = &aRegion;
327 i = 0;
328 boxes = pixman_region32_rectangles(aRegion.Impl(), &n);
329 }
331 const nsRect* Next ()
332 {
333 if (i == n)
334 return nullptr;
335 rect = nsRegion::BoxToRect(boxes[i]);
336 i++;
337 return ▭
338 }
340 const nsRect* Prev ()
341 {
342 if (i == -1)
343 return nullptr;
344 rect = nsRegion::BoxToRect(boxes[i]);
345 i--;
346 return ▭
347 }
349 void Reset ()
350 {
351 i = 0;
352 }
353 };
355 /**
356 * nsIntRegions use int32_t coordinates and nsIntRects.
357 */
358 class NS_GFX nsIntRegion
359 {
360 friend class nsIntRegionRectIterator;
361 friend class nsRegion;
363 public:
364 nsIntRegion () {}
365 nsIntRegion (const nsIntRect& aRect) : mImpl (ToRect(aRect)) {}
366 nsIntRegion (const nsIntRegion& aRegion) : mImpl (aRegion.mImpl) {}
367 nsIntRegion& operator = (const nsIntRect& aRect) { mImpl = ToRect (aRect); return *this; }
368 nsIntRegion& operator = (const nsIntRegion& aRegion) { mImpl = aRegion.mImpl; return *this; }
370 bool operator==(const nsIntRegion& aRgn) const
371 {
372 return IsEqual(aRgn);
373 }
375 void Swap(nsIntRegion* aOther)
376 {
377 mImpl.Swap(&aOther->mImpl);
378 }
380 nsIntRegion& And (const nsIntRegion& aRgn1, const nsIntRegion& aRgn2)
381 {
382 mImpl.And (aRgn1.mImpl, aRgn2.mImpl);
383 return *this;
384 }
385 nsIntRegion& And (const nsIntRegion& aRegion, const nsIntRect& aRect)
386 {
387 mImpl.And (aRegion.mImpl, ToRect (aRect));
388 return *this;
389 }
390 nsIntRegion& And (const nsIntRect& aRect, const nsIntRegion& aRegion)
391 {
392 return And (aRegion, aRect);
393 }
394 nsIntRegion& And (const nsIntRect& aRect1, const nsIntRect& aRect2)
395 {
396 nsIntRect TmpRect;
398 TmpRect.IntersectRect (aRect1, aRect2);
399 mImpl = ToRect (TmpRect);
400 return *this;
401 }
403 nsIntRegion& Or (const nsIntRegion& aRgn1, const nsIntRegion& aRgn2)
404 {
405 mImpl.Or (aRgn1.mImpl, aRgn2.mImpl);
406 return *this;
407 }
408 nsIntRegion& Or (const nsIntRegion& aRegion, const nsIntRect& aRect)
409 {
410 mImpl.Or (aRegion.mImpl, ToRect (aRect));
411 return *this;
412 }
413 nsIntRegion& Or (const nsIntRect& aRect, const nsIntRegion& aRegion)
414 {
415 return Or (aRegion, aRect);
416 }
417 nsIntRegion& Or (const nsIntRect& aRect1, const nsIntRect& aRect2)
418 {
419 mImpl = ToRect (aRect1);
420 return Or (*this, aRect2);
421 }
423 nsIntRegion& Xor (const nsIntRegion& aRgn1, const nsIntRegion& aRgn2)
424 {
425 mImpl.Xor (aRgn1.mImpl, aRgn2.mImpl);
426 return *this;
427 }
428 nsIntRegion& Xor (const nsIntRegion& aRegion, const nsIntRect& aRect)
429 {
430 mImpl.Xor (aRegion.mImpl, ToRect (aRect));
431 return *this;
432 }
433 nsIntRegion& Xor (const nsIntRect& aRect, const nsIntRegion& aRegion)
434 {
435 return Xor (aRegion, aRect);
436 }
437 nsIntRegion& Xor (const nsIntRect& aRect1, const nsIntRect& aRect2)
438 {
439 mImpl = ToRect (aRect1);
440 return Xor (*this, aRect2);
441 }
443 nsIntRegion& Sub (const nsIntRegion& aRgn1, const nsIntRegion& aRgn2)
444 {
445 mImpl.Sub (aRgn1.mImpl, aRgn2.mImpl);
446 return *this;
447 }
448 nsIntRegion& Sub (const nsIntRegion& aRegion, const nsIntRect& aRect)
449 {
450 mImpl.Sub (aRegion.mImpl, ToRect (aRect));
451 return *this;
452 }
453 nsIntRegion& Sub (const nsIntRect& aRect, const nsIntRegion& aRegion)
454 {
455 return Sub (nsIntRegion (aRect), aRegion);
456 }
457 nsIntRegion& Sub (const nsIntRect& aRect1, const nsIntRect& aRect2)
458 {
459 mImpl = ToRect (aRect1);
460 return Sub (*this, aRect2);
461 }
463 bool Contains (const nsIntRect& aRect) const
464 {
465 return mImpl.Contains (ToRect (aRect));
466 }
467 bool Contains (const nsIntRegion& aRgn) const
468 {
469 return mImpl.Contains (aRgn.mImpl);
470 }
471 bool Intersects (const nsIntRect& aRect) const
472 {
473 return mImpl.Intersects (ToRect (aRect));
474 }
476 void MoveBy (int32_t aXOffset, int32_t aYOffset)
477 {
478 MoveBy (nsIntPoint (aXOffset, aYOffset));
479 }
480 void MoveBy (nsIntPoint aPt)
481 {
482 mImpl.MoveBy (aPt.x, aPt.y);
483 }
484 nsIntRegion MovedBy(int32_t aXOffset, int32_t aYOffset) const
485 {
486 return MovedBy(nsIntPoint(aXOffset, aYOffset));
487 }
488 nsIntRegion MovedBy(const nsIntPoint& aPt) const
489 {
490 nsIntRegion copy(*this);
491 copy.MoveBy(aPt);
492 return copy;
493 }
495 nsIntRegion Intersect(const nsIntRegion& aOther) const
496 {
497 nsIntRegion intersection;
498 intersection.And(*this, aOther);
499 return intersection;
500 }
502 void Inflate(const nsIntMargin& aMargin)
503 {
504 mImpl.Inflate(nsMargin(aMargin.top, aMargin.right, aMargin.bottom, aMargin.left));
505 }
506 nsIntRegion Inflated(const nsIntMargin& aMargin) const
507 {
508 nsIntRegion copy(*this);
509 copy.Inflate(aMargin);
510 return copy;
511 }
513 void SetEmpty ()
514 {
515 mImpl.SetEmpty ();
516 }
518 bool IsEmpty () const { return mImpl.IsEmpty (); }
519 bool IsComplex () const { return mImpl.IsComplex (); }
520 bool IsEqual (const nsIntRegion& aRegion) const
521 {
522 return mImpl.IsEqual (aRegion.mImpl);
523 }
524 uint32_t GetNumRects () const { return mImpl.GetNumRects (); }
525 nsIntRect GetBounds () const { return FromRect (mImpl.GetBounds ()); }
526 uint64_t Area () const { return mImpl.Area(); }
527 nsRegion ToAppUnits (nscoord aAppUnitsPerPixel) const;
528 nsIntRect GetLargestRectangle (const nsIntRect& aContainingRect = nsIntRect()) const
529 {
530 return FromRect (mImpl.GetLargestRectangle( ToRect(aContainingRect) ));
531 }
533 nsIntRegion& ScaleRoundOut (float aXScale, float aYScale)
534 {
535 mImpl.ScaleRoundOut(aXScale, aYScale);
536 return *this;
537 }
539 /**
540 * Make sure the region has at most aMaxRects by adding area to it
541 * if necessary. The simplified region will be a superset of the
542 * original region. The simplified region's bounding box will be
543 * the same as for the current region.
544 */
545 void SimplifyOutward (uint32_t aMaxRects)
546 {
547 mImpl.SimplifyOutward (aMaxRects);
548 }
549 void SimplifyOutwardByArea (uint32_t aThreshold)
550 {
551 mImpl.SimplifyOutwardByArea (aThreshold);
552 }
553 /**
554 * Make sure the region has at most aMaxRects by removing area from
555 * it if necessary. The simplified region will be a subset of the
556 * original region.
557 */
558 void SimplifyInward (uint32_t aMaxRects)
559 {
560 mImpl.SimplifyInward (aMaxRects);
561 }
563 nsCString ToString() const { return mImpl.ToString(); }
565 private:
566 nsRegion mImpl;
568 static nsRect ToRect(const nsIntRect& aRect)
569 {
570 return nsRect (aRect.x, aRect.y, aRect.width, aRect.height);
571 }
572 static nsIntRect FromRect(const nsRect& aRect)
573 {
574 return nsIntRect (aRect.x, aRect.y, aRect.width, aRect.height);
575 }
576 };
578 class NS_GFX nsIntRegionRectIterator
579 {
580 nsRegionRectIterator mImpl;
581 nsIntRect mTmp;
583 public:
584 nsIntRegionRectIterator (const nsIntRegion& aRegion) : mImpl (aRegion.mImpl) {}
586 const nsIntRect* Next ()
587 {
588 const nsRect* r = mImpl.Next();
589 if (!r)
590 return nullptr;
591 mTmp = nsIntRegion::FromRect (*r);
592 return &mTmp;
593 }
595 const nsIntRect* Prev ()
596 {
597 const nsRect* r = mImpl.Prev();
598 if (!r)
599 return nullptr;
600 mTmp = nsIntRegion::FromRect (*r);
601 return &mTmp;
602 }
604 void Reset ()
605 {
606 mImpl.Reset ();
607 }
608 };
609 #endif