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

Side by Side Diff: src/pathops/SkOpSpan.cpp

Issue 1037573004: cumulative pathops patch (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: fix pathopsinverse gm Created 5 years, 9 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/pathops/SkOpSpan.h ('k') | src/pathops/SkOpTAllocator.h » ('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 2014 Google Inc. 2 * Copyright 2014 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 #include "SkOpCoincidence.h" 7 #include "SkOpCoincidence.h"
8 #include "SkOpContour.h" 8 #include "SkOpContour.h"
9 #include "SkOpSegment.h" 9 #include "SkOpSegment.h"
10 #include "SkPathWriter.h" 10 #include "SkPathWriter.h"
11 11
12 bool SkOpPtT::alias() const { 12 bool SkOpPtT::alias() const {
13 return this->span()->ptT() != this; 13 return this->span()->ptT() != this;
14 } 14 }
15 15
16 SkOpContour* SkOpPtT::contour() const { 16 SkOpContour* SkOpPtT::contour() const {
17 return segment()->contour(); 17 return segment()->contour();
18 } 18 }
19 19
20 SkOpDebugState* SkOpPtT::debugState() const { 20 SkOpGlobalState* SkOpPtT::globalState() const {
21 return PATH_OPS_DEBUG_RELEASE(contour()->debugState(), NULL); 21 return contour()->globalState();
22 } 22 }
23 23
24 void SkOpPtT::init(SkOpSpanBase* span, double t, const SkPoint& pt, bool duplica te) { 24 void SkOpPtT::init(SkOpSpanBase* span, double t, const SkPoint& pt, bool duplica te) {
25 fT = t; 25 fT = t;
26 fPt = pt; 26 fPt = pt;
27 fSpan = span; 27 fSpan = span;
28 fNext = this; 28 fNext = this;
29 fDuplicatePt = duplicate; 29 fDuplicatePt = duplicate;
30 fDeleted = false; 30 fDeleted = false;
31 PATH_OPS_DEBUG_CODE(fID = ++span->debugState()->fPtTID); 31 PATH_OPS_DEBUG_CODE(fID = span->globalState()->nextPtTID());
32 } 32 }
33 33
34 bool SkOpPtT::onEnd() const { 34 bool SkOpPtT::onEnd() const {
35 const SkOpSpanBase* span = this->span(); 35 const SkOpSpanBase* span = this->span();
36 if (span->ptT() != this) { 36 if (span->ptT() != this) {
37 return false; 37 return false;
38 } 38 }
39 const SkOpSegment* segment = this->segment(); 39 const SkOpSegment* segment = this->segment();
40 return span == segment->head() || span == segment->tail(); 40 return span == segment->head() || span == segment->tail();
41 } 41 }
42 42
43 SkOpPtT* SkOpPtT::prev() {
44 SkOpPtT* result = this;
45 SkOpPtT* next = this;
46 while ((next = next->fNext) != this) {
47 result = next;
48 }
49 SkASSERT(result->fNext == this);
50 return result;
51 }
52
43 SkOpPtT* SkOpPtT::remove() { 53 SkOpPtT* SkOpPtT::remove() {
44 SkOpPtT* prev = this; 54 SkOpPtT* prev = this;
45 do { 55 do {
46 SkOpPtT* next = prev->fNext; 56 SkOpPtT* next = prev->fNext;
47 if (next == this) { 57 if (next == this) {
48 prev->removeNext(); 58 prev->removeNext(this);
59 SkASSERT(prev->fNext != prev);
49 fDeleted = true; 60 fDeleted = true;
50 return prev; 61 return prev;
51 } 62 }
52 prev = next; 63 prev = next;
53 } while (prev != this); 64 } while (prev != this);
54 SkASSERT(0); 65 SkASSERT(0);
55 return NULL; 66 return NULL;
56 } 67 }
57 68
58 void SkOpPtT::removeNext() { 69 void SkOpPtT::removeNext(SkOpPtT* kept) {
59 SkASSERT(this->fNext); 70 SkASSERT(this->fNext);
60 SkOpPtT* next = this->fNext; 71 SkOpPtT* next = this->fNext;
72 SkASSERT(this != next->fNext);
61 this->fNext = next->fNext; 73 this->fNext = next->fNext;
62 SkOpSpanBase* span = next->span(); 74 SkOpSpanBase* span = next->span();
63 next->setDeleted(); 75 next->setDeleted();
64 if (span->ptT() == next) { 76 if (span->ptT() == next) {
65 span->upCast()->detach(); 77 span->upCast()->detach(kept);
66 } 78 }
67 } 79 }
68 80
69 const SkOpSegment* SkOpPtT::segment() const { 81 const SkOpSegment* SkOpPtT::segment() const {
70 return span()->segment(); 82 return span()->segment();
71 } 83 }
72 84
73 SkOpSegment* SkOpPtT::segment() { 85 SkOpSegment* SkOpPtT::segment() {
74 return span()->segment(); 86 return span()->segment();
75 } 87 }
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
192 SkOpPtT* test = ptT; 204 SkOpPtT* test = ptT;
193 do { 205 do {
194 SkOpPtT* prev = test; 206 SkOpPtT* prev = test;
195 if ((test = test->next()) == stopPtT) { 207 if ((test = test->next()) == stopPtT) {
196 break; 208 break;
197 } 209 }
198 if (span == test->span() && !span->segment()->ptsDisjoint(*ptT, *tes t)) { 210 if (span == test->span() && !span->segment()->ptsDisjoint(*ptT, *tes t)) {
199 // omit aliases that alignment makes redundant 211 // omit aliases that alignment makes redundant
200 if ((!ptT->alias() || test->alias()) && (ptT->onEnd() || !test-> onEnd())) { 212 if ((!ptT->alias() || test->alias()) && (ptT->onEnd() || !test-> onEnd())) {
201 SkASSERT(test->alias()); 213 SkASSERT(test->alias());
202 prev->removeNext(); 214 prev->removeNext(ptT);
203 test = prev; 215 test = prev;
204 } else { 216 } else {
205 SkASSERT(ptT->alias()); 217 SkASSERT(ptT->alias());
206 stopPtT = ptT = ptT->remove(); 218 stopPtT = ptT = ptT->remove();
207 break; 219 break;
208 } 220 }
209 } 221 }
210 } while (true); 222 } while (true);
211 } while ((ptT = ptT->next()) != stopPtT); 223 } while ((ptT = ptT->next()) != stopPtT);
212 } 224 }
213 225
214 bool SkOpSpanBase::contains(const SkOpSpanBase* span) const { 226 bool SkOpSpanBase::contains(const SkOpSpanBase* span) const {
215 const SkOpPtT* start = &fPtT; 227 const SkOpPtT* start = &fPtT;
216 const SkOpPtT* check = &span->fPtT; 228 const SkOpPtT* check = &span->fPtT;
217 SkASSERT(start != check); 229 SkASSERT(start != check);
218 const SkOpPtT* walk = start; 230 const SkOpPtT* walk = start;
219 while ((walk = walk->next()) != start) { 231 while ((walk = walk->next()) != start) {
220 if (walk == check) { 232 if (walk == check) {
221 return true; 233 return true;
222 } 234 }
223 } 235 }
224 return false; 236 return false;
225 } 237 }
226 238
239 SkOpPtT* SkOpSpanBase::contains(const SkOpSegment* segment) {
240 SkOpPtT* start = &fPtT;
241 SkOpPtT* walk = start;
242 while ((walk = walk->next()) != start) {
243 if (walk->segment() == segment) {
244 return walk;
245 }
246 }
247 return NULL;
248 }
249
227 bool SkOpSpanBase::containsCoinEnd(const SkOpSegment* segment) const { 250 bool SkOpSpanBase::containsCoinEnd(const SkOpSegment* segment) const {
228 SkASSERT(this->segment() != segment); 251 SkASSERT(this->segment() != segment);
229 const SkOpSpanBase* next = this; 252 const SkOpSpanBase* next = this;
230 while ((next = next->fCoinEnd) != this) { 253 while ((next = next->fCoinEnd) != this) {
231 if (next->segment() == segment) { 254 if (next->segment() == segment) {
232 return true; 255 return true;
233 } 256 }
234 } 257 }
235 return false; 258 return false;
236 } 259 }
237 260
238 SkOpContour* SkOpSpanBase::contour() const { 261 SkOpContour* SkOpSpanBase::contour() const {
239 return segment()->contour(); 262 return segment()->contour();
240 } 263 }
241 264
242 SkOpDebugState* SkOpSpanBase::debugState() const { 265 SkOpGlobalState* SkOpSpanBase::globalState() const {
243 return PATH_OPS_DEBUG_RELEASE(contour()->debugState(), NULL); 266 return contour()->globalState();
244 } 267 }
245 268
246 void SkOpSpanBase::initBase(SkOpSegment* segment, SkOpSpan* prev, double t, cons t SkPoint& pt) { 269 void SkOpSpanBase::initBase(SkOpSegment* segment, SkOpSpan* prev, double t, cons t SkPoint& pt) {
247 fSegment = segment; 270 fSegment = segment;
248 fPtT.init(this, t, pt, false); 271 fPtT.init(this, t, pt, false);
249 fCoinEnd = this; 272 fCoinEnd = this;
250 fFromAngle = NULL; 273 fFromAngle = NULL;
251 fPrev = prev; 274 fPrev = prev;
252 fAligned = true; 275 fAligned = true;
253 fChased = false; 276 fChased = false;
254 PATH_OPS_DEBUG_CODE(fCount = 1); 277 PATH_OPS_DEBUG_CODE(fCount = 1);
255 PATH_OPS_DEBUG_CODE(fID = ++debugState()->fSpanID); 278 PATH_OPS_DEBUG_CODE(fID = globalState()->nextSpanID());
256 } 279 }
257 280
258 // this pair of spans share a common t value or point; merge them and eliminate duplicates 281 // this pair of spans share a common t value or point; merge them and eliminate duplicates
259 // this does not compute the best t or pt value; this merely moves all data into a single list 282 // this does not compute the best t or pt value; this merely moves all data into a single list
260 void SkOpSpanBase::merge(SkOpSpan* span) { 283 void SkOpSpanBase::merge(SkOpSpan* span) {
261 SkOpPtT* spanPtT = span->ptT(); 284 SkOpPtT* spanPtT = span->ptT();
262 SkASSERT(this->t() != spanPtT->fT); 285 SkASSERT(this->t() != spanPtT->fT);
263 SkASSERT(!zero_or_one(spanPtT->fT)); 286 SkASSERT(!zero_or_one(spanPtT->fT));
264 span->detach(); 287 span->detach(this->ptT());
265 SkOpPtT* remainder = spanPtT->next(); 288 SkOpPtT* remainder = spanPtT->next();
266 ptT()->insert(spanPtT); 289 ptT()->insert(spanPtT);
267 while (remainder != spanPtT) { 290 while (remainder != spanPtT) {
268 SkOpPtT* next = remainder->next(); 291 SkOpPtT* next = remainder->next();
269 SkOpPtT* compare = spanPtT->next(); 292 SkOpPtT* compare = spanPtT->next();
270 while (compare != spanPtT) { 293 while (compare != spanPtT) {
271 SkOpPtT* nextC = compare->next(); 294 SkOpPtT* nextC = compare->next();
272 if (nextC->span() == remainder->span() && nextC->fT == remainder->fT ) { 295 if (nextC->span() == remainder->span() && nextC->fT == remainder->fT ) {
273 goto tryNextRemainder; 296 goto tryNextRemainder;
274 } 297 }
275 compare = nextC; 298 compare = nextC;
276 } 299 }
277 spanPtT->insert(remainder); 300 spanPtT->insert(remainder);
278 tryNextRemainder: 301 tryNextRemainder:
279 remainder = next; 302 remainder = next;
280 } 303 }
281 } 304 }
282 305
283 void SkOpSpanBase::mergeBaseAttributes(SkOpSpanBase* span) {
284 SkASSERT(!span->fChased);
285 SkASSERT(!span->fFromAngle);
286 if (this->upCastable() && span->upCastable()) {
287 this->upCast()->mergeAttributes(span->upCast());
288 }
289 }
290
291 void SkOpSpan::applyCoincidence(SkOpSpan* opp) { 306 void SkOpSpan::applyCoincidence(SkOpSpan* opp) {
292 SkASSERT(!final()); 307 SkASSERT(!final());
293 SkASSERT(0); // incomplete 308 SkASSERT(0); // incomplete
294 } 309 }
295 310
296 bool SkOpSpan::containsCoincidence(const SkOpSegment* segment) const { 311 bool SkOpSpan::containsCoincidence(const SkOpSegment* segment) const {
297 SkASSERT(this->segment() != segment); 312 SkASSERT(this->segment() != segment);
298 const SkOpSpan* next = this; 313 const SkOpSpan* next = fCoincident;
299 while ((next = next->fCoincident) != this) { 314 do {
300 if (next->segment() == segment) { 315 if (next->segment() == segment) {
301 return true; 316 return true;
302 } 317 }
303 } 318 } while ((next = next->fCoincident) != this);
304 return false; 319 return false;
305 } 320 }
306 321
307 void SkOpSpan::detach() { 322 void SkOpSpan::detach(SkOpPtT* kept) {
308 SkASSERT(!final()); 323 SkASSERT(!final());
309 SkOpSpan* prev = this->prev(); 324 SkOpSpan* prev = this->prev();
310 SkASSERT(prev); 325 SkASSERT(prev);
311 SkOpSpanBase* next = this->next(); 326 SkOpSpanBase* next = this->next();
312 SkASSERT(next); 327 SkASSERT(next);
313 prev->setNext(next); 328 prev->setNext(next);
314 next->setPrev(prev); 329 next->setPrev(prev);
315 this->segment()->detach(this); 330 this->segment()->detach(this);
331 this->globalState()->coincidence()->fixUp(this->ptT(), kept);
316 this->ptT()->setDeleted(); 332 this->ptT()->setDeleted();
317 } 333 }
318 334
319 void SkOpSpan::init(SkOpSegment* segment, SkOpSpan* prev, double t, const SkPoin t& pt) { 335 void SkOpSpan::init(SkOpSegment* segment, SkOpSpan* prev, double t, const SkPoin t& pt) {
320 SkASSERT(t != 1); 336 SkASSERT(t != 1);
321 initBase(segment, prev, t, pt); 337 initBase(segment, prev, t, pt);
322 fCoincident = this; 338 fCoincident = this;
323 fToAngle = NULL; 339 fToAngle = NULL;
324 fWindSum = fOppSum = SK_MinS32; 340 fWindSum = fOppSum = SK_MinS32;
325 fWindValue = 1; 341 fWindValue = 1;
326 fOppValue = 0; 342 fOppValue = 0;
327 fChased = fDone = false; 343 fChased = fDone = false;
328 segment->bumpCount(); 344 segment->bumpCount();
329 } 345 }
330 346
331 void SkOpSpan::mergeAttributes(SkOpSpan* span) { 347 void SkOpSpan::setOppSum(int oppSum) {
332 SkASSERT(!span->fToAngle); 348 SkASSERT(!final());
333 if (span->fCoincident) { 349 if (fOppSum != SK_MinS32 && fOppSum != oppSum) {
334 this->insertCoincidence(span); 350 this->globalState()->setWindingFailed();
335 }
336 }
337
338 void SkOpCoincidence::add(SkOpPtT* coinPtTStart, SkOpPtT* coinPtTEnd, SkOpPtT* o ppPtTStart,
339 SkOpPtT* oppPtTEnd, bool flipped, SkChunkAlloc* allocator) {
340 SkCoincidentSpans* coinRec = SkOpTAllocator<SkCoincidentSpans>::Allocate(all ocator);
341 SkOpSpanBase* coinEnd = coinPtTEnd->span();
342 SkOpSpanBase* oppEnd = oppPtTEnd->span();
343 SkOpSpan* coinStart = coinPtTStart->span()->upCast();
344 SkASSERT(coinStart == coinStart->starter(coinEnd));
345 SkOpSpan* oppStart = (flipped ? oppPtTEnd : oppPtTStart)->span()->upCast();
346 SkASSERT(oppStart == oppStart->starter(oppEnd));
347 coinStart->insertCoincidence(oppStart);
348 coinEnd->insertCoinEnd(oppEnd);
349 coinRec->fNext = this->fHead;
350 coinRec->fCoinPtTStart = coinPtTStart;
351 coinRec->fCoinPtTEnd = coinPtTEnd;
352 coinRec->fOppPtTStart = oppPtTStart;
353 coinRec->fOppPtTEnd = oppPtTEnd;
354 coinRec->fFlipped = flipped;
355 this->fHead = coinRec;
356 }
357
358 bool SkOpCoincidence::contains(SkOpPtT* coinPtTStart, SkOpPtT* coinPtTEnd, SkOpP tT* oppPtTStart,
359 SkOpPtT* oppPtTEnd, bool flipped) {
360 SkCoincidentSpans* coin = fHead;
361 if (!coin) {
362 return false;
363 }
364 do {
365 if (coin->fCoinPtTStart == coinPtTStart && coin->fCoinPtTEnd == coinPtT End
366 && coin->fOppPtTStart == oppPtTStart && coin->fOppPtTEnd == oppP tTEnd
367 && coin->fFlipped == flipped) {
368 return true;
369 }
370 } while ((coin = coin->fNext));
371 return false;
372 }
373
374 // walk span sets in parallel, moving winding from one to the other
375 void SkOpCoincidence::apply() {
376 SkCoincidentSpans* coin = fHead;
377 if (!coin) {
378 return; 351 return;
379 } 352 }
380 do { 353 SkASSERT(!DEBUG_LIMIT_WIND_SUM || abs(oppSum) <= DEBUG_LIMIT_WIND_SUM);
381 SkOpSpanBase* end = coin->fCoinPtTEnd->span(); 354 fOppSum = oppSum;
382 SkOpSpan* start = coin->fCoinPtTStart->span()->upCast();
383 SkASSERT(start == start->starter(end));
384 bool flipped = coin->fFlipped;
385 SkOpSpanBase* oEnd = (flipped ? coin->fOppPtTStart : coin->fOppPtTEnd)-> span();
386 SkOpSpan* oStart = (flipped ? coin->fOppPtTEnd : coin->fOppPtTStart)->sp an()->upCast();
387 SkASSERT(oStart == oStart->starter(oEnd));
388 SkOpSegment* segment = start->segment();
389 SkOpSegment* oSegment = oStart->segment();
390 bool operandSwap = segment->operand() != oSegment->operand();
391 if (flipped) {
392 do {
393 SkOpSpanBase* oNext = oStart->next();
394 if (oNext == oEnd) {
395 break;
396 }
397 oStart = oNext->upCast();
398 } while (true);
399 }
400 bool isXor = segment->isXor();
401 bool oppXor = oSegment->isXor();
402 do {
403 int windValue = start->windValue();
404 int oWindValue = oStart->windValue();
405 int oppValue = start->oppValue();
406 int oOppValue = oStart->oppValue();
407 // winding values are added or subtracted depending on direction and wind type
408 // same or opposite values are summed depending on the operand value
409 if (windValue >= oWindValue) {
410 if (operandSwap) {
411 SkTSwap(oWindValue, oOppValue);
412 }
413 if (flipped) {
414 windValue -= oWindValue;
415 oppValue -= oOppValue;
416 } else {
417 windValue += oWindValue;
418 oppValue += oOppValue;
419 }
420 if (isXor) {
421 windValue &= 1;
422 }
423 if (oppXor) {
424 oppValue &= 1;
425 }
426 oWindValue = oOppValue = 0;
427 } else {
428 if (operandSwap) {
429 SkTSwap(windValue, oppValue);
430 }
431 if (flipped) {
432 oWindValue -= windValue;
433 oOppValue -= oppValue;
434 } else {
435 oWindValue += windValue;
436 oOppValue += oppValue;
437 }
438 if (isXor) {
439 oOppValue &= 1;
440 }
441 if (oppXor) {
442 oWindValue &= 1;
443 }
444 windValue = oppValue = 0;
445 }
446 start->setWindValue(windValue);
447 start->setOppValue(oppValue);
448 oStart->setWindValue(oWindValue);
449 oStart->setOppValue(oOppValue);
450 if (!windValue && !oppValue) {
451 segment->markDone(start);
452 }
453 if (!oWindValue && !oOppValue) {
454 oSegment->markDone(oStart);
455 }
456 SkOpSpanBase* next = start->next();
457 SkOpSpanBase* oNext = flipped ? oStart->prev() : oStart->next();
458 if (next == end) {
459 break;
460 }
461 start = next->upCast();
462 oStart = oNext->upCast();
463 } while (true);
464 } while ((coin = coin->fNext));
465 } 355 }
466
467 void SkOpCoincidence::mark() {
468 SkCoincidentSpans* coin = fHead;
469 if (!coin) {
470 return;
471 }
472 do {
473 SkOpSpanBase* end = coin->fCoinPtTEnd->span();
474 SkOpSpanBase* oldEnd = end;
475 SkOpSpan* start = coin->fCoinPtTStart->span()->starter(&end);
476 SkOpSpanBase* oEnd = coin->fOppPtTEnd->span();
477 SkOpSpanBase* oOldEnd = oEnd;
478 SkOpSpanBase* oStart = coin->fOppPtTStart->span()->starter(&oEnd);
479 bool flipped = (end == oldEnd) != (oEnd == oOldEnd);
480 if (flipped) {
481 SkTSwap(oStart, oEnd);
482 }
483 SkOpSpanBase* next = start;
484 SkOpSpanBase* oNext = oStart;
485 do {
486 next = next->upCast()->next();
487 oNext = flipped ? oNext->prev() : oNext->upCast()->next();
488 if (next == end) {
489 SkASSERT(oNext == oEnd);
490 break;
491 }
492 if (!next->containsCoinEnd(oNext)) {
493 next->insertCoinEnd(oNext);
494 }
495 SkOpSpan* nextSpan = next->upCast();
496 SkOpSpan* oNextSpan = oNext->upCast();
497 if (!nextSpan->containsCoincidence(oNextSpan)) {
498 nextSpan->insertCoincidence(oNextSpan);
499 }
500 } while (true);
501 } while ((coin = coin->fNext));
502 }
OLDNEW
« no previous file with comments | « src/pathops/SkOpSpan.h ('k') | src/pathops/SkOpTAllocator.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698