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 |