Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 :
8 : #ifndef nsRegion_h__
9 : #define nsRegion_h__
10 :
11 : #include <stddef.h> // for size_t
12 : #include <stdint.h> // for uint32_t, uint64_t
13 : #include <sys/types.h> // for int32_t
14 : #include <ostream> // for std::ostream
15 : #include "nsCoord.h" // for nscoord
16 : #include "nsError.h" // for nsresult
17 : #include "nsPoint.h" // for nsIntPoint, nsPoint
18 : #include "nsRect.h" // for mozilla::gfx::IntRect, nsRect
19 : #include "nsMargin.h" // for nsIntMargin
20 : #include "nsRegionFwd.h" // for nsIntRegion
21 : #include "nsStringGlue.h" // for nsCString
22 : #include "xpcom-config.h" // for CPP_THROW_NEW
23 : #include "mozilla/ArrayView.h" // for ArrayView
24 : #include "mozilla/Move.h" // for mozilla::Move
25 : #include "mozilla/gfx/MatrixFwd.h" // for mozilla::gfx::Matrix4x4
26 :
27 : #include "pixman.h"
28 :
29 : /* For information on the internal representation look at pixman-region.c
30 : *
31 : * This replaces an older homebrew implementation of nsRegion. The
32 : * representation used here may use more rectangles than nsRegion however, the
33 : * representation is canonical. This means that there's no need for an
34 : * Optimize() method because for a paticular region there is only one
35 : * representation. This means that nsIntRegion will have more predictable
36 : * performance characteristics than the old nsRegion and should not become
37 : * degenerate.
38 : *
39 : * The pixman region code originates from X11 which has spread to a variety of
40 : * projects including Qt, Gtk, Wine. It should perform reasonably well.
41 : */
42 :
43 : enum class VisitSide {
44 : TOP,
45 : BOTTOM,
46 : LEFT,
47 : RIGHT
48 : };
49 :
50 : class nsRegion
51 : {
52 : public:
53 : typedef nsRect RectType;
54 : typedef nsPoint PointType;
55 : typedef nsMargin MarginType;
56 :
57 27897 : nsRegion () { pixman_region32_init(&mImpl); }
58 11392 : MOZ_IMPLICIT nsRegion (const nsRect& aRect) { pixman_region32_init_rect(&mImpl,
59 2848 : aRect.x,
60 2848 : aRect.y,
61 2848 : aRect.width,
62 5696 : aRect.height); }
63 1251 : explicit nsRegion (mozilla::gfx::ArrayView<pixman_box32_t> aRects)
64 1251 : {
65 1251 : pixman_region32_init_rects(&mImpl, aRects.Data(), aRects.Length());
66 1250 : }
67 6450 : nsRegion (const nsRegion& aRegion) { pixman_region32_init(&mImpl); pixman_region32_copy(&mImpl,aRegion.Impl()); }
68 3399 : nsRegion (nsRegion&& aRegion) { mImpl = aRegion.mImpl; pixman_region32_init(&aRegion.mImpl); }
69 2059 : nsRegion& operator = (nsRegion&& aRegion) {
70 2059 : pixman_region32_fini(&mImpl);
71 2059 : mImpl = aRegion.mImpl;
72 2059 : pixman_region32_init(&aRegion.mImpl);
73 2059 : return *this;
74 : }
75 41469 : ~nsRegion () { pixman_region32_fini(&mImpl); }
76 1512 : nsRegion& operator = (const nsRect& aRect) { Copy (aRect); return *this; }
77 5449 : nsRegion& operator = (const nsRegion& aRegion) { Copy (aRegion); return *this; }
78 : bool operator==(const nsRegion& aRgn) const
79 : {
80 : return IsEqual(aRgn);
81 : }
82 : bool operator!=(const nsRegion& aRgn) const
83 : {
84 : return !(*this == aRgn);
85 : }
86 :
87 : friend std::ostream& operator<<(std::ostream& stream, const nsRegion& m);
88 :
89 : void Swap(nsRegion* aOther)
90 : {
91 : pixman_region32_t tmp = mImpl;
92 : mImpl = aOther->mImpl;
93 : aOther->mImpl = tmp;
94 : }
95 :
96 : static
97 3 : nsresult InitStatic()
98 : {
99 3 : return NS_OK;
100 : }
101 :
102 : static
103 0 : void ShutdownStatic() {}
104 :
105 : void AndWith(const nsRegion& aOther)
106 : {
107 : And(*this, aOther);
108 : }
109 : void AndWith(const nsRect& aOther)
110 : {
111 : And(*this, aOther);
112 : }
113 1337 : nsRegion& And(const nsRegion& aRgn1, const nsRegion& aRgn2)
114 : {
115 1337 : pixman_region32_intersect(&mImpl, aRgn1.Impl(), aRgn2.Impl());
116 1337 : return *this;
117 : }
118 : nsRegion& And(const nsRect& aRect, const nsRegion& aRegion)
119 : {
120 : return And(aRegion, aRect);
121 : }
122 3266 : nsRegion& And(const nsRegion& aRegion, const nsRect& aRect)
123 : {
124 3266 : pixman_region32_intersect_rect(&mImpl, aRegion.Impl(), aRect.x, aRect.y, aRect.width, aRect.height);
125 3266 : return *this;
126 : }
127 : nsRegion& And(const nsRect& aRect1, const nsRect& aRect2)
128 : {
129 : nsRect TmpRect;
130 :
131 : TmpRect.IntersectRect(aRect1, aRect2);
132 : return Copy(TmpRect);
133 : }
134 :
135 2838 : nsRegion& OrWith(const nsRegion& aOther)
136 : {
137 2838 : return Or(*this, aOther);
138 : }
139 587 : nsRegion& OrWith(const nsRect& aOther)
140 : {
141 587 : return Or(*this, aOther);
142 : }
143 5964 : nsRegion& Or(const nsRegion& aRgn1, const nsRegion& aRgn2)
144 : {
145 5964 : pixman_region32_union(&mImpl, aRgn1.Impl(), aRgn2.Impl());
146 5964 : return *this;
147 : }
148 7179 : nsRegion& Or(const nsRegion& aRegion, const nsRect& aRect)
149 : {
150 7179 : pixman_region32_union_rect(&mImpl, aRegion.Impl(), aRect.x, aRect.y, aRect.width, aRect.height);
151 7179 : return *this;
152 : }
153 : nsRegion& Or(const nsRect& aRect, const nsRegion& aRegion)
154 : {
155 : return Or(aRegion, aRect);
156 : }
157 105 : nsRegion& Or(const nsRect& aRect1, const nsRect& aRect2)
158 : {
159 105 : Copy (aRect1);
160 105 : return Or (*this, aRect2);
161 : }
162 :
163 : nsRegion& XorWith(const nsRegion& aOther)
164 : {
165 : return Xor(*this, aOther);
166 : }
167 : nsRegion& XorWith(const nsRect& aOther)
168 : {
169 : return Xor(*this, aOther);
170 : }
171 66 : nsRegion& Xor(const nsRegion& aRgn1, const nsRegion& aRgn2)
172 : {
173 : // this could be implemented better if pixman had direct
174 : // support for xoring regions.
175 132 : nsRegion p;
176 66 : p.Sub(aRgn1, aRgn2);
177 132 : nsRegion q;
178 66 : q.Sub(aRgn2, aRgn1);
179 132 : return Or(p, q);
180 : }
181 32 : nsRegion& Xor(const nsRegion& aRegion, const nsRect& aRect)
182 : {
183 32 : return Xor(aRegion, nsRegion(aRect));
184 : }
185 : nsRegion& Xor(const nsRect& aRect, const nsRegion& aRegion)
186 : {
187 : return Xor(nsRegion(aRect), aRegion);
188 : }
189 34 : nsRegion& Xor(const nsRect& aRect1, const nsRect& aRect2)
190 : {
191 34 : return Xor(nsRegion(aRect1), nsRegion(aRect2));
192 : }
193 :
194 : nsRegion ToAppUnits (nscoord aAppUnitsPerPixel) const;
195 :
196 : nsRegion& SubOut(const nsRegion& aOther)
197 : {
198 : return Sub(*this, aOther);
199 : }
200 : nsRegion& SubOut(const nsRect& aOther)
201 : {
202 : return Sub(*this, aOther);
203 : }
204 1648 : nsRegion& Sub(const nsRegion& aRgn1, const nsRegion& aRgn2)
205 : {
206 1648 : pixman_region32_subtract(&mImpl, aRgn1.Impl(), aRgn2.Impl());
207 1648 : return *this;
208 : }
209 70 : nsRegion& Sub(const nsRegion& aRegion, const nsRect& aRect)
210 : {
211 70 : return Sub(aRegion, nsRegion(aRect));
212 : }
213 0 : nsRegion& Sub(const nsRect& aRect, const nsRegion& aRegion)
214 : {
215 0 : return Sub(nsRegion(aRect), aRegion);
216 : }
217 0 : nsRegion& Sub(const nsRect& aRect1, const nsRect& aRect2)
218 : {
219 0 : Copy(aRect1);
220 0 : return Sub(*this, aRect2);
221 : }
222 :
223 : /**
224 : * Returns true iff the given point is inside the region. A region
225 : * created from a rect (x=0, y=0, w=100, h=100) will NOT contain
226 : * the point x=100, y=100.
227 : */
228 46 : bool Contains (int aX, int aY) const
229 : {
230 46 : return pixman_region32_contains_point(Impl(), aX, aY, nullptr);
231 : }
232 2969 : bool Contains (const nsRect& aRect) const
233 : {
234 2969 : pixman_box32_t box = RectToBox(aRect);
235 2969 : return pixman_region32_contains_rectangle(Impl(), &box) == PIXMAN_REGION_IN;
236 : }
237 : bool Contains (const nsRegion& aRgn) const;
238 : bool Intersects (const nsRect& aRect) const;
239 :
240 1961 : void MoveBy (int32_t aXOffset, int32_t aYOffset)
241 : {
242 1961 : MoveBy (nsPoint (aXOffset, aYOffset));
243 1961 : }
244 2939 : void MoveBy (nsPoint aPt) { pixman_region32_translate(&mImpl, aPt.x, aPt.y); }
245 1758 : void SetEmpty ()
246 : {
247 1758 : pixman_region32_clear(&mImpl);
248 1758 : }
249 :
250 : nsRegion MovedBy(int32_t aXOffset, int32_t aYOffset) const
251 : {
252 : return MovedBy(nsPoint(aXOffset, aYOffset));
253 : }
254 0 : nsRegion MovedBy(const nsPoint& aPt) const
255 : {
256 0 : nsRegion copy(*this);
257 0 : copy.MoveBy(aPt);
258 0 : return copy;
259 : }
260 :
261 : nsRegion Intersect(const nsRegion& aOther) const
262 : {
263 : nsRegion intersection;
264 : intersection.And(*this, aOther);
265 : return intersection;
266 : }
267 :
268 : void Inflate(const nsMargin& aMargin);
269 :
270 : nsRegion Inflated(const nsMargin& aMargin) const
271 : {
272 : nsRegion copy(*this);
273 : copy.Inflate(aMargin);
274 : return copy;
275 : }
276 :
277 14838 : bool IsEmpty () const { return !pixman_region32_not_empty(Impl()); }
278 : bool IsComplex () const { return GetNumRects() > 1; }
279 1717 : bool IsEqual (const nsRegion& aRegion) const
280 : {
281 1717 : return pixman_region32_equal(Impl(), aRegion.Impl());
282 : }
283 3787 : uint32_t GetNumRects () const
284 : {
285 : // Work around pixman bug. Sometimes pixman creates regions with 1 rect
286 : // that's empty.
287 3787 : uint32_t result = pixman_region32_n_rects(Impl());
288 3787 : return (result == 1 && GetBounds().IsEmpty()) ? 0 : result;
289 : }
290 8036 : const nsRect GetBounds () const { return BoxToRect(mImpl.extents); }
291 : uint64_t Area () const;
292 :
293 : /**
294 : * Return this region scaled to a different appunits per pixel (APP) ratio.
295 : * This applies nsRect::ScaleToOtherAppUnitsRoundOut/In to each rect of the region.
296 : * @param aFromAPP the APP to scale from
297 : * @param aToAPP the APP to scale to
298 : * @note this can turn an empty region into a non-empty region
299 : */
300 : MOZ_MUST_USE nsRegion
301 : ScaleToOtherAppUnitsRoundOut (int32_t aFromAPP, int32_t aToAPP) const;
302 : MOZ_MUST_USE nsRegion
303 : ScaleToOtherAppUnitsRoundIn (int32_t aFromAPP, int32_t aToAPP) const;
304 : nsRegion& ScaleRoundOut(float aXScale, float aYScale);
305 : nsRegion& ScaleInverseRoundOut(float aXScale, float aYScale);
306 : nsRegion& Transform (const mozilla::gfx::Matrix4x4 &aTransform);
307 : nsIntRegion ScaleToOutsidePixels (float aXScale, float aYScale, nscoord aAppUnitsPerPixel) const;
308 : nsIntRegion ScaleToInsidePixels (float aXScale, float aYScale, nscoord aAppUnitsPerPixel) const;
309 : nsIntRegion ScaleToNearestPixels (float aXScale, float aYScale, nscoord aAppUnitsPerPixel) const;
310 : nsIntRegion ToOutsidePixels (nscoord aAppUnitsPerPixel) const;
311 : nsIntRegion ToNearestPixels (nscoord aAppUnitsPerPixel) const;
312 :
313 : /**
314 : * Gets the largest rectangle contained in the region.
315 : * @param aContainingRect if non-empty, we choose a rectangle that
316 : * maximizes the area intersecting with aContainingRect (and break ties by
317 : * then choosing the largest rectangle overall)
318 : */
319 : nsRect GetLargestRectangle (const nsRect& aContainingRect = nsRect()) const;
320 :
321 : /**
322 : * Make sure the region has at most aMaxRects by adding area to it
323 : * if necessary. The simplified region will be a superset of the
324 : * original region. The simplified region's bounding box will be
325 : * the same as for the current region.
326 : */
327 : void SimplifyOutward (uint32_t aMaxRects);
328 : /**
329 : * Simplify the region by adding at most aThreshold area between spans of
330 : * rects. The simplified region will be a superset of the original region.
331 : * The simplified region's bounding box will be the same as for the current
332 : * region.
333 : */
334 : void SimplifyOutwardByArea(uint32_t aThreshold);
335 : /**
336 : * Make sure the region has at most aMaxRects by removing area from
337 : * it if necessary. The simplified region will be a subset of the
338 : * original region.
339 : */
340 : void SimplifyInward (uint32_t aMaxRects);
341 :
342 : /**
343 : * VisitEdges is a weird kind of function that we use for padding
344 : * out surfaces to prevent texture filtering artifacts.
345 : * It calls the visitFn callback for each of the exterior edges of
346 : * the regions. The top and bottom edges will be expanded 1 pixel
347 : * to the left and right if there's an outside corner. The order
348 : * the edges are visited is not guaranteed.
349 : *
350 : * visitFn has a side parameter that can be TOP,BOTTOM,LEFT,RIGHT
351 : * and specifies which kind of edge is being visited. x1, y1, x2, y2
352 : * are the coordinates of the line. (x1 == x2) || (y1 == y2)
353 : */
354 : typedef void (*visitFn)(void *closure, VisitSide side, int x1, int y1, int x2, int y2);
355 : void VisitEdges(visitFn, void *closure);
356 :
357 : nsCString ToString() const;
358 :
359 6847 : class RectIterator
360 : {
361 : int mCurrent; // Index of the current entry
362 : int mLimit; // Index one past the final entry.
363 : mutable nsRect mTmp; // The most recently gotten rectangle.
364 : pixman_box32_t *mBoxes;
365 :
366 : public:
367 6847 : explicit RectIterator(const nsRegion& aRegion)
368 6847 : {
369 6847 : mCurrent = 0;
370 6847 : mBoxes = pixman_region32_rectangles(aRegion.Impl(), &mLimit);
371 : // Work around pixman bug. Sometimes pixman creates regions with 1 rect
372 : // that's empty.
373 6846 : if (mLimit == 1 && nsRegion::BoxToRect(mBoxes[0]).IsEmpty()) {
374 0 : mLimit = 0;
375 : }
376 6846 : }
377 :
378 18582 : bool Done() const { return mCurrent == mLimit; }
379 :
380 4213 : const nsRect& Get() const
381 : {
382 4213 : MOZ_ASSERT(!Done());
383 4213 : mTmp = nsRegion::BoxToRect(mBoxes[mCurrent]);
384 4213 : NS_ASSERTION(!mTmp.IsEmpty(), "Shouldn't return empty rect");
385 4213 : return mTmp;
386 : }
387 :
388 3790 : void Next()
389 : {
390 3790 : MOZ_ASSERT(!Done());
391 3790 : mCurrent++;
392 3790 : }
393 : };
394 :
395 4455 : RectIterator RectIter() const { return RectIterator(*this); }
396 :
397 : private:
398 : pixman_region32_t mImpl;
399 :
400 : #ifndef MOZ_TREE_PIXMAN
401 : // For compatibility with pixman versions older than 0.25.2.
402 : static inline void
403 : pixman_region32_clear(pixman_region32_t *region)
404 : {
405 : pixman_region32_fini(region);
406 : pixman_region32_init(region);
407 : }
408 : #endif
409 :
410 : nsIntRegion ToPixels(nscoord aAppUnitsPerPixel, bool aOutsidePixels) const;
411 :
412 5449 : nsRegion& Copy (const nsRegion& aRegion)
413 : {
414 5449 : pixman_region32_copy(&mImpl, aRegion.Impl());
415 5449 : return *this;
416 : }
417 :
418 1617 : nsRegion& Copy (const nsRect& aRect)
419 : {
420 : // pixman needs to distinguish between an empty region and a region
421 : // with one rect so that it can return a different number of rectangles.
422 : // Empty rect: data = empty_box
423 : // 1 rect: data = null
424 : // >1 rect: data = rects
425 1617 : if (aRect.IsEmpty()) {
426 163 : pixman_region32_clear(&mImpl);
427 : } else {
428 1454 : pixman_box32_t box = RectToBox(aRect);
429 1454 : pixman_region32_reset(&mImpl, &box);
430 : }
431 1617 : return *this;
432 : }
433 :
434 4760 : static inline pixman_box32_t RectToBox(const nsRect &aRect)
435 : {
436 4760 : pixman_box32_t box = { aRect.x, aRect.y, aRect.XMost(), aRect.YMost() };
437 4761 : return box;
438 : }
439 :
440 435 : static inline pixman_box32_t RectToBox(const mozilla::gfx::IntRect &aRect)
441 : {
442 435 : pixman_box32_t box = { aRect.x, aRect.y, aRect.XMost(), aRect.YMost() };
443 435 : return box;
444 : }
445 :
446 :
447 16206 : static inline nsRect BoxToRect(const pixman_box32_t &aBox)
448 : {
449 16206 : return nsRect(aBox.x1, aBox.y1,
450 16206 : aBox.x2 - aBox.x1,
451 48618 : aBox.y2 - aBox.y1);
452 : }
453 :
454 72154 : pixman_region32_t* Impl() const
455 : {
456 72154 : return const_cast<pixman_region32_t*>(&mImpl);
457 : }
458 : };
459 :
460 : namespace mozilla {
461 : namespace gfx {
462 :
463 : /**
464 : * BaseIntRegions use int32_t coordinates.
465 : */
466 : template <typename Derived, typename Rect, typename Point, typename Margin>
467 24357 : class BaseIntRegion
468 : {
469 : friend class ::nsRegion;
470 :
471 : // Give access to all specializations of IntRegionTyped, not just ones that
472 : // derive from this specialization of BaseIntRegion.
473 : template <typename units>
474 : friend class IntRegionTyped;
475 :
476 : public:
477 : typedef Rect RectType;
478 : typedef Point PointType;
479 : typedef Margin MarginType;
480 :
481 14596 : BaseIntRegion () {}
482 2451 : MOZ_IMPLICIT BaseIntRegion (const Rect& aRect) : mImpl (ToRect(aRect)) {}
483 1179 : explicit BaseIntRegion (mozilla::gfx::ArrayView<pixman_box32_t> aRects) : mImpl (aRects) {}
484 2237 : BaseIntRegion (const BaseIntRegion& aRegion) : mImpl (aRegion.mImpl) {}
485 1345 : BaseIntRegion (BaseIntRegion&& aRegion) : mImpl (mozilla::Move(aRegion.mImpl)) {}
486 : Derived& operator = (const Rect& aRect) { mImpl = ToRect (aRect); return This(); }
487 5061 : Derived& operator = (const Derived& aRegion) { mImpl = aRegion.mImpl; return This(); }
488 2059 : Derived& operator = (Derived&& aRegion) { mImpl = mozilla::Move(aRegion.mImpl); return This(); }
489 :
490 1172 : bool operator==(const Derived& aRgn) const
491 : {
492 1172 : return IsEqual(aRgn);
493 : }
494 124 : bool operator!=(const Derived& aRgn) const
495 : {
496 124 : return !(*this == aRgn);
497 : }
498 :
499 : friend std::ostream& operator<<(std::ostream& stream, const Derived& m) {
500 : return stream << m.mImpl;
501 : }
502 :
503 : void Swap(Derived* aOther)
504 : {
505 : mImpl.Swap(&aOther->mImpl);
506 : }
507 :
508 0 : void AndWith(const Derived& aOther)
509 : {
510 0 : And(This(), aOther);
511 0 : }
512 1424 : void AndWith(const Rect& aOther)
513 : {
514 1424 : And(This(), aOther);
515 1424 : }
516 391 : Derived& And (const Derived& aRgn1, const Derived& aRgn2)
517 : {
518 391 : mImpl.And (aRgn1.mImpl, aRgn2.mImpl);
519 391 : return This();
520 : }
521 1611 : Derived& And (const Derived& aRegion, const Rect& aRect)
522 : {
523 1611 : mImpl.And (aRegion.mImpl, ToRect (aRect));
524 1611 : return This();
525 : }
526 0 : Derived& And (const Rect& aRect, const Derived& aRegion)
527 : {
528 0 : return And (aRegion, aRect);
529 : }
530 184 : Derived& And (const Rect& aRect1, const Rect& aRect2)
531 : {
532 184 : Rect TmpRect;
533 :
534 184 : TmpRect.IntersectRect (aRect1, aRect2);
535 184 : mImpl = ToRect (TmpRect);
536 184 : return This();
537 : }
538 :
539 861 : Derived& OrWith(const Derived& aOther)
540 : {
541 861 : return Or(This(), aOther);
542 : }
543 481 : Derived& OrWith(const Rect& aOther)
544 : {
545 481 : return Or(This(), aOther);
546 : }
547 1742 : Derived& Or (const Derived& aRgn1, const Derived& aRgn2)
548 : {
549 1742 : mImpl.Or (aRgn1.mImpl, aRgn2.mImpl);
550 1742 : return This();
551 : }
552 1345 : Derived& Or (const Derived& aRegion, const Rect& aRect)
553 : {
554 1345 : mImpl.Or (aRegion.mImpl, ToRect (aRect));
555 1345 : return This();
556 : }
557 : Derived& Or (const Rect& aRect, const Derived& aRegion)
558 : {
559 : return Or (aRegion, aRect);
560 : }
561 0 : Derived& Or (const Rect& aRect1, const Rect& aRect2)
562 : {
563 0 : mImpl = ToRect (aRect1);
564 0 : return Or (This(), aRect2);
565 : }
566 :
567 : Derived& XorWith(const Derived& aOther)
568 : {
569 : return Xor(This(), aOther);
570 : }
571 : Derived& XorWith(const Rect& aOther)
572 : {
573 : return Xor(This(), aOther);
574 : }
575 : Derived& Xor (const Derived& aRgn1, const Derived& aRgn2)
576 : {
577 : mImpl.Xor (aRgn1.mImpl, aRgn2.mImpl);
578 : return This();
579 : }
580 32 : Derived& Xor (const Derived& aRegion, const Rect& aRect)
581 : {
582 32 : mImpl.Xor (aRegion.mImpl, ToRect (aRect));
583 32 : return This();
584 : }
585 : Derived& Xor (const Rect& aRect, const Derived& aRegion)
586 : {
587 : return Xor (aRegion, aRect);
588 : }
589 32 : Derived& Xor (const Rect& aRect1, const Rect& aRect2)
590 : {
591 32 : mImpl = ToRect (aRect1);
592 32 : return Xor (This(), aRect2);
593 : }
594 :
595 156 : Derived& SubOut(const Derived& aOther)
596 : {
597 156 : return Sub(This(), aOther);
598 : }
599 : Derived& SubOut(const Rect& aOther)
600 : {
601 : return Sub(This(), aOther);
602 : }
603 662 : Derived& Sub (const Derived& aRgn1, const Derived& aRgn2)
604 : {
605 662 : mImpl.Sub (aRgn1.mImpl, aRgn2.mImpl);
606 662 : return This();
607 : }
608 70 : Derived& Sub (const Derived& aRegion, const Rect& aRect)
609 : {
610 70 : mImpl.Sub (aRegion.mImpl, ToRect (aRect));
611 70 : return This();
612 : }
613 0 : Derived& Sub (const Rect& aRect, const Derived& aRegion)
614 : {
615 0 : return Sub (Derived (aRect), aRegion);
616 : }
617 35 : Derived& Sub (const Rect& aRect1, const Rect& aRect2)
618 : {
619 35 : mImpl = ToRect (aRect1);
620 35 : return Sub (This(), aRect2);
621 : }
622 :
623 : /**
624 : * Returns true iff the given point is inside the region. A region
625 : * created from a rect (x=0, y=0, w=100, h=100) will NOT contain
626 : * the point x=100, y=100.
627 : */
628 46 : bool Contains (int aX, int aY) const
629 : {
630 46 : return mImpl.Contains(aX, aY);
631 : }
632 2279 : bool Contains (const Rect& aRect) const
633 : {
634 2279 : return mImpl.Contains (ToRect (aRect));
635 : }
636 1952 : bool Contains (const Derived& aRgn) const
637 : {
638 1952 : return mImpl.Contains (aRgn.mImpl);
639 : }
640 1763 : bool Intersects (const Rect& aRect) const
641 : {
642 1763 : return mImpl.Intersects (ToRect (aRect));
643 : }
644 :
645 1055 : void MoveBy (int32_t aXOffset, int32_t aYOffset)
646 : {
647 1055 : MoveBy (Point (aXOffset, aYOffset));
648 1055 : }
649 1901 : void MoveBy (Point aPt)
650 : {
651 1901 : mImpl.MoveBy (aPt.x, aPt.y);
652 1901 : }
653 0 : Derived MovedBy(int32_t aXOffset, int32_t aYOffset) const
654 : {
655 0 : return MovedBy(Point(aXOffset, aYOffset));
656 : }
657 0 : Derived MovedBy(const Point& aPt) const
658 : {
659 0 : Derived copy(This());
660 0 : copy.MoveBy(aPt);
661 0 : return copy;
662 : }
663 :
664 281 : Derived Intersect(const Derived& aOther) const
665 : {
666 281 : Derived intersection;
667 281 : intersection.And(This(), aOther);
668 281 : return intersection;
669 : }
670 :
671 0 : void Inflate(const Margin& aMargin)
672 : {
673 0 : mImpl.Inflate(nsMargin(aMargin.top, aMargin.right, aMargin.bottom, aMargin.left));
674 0 : }
675 0 : Derived Inflated(const Margin& aMargin) const
676 : {
677 0 : Derived copy(This());
678 0 : copy.Inflate(aMargin);
679 0 : return copy;
680 : }
681 :
682 521 : void SetEmpty ()
683 : {
684 521 : mImpl.SetEmpty ();
685 521 : }
686 :
687 4670 : bool IsEmpty () const { return mImpl.IsEmpty (); }
688 : bool IsComplex () const { return mImpl.IsComplex (); }
689 1717 : bool IsEqual (const Derived& aRegion) const
690 : {
691 1717 : return mImpl.IsEqual (aRegion.mImpl);
692 : }
693 293 : uint32_t GetNumRects () const { return mImpl.GetNumRects (); }
694 1765 : Rect GetBounds () const { return FromRect (mImpl.GetBounds ()); }
695 35 : uint64_t Area () const { return mImpl.Area(); }
696 61 : nsRegion ToAppUnits (nscoord aAppUnitsPerPixel) const
697 : {
698 61 : nsRegion result;
699 152 : for (auto iter = RectIter(); !iter.Done(); iter.Next()) {
700 182 : nsRect appRect = ::ToAppUnits(iter.Get(), aAppUnitsPerPixel);
701 91 : result.Or(result, appRect);
702 : }
703 61 : return result;
704 : }
705 : Rect GetLargestRectangle (const Rect& aContainingRect = Rect()) const
706 : {
707 : return FromRect (mImpl.GetLargestRectangle( ToRect(aContainingRect) ));
708 : }
709 :
710 595 : Derived& ScaleRoundOut (float aXScale, float aYScale)
711 : {
712 595 : mImpl.ScaleRoundOut(aXScale, aYScale);
713 595 : return This();
714 : }
715 :
716 : Derived& ScaleInverseRoundOut (float aXScale, float aYScale)
717 : {
718 : mImpl.ScaleInverseRoundOut(aXScale, aYScale);
719 : return This();
720 : }
721 :
722 : // Prefer using TransformBy(matrix, region) from UnitTransforms.h,
723 : // as applying the transform should typically change the unit system.
724 : // TODO(botond): Move this to IntRegionTyped and disable it for
725 : // unit != UnknownUnits.
726 418 : Derived& Transform (const mozilla::gfx::Matrix4x4 &aTransform)
727 : {
728 418 : mImpl.Transform(aTransform);
729 418 : return This();
730 : }
731 :
732 : /**
733 : * Make sure the region has at most aMaxRects by adding area to it
734 : * if necessary. The simplified region will be a superset of the
735 : * original region. The simplified region's bounding box will be
736 : * the same as for the current region.
737 : */
738 1775 : void SimplifyOutward (uint32_t aMaxRects)
739 : {
740 1775 : mImpl.SimplifyOutward (aMaxRects);
741 1775 : }
742 0 : void SimplifyOutwardByArea (uint32_t aThreshold)
743 : {
744 0 : mImpl.SimplifyOutwardByArea (aThreshold);
745 0 : }
746 : /**
747 : * Make sure the region has at most aMaxRects by removing area from
748 : * it if necessary. The simplified region will be a subset of the
749 : * original region.
750 : */
751 : void SimplifyInward (uint32_t aMaxRects)
752 : {
753 : mImpl.SimplifyInward (aMaxRects);
754 : }
755 :
756 : typedef void (*visitFn)(void *closure, VisitSide side, int x1, int y1, int x2, int y2);
757 0 : void VisitEdges (visitFn visit, void *closure)
758 : {
759 0 : mImpl.VisitEdges (visit, closure);
760 0 : }
761 :
762 0 : nsCString ToString() const { return mImpl.ToString(); }
763 :
764 2392 : class RectIterator
765 : {
766 : nsRegion::RectIterator mImpl; // The underlying iterator.
767 : mutable Rect mTmp; // The most recently gotten rectangle.
768 :
769 : public:
770 2392 : explicit RectIterator(const BaseIntRegion& aRegion)
771 2392 : : mImpl(aRegion.mImpl)
772 2392 : {}
773 :
774 3664 : bool Done() const { return mImpl.Done(); }
775 :
776 1384 : const Rect& Get() const
777 : {
778 1384 : mTmp = FromRect(mImpl.Get());
779 1384 : return mTmp;
780 : }
781 :
782 1328 : void Next() { mImpl.Next(); }
783 : };
784 :
785 2392 : RectIterator RectIter() const { return RectIterator(*this); }
786 :
787 : protected:
788 : // Expose enough to derived classes from them to define conversions
789 : // between different types of BaseIntRegions.
790 2838 : explicit BaseIntRegion(const nsRegion& aImpl) : mImpl(aImpl) {}
791 2838 : const nsRegion& Impl() const { return mImpl; }
792 : private:
793 : nsRegion mImpl;
794 :
795 10048 : static nsRect ToRect(const Rect& aRect)
796 : {
797 10048 : return nsRect (aRect.x, aRect.y, aRect.width, aRect.height);
798 : }
799 3396 : static Rect FromRect(const nsRect& aRect)
800 : {
801 3396 : return Rect (aRect.x, aRect.y, aRect.width, aRect.height);
802 : }
803 :
804 17150 : Derived& This()
805 : {
806 17150 : return *static_cast<Derived*>(this);
807 : }
808 281 : const Derived& This() const
809 : {
810 281 : return *static_cast<const Derived*>(this);
811 : }
812 : };
813 :
814 : template <class units>
815 24357 : class IntRegionTyped :
816 : public BaseIntRegion<IntRegionTyped<units>, IntRectTyped<units>, IntPointTyped<units>, IntMarginTyped<units>>
817 : {
818 : typedef BaseIntRegion<IntRegionTyped<units>, IntRectTyped<units>, IntPointTyped<units>, IntMarginTyped<units>> Super;
819 :
820 : // Make other specializations of IntRegionTyped friends.
821 : template <typename OtherUnits>
822 : friend class IntRegionTyped;
823 :
824 : static_assert(IsPixel<units>::value, "'units' must be a coordinate system tag");
825 :
826 : public:
827 : typedef IntRectTyped<units> RectType;
828 : typedef IntPointTyped<units> PointType;
829 : typedef IntMarginTyped<units> MarginType;
830 :
831 : // Forward constructors.
832 14596 : IntRegionTyped() {}
833 2451 : MOZ_IMPLICIT IntRegionTyped(const IntRectTyped<units>& aRect) : Super(aRect) {}
834 2237 : IntRegionTyped(const IntRegionTyped& aRegion) : Super(aRegion) {}
835 1179 : explicit IntRegionTyped(mozilla::gfx::ArrayView<pixman_box32_t> aRects) : Super(aRects) {}
836 1345 : IntRegionTyped(IntRegionTyped&& aRegion) : Super(mozilla::Move(aRegion)) {}
837 :
838 : // Assignment operators need to be forwarded as well, otherwise the compiler
839 : // will declare deleted ones.
840 5061 : IntRegionTyped& operator=(const IntRegionTyped& aRegion)
841 : {
842 5061 : return Super::operator=(aRegion);
843 : }
844 2059 : IntRegionTyped& operator=(IntRegionTyped&& aRegion)
845 : {
846 2059 : return Super::operator=(mozilla::Move(aRegion));
847 : }
848 :
849 871 : static IntRegionTyped FromUnknownRegion(const IntRegion& aRegion)
850 : {
851 871 : return IntRegionTyped(aRegion.Impl());
852 : }
853 1967 : IntRegion ToUnknownRegion() const
854 : {
855 : // Need |this->| because Impl() is defined in a dependent base class.
856 1967 : return IntRegion(this->Impl());
857 : }
858 : private:
859 : // This is deliberately private, so calling code uses FromUnknownRegion().
860 2838 : explicit IntRegionTyped(const nsRegion& aRegion) : Super(aRegion) {}
861 : };
862 :
863 : } // namespace gfx
864 : } // namespace mozilla
865 :
866 : typedef mozilla::gfx::IntRegion nsIntRegion;
867 :
868 : #endif
|