OLD | NEW |
1 | |
2 /* | 1 /* |
3 * Copyright 2011 Google Inc. | 2 * Copyright 2011 Google Inc. |
4 * | 3 * |
5 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
6 * found in the LICENSE file. | 5 * found in the LICENSE file. |
7 */ | 6 */ |
| 7 |
8 #ifndef SkClipStack_DEFINED | 8 #ifndef SkClipStack_DEFINED |
9 #define SkClipStack_DEFINED | 9 #define SkClipStack_DEFINED |
10 | 10 |
| 11 #include "SkCanvas.h" |
11 #include "SkDeque.h" | 12 #include "SkDeque.h" |
12 #include "SkPath.h" | 13 #include "SkPath.h" |
13 #include "SkRect.h" | 14 #include "SkRect.h" |
14 #include "SkRRect.h" | 15 #include "SkRRect.h" |
15 #include "SkRegion.h" | 16 #include "SkRegion.h" |
16 #include "SkTLazy.h" | 17 #include "SkTLazy.h" |
17 | 18 |
18 class SkCanvasClipVisitor; | 19 class SkCanvasClipVisitor; |
19 | 20 |
20 // Because a single save/restore state can have multiple clips, this class | 21 // Because a single save/restore state can have multiple clips, this class |
(...skipping 25 matching lines...) Expand all Loading... |
46 //!< This element combines a round-rect with the current clip using
a set operation | 47 //!< This element combines a round-rect with the current clip using
a set operation |
47 kRRect_Type, | 48 kRRect_Type, |
48 //!< This element combines a path with the current clip using a set
operation | 49 //!< This element combines a path with the current clip using a set
operation |
49 kPath_Type, | 50 kPath_Type, |
50 | 51 |
51 kLastType = kPath_Type | 52 kLastType = kPath_Type |
52 }; | 53 }; |
53 static const int kTypeCnt = kLastType + 1; | 54 static const int kTypeCnt = kLastType + 1; |
54 | 55 |
55 Element() { | 56 Element() { |
56 this->initCommon(0, SkRegion::kReplace_Op, false); | 57 this->initCommon(0, SkCanvas::kReplace_Op, false); |
57 this->setEmpty(); | 58 this->setEmpty(); |
58 } | 59 } |
59 | 60 |
60 Element(const Element&); | 61 Element(const Element&); |
61 | 62 |
62 Element(const SkRect& rect, SkRegion::Op op, bool doAA) { | 63 Element(const SkRect& rect, SkCanvas::ClipOp op, bool doAA) { |
63 this->initRect(0, rect, op, doAA); | 64 this->initRect(0, rect, op, doAA); |
64 } | 65 } |
65 | 66 |
66 Element(const SkRRect& rrect, SkRegion::Op op, bool doAA) { | 67 Element(const SkRRect& rrect, SkCanvas::ClipOp op, bool doAA) { |
67 this->initRRect(0, rrect, op, doAA); | 68 this->initRRect(0, rrect, op, doAA); |
68 } | 69 } |
69 | 70 |
70 Element(const SkPath& path, SkRegion::Op op, bool doAA) { | 71 Element(const SkPath& path, SkCanvas::ClipOp op, bool doAA) { |
71 this->initPath(0, path, op, doAA); | 72 this->initPath(0, path, op, doAA); |
72 } | 73 } |
73 | 74 |
74 bool operator== (const Element& element) const; | 75 bool operator== (const Element& element) const; |
75 bool operator!= (const Element& element) const { return !(*this == eleme
nt); } | 76 bool operator!= (const Element& element) const { return !(*this == eleme
nt); } |
76 | 77 |
77 //!< Call to get the type of the clip element. | 78 //!< Call to get the type of the clip element. |
78 Type getType() const { return fType; } | 79 Type getType() const { return fType; } |
79 | 80 |
80 //!< Call to get the save count associated with this clip element. | 81 //!< Call to get the save count associated with this clip element. |
81 int getSaveCount() const { return fSaveCount; } | 82 int getSaveCount() const { return fSaveCount; } |
82 | 83 |
83 //!< Call if getType() is kPath to get the path. | 84 //!< Call if getType() is kPath to get the path. |
84 const SkPath& getPath() const { SkASSERT(kPath_Type == fType); return *f
Path.get(); } | 85 const SkPath& getPath() const { SkASSERT(kPath_Type == fType); return *f
Path.get(); } |
85 | 86 |
86 //!< Call if getType() is kRRect to get the round-rect. | 87 //!< Call if getType() is kRRect to get the round-rect. |
87 const SkRRect& getRRect() const { SkASSERT(kRRect_Type == fType); return
fRRect; } | 88 const SkRRect& getRRect() const { SkASSERT(kRRect_Type == fType); return
fRRect; } |
88 | 89 |
89 //!< Call if getType() is kRect to get the rect. | 90 //!< Call if getType() is kRect to get the rect. |
90 const SkRect& getRect() const { | 91 const SkRect& getRect() const { |
91 SkASSERT(kRect_Type == fType && (fRRect.isRect() || fRRect.isEmpty()
)); | 92 SkASSERT(kRect_Type == fType && (fRRect.isRect() || fRRect.isEmpty()
)); |
92 return fRRect.getBounds(); | 93 return fRRect.getBounds(); |
93 } | 94 } |
94 | 95 |
95 //!< Call if getType() is not kEmpty to get the set operation used to co
mbine this element. | 96 //!< Call if getType() is not kEmpty to get the set operation used to co
mbine this element. |
96 SkRegion::Op getOp() const { return fOp; } | 97 SkCanvas::ClipOp getOp() const { return fOp; } |
97 | 98 |
98 //!< Call to get the element as a path, regardless of its type. | 99 //!< Call to get the element as a path, regardless of its type. |
99 void asPath(SkPath* path) const; | 100 void asPath(SkPath* path) const; |
100 | 101 |
101 //!< Call if getType() is not kPath to get the element as a round rect. | 102 //!< Call if getType() is not kPath to get the element as a round rect. |
102 const SkRRect& asRRect() const { SkASSERT(kPath_Type != fType); return f
RRect; } | 103 const SkRRect& asRRect() const { SkASSERT(kPath_Type != fType); return f
RRect; } |
103 | 104 |
104 /** If getType() is not kEmpty this indicates whether the clip shape sho
uld be anti-aliased | 105 /** If getType() is not kEmpty this indicates whether the clip shape sho
uld be anti-aliased |
105 when it is rasterized. */ | 106 when it is rasterized. */ |
106 bool isAA() const { return fDoAA; } | 107 bool isAA() const { return fDoAA; } |
107 | 108 |
108 //!< Inverts the fill of the clip shape. Note that a kEmpty element rema
ins kEmpty. | 109 //!< Inverts the fill of the clip shape. Note that a kEmpty element rema
ins kEmpty. |
109 void invertShapeFillType(); | 110 void invertShapeFillType(); |
110 | 111 |
111 //!< Sets the set operation represented by the element. | 112 //!< Sets the set operation represented by the element. |
112 void setOp(SkRegion::Op op) { fOp = op; } | 113 void setOp(SkCanvas::ClipOp op) { fOp = op; } |
113 | 114 |
114 /** The GenID can be used by clip stack clients to cache representations
of the clip. The | 115 /** The GenID can be used by clip stack clients to cache representations
of the clip. The |
115 ID corresponds to the set of clip elements up to and including this
element within the | 116 ID corresponds to the set of clip elements up to and including this
element within the |
116 stack not to the element itself. That is the same clip path in diffe
rent stacks will | 117 stack not to the element itself. That is the same clip path in diffe
rent stacks will |
117 have a different ID since the elements produce different clip result
in the context of | 118 have a different ID since the elements produce different clip result
in the context of |
118 their stacks. */ | 119 their stacks. */ |
119 int32_t getGenID() const { SkASSERT(kInvalidGenID != fGenID); return fGe
nID; } | 120 int32_t getGenID() const { SkASSERT(kInvalidGenID != fGenID); return fGe
nID; } |
120 | 121 |
121 /** | 122 /** |
122 * Gets the bounds of the clip element, either the rect or path bounds.
(Whether the shape | 123 * Gets the bounds of the clip element, either the rect or path bounds.
(Whether the shape |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
194 */ | 195 */ |
195 void dump() const; | 196 void dump() const; |
196 #endif | 197 #endif |
197 | 198 |
198 private: | 199 private: |
199 friend class SkClipStack; | 200 friend class SkClipStack; |
200 | 201 |
201 SkTLazy<SkPath> fPath; | 202 SkTLazy<SkPath> fPath; |
202 SkRRect fRRect; | 203 SkRRect fRRect; |
203 int fSaveCount; // save count of stack when this element was
added. | 204 int fSaveCount; // save count of stack when this element was
added. |
204 SkRegion::Op fOp; | 205 SkCanvas::ClipOp fOp; |
205 Type fType; | 206 Type fType; |
206 bool fDoAA; | 207 bool fDoAA; |
207 | 208 |
208 /* fFiniteBoundType and fFiniteBound are used to incrementally update th
e clip stack's | 209 /* fFiniteBoundType and fFiniteBound are used to incrementally update th
e clip stack's |
209 bound. When fFiniteBoundType is kNormal_BoundsType, fFiniteBound repr
esents the | 210 bound. When fFiniteBoundType is kNormal_BoundsType, fFiniteBound repr
esents the |
210 conservative bounding box of the pixels that aren't clipped (i.e., an
y pixels that can be | 211 conservative bounding box of the pixels that aren't clipped (i.e., an
y pixels that can be |
211 drawn to are inside the bound). When fFiniteBoundType is kInsideOut_B
oundsType (which | 212 drawn to are inside the bound). When fFiniteBoundType is kInsideOut_B
oundsType (which |
212 occurs when a clip is inverse filled), fFiniteBound represents the co
nservative bounding | 213 occurs when a clip is inverse filled), fFiniteBound represents the co
nservative bounding |
213 box of the pixels that _are_ clipped (i.e., any pixels that cannot be
drawn to are inside | 214 box of the pixels that _are_ clipped (i.e., any pixels that cannot be
drawn to are inside |
214 the bound). When fFiniteBoundType is kInsideOut_BoundsType the actual
bound is the | 215 the bound). When fFiniteBoundType is kInsideOut_BoundsType the actual
bound is the |
215 infinite plane. This behavior of fFiniteBoundType and fFiniteBound is
required so that we | 216 infinite plane. This behavior of fFiniteBoundType and fFiniteBound is
required so that we |
216 can capture the cancelling out of the extensions to infinity when two
inverse filled | 217 can capture the cancelling out of the extensions to infinity when two
inverse filled |
217 clips are Booleaned together. */ | 218 clips are Booleaned together. */ |
218 SkClipStack::BoundsType fFiniteBoundType; | 219 SkClipStack::BoundsType fFiniteBoundType; |
219 SkRect fFiniteBound; | 220 SkRect fFiniteBound; |
220 | 221 |
221 // When element is applied to the previous elements in the stack is the
result known to be | 222 // When element is applied to the previous elements in the stack is the
result known to be |
222 // equivalent to a single rect intersection? IIOW, is the clip effective
ly a rectangle. | 223 // equivalent to a single rect intersection? IIOW, is the clip effective
ly a rectangle. |
223 bool fIsIntersectionOfRects; | 224 bool fIsIntersectionOfRects; |
224 | 225 |
225 int fGenID; | 226 int fGenID; |
226 | 227 |
227 Element(int saveCount) { | 228 Element(int saveCount) { |
228 this->initCommon(saveCount, SkRegion::kReplace_Op, false); | 229 this->initCommon(saveCount, SkCanvas::kReplace_Op, false); |
229 this->setEmpty(); | 230 this->setEmpty(); |
230 } | 231 } |
231 | 232 |
232 Element(int saveCount, const SkRRect& rrect, SkRegion::Op op, bool doAA)
{ | 233 Element(int saveCount, const SkRRect& rrect, SkCanvas::ClipOp op, bool d
oAA) { |
233 this->initRRect(saveCount, rrect, op, doAA); | 234 this->initRRect(saveCount, rrect, op, doAA); |
234 } | 235 } |
235 | 236 |
236 Element(int saveCount, const SkRect& rect, SkRegion::Op op, bool doAA) { | 237 Element(int saveCount, const SkRect& rect, SkCanvas::ClipOp op, bool doA
A) { |
237 this->initRect(saveCount, rect, op, doAA); | 238 this->initRect(saveCount, rect, op, doAA); |
238 } | 239 } |
239 | 240 |
240 Element(int saveCount, const SkPath& path, SkRegion::Op op, bool doAA) { | 241 Element(int saveCount, const SkPath& path, SkCanvas::ClipOp op, bool doA
A) { |
241 this->initPath(saveCount, path, op, doAA); | 242 this->initPath(saveCount, path, op, doAA); |
242 } | 243 } |
243 | 244 |
244 void initCommon(int saveCount, SkRegion::Op op, bool doAA) { | 245 void initCommon(int saveCount, SkCanvas::ClipOp op, bool doAA) { |
245 fSaveCount = saveCount; | 246 fSaveCount = saveCount; |
246 fOp = op; | 247 fOp = op; |
247 fDoAA = doAA; | 248 fDoAA = doAA; |
248 // A default of inside-out and empty bounds means the bounds are eff
ectively void as it | 249 // A default of inside-out and empty bounds means the bounds are eff
ectively void as it |
249 // indicates that nothing is known to be outside the clip. | 250 // indicates that nothing is known to be outside the clip. |
250 fFiniteBoundType = kInsideOut_BoundsType; | 251 fFiniteBoundType = kInsideOut_BoundsType; |
251 fFiniteBound.setEmpty(); | 252 fFiniteBound.setEmpty(); |
252 fIsIntersectionOfRects = false; | 253 fIsIntersectionOfRects = false; |
253 fGenID = kInvalidGenID; | 254 fGenID = kInvalidGenID; |
254 } | 255 } |
255 | 256 |
256 void initRect(int saveCount, const SkRect& rect, SkRegion::Op op, bool d
oAA) { | 257 void initRect(int saveCount, const SkRect& rect, SkCanvas::ClipOp op, bo
ol doAA) { |
257 fRRect.setRect(rect); | 258 fRRect.setRect(rect); |
258 fType = kRect_Type; | 259 fType = kRect_Type; |
259 this->initCommon(saveCount, op, doAA); | 260 this->initCommon(saveCount, op, doAA); |
260 } | 261 } |
261 | 262 |
262 void initRRect(int saveCount, const SkRRect& rrect, SkRegion::Op op, boo
l doAA) { | 263 void initRRect(int saveCount, const SkRRect& rrect, SkCanvas::ClipOp op,
bool doAA) { |
263 SkRRect::Type type = rrect.getType(); | 264 SkRRect::Type type = rrect.getType(); |
264 fRRect = rrect; | 265 fRRect = rrect; |
265 if (SkRRect::kRect_Type == type || SkRRect::kEmpty_Type == type) { | 266 if (SkRRect::kRect_Type == type || SkRRect::kEmpty_Type == type) { |
266 fType = kRect_Type; | 267 fType = kRect_Type; |
267 } else { | 268 } else { |
268 fType = kRRect_Type; | 269 fType = kRRect_Type; |
269 } | 270 } |
270 this->initCommon(saveCount, op, doAA); | 271 this->initCommon(saveCount, op, doAA); |
271 } | 272 } |
272 | 273 |
273 void initPath(int saveCount, const SkPath& path, SkRegion::Op op, bool d
oAA); | 274 void initPath(int saveCount, const SkPath& path, SkCanvas::ClipOp op, bo
ol doAA); |
274 | 275 |
275 void setEmpty(); | 276 void setEmpty(); |
276 | 277 |
277 // All Element methods below are only used within SkClipStack.cpp | 278 // All Element methods below are only used within SkClipStack.cpp |
278 inline void checkEmpty() const; | 279 inline void checkEmpty() const; |
279 inline bool canBeIntersectedInPlace(int saveCount, SkRegion::Op op) cons
t; | 280 inline bool canBeIntersectedInPlace(int saveCount, SkCanvas::ClipOp op)
const; |
280 /* This method checks to see if two rect clips can be safely merged into
one. The issue here | 281 /* This method checks to see if two rect clips can be safely merged into
one. The issue here |
281 is that to be strictly correct all the edges of the resulting rect mus
t have the same | 282 is that to be strictly correct all the edges of the resulting rect mus
t have the same |
282 anti-aliasing. */ | 283 anti-aliasing. */ |
283 bool rectRectIntersectAllowed(const SkRect& newR, bool newAA) const; | 284 bool rectRectIntersectAllowed(const SkRect& newR, bool newAA) const; |
284 /** Determines possible finite bounds for the Element given the previous
element of the | 285 /** Determines possible finite bounds for the Element given the previous
element of the |
285 stack */ | 286 stack */ |
286 void updateBoundAndGenID(const Element* prior); | 287 void updateBoundAndGenID(const Element* prior); |
287 // The different combination of fill & inverse fill when combining bound
ing boxes | 288 // The different combination of fill & inverse fill when combining bound
ing boxes |
288 enum FillCombo { | 289 enum FillCombo { |
289 kPrev_Cur_FillCombo, | 290 kPrev_Cur_FillCombo, |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
340 bool quickContains(const SkRRect& devRRect) const { | 341 bool quickContains(const SkRRect& devRRect) const { |
341 return this->isWideOpen() || this->internalQuickContains(devRRect); | 342 return this->isWideOpen() || this->internalQuickContains(devRRect); |
342 } | 343 } |
343 | 344 |
344 /** | 345 /** |
345 * Flattens the clip stack into a single SkPath. Returns true if any of | 346 * Flattens the clip stack into a single SkPath. Returns true if any of |
346 * the clip stack components requires anti-aliasing. | 347 * the clip stack components requires anti-aliasing. |
347 */ | 348 */ |
348 bool asPath(SkPath* path) const; | 349 bool asPath(SkPath* path) const; |
349 | 350 |
350 void clipDevRect(const SkIRect& ir, SkRegion::Op op) { | 351 void clipDevRect(const SkIRect& ir, SkCanvas::ClipOp op) { |
351 SkRect r; | 352 SkRect r; |
352 r.set(ir); | 353 r.set(ir); |
353 this->clipDevRect(r, op, false); | 354 this->clipDevRect(r, op, false); |
354 } | 355 } |
355 void clipDevRect(const SkRect&, SkRegion::Op, bool doAA); | 356 void clipDevRect(const SkRect&, SkCanvas::ClipOp, bool doAA); |
356 void clipDevRRect(const SkRRect&, SkRegion::Op, bool doAA); | 357 void clipDevRRect(const SkRRect&, SkCanvas::ClipOp, bool doAA); |
357 void clipDevPath(const SkPath&, SkRegion::Op, bool doAA); | 358 void clipDevPath(const SkPath&, SkCanvas::ClipOp, bool doAA); |
358 // An optimized version of clipDevRect(emptyRect, kIntersect, ...) | 359 // An optimized version of clipDevRect(emptyRect, kIntersect, ...) |
359 void clipEmpty(); | 360 void clipEmpty(); |
360 | 361 |
361 /** | 362 /** |
362 * isWideOpen returns true if the clip state corresponds to the infinite | 363 * isWideOpen returns true if the clip state corresponds to the infinite |
363 * plane (i.e., draws are not limited at all) | 364 * plane (i.e., draws are not limited at all) |
364 */ | 365 */ |
365 bool isWideOpen() const { return this->getTopmostGenID() == kWideOpenGenID;
} | 366 bool isWideOpen() const { return this->getTopmostGenID() == kWideOpenGenID;
} |
366 | 367 |
367 /** | 368 /** |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
418 * Return the clip element for this iterator. If next()/prev() returns
NULL, then the | 419 * Return the clip element for this iterator. If next()/prev() returns
NULL, then the |
419 * iterator is done. | 420 * iterator is done. |
420 */ | 421 */ |
421 const Element* next(); | 422 const Element* next(); |
422 const Element* prev(); | 423 const Element* prev(); |
423 | 424 |
424 /** | 425 /** |
425 * Moves the iterator to the topmost element with the specified RegionOp
and returns that | 426 * Moves the iterator to the topmost element with the specified RegionOp
and returns that |
426 * element. If no clip element with that op is found, the first element
is returned. | 427 * element. If no clip element with that op is found, the first element
is returned. |
427 */ | 428 */ |
428 const Element* skipToTopmost(SkRegion::Op op); | 429 const Element* skipToTopmost(SkCanvas::ClipOp op); |
429 | 430 |
430 /** | 431 /** |
431 * Restarts the iterator on a clip stack. | 432 * Restarts the iterator on a clip stack. |
432 */ | 433 */ |
433 void reset(const SkClipStack& stack, IterStart startLoc); | 434 void reset(const SkClipStack& stack, IterStart startLoc); |
434 | 435 |
435 private: | 436 private: |
436 const SkClipStack* fStack; | 437 const SkClipStack* fStack; |
437 SkDeque::Iter fIter; | 438 SkDeque::Iter fIter; |
438 }; | 439 }; |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
512 */ | 513 */ |
513 void restoreTo(int saveCount); | 514 void restoreTo(int saveCount); |
514 | 515 |
515 /** | 516 /** |
516 * Return the next unique generation ID. | 517 * Return the next unique generation ID. |
517 */ | 518 */ |
518 static int32_t GetNextGenID(); | 519 static int32_t GetNextGenID(); |
519 }; | 520 }; |
520 | 521 |
521 #endif | 522 #endif |
OLD | NEW |