|
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/. */ |
|
5 |
|
6 #ifndef DISPLAYITEMCLIP_H_ |
|
7 #define DISPLAYITEMCLIP_H_ |
|
8 |
|
9 #include "nsRect.h" |
|
10 #include "nsTArray.h" |
|
11 #include "nsStyleConsts.h" |
|
12 |
|
13 class gfxContext; |
|
14 class nsDisplayItem; |
|
15 class nsPresContext; |
|
16 class nsRegion; |
|
17 |
|
18 namespace mozilla { |
|
19 |
|
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]; |
|
32 |
|
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 } |
|
42 |
|
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 }; |
|
54 |
|
55 // Constructs a DisplayItemClip that does no clipping at all. |
|
56 DisplayItemClip() : mHaveClipRect(false) {} |
|
57 |
|
58 void SetTo(const nsRect& aRect); |
|
59 void SetTo(const nsRect& aRect, const nscoord* aRadii); |
|
60 void IntersectWith(const DisplayItemClip& aOther); |
|
61 |
|
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); |
|
67 |
|
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; |
|
74 |
|
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; |
|
81 |
|
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; |
|
92 |
|
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; |
|
103 |
|
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; |
|
109 |
|
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; |
|
113 |
|
114 // Intersection of all rects in this clip ignoring any rounded corners. |
|
115 nsRect NonRoundedIntersection() const; |
|
116 |
|
117 // Intersect the given rects with all rects in this clip, ignoring any |
|
118 // rounded corners. |
|
119 nsRect ApplyNonRoundedIntersection(const nsRect& aRect) const; |
|
120 |
|
121 // Gets rid of any rounded corners in this clip. |
|
122 void RemoveRoundedCorners(); |
|
123 |
|
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); |
|
129 |
|
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 } |
|
138 |
|
139 bool HasClip() const { return mHaveClipRect; } |
|
140 const nsRect& GetClipRect() const |
|
141 { |
|
142 NS_ASSERTION(HasClip(), "No clip rect!"); |
|
143 return mClipRect; |
|
144 } |
|
145 |
|
146 void MoveBy(nsPoint aPoint); |
|
147 |
|
148 #ifdef MOZ_DUMP_PAINTING |
|
149 nsCString ToString() const; |
|
150 #endif |
|
151 |
|
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; |
|
160 |
|
161 static const DisplayItemClip& NoClip(); |
|
162 |
|
163 static void Shutdown(); |
|
164 |
|
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 }; |
|
172 |
|
173 } |
|
174 |
|
175 #endif /* DISPLAYITEMCLIP_H_ */ |