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

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

Issue 1111333002: compute initial winding from projected rays (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: add missing test reference Created 5 years, 7 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/SkOpSegment.h ('k') | src/pathops/SkOpSpan.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 2012 Google Inc. 2 * Copyright 2012 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"
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
95 } 95 }
96 96
97 SkOpAngle* SkOpSegment::activeAngleOther(SkOpSpanBase* start, SkOpSpanBase** sta rtPtr, 97 SkOpAngle* SkOpSegment::activeAngleOther(SkOpSpanBase* start, SkOpSpanBase** sta rtPtr,
98 SkOpSpanBase** endPtr, bool* done, bool* sortable) { 98 SkOpSpanBase** endPtr, bool* done, bool* sortable) {
99 SkOpPtT* oPtT = start->ptT()->next(); 99 SkOpPtT* oPtT = start->ptT()->next();
100 SkOpSegment* other = oPtT->segment(); 100 SkOpSegment* other = oPtT->segment();
101 SkOpSpanBase* oSpan = oPtT->span(); 101 SkOpSpanBase* oSpan = oPtT->span();
102 return other->activeAngleInner(oSpan, startPtr, endPtr, done, sortable); 102 return other->activeAngleInner(oSpan, startPtr, endPtr, done, sortable);
103 } 103 }
104 104
105 SkDPoint SkOpSegment::activeLeftTop(SkOpSpanBase** firstSpan) {
106 SkASSERT(!done());
107 SkDPoint topPt = {SK_ScalarMax, SK_ScalarMax};
108 // see if either end is not done since we want smaller Y of the pair
109 bool lastDone = true;
110 SkOpSpanBase* span = &fHead;
111 SkOpSpanBase* lastSpan = NULL;
112 do {
113 if (!lastDone || (!span->final() && !span->upCast()->done())) {
114 const SkPoint& xy = span->pt();
115 if (topPt.fY > xy.fY || (topPt.fY == xy.fY && topPt.fX > xy.fX)) {
116 topPt = xy;
117 if (firstSpan) {
118 *firstSpan = span;
119 }
120 }
121 if (fVerb != SkPath::kLine_Verb && !lastDone) {
122 double curveTopT;
123 SkDCurve curve;
124 this->subDivide(lastSpan, span, &curve);
125 SkDPoint curveTop = (curve.*Top[fVerb])(fPts, fWeight, lastSpan- >t(), span->t(),
126 &curveTopT);
127 if (topPt.fY > curveTop.fY || (topPt.fY == curveTop.fY && topPt. fX > curveTop.fX)) {
128 topPt = curveTop;
129 if (firstSpan) {
130 const SkPoint& lastXY = lastSpan->pt();
131 *firstSpan = lastXY.fY > xy.fY || (lastXY.fY == xy.fY && lastXY.fX > xy.fX)
132 ? span : lastSpan;
133 }
134 }
135 }
136 lastSpan = span;
137 }
138 if (span->final()) {
139 break;
140 }
141 lastDone = span->upCast()->done();
142 } while ((span = span->upCast()->next()));
143 return topPt;
144 }
145
146 bool SkOpSegment::activeOp(SkOpSpanBase* start, SkOpSpanBase* end, int xorMiMask , int xorSuMask, 105 bool SkOpSegment::activeOp(SkOpSpanBase* start, SkOpSpanBase* end, int xorMiMask , int xorSuMask,
147 SkPathOp op) { 106 SkPathOp op) {
148 int sumMiWinding = this->updateWinding(end, start); 107 int sumMiWinding = this->updateWinding(end, start);
149 int sumSuWinding = this->updateOppWinding(end, start); 108 int sumSuWinding = this->updateOppWinding(end, start);
150 #if DEBUG_LIMIT_WIND_SUM 109 #if DEBUG_LIMIT_WIND_SUM
151 SkASSERT(abs(sumMiWinding) <= DEBUG_LIMIT_WIND_SUM); 110 SkASSERT(abs(sumMiWinding) <= DEBUG_LIMIT_WIND_SUM);
152 SkASSERT(abs(sumSuWinding) <= DEBUG_LIMIT_WIND_SUM); 111 SkASSERT(abs(sumSuWinding) <= DEBUG_LIMIT_WIND_SUM);
153 #endif 112 #endif
154 if (this->operand()) { 113 if (this->operand()) {
155 SkTSwap<int>(sumMiWinding, sumSuWinding); 114 SkTSwap<int>(sumMiWinding, sumSuWinding);
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
271 SkOpPtT* result; 230 SkOpPtT* result;
272 if (existing && existing->contains(opp)) { 231 if (existing && existing->contains(opp)) {
273 result = existing->ptT(); 232 result = existing->ptT();
274 } else { 233 } else {
275 result = this->addT(t, SkOpSegment::kNoAlias, allocator); 234 result = this->addT(t, SkOpSegment::kNoAlias, allocator);
276 } 235 }
277 SkASSERT(result); 236 SkASSERT(result);
278 return result; 237 return result;
279 } 238 }
280 239
281 SkOpAngle* SkOpSegment::addSingletonAngleDown(SkOpSegment** otherPtr, SkOpAngle* * anglePtr,
282 SkChunkAlloc* allocator) {
283 SkOpSpan* startSpan = fTail.prev();
284 SkASSERT(startSpan);
285 SkOpAngle* angle = SkOpTAllocator<SkOpAngle>::Allocate(allocator);
286 *anglePtr = angle;
287 angle->set(&fTail, startSpan);
288 fTail.setFromAngle(angle);
289 SkOpSegment* other = NULL; // these initializations silence a release build warning
290 SkOpSpan* oStartSpan = NULL;
291 SkOpSpanBase* oEndSpan = NULL;
292 SkOpPtT* ptT = fTail.ptT(), * startPtT = ptT;
293 while ((ptT = ptT->next()) != startPtT) {
294 other = ptT->segment();
295 oStartSpan = ptT->span()->upCastable();
296 if (oStartSpan && oStartSpan->windValue()) {
297 oEndSpan = oStartSpan->next();
298 break;
299 }
300 oEndSpan = ptT->span();
301 oStartSpan = oEndSpan->prev();
302 if (oStartSpan && oStartSpan->windValue()) {
303 break;
304 }
305 }
306 if (!oStartSpan) {
307 return NULL;
308 }
309 SkOpAngle* oAngle = SkOpTAllocator<SkOpAngle>::Allocate(allocator);
310 oAngle->set(oStartSpan, oEndSpan);
311 oStartSpan->setToAngle(oAngle);
312 *otherPtr = other;
313 return oAngle;
314 }
315
316 SkOpAngle* SkOpSegment::addSingletonAngles(int step, SkChunkAlloc* allocator) {
317 SkOpSegment* other;
318 SkOpAngle* angle, * otherAngle;
319 if (step > 0) {
320 otherAngle = addSingletonAngleUp(&other, &angle, allocator);
321 } else {
322 otherAngle = addSingletonAngleDown(&other, &angle, allocator);
323 }
324 if (!otherAngle) {
325 return NULL;
326 }
327 angle->insert(otherAngle);
328 return angle;
329 }
330
331 SkOpAngle* SkOpSegment::addSingletonAngleUp(SkOpSegment** otherPtr, SkOpAngle** anglePtr,
332 SkChunkAlloc* allocator) {
333 SkOpSpanBase* endSpan = fHead.next();
334 SkASSERT(endSpan);
335 SkOpAngle* angle = SkOpTAllocator<SkOpAngle>::Allocate(allocator);
336 *anglePtr = angle;
337 angle->set(&fHead, endSpan);
338 fHead.setToAngle(angle);
339 SkOpSegment* other = NULL; // these initializations silence a release build warning
340 SkOpSpan* oStartSpan = NULL;
341 SkOpSpanBase* oEndSpan = NULL;
342 SkOpPtT* ptT = fHead.ptT(), * startPtT = ptT;
343 while ((ptT = ptT->next()) != startPtT) {
344 other = ptT->segment();
345 oEndSpan = ptT->span();
346 oStartSpan = oEndSpan->prev();
347 if (oStartSpan && oStartSpan->windValue()) {
348 break;
349 }
350 oStartSpan = oEndSpan->upCastable();
351 if (oStartSpan && oStartSpan->windValue()) {
352 oEndSpan = oStartSpan->next();
353 break;
354 }
355 }
356 SkOpAngle* oAngle = SkOpTAllocator<SkOpAngle>::Allocate(allocator);
357 oAngle->set(oEndSpan, oStartSpan);
358 oEndSpan->setFromAngle(oAngle);
359 *otherPtr = other;
360 return oAngle;
361 }
362
363 SkOpPtT* SkOpSegment::addT(double t, AllowAlias allowAlias, SkChunkAlloc* alloca tor) { 240 SkOpPtT* SkOpSegment::addT(double t, AllowAlias allowAlias, SkChunkAlloc* alloca tor) {
364 debugValidate(); 241 debugValidate();
365 SkPoint pt = this->ptAtT(t); 242 SkPoint pt = this->ptAtT(t);
366 SkOpSpanBase* span = &fHead; 243 SkOpSpanBase* span = &fHead;
367 do { 244 do {
368 SkOpPtT* result = span->ptT(); 245 SkOpPtT* result = span->ptT();
369 SkOpPtT* loop; 246 SkOpPtT* loop;
370 bool duplicatePt; 247 bool duplicatePt;
371 if (t == result->fT) { 248 if (t == result->fT) {
372 goto bumpSpan; 249 goto bumpSpan;
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
430 break; 307 break;
431 } 308 }
432 span->align(); 309 span->align();
433 } 310 }
434 if (!span->aligned()) { 311 if (!span->aligned()) {
435 span->alignEnd(1, fPts[SkPathOpsVerbToPoints(fVerb)]); 312 span->alignEnd(1, fPts[SkPathOpsVerbToPoints(fVerb)]);
436 } 313 }
437 debugValidate(); 314 debugValidate();
438 } 315 }
439 316
440 bool SkOpSegment::BetweenTs(const SkOpSpanBase* lesser, double testT,
441 const SkOpSpanBase* greater) {
442 if (lesser->t() > greater->t()) {
443 SkTSwap<const SkOpSpanBase*>(lesser, greater);
444 }
445 return approximately_between(lesser->t(), testT, greater->t());
446 }
447
448 void SkOpSegment::calcAngles(SkChunkAlloc* allocator) { 317 void SkOpSegment::calcAngles(SkChunkAlloc* allocator) {
449 bool activePrior = !fHead.isCanceled(); 318 bool activePrior = !fHead.isCanceled();
450 if (activePrior && !fHead.simple()) { 319 if (activePrior && !fHead.simple()) {
451 addStartSpan(allocator); 320 addStartSpan(allocator);
452 } 321 }
453 SkOpSpan* prior = &fHead; 322 SkOpSpan* prior = &fHead;
454 SkOpSpanBase* spanBase = fHead.next(); 323 SkOpSpanBase* spanBase = fHead.next();
455 while (spanBase != &fTail) { 324 while (spanBase != &fTail) {
456 if (activePrior) { 325 if (activePrior) {
457 SkOpAngle* priorAngle = SkOpTAllocator<SkOpAngle>::Allocate(allocato r); 326 SkOpAngle* priorAngle = SkOpTAllocator<SkOpAngle>::Allocate(allocato r);
(...skipping 29 matching lines...) Expand all
487 break; 356 break;
488 } 357 }
489 span = base->upCast(); 358 span = base->upCast();
490 angle = span->toAngle(); 359 angle = span->toAngle();
491 if (angle && angle->fCheckCoincidence) { 360 if (angle && angle->fCheckCoincidence) {
492 angle->checkNearCoincidence(); 361 angle->checkNearCoincidence();
493 } 362 }
494 } while ((base = span->next())); 363 } while ((base = span->next()));
495 } 364 }
496 365
497 // from http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of -polygon-points-are-in-clockwise-order
498 bool SkOpSegment::clockwise(const SkOpSpanBase* start, const SkOpSpanBase* end, bool* swap) const {
499 SkASSERT(fVerb != SkPath::kLine_Verb);
500 if (fVerb != SkPath::kCubic_Verb) {
501 SkOpCurve edge;
502 this->subDivide(start, end, &edge);
503 return SkDQuad::Clockwise(edge, swap);
504 }
505 return SkDCubic::Clockwise(fPts, start->t(), end->t(), swap);
506 }
507
508 void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle , 366 void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle ,
509 SkOpAngle::IncludeType includeType) { 367 SkOpAngle::IncludeType includeType) {
510 const SkOpSegment* baseSegment = baseAngle->segment(); 368 SkOpSegment* baseSegment = baseAngle->segment();
511 int sumMiWinding = baseSegment->updateWindingReverse(baseAngle); 369 int sumMiWinding = baseSegment->updateWindingReverse(baseAngle);
512 int sumSuWinding; 370 int sumSuWinding;
513 bool binary = includeType >= SkOpAngle::kBinarySingle; 371 bool binary = includeType >= SkOpAngle::kBinarySingle;
514 if (binary) { 372 if (binary) {
515 sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle); 373 sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle);
516 if (baseSegment->operand()) { 374 if (baseSegment->operand()) {
517 SkTSwap<int>(sumMiWinding, sumSuWinding); 375 SkTSwap<int>(sumMiWinding, sumSuWinding);
518 } 376 }
519 } 377 }
520 SkOpSegment* nextSegment = nextAngle->segment(); 378 SkOpSegment* nextSegment = nextAngle->segment();
521 int maxWinding, sumWinding; 379 int maxWinding, sumWinding;
522 SkOpSpanBase* last; 380 SkOpSpanBase* last;
523 if (binary) { 381 if (binary) {
524 int oppMaxWinding, oppSumWinding; 382 int oppMaxWinding, oppSumWinding;
525 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiW inding, 383 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiW inding,
526 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSum Winding); 384 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSum Winding);
527 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, opp SumWinding, 385 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, opp SumWinding,
528 nextAngle); 386 nextAngle);
529 } else { 387 } else {
530 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiW inding, 388 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiW inding,
531 &maxWinding, &sumWinding); 389 &maxWinding, &sumWinding);
532 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle); 390 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
533 } 391 }
534 nextAngle->setLastMarked(last); 392 nextAngle->setLastMarked(last);
535 } 393 }
536 394
537 void SkOpSegment::ComputeOneSumReverse(const SkOpAngle* baseAngle, SkOpAngle* ne xtAngle, 395 void SkOpSegment::ComputeOneSumReverse(SkOpAngle* baseAngle, SkOpAngle* nextAngl e,
538 SkOpAngle::IncludeType includeType) { 396 SkOpAngle::IncludeType includeType) {
539 const SkOpSegment* baseSegment = baseAngle->segment(); 397 SkOpSegment* baseSegment = baseAngle->segment();
540 int sumMiWinding = baseSegment->updateWinding(baseAngle); 398 int sumMiWinding = baseSegment->updateWinding(baseAngle);
541 int sumSuWinding; 399 int sumSuWinding;
542 bool binary = includeType >= SkOpAngle::kBinarySingle; 400 bool binary = includeType >= SkOpAngle::kBinarySingle;
543 if (binary) { 401 if (binary) {
544 sumSuWinding = baseSegment->updateOppWinding(baseAngle); 402 sumSuWinding = baseSegment->updateOppWinding(baseAngle);
545 if (baseSegment->operand()) { 403 if (baseSegment->operand()) {
546 SkTSwap<int>(sumMiWinding, sumSuWinding); 404 SkTSwap<int>(sumMiWinding, sumSuWinding);
547 } 405 }
548 } 406 }
549 SkOpSegment* nextSegment = nextAngle->segment(); 407 SkOpSegment* nextSegment = nextAngle->segment();
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
627 } 485 }
628 if (baseAngle) { 486 if (baseAngle) {
629 ComputeOneSumReverse(baseAngle, angle, includeType); 487 ComputeOneSumReverse(baseAngle, angle, includeType);
630 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : N ULL; 488 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : N ULL;
631 } 489 }
632 } while (prior != firstAngle); 490 } while (prior != firstAngle);
633 } 491 }
634 return start->starter(end)->windSum(); 492 return start->starter(end)->windSum();
635 } 493 }
636 494
637 SkOpSpan* SkOpSegment::crossedSpanY(const SkPoint& basePt, double mid, bool opp, bool current,
638 SkScalar* bestY, double* hitT, bool* hitSomething, bool* vertical) {
639 SkScalar bottom = fBounds.fBottom;
640 *vertical = false;
641 if (bottom <= *bestY) {
642 return NULL;
643 }
644 SkScalar top = fBounds.fTop;
645 if (top >= basePt.fY) {
646 return NULL;
647 }
648 if (fBounds.fLeft > basePt.fX) {
649 return NULL;
650 }
651 if (fBounds.fRight < basePt.fX) {
652 return NULL;
653 }
654 if (fBounds.fLeft == fBounds.fRight) {
655 // if vertical, and directly above test point, wait for another one
656 *vertical = AlmostEqualUlps(basePt.fX, fBounds.fLeft);
657 return NULL;
658 }
659 // intersect ray starting at basePt with edge
660 SkIntersections intersections;
661 // OPTIMIZE: use specialty function that intersects ray with curve,
662 // returning t values only for curve (we don't care about t on ray)
663 intersections.allowNear(false);
664 int pts = (intersections.*CurveVertical[fVerb])(fPts, fWeight, top, bottom, basePt.fX, false);
665 if (pts == 0 || (current && pts == 1)) {
666 return NULL;
667 }
668 if (current) {
669 SkASSERT(pts > 1);
670 int closestIdx = 0;
671 double closest = fabs(intersections[0][0] - mid);
672 for (int idx = 1; idx < pts; ++idx) {
673 double test = fabs(intersections[0][idx] - mid);
674 if (closest > test) {
675 closestIdx = idx;
676 closest = test;
677 }
678 }
679 intersections.quickRemoveOne(closestIdx, --pts);
680 }
681 double bestT = -1;
682 for (int index = 0; index < pts; ++index) {
683 double foundT = intersections[0][index];
684 if (approximately_less_than_zero(foundT)
685 || approximately_greater_than_one(foundT)) {
686 continue;
687 }
688 SkScalar testY = (*CurvePointAtT[fVerb])(fPts, fWeight, foundT).fY;
689 if (approximately_negative(testY - *bestY)
690 || approximately_negative(basePt.fY - testY)) {
691 continue;
692 }
693 if (pts > 1 && fVerb == SkPath::kLine_Verb) {
694 *vertical = true;
695 return NULL; // if the intersection is edge on, wait for another on e
696 }
697 if (fVerb > SkPath::kLine_Verb) {
698 SkScalar dx = (*CurveSlopeAtT[fVerb])(fPts, fWeight, foundT).fX;
699 if (approximately_zero(dx)) {
700 *vertical = true;
701 return NULL; // hit vertical, wait for another one
702 }
703 }
704 *bestY = testY;
705 bestT = foundT;
706 }
707 if (bestT < 0) {
708 return NULL;
709 }
710 SkASSERT(bestT >= 0);
711 SkASSERT(bestT < 1);
712 SkOpSpanBase* testTSpanBase = &this->fHead;
713 SkOpSpanBase* nextTSpan;
714 double endT = 0;
715 do {
716 nextTSpan = testTSpanBase->upCast()->next();
717 endT = nextTSpan->t();
718 if (endT >= bestT) {
719 break;
720 }
721 testTSpanBase = nextTSpan;
722 } while (testTSpanBase);
723 SkOpSpan* bestTSpan = NULL;
724 SkOpSpan* testTSpan = testTSpanBase->upCast();
725 if (!testTSpan->isCanceled()) {
726 *hitT = bestT;
727 bestTSpan = testTSpan;
728 *hitSomething = true;
729 }
730 return bestTSpan;
731 }
732
733 void SkOpSegment::detach(const SkOpSpan* span) { 495 void SkOpSegment::detach(const SkOpSpan* span) {
734 if (span->done()) { 496 if (span->done()) {
735 --fDoneCount; 497 --fDoneCount;
736 } 498 }
737 --fCount; 499 --fCount;
738 SkASSERT(fCount >= fDoneCount); 500 SkASSERT(fCount >= fDoneCount);
739 } 501 }
740 502
741 double SkOpSegment::distSq(double t, SkOpAngle* oppAngle) { 503 double SkOpSegment::distSq(double t, SkOpAngle* oppAngle) {
742 SkDPoint testPt = this->dPtAtT(t); 504 SkDPoint testPt = this->dPtAtT(t);
(...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after
1029 *nextStart = foundAngle->start(); 791 *nextStart = foundAngle->start();
1030 *nextEnd = foundAngle->end(); 792 *nextEnd = foundAngle->end();
1031 nextSegment = foundAngle->segment(); 793 nextSegment = foundAngle->segment();
1032 #if DEBUG_WINDING 794 #if DEBUG_WINDING
1033 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", 795 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
1034 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEn d); 796 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEn d);
1035 #endif 797 #endif
1036 return nextSegment; 798 return nextSegment;
1037 } 799 }
1038 800
1039 SkOpSegment* SkOpSegment::findTop(bool firstPass, SkOpSpanBase** startPtr, SkOpS panBase** endPtr,
1040 bool* unsortable, SkChunkAlloc* allocator) {
1041 // iterate through T intersections and return topmost
1042 // topmost tangent from y-min to first pt is closer to horizontal
1043 SkASSERT(!done());
1044 SkOpSpanBase* firstT = NULL;
1045 (void) this->activeLeftTop(&firstT);
1046 if (!firstT) {
1047 *unsortable = !firstPass;
1048 firstT = &fHead;
1049 while (firstT->upCast()->done()) {
1050 firstT = firstT->upCast()->next();
1051 }
1052 *startPtr = firstT;
1053 *endPtr = firstT->upCast()->next();
1054 return this;
1055 }
1056 // sort the edges to find the leftmost
1057 int step = 1;
1058 SkOpSpanBase* end;
1059 if (firstT->final() || firstT->upCast()->done()) {
1060 step = -1;
1061 end = firstT->prev();
1062 SkASSERT(end);
1063 } else {
1064 end = firstT->upCast()->next();
1065 }
1066 // if the topmost T is not on end, or is three-way or more, find left
1067 // look for left-ness from tLeft to firstT (matching y of other)
1068 SkASSERT(firstT != end);
1069 SkOpAngle* markAngle = spanToAngle(firstT, end);
1070 if (!markAngle) {
1071 markAngle = addSingletonAngles(step, allocator);
1072 }
1073 if (!markAngle) {
1074 return NULL;
1075 }
1076 if (!markAngle->markStops()) {
1077 return NULL;
1078 }
1079 const SkOpAngle* baseAngle = markAngle->next() == markAngle && !isVertical() ? markAngle
1080 : markAngle->findFirst();
1081 if (!baseAngle) {
1082 return NULL; // nothing to do
1083 }
1084 SkScalar top = SK_ScalarMax;
1085 const SkOpAngle* firstAngle = NULL;
1086 const SkOpAngle* angle = baseAngle;
1087 #if DEBUG_SWAP_TOP
1088 SkDebugf("-%s- baseAngle\n", __FUNCTION__);
1089 baseAngle->debugLoop();
1090 #endif
1091 do {
1092 if (!angle->unorderable()) {
1093 const SkOpSegment* next = angle->segment();
1094 SkPathOpsBounds bounds;
1095 next->subDivideBounds(angle->end(), angle->start(), &bounds);
1096 if (top > bounds.fTop) {
1097 top = bounds.fTop;
1098 firstAngle = angle;
1099 }
1100 }
1101 angle = angle->next();
1102 } while (angle != baseAngle);
1103 if (!firstAngle) {
1104 return NULL; // if all are unorderable, give up
1105 }
1106 #if DEBUG_SWAP_TOP
1107 SkDebugf("-%s- firstAngle\n", __FUNCTION__);
1108 firstAngle->debugLoop();
1109 #endif
1110 // skip edges that have already been processed
1111 angle = firstAngle;
1112 SkOpSegment* leftSegment = NULL;
1113 bool looped = false;
1114 do {
1115 *unsortable = angle->unorderable();
1116 if (firstPass || !*unsortable) {
1117 leftSegment = angle->segment();
1118 *startPtr = angle->end();
1119 *endPtr = angle->start();
1120 const SkOpSpan* firstSpan = (*startPtr)->starter(*endPtr);
1121 if (!firstSpan->done()) {
1122 break;
1123 }
1124 }
1125 angle = angle->next();
1126 looped = true;
1127 } while (angle != firstAngle);
1128 if (angle == firstAngle && looped) {
1129 return NULL;
1130 }
1131 if (leftSegment->verb() >= SkPath::kQuad_Verb) {
1132 SkOpSpanBase* start = *startPtr;
1133 SkOpSpanBase* end = *endPtr;
1134 bool swap;
1135 bool cw = leftSegment->clockwise(start, end, &swap);
1136 #if DEBUG_SWAP_TOP
1137 SkDebugf("%s id=%d s=%1.9g e=%1.9g (%c) cw=%d swap=%d inflections=%d mon otonic=%d\n",
1138 __FUNCTION__, leftSegment->debugID(), start->t(), end->t(),
1139 start->t() < end->t() ? '-' : '+', cw,
1140 swap, leftSegment->debugInflections(start, end),
1141 leftSegment->monotonicInY(start, end));
1142 #endif
1143 if (!cw && swap) {
1144 // FIXME: I doubt it makes sense to (necessarily) swap if the edge was not t he first
1145 // sorted but merely the first not already processed (i.e., not done)
1146 SkTSwap(*startPtr, *endPtr);
1147 }
1148 // FIXME: clockwise isn't reliable -- try computing swap from tangent ?
1149 } else {
1150 #if DEBUG_SWAP_TOP
1151 SkDebugf("%s id=%d s=%1.9g e=%1.9g (%c) cw=%d swap=%d inflections=%d mon otonic=%d\n",
1152 __FUNCTION__, leftSegment->debugID(), (*startPtr)->t(), (*endPtr )->t(),
1153 (*startPtr)->t() < (*endPtr)->t() ? '-' : '+', -1, -1, -1, 1);
1154 #endif
1155 }
1156 return leftSegment;
1157 }
1158
1159 SkOpGlobalState* SkOpSegment::globalState() const { 801 SkOpGlobalState* SkOpSegment::globalState() const {
1160 return contour()->globalState(); 802 return contour()->globalState();
1161 } 803 }
1162 804
1163 void SkOpSegment::init(SkPoint pts[], SkScalar weight, SkOpContour* contour, SkP ath::Verb verb) { 805 void SkOpSegment::init(SkPoint pts[], SkScalar weight, SkOpContour* contour, SkP ath::Verb verb) {
1164 fContour = contour; 806 fContour = contour;
1165 fNext = NULL; 807 fNext = NULL;
1166 fPts = pts; 808 fPts = pts;
1167 fWeight = weight; 809 fWeight = weight;
1168 fVerb = verb; 810 fVerb = verb;
1169 fCubicType = SkDCubic::kUnsplit_SkDCubicType; 811 fCubicType = SkDCubic::kUnsplit_SkDCubicType;
1170 fCount = 0; 812 fCount = 0;
1171 fDoneCount = 0; 813 fDoneCount = 0;
814 fTopsFound = false;
1172 fVisited = false; 815 fVisited = false;
1173 SkOpSpan* zeroSpan = &fHead; 816 SkOpSpan* zeroSpan = &fHead;
1174 zeroSpan->init(this, NULL, 0, fPts[0]); 817 zeroSpan->init(this, NULL, 0, fPts[0]);
1175 SkOpSpanBase* oneSpan = &fTail; 818 SkOpSpanBase* oneSpan = &fTail;
1176 zeroSpan->setNext(oneSpan); 819 zeroSpan->setNext(oneSpan);
1177 oneSpan->initBase(this, zeroSpan, 1, fPts[SkPathOpsVerbToPoints(fVerb)]); 820 oneSpan->initBase(this, zeroSpan, 1, fPts[SkPathOpsVerbToPoints(fVerb)]);
1178 SkDEBUGCODE(fID = globalState()->nextSegmentID()); 821 SkDEBUGCODE(fID = globalState()->nextSegmentID());
1179 } 822 }
1180 823
1181 void SkOpSegment::initWinding(SkOpSpanBase* start, SkOpSpanBase* end,
1182 SkOpAngle::IncludeType angleIncludeType) {
1183 int local = SkOpSegment::SpanSign(start, end);
1184 SkDEBUGCODE(bool success);
1185 if (angleIncludeType == SkOpAngle::kBinarySingle) {
1186 int oppLocal = SkOpSegment::OppSign(start, end);
1187 SkDEBUGCODE(success =) markAndChaseWinding(start, end, local, oppLocal, NULL);
1188 // OPTIMIZATION: the reverse mark and chase could skip the first marking
1189 SkDEBUGCODE(success |=) markAndChaseWinding(end, start, local, oppLocal, NULL);
1190 } else {
1191 SkDEBUGCODE(success =) markAndChaseWinding(start, end, local, NULL);
1192 // OPTIMIZATION: the reverse mark and chase could skip the first marking
1193 SkDEBUGCODE(success |=) markAndChaseWinding(end, start, local, NULL);
1194 }
1195 SkASSERT(success);
1196 }
1197
1198 /*
1199 when we start with a vertical intersect, we try to use the dx to determine if th e edge is to
1200 the left or the right of vertical. This determines if we need to add the span's
1201 sign or not. However, this isn't enough.
1202 If the supplied sign (winding) is zero, then we didn't hit another vertical span , so dx is needed.
1203 If there was a winding, then it may or may not need adjusting. If the span the w inding was borrowed
1204 from has the same x direction as this span, the winding should change. If the dx is opposite, then
1205 the same winding is shared by both.
1206 */
1207 bool SkOpSegment::initWinding(SkOpSpanBase* start, SkOpSpanBase* end, double tHi t,
1208 int winding, SkScalar hitDx, int oppWind, SkScalar hitOppDx) {
1209 SkASSERT(this == start->segment());
1210 SkASSERT(hitDx || !winding);
1211 SkScalar dx = (*CurveSlopeAtT[fVerb])(fPts, fWeight, tHit).fX;
1212 // SkASSERT(dx);
1213 int windVal = start->starter(end)->windValue();
1214 #if DEBUG_WINDING_AT_T
1215 SkDebugf("%s id=%d oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, d ebugID(), winding,
1216 hitDx ? hitDx > 0 ? '+' : '-' : '0', dx > 0 ? '+' : '-', windVal);
1217 #endif
1218 int sideWind = winding + (dx < 0 ? windVal : -windVal);
1219 if (abs(winding) < abs(sideWind)) {
1220 winding = sideWind;
1221 }
1222 SkDEBUGCODE(int oppLocal = SkOpSegment::OppSign(start, end));
1223 SkASSERT(hitOppDx || !oppWind || !oppLocal);
1224 int oppWindVal = start->starter(end)->oppValue();
1225 if (!oppWind) {
1226 oppWind = dx < 0 ? oppWindVal : -oppWindVal;
1227 } else if (hitOppDx * dx >= 0) {
1228 int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal);
1229 if (abs(oppWind) < abs(oppSideWind)) {
1230 oppWind = oppSideWind;
1231 }
1232 }
1233 #if DEBUG_WINDING_AT_T
1234 SkDebugf(" winding=%d oppWind=%d\n", winding, oppWind);
1235 #endif
1236 // if this fails to mark (because the edges are too small) inform caller to try again
1237 bool success = markAndChaseWinding(start, end, winding, oppWind, NULL);
1238 // OPTIMIZATION: the reverse mark and chase could skip the first marking
1239 success |= markAndChaseWinding(end, start, winding, oppWind, NULL);
1240 return success;
1241 }
1242
1243 bool SkOpSegment::isClose(double t, const SkOpSegment* opp) const { 824 bool SkOpSegment::isClose(double t, const SkOpSegment* opp) const {
1244 SkDPoint cPt = this->dPtAtT(t); 825 SkDPoint cPt = this->dPtAtT(t);
1245 SkDVector dxdy = (*CurveDSlopeAtT[this->verb()])(this->pts(), this->weight() , t); 826 SkDVector dxdy = (*CurveDSlopeAtT[this->verb()])(this->pts(), this->weight() , t);
1246 SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }}; 827 SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }};
1247 SkIntersections i; 828 SkIntersections i;
1248 (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(), perp, &i); 829 (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(), perp, &i);
1249 int used = i.used(); 830 int used = i.used();
1250 for (int index = 0; index < used; ++index) { 831 for (int index = 0; index < used; ++index) {
1251 if (cPt.roughlyEqual(i.pt(index))) { 832 if (cPt.roughlyEqual(i.pt(index))) {
1252 return true; 833 return true;
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
1299 bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end, 880 bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end,
1300 int winding, int oppWinding, SkOpSpanBase** lastPtr) { 881 int winding, int oppWinding, SkOpSpanBase** lastPtr) {
1301 SkOpSpan* spanStart = start->starter(end); 882 SkOpSpan* spanStart = start->starter(end);
1302 int step = start->step(end); 883 int step = start->step(end);
1303 bool success = markWinding(spanStart, winding, oppWinding); 884 bool success = markWinding(spanStart, winding, oppWinding);
1304 SkOpSpanBase* last = NULL; 885 SkOpSpanBase* last = NULL;
1305 SkOpSegment* other = this; 886 SkOpSegment* other = this;
1306 while ((other = other->nextChase(&start, &step, &spanStart, &last))) { 887 while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
1307 if (spanStart->windSum() != SK_MinS32) { 888 if (spanStart->windSum() != SK_MinS32) {
1308 if (this->operand() == other->operand()) { 889 if (this->operand() == other->operand()) {
1309 SkASSERT(spanStart->windSum() == winding); 890 if (spanStart->windSum() != winding || spanStart->oppSum() != op pWinding) {
1310 if (spanStart->oppSum() != oppWinding) {
1311 this->globalState()->setWindingFailed(); 891 this->globalState()->setWindingFailed();
1312 return false; 892 return false;
1313 } 893 }
1314 } else { 894 } else {
1315 SkASSERT(spanStart->windSum() == oppWinding); 895 SkASSERT(spanStart->windSum() == oppWinding);
1316 SkASSERT(spanStart->oppSum() == winding); 896 SkASSERT(spanStart->oppSum() == winding);
1317 } 897 }
1318 SkASSERT(!last); 898 SkASSERT(!last);
1319 break; 899 break;
1320 } 900 }
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
1431 return !this->ptsDisjoint(base->fT, base->fPt, testT, testPt); 1011 return !this->ptsDisjoint(base->fT, base->fPt, testT, testPt);
1432 } 1012 }
1433 1013
1434 static SkOpSegment* set_last(SkOpSpanBase** last, SkOpSpanBase* endSpan) { 1014 static SkOpSegment* set_last(SkOpSpanBase** last, SkOpSpanBase* endSpan) {
1435 if (last) { 1015 if (last) {
1436 *last = endSpan; 1016 *last = endSpan;
1437 } 1017 }
1438 return NULL; 1018 return NULL;
1439 } 1019 }
1440 1020
1441 bool SkOpSegment::monotonicInY(const SkOpSpanBase* start, const SkOpSpanBase* en d) const {
1442 SkASSERT(fVerb != SkPath::kLine_Verb);
1443 if (fVerb == SkPath::kQuad_Verb) {
1444 SkDQuad dst = SkDQuad::SubDivide(fPts, start->t(), end->t());
1445 return dst.monotonicInY();
1446 }
1447 if (fVerb == SkPath::kConic_Verb) {
1448 SkDConic dst = SkDConic::SubDivide(fPts, fWeight, start->t(), end->t());
1449 return dst.monotonicInY();
1450 }
1451 SkASSERT(fVerb == SkPath::kCubic_Verb);
1452 SkDCubic dst = SkDCubic::SubDivide(fPts, start->t(), end->t());
1453 if (dst.monotonicInY()) {
1454 return true;
1455 }
1456 SkDCubic whole;
1457 whole.set(fPts);
1458 return whole.monotonicInY();
1459 }
1460
1461 bool SkOpSegment::NextCandidate(SkOpSpanBase* span, SkOpSpanBase** start,
1462 SkOpSpanBase** end) {
1463 while (span->final() || span->upCast()->done()) {
1464 if (span->final()) {
1465 return false;
1466 }
1467 span = span->upCast()->next();
1468 }
1469 *start = span;
1470 *end = span->upCast()->next();
1471 return true;
1472 }
1473
1474 SkOpSegment* SkOpSegment::nextChase(SkOpSpanBase** startPtr, int* stepPtr, SkOpS pan** minPtr, 1021 SkOpSegment* SkOpSegment::nextChase(SkOpSpanBase** startPtr, int* stepPtr, SkOpS pan** minPtr,
1475 SkOpSpanBase** last) const { 1022 SkOpSpanBase** last) const {
1476 SkOpSpanBase* origStart = *startPtr; 1023 SkOpSpanBase* origStart = *startPtr;
1477 int step = *stepPtr; 1024 int step = *stepPtr;
1478 SkOpSpanBase* endSpan = step > 0 ? origStart->upCast()->next() : origStart-> prev(); 1025 SkOpSpanBase* endSpan = step > 0 ? origStart->upCast()->next() : origStart-> prev();
1479 SkASSERT(endSpan); 1026 SkASSERT(endSpan);
1480 SkOpAngle* angle = step > 0 ? endSpan->fromAngle() : endSpan->upCast()->toAn gle(); 1027 SkOpAngle* angle = step > 0 ? endSpan->fromAngle() : endSpan->upCast()->toAn gle();
1481 SkOpSpanBase* foundSpan; 1028 SkOpSpanBase* foundSpan;
1482 SkOpSpanBase* otherEnd; 1029 SkOpSpanBase* otherEnd;
1483 SkOpSegment* other; 1030 SkOpSegment* other;
1484 if (angle == NULL) { 1031 if (angle == NULL) {
1485 if (endSpan->t() != 0 && endSpan->t() != 1) { 1032 if (endSpan->t() != 0 && endSpan->t() != 1) {
1486 return NULL; 1033 return NULL;
1487 } 1034 }
1488 SkOpPtT* otherPtT = endSpan->ptT()->next(); 1035 SkOpPtT* otherPtT = endSpan->ptT()->next();
1489 other = otherPtT->segment(); 1036 other = otherPtT->segment();
1490 foundSpan = otherPtT->span(); 1037 foundSpan = otherPtT->span();
1491 otherEnd = step > 0 ? foundSpan->upCast()->next() : foundSpan->prev(); 1038 otherEnd = step > 0 ? foundSpan->upCast()->next() : foundSpan->prev();
1492 } else { 1039 } else {
1493 int loopCount = angle->loopCount(); 1040 int loopCount = angle->loopCount();
1494 if (loopCount > 2) { 1041 if (loopCount > 2) {
1495 return set_last(last, endSpan); 1042 return set_last(last, endSpan);
1496 } 1043 }
1497 const SkOpAngle* next = angle->next(); 1044 const SkOpAngle* next = angle->next();
1498 if (NULL == next) { 1045 if (NULL == next) {
1499 return NULL; 1046 return NULL;
1500 } 1047 }
1501 #if DEBUG_WINDING 1048 #if DEBUG_WINDING
1502 if (angle->sign() != next->sign() && !angle->segment()->contour()->isXor () 1049 if (angle->debugSign() != next->debugSign() && !angle->segment()->contou r()->isXor()
1503 && !next->segment()->contour()->isXor()) { 1050 && !next->segment()->contour()->isXor()) {
1504 SkDebugf("%s mismatched signs\n", __FUNCTION__); 1051 SkDebugf("%s mismatched signs\n", __FUNCTION__);
1505 } 1052 }
1506 #endif 1053 #endif
1507 other = next->segment(); 1054 other = next->segment();
1508 foundSpan = endSpan = next->start(); 1055 foundSpan = endSpan = next->start();
1509 otherEnd = next->end(); 1056 otherEnd = next->end();
1510 } 1057 }
1511 int foundStep = foundSpan->step(otherEnd); 1058 int foundStep = foundSpan->step(otherEnd);
1512 if (*stepPtr != foundStep) { 1059 if (*stepPtr != foundStep) {
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
1551 if (this->verb() != SkPath::kLine_Verb) { 1098 if (this->verb() != SkPath::kLine_Verb) {
1552 return; 1099 return;
1553 } 1100 }
1554 SkOpSpan* prior = NULL; 1101 SkOpSpan* prior = NULL;
1555 SkOpSpan* span = &fHead; 1102 SkOpSpan* span = &fHead;
1556 do { 1103 do {
1557 SkOpPtT* ptT = span->ptT(), * spanStopPtT = ptT; 1104 SkOpPtT* ptT = span->ptT(), * spanStopPtT = ptT;
1558 SkASSERT(ptT->span() == span); 1105 SkASSERT(ptT->span() == span);
1559 while ((ptT = ptT->next()) != spanStopPtT) { 1106 while ((ptT = ptT->next()) != spanStopPtT) {
1560 SkOpSegment* opp = ptT->span()->segment(); 1107 SkOpSegment* opp = ptT->span()->segment();
1561 if (opp->setVisited()) { 1108 if (!opp->setVisited()) {
1562 continue; 1109 continue;
1563 } 1110 }
1564 if (opp->verb() == SkPath::kLine_Verb) { 1111 if (opp->verb() == SkPath::kLine_Verb) {
1565 continue; 1112 continue;
1566 } 1113 }
1567 if (span->containsCoincidence(opp)) { // FIXME: this assumes that if the opposite 1114 if (span->containsCoincidence(opp)) { // FIXME: this assumes that if the opposite
1568 // segment is coincident then no more coincidence 1115 // segment is coincident then no more coincidence
1569 // needs to be detected. This may not be true. 1116 // needs to be detected. This may not be true.
1570 continue; 1117 continue;
1571 } 1118 }
(...skipping 445 matching lines...) Expand 10 before | Expand all | Expand 10 after
2017 } else if (fVerb == SkPath::kConic_Verb) { 1564 } else if (fVerb == SkPath::kConic_Verb) {
2018 edge->fConic[1] = SkDConic::SubDivide(fPts, fWeight, edge->fQuad[0], edg e->fQuad[2], 1565 edge->fConic[1] = SkDConic::SubDivide(fPts, fWeight, edge->fQuad[0], edg e->fQuad[2],
2019 startT, endT, &edge->fConic.fWeight); 1566 startT, endT, &edge->fConic.fWeight);
2020 } else { 1567 } else {
2021 SkASSERT(fVerb == SkPath::kCubic_Verb); 1568 SkASSERT(fVerb == SkPath::kCubic_Verb);
2022 SkDCubic::SubDivide(fPts, edge->fCubic[0], edge->fCubic[3], startT, endT , &edge->fCubic[1]); 1569 SkDCubic::SubDivide(fPts, edge->fCubic[0], edge->fCubic[3], startT, endT , &edge->fCubic[1]);
2023 } 1570 }
2024 return true; 1571 return true;
2025 } 1572 }
2026 1573
2027 void SkOpSegment::subDivideBounds(const SkOpSpanBase* start, const SkOpSpanBase* end,
2028 SkPathOpsBounds* bounds) const {
2029 SkDCurve edge;
2030 subDivide(start, end, &edge);
2031 (edge.*SetBounds[fVerb])(fPts, fWeight, start->t(), end->t(), bounds);
2032 }
2033
2034 SkDPoint SkOpSegment::top(const SkOpSpanBase* start, const SkOpSpanBase* end, do uble* topT) const {
2035 SkDCurve edge;
2036 subDivide(start, end, &edge);
2037 return (edge.*Top[fVerb])(fPts, fWeight, start->t(), end->t(), topT);
2038 }
2039
2040 void SkOpSegment::undoneSpan(SkOpSpanBase** start, SkOpSpanBase** end) { 1574 void SkOpSegment::undoneSpan(SkOpSpanBase** start, SkOpSpanBase** end) {
2041 SkOpSpan* span = this->head(); 1575 SkOpSpan* span = this->head();
2042 do { 1576 do {
2043 if (!span->done()) { 1577 if (!span->done()) {
2044 break; 1578 break;
2045 } 1579 }
2046 } while ((span = span->next()->upCastable())); 1580 } while ((span = span->next()->upCastable()));
2047 SkASSERT(span); 1581 SkASSERT(span);
2048 *start = span; 1582 *start = span;
2049 *end = span->next(); 1583 *end = span->next();
(...skipping 15 matching lines...) Expand all
2065 const SkOpSpanBase* endSpan = angle->end(); 1599 const SkOpSpanBase* endSpan = angle->end();
2066 return updateOppWinding(endSpan, startSpan); 1600 return updateOppWinding(endSpan, startSpan);
2067 } 1601 }
2068 1602
2069 int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const { 1603 int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const {
2070 const SkOpSpanBase* startSpan = angle->start(); 1604 const SkOpSpanBase* startSpan = angle->start();
2071 const SkOpSpanBase* endSpan = angle->end(); 1605 const SkOpSpanBase* endSpan = angle->end();
2072 return updateOppWinding(startSpan, endSpan); 1606 return updateOppWinding(startSpan, endSpan);
2073 } 1607 }
2074 1608
2075 int SkOpSegment::updateWinding(const SkOpSpanBase* start, const SkOpSpanBase* en d) const { 1609 int SkOpSegment::updateWinding(SkOpSpanBase* start, SkOpSpanBase* end) {
2076 const SkOpSpan* lesser = start->starter(end); 1610 SkOpSpan* lesser = start->starter(end);
2077 int winding = lesser->windSum(); 1611 int winding = lesser->windSum();
2078 if (winding == SK_MinS32) { 1612 if (winding == SK_MinS32) {
1613 SkOpGlobalState* globals = this->globalState();
1614 SkOpContour* contourHead = globals->contourHead();
1615 int windTry = 0;
1616 while (!lesser->sortableTop(contourHead) && ++windTry < SkOpGlobalState: :kMaxWindingTries) {
1617 ;
1618 }
1619 winding = lesser->windSum();
1620 }
1621 if (winding == SK_MinS32) {
2079 return winding; 1622 return winding;
2080 } 1623 }
2081 int spanWinding = SkOpSegment::SpanSign(start, end); 1624 int spanWinding = SkOpSegment::SpanSign(start, end);
2082 if (winding && UseInnerWinding(winding - spanWinding, winding) 1625 if (winding && UseInnerWinding(winding - spanWinding, winding)
2083 && winding != SK_MaxS32) { 1626 && winding != SK_MaxS32) {
2084 winding -= spanWinding; 1627 winding -= spanWinding;
2085 } 1628 }
2086 return winding; 1629 return winding;
2087 } 1630 }
2088 1631
2089 int SkOpSegment::updateWinding(const SkOpAngle* angle) const { 1632 int SkOpSegment::updateWinding(SkOpAngle* angle) {
2090 const SkOpSpanBase* startSpan = angle->start(); 1633 SkOpSpanBase* startSpan = angle->start();
2091 const SkOpSpanBase* endSpan = angle->end(); 1634 SkOpSpanBase* endSpan = angle->end();
2092 return updateWinding(endSpan, startSpan); 1635 return updateWinding(endSpan, startSpan);
2093 } 1636 }
2094 1637
2095 int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) const { 1638 int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) {
2096 const SkOpSpanBase* startSpan = angle->start(); 1639 SkOpSpanBase* startSpan = angle->start();
2097 const SkOpSpanBase* endSpan = angle->end(); 1640 SkOpSpanBase* endSpan = angle->end();
2098 return updateWinding(startSpan, endSpan); 1641 return updateWinding(startSpan, endSpan);
2099 } 1642 }
2100 1643
2101 // OPTIMIZATION: does the following also work, and is it any faster? 1644 // OPTIMIZATION: does the following also work, and is it any faster?
2102 // return outerWinding * innerWinding > 0 1645 // return outerWinding * innerWinding > 0
2103 // || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0))) 1646 // || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
2104 bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) { 1647 bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) {
2105 SkASSERT(outerWinding != SK_MaxS32); 1648 SkASSERT(outerWinding != SK_MaxS32);
2106 SkASSERT(innerWinding != SK_MaxS32); 1649 SkASSERT(innerWinding != SK_MaxS32);
2107 int absOut = abs(outerWinding); 1650 int absOut = abs(outerWinding);
2108 int absIn = abs(innerWinding); 1651 int absIn = abs(innerWinding);
2109 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn; 1652 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
2110 return result; 1653 return result;
2111 } 1654 }
2112 1655
2113 int SkOpSegment::windingAtT(double tHit, const SkOpSpan* span, bool crossOpp,
2114 SkScalar* dx) const {
2115 if (approximately_zero(tHit - span->t())) { // if we hit the end of a span, disregard
2116 return SK_MinS32;
2117 }
2118 int winding = crossOpp ? span->oppSum() : span->windSum();
2119 SkASSERT(winding != SK_MinS32);
2120 int windVal = crossOpp ? span->oppValue() : span->windValue();
2121 #if DEBUG_WINDING_AT_T
2122 SkDebugf("%s id=%d opp=%d tHit=%1.9g t=%1.9g oldWinding=%d windValue=%d", __ FUNCTION__,
2123 debugID(), crossOpp, tHit, span->t(), winding, windVal);
2124 #endif
2125 // see if a + change in T results in a +/- change in X (compute x'(T))
2126 *dx = (*CurveSlopeAtT[fVerb])(fPts, fWeight, tHit).fX;
2127 if (fVerb > SkPath::kLine_Verb && approximately_zero(*dx)) {
2128 *dx = fPts[2].fX - fPts[1].fX - *dx;
2129 }
2130 if (*dx == 0) {
2131 #if DEBUG_WINDING_AT_T
2132 SkDebugf(" dx=0 winding=SK_MinS32\n");
2133 #endif
2134 return SK_MinS32;
2135 }
2136 if (windVal < 0) { // reverse sign if opp contour traveled in reverse
2137 *dx = -*dx;
2138 }
2139 if (winding * *dx > 0) { // if same signs, result is negative
2140 winding += *dx > 0 ? -windVal : windVal;
2141 }
2142 #if DEBUG_WINDING_AT_T
2143 SkDebugf(" dx=%c winding=%d\n", *dx > 0 ? '+' : '-', winding);
2144 #endif
2145 return winding;
2146 }
2147
2148 int SkOpSegment::windSum(const SkOpAngle* angle) const { 1656 int SkOpSegment::windSum(const SkOpAngle* angle) const {
2149 const SkOpSpan* minSpan = angle->start()->starter(angle->end()); 1657 const SkOpSpan* minSpan = angle->start()->starter(angle->end());
2150 return minSpan->windSum(); 1658 return minSpan->windSum();
2151 } 1659 }
OLDNEW
« no previous file with comments | « src/pathops/SkOpSegment.h ('k') | src/pathops/SkOpSpan.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698