OLD | NEW |
1 | 1 |
2 /* | 2 /* |
3 * Copyright 2011 Google Inc. | 3 * Copyright 2011 Google Inc. |
4 * | 4 * |
5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
7 */ | 7 */ |
8 #ifndef SkClipStack_DEFINED | 8 #ifndef SkClipStack_DEFINED |
9 #define SkClipStack_DEFINED | 9 #define SkClipStack_DEFINED |
10 | 10 |
11 #include "SkDeque.h" | 11 #include "SkDeque.h" |
12 #include "SkPath.h" | 12 #include "SkPath.h" |
13 #include "SkRect.h" | 13 #include "SkRect.h" |
| 14 #include "SkRRect.h" |
14 #include "SkRegion.h" | 15 #include "SkRegion.h" |
15 #include "SkTDArray.h" | 16 #include "SkTDArray.h" |
16 | 17 |
17 | 18 |
18 // Because a single save/restore state can have multiple clips, this class | 19 // Because a single save/restore state can have multiple clips, this class |
19 // stores the stack depth (fSaveCount) and clips (fDeque) separately. | 20 // stores the stack depth (fSaveCount) and clips (fDeque) separately. |
20 // Each clip in fDeque stores the stack state to which it belongs | 21 // Each clip in fDeque stores the stack state to which it belongs |
21 // (i.e., the fSaveCount in force when it was added). Restores are thus | 22 // (i.e., the fSaveCount in force when it was added). Restores are thus |
22 // implemented by removing clips from fDeque that have an fSaveCount larger | 23 // implemented by removing clips from fDeque that have an fSaveCount larger |
23 // then the freshly decremented count. | 24 // then the freshly decremented count. |
(...skipping 10 matching lines...) Expand all Loading... |
34 kInsideOut_BoundsType | 35 kInsideOut_BoundsType |
35 }; | 36 }; |
36 | 37 |
37 class Element { | 38 class Element { |
38 public: | 39 public: |
39 enum Type { | 40 enum Type { |
40 //!< This element makes the clip empty (regardless of previous eleme
nts). | 41 //!< This element makes the clip empty (regardless of previous eleme
nts). |
41 kEmpty_Type, | 42 kEmpty_Type, |
42 //!< This element combines a rect with the current clip using a set
operation | 43 //!< This element combines a rect with the current clip using a set
operation |
43 kRect_Type, | 44 kRect_Type, |
| 45 //!< This element combines a round-rect with the current clip using
a set operation |
| 46 kRRect_Type, |
44 //!< This element combines a path with the current clip using a set
operation | 47 //!< This element combines a path with the current clip using a set
operation |
45 kPath_Type, | 48 kPath_Type, |
46 }; | 49 }; |
47 | 50 |
48 Element() { | 51 Element() { |
49 this->initCommon(0, SkRegion::kReplace_Op, false); | 52 this->initCommon(0, SkRegion::kReplace_Op, false); |
50 this->setEmpty(); | 53 this->setEmpty(); |
51 } | 54 } |
52 | 55 |
53 Element(const SkRect& rect, SkRegion::Op op, bool doAA) { | 56 Element(const SkRect& rect, SkRegion::Op op, bool doAA) { |
54 this->initRect(0, rect, op, doAA); | 57 this->initRect(0, rect, op, doAA); |
55 } | 58 } |
56 | 59 |
| 60 Element(const SkRRect& rrect, SkRegion::Op op, bool doAA) { |
| 61 this->initRRect(0, rrect, op, doAA); |
| 62 } |
| 63 |
57 Element(const SkPath& path, SkRegion::Op op, bool doAA) { | 64 Element(const SkPath& path, SkRegion::Op op, bool doAA) { |
58 this->initPath(0, path, op, doAA); | 65 this->initPath(0, path, op, doAA); |
59 } | 66 } |
60 | 67 |
61 bool operator== (const Element& element) const { | 68 bool operator== (const Element& element) const; |
62 if (this == &element) { | |
63 return true; | |
64 } | |
65 if (fOp != element.fOp || | |
66 fType != element.fType || | |
67 fDoAA != element.fDoAA || | |
68 fSaveCount != element.fSaveCount) { | |
69 return false; | |
70 } | |
71 switch (fType) { | |
72 case kPath_Type: | |
73 return fPath == element.fPath; | |
74 case kRect_Type: | |
75 return fRect == element.fRect; | |
76 case kEmpty_Type: | |
77 return true; | |
78 default: | |
79 SkDEBUGFAIL("Unexpected type."); | |
80 return false; | |
81 } | |
82 } | |
83 bool operator!= (const Element& element) const { return !(*this == eleme
nt); } | 69 bool operator!= (const Element& element) const { return !(*this == eleme
nt); } |
84 | 70 |
85 //!< Call to get the type of the clip element. | 71 //!< Call to get the type of the clip element. |
86 Type getType() const { return fType; } | 72 Type getType() const { return fType; } |
87 | 73 |
88 //!< Call if getType() is kPath to get the path. | 74 //!< Call if getType() is kPath to get the path. |
89 const SkPath& getPath() const { return fPath; } | 75 const SkPath& getPath() const { SkASSERT(kPath_Type == fType); return fP
ath; } |
| 76 |
| 77 //!< Call if getType() is kRRect to get the round-rect. |
| 78 const SkRRect& getRRect() const { SkASSERT(kRRect_Type == fType); return
fRRect; } |
90 | 79 |
91 //!< Call if getType() is kRect to get the rect. | 80 //!< Call if getType() is kRect to get the rect. |
92 const SkRect& getRect() const { return fRect; } | 81 const SkRect& getRect() const { SkASSERT(kRect_Type == fType); return fR
ect; } |
93 | 82 |
94 //!< Call if getType() is not kEmpty to get the set operation used to co
mbine this element. | 83 //!< Call if getType() is not kEmpty to get the set operation used to co
mbine this element. |
95 SkRegion::Op getOp() const { return fOp; } | 84 SkRegion::Op getOp() const { return fOp; } |
96 | 85 |
| 86 //!< Call to get the element as a path, regardless of its type. |
| 87 void asPath(SkPath* path) const; |
| 88 |
97 /** If getType() is not kEmpty this indicates whether the clip shape sho
uld be anti-aliased | 89 /** If getType() is not kEmpty this indicates whether the clip shape sho
uld be anti-aliased |
98 when it is rasterized. */ | 90 when it is rasterized. */ |
99 bool isAA() const { return fDoAA; } | 91 bool isAA() const { return fDoAA; } |
100 | 92 |
101 //!< Inverts the fill of the clip shape. Note that a kEmpty element rema
ins kEmpty. | 93 //!< Inverts the fill of the clip shape. Note that a kEmpty element rema
ins kEmpty. |
102 void invertShapeFillType(); | 94 void invertShapeFillType(); |
103 | 95 |
104 //!< Sets the set operation represented by the element. | 96 //!< Sets the set operation represented by the element. |
105 void setOp(SkRegion::Op op) { fOp = op; } | 97 void setOp(SkRegion::Op op) { fOp = op; } |
106 | 98 |
107 /** The GenID can be used by clip stack clients to cache representations
of the clip. The | 99 /** The GenID can be used by clip stack clients to cache representations
of the clip. The |
108 ID corresponds to the set of clip elements up to and including this
element within the | 100 ID corresponds to the set of clip elements up to and including this
element within the |
109 stack not to the element itself. That is the same clip path in diffe
rent stacks will | 101 stack not to the element itself. That is the same clip path in diffe
rent stacks will |
110 have a different ID since the elements produce different clip result
in the context of | 102 have a different ID since the elements produce different clip result
in the context of |
111 their stacks. */ | 103 their stacks. */ |
112 int32_t getGenID() const { SkASSERT(kInvalidGenID != fGenID); return fGe
nID; } | 104 int32_t getGenID() const { SkASSERT(kInvalidGenID != fGenID); return fGe
nID; } |
113 | 105 |
114 /** | 106 /** |
115 * Gets the bounds of the clip element, either the rect or path bounds.
(Whether the shape | 107 * Gets the bounds of the clip element, either the rect or path bounds.
(Whether the shape |
116 * is inverse filled is not considered.) | 108 * is inverse filled is not considered.) |
117 */ | 109 */ |
118 const SkRect& getBounds() const { | 110 const SkRect& getBounds() const { |
119 static const SkRect kEmpty = { 0, 0, 0, 0 }; | 111 static const SkRect kEmpty = { 0, 0, 0, 0 }; |
120 switch (fType) { | 112 switch (fType) { |
121 case kRect_Type: | 113 case kRect_Type: |
122 return fRect; | 114 return fRect; |
| 115 case kRRect_Type: |
| 116 return fRRect.getBounds(); |
123 case kPath_Type: | 117 case kPath_Type: |
124 return fPath.getBounds(); | 118 return fPath.getBounds(); |
125 case kEmpty_Type: | 119 case kEmpty_Type: |
126 return kEmpty; | 120 return kEmpty; |
127 default: | 121 default: |
128 SkDEBUGFAIL("Unexpected type."); | 122 SkDEBUGFAIL("Unexpected type."); |
129 return kEmpty; | 123 return kEmpty; |
130 } | 124 } |
131 } | 125 } |
132 | 126 |
133 /** | 127 /** |
134 * Conservatively checks whether the clip shape contains the rect param.
(Whether the shape | 128 * Conservatively checks whether the clip shape contains the rect param.
(Whether the shape |
135 * is inverse filled is not considered.) | 129 * is inverse filled is not considered.) |
136 */ | 130 */ |
137 bool contains(const SkRect& rect) const { | 131 bool contains(const SkRect& rect) const { |
138 switch (fType) { | 132 switch (fType) { |
139 case kRect_Type: | 133 case kRect_Type: |
140 return fRect.contains(rect); | 134 return fRect.contains(rect); |
| 135 case kRRect_Type: |
| 136 return fRRect.contains(rect); |
141 case kPath_Type: | 137 case kPath_Type: |
142 return fPath.conservativelyContainsRect(rect); | 138 return fPath.conservativelyContainsRect(rect); |
143 case kEmpty_Type: | 139 case kEmpty_Type: |
144 return false; | 140 return false; |
145 default: | 141 default: |
146 SkDEBUGFAIL("Unexpected type."); | 142 SkDEBUGFAIL("Unexpected type."); |
147 return false; | 143 return false; |
148 } | 144 } |
149 } | 145 } |
150 | 146 |
151 /** | 147 /** |
152 * Is the clip shape inverse filled. | 148 * Is the clip shape inverse filled. |
153 */ | 149 */ |
154 bool isInverseFilled() const { | 150 bool isInverseFilled() const { |
155 return kPath_Type == fType && fPath.isInverseFillType(); | 151 return kPath_Type == fType && fPath.isInverseFillType(); |
156 } | 152 } |
157 | 153 |
158 private: | 154 private: |
159 friend class SkClipStack; | 155 friend class SkClipStack; |
160 | 156 |
161 SkPath fPath; | 157 SkPath fPath; |
162 SkRect fRect; | 158 SkRect fRect; |
| 159 SkRRect fRRect; |
163 int fSaveCount; // save count of stack when this element was
added. | 160 int fSaveCount; // save count of stack when this element was
added. |
164 SkRegion::Op fOp; | 161 SkRegion::Op fOp; |
165 Type fType; | 162 Type fType; |
166 bool fDoAA; | 163 bool fDoAA; |
167 | 164 |
168 /* fFiniteBoundType and fFiniteBound are used to incrementally update th
e clip stack's | 165 /* fFiniteBoundType and fFiniteBound are used to incrementally update th
e clip stack's |
169 bound. When fFiniteBoundType is kNormal_BoundsType, fFiniteBound repr
esents the | 166 bound. When fFiniteBoundType is kNormal_BoundsType, fFiniteBound repr
esents the |
170 conservative bounding box of the pixels that aren't clipped (i.e., an
y pixels that can be | 167 conservative bounding box of the pixels that aren't clipped (i.e., an
y pixels that can be |
171 drawn to are inside the bound). When fFiniteBoundType is kInsideOut_B
oundsType (which | 168 drawn to are inside the bound). When fFiniteBoundType is kInsideOut_B
oundsType (which |
172 occurs when a clip is inverse filled), fFiniteBound represents the co
nservative bounding | 169 occurs when a clip is inverse filled), fFiniteBound represents the co
nservative bounding |
173 box of the pixels that _are_ clipped (i.e., any pixels that cannot be
drawn to are inside | 170 box of the pixels that _are_ clipped (i.e., any pixels that cannot be
drawn to are inside |
174 the bound). When fFiniteBoundType is kInsideOut_BoundsType the actual
bound is the | 171 the bound). When fFiniteBoundType is kInsideOut_BoundsType the actual
bound is the |
175 infinite plane. This behavior of fFiniteBoundType and fFiniteBound is
required so that we | 172 infinite plane. This behavior of fFiniteBoundType and fFiniteBound is
required so that we |
176 can capture the cancelling out of the extensions to infinity when two
inverse filled | 173 can capture the cancelling out of the extensions to infinity when two
inverse filled |
177 clips are Booleaned together. */ | 174 clips are Booleaned together. */ |
178 SkClipStack::BoundsType fFiniteBoundType; | 175 SkClipStack::BoundsType fFiniteBoundType; |
179 SkRect fFiniteBound; | 176 SkRect fFiniteBound; |
180 | 177 |
181 // When element is applied to the previous elements in the stack is the
result known to be | 178 // When element is applied to the previous elements in the stack is the
result known to be |
182 // equivalent to a single rect intersection? IIOW, is the clip effective
ly a rectangle. | 179 // equivalent to a single rect intersection? IIOW, is the clip effective
ly a rectangle. |
183 bool fIsIntersectionOfRects; | 180 bool fIsIntersectionOfRects; |
184 | 181 |
185 int fGenID; | 182 int fGenID; |
186 | 183 |
187 Element(int saveCount) { | 184 Element(int saveCount) { |
188 this->initCommon(saveCount, SkRegion::kReplace_Op, false); | 185 this->initCommon(saveCount, SkRegion::kReplace_Op, false); |
189 this->setEmpty(); | 186 this->setEmpty(); |
190 } | 187 } |
191 | 188 |
| 189 Element(int saveCount, const SkRRect& rrect, SkRegion::Op op, bool doAA)
{ |
| 190 this->initRRect(saveCount, rrect, op, doAA); |
| 191 } |
| 192 |
192 Element(int saveCount, const SkRect& rect, SkRegion::Op op, bool doAA) { | 193 Element(int saveCount, const SkRect& rect, SkRegion::Op op, bool doAA) { |
193 this->initRect(saveCount, rect, op, doAA); | 194 this->initRect(saveCount, rect, op, doAA); |
194 } | 195 } |
195 | 196 |
196 Element(int saveCount, const SkPath& path, SkRegion::Op op, bool doAA) { | 197 Element(int saveCount, const SkPath& path, SkRegion::Op op, bool doAA) { |
197 this->initPath(saveCount, path, op, doAA); | 198 this->initPath(saveCount, path, op, doAA); |
198 } | 199 } |
199 | 200 |
200 void initCommon(int saveCount, SkRegion::Op op, bool doAA) { | 201 void initCommon(int saveCount, SkRegion::Op op, bool doAA) { |
201 fSaveCount = saveCount; | 202 fSaveCount = saveCount; |
202 fOp = op; | 203 fOp = op; |
203 fDoAA = doAA; | 204 fDoAA = doAA; |
204 // A default of inside-out and empty bounds means the bounds are eff
ectively void as it | 205 // A default of inside-out and empty bounds means the bounds are eff
ectively void as it |
205 // indicates that nothing is known to be outside the clip. | 206 // indicates that nothing is known to be outside the clip. |
206 fFiniteBoundType = kInsideOut_BoundsType; | 207 fFiniteBoundType = kInsideOut_BoundsType; |
207 fFiniteBound.setEmpty(); | 208 fFiniteBound.setEmpty(); |
208 fIsIntersectionOfRects = false; | 209 fIsIntersectionOfRects = false; |
209 fGenID = kInvalidGenID; | 210 fGenID = kInvalidGenID; |
210 } | 211 } |
211 | 212 |
212 void initRect(int saveCount, const SkRect& rect, SkRegion::Op op, bool d
oAA) { | 213 void initRect(int saveCount, const SkRect& rect, SkRegion::Op op, bool d
oAA) { |
213 fRect = rect; | 214 fRect = rect; |
214 fType = kRect_Type; | 215 fType = kRect_Type; |
215 this->initCommon(saveCount, op, doAA); | 216 this->initCommon(saveCount, op, doAA); |
216 } | 217 } |
217 | 218 |
218 void initPath(int saveCount, const SkPath& path, SkRegion::Op op, bool d
oAA) { | 219 void initRRect(int saveCount, const SkRRect& rrect, SkRegion::Op op, boo
l doAA) { |
219 fPath = path; | 220 if (rrect.isRect()) { |
220 fType = kPath_Type; | 221 fRect = rrect.getBounds(); |
| 222 fType = kRect_Type; |
| 223 } else { |
| 224 fRRect = rrect; |
| 225 fType = kRRect_Type; |
| 226 } |
221 this->initCommon(saveCount, op, doAA); | 227 this->initCommon(saveCount, op, doAA); |
222 } | 228 } |
223 | 229 |
| 230 void initPath(int saveCount, const SkPath& path, SkRegion::Op op, bool d
oAA); |
| 231 |
224 void setEmpty() { | 232 void setEmpty() { |
225 fType = kEmpty_Type; | 233 fType = kEmpty_Type; |
226 fFiniteBound.setEmpty(); | 234 fFiniteBound.setEmpty(); |
227 fFiniteBoundType = kNormal_BoundsType; | 235 fFiniteBoundType = kNormal_BoundsType; |
228 fIsIntersectionOfRects = false; | 236 fIsIntersectionOfRects = false; |
229 fRect.setEmpty(); | 237 fRect.setEmpty(); |
| 238 fRRect.setEmpty(); |
230 fPath.reset(); | 239 fPath.reset(); |
231 fGenID = kEmptyGenID; | 240 fGenID = kEmptyGenID; |
| 241 SkDEBUGCODE(this->checkEmpty();) |
232 } | 242 } |
233 | 243 |
234 // All Element methods below are only used within SkClipStack.cpp | 244 // All Element methods below are only used within SkClipStack.cpp |
235 inline void checkEmpty() const; | 245 inline void checkEmpty() const; |
236 inline bool canBeIntersectedInPlace(int saveCount, SkRegion::Op op) cons
t; | 246 inline bool canBeIntersectedInPlace(int saveCount, SkRegion::Op op) cons
t; |
237 /* This method checks to see if two rect clips can be safely merged into
one. The issue here | 247 /* This method checks to see if two rect clips can be safely merged into
one. The issue here |
238 is that to be strictly correct all the edges of the resulting rect mus
t have the same | 248 is that to be strictly correct all the edges of the resulting rect mus
t have the same |
239 anti-aliasing. */ | 249 anti-aliasing. */ |
240 bool rectRectIntersectAllowed(const SkRect& newR, bool newAA) const; | 250 bool rectRectIntersectAllowed(const SkRect& newR, bool newAA) const; |
241 /** Determines possible finite bounds for the Element given the previous
element of the | 251 /** Determines possible finite bounds for the Element given the previous
element of the |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
298 * is not contained by the clip. | 308 * is not contained by the clip. |
299 */ | 309 */ |
300 bool quickContains(const SkRect& devRect) const; | 310 bool quickContains(const SkRect& devRect) const; |
301 | 311 |
302 void clipDevRect(const SkIRect& ir, SkRegion::Op op) { | 312 void clipDevRect(const SkIRect& ir, SkRegion::Op op) { |
303 SkRect r; | 313 SkRect r; |
304 r.set(ir); | 314 r.set(ir); |
305 this->clipDevRect(r, op, false); | 315 this->clipDevRect(r, op, false); |
306 } | 316 } |
307 void clipDevRect(const SkRect&, SkRegion::Op, bool doAA); | 317 void clipDevRect(const SkRect&, SkRegion::Op, bool doAA); |
| 318 void clipDevRRect(const SkRRect&, SkRegion::Op, bool doAA); |
308 void clipDevPath(const SkPath&, SkRegion::Op, bool doAA); | 319 void clipDevPath(const SkPath&, SkRegion::Op, bool doAA); |
309 // An optimized version of clipDevRect(emptyRect, kIntersect, ...) | 320 // An optimized version of clipDevRect(emptyRect, kIntersect, ...) |
310 void clipEmpty(); | 321 void clipEmpty(); |
311 | 322 |
312 /** | 323 /** |
313 * isWideOpen returns true if the clip state corresponds to the infinite | 324 * isWideOpen returns true if the clip state corresponds to the infinite |
314 * plane (i.e., draws are not limited at all) | 325 * plane (i.e., draws are not limited at all) |
315 */ | 326 */ |
316 bool isWideOpen() const; | 327 bool isWideOpen() const; |
317 | 328 |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
421 | 432 |
422 SkDeque fDeque; | 433 SkDeque fDeque; |
423 int fSaveCount; | 434 int fSaveCount; |
424 | 435 |
425 // Generation ID for the clip stack. This is incremented for each | 436 // Generation ID for the clip stack. This is incremented for each |
426 // clipDevRect and clipDevPath call. 0 is reserved to indicate an | 437 // clipDevRect and clipDevPath call. 0 is reserved to indicate an |
427 // invalid ID. | 438 // invalid ID. |
428 static int32_t gGenID; | 439 static int32_t gGenID; |
429 | 440 |
430 /** | 441 /** |
| 442 * Helper for clipDevPath, etc. |
| 443 */ |
| 444 void pushElement(const Element& element); |
| 445 |
| 446 /** |
431 * Restore the stack back to the specified save count. | 447 * Restore the stack back to the specified save count. |
432 */ | 448 */ |
433 void restoreTo(int saveCount); | 449 void restoreTo(int saveCount); |
434 | 450 |
435 /** | 451 /** |
436 * Return the next unique generation ID. | 452 * Return the next unique generation ID. |
437 */ | 453 */ |
438 static int32_t GetNextGenID(); | 454 static int32_t GetNextGenID(); |
439 }; | 455 }; |
440 | 456 |
441 #endif | 457 #endif |
OLD | NEW |