Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef DISPLAYITEMCLIP_H_
7 #define DISPLAYITEMCLIP_H_
9 #include "nsRect.h"
10 #include "nsTArray.h"
11 #include "nsStyleConsts.h"
13 class gfxContext;
14 class nsDisplayItem;
15 class nsPresContext;
16 class nsRegion;
18 namespace mozilla {
20 /**
21 * An DisplayItemClip represents the intersection of an optional rectangle
22 * with a list of rounded rectangles (which is often empty), all in appunits.
23 * It can represent everything CSS clipping can do to an element (except for
24 * SVG clip-path), including no clipping at all.
25 */
26 class DisplayItemClip {
27 public:
28 struct RoundedRect {
29 nsRect mRect;
30 // Indices into mRadii are the NS_CORNER_* constants in nsStyleConsts.h
31 nscoord mRadii[8];
33 RoundedRect operator+(const nsPoint& aOffset) const {
34 RoundedRect r = *this;
35 r.mRect += aOffset;
36 return r;
37 }
38 bool operator==(const RoundedRect& aOther) const {
39 if (!mRect.IsEqualInterior(aOther.mRect)) {
40 return false;
41 }
43 NS_FOR_CSS_HALF_CORNERS(corner) {
44 if (mRadii[corner] != aOther.mRadii[corner]) {
45 return false;
46 }
47 }
48 return true;
49 }
50 bool operator!=(const RoundedRect& aOther) const {
51 return !(*this == aOther);
52 }
53 };
55 // Constructs a DisplayItemClip that does no clipping at all.
56 DisplayItemClip() : mHaveClipRect(false) {}
58 void SetTo(const nsRect& aRect);
59 void SetTo(const nsRect& aRect, const nscoord* aRadii);
60 void IntersectWith(const DisplayItemClip& aOther);
62 // Apply this |DisplayItemClip| to the given gfxContext. Any saving of state
63 // or clearing of other clips must be done by the caller.
64 // See aBegin/aEnd note on ApplyRoundedRectsTo.
65 void ApplyTo(gfxContext* aContext, nsPresContext* aPresContext,
66 uint32_t aBegin = 0, uint32_t aEnd = UINT32_MAX);
68 void ApplyRectTo(gfxContext* aContext, int32_t A2D) const;
69 // Applies the rounded rects in this Clip to aContext
70 // Will only apply rounded rects from aBegin (inclusive) to aEnd
71 // (exclusive) or the number of rounded rects, whichever is smaller.
72 void ApplyRoundedRectsTo(gfxContext* aContext, int32_t A2DPRInt32,
73 uint32_t aBegin, uint32_t aEnd) const;
75 // Draw (fill) the rounded rects in this clip to aContext
76 void DrawRoundedRectsTo(gfxContext* aContext, int32_t A2D,
77 uint32_t aBegin, uint32_t aEnd) const;
78 // 'Draw' (create as a path, does not stroke or fill) aRoundRect to aContext
79 void AddRoundedRectPathTo(gfxContext* aContext, int32_t A2D,
80 const RoundedRect &aRoundRect) const;
82 // Returns true if the intersection of aRect and this clip region is
83 // non-empty. This is precise for DisplayItemClips with at most one
84 // rounded rectangle. When multiple rounded rectangles are present, we just
85 // check that the rectangle intersects all of them (but possibly in different
86 // places). So it may return true when the correct answer is false.
87 bool MayIntersect(const nsRect& aRect) const;
88 // Return a rectangle contained in the intersection of aRect with this
89 // clip region. Tries to return the largest possible rectangle, but may
90 // not succeed.
91 nsRect ApproximateIntersectInward(const nsRect& aRect) const;
93 /*
94 * Computes a region which contains the clipped area of this DisplayItemClip,
95 * or if aOldClip is non-null, the union of the clipped area of this
96 * DisplayItemClip with the clipped area of aOldClip translated by aShift.
97 * The result is stored in aCombined. If the result would be infinite
98 * (because one or both of the clips does no clipping), returns false.
99 */
100 bool ComputeRegionInClips(DisplayItemClip* aOldClip,
101 const nsPoint& aShift,
102 nsRegion* aCombined) const;
104 // Returns false if aRect is definitely not clipped by a rounded corner in
105 // this clip. Returns true if aRect is clipped by a rounded corner in this
106 // clip or it can not be quickly determined that it is not clipped by a
107 // rounded corner in this clip.
108 bool IsRectClippedByRoundedCorner(const nsRect& aRect) const;
110 // Returns false if aRect is definitely not clipped by anything in this clip.
111 // Fast but not necessarily accurate.
112 bool IsRectAffectedByClip(const nsRect& aRect) const;
114 // Intersection of all rects in this clip ignoring any rounded corners.
115 nsRect NonRoundedIntersection() const;
117 // Intersect the given rects with all rects in this clip, ignoring any
118 // rounded corners.
119 nsRect ApplyNonRoundedIntersection(const nsRect& aRect) const;
121 // Gets rid of any rounded corners in this clip.
122 void RemoveRoundedCorners();
124 // Adds the difference between Intersect(*this + aPoint, aBounds) and
125 // Intersect(aOther, aOtherBounds) to aDifference (or a bounding-box thereof).
126 void AddOffsetAndComputeDifference(const nsPoint& aPoint, const nsRect& aBounds,
127 const DisplayItemClip& aOther, const nsRect& aOtherBounds,
128 nsRegion* aDifference);
130 bool operator==(const DisplayItemClip& aOther) const {
131 return mHaveClipRect == aOther.mHaveClipRect &&
132 (!mHaveClipRect || mClipRect.IsEqualInterior(aOther.mClipRect)) &&
133 mRoundedClipRects == aOther.mRoundedClipRects;
134 }
135 bool operator!=(const DisplayItemClip& aOther) const {
136 return !(*this == aOther);
137 }
139 bool HasClip() const { return mHaveClipRect; }
140 const nsRect& GetClipRect() const
141 {
142 NS_ASSERTION(HasClip(), "No clip rect!");
143 return mClipRect;
144 }
146 void MoveBy(nsPoint aPoint);
148 #ifdef MOZ_DUMP_PAINTING
149 nsCString ToString() const;
150 #endif
152 /**
153 * Find the largest N such that the first N rounded rects in 'this' are
154 * equal to the first N rounded rects in aOther, and N <= aMax.
155 */
156 uint32_t GetCommonRoundedRectCount(const DisplayItemClip& aOther,
157 uint32_t aMax) const;
158 uint32_t GetRoundedRectCount() const { return mRoundedClipRects.Length(); }
159 void AppendRoundedRects(nsTArray<RoundedRect>* aArray, uint32_t aCount) const;
161 static const DisplayItemClip& NoClip();
163 static void Shutdown();
165 private:
166 nsRect mClipRect;
167 nsTArray<RoundedRect> mRoundedClipRects;
168 // If mHaveClipRect is false then this object represents no clipping at all
169 // and mRoundedClipRects must be empty.
170 bool mHaveClipRect;
171 };
173 }
175 #endif /* DISPLAYITEMCLIP_H_ */