Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(162)

Side by Side Diff: src/gpu/GrShape.cpp

Issue 2056523002: Make GrShape capable of representing inverse filled rrects. (Closed) Base URL: https://chromium.googlesource.com/skia.git@faildashstrokeandfill
Patch Set: Fix windows warning Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/gpu/GrShape.h ('k') | tests/GrShapeTest.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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; 11 bool wasPath = Type::kPath == fType;
12 fStyle = that.fStyle; 12 fStyle = that.fStyle;
13 fType = that.fType; 13 fType = that.fType;
14 switch (fType) { 14 switch (fType) {
15 case Type::kEmpty: 15 case Type::kEmpty:
16 if (wasPath) { 16 if (wasPath) {
17 fPath.reset(); 17 fPath.reset();
18 } 18 }
19 break; 19 break;
20 case Type::kRRect: 20 case Type::kRRect:
21 if (wasPath) { 21 if (wasPath) {
22 fPath.reset(); 22 fPath.reset();
23 } 23 }
24 fRRect = that.fRRect; 24 fRRect = that.fRRect;
25 fRRectDir = that.fRRectDir; 25 fRRectDir = that.fRRectDir;
26 fRRectStart = that.fRRectStart; 26 fRRectStart = that.fRRectStart;
27 fRRectIsInverted = that.fRRectIsInverted;
27 break; 28 break;
28 case Type::kPath: 29 case Type::kPath:
29 if (wasPath) { 30 if (wasPath) {
30 *fPath.get() = *that.fPath.get(); 31 *fPath.get() = *that.fPath.get();
31 } else { 32 } else {
32 fPath.set(*that.fPath.get()); 33 fPath.set(*that.fPath.get());
33 } 34 }
34 break; 35 break;
35 } 36 }
36 fInheritedKey.reset(that.fInheritedKey.count()); 37 fInheritedKey.reset(that.fInheritedKey.count());
(...skipping 27 matching lines...) Expand all
64 int GrShape::unstyledKeySize() const { 65 int GrShape::unstyledKeySize() const {
65 if (fInheritedKey.count()) { 66 if (fInheritedKey.count()) {
66 return fInheritedKey.count(); 67 return fInheritedKey.count();
67 } 68 }
68 switch (fType) { 69 switch (fType) {
69 case Type::kEmpty: 70 case Type::kEmpty:
70 return 1; 71 return 1;
71 case Type::kRRect: 72 case Type::kRRect:
72 SkASSERT(!fInheritedKey.count()); 73 SkASSERT(!fInheritedKey.count());
73 SkASSERT(0 == SkRRect::kSizeInMemory % sizeof(uint32_t)); 74 SkASSERT(0 == SkRRect::kSizeInMemory % sizeof(uint32_t));
74 // + 1 for the direction + start index. 75 // + 1 for the direction, start index, and inverseness.
75 return SkRRect::kSizeInMemory / sizeof(uint32_t) + 1; 76 return SkRRect::kSizeInMemory / sizeof(uint32_t) + 1;
76 case Type::kPath: 77 case Type::kPath:
77 if (fPath.get()->isVolatile()) { 78 if (fPath.get()->isVolatile()) {
78 return -1; 79 return -1;
79 } else { 80 } else {
80 return 1; 81 // The key is the path ID and fill type.
82 return 2;
81 } 83 }
82 } 84 }
83 SkFAIL("Should never get here."); 85 SkFAIL("Should never get here.");
84 return 0; 86 return 0;
85 } 87 }
86 88
87 void GrShape::writeUnstyledKey(uint32_t* key) const { 89 void GrShape::writeUnstyledKey(uint32_t* key) const {
88 SkASSERT(this->unstyledKeySize()); 90 SkASSERT(this->unstyledKeySize());
89 SkDEBUGCODE(uint32_t* origKey = key;) 91 SkDEBUGCODE(uint32_t* origKey = key;)
90 if (fInheritedKey.count()) { 92 if (fInheritedKey.count()) {
91 memcpy(key, fInheritedKey.get(), sizeof(uint32_t) * fInheritedKey.count( )); 93 memcpy(key, fInheritedKey.get(), sizeof(uint32_t) * fInheritedKey.count( ));
92 SkDEBUGCODE(key += fInheritedKey.count();) 94 SkDEBUGCODE(key += fInheritedKey.count();)
93 } else { 95 } else {
94 switch (fType) { 96 switch (fType) {
95 case Type::kEmpty: 97 case Type::kEmpty:
96 *key++ = 1; 98 *key++ = 1;
97 break; 99 break;
98 case Type::kRRect: 100 case Type::kRRect:
99 fRRect.writeToMemory(key); 101 fRRect.writeToMemory(key);
100 key += SkRRect::kSizeInMemory / sizeof(uint32_t); 102 key += SkRRect::kSizeInMemory / sizeof(uint32_t);
101 *key = (fRRectDir == SkPath::kCCW_Direction) ? (1 << 31) : 0; 103 *key = (fRRectDir == SkPath::kCCW_Direction) ? (1 << 31) : 0;
104 *key |= fRRectIsInverted ? (1 << 30) : 0;
102 *key++ |= fRRectStart; 105 *key++ |= fRRectStart;
103 SkASSERT(fRRectStart < 8); 106 SkASSERT(fRRectStart < 8);
104 break; 107 break;
105 case Type::kPath: 108 case Type::kPath:
106 SkASSERT(!fPath.get()->isVolatile()); 109 SkASSERT(!fPath.get()->isVolatile());
107 *key++ = fPath.get()->getGenerationID(); 110 *key++ = fPath.get()->getGenerationID();
111 // We could canonicalize the fill rule for paths that don't diff erentiate between
112 // even/odd or winding fill (e.g. convex).
113 *key++ = fPath.get()->getFillType();
108 break; 114 break;
109 } 115 }
110 } 116 }
111 SkASSERT(key - origKey == this->unstyledKeySize()); 117 SkASSERT(key - origKey == this->unstyledKeySize());
112 } 118 }
113 119
114 void GrShape::setInheritedKey(const GrShape &parent, GrStyle::Apply apply, SkSca lar scale) { 120 void GrShape::setInheritedKey(const GrShape &parent, GrStyle::Apply apply, SkSca lar scale) {
115 SkASSERT(!fInheritedKey.count()); 121 SkASSERT(!fInheritedKey.count());
116 // If the output shape turns out to be simple, then we will just use its geo metric key 122 // If the output shape turns out to be simple, then we will just use its geo metric key
117 if (Type::kPath == fType) { 123 if (Type::kPath == fType) {
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
156 styleKeyFlags); 162 styleKeyFlags);
157 } 163 }
158 } 164 }
159 165
160 GrShape::GrShape(const GrShape& that) : fType(that.fType), fStyle(that.fStyle) { 166 GrShape::GrShape(const GrShape& that) : fType(that.fType), fStyle(that.fStyle) {
161 switch (fType) { 167 switch (fType) {
162 case Type::kEmpty: 168 case Type::kEmpty:
163 return; 169 return;
164 case Type::kRRect: 170 case Type::kRRect:
165 fRRect = that.fRRect; 171 fRRect = that.fRRect;
172 fRRectDir = that.fRRectDir;
173 fRRectStart = that.fRRectStart;
174 fRRectIsInverted = that.fRRectIsInverted;
166 return; 175 return;
167 case Type::kPath: 176 case Type::kPath:
168 fPath.set(*that.fPath.get()); 177 fPath.set(*that.fPath.get());
169 return; 178 return;
170 } 179 }
171 fInheritedKey.reset(that.fInheritedKey.count()); 180 fInheritedKey.reset(that.fInheritedKey.count());
172 memcpy(fInheritedKey.get(), that.fInheritedKey.get(), 181 memcpy(fInheritedKey.get(), that.fInheritedKey.get(),
173 sizeof(uint32_t) * fInheritedKey.count()); 182 sizeof(uint32_t) * fInheritedKey.count());
174 } 183 }
175 184
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
223 // The intermediate shape may not be a general path. If we we're just applying 232 // The intermediate shape may not be a general path. If we we're just applying
224 // the path effect then attemptToReduceFromPath would catch it. This means that 233 // the path effect then attemptToReduceFromPath would catch it. This means that
225 // when we subsequently applied the remaining strokeRec we would have a non-path 234 // when we subsequently applied the remaining strokeRec we would have a non-path
226 // 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.
227 // We detect that case here and change parentForKey to a tempora ry that represents 236 // We detect that case here and change parentForKey to a tempora ry that represents
228 // the simpler shape so that applying both path effect and the s trokerec all at 237 // the simpler shape so that applying both path effect and the s trokerec all at
229 // once produces the same key. 238 // once produces the same key.
230 SkRRect rrect; 239 SkRRect rrect;
231 SkPath::Direction dir; 240 SkPath::Direction dir;
232 unsigned start; 241 unsigned start;
242 bool inverted;
233 Type parentType = AttemptToReduceFromPathImpl(*fPath.get(), &rre ct, &dir, &start, 243 Type parentType = AttemptToReduceFromPathImpl(*fPath.get(), &rre ct, &dir, &start,
234 nullptr, strokeRec ); 244 &inverted, nullptr , strokeRec);
235 switch (parentType) { 245 switch (parentType) {
236 case Type::kEmpty: 246 case Type::kEmpty:
237 tmpParent.init(); 247 tmpParent.init();
238 parentForKey = tmpParent.get(); 248 parentForKey = tmpParent.get();
239 break; 249 break;
240 case Type::kRRect: 250 case Type::kRRect:
241 tmpParent.init(rrect, dir, start, GrStyle(strokeRec, nul lptr)); 251 tmpParent.init(rrect, dir, start, inverted, GrStyle(stro keRec, nullptr));
242 parentForKey = tmpParent.get(); 252 parentForKey = tmpParent.get();
243 case Type::kPath: 253 case Type::kPath:
244 break; 254 break;
245 } 255 }
246 SkAssertResult(strokeRec.applyToPath(fPath.get(), *fPath.get())) ; 256 SkAssertResult(strokeRec.applyToPath(fPath.get(), *fPath.get())) ;
247 } else { 257 } else {
248 fStyle = GrStyle(strokeRec, nullptr); 258 fStyle = GrStyle(strokeRec, nullptr);
249 } 259 }
250 } else { 260 } else {
251 fStyle = GrStyle(strokeRec, nullptr); 261 fStyle = GrStyle(strokeRec, nullptr);
(...skipping 10 matching lines...) Expand all
262 SkASSERT(parent.fStyle.applies()); 272 SkASSERT(parent.fStyle.applies());
263 SkASSERT(!parent.fStyle.pathEffect()); 273 SkASSERT(!parent.fStyle.pathEffect());
264 SkAssertResult(parent.fStyle.applyToPath(fPath.get(), &fillOrHairline, * srcForParentStyle, 274 SkAssertResult(parent.fStyle.applyToPath(fPath.get(), &fillOrHairline, * srcForParentStyle,
265 scale)); 275 scale));
266 fStyle.resetToInitStyle(fillOrHairline); 276 fStyle.resetToInitStyle(fillOrHairline);
267 } 277 }
268 this->attemptToReduceFromPath(); 278 this->attemptToReduceFromPath();
269 this->setInheritedKey(*parentForKey, apply, scale); 279 this->setInheritedKey(*parentForKey, apply, scale);
270 } 280 }
271 281
282 static inline bool rrect_path_is_inverse_filled(const SkPath& path, const SkStro keRec& strokeRec,
283 const SkPathEffect* pe) {
284 // Dashing doesn't use the path fill type. Dashing only works with stroking
285 if (pe && pe->asADash(nullptr)) {
286 pe = nullptr;
287 }
288
289 SkStrokeRec::Style style = strokeRec.getStyle();
290 if (!pe && (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_St yle == style)) {
291 // stroking ignores the path fill rule.
292 return false;
293 }
294 return path.isInverseFillType();
295 }
296
272 GrShape::Type GrShape::AttemptToReduceFromPathImpl(const SkPath& path, SkRRect* rrect, 297 GrShape::Type GrShape::AttemptToReduceFromPathImpl(const SkPath& path, SkRRect* rrect,
273 SkPath::Direction* rrectDir, 298 SkPath::Direction* rrectDir,
274 unsigned* rrectStart, 299 unsigned* rrectStart,
300 bool* rrectIsInverted,
275 const SkPathEffect* pe, 301 const SkPathEffect* pe,
276 const SkStrokeRec& strokeRec) { 302 const SkStrokeRec& strokeRec) {
277 if (path.isEmpty()) { 303 if (path.isEmpty()) {
278 return Type::kEmpty; 304 return Type::kEmpty;
279 } 305 }
280 if (path.isRRect(rrect, rrectDir, rrectStart)) { 306 if (path.isRRect(rrect, rrectDir, rrectStart)) {
281 // Currently SkPath does not acknowledge that empty, rect, or oval subty pes as rrects. 307 // Currently SkPath does not acknowledge that empty, rect, or oval subty pes as rrects.
282 SkASSERT(!rrect->isEmpty()); 308 SkASSERT(!rrect->isEmpty());
283 SkASSERT(rrect->getType() != SkRRect::kRect_Type); 309 SkASSERT(rrect->getType() != SkRRect::kRect_Type);
284 SkASSERT(rrect->getType() != SkRRect::kOval_Type); 310 SkASSERT(rrect->getType() != SkRRect::kOval_Type);
285 if (!pe) { 311 if (!pe) {
286 *rrectStart = DefaultRRectDirAndStartIndex(*rrect, false, rrectDir); 312 *rrectStart = DefaultRRectDirAndStartIndex(*rrect, false, rrectDir);
287 } 313 }
314 *rrectIsInverted = rrect_path_is_inverse_filled(path, strokeRec, pe);
288 return Type::kRRect; 315 return Type::kRRect;
289 } 316 }
290 SkRect rect; 317 SkRect rect;
291 if (path.isOval(&rect, rrectDir, rrectStart)) { 318 if (path.isOval(&rect, rrectDir, rrectStart)) {
292 rrect->setOval(rect); 319 rrect->setOval(rect);
293 if (!pe) { 320 if (!pe) {
294 *rrectDir = kDefaultRRectDir; 321 *rrectDir = kDefaultRRectDir;
295 *rrectStart = kDefaultRRectStart; 322 *rrectStart = kDefaultRRectStart;
296 } else { 323 } else {
297 // convert from oval indexing to rrect indexiing. 324 // convert from oval indexing to rrect indexiing.
298 *rrectStart *= 2; 325 *rrectStart *= 2;
299 } 326 }
327 *rrectIsInverted = rrect_path_is_inverse_filled(path, strokeRec, pe);
300 return Type::kRRect; 328 return Type::kRRect;
301 } 329 }
302 // When there is a path effect we restrict rect detection to the narrower AP I that 330 // When there is a path effect we restrict rect detection to the narrower AP I that
303 // gives us the starting position. Otherwise, we will retry with the more ag gressive isRect(). 331 // gives us the starting position. Otherwise, we will retry with the more ag gressive isRect().
304 if (SkPathPriv::IsSimpleClosedRect(path, &rect, rrectDir, rrectStart)) { 332 if (SkPathPriv::IsSimpleClosedRect(path, &rect, rrectDir, rrectStart)) {
305 if (!pe) { 333 if (!pe) {
306 *rrectDir = kDefaultRRectDir; 334 *rrectDir = kDefaultRRectDir;
307 *rrectStart = kDefaultRRectStart; 335 *rrectStart = kDefaultRRectStart;
308 } else { 336 } else {
309 // convert from rect indexing to rrect indexiing. 337 // convert from rect indexing to rrect indexiing.
310 *rrectStart *= 2; 338 *rrectStart *= 2;
311 } 339 }
312 rrect->setRect(rect); 340 rrect->setRect(rect);
341 *rrectIsInverted = rrect_path_is_inverse_filled(path, strokeRec, pe);
313 return Type::kRRect; 342 return Type::kRRect;
314 } 343 }
315 if (!pe) { 344 if (!pe) {
316 bool closed; 345 bool closed;
317 if (path.isRect(&rect, &closed, nullptr)) { 346 if (path.isRect(&rect, &closed, nullptr)) {
318 if (closed || strokeRec.isFillStyle()) { 347 if (closed || strokeRec.isFillStyle()) {
319 rrect->setRect(rect); 348 rrect->setRect(rect);
320 // Since there is no path effect the dir and start index is imma terial. 349 // Since there is no path effect the dir and start index is imma terial.
321 *rrectDir = kDefaultRRectDir; 350 *rrectDir = kDefaultRRectDir;
322 *rrectStart = kDefaultRRectStart; 351 *rrectStart = kDefaultRRectStart;
352 *rrectIsInverted = rrect_path_is_inverse_filled(path, strokeRec, pe);
323 return Type::kRRect; 353 return Type::kRRect;
324 } 354 }
325 } 355 }
326 } 356 }
327 return Type::kPath; 357 return Type::kPath;
328 } 358 }
OLDNEW
« no previous file with comments | « src/gpu/GrShape.h ('k') | tests/GrShapeTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698