summaryrefslogtreecommitdiffstats
path: root/layout/painting/DisplayItemClip.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--layout/painting/DisplayItemClip.h193
1 files changed, 193 insertions, 0 deletions
diff --git a/layout/painting/DisplayItemClip.h b/layout/painting/DisplayItemClip.h
new file mode 100644
index 0000000000..ff9df26603
--- /dev/null
+++ b/layout/painting/DisplayItemClip.h
@@ -0,0 +1,193 @@
+/* -*- 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 DISPLAYITEMCLIP_H_
+#define DISPLAYITEMCLIP_H_
+
+#include "mozilla/RefPtr.h"
+#include "nsRect.h"
+#include "nsTArray.h"
+
+class gfxContext;
+class nsPresContext;
+class nsRegion;
+
+namespace mozilla {
+namespace gfx {
+class DrawTarget;
+class Path;
+} // namespace gfx
+namespace layers {
+class StackingContextHelper;
+} // namespace layers
+namespace wr {
+struct ComplexClipRegion;
+} // namespace wr
+} // namespace mozilla
+
+namespace mozilla {
+
+/**
+ * An DisplayItemClip represents the intersection of an optional rectangle
+ * with a list of rounded rectangles (which is often empty), all in appunits.
+ * It can represent everything CSS clipping can do to an element (except for
+ * SVG clip-path), including no clipping at all.
+ */
+class DisplayItemClip {
+ typedef mozilla::gfx::DeviceColor DeviceColor;
+ typedef mozilla::gfx::DrawTarget DrawTarget;
+ typedef mozilla::gfx::Path Path;
+
+ public:
+ struct RoundedRect {
+ nsRect mRect;
+ // Indices into mRadii are the HalfCorner values in gfx/2d/Types.h
+ nscoord mRadii[8];
+
+ RoundedRect operator+(const nsPoint& aOffset) const {
+ RoundedRect r = *this;
+ r.mRect += aOffset;
+ return r;
+ }
+ bool operator==(const RoundedRect& aOther) const {
+ if (!mRect.IsEqualInterior(aOther.mRect)) {
+ return false;
+ }
+
+ for (const auto corner : mozilla::AllPhysicalHalfCorners()) {
+ if (mRadii[corner] != aOther.mRadii[corner]) {
+ return false;
+ }
+ }
+ return true;
+ }
+ bool operator!=(const RoundedRect& aOther) const {
+ return !(*this == aOther);
+ }
+ };
+
+ // Constructs a DisplayItemClip that does no clipping at all.
+ DisplayItemClip() : mHaveClipRect(false) {}
+
+ void SetTo(const nsRect& aRect);
+ void SetTo(const nsRect& aRect, const nscoord* aRadii);
+ void SetTo(const nsRect& aRect, const nsRect& aRoundedRect,
+ const nscoord* aRadii);
+ void IntersectWith(const DisplayItemClip& aOther);
+
+ // Apply this |DisplayItemClip| to the given gfxContext. Any saving of state
+ // or clearing of other clips must be done by the caller.
+ // See aBegin/aEnd note on ApplyRoundedRectsTo.
+ void ApplyTo(gfxContext* aContext, int32_t A2D) const;
+
+ void ApplyRectTo(gfxContext* aContext, int32_t A2D) const;
+ // Applies the rounded rects in this Clip to aContext
+ // Will only apply rounded rects from aBegin (inclusive) to aEnd
+ // (exclusive) or the number of rounded rects, whichever is smaller.
+ void ApplyRoundedRectClipsTo(gfxContext* aContext, int32_t A2DPRInt32,
+ uint32_t aBegin, uint32_t aEnd) const;
+
+ // Draw (fill) the rounded rects in this clip to aContext
+ void FillIntersectionOfRoundedRectClips(gfxContext* aContext,
+ const DeviceColor& aColor,
+ int32_t aAppUnitsPerDevPixel) const;
+ // 'Draw' (create as a path, does not stroke or fill) aRoundRect to aContext
+ already_AddRefed<Path> MakeRoundedRectPath(
+ DrawTarget& aDrawTarget, int32_t A2D,
+ const RoundedRect& aRoundRect) const;
+
+ // Returns true if the intersection of aRect and this clip region is
+ // non-empty. This is precise for DisplayItemClips with at most one
+ // rounded rectangle. When multiple rounded rectangles are present, we just
+ // check that the rectangle intersects all of them (but possibly in different
+ // places). So it may return true when the correct answer is false.
+ bool MayIntersect(const nsRect& aRect) const;
+
+ // Return a rectangle contained in the intersection of aRect with this
+ // clip region. Tries to return the largest possible rectangle, but may
+ // not succeed.
+ nsRect ApproximateIntersectInward(const nsRect& aRect) const;
+
+ /*
+ * Computes a region which contains the clipped area of this DisplayItemClip,
+ * or if aOldClip is non-null, the union of the clipped area of this
+ * DisplayItemClip with the clipped area of aOldClip translated by aShift.
+ * The result is stored in aCombined. If the result would be infinite
+ * (because one or both of the clips does no clipping), returns false.
+ */
+ bool ComputeRegionInClips(const DisplayItemClip* aOldClip,
+ const nsPoint& aShift, nsRegion* aCombined) const;
+
+ // Returns false if aRect is definitely not clipped by a rounded corner in
+ // this clip. Returns true if aRect is clipped by a rounded corner in this
+ // clip or it can not be quickly determined that it is not clipped by a
+ // rounded corner in this clip.
+ bool IsRectClippedByRoundedCorner(const nsRect& aRect) const;
+
+ // Returns false if aRect is definitely not clipped by anything in this clip.
+ // Fast but not necessarily accurate.
+ bool IsRectAffectedByClip(const nsRect& aRect) const;
+ bool IsRectAffectedByClip(const nsIntRect& aRect, float aXScale,
+ float aYScale, int32_t A2D) const;
+
+ // Intersection of all rects in this clip ignoring any rounded corners.
+ nsRect NonRoundedIntersection() const;
+
+ // Intersect the given rects with all rects in this clip, ignoring any
+ // rounded corners.
+ nsRect ApplyNonRoundedIntersection(const nsRect& aRect) const;
+
+ // Gets rid of any rounded corners in this clip.
+ void RemoveRoundedCorners();
+
+ // Adds the difference between Intersect(*this + aPoint, aBounds) and
+ // Intersect(aOther, aOtherBounds) to aDifference (or a bounding-box thereof).
+ void AddOffsetAndComputeDifference(const nsPoint& aPoint,
+ const nsRect& aBounds,
+ const DisplayItemClip& aOther,
+ const nsRect& aOtherBounds,
+ nsRegion* aDifference);
+
+ bool operator==(const DisplayItemClip& aOther) const {
+ return mHaveClipRect == aOther.mHaveClipRect &&
+ (!mHaveClipRect || mClipRect.IsEqualInterior(aOther.mClipRect)) &&
+ mRoundedClipRects == aOther.mRoundedClipRects;
+ }
+ bool operator!=(const DisplayItemClip& aOther) const {
+ return !(*this == aOther);
+ }
+
+ bool HasClip() const { return mHaveClipRect; }
+ const nsRect& GetClipRect() const {
+ NS_ASSERTION(HasClip(), "No clip rect!");
+ return mClipRect;
+ }
+
+ void MoveBy(const nsPoint& aPoint);
+
+ nsCString ToString() const;
+
+ uint32_t GetRoundedRectCount() const { return mRoundedClipRects.Length(); }
+ void AppendRoundedRects(nsTArray<RoundedRect>* aArray) const;
+
+ void ToComplexClipRegions(int32_t aAppUnitsPerDevPixel,
+ nsTArray<wr::ComplexClipRegion>& aOutArray) const;
+
+ static const DisplayItemClip& NoClip();
+
+ static void Shutdown();
+
+ private:
+ nsRect mClipRect;
+ CopyableTArray<RoundedRect> mRoundedClipRects;
+ // If mHaveClipRect is false then this object represents no clipping at all
+ // and mRoundedClipRects must be empty.
+ bool mHaveClipRect;
+};
+
+} // namespace mozilla
+
+#endif /* DISPLAYITEMCLIP_H_ */