summaryrefslogtreecommitdiffstats
path: root/gfx/src/nsRegion.h
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/src/nsRegion.h')
-rw-r--r--gfx/src/nsRegion.h868
1 files changed, 868 insertions, 0 deletions
diff --git a/gfx/src/nsRegion.h b/gfx/src/nsRegion.h
new file mode 100644
index 000000000..6f9f7fc8e
--- /dev/null
+++ b/gfx/src/nsRegion.h
@@ -0,0 +1,868 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+
+#ifndef nsRegion_h__
+#define nsRegion_h__
+
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint32_t, uint64_t
+#include <sys/types.h> // for int32_t
+#include <ostream> // for std::ostream
+#include "nsCoord.h" // for nscoord
+#include "nsError.h" // for nsresult
+#include "nsPoint.h" // for nsIntPoint, nsPoint
+#include "nsRect.h" // for mozilla::gfx::IntRect, nsRect
+#include "nsMargin.h" // for nsIntMargin
+#include "nsRegionFwd.h" // for nsIntRegion
+#include "nsStringGlue.h" // for nsCString
+#include "xpcom-config.h" // for CPP_THROW_NEW
+#include "mozilla/ArrayView.h" // for ArrayView
+#include "mozilla/Move.h" // for mozilla::Move
+#include "mozilla/gfx/MatrixFwd.h" // for mozilla::gfx::Matrix4x4
+
+#include "pixman.h"
+
+/* For information on the internal representation look at pixman-region.c
+ *
+ * This replaces an older homebrew implementation of nsRegion. The
+ * representation used here may use more rectangles than nsRegion however, the
+ * representation is canonical. This means that there's no need for an
+ * Optimize() method because for a paticular region there is only one
+ * representation. This means that nsIntRegion will have more predictable
+ * performance characteristics than the old nsRegion and should not become
+ * degenerate.
+ *
+ * The pixman region code originates from X11 which has spread to a variety of
+ * projects including Qt, Gtk, Wine. It should perform reasonably well.
+ */
+
+enum class VisitSide {
+ TOP,
+ BOTTOM,
+ LEFT,
+ RIGHT
+};
+
+class nsRegion
+{
+public:
+ typedef nsRect RectType;
+ typedef nsPoint PointType;
+ typedef nsMargin MarginType;
+
+ nsRegion () { pixman_region32_init(&mImpl); }
+ MOZ_IMPLICIT nsRegion (const nsRect& aRect) { pixman_region32_init_rect(&mImpl,
+ aRect.x,
+ aRect.y,
+ aRect.width,
+ aRect.height); }
+ explicit nsRegion (mozilla::gfx::ArrayView<pixman_box32_t> aRects)
+ {
+ pixman_region32_init_rects(&mImpl, aRects.Data(), aRects.Length());
+ }
+ nsRegion (const nsRegion& aRegion) { pixman_region32_init(&mImpl); pixman_region32_copy(&mImpl,aRegion.Impl()); }
+ nsRegion (nsRegion&& aRegion) { mImpl = aRegion.mImpl; pixman_region32_init(&aRegion.mImpl); }
+ nsRegion& operator = (nsRegion&& aRegion) {
+ pixman_region32_fini(&mImpl);
+ mImpl = aRegion.mImpl;
+ pixman_region32_init(&aRegion.mImpl);
+ return *this;
+ }
+ ~nsRegion () { pixman_region32_fini(&mImpl); }
+ nsRegion& operator = (const nsRect& aRect) { Copy (aRect); return *this; }
+ nsRegion& operator = (const nsRegion& aRegion) { Copy (aRegion); return *this; }
+ bool operator==(const nsRegion& aRgn) const
+ {
+ return IsEqual(aRgn);
+ }
+ bool operator!=(const nsRegion& aRgn) const
+ {
+ return !(*this == aRgn);
+ }
+
+ friend std::ostream& operator<<(std::ostream& stream, const nsRegion& m);
+
+ void Swap(nsRegion* aOther)
+ {
+ pixman_region32_t tmp = mImpl;
+ mImpl = aOther->mImpl;
+ aOther->mImpl = tmp;
+ }
+
+ static
+ nsresult InitStatic()
+ {
+ return NS_OK;
+ }
+
+ static
+ void ShutdownStatic() {}
+
+ void AndWith(const nsRegion& aOther)
+ {
+ And(*this, aOther);
+ }
+ void AndWith(const nsRect& aOther)
+ {
+ And(*this, aOther);
+ }
+ nsRegion& And(const nsRegion& aRgn1, const nsRegion& aRgn2)
+ {
+ pixman_region32_intersect(&mImpl, aRgn1.Impl(), aRgn2.Impl());
+ return *this;
+ }
+ nsRegion& And(const nsRect& aRect, const nsRegion& aRegion)
+ {
+ return And(aRegion, aRect);
+ }
+ nsRegion& And(const nsRegion& aRegion, const nsRect& aRect)
+ {
+ pixman_region32_intersect_rect(&mImpl, aRegion.Impl(), aRect.x, aRect.y, aRect.width, aRect.height);
+ return *this;
+ }
+ nsRegion& And(const nsRect& aRect1, const nsRect& aRect2)
+ {
+ nsRect TmpRect;
+
+ TmpRect.IntersectRect(aRect1, aRect2);
+ return Copy(TmpRect);
+ }
+
+ nsRegion& OrWith(const nsRegion& aOther)
+ {
+ return Or(*this, aOther);
+ }
+ nsRegion& OrWith(const nsRect& aOther)
+ {
+ return Or(*this, aOther);
+ }
+ nsRegion& Or(const nsRegion& aRgn1, const nsRegion& aRgn2)
+ {
+ pixman_region32_union(&mImpl, aRgn1.Impl(), aRgn2.Impl());
+ return *this;
+ }
+ nsRegion& Or(const nsRegion& aRegion, const nsRect& aRect)
+ {
+ pixman_region32_union_rect(&mImpl, aRegion.Impl(), aRect.x, aRect.y, aRect.width, aRect.height);
+ return *this;
+ }
+ nsRegion& Or(const nsRect& aRect, const nsRegion& aRegion)
+ {
+ return Or(aRegion, aRect);
+ }
+ nsRegion& Or(const nsRect& aRect1, const nsRect& aRect2)
+ {
+ Copy (aRect1);
+ return Or (*this, aRect2);
+ }
+
+ nsRegion& XorWith(const nsRegion& aOther)
+ {
+ return Xor(*this, aOther);
+ }
+ nsRegion& XorWith(const nsRect& aOther)
+ {
+ return Xor(*this, aOther);
+ }
+ nsRegion& Xor(const nsRegion& aRgn1, const nsRegion& aRgn2)
+ {
+ // this could be implemented better if pixman had direct
+ // support for xoring regions.
+ nsRegion p;
+ p.Sub(aRgn1, aRgn2);
+ nsRegion q;
+ q.Sub(aRgn2, aRgn1);
+ return Or(p, q);
+ }
+ nsRegion& Xor(const nsRegion& aRegion, const nsRect& aRect)
+ {
+ return Xor(aRegion, nsRegion(aRect));
+ }
+ nsRegion& Xor(const nsRect& aRect, const nsRegion& aRegion)
+ {
+ return Xor(nsRegion(aRect), aRegion);
+ }
+ nsRegion& Xor(const nsRect& aRect1, const nsRect& aRect2)
+ {
+ return Xor(nsRegion(aRect1), nsRegion(aRect2));
+ }
+
+ nsRegion ToAppUnits (nscoord aAppUnitsPerPixel) const;
+
+ nsRegion& SubOut(const nsRegion& aOther)
+ {
+ return Sub(*this, aOther);
+ }
+ nsRegion& SubOut(const nsRect& aOther)
+ {
+ return Sub(*this, aOther);
+ }
+ nsRegion& Sub(const nsRegion& aRgn1, const nsRegion& aRgn2)
+ {
+ pixman_region32_subtract(&mImpl, aRgn1.Impl(), aRgn2.Impl());
+ return *this;
+ }
+ nsRegion& Sub(const nsRegion& aRegion, const nsRect& aRect)
+ {
+ return Sub(aRegion, nsRegion(aRect));
+ }
+ nsRegion& Sub(const nsRect& aRect, const nsRegion& aRegion)
+ {
+ return Sub(nsRegion(aRect), aRegion);
+ }
+ nsRegion& Sub(const nsRect& aRect1, const nsRect& aRect2)
+ {
+ Copy(aRect1);
+ return Sub(*this, aRect2);
+ }
+
+ /**
+ * Returns true iff the given point is inside the region. A region
+ * created from a rect (x=0, y=0, w=100, h=100) will NOT contain
+ * the point x=100, y=100.
+ */
+ bool Contains (int aX, int aY) const
+ {
+ return pixman_region32_contains_point(Impl(), aX, aY, nullptr);
+ }
+ bool Contains (const nsRect& aRect) const
+ {
+ pixman_box32_t box = RectToBox(aRect);
+ return pixman_region32_contains_rectangle(Impl(), &box) == PIXMAN_REGION_IN;
+ }
+ bool Contains (const nsRegion& aRgn) const;
+ bool Intersects (const nsRect& aRect) const;
+
+ void MoveBy (int32_t aXOffset, int32_t aYOffset)
+ {
+ MoveBy (nsPoint (aXOffset, aYOffset));
+ }
+ void MoveBy (nsPoint aPt) { pixman_region32_translate(&mImpl, aPt.x, aPt.y); }
+ void SetEmpty ()
+ {
+ pixman_region32_clear(&mImpl);
+ }
+
+ nsRegion MovedBy(int32_t aXOffset, int32_t aYOffset) const
+ {
+ return MovedBy(nsPoint(aXOffset, aYOffset));
+ }
+ nsRegion MovedBy(const nsPoint& aPt) const
+ {
+ nsRegion copy(*this);
+ copy.MoveBy(aPt);
+ return copy;
+ }
+
+ nsRegion Intersect(const nsRegion& aOther) const
+ {
+ nsRegion intersection;
+ intersection.And(*this, aOther);
+ return intersection;
+ }
+
+ void Inflate(const nsMargin& aMargin);
+
+ nsRegion Inflated(const nsMargin& aMargin) const
+ {
+ nsRegion copy(*this);
+ copy.Inflate(aMargin);
+ return copy;
+ }
+
+ bool IsEmpty () const { return !pixman_region32_not_empty(Impl()); }
+ bool IsComplex () const { return GetNumRects() > 1; }
+ bool IsEqual (const nsRegion& aRegion) const
+ {
+ return pixman_region32_equal(Impl(), aRegion.Impl());
+ }
+ uint32_t GetNumRects () const
+ {
+ // Work around pixman bug. Sometimes pixman creates regions with 1 rect
+ // that's empty.
+ uint32_t result = pixman_region32_n_rects(Impl());
+ return (result == 1 && GetBounds().IsEmpty()) ? 0 : result;
+ }
+ const nsRect GetBounds () const { return BoxToRect(mImpl.extents); }
+ uint64_t Area () const;
+
+ /**
+ * Return this region scaled to a different appunits per pixel (APP) ratio.
+ * This applies nsRect::ScaleToOtherAppUnitsRoundOut/In to each rect of the region.
+ * @param aFromAPP the APP to scale from
+ * @param aToAPP the APP to scale to
+ * @note this can turn an empty region into a non-empty region
+ */
+ MOZ_MUST_USE nsRegion
+ ScaleToOtherAppUnitsRoundOut (int32_t aFromAPP, int32_t aToAPP) const;
+ MOZ_MUST_USE nsRegion
+ ScaleToOtherAppUnitsRoundIn (int32_t aFromAPP, int32_t aToAPP) const;
+ nsRegion& ScaleRoundOut(float aXScale, float aYScale);
+ nsRegion& ScaleInverseRoundOut(float aXScale, float aYScale);
+ nsRegion& Transform (const mozilla::gfx::Matrix4x4 &aTransform);
+ nsIntRegion ScaleToOutsidePixels (float aXScale, float aYScale, nscoord aAppUnitsPerPixel) const;
+ nsIntRegion ScaleToInsidePixels (float aXScale, float aYScale, nscoord aAppUnitsPerPixel) const;
+ nsIntRegion ScaleToNearestPixels (float aXScale, float aYScale, nscoord aAppUnitsPerPixel) const;
+ nsIntRegion ToOutsidePixels (nscoord aAppUnitsPerPixel) const;
+ nsIntRegion ToNearestPixels (nscoord aAppUnitsPerPixel) const;
+
+ /**
+ * Gets the largest rectangle contained in the region.
+ * @param aContainingRect if non-empty, we choose a rectangle that
+ * maximizes the area intersecting with aContainingRect (and break ties by
+ * then choosing the largest rectangle overall)
+ */
+ nsRect GetLargestRectangle (const nsRect& aContainingRect = nsRect()) const;
+
+ /**
+ * Make sure the region has at most aMaxRects by adding area to it
+ * if necessary. The simplified region will be a superset of the
+ * original region. The simplified region's bounding box will be
+ * the same as for the current region.
+ */
+ void SimplifyOutward (uint32_t aMaxRects);
+ /**
+ * Simplify the region by adding at most aThreshold area between spans of
+ * rects. The simplified region will be a superset of the original region.
+ * The simplified region's bounding box will be the same as for the current
+ * region.
+ */
+ void SimplifyOutwardByArea(uint32_t aThreshold);
+ /**
+ * Make sure the region has at most aMaxRects by removing area from
+ * it if necessary. The simplified region will be a subset of the
+ * original region.
+ */
+ void SimplifyInward (uint32_t aMaxRects);
+
+ /**
+ * VisitEdges is a weird kind of function that we use for padding
+ * out surfaces to prevent texture filtering artifacts.
+ * It calls the visitFn callback for each of the exterior edges of
+ * the regions. The top and bottom edges will be expanded 1 pixel
+ * to the left and right if there's an outside corner. The order
+ * the edges are visited is not guaranteed.
+ *
+ * visitFn has a side parameter that can be TOP,BOTTOM,LEFT,RIGHT
+ * and specifies which kind of edge is being visited. x1, y1, x2, y2
+ * are the coordinates of the line. (x1 == x2) || (y1 == y2)
+ */
+ typedef void (*visitFn)(void *closure, VisitSide side, int x1, int y1, int x2, int y2);
+ void VisitEdges(visitFn, void *closure);
+
+ nsCString ToString() const;
+
+ class RectIterator
+ {
+ int mCurrent; // Index of the current entry
+ int mLimit; // Index one past the final entry.
+ mutable nsRect mTmp; // The most recently gotten rectangle.
+ pixman_box32_t *mBoxes;
+
+ public:
+ explicit RectIterator(const nsRegion& aRegion)
+ {
+ mCurrent = 0;
+ mBoxes = pixman_region32_rectangles(aRegion.Impl(), &mLimit);
+ // Work around pixman bug. Sometimes pixman creates regions with 1 rect
+ // that's empty.
+ if (mLimit == 1 && nsRegion::BoxToRect(mBoxes[0]).IsEmpty()) {
+ mLimit = 0;
+ }
+ }
+
+ bool Done() const { return mCurrent == mLimit; }
+
+ const nsRect& Get() const
+ {
+ MOZ_ASSERT(!Done());
+ mTmp = nsRegion::BoxToRect(mBoxes[mCurrent]);
+ NS_ASSERTION(!mTmp.IsEmpty(), "Shouldn't return empty rect");
+ return mTmp;
+ }
+
+ void Next()
+ {
+ MOZ_ASSERT(!Done());
+ mCurrent++;
+ }
+ };
+
+ RectIterator RectIter() const { return RectIterator(*this); }
+
+private:
+ pixman_region32_t mImpl;
+
+#ifndef MOZ_TREE_PIXMAN
+ // For compatibility with pixman versions older than 0.25.2.
+ static inline void
+ pixman_region32_clear(pixman_region32_t *region)
+ {
+ pixman_region32_fini(region);
+ pixman_region32_init(region);
+ }
+#endif
+
+ nsIntRegion ToPixels(nscoord aAppUnitsPerPixel, bool aOutsidePixels) const;
+
+ nsRegion& Copy (const nsRegion& aRegion)
+ {
+ pixman_region32_copy(&mImpl, aRegion.Impl());
+ return *this;
+ }
+
+ nsRegion& Copy (const nsRect& aRect)
+ {
+ // pixman needs to distinguish between an empty region and a region
+ // with one rect so that it can return a different number of rectangles.
+ // Empty rect: data = empty_box
+ // 1 rect: data = null
+ // >1 rect: data = rects
+ if (aRect.IsEmpty()) {
+ pixman_region32_clear(&mImpl);
+ } else {
+ pixman_box32_t box = RectToBox(aRect);
+ pixman_region32_reset(&mImpl, &box);
+ }
+ return *this;
+ }
+
+ static inline pixman_box32_t RectToBox(const nsRect &aRect)
+ {
+ pixman_box32_t box = { aRect.x, aRect.y, aRect.XMost(), aRect.YMost() };
+ return box;
+ }
+
+ static inline pixman_box32_t RectToBox(const mozilla::gfx::IntRect &aRect)
+ {
+ pixman_box32_t box = { aRect.x, aRect.y, aRect.XMost(), aRect.YMost() };
+ return box;
+ }
+
+
+ static inline nsRect BoxToRect(const pixman_box32_t &aBox)
+ {
+ return nsRect(aBox.x1, aBox.y1,
+ aBox.x2 - aBox.x1,
+ aBox.y2 - aBox.y1);
+ }
+
+ pixman_region32_t* Impl() const
+ {
+ return const_cast<pixman_region32_t*>(&mImpl);
+ }
+};
+
+namespace mozilla {
+namespace gfx {
+
+/**
+ * BaseIntRegions use int32_t coordinates.
+ */
+template <typename Derived, typename Rect, typename Point, typename Margin>
+class BaseIntRegion
+{
+ friend class ::nsRegion;
+
+ // Give access to all specializations of IntRegionTyped, not just ones that
+ // derive from this specialization of BaseIntRegion.
+ template <typename units>
+ friend class IntRegionTyped;
+
+public:
+ typedef Rect RectType;
+ typedef Point PointType;
+ typedef Margin MarginType;
+
+ BaseIntRegion () {}
+ MOZ_IMPLICIT BaseIntRegion (const Rect& aRect) : mImpl (ToRect(aRect)) {}
+ explicit BaseIntRegion (mozilla::gfx::ArrayView<pixman_box32_t> aRects) : mImpl (aRects) {}
+ BaseIntRegion (const BaseIntRegion& aRegion) : mImpl (aRegion.mImpl) {}
+ BaseIntRegion (BaseIntRegion&& aRegion) : mImpl (mozilla::Move(aRegion.mImpl)) {}
+ Derived& operator = (const Rect& aRect) { mImpl = ToRect (aRect); return This(); }
+ Derived& operator = (const Derived& aRegion) { mImpl = aRegion.mImpl; return This(); }
+ Derived& operator = (Derived&& aRegion) { mImpl = mozilla::Move(aRegion.mImpl); return This(); }
+
+ bool operator==(const Derived& aRgn) const
+ {
+ return IsEqual(aRgn);
+ }
+ bool operator!=(const Derived& aRgn) const
+ {
+ return !(*this == aRgn);
+ }
+
+ friend std::ostream& operator<<(std::ostream& stream, const Derived& m) {
+ return stream << m.mImpl;
+ }
+
+ void Swap(Derived* aOther)
+ {
+ mImpl.Swap(&aOther->mImpl);
+ }
+
+ void AndWith(const Derived& aOther)
+ {
+ And(This(), aOther);
+ }
+ void AndWith(const Rect& aOther)
+ {
+ And(This(), aOther);
+ }
+ Derived& And (const Derived& aRgn1, const Derived& aRgn2)
+ {
+ mImpl.And (aRgn1.mImpl, aRgn2.mImpl);
+ return This();
+ }
+ Derived& And (const Derived& aRegion, const Rect& aRect)
+ {
+ mImpl.And (aRegion.mImpl, ToRect (aRect));
+ return This();
+ }
+ Derived& And (const Rect& aRect, const Derived& aRegion)
+ {
+ return And (aRegion, aRect);
+ }
+ Derived& And (const Rect& aRect1, const Rect& aRect2)
+ {
+ Rect TmpRect;
+
+ TmpRect.IntersectRect (aRect1, aRect2);
+ mImpl = ToRect (TmpRect);
+ return This();
+ }
+
+ Derived& OrWith(const Derived& aOther)
+ {
+ return Or(This(), aOther);
+ }
+ Derived& OrWith(const Rect& aOther)
+ {
+ return Or(This(), aOther);
+ }
+ Derived& Or (const Derived& aRgn1, const Derived& aRgn2)
+ {
+ mImpl.Or (aRgn1.mImpl, aRgn2.mImpl);
+ return This();
+ }
+ Derived& Or (const Derived& aRegion, const Rect& aRect)
+ {
+ mImpl.Or (aRegion.mImpl, ToRect (aRect));
+ return This();
+ }
+ Derived& Or (const Rect& aRect, const Derived& aRegion)
+ {
+ return Or (aRegion, aRect);
+ }
+ Derived& Or (const Rect& aRect1, const Rect& aRect2)
+ {
+ mImpl = ToRect (aRect1);
+ return Or (This(), aRect2);
+ }
+
+ Derived& XorWith(const Derived& aOther)
+ {
+ return Xor(This(), aOther);
+ }
+ Derived& XorWith(const Rect& aOther)
+ {
+ return Xor(This(), aOther);
+ }
+ Derived& Xor (const Derived& aRgn1, const Derived& aRgn2)
+ {
+ mImpl.Xor (aRgn1.mImpl, aRgn2.mImpl);
+ return This();
+ }
+ Derived& Xor (const Derived& aRegion, const Rect& aRect)
+ {
+ mImpl.Xor (aRegion.mImpl, ToRect (aRect));
+ return This();
+ }
+ Derived& Xor (const Rect& aRect, const Derived& aRegion)
+ {
+ return Xor (aRegion, aRect);
+ }
+ Derived& Xor (const Rect& aRect1, const Rect& aRect2)
+ {
+ mImpl = ToRect (aRect1);
+ return Xor (This(), aRect2);
+ }
+
+ Derived& SubOut(const Derived& aOther)
+ {
+ return Sub(This(), aOther);
+ }
+ Derived& SubOut(const Rect& aOther)
+ {
+ return Sub(This(), aOther);
+ }
+ Derived& Sub (const Derived& aRgn1, const Derived& aRgn2)
+ {
+ mImpl.Sub (aRgn1.mImpl, aRgn2.mImpl);
+ return This();
+ }
+ Derived& Sub (const Derived& aRegion, const Rect& aRect)
+ {
+ mImpl.Sub (aRegion.mImpl, ToRect (aRect));
+ return This();
+ }
+ Derived& Sub (const Rect& aRect, const Derived& aRegion)
+ {
+ return Sub (Derived (aRect), aRegion);
+ }
+ Derived& Sub (const Rect& aRect1, const Rect& aRect2)
+ {
+ mImpl = ToRect (aRect1);
+ return Sub (This(), aRect2);
+ }
+
+ /**
+ * Returns true iff the given point is inside the region. A region
+ * created from a rect (x=0, y=0, w=100, h=100) will NOT contain
+ * the point x=100, y=100.
+ */
+ bool Contains (int aX, int aY) const
+ {
+ return mImpl.Contains(aX, aY);
+ }
+ bool Contains (const Rect& aRect) const
+ {
+ return mImpl.Contains (ToRect (aRect));
+ }
+ bool Contains (const Derived& aRgn) const
+ {
+ return mImpl.Contains (aRgn.mImpl);
+ }
+ bool Intersects (const Rect& aRect) const
+ {
+ return mImpl.Intersects (ToRect (aRect));
+ }
+
+ void MoveBy (int32_t aXOffset, int32_t aYOffset)
+ {
+ MoveBy (Point (aXOffset, aYOffset));
+ }
+ void MoveBy (Point aPt)
+ {
+ mImpl.MoveBy (aPt.x, aPt.y);
+ }
+ Derived MovedBy(int32_t aXOffset, int32_t aYOffset) const
+ {
+ return MovedBy(Point(aXOffset, aYOffset));
+ }
+ Derived MovedBy(const Point& aPt) const
+ {
+ Derived copy(This());
+ copy.MoveBy(aPt);
+ return copy;
+ }
+
+ Derived Intersect(const Derived& aOther) const
+ {
+ Derived intersection;
+ intersection.And(This(), aOther);
+ return intersection;
+ }
+
+ void Inflate(const Margin& aMargin)
+ {
+ mImpl.Inflate(nsMargin(aMargin.top, aMargin.right, aMargin.bottom, aMargin.left));
+ }
+ Derived Inflated(const Margin& aMargin) const
+ {
+ Derived copy(This());
+ copy.Inflate(aMargin);
+ return copy;
+ }
+
+ void SetEmpty ()
+ {
+ mImpl.SetEmpty ();
+ }
+
+ bool IsEmpty () const { return mImpl.IsEmpty (); }
+ bool IsComplex () const { return mImpl.IsComplex (); }
+ bool IsEqual (const Derived& aRegion) const
+ {
+ return mImpl.IsEqual (aRegion.mImpl);
+ }
+ uint32_t GetNumRects () const { return mImpl.GetNumRects (); }
+ Rect GetBounds () const { return FromRect (mImpl.GetBounds ()); }
+ uint64_t Area () const { return mImpl.Area(); }
+ nsRegion ToAppUnits (nscoord aAppUnitsPerPixel) const
+ {
+ nsRegion result;
+ for (auto iter = RectIter(); !iter.Done(); iter.Next()) {
+ nsRect appRect = ::ToAppUnits(iter.Get(), aAppUnitsPerPixel);
+ result.Or(result, appRect);
+ }
+ return result;
+ }
+ Rect GetLargestRectangle (const Rect& aContainingRect = Rect()) const
+ {
+ return FromRect (mImpl.GetLargestRectangle( ToRect(aContainingRect) ));
+ }
+
+ Derived& ScaleRoundOut (float aXScale, float aYScale)
+ {
+ mImpl.ScaleRoundOut(aXScale, aYScale);
+ return This();
+ }
+
+ Derived& ScaleInverseRoundOut (float aXScale, float aYScale)
+ {
+ mImpl.ScaleInverseRoundOut(aXScale, aYScale);
+ return This();
+ }
+
+ // Prefer using TransformBy(matrix, region) from UnitTransforms.h,
+ // as applying the transform should typically change the unit system.
+ // TODO(botond): Move this to IntRegionTyped and disable it for
+ // unit != UnknownUnits.
+ Derived& Transform (const mozilla::gfx::Matrix4x4 &aTransform)
+ {
+ mImpl.Transform(aTransform);
+ return This();
+ }
+
+ /**
+ * Make sure the region has at most aMaxRects by adding area to it
+ * if necessary. The simplified region will be a superset of the
+ * original region. The simplified region's bounding box will be
+ * the same as for the current region.
+ */
+ void SimplifyOutward (uint32_t aMaxRects)
+ {
+ mImpl.SimplifyOutward (aMaxRects);
+ }
+ void SimplifyOutwardByArea (uint32_t aThreshold)
+ {
+ mImpl.SimplifyOutwardByArea (aThreshold);
+ }
+ /**
+ * Make sure the region has at most aMaxRects by removing area from
+ * it if necessary. The simplified region will be a subset of the
+ * original region.
+ */
+ void SimplifyInward (uint32_t aMaxRects)
+ {
+ mImpl.SimplifyInward (aMaxRects);
+ }
+
+ typedef void (*visitFn)(void *closure, VisitSide side, int x1, int y1, int x2, int y2);
+ void VisitEdges (visitFn visit, void *closure)
+ {
+ mImpl.VisitEdges (visit, closure);
+ }
+
+ nsCString ToString() const { return mImpl.ToString(); }
+
+ class RectIterator
+ {
+ nsRegion::RectIterator mImpl; // The underlying iterator.
+ mutable Rect mTmp; // The most recently gotten rectangle.
+
+ public:
+ explicit RectIterator(const BaseIntRegion& aRegion)
+ : mImpl(aRegion.mImpl)
+ {}
+
+ bool Done() const { return mImpl.Done(); }
+
+ const Rect& Get() const
+ {
+ mTmp = FromRect(mImpl.Get());
+ return mTmp;
+ }
+
+ void Next() { mImpl.Next(); }
+ };
+
+ RectIterator RectIter() const { return RectIterator(*this); }
+
+protected:
+ // Expose enough to derived classes from them to define conversions
+ // between different types of BaseIntRegions.
+ explicit BaseIntRegion(const nsRegion& aImpl) : mImpl(aImpl) {}
+ const nsRegion& Impl() const { return mImpl; }
+private:
+ nsRegion mImpl;
+
+ static nsRect ToRect(const Rect& aRect)
+ {
+ return nsRect (aRect.x, aRect.y, aRect.width, aRect.height);
+ }
+ static Rect FromRect(const nsRect& aRect)
+ {
+ return Rect (aRect.x, aRect.y, aRect.width, aRect.height);
+ }
+
+ Derived& This()
+ {
+ return *static_cast<Derived*>(this);
+ }
+ const Derived& This() const
+ {
+ return *static_cast<const Derived*>(this);
+ }
+};
+
+template <class units>
+class IntRegionTyped :
+ public BaseIntRegion<IntRegionTyped<units>, IntRectTyped<units>, IntPointTyped<units>, IntMarginTyped<units>>
+{
+ typedef BaseIntRegion<IntRegionTyped<units>, IntRectTyped<units>, IntPointTyped<units>, IntMarginTyped<units>> Super;
+
+ // Make other specializations of IntRegionTyped friends.
+ template <typename OtherUnits>
+ friend class IntRegionTyped;
+
+ static_assert(IsPixel<units>::value, "'units' must be a coordinate system tag");
+
+public:
+ typedef IntRectTyped<units> RectType;
+ typedef IntPointTyped<units> PointType;
+ typedef IntMarginTyped<units> MarginType;
+
+ // Forward constructors.
+ IntRegionTyped() {}
+ MOZ_IMPLICIT IntRegionTyped(const IntRectTyped<units>& aRect) : Super(aRect) {}
+ IntRegionTyped(const IntRegionTyped& aRegion) : Super(aRegion) {}
+ explicit IntRegionTyped(mozilla::gfx::ArrayView<pixman_box32_t> aRects) : Super(aRects) {}
+ IntRegionTyped(IntRegionTyped&& aRegion) : Super(mozilla::Move(aRegion)) {}
+
+ // Assignment operators need to be forwarded as well, otherwise the compiler
+ // will declare deleted ones.
+ IntRegionTyped& operator=(const IntRegionTyped& aRegion)
+ {
+ return Super::operator=(aRegion);
+ }
+ IntRegionTyped& operator=(IntRegionTyped&& aRegion)
+ {
+ return Super::operator=(mozilla::Move(aRegion));
+ }
+
+ static IntRegionTyped FromUnknownRegion(const IntRegion& aRegion)
+ {
+ return IntRegionTyped(aRegion.Impl());
+ }
+ IntRegion ToUnknownRegion() const
+ {
+ // Need |this->| because Impl() is defined in a dependent base class.
+ return IntRegion(this->Impl());
+ }
+private:
+ // This is deliberately private, so calling code uses FromUnknownRegion().
+ explicit IntRegionTyped(const nsRegion& aRegion) : Super(aRegion) {}
+};
+
+} // namespace gfx
+} // namespace mozilla
+
+typedef mozilla::gfx::IntRegion nsIntRegion;
+
+#endif