| 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 |