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) { |
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
220 parent.fRRectStart != kDefaultR
RectStart)) { | 220 parent.fRRectStart != kDefaultR
RectStart)) { |
221 SkASSERT(srcForPathEffect == tmpPath.get()); | 221 SkASSERT(srcForPathEffect == tmpPath.get()); |
222 tmpPath.get()->reset(); | 222 tmpPath.get()->reset(); |
223 tmpPath.get()->addRRect(parent.fRRect, kDefaultRRectDir, kDefaul
tRRectDir); | 223 tmpPath.get()->addRRect(parent.fRRect, kDefaultRRectDir, kDefaul
tRRectDir); |
224 } | 224 } |
225 *fPath.get() = *srcForPathEffect; | 225 *fPath.get() = *srcForPathEffect; |
226 } | 226 } |
227 // A path effect has access to change the res scale but we aren't expect
ing it to and it | 227 // A path effect has access to change the res scale but we aren't expect
ing it to and it |
228 // would mess up our key computation. | 228 // would mess up our key computation. |
229 SkASSERT(scale == strokeRec.getResScale()); | 229 SkASSERT(scale == strokeRec.getResScale()); |
230 if (GrStyle::Apply::kPathEffectAndStrokeRec == apply) { | 230 if (GrStyle::Apply::kPathEffectAndStrokeRec == apply && strokeRec.needTo
Apply()) { |
231 if (strokeRec.needToApply()) { | 231 // The intermediate shape may not be a general path. If we we're jus
t applying |
232 // The intermediate shape may not be a general path. If we we're
just applying | 232 // the path effect then attemptToReduceFromPath would catch it. This
means that |
233 // the path effect then attemptToReduceFromPath would catch it.
This means that | 233 // when we subsequently applied the remaining strokeRec we would hav
e a non-path |
234 // when we subsequently applied the remaining strokeRec we would
have a non-path | 234 // parent shape that would be used to determine the the stroked path
's key. |
235 // parent shape that would be used to determine the the stroked
path's key. | 235 // We detect that case here and change parentForKey to a temporary t
hat represents |
236 // We detect that case here and change parentForKey to a tempora
ry that represents | 236 // the simpler shape so that applying both path effect and the strok
erec all at |
237 // the simpler shape so that applying both path effect and the s
trokerec all at | 237 // once produces the same key. |
238 // once produces the same key. | 238 tmpParent.init(*fPath.get(), GrStyle(strokeRec, nullptr)); |
239 SkRRect rrect; | 239 tmpParent.get()->setInheritedKey(parent, GrStyle::Apply::kPathEffect
Only, scale); |
240 SkPath::Direction dir; | 240 if (!tmpPath.isValid()) { |
241 unsigned start; | 241 tmpPath.init(); |
242 bool inverted; | |
243 Type parentType = AttemptToReduceFromPathImpl(*fPath.get(), &rre
ct, &dir, &start, | |
244 &inverted, nullptr
, strokeRec); | |
245 switch (parentType) { | |
246 case Type::kEmpty: | |
247 tmpParent.init(); | |
248 parentForKey = tmpParent.get(); | |
249 break; | |
250 case Type::kRRect: | |
251 tmpParent.init(rrect, dir, start, inverted, GrStyle(stro
keRec, nullptr)); | |
252 parentForKey = tmpParent.get(); | |
253 case Type::kPath: | |
254 break; | |
255 } | |
256 SkAssertResult(strokeRec.applyToPath(fPath.get(), *fPath.get()))
; | |
257 } else { | |
258 fStyle = GrStyle(strokeRec, nullptr); | |
259 } | 242 } |
| 243 tmpParent.get()->asPath(tmpPath.get()); |
| 244 SkStrokeRec::InitStyle fillOrHairline; |
| 245 SkAssertResult(tmpParent.get()->style().applyToPath(fPath.get(), &fi
llOrHairline, |
| 246 *tmpPath.get(),
scale)); |
| 247 fStyle.resetToInitStyle(fillOrHairline); |
| 248 parentForKey = tmpParent.get(); |
260 } else { | 249 } else { |
261 fStyle = GrStyle(strokeRec, nullptr); | 250 fStyle = GrStyle(strokeRec, nullptr); |
262 } | 251 } |
263 } else { | 252 } else { |
264 const SkPath* srcForParentStyle; | 253 const SkPath* srcForParentStyle; |
265 if (parent.fType == Type::kPath) { | 254 if (parent.fType == Type::kPath) { |
266 srcForParentStyle = parent.fPath.get(); | 255 srcForParentStyle = parent.fPath.get(); |
267 } else { | 256 } else { |
268 srcForParentStyle = tmpPath.init(); | 257 srcForParentStyle = tmpPath.init(); |
269 parent.asPath(tmpPath.get()); | 258 parent.asPath(tmpPath.get()); |
270 } | 259 } |
271 SkStrokeRec::InitStyle fillOrHairline; | 260 SkStrokeRec::InitStyle fillOrHairline; |
272 SkASSERT(parent.fStyle.applies()); | 261 SkASSERT(parent.fStyle.applies()); |
273 SkASSERT(!parent.fStyle.pathEffect()); | 262 SkASSERT(!parent.fStyle.pathEffect()); |
274 SkAssertResult(parent.fStyle.applyToPath(fPath.get(), &fillOrHairline, *
srcForParentStyle, | 263 SkAssertResult(parent.fStyle.applyToPath(fPath.get(), &fillOrHairline, *
srcForParentStyle, |
275 scale)); | 264 scale)); |
276 fStyle.resetToInitStyle(fillOrHairline); | 265 fStyle.resetToInitStyle(fillOrHairline); |
277 } | 266 } |
278 this->attemptToReduceFromPath(); | 267 this->attemptToSimplifyPath(); |
279 this->setInheritedKey(*parentForKey, apply, scale); | 268 this->setInheritedKey(*parentForKey, apply, scale); |
280 } | 269 } |
281 | 270 |
282 static inline bool rrect_path_is_inverse_filled(const SkPath& path, const SkStro
keRec& strokeRec, | 271 void GrShape::attemptToSimplifyPath() { |
283 const SkPathEffect* pe) { | 272 SkASSERT(Type::kPath == fType); |
284 // This is currently imitating the questionable behavior of the sw-rasterize
r. Inverseness is | 273 SkRect rect; |
285 // respected for stroking but not dashing + stroking. (We make no assumption
s about arbitrary | 274 if (fPath.get()->isEmpty()) { |
286 // path effects and preserve the path's inverseness.) | 275 fType = Type::kEmpty; |
287 // skbug.com/5421 | 276 } else if (fPath.get()->isRRect(&fRRect, &fRRectDir, &fRRectStart)) { |
288 if (pe && pe->asADash(nullptr)) { | |
289 SkDEBUGCODE(SkStrokeRec::Style style = strokeRec.getStyle();) | |
290 SkASSERT(SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_S
tyle == style); | |
291 return false; | |
292 } | |
293 | |
294 return path.isInverseFillType(); | |
295 } | |
296 | |
297 GrShape::Type GrShape::AttemptToReduceFromPathImpl(const SkPath& path, SkRRect*
rrect, | |
298 SkPath::Direction* rrectDir, | |
299 unsigned* rrectStart, | |
300 bool* rrectIsInverted, | |
301 const SkPathEffect* pe, | |
302 const SkStrokeRec& strokeRec)
{ | |
303 if (path.isEmpty()) { | |
304 return Type::kEmpty; | |
305 } | |
306 if (path.isRRect(rrect, rrectDir, rrectStart)) { | |
307 // 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. |
308 SkASSERT(!rrect->isEmpty()); | 278 SkASSERT(!fRRect.isEmpty()); |
309 SkASSERT(rrect->getType() != SkRRect::kRect_Type); | 279 SkASSERT(fRRect.getType() != SkRRect::kRect_Type); |
310 SkASSERT(rrect->getType() != SkRRect::kOval_Type); | 280 SkASSERT(fRRect.getType() != SkRRect::kOval_Type); |
311 if (!pe) { | 281 fRRectIsInverted = fPath.get()->isInverseFillType(); |
312 *rrectStart = DefaultRRectDirAndStartIndex(*rrect, false, rrectDir); | 282 fType = Type::kRRect; |
313 } | 283 } else if (fPath.get()->isOval(&rect, &fRRectDir, &fRRectStart)) { |
314 *rrectIsInverted = rrect_path_is_inverse_filled(path, strokeRec, pe); | 284 fRRect.setOval(rect); |
315 return Type::kRRect; | 285 fRRectIsInverted = fPath.get()->isInverseFillType(); |
316 } | 286 // convert from oval indexing to rrect indexiing. |
317 SkRect rect; | 287 fRRectStart *= 2; |
318 if (path.isOval(&rect, rrectDir, rrectStart)) { | 288 fType = Type::kRRect; |
319 rrect->setOval(rect); | 289 } else if (SkPathPriv::IsSimpleClosedRect(*fPath.get(), &rect, &fRRectDir, &
fRRectStart)) { |
320 if (!pe) { | 290 // When there is a path effect we restrict rect detection to the narrowe
r API that |
321 *rrectDir = kDefaultRRectDir; | 291 // gives us the starting position. Otherwise, we will retry with the mor
e aggressive |
322 *rrectStart = kDefaultRRectStart; | 292 // isRect(). |
323 } else { | 293 fRRect.setRect(rect); |
324 // convert from oval indexing to rrect indexiing. | 294 fRRectIsInverted = fPath.get()->isInverseFillType(); |
325 *rrectStart *= 2; | 295 // convert from rect indexing to rrect indexiing. |
326 } | 296 fRRectStart *= 2; |
327 *rrectIsInverted = rrect_path_is_inverse_filled(path, strokeRec, pe); | 297 fType = Type::kRRect; |
328 return Type::kRRect; | 298 } else if (!this->style().hasPathEffect()) { |
329 } | |
330 // When there is a path effect we restrict rect detection to the narrower AP
I that | |
331 // gives us the starting position. Otherwise, we will retry with the more ag
gressive isRect(). | |
332 if (SkPathPriv::IsSimpleClosedRect(path, &rect, rrectDir, rrectStart)) { | |
333 if (!pe) { | |
334 *rrectDir = kDefaultRRectDir; | |
335 *rrectStart = kDefaultRRectStart; | |
336 } else { | |
337 // convert from rect indexing to rrect indexiing. | |
338 *rrectStart *= 2; | |
339 } | |
340 rrect->setRect(rect); | |
341 *rrectIsInverted = rrect_path_is_inverse_filled(path, strokeRec, pe); | |
342 return Type::kRRect; | |
343 } | |
344 if (!pe) { | |
345 bool closed; | 299 bool closed; |
346 if (path.isRect(&rect, &closed, nullptr)) { | 300 if (fPath.get()->isRect(&rect, &closed, nullptr)) { |
347 if (closed || strokeRec.isFillStyle()) { | 301 if (closed || this->style().isSimpleFill()) { |
348 rrect->setRect(rect); | 302 fRRect.setRect(rect); |
349 // Since there is no path effect the dir and start index is imma
terial. | 303 // Since there is no path effect the dir and start index is imma
terial. |
350 *rrectDir = kDefaultRRectDir; | 304 fRRectDir = kDefaultRRectDir; |
351 *rrectStart = kDefaultRRectStart; | 305 fRRectStart = kDefaultRRectStart; |
352 *rrectIsInverted = rrect_path_is_inverse_filled(path, strokeRec,
pe); | 306 // There isn't dashing so we will have to preserver inverseness. |
353 return Type::kRRect; | 307 fRRectIsInverted = fPath.get()->isInverseFillType(); |
| 308 fType = Type::kRRect; |
354 } | 309 } |
355 } | 310 } |
356 } | 311 } |
357 return Type::kPath; | 312 if (Type::kPath != fType) { |
| 313 fPath.reset(); |
| 314 fInheritedKey.reset(0); |
| 315 if (Type::kRRect == fType) { |
| 316 this->attemptToSimplifyRRect(); |
| 317 } |
| 318 } |
358 } | 319 } |
| 320 |
| 321 void GrShape::attemptToSimplifyRRect() { |
| 322 SkASSERT(Type::kRRect == fType); |
| 323 SkASSERT(!fInheritedKey.count()); |
| 324 if (fRRect.isEmpty()) { |
| 325 fType = Type::kEmpty; |
| 326 return; |
| 327 } |
| 328 if (!this->style().hasPathEffect()) { |
| 329 fRRectDir = kDefaultRRectDir; |
| 330 fRRectStart = kDefaultRRectStart; |
| 331 } else if (fStyle.isDashed()) { |
| 332 // Dashing ignores the inverseness (currently). skbug.com/5421 |
| 333 fRRectIsInverted = false; |
| 334 } |
| 335 } |
OLD | NEW |