| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2016 Google Inc. | 2 * Copyright 2016 Google Inc. |
| 3 * | 3 * |
| 4 * 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 |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "GrShape.h" | 8 #include "GrShape.h" |
| 9 | 9 |
| 10 GrShape& GrShape::operator=(const GrShape& that) { | 10 GrShape& GrShape::operator=(const GrShape& that) { |
| 11 bool wasPath = Type::kPath == fType; | |
| 12 fStyle = that.fStyle; | 11 fStyle = that.fStyle; |
| 13 fType = that.fType; | 12 this->changeType(that.fType, Type::kPath == that.fType ? &that.path() : null
ptr); |
| 14 switch (fType) { | 13 switch (fType) { |
| 15 case Type::kEmpty: | 14 case Type::kEmpty: |
| 16 if (wasPath) { | |
| 17 fPath.reset(); | |
| 18 } | |
| 19 break; | 15 break; |
| 20 case Type::kRRect: | 16 case Type::kRRect: |
| 21 if (wasPath) { | 17 fRRectData.fRRect = that.fRRectData.fRRect; |
| 22 fPath.reset(); | 18 fRRectData.fDir = that.fRRectData.fDir; |
| 23 } | 19 fRRectData.fStart = that.fRRectData.fStart; |
| 24 fRRect = that.fRRect; | 20 fRRectData.fInverted = that.fRRectData.fInverted; |
| 25 fRRectDir = that.fRRectDir; | |
| 26 fRRectStart = that.fRRectStart; | |
| 27 fRRectIsInverted = that.fRRectIsInverted; | |
| 28 break; | 21 break; |
| 29 case Type::kPath: | 22 case Type::kPath: |
| 30 if (wasPath) { | 23 fPathData.fGenID = that.fPathData.fGenID; |
| 31 *fPath.get() = *that.fPath.get(); | |
| 32 } else { | |
| 33 fPath.set(*that.fPath.get()); | |
| 34 } | |
| 35 fPathGenID = that.fPathGenID; | |
| 36 break; | 24 break; |
| 37 } | 25 } |
| 38 fInheritedKey.reset(that.fInheritedKey.count()); | 26 fInheritedKey.reset(that.fInheritedKey.count()); |
| 39 sk_careful_memcpy(fInheritedKey.get(), that.fInheritedKey.get(), | 27 sk_careful_memcpy(fInheritedKey.get(), that.fInheritedKey.get(), |
| 40 sizeof(uint32_t) * fInheritedKey.count()); | 28 sizeof(uint32_t) * fInheritedKey.count()); |
| 41 return *this; | 29 return *this; |
| 42 } | 30 } |
| 43 | 31 |
| 44 const SkRect& GrShape::bounds() const { | 32 const SkRect& GrShape::bounds() const { |
| 45 static constexpr SkRect kEmpty = SkRect::MakeEmpty(); | 33 static constexpr SkRect kEmpty = SkRect::MakeEmpty(); |
| 46 switch (fType) { | 34 switch (fType) { |
| 47 case Type::kEmpty: | 35 case Type::kEmpty: |
| 48 return kEmpty; | 36 return kEmpty; |
| 49 case Type::kRRect: | 37 case Type::kRRect: |
| 50 return fRRect.getBounds(); | 38 return fRRectData.fRRect.getBounds(); |
| 51 case Type::kPath: | 39 case Type::kPath: |
| 52 return fPath.get()->getBounds(); | 40 return this->path().getBounds(); |
| 53 } | 41 } |
| 54 SkFAIL("Unknown shape type"); | 42 SkFAIL("Unknown shape type"); |
| 55 return kEmpty; | 43 return kEmpty; |
| 56 } | 44 } |
| 57 | 45 |
| 58 void GrShape::styledBounds(SkRect* bounds) const { | 46 void GrShape::styledBounds(SkRect* bounds) const { |
| 59 if (Type::kEmpty == fType && !fStyle.hasNonDashPathEffect()) { | 47 if (Type::kEmpty == fType && !fStyle.hasNonDashPathEffect()) { |
| 60 *bounds = SkRect::MakeEmpty(); | 48 *bounds = SkRect::MakeEmpty(); |
| 61 } else { | 49 } else { |
| 62 fStyle.adjustBounds(bounds, this->bounds()); | 50 fStyle.adjustBounds(bounds, this->bounds()); |
| 63 } | 51 } |
| 64 } | 52 } |
| 65 | 53 |
| 66 int GrShape::unstyledKeySize() const { | 54 int GrShape::unstyledKeySize() const { |
| 67 if (fInheritedKey.count()) { | 55 if (fInheritedKey.count()) { |
| 68 return fInheritedKey.count(); | 56 return fInheritedKey.count(); |
| 69 } | 57 } |
| 70 switch (fType) { | 58 switch (fType) { |
| 71 case Type::kEmpty: | 59 case Type::kEmpty: |
| 72 return 1; | 60 return 1; |
| 73 case Type::kRRect: | 61 case Type::kRRect: |
| 74 SkASSERT(!fInheritedKey.count()); | 62 SkASSERT(!fInheritedKey.count()); |
| 75 SkASSERT(0 == SkRRect::kSizeInMemory % sizeof(uint32_t)); | 63 SkASSERT(0 == SkRRect::kSizeInMemory % sizeof(uint32_t)); |
| 76 // + 1 for the direction, start index, and inverseness. | 64 // + 1 for the direction, start index, and inverseness. |
| 77 return SkRRect::kSizeInMemory / sizeof(uint32_t) + 1; | 65 return SkRRect::kSizeInMemory / sizeof(uint32_t) + 1; |
| 78 case Type::kPath: | 66 case Type::kPath: |
| 79 if (0 == fPathGenID) { | 67 if (0 == fPathData.fGenID) { |
| 80 return -1; | 68 return -1; |
| 81 } else { | 69 } else { |
| 82 // The key is the path ID and fill type. | 70 // The key is the path ID and fill type. |
| 83 return 2; | 71 return 2; |
| 84 } | 72 } |
| 85 } | 73 } |
| 86 SkFAIL("Should never get here."); | 74 SkFAIL("Should never get here."); |
| 87 return 0; | 75 return 0; |
| 88 } | 76 } |
| 89 | 77 |
| 90 void GrShape::writeUnstyledKey(uint32_t* key) const { | 78 void GrShape::writeUnstyledKey(uint32_t* key) const { |
| 91 SkASSERT(this->unstyledKeySize()); | 79 SkASSERT(this->unstyledKeySize()); |
| 92 SkDEBUGCODE(uint32_t* origKey = key;) | 80 SkDEBUGCODE(uint32_t* origKey = key;) |
| 93 if (fInheritedKey.count()) { | 81 if (fInheritedKey.count()) { |
| 94 memcpy(key, fInheritedKey.get(), sizeof(uint32_t) * fInheritedKey.count(
)); | 82 memcpy(key, fInheritedKey.get(), sizeof(uint32_t) * fInheritedKey.count(
)); |
| 95 SkDEBUGCODE(key += fInheritedKey.count();) | 83 SkDEBUGCODE(key += fInheritedKey.count();) |
| 96 } else { | 84 } else { |
| 97 switch (fType) { | 85 switch (fType) { |
| 98 case Type::kEmpty: | 86 case Type::kEmpty: |
| 99 *key++ = 1; | 87 *key++ = 1; |
| 100 break; | 88 break; |
| 101 case Type::kRRect: | 89 case Type::kRRect: |
| 102 fRRect.writeToMemory(key); | 90 fRRectData.fRRect.writeToMemory(key); |
| 103 key += SkRRect::kSizeInMemory / sizeof(uint32_t); | 91 key += SkRRect::kSizeInMemory / sizeof(uint32_t); |
| 104 *key = (fRRectDir == SkPath::kCCW_Direction) ? (1 << 31) : 0; | 92 *key = (fRRectData.fDir == SkPath::kCCW_Direction) ? (1 << 31) :
0; |
| 105 *key |= fRRectIsInverted ? (1 << 30) : 0; | 93 *key |= fRRectData.fInverted ? (1 << 30) : 0; |
| 106 *key++ |= fRRectStart; | 94 *key++ |= fRRectData.fStart; |
| 107 SkASSERT(fRRectStart < 8); | 95 SkASSERT(fRRectData.fStart < 8); |
| 108 break; | 96 break; |
| 109 case Type::kPath: | 97 case Type::kPath: |
| 110 SkASSERT(fPathGenID); | 98 SkASSERT(fPathData.fGenID); |
| 111 *key++ = fPathGenID; | 99 *key++ = fPathData.fGenID; |
| 112 // We could canonicalize the fill rule for paths that don't diff
erentiate between | 100 // We could canonicalize the fill rule for paths that don't diff
erentiate between |
| 113 // even/odd or winding fill (e.g. convex). | 101 // even/odd or winding fill (e.g. convex). |
| 114 *key++ = fPath.get()->getFillType(); | 102 *key++ = this->path().getFillType(); |
| 115 break; | 103 break; |
| 116 } | 104 } |
| 117 } | 105 } |
| 118 SkASSERT(key - origKey == this->unstyledKeySize()); | 106 SkASSERT(key - origKey == this->unstyledKeySize()); |
| 119 } | 107 } |
| 120 | 108 |
| 121 void GrShape::setInheritedKey(const GrShape &parent, GrStyle::Apply apply, SkSca
lar scale) { | 109 void GrShape::setInheritedKey(const GrShape &parent, GrStyle::Apply apply, SkSca
lar scale) { |
| 122 SkASSERT(!fInheritedKey.count()); | 110 SkASSERT(!fInheritedKey.count()); |
| 123 // If the output shape turns out to be simple, then we will just use its geo
metric key | 111 // If the output shape turns out to be simple, then we will just use its geo
metric key |
| 124 if (Type::kPath == fType) { | 112 if (Type::kPath == fType) { |
| 125 // We want ApplyFullStyle(ApplyPathEffect(shape)) to have the same key a
s | 113 // We want ApplyFullStyle(ApplyPathEffect(shape)) to have the same key a
s |
| 126 // ApplyFullStyle(shape). | 114 // ApplyFullStyle(shape). |
| 127 // The full key is structured as (geo,path_effect,stroke). | 115 // The full key is structured as (geo,path_effect,stroke). |
| 128 // If we do ApplyPathEffect we get get,path_effect as the inherited key.
If we then | 116 // If we do ApplyPathEffect we get get,path_effect as the inherited key.
If we then |
| 129 // do ApplyFullStyle we'll memcpy geo,path_effect into the new inherited
key | 117 // do ApplyFullStyle we'll memcpy geo,path_effect into the new inherited
key |
| 130 // and then append the style key (which should now be stroke only) at th
e end. | 118 // and then append the style key (which should now be stroke only) at th
e end. |
| 131 int parentCnt = parent.fInheritedKey.count(); | 119 int parentCnt = parent.fInheritedKey.count(); |
| 132 bool useParentGeoKey = !parentCnt; | 120 bool useParentGeoKey = !parentCnt; |
| 133 if (useParentGeoKey) { | 121 if (useParentGeoKey) { |
| 134 parentCnt = parent.unstyledKeySize(); | 122 parentCnt = parent.unstyledKeySize(); |
| 135 if (parentCnt < 0) { | 123 if (parentCnt < 0) { |
| 136 // The parent's geometry has no key so we will have no key. | 124 // The parent's geometry has no key so we will have no key. |
| 137 fPathGenID = 0; | 125 fPathData.fGenID = 0; |
| 138 return; | 126 return; |
| 139 } | 127 } |
| 140 } | 128 } |
| 141 uint32_t styleKeyFlags = 0; | 129 uint32_t styleKeyFlags = 0; |
| 142 if (parent.knownToBeClosed()) { | 130 if (parent.knownToBeClosed()) { |
| 143 styleKeyFlags |= GrStyle::kClosed_KeyFlag; | 131 styleKeyFlags |= GrStyle::kClosed_KeyFlag; |
| 144 } | 132 } |
| 145 int styleCnt = GrStyle::KeySize(parent.fStyle, apply, styleKeyFlags); | 133 int styleCnt = GrStyle::KeySize(parent.fStyle, apply, styleKeyFlags); |
| 146 if (styleCnt < 0) { | 134 if (styleCnt < 0) { |
| 147 // The style doesn't allow a key, set the path gen ID to 0 so that w
e fail when | 135 // The style doesn't allow a key, set the path gen ID to 0 so that w
e fail when |
| 148 // we try to get a key for the shape. | 136 // we try to get a key for the shape. |
| 149 fPathGenID = 0; | 137 fPathData.fGenID = 0; |
| 150 return; | 138 return; |
| 151 } | 139 } |
| 152 fInheritedKey.reset(parentCnt + styleCnt); | 140 fInheritedKey.reset(parentCnt + styleCnt); |
| 153 if (useParentGeoKey) { | 141 if (useParentGeoKey) { |
| 154 // This will be the geo key. | 142 // This will be the geo key. |
| 155 parent.writeUnstyledKey(fInheritedKey.get()); | 143 parent.writeUnstyledKey(fInheritedKey.get()); |
| 156 } else { | 144 } else { |
| 157 // This should be (geo,path_effect). | 145 // This should be (geo,path_effect). |
| 158 memcpy(fInheritedKey.get(), parent.fInheritedKey.get(), | 146 memcpy(fInheritedKey.get(), parent.fInheritedKey.get(), |
| 159 parentCnt * sizeof(uint32_t)); | 147 parentCnt * sizeof(uint32_t)); |
| 160 } | 148 } |
| 161 // Now turn (geo,path_effect) or (geo) into (geo,path_effect,stroke) | 149 // Now turn (geo,path_effect) or (geo) into (geo,path_effect,stroke) |
| 162 GrStyle::WriteKey(fInheritedKey.get() + parentCnt, parent.fStyle, apply,
scale, | 150 GrStyle::WriteKey(fInheritedKey.get() + parentCnt, parent.fStyle, apply,
scale, |
| 163 styleKeyFlags); | 151 styleKeyFlags); |
| 164 } | 152 } |
| 165 } | 153 } |
| 166 | 154 |
| 167 GrShape::GrShape(const GrShape& that) : fType(that.fType), fStyle(that.fStyle) { | 155 GrShape::GrShape(const GrShape& that) : fStyle(that.fStyle) { |
| 156 const SkPath* thatPath = Type::kPath == that.fType ? &that.fPathData.fPath :
nullptr; |
| 157 this->initType(that.fType, thatPath); |
| 168 switch (fType) { | 158 switch (fType) { |
| 169 case Type::kEmpty: | 159 case Type::kEmpty: |
| 170 break; | 160 break; |
| 171 case Type::kRRect: | 161 case Type::kRRect: |
| 172 fRRect = that.fRRect; | 162 fRRectData.fRRect = that.fRRectData.fRRect; |
| 173 fRRectDir = that.fRRectDir; | 163 fRRectData.fDir = that.fRRectData.fDir; |
| 174 fRRectStart = that.fRRectStart; | 164 fRRectData.fStart = that.fRRectData.fStart; |
| 175 fRRectIsInverted = that.fRRectIsInverted; | 165 fRRectData.fInverted = that.fRRectData.fInverted; |
| 176 break; | 166 break; |
| 177 case Type::kPath: | 167 case Type::kPath: |
| 178 fPath.set(*that.fPath.get()); | 168 fPathData.fGenID = that.fPathData.fGenID; |
| 179 fPathGenID = that.fPathGenID; | |
| 180 break; | 169 break; |
| 181 } | 170 } |
| 182 fInheritedKey.reset(that.fInheritedKey.count()); | 171 fInheritedKey.reset(that.fInheritedKey.count()); |
| 183 sk_careful_memcpy(fInheritedKey.get(), that.fInheritedKey.get(), | 172 sk_careful_memcpy(fInheritedKey.get(), that.fInheritedKey.get(), |
| 184 sizeof(uint32_t) * fInheritedKey.count()); | 173 sizeof(uint32_t) * fInheritedKey.count()); |
| 185 } | 174 } |
| 186 | 175 |
| 187 GrShape::GrShape(const GrShape& parent, GrStyle::Apply apply, SkScalar scale) { | 176 GrShape::GrShape(const GrShape& parent, GrStyle::Apply apply, SkScalar scale) { |
| 188 // TODO: Add some quantization of scale for better cache performance here or
leave that up | 177 // TODO: Add some quantization of scale for better cache performance here or
leave that up |
| 189 // to caller? | 178 // to caller? |
| 190 // TODO: For certain shapes and stroke params we could ignore the scale. (e.
g. miter or bevel | 179 // TODO: For certain shapes and stroke params we could ignore the scale. (e.
g. miter or bevel |
| 191 // stroke of a rect). | 180 // stroke of a rect). |
| 192 if (!parent.style().applies() || | 181 if (!parent.style().applies() || |
| 193 (GrStyle::Apply::kPathEffectOnly == apply && !parent.style().pathEffect(
))) { | 182 (GrStyle::Apply::kPathEffectOnly == apply && !parent.style().pathEffect(
))) { |
| 194 fType = Type::kEmpty; | 183 this->initType(Type::kEmpty); |
| 195 *this = parent; | 184 *this = parent; |
| 196 return; | 185 return; |
| 197 } | 186 } |
| 198 | 187 |
| 199 SkPathEffect* pe = parent.fStyle.pathEffect(); | 188 SkPathEffect* pe = parent.fStyle.pathEffect(); |
| 200 SkTLazy<SkPath> tmpPath; | 189 SkTLazy<SkPath> tmpPath; |
| 201 const GrShape* parentForKey = &parent; | 190 const GrShape* parentForKey = &parent; |
| 202 SkTLazy<GrShape> tmpParent; | 191 SkTLazy<GrShape> tmpParent; |
| 203 fType = Type::kPath; | 192 this->initType(Type::kPath); |
| 204 fPath.init(); | 193 fPathData.fGenID = 0; |
| 205 if (pe) { | 194 if (pe) { |
| 206 SkPath* srcForPathEffect; | 195 const SkPath* srcForPathEffect; |
| 207 if (parent.fType == Type::kPath) { | 196 if (parent.fType == Type::kPath) { |
| 208 srcForPathEffect = parent.fPath.get(); | 197 srcForPathEffect = &parent.path(); |
| 209 } else { | 198 } else { |
| 210 srcForPathEffect = tmpPath.init(); | 199 srcForPathEffect = tmpPath.init(); |
| 211 parent.asPath(tmpPath.get()); | 200 parent.asPath(tmpPath.get()); |
| 212 } | 201 } |
| 213 // Should we consider bounds? Would have to include in key, but it'd be
nice to know | 202 // Should we consider bounds? Would have to include in key, but it'd be
nice to know |
| 214 // if the bounds actually modified anything before including in key. | 203 // if the bounds actually modified anything before including in key. |
| 215 SkStrokeRec strokeRec = parent.fStyle.strokeRec(); | 204 SkStrokeRec strokeRec = parent.fStyle.strokeRec(); |
| 216 if (!parent.fStyle.applyPathEffectToPath(fPath.get(), &strokeRec, *srcFo
rPathEffect, | 205 if (!parent.fStyle.applyPathEffectToPath(&this->path(), &strokeRec, *src
ForPathEffect, |
| 217 scale)) { | 206 scale)) { |
| 218 // If the path effect fails then we continue as though there was no
path effect. | 207 // If the path effect fails then we continue as though there was no
path effect. |
| 219 // If the original was a rrect that we couldn't canonicalize because
of the path | 208 // If the original was a rrect that we couldn't canonicalize because
of the path |
| 220 // effect, then do so now. | 209 // effect, then do so now. |
| 221 if (parent.fType == Type::kRRect && (parent.fRRectDir != kDefaultRRe
ctDir || | 210 if (parent.fType == Type::kRRect && (parent.fRRectData.fDir != kDefa
ultRRectDir || |
| 222 parent.fRRectStart != kDefaultR
RectStart)) { | 211 parent.fRRectData.fStart != kDe
faultRRectStart)) { |
| 223 SkASSERT(srcForPathEffect == tmpPath.get()); | 212 SkASSERT(srcForPathEffect == tmpPath.get()); |
| 224 tmpPath.get()->reset(); | 213 tmpPath.get()->reset(); |
| 225 tmpPath.get()->addRRect(parent.fRRect, kDefaultRRectDir, kDefaul
tRRectDir); | 214 tmpPath.get()->addRRect(parent.fRRectData.fRRect, kDefaultRRectD
ir, |
| 215 kDefaultRRectDir); |
| 226 } | 216 } |
| 227 *fPath.get() = *srcForPathEffect; | 217 this->path() = *srcForPathEffect; |
| 228 } | 218 } |
| 229 // A path effect has access to change the res scale but we aren't expect
ing it to and it | 219 // A path effect has access to change the res scale but we aren't expect
ing it to and it |
| 230 // would mess up our key computation. | 220 // would mess up our key computation. |
| 231 SkASSERT(scale == strokeRec.getResScale()); | 221 SkASSERT(scale == strokeRec.getResScale()); |
| 232 if (GrStyle::Apply::kPathEffectAndStrokeRec == apply && strokeRec.needTo
Apply()) { | 222 if (GrStyle::Apply::kPathEffectAndStrokeRec == apply && strokeRec.needTo
Apply()) { |
| 233 // The intermediate shape may not be a general path. If we we're jus
t applying | 223 // The intermediate shape may not be a general path. If we we're jus
t applying |
| 234 // the path effect then attemptToReduceFromPath would catch it. This
means that | 224 // the path effect then attemptToReduceFromPath would catch it. This
means that |
| 235 // when we subsequently applied the remaining strokeRec we would hav
e a non-path | 225 // when we subsequently applied the remaining strokeRec we would hav
e a non-path |
| 236 // parent shape that would be used to determine the the stroked path
's key. | 226 // parent shape that would be used to determine the the stroked path
's key. |
| 237 // We detect that case here and change parentForKey to a temporary t
hat represents | 227 // We detect that case here and change parentForKey to a temporary t
hat represents |
| 238 // the simpler shape so that applying both path effect and the strok
erec all at | 228 // the simpler shape so that applying both path effect and the strok
erec all at |
| 239 // once produces the same key. | 229 // once produces the same key. |
| 240 tmpParent.init(*fPath.get(), GrStyle(strokeRec, nullptr)); | 230 tmpParent.init(this->path(), GrStyle(strokeRec, nullptr)); |
| 241 tmpParent.get()->setInheritedKey(parent, GrStyle::Apply::kPathEffect
Only, scale); | 231 tmpParent.get()->setInheritedKey(parent, GrStyle::Apply::kPathEffect
Only, scale); |
| 242 if (!tmpPath.isValid()) { | 232 if (!tmpPath.isValid()) { |
| 243 tmpPath.init(); | 233 tmpPath.init(); |
| 244 } | 234 } |
| 245 tmpParent.get()->asPath(tmpPath.get()); | 235 tmpParent.get()->asPath(tmpPath.get()); |
| 246 SkStrokeRec::InitStyle fillOrHairline; | 236 SkStrokeRec::InitStyle fillOrHairline; |
| 247 SkAssertResult(tmpParent.get()->style().applyToPath(fPath.get(), &fi
llOrHairline, | 237 SkAssertResult(tmpParent.get()->style().applyToPath(&this->path(), &
fillOrHairline, |
| 248 *tmpPath.get(),
scale)); | 238 *tmpPath.get(),
scale)); |
| 249 fStyle.resetToInitStyle(fillOrHairline); | 239 fStyle.resetToInitStyle(fillOrHairline); |
| 250 parentForKey = tmpParent.get(); | 240 parentForKey = tmpParent.get(); |
| 251 } else { | 241 } else { |
| 252 fStyle = GrStyle(strokeRec, nullptr); | 242 fStyle = GrStyle(strokeRec, nullptr); |
| 253 } | 243 } |
| 254 } else { | 244 } else { |
| 255 const SkPath* srcForParentStyle; | 245 const SkPath* srcForParentStyle; |
| 256 if (parent.fType == Type::kPath) { | 246 if (parent.fType == Type::kPath) { |
| 257 srcForParentStyle = parent.fPath.get(); | 247 srcForParentStyle = &parent.path(); |
| 258 } else { | 248 } else { |
| 259 srcForParentStyle = tmpPath.init(); | 249 srcForParentStyle = tmpPath.init(); |
| 260 parent.asPath(tmpPath.get()); | 250 parent.asPath(tmpPath.get()); |
| 261 } | 251 } |
| 262 SkStrokeRec::InitStyle fillOrHairline; | 252 SkStrokeRec::InitStyle fillOrHairline; |
| 263 SkASSERT(parent.fStyle.applies()); | 253 SkASSERT(parent.fStyle.applies()); |
| 264 SkASSERT(!parent.fStyle.pathEffect()); | 254 SkASSERT(!parent.fStyle.pathEffect()); |
| 265 SkAssertResult(parent.fStyle.applyToPath(fPath.get(), &fillOrHairline, *
srcForParentStyle, | 255 SkAssertResult(parent.fStyle.applyToPath(&this->path(), &fillOrHairline,
*srcForParentStyle, |
| 266 scale)); | 256 scale)); |
| 267 fStyle.resetToInitStyle(fillOrHairline); | 257 fStyle.resetToInitStyle(fillOrHairline); |
| 268 } | 258 } |
| 269 this->attemptToSimplifyPath(); | 259 this->attemptToSimplifyPath(); |
| 270 this->setInheritedKey(*parentForKey, apply, scale); | 260 this->setInheritedKey(*parentForKey, apply, scale); |
| 271 } | 261 } |
| 272 | 262 |
| 273 void GrShape::attemptToSimplifyPath() { | 263 void GrShape::attemptToSimplifyPath() { |
| 274 SkASSERT(Type::kPath == fType); | |
| 275 SkRect rect; | 264 SkRect rect; |
| 276 if (fPath.get()->isEmpty()) { | 265 SkRRect rrect; |
| 277 fType = Type::kEmpty; | 266 SkPath::Direction rrectDir; |
| 278 } else if (fPath.get()->isRRect(&fRRect, &fRRectDir, &fRRectStart)) { | 267 unsigned rrectStart; |
| 268 bool inverted = this->path().isInverseFillType(); |
| 269 if (this->path().isEmpty()) { |
| 270 this->changeType(Type::kEmpty); |
| 271 } else if (this->path().isRRect(&rrect, &rrectDir, &rrectStart)) { |
| 272 this->changeType(Type::kRRect); |
| 273 fRRectData.fRRect = rrect; |
| 274 fRRectData.fDir = rrectDir; |
| 275 fRRectData.fStart = rrectStart; |
| 276 fRRectData.fInverted = inverted; |
| 279 // Currently SkPath does not acknowledge that empty, rect, or oval subty
pes as rrects. | 277 // Currently SkPath does not acknowledge that empty, rect, or oval subty
pes as rrects. |
| 280 SkASSERT(!fRRect.isEmpty()); | 278 SkASSERT(!fRRectData.fRRect.isEmpty()); |
| 281 SkASSERT(fRRect.getType() != SkRRect::kRect_Type); | 279 SkASSERT(fRRectData.fRRect.getType() != SkRRect::kRect_Type); |
| 282 SkASSERT(fRRect.getType() != SkRRect::kOval_Type); | 280 SkASSERT(fRRectData.fRRect.getType() != SkRRect::kOval_Type); |
| 283 fRRectIsInverted = fPath.get()->isInverseFillType(); | 281 } else if (this->path().isOval(&rect, &rrectDir, &rrectStart)) { |
| 284 fType = Type::kRRect; | 282 this->changeType(Type::kRRect); |
| 285 } else if (fPath.get()->isOval(&rect, &fRRectDir, &fRRectStart)) { | 283 fRRectData.fRRect.setOval(rect); |
| 286 fRRect.setOval(rect); | 284 fRRectData.fDir = rrectDir; |
| 287 fRRectIsInverted = fPath.get()->isInverseFillType(); | 285 fRRectData.fInverted = inverted; |
| 288 // convert from oval indexing to rrect indexiing. | 286 // convert from oval indexing to rrect indexiing. |
| 289 fRRectStart *= 2; | 287 fRRectData.fStart = 2 * rrectStart; |
| 290 fType = Type::kRRect; | 288 } else if (SkPathPriv::IsSimpleClosedRect(this->path(), &rect, &rrectDir, &r
rectStart)) { |
| 291 } else if (SkPathPriv::IsSimpleClosedRect(*fPath.get(), &rect, &fRRectDir, &
fRRectStart)) { | 289 this->changeType(Type::kRRect); |
| 292 // When there is a path effect we restrict rect detection to the narrowe
r API that | 290 // When there is a path effect we restrict rect detection to the narrowe
r API that |
| 293 // gives us the starting position. Otherwise, we will retry with the mor
e aggressive | 291 // gives us the starting position. Otherwise, we will retry with the mor
e aggressive |
| 294 // isRect(). | 292 // isRect(). |
| 295 fRRect.setRect(rect); | 293 fRRectData.fRRect.setRect(rect); |
| 296 fRRectIsInverted = fPath.get()->isInverseFillType(); | 294 fRRectData.fInverted = inverted; |
| 295 fRRectData.fDir = rrectDir; |
| 297 // convert from rect indexing to rrect indexiing. | 296 // convert from rect indexing to rrect indexiing. |
| 298 fRRectStart *= 2; | 297 fRRectData.fStart = 2 * rrectStart; |
| 299 fType = Type::kRRect; | |
| 300 } else if (!this->style().hasPathEffect()) { | 298 } else if (!this->style().hasPathEffect()) { |
| 301 bool closed; | 299 bool closed; |
| 302 if (fPath.get()->isRect(&rect, &closed, nullptr)) { | 300 if (this->path().isRect(&rect, &closed, nullptr)) { |
| 303 if (closed || this->style().isSimpleFill()) { | 301 if (closed || this->style().isSimpleFill()) { |
| 304 fRRect.setRect(rect); | 302 this->changeType(Type::kRRect); |
| 303 fRRectData.fRRect.setRect(rect); |
| 305 // Since there is no path effect the dir and start index is imma
terial. | 304 // Since there is no path effect the dir and start index is imma
terial. |
| 306 fRRectDir = kDefaultRRectDir; | 305 fRRectData.fDir = kDefaultRRectDir; |
| 307 fRRectStart = kDefaultRRectStart; | 306 fRRectData.fStart = kDefaultRRectStart; |
| 308 // There isn't dashing so we will have to preserver inverseness. | 307 // There isn't dashing so we will have to preserver inverseness. |
| 309 fRRectIsInverted = fPath.get()->isInverseFillType(); | 308 fRRectData.fInverted = inverted; |
| 310 fType = Type::kRRect; | |
| 311 } | 309 } |
| 312 } | 310 } |
| 313 } | 311 } |
| 314 if (Type::kPath != fType) { | 312 if (Type::kPath != fType) { |
| 315 fPath.reset(); | |
| 316 fInheritedKey.reset(0); | 313 fInheritedKey.reset(0); |
| 317 if (Type::kRRect == fType) { | 314 if (Type::kRRect == fType) { |
| 318 this->attemptToSimplifyRRect(); | 315 this->attemptToSimplifyRRect(); |
| 319 } | 316 } |
| 320 } else { | 317 } else { |
| 321 if (fInheritedKey.count() || fPath.get()->isVolatile()) { | 318 if (fInheritedKey.count() || this->path().isVolatile()) { |
| 322 fPathGenID = 0; | 319 fPathData.fGenID = 0; |
| 323 } else { | 320 } else { |
| 324 fPathGenID = fPath.get()->getGenerationID(); | 321 fPathData.fGenID = this->path().getGenerationID(); |
| 325 } | 322 } |
| 326 if (this->style().isSimpleFill()) { | 323 if (this->style().isSimpleFill()) { |
| 327 // Filled paths are treated as though all their contours were closed
. | 324 // Filled paths are treated as though all their contours were closed
. |
| 328 // Since SkPath doesn't track individual contours, this will only cl
ose the last. :( | 325 // Since SkPath doesn't track individual contours, this will only cl
ose the last. :( |
| 329 // There is no point in closing lines, though, since they loose thei
r line-ness. | 326 // There is no point in closing lines, though, since they loose thei
r line-ness. |
| 330 if (!fPath.get()->isLine(nullptr)) { | 327 if (!this->path().isLine(nullptr)) { |
| 331 fPath.get()->close(); | 328 this->path().close(); |
| 332 fPath.get()->setIsVolatile(true); | 329 this->path().setIsVolatile(true); |
| 333 } | 330 } |
| 334 } | 331 } |
| 335 if (!this->style().hasNonDashPathEffect()) { | 332 if (!this->style().hasNonDashPathEffect()) { |
| 336 if (this->style().strokeRec().getStyle() == SkStrokeRec::kStroke_Sty
le || | 333 if (this->style().strokeRec().getStyle() == SkStrokeRec::kStroke_Sty
le || |
| 337 this->style().strokeRec().getStyle() == SkStrokeRec::kHairline_S
tyle) { | 334 this->style().strokeRec().getStyle() == SkStrokeRec::kHairline_S
tyle) { |
| 338 // Stroke styles don't differentiate between winding and even/od
d. | 335 // Stroke styles don't differentiate between winding and even/od
d. |
| 339 // Moreover, dashing ignores inverseness (skbug.com/5421) | 336 // Moreover, dashing ignores inverseness (skbug.com/5421) |
| 340 bool inverse = !this->style().isDashed() && fPath.get()->isInver
seFillType(); | 337 bool inverse = !this->style().isDashed() && this->path().isInver
seFillType(); |
| 341 if (inverse) { | 338 if (inverse) { |
| 342 fPath.get()->setFillType(kDefaultPathInverseFillType); | 339 this->path().setFillType(kDefaultPathInverseFillType); |
| 343 } else { | 340 } else { |
| 344 fPath.get()->setFillType(kDefaultPathFillType); | 341 this->path().setFillType(kDefaultPathFillType); |
| 345 } | 342 } |
| 346 } else if (fPath.get()->isConvex()) { | 343 } else if (this->path().isConvex()) { |
| 347 // There is no distinction between even/odd and non-zero winding
count for convex | 344 // There is no distinction between even/odd and non-zero winding
count for convex |
| 348 // paths. | 345 // paths. |
| 349 if (fPath.get()->isInverseFillType()) { | 346 if (this->path().isInverseFillType()) { |
| 350 fPath.get()->setFillType(kDefaultPathInverseFillType); | 347 this->path().setFillType(kDefaultPathInverseFillType); |
| 351 } else { | 348 } else { |
| 352 fPath.get()->setFillType(kDefaultPathFillType); | 349 this->path().setFillType(kDefaultPathFillType); |
| 353 } | 350 } |
| 354 } | 351 } |
| 355 } | 352 } |
| 356 } | 353 } |
| 357 } | 354 } |
| 358 | 355 |
| 359 void GrShape::attemptToSimplifyRRect() { | 356 void GrShape::attemptToSimplifyRRect() { |
| 360 SkASSERT(Type::kRRect == fType); | 357 SkASSERT(Type::kRRect == fType); |
| 361 SkASSERT(!fInheritedKey.count()); | 358 SkASSERT(!fInheritedKey.count()); |
| 362 if (fRRect.isEmpty()) { | 359 if (fRRectData.fRRect.isEmpty()) { |
| 363 fType = Type::kEmpty; | 360 fType = Type::kEmpty; |
| 364 return; | 361 return; |
| 365 } | 362 } |
| 366 if (!this->style().hasPathEffect()) { | 363 if (!this->style().hasPathEffect()) { |
| 367 fRRectDir = kDefaultRRectDir; | 364 fRRectData.fDir = kDefaultRRectDir; |
| 368 fRRectStart = kDefaultRRectStart; | 365 fRRectData.fStart = kDefaultRRectStart; |
| 369 } else if (fStyle.isDashed()) { | 366 } else if (fStyle.isDashed()) { |
| 370 // Dashing ignores the inverseness (currently). skbug.com/5421 | 367 // Dashing ignores the inverseness (currently). skbug.com/5421 |
| 371 fRRectIsInverted = false; | 368 fRRectData.fInverted = false; |
| 372 } | 369 } |
| 373 } | 370 } |
| OLD | NEW |