2 * Copyright 2012 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
7 #include "SkIntersections.h"
8 #include "SkOpContour.h"
9 #include "SkOpSegment.h"
10 #include "SkPathWriter.h"
13 #define F (false) // discard the edge
14 #define T (true) // keep the edge
16 static const bool gUnaryActiveEdge[2][2] = {
22 static const bool gActiveEdge[kXOR_PathOp + 1][2][2][2][2] = {
24 // miTo=0 miTo=1 miTo=0 miTo=1
25 // suFrom=0 1 suFrom=0 1 suFrom=0 1 suFrom=0 1
26 // suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1
27 {{{{F, F}, {F, F}}, {{T, F}, {T, F}}}, {{{T, T}, {F, F}}, {{F, T}, {T, F}}}}, // mi - su
28 {{{{F, F}, {F, F}}, {{F, T}, {F, T}}}, {{{F, F}, {T, T}}, {{F, T}, {T, F}}}}, // mi & su
29 {{{{F, T}, {T, F}}, {{T, T}, {F, F}}}, {{{T, F}, {T, F}}, {{F, F}, {F, F}}}}, // mi | su
30 {{{{F, T}, {T, F}}, {{T, F}, {F, T}}}, {{{T, F}, {F, T}}, {{F, T}, {T, F}}}}, // mi ^ su
37 kOutsideTrackedTCount = 16, // FIXME: determine what this should be
38 kMissingSpanCount = 4, // FIXME: determine what this should be
41 const SkOpAngle* SkOpSegment::activeAngle(int index, int* start, int* end, bool* done,
42 bool* sortable) const {
43 if (const SkOpAngle* result = activeAngleInner(index, start, end, done, sortable)) {
46 double referenceT = fTs[index].fT;
49 && (precisely_negative(referenceT - fTs[lesser].fT) || fTs[lesser].fTiny)) {
50 if (const SkOpAngle* result = activeAngleOther(lesser, start, end, done, sortable)) {
55 if (const SkOpAngle* result = activeAngleOther(index, start, end, done, sortable)) {
58 if (++index == fTs.count()) {
61 if (fTs[index - 1].fTiny) {
62 referenceT = fTs[index].fT;
65 } while (precisely_negative(fTs[index].fT - referenceT));
69 const SkOpAngle* SkOpSegment::activeAngleInner(int index, int* start, int* end, bool* done,
70 bool* sortable) const {
71 int next = nextExactSpan(index, 1);
73 const SkOpSpan& upSpan = fTs[index];
74 if (upSpan.fWindValue || upSpan.fOppValue) {
80 if (upSpan.fWindSum != SK_MinS32) {
81 return spanToAngle(index, next);
86 SkASSERT(upSpan.fDone);
89 int prev = nextExactSpan(index, -1);
90 // edge leading into junction
92 const SkOpSpan& downSpan = fTs[prev];
93 if (downSpan.fWindValue || downSpan.fOppValue) {
98 if (!downSpan.fDone) {
99 if (downSpan.fWindSum != SK_MinS32) {
100 return spanToAngle(index, prev);
105 SkASSERT(downSpan.fDone);
111 const SkOpAngle* SkOpSegment::activeAngleOther(int index, int* start, int* end, bool* done,
112 bool* sortable) const {
113 const SkOpSpan* span = &fTs[index];
114 SkOpSegment* other = span->fOther;
115 int oIndex = span->fOtherIndex;
116 return other->activeAngleInner(oIndex, start, end, done, sortable);
119 SkPoint SkOpSegment::activeLeftTop(int* firstT) const {
121 SkPoint topPt = {SK_ScalarMax, SK_ScalarMax};
122 int count = fTs.count();
123 // see if either end is not done since we want smaller Y of the pair
124 bool lastDone = true;
126 for (int index = 0; index < count; ++index) {
127 const SkOpSpan& span = fTs[index];
128 if (span.fDone && lastDone) {
131 if (approximately_negative(span.fT - lastT)) {
135 const SkPoint& xy = xyAtT(&span);
136 if (topPt.fY > xy.fY || (topPt.fY == xy.fY && topPt.fX > xy.fX)) {
142 if (fVerb != SkPath::kLine_Verb && !lastDone) {
143 SkPoint curveTop = (*CurveTop[SkPathOpsVerbToPoints(fVerb)])(fPts, lastT, span.fT);
144 if (topPt.fY > curveTop.fY || (topPt.fY == curveTop.fY
145 && topPt.fX > curveTop.fX)) {
155 lastDone = span.fDone;
160 bool SkOpSegment::activeOp(int index, int endIndex, int xorMiMask, int xorSuMask, SkPathOp op) {
161 int sumMiWinding = updateWinding(endIndex, index);
162 int sumSuWinding = updateOppWinding(endIndex, index);
164 SkTSwap<int>(sumMiWinding, sumSuWinding);
166 return activeOp(xorMiMask, xorSuMask, index, endIndex, op, &sumMiWinding, &sumSuWinding);
169 bool SkOpSegment::activeOp(int xorMiMask, int xorSuMask, int index, int endIndex, SkPathOp op,
170 int* sumMiWinding, int* sumSuWinding) {
171 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
172 setUpWindings(index, endIndex, sumMiWinding, sumSuWinding,
173 &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
179 miFrom = (oppMaxWinding & xorMiMask) != 0;
180 miTo = (oppSumWinding & xorMiMask) != 0;
181 suFrom = (maxWinding & xorSuMask) != 0;
182 suTo = (sumWinding & xorSuMask) != 0;
184 miFrom = (maxWinding & xorMiMask) != 0;
185 miTo = (sumWinding & xorMiMask) != 0;
186 suFrom = (oppMaxWinding & xorSuMask) != 0;
187 suTo = (oppSumWinding & xorSuMask) != 0;
189 bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo];
191 SkDebugf("%s id=%d t=%1.9g tEnd=%1.9g op=%s miFrom=%d miTo=%d suFrom=%d suTo=%d result=%d\n",
192 __FUNCTION__, debugID(), span(index).fT, span(endIndex).fT,
193 SkPathOpsDebug::kPathOpStr[op], miFrom, miTo, suFrom, suTo, result);
198 bool SkOpSegment::activeWinding(int index, int endIndex) {
199 int sumWinding = updateWinding(endIndex, index);
200 return activeWinding(index, endIndex, &sumWinding);
203 bool SkOpSegment::activeWinding(int index, int endIndex, int* sumWinding) {
205 setUpWinding(index, endIndex, &maxWinding, sumWinding);
206 bool from = maxWinding != 0;
207 bool to = *sumWinding != 0;
208 bool result = gUnaryActiveEdge[from][to];
212 void SkOpSegment::addCancelOutsides(const SkPoint& startPt, const SkPoint& endPt,
213 SkOpSegment* other) {
215 int tCount = fTs.count();
217 int oCount = other->fTs.count();
220 } while (startPt != fTs[tIndex].fPt && tIndex < tCount);
221 int tIndexStart = tIndex;
224 } while (endPt != other->fTs[oIndex].fPt && oIndex < oCount);
225 int oIndexStart = oIndex;
226 const SkPoint* nextPt;
228 nextPt = &fTs[++tIndex].fPt;
229 SkASSERT(fTs[tIndex].fT < 1 || startPt != *nextPt);
230 } while (startPt == *nextPt);
231 double nextT = fTs[tIndex].fT;
232 const SkPoint* oNextPt;
234 oNextPt = &other->fTs[++oIndex].fPt;
235 SkASSERT(other->fTs[oIndex].fT < 1 || endPt != *oNextPt);
236 } while (endPt == *oNextPt);
237 double oNextT = other->fTs[oIndex].fT;
238 // at this point, spans before and after are at:
239 // fTs[tIndexStart - 1], fTs[tIndexStart], fTs[tIndex]
240 // if tIndexStart == 0, no prior span
241 // if nextT == 1, no following span
243 // advance the span with zero winding
244 // if the following span exists (not past the end, non-zero winding)
245 // connect the two edges
246 if (!fTs[tIndexStart].fWindValue) {
247 if (tIndexStart > 0 && fTs[tIndexStart - 1].fWindValue) {
249 SkDebugf("%s 1 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
250 __FUNCTION__, fID, other->fID, tIndexStart - 1,
251 fTs[tIndexStart].fT, xyAtT(tIndexStart).fX,
252 xyAtT(tIndexStart).fY);
254 SkPoint copy = fTs[tIndexStart].fPt; // add t pair may move the point array
255 addTPair(fTs[tIndexStart].fT, other, other->fTs[oIndex].fT, false, copy);
257 if (nextT < 1 && fTs[tIndex].fWindValue) {
259 SkDebugf("%s 2 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
260 __FUNCTION__, fID, other->fID, tIndex,
261 fTs[tIndex].fT, xyAtT(tIndex).fX,
264 SkPoint copy = fTs[tIndex].fPt; // add t pair may move the point array
265 addTPair(fTs[tIndex].fT, other, other->fTs[oIndexStart].fT, false, copy);
268 SkASSERT(!other->fTs[oIndexStart].fWindValue);
269 if (oIndexStart > 0 && other->fTs[oIndexStart - 1].fWindValue) {
271 SkDebugf("%s 3 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
272 __FUNCTION__, fID, other->fID, oIndexStart - 1,
273 other->fTs[oIndexStart].fT, other->xyAtT(oIndexStart).fX,
274 other->xyAtT(oIndexStart).fY);
275 other->debugAddTPair(other->fTs[oIndexStart].fT, *this, fTs[tIndex].fT);
278 if (oNextT < 1 && other->fTs[oIndex].fWindValue) {
280 SkDebugf("%s 4 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
281 __FUNCTION__, fID, other->fID, oIndex,
282 other->fTs[oIndex].fT, other->xyAtT(oIndex).fX,
283 other->xyAtT(oIndex).fY);
284 other->debugAddTPair(other->fTs[oIndex].fT, *this, fTs[tIndexStart].fT);
290 void SkOpSegment::addCoinOutsides(const SkPoint& startPt, const SkPoint& endPt,
291 SkOpSegment* other) {
292 // walk this to startPt
293 // walk other to startPt
294 // if either is > 0, add a pointer to the other, copying adjacent winding
299 } while (startPt != fTs[tIndex].fPt);
300 int ttIndex = tIndex;
301 bool checkOtherTMatch = false;
303 const SkOpSpan& span = fTs[ttIndex];
304 if (startPt != span.fPt) {
307 if (span.fOther == other && span.fPt == startPt) {
308 checkOtherTMatch = true;
311 } while (++ttIndex < count());
314 } while (startPt != other->fTs[oIndex].fPt);
315 bool skipAdd = false;
316 if (checkOtherTMatch) {
317 int ooIndex = oIndex;
319 const SkOpSpan& oSpan = other->fTs[ooIndex];
320 if (startPt != oSpan.fPt) {
323 if (oSpan.fT == fTs[ttIndex].fOtherT) {
327 } while (++ooIndex < other->count());
329 if ((tIndex > 0 || oIndex > 0 || fOperand != other->fOperand) && !skipAdd) {
330 addTPair(fTs[tIndex].fT, other, other->fTs[oIndex].fT, false, startPt);
332 SkPoint nextPt = startPt;
334 const SkPoint* workPt;
336 workPt = &fTs[++tIndex].fPt;
337 } while (nextPt == *workPt);
338 const SkPoint* oWorkPt;
340 oWorkPt = &other->fTs[++oIndex].fPt;
341 } while (nextPt == *oWorkPt);
343 double tStart = fTs[tIndex].fT;
344 double oStart = other->fTs[oIndex].fT;
345 if (tStart == 1 && oStart == 1 && fOperand == other->fOperand) {
348 if (*workPt == *oWorkPt) {
349 addTPair(tStart, other, oStart, false, nextPt);
351 } while (endPt != nextPt);
354 void SkOpSegment::addCubic(const SkPoint pts[4], bool operand, bool evenOdd) {
355 init(pts, SkPath::kCubic_Verb, operand, evenOdd);
356 fBounds.setCubicBounds(pts);
359 void SkOpSegment::addCurveTo(int start, int end, SkPathWriter* path, bool active) const {
362 int lastT = fTs.count() - 1;
363 if (lastT < 0 || (start == 0 && end == lastT) || (start == lastT && end == 0)) {
366 // OPTIMIZE? if not active, skip remainder and return xyAtT(end)
367 subDivide(start, end, edge);
371 bool reverse = ePtr == fPts && start != 0;
373 path->deferredMoveLine(ePtr[SkPathOpsVerbToPoints(fVerb)]);
375 case SkPath::kLine_Verb:
376 path->deferredLine(ePtr[0]);
378 case SkPath::kQuad_Verb:
379 path->quadTo(ePtr[1], ePtr[0]);
381 case SkPath::kCubic_Verb:
382 path->cubicTo(ePtr[2], ePtr[1], ePtr[0]);
389 path->deferredMoveLine(ePtr[0]);
391 case SkPath::kLine_Verb:
392 path->deferredLine(ePtr[1]);
394 case SkPath::kQuad_Verb:
395 path->quadTo(ePtr[1], ePtr[2]);
397 case SkPath::kCubic_Verb:
398 path->cubicTo(ePtr[1], ePtr[2], ePtr[3]);
405 // return ePtr[SkPathOpsVerbToPoints(fVerb)];
408 void SkOpSegment::addEndSpan(int endIndex) {
409 SkASSERT(span(endIndex).fT == 1 || (span(endIndex).fTiny
410 // && approximately_greater_than_one(span(endIndex).fT)
412 int spanCount = fTs.count();
413 int startIndex = endIndex - 1;
414 while (fTs[startIndex].fT == 1 || fTs[startIndex].fTiny) {
416 SkASSERT(startIndex > 0);
419 SkOpAngle& angle = fAngles.push_back();
420 angle.set(this, spanCount - 1, startIndex);
422 debugCheckPointsEqualish(endIndex, spanCount);
424 setFromAngle(endIndex, &angle);
427 void SkOpSegment::setFromAngle(int endIndex, SkOpAngle* angle) {
428 int spanCount = fTs.count();
430 fTs[endIndex].fFromAngle = angle;
431 } while (++endIndex < spanCount);
434 void SkOpSegment::addLine(const SkPoint pts[2], bool operand, bool evenOdd) {
435 init(pts, SkPath::kLine_Verb, operand, evenOdd);
439 // add 2 to edge or out of range values to get T extremes
440 void SkOpSegment::addOtherT(int index, double otherT, int otherIndex) {
441 SkOpSpan& span = fTs[index];
442 if (precisely_zero(otherT)) {
444 } else if (precisely_equal(otherT, 1)) {
447 span.fOtherT = otherT;
448 span.fOtherIndex = otherIndex;
451 void SkOpSegment::addQuad(const SkPoint pts[3], bool operand, bool evenOdd) {
452 init(pts, SkPath::kQuad_Verb, operand, evenOdd);
453 fBounds.setQuadBounds(pts);
456 SkOpAngle* SkOpSegment::addSingletonAngleDown(SkOpSegment** otherPtr, SkOpAngle** anglePtr) {
457 int spanIndex = count() - 1;
458 int startIndex = nextExactSpan(spanIndex, -1);
459 SkASSERT(startIndex >= 0);
460 SkOpAngle& angle = fAngles.push_back();
462 angle.set(this, spanIndex, startIndex);
463 setFromAngle(spanIndex, &angle);
465 int oStartIndex, oEndIndex;
467 const SkOpSpan& span = fTs[spanIndex];
468 SkASSERT(span.fT > 0);
470 oStartIndex = span.fOtherIndex;
471 oEndIndex = other->nextExactSpan(oStartIndex, 1);
472 if (oEndIndex > 0 && other->span(oStartIndex).fWindValue) {
475 oEndIndex = oStartIndex;
476 oStartIndex = other->nextExactSpan(oEndIndex, -1);
478 } while (oStartIndex < 0 || !other->span(oStartIndex).fWindSum);
479 SkOpAngle& oAngle = other->fAngles.push_back();
480 oAngle.set(other, oStartIndex, oEndIndex);
481 other->setToAngle(oEndIndex, &oAngle);
486 SkOpAngle* SkOpSegment::addSingletonAngleUp(SkOpSegment** otherPtr, SkOpAngle** anglePtr) {
487 int endIndex = nextExactSpan(0, 1);
488 SkASSERT(endIndex > 0);
489 SkOpAngle& angle = fAngles.push_back();
491 angle.set(this, 0, endIndex);
492 setToAngle(endIndex, &angle);
495 int oStartIndex, oEndIndex;
497 const SkOpSpan& span = fTs[spanIndex];
498 SkASSERT(span.fT < 1);
500 oEndIndex = span.fOtherIndex;
501 oStartIndex = other->nextExactSpan(oEndIndex, -1);
502 if (oStartIndex >= 0 && other->span(oStartIndex).fWindValue) {
505 oStartIndex = oEndIndex;
506 oEndIndex = other->nextExactSpan(oStartIndex, 1);
508 } while (oEndIndex < 0 || !other->span(oStartIndex).fWindValue);
509 SkOpAngle& oAngle = other->fAngles.push_back();
510 oAngle.set(other, oEndIndex, oStartIndex);
511 other->setFromAngle(oEndIndex, &oAngle);
516 SkOpAngle* SkOpSegment::addSingletonAngles(int step) {
518 SkOpAngle* angle, * otherAngle;
520 otherAngle = addSingletonAngleUp(&other, &angle);
522 otherAngle = addSingletonAngleDown(&other, &angle);
524 angle->insert(otherAngle);
528 void SkOpSegment::addStartSpan(int endIndex) {
530 SkOpAngle& angle = fAngles.push_back();
531 angle.set(this, index, endIndex);
533 debugCheckPointsEqualish(index, endIndex);
535 setToAngle(endIndex, &angle);
538 void SkOpSegment::setToAngle(int endIndex, SkOpAngle* angle) {
541 fTs[index].fToAngle = angle;
542 } while (++index < endIndex);
545 // Defer all coincident edge processing until
546 // after normal intersections have been computed
548 // no need to be tricky; insert in normal T order
549 // resolve overlapping ts when considering coincidence later
551 // add non-coincident intersection. Resulting edges are sorted in T.
552 int SkOpSegment::addT(SkOpSegment* other, const SkPoint& pt, double newT) {
553 SkASSERT(this != other || fVerb == SkPath::kCubic_Verb);
554 #if 0 // this needs an even rougher association to be useful
555 SkASSERT(SkDPoint::RoughlyEqual(ptAtT(newT), pt));
557 const SkPoint& firstPt = fPts[0];
558 const SkPoint& lastPt = fPts[SkPathOpsVerbToPoints(fVerb)];
559 SkASSERT(newT == 0 || !precisely_zero(newT));
560 SkASSERT(newT == 1 || !precisely_equal(newT, 1));
561 // FIXME: in the pathological case where there is a ton of intercepts,
564 int tCount = fTs.count();
565 for (int index = 0; index < tCount; ++index) {
566 // OPTIMIZATION: if there are three or more identical Ts, then
567 // the fourth and following could be further insertion-sorted so
568 // that all the edges are clockwise or counterclockwise.
569 // This could later limit segment tests to the two adjacent
570 // neighbors, although it doesn't help with determining which
571 // circular direction to go in.
572 const SkOpSpan& span = fTs[index];
573 if (newT < span.fT) {
577 if (newT == span.fT) {
578 if (pt == span.fPt) {
582 if ((pt == firstPt && newT == 0) || (span.fPt == lastPt && newT == 1)) {
589 if (insertedAt >= 0) {
590 span = fTs.insert(insertedAt);
597 span->fOther = other;
600 // cubics, for instance, may not be exact enough to satisfy this check (e.g., cubicOp69d)
601 SkASSERT(approximately_equal(xyAtT(newT).fX, pt.fX)
602 && approximately_equal(xyAtT(newT).fY, pt.fY));
604 span->fFromAngle = NULL;
605 span->fToAngle = NULL;
606 span->fWindSum = SK_MinS32;
607 span->fOppSum = SK_MinS32;
608 span->fWindValue = 1;
610 span->fChased = false;
611 span->fCoincident = false;
614 span->fMultiple = false;
615 span->fSmall = false;
617 if ((span->fDone = newT == 1)) {
621 // FIXME: note that this relies on spans being a continguous array
622 // find range of spans with nearly the same point as this one
623 // FIXME: SkDPoint::ApproximatelyEqual is better but breaks tests at the moment
624 while (&span[less + 1] - fTs.begin() > 0 && AlmostEqualUlps(span[less].fPt, pt)) {
625 if (fVerb == SkPath::kCubic_Verb) {
626 double tInterval = newT - span[less].fT;
627 double tMid = newT - tInterval / 2;
628 SkDPoint midPt = dcubic_xy_at_t(fPts, tMid);
629 if (!midPt.approximatelyEqual(xyAtT(span))) {
636 // FIXME: SkDPoint::ApproximatelyEqual is better but breaks tests at the moment
637 while (fTs.end() - &span[more - 1] > 1 && AlmostEqualUlps(span[more].fPt, pt)) {
638 if (fVerb == SkPath::kCubic_Verb) {
639 double tEndInterval = span[more].fT - newT;
640 double tMid = newT - tEndInterval / 2;
641 SkDPoint midEndPt = dcubic_xy_at_t(fPts, tMid);
642 if (!midEndPt.approximatelyEqual(xyAtT(span))) {
650 while (more - 1 > less && span[more].fPt == span[more - 1].fPt
651 && span[more].fT == span[more - 1].fT) {
657 if (precisely_negative(span[more].fT - span[less].fT)) {
660 // if the total range of t values is big enough, mark all tiny
661 bool tiny = span[less].fPt == span[more].fPt;
664 fSmall = span[index].fSmall = true;
665 fTiny |= span[index].fTiny = tiny;
666 if (!span[index].fDone) {
667 span[index].fDone = true;
670 } while (++index < more);
674 // set spans from start to end to decrement by one
675 // note this walks other backwards
676 // FIXME: there's probably an edge case that can be constructed where
677 // two span in one segment are separated by float epsilon on one span but
678 // not the other, if one segment is very small. For this
679 // case the counts asserted below may or may not be enough to separate the
680 // spans. Even if the counts work out, what if the spans aren't correctly
681 // sorted? It feels better in such a case to match the span's other span
682 // pointer since both coincident segments must contain the same spans.
683 // FIXME? It seems that decrementing by one will fail for complex paths that
684 // have three or more coincident edges. Shouldn't this subtract the difference
685 // between the winding values?
687 this 0>>>>1>>>>2>>>>3>>>4 0>>>>1>>>>2>>>>3>>>4 0>>>>1>>>>2>>>>3>>>4
688 other 2<<<<1<<<<0 2<<<<1<<<<0 2<<<<1<<<<0
690 startPt endPt test/oTest first pos test/oTest final pos
692 void SkOpSegment::addTCancel(const SkPoint& startPt, const SkPoint& endPt, SkOpSegment* other) {
693 bool binary = fOperand != other->fOperand;
695 while (startPt != fTs[index].fPt) {
696 SkASSERT(index < fTs.count());
699 while (index > 0 && precisely_equal(fTs[index].fT, fTs[index - 1].fT)) {
702 bool oFoundEnd = false;
703 int oIndex = other->fTs.count();
704 while (startPt != other->fTs[--oIndex].fPt) { // look for startPt match
705 SkASSERT(oIndex > 0);
707 double oStartT = other->fTs[oIndex].fT;
708 // look for first point beyond match
709 while (startPt == other->fTs[--oIndex].fPt || precisely_equal(oStartT, other->fTs[oIndex].fT)) {
711 return; // tiny spans may move in the wrong direction
714 SkOpSpan* test = &fTs[index];
715 SkOpSpan* oTest = &other->fTs[oIndex];
716 SkSTArray<kOutsideTrackedTCount, SkPoint, true> outsidePts;
717 SkSTArray<kOutsideTrackedTCount, SkPoint, true> oOutsidePts;
718 bool decrement, track, bigger;
719 int originalWindValue;
720 const SkPoint* testPt;
721 const SkPoint* oTestPt;
723 SkASSERT(test->fT < 1);
724 SkASSERT(oTest->fT < 1);
725 decrement = test->fWindValue && oTest->fWindValue;
726 track = test->fWindValue || oTest->fWindValue;
727 bigger = test->fWindValue >= oTest->fWindValue;
729 double testT = test->fT;
730 oTestPt = &oTest->fPt;
731 double oTestT = oTest->fT;
734 if (binary && bigger) {
740 TrackOutsidePair(&outsidePts, *testPt, *oTestPt);
742 SkASSERT(index < fTs.count() - 1);
743 test = &fTs[++index];
744 } while (*testPt == test->fPt || precisely_equal(testT, test->fT));
745 originalWindValue = oTest->fWindValue;
747 SkASSERT(oTest->fT < 1);
748 SkASSERT(originalWindValue == oTest->fWindValue);
750 if (binary && !bigger) {
753 other->decrementSpan(oTest);
756 TrackOutsidePair(&oOutsidePts, *oTestPt, *testPt);
761 oFoundEnd |= endPt == oTest->fPt;
762 oTest = &other->fTs[--oIndex];
763 } while (*oTestPt == oTest->fPt || precisely_equal(oTestT, oTest->fT));
764 } while (endPt != test->fPt && test->fT < 1);
765 // FIXME: determine if canceled edges need outside ts added
767 for (int oIdx2 = oIndex; oIdx2 >= 0; --oIdx2) {
768 SkOpSpan* oTst2 = &other->fTs[oIdx2];
769 if (originalWindValue != oTst2->fWindValue) {
770 goto skipAdvanceOtherCancel;
772 if (!oTst2->fWindValue) {
773 goto skipAdvanceOtherCancel;
775 if (endPt == other->fTs[oIdx2].fPt) {
780 SkASSERT(originalWindValue == oTest->fWindValue);
782 if (binary && !bigger) {
785 other->decrementSpan(oTest);
788 TrackOutsidePair(&oOutsidePts, *oTestPt, *testPt);
793 oTest = &other->fTs[--oIndex];
794 oFoundEnd |= endPt == oTest->fPt;
795 } while (!oFoundEnd || endPt == oTest->fPt);
797 skipAdvanceOtherCancel:
798 int outCount = outsidePts.count();
799 if (!done() && outCount) {
800 addCancelOutsides(outsidePts[0], outsidePts[1], other);
802 addCancelOutsides(outsidePts[outCount - 2], outsidePts[outCount - 1], other);
805 if (!other->done() && oOutsidePts.count()) {
806 other->addCancelOutsides(oOutsidePts[0], oOutsidePts[1], this);
808 setCoincidentRange(startPt, endPt, other);
809 other->setCoincidentRange(startPt, endPt, this);
812 int SkOpSegment::addSelfT(const SkPoint& pt, double newT) {
813 // if the tail nearly intersects itself but not quite, the caller records this separately
814 int result = addT(this, pt, newT);
815 SkOpSpan* span = &fTs[result];
816 fLoop = span->fLoop = true;
820 // find the starting or ending span with an existing loop of angles
821 // FIXME? replicate for all identical starting/ending spans?
822 // OPTIMIZE? remove the spans pointing to windValue==0 here or earlier?
823 // FIXME? assert that only one other span has a valid windValue or oppValue
824 void SkOpSegment::addSimpleAngle(int index) {
825 SkOpSpan* span = &fTs[index];
832 if (span->fToAngle) {
833 SkASSERT(span->fToAngle->loopCount() == 2);
834 SkASSERT(!span->fFromAngle);
835 span->fFromAngle = span->fToAngle->next();
839 } while (span->fT == 0);
840 SkASSERT(!fTs[0].fTiny && fTs[idx].fT > 0);
848 if (span->fFromAngle) {
849 SkASSERT(span->fFromAngle->loopCount() == 2);
850 SkASSERT(!span->fToAngle);
851 span->fToAngle = span->fFromAngle->next();
855 } while (span->fT == 1);
856 SkASSERT(!fTs[idx].fTiny && fTs[idx].fT < 1);
866 other = span->fOther;
867 int oFrom = span->fOtherIndex;
868 oSpan = &other->fTs[oFrom];
869 if (oSpan->fT < 1 && oSpan->fWindValue) {
872 if (oSpan->fT == 0) {
875 oFrom = other->nextExactSpan(oFrom, -1);
876 SkOpSpan* oFromSpan = &other->fTs[oFrom];
877 SkASSERT(oFromSpan->fT < 1);
878 if (oFromSpan->fWindValue) {
881 } while (++index < end);
882 SkOpAngle* angle, * oAngle;
884 SkASSERT(span->fOtherIndex - 1 >= 0);
885 SkASSERT(span->fOtherT == 1);
886 SkDEBUGCODE(int oPriorIndex = other->nextExactSpan(span->fOtherIndex, -1));
887 SkDEBUGCODE(const SkOpSpan& oPrior = other->span(oPriorIndex));
888 SkASSERT(!oPrior.fTiny && oPrior.fT < 1);
889 other->addEndSpan(span->fOtherIndex);
890 angle = span->fToAngle;
891 oAngle = oSpan->fFromAngle;
893 SkASSERT(span->fOtherIndex + 1 < other->count());
894 SkASSERT(span->fOtherT == 0);
895 SkASSERT(!oSpan->fTiny && (other->fTs[span->fOtherIndex + 1].fT > 0
896 || (other->fTs[span->fOtherIndex + 1].fFromAngle == NULL
897 && other->fTs[span->fOtherIndex + 1].fToAngle == NULL)));
900 const SkOpSpan& osSpan = other->span(oIndex);
901 if (osSpan.fFromAngle || osSpan.fT > 0) {
905 SkASSERT(oIndex < other->count());
907 other->addStartSpan(oIndex);
908 angle = span->fFromAngle;
909 oAngle = oSpan->fToAngle;
911 angle->insert(oAngle);
914 void SkOpSegment::alignMultiples(SkTDArray<AlignedSpan>* alignedArray) {
916 int count = this->count();
917 for (int index = 0; index < count; ++index) {
918 SkOpSpan& span = fTs[index];
919 if (!span.fMultiple) {
922 int end = nextExactSpan(index, 1);
923 SkASSERT(end > index + 1);
924 const SkPoint& thisPt = span.fPt;
925 while (index < end - 1) {
926 SkOpSegment* other1 = span.fOther;
927 int oCnt = other1->count();
928 for (int idx2 = index + 1; idx2 < end; ++idx2) {
929 SkOpSpan& span2 = fTs[idx2];
930 SkOpSegment* other2 = span2.fOther;
931 for (int oIdx = 0; oIdx < oCnt; ++oIdx) {
932 SkOpSpan& oSpan = other1->fTs[oIdx];
933 if (oSpan.fOther != other2) {
936 if (oSpan.fPt == thisPt) {
937 goto skipExactMatches;
940 for (int oIdx = 0; oIdx < oCnt; ++oIdx) {
941 SkOpSpan& oSpan = other1->fTs[oIdx];
942 if (oSpan.fOther != other2) {
945 if (SkDPoint::RoughlyEqual(oSpan.fPt, thisPt)) {
946 SkOpSpan& oSpan2 = other2->fTs[oSpan.fOtherIndex];
947 if (zero_or_one(span.fOtherT) || zero_or_one(oSpan.fT)
948 || zero_or_one(span2.fOtherT) || zero_or_one(oSpan2.fT)) {
951 if (!way_roughly_equal(span.fOtherT, oSpan.fT)
952 || !way_roughly_equal(span2.fOtherT, oSpan2.fT)
953 || !way_roughly_equal(span2.fOtherT, oSpan.fOtherT)
954 || !way_roughly_equal(span.fOtherT, oSpan2.fOtherT)) {
957 alignSpan(thisPt, span.fOtherT, other1, span2.fOtherT,
958 other2, &oSpan, alignedArray);
959 alignSpan(thisPt, span2.fOtherT, other2, span.fOtherT,
960 other1, &oSpan2, alignedArray);
973 void SkOpSegment::alignSpan(const SkPoint& newPt, double newT, const SkOpSegment* other,
974 double otherT, const SkOpSegment* other2, SkOpSpan* oSpan,
975 SkTDArray<AlignedSpan>* alignedArray) {
976 AlignedSpan* aligned = alignedArray->append();
977 aligned->fOldPt = oSpan->fPt;
978 aligned->fPt = newPt;
979 aligned->fOldT = oSpan->fT;
981 aligned->fSegment = this; // OPTIMIZE: may be unused, can remove
982 aligned->fOther1 = other;
983 aligned->fOther2 = other2;
984 SkASSERT(SkDPoint::RoughlyEqual(oSpan->fPt, newPt));
986 // SkASSERT(way_roughly_equal(oSpan->fT, newT));
988 // SkASSERT(way_roughly_equal(oSpan->fOtherT, otherT));
989 oSpan->fOtherT = otherT;
992 bool SkOpSegment::alignSpan(int index, double thisT, const SkPoint& thisPt) {
993 bool aligned = false;
994 SkOpSpan* span = &fTs[index];
995 SkOpSegment* other = span->fOther;
996 int oIndex = span->fOtherIndex;
997 SkOpSpan* oSpan = &other->fTs[oIndex];
998 if (span->fT != thisT) {
1000 oSpan->fOtherT = thisT;
1003 if (span->fPt != thisPt) {
1005 oSpan->fPt = thisPt;
1008 double oT = oSpan->fT;
1012 int oStart = other->nextSpan(oIndex, -1) + 1;
1013 oSpan = &other->fTs[oStart];
1014 int otherIndex = oStart;
1017 while (oSpan->fPt == thisPt && oSpan->fT != 1) {
1018 oSpan->fTiny = true;
1025 int oEnd = other->nextSpan(oIndex, 1);
1026 bool oAligned = false;
1027 if (oSpan->fPt != thisPt) {
1028 oAligned |= other->alignSpan(oStart, oT, thisPt);
1030 while (++otherIndex < oEnd) {
1031 SkOpSpan* oNextSpan = &other->fTs[otherIndex];
1032 if (oNextSpan->fT != oT || oNextSpan->fPt != thisPt) {
1033 oAligned |= other->alignSpan(otherIndex, oT, thisPt);
1037 other->alignSpanState(oStart, oEnd);
1042 void SkOpSegment::alignSpanState(int start, int end) {
1043 SkOpSpan* lastSpan = &fTs[--end];
1044 bool allSmall = lastSpan->fSmall;
1045 bool allTiny = lastSpan->fTiny;
1046 bool allDone = lastSpan->fDone;
1047 SkDEBUGCODE(int winding = lastSpan->fWindValue);
1048 SkDEBUGCODE(int oppWinding = lastSpan->fOppValue);
1050 while (index < end) {
1051 SkOpSpan* span = &fTs[index];
1052 span->fSmall = allSmall;
1053 span->fTiny = allTiny;
1054 if (span->fDone != allDone) {
1055 span->fDone = allDone;
1056 fDoneSpans += allDone ? 1 : -1;
1058 SkASSERT(span->fWindValue == winding);
1059 SkASSERT(span->fOppValue == oppWinding);
1064 void SkOpSegment::blindCancel(const SkCoincidence& coincidence, SkOpSegment* other) {
1065 bool binary = fOperand != other->fOperand;
1067 int last = this->count();
1069 SkOpSpan& span = this->fTs[--last];
1070 if (span.fT != 1 && !span.fSmall) {
1073 span.fCoincident = true;
1075 int oIndex = other->count();
1077 SkOpSpan& oSpan = other->fTs[--oIndex];
1078 if (oSpan.fT != 1 && !oSpan.fSmall) {
1081 oSpan.fCoincident = true;
1084 SkOpSpan* test = &this->fTs[index];
1085 int baseWind = test->fWindValue;
1086 int baseOpp = test->fOppValue;
1087 int endIndex = index;
1088 while (++endIndex <= last) {
1089 SkOpSpan* endSpan = &this->fTs[endIndex];
1090 SkASSERT(endSpan->fT < 1);
1091 if (endSpan->fWindValue != baseWind || endSpan->fOppValue != baseOpp) {
1094 endSpan->fCoincident = true;
1096 SkOpSpan* oTest = &other->fTs[oIndex];
1097 int oBaseWind = oTest->fWindValue;
1098 int oBaseOpp = oTest->fOppValue;
1099 int oStartIndex = oIndex;
1100 while (--oStartIndex >= 0) {
1101 SkOpSpan* oStartSpan = &other->fTs[oStartIndex];
1102 if (oStartSpan->fWindValue != oBaseWind || oStartSpan->fOppValue != oBaseOpp) {
1105 oStartSpan->fCoincident = true;
1107 bool decrement = baseWind && oBaseWind;
1108 bool bigger = baseWind >= oBaseWind;
1110 SkASSERT(test->fT < 1);
1112 if (binary && bigger) {
1115 decrementSpan(test);
1118 test->fCoincident = true;
1119 test = &fTs[++index];
1120 } while (index < endIndex);
1122 SkASSERT(oTest->fT < 1);
1124 if (binary && !bigger) {
1127 other->decrementSpan(oTest);
1130 oTest->fCoincident = true;
1131 oTest = &other->fTs[--oIndex];
1132 } while (oIndex > oStartIndex);
1133 } while (index <= last && oIndex >= 0);
1134 SkASSERT(index > last);
1135 SkASSERT(oIndex < 0);
1138 void SkOpSegment::blindCoincident(const SkCoincidence& coincidence, SkOpSegment* other) {
1139 bool binary = fOperand != other->fOperand;
1141 int last = this->count();
1143 SkOpSpan& span = this->fTs[--last];
1144 if (span.fT != 1 && !span.fSmall) {
1147 span.fCoincident = true;
1150 int oLast = other->count();
1152 SkOpSpan& oSpan = other->fTs[--oLast];
1153 if (oSpan.fT != 1 && !oSpan.fSmall) {
1156 oSpan.fCoincident = true;
1159 SkOpSpan* test = &this->fTs[index];
1160 int baseWind = test->fWindValue;
1161 int baseOpp = test->fOppValue;
1162 int endIndex = index;
1164 while (++endIndex <= last) {
1165 endSpan = &this->fTs[endIndex];
1166 SkASSERT(endSpan->fT < 1);
1167 if (endSpan->fWindValue != baseWind || endSpan->fOppValue != baseOpp) {
1170 endSpan->fCoincident = true;
1172 SkOpSpan* oTest = &other->fTs[oIndex];
1173 int oBaseWind = oTest->fWindValue;
1174 int oBaseOpp = oTest->fOppValue;
1175 int oEndIndex = oIndex;
1177 while (++oEndIndex <= oLast) {
1178 oEndSpan = &this->fTs[oEndIndex];
1179 SkASSERT(oEndSpan->fT < 1);
1180 if (oEndSpan->fWindValue != oBaseWind || oEndSpan->fOppValue != oBaseOpp) {
1183 oEndSpan->fCoincident = true;
1185 // consolidate the winding count even if done
1186 if ((test->fWindValue || test->fOppValue) && (oTest->fWindValue || oTest->fOppValue)) {
1187 if (!binary || test->fWindValue + oTest->fOppValue >= 0) {
1188 bumpCoincidentBlind(binary, index, endIndex);
1189 other->bumpCoincidentOBlind(oIndex, oEndIndex);
1191 other->bumpCoincidentBlind(binary, oIndex, oEndIndex);
1192 bumpCoincidentOBlind(index, endIndex);
1197 } while (index <= last && oIndex <= oLast);
1198 SkASSERT(index > last);
1199 SkASSERT(oIndex > oLast);
1202 void SkOpSegment::bumpCoincidentBlind(bool binary, int index, int endIndex) {
1203 const SkOpSpan& oTest = fTs[index];
1204 int oWindValue = oTest.fWindValue;
1205 int oOppValue = oTest.fOppValue;
1207 SkTSwap<int>(oWindValue, oOppValue);
1210 (void) bumpSpan(&fTs[index], oWindValue, oOppValue);
1211 } while (++index < endIndex);
1214 bool SkOpSegment::bumpCoincidentThis(const SkOpSpan& oTest, bool binary, int* indexPtr,
1215 SkTArray<SkPoint, true>* outsideTs) {
1216 int index = *indexPtr;
1217 int oWindValue = oTest.fWindValue;
1218 int oOppValue = oTest.fOppValue;
1220 SkTSwap<int>(oWindValue, oOppValue);
1222 SkOpSpan* const test = &fTs[index];
1223 SkOpSpan* end = test;
1224 const SkPoint& oStartPt = oTest.fPt;
1226 if (end->fDone && !end->fTiny && !end->fSmall) { // extremely large paths trigger this
1229 if (bumpSpan(end, oWindValue, oOppValue)) {
1230 TrackOutside(outsideTs, oStartPt);
1232 end = &fTs[++index];
1233 } while ((end->fPt == test->fPt || precisely_equal(end->fT, test->fT)) && end->fT < 1);
1238 void SkOpSegment::bumpCoincidentOBlind(int index, int endIndex) {
1240 zeroSpan(&fTs[index]);
1241 } while (++index < endIndex);
1244 // because of the order in which coincidences are resolved, this and other
1245 // may not have the same intermediate points. Compute the corresponding
1246 // intermediate T values (using this as the master, other as the follower)
1247 // and walk other conditionally -- hoping that it catches up in the end
1248 void SkOpSegment::bumpCoincidentOther(const SkOpSpan& test, int* oIndexPtr,
1249 SkTArray<SkPoint, true>* oOutsidePts) {
1250 int oIndex = *oIndexPtr;
1251 SkOpSpan* const oTest = &fTs[oIndex];
1252 SkOpSpan* oEnd = oTest;
1253 const SkPoint& oStartPt = oTest->fPt;
1254 double oStartT = oTest->fT;
1255 #if 0 // FIXME : figure out what disabling this breaks
1256 const SkPoint& startPt = test.fPt;
1257 // this is always true since oEnd == oTest && oStartPt == oTest->fPt -- find proper condition
1258 if (oStartPt == oEnd->fPt || precisely_equal(oStartT, oEnd->fT)) {
1259 TrackOutside(oOutsidePts, startPt);
1262 while (oStartPt == oEnd->fPt || precisely_equal(oStartT, oEnd->fT)) {
1264 oEnd = &fTs[++oIndex];
1266 *oIndexPtr = oIndex;
1269 // FIXME: need to test this case:
1270 // contourA has two segments that are coincident
1271 // contourB has two segments that are coincident in the same place
1272 // each ends up with +2/0 pairs for winding count
1273 // since logic below doesn't transfer count (only increments/decrements) can this be
1274 // resolved to +4/0 ?
1276 // set spans from start to end to increment the greater by one and decrement
1278 bool SkOpSegment::addTCoincident(const SkPoint& startPt, const SkPoint& endPt, double endT,
1279 SkOpSegment* other) {
1280 bool binary = fOperand != other->fOperand;
1282 while (startPt != fTs[index].fPt) {
1283 SkASSERT(index < fTs.count());
1286 double startT = fTs[index].fT;
1287 while (index > 0 && precisely_equal(fTs[index - 1].fT, startT)) {
1291 while (startPt != other->fTs[oIndex].fPt) {
1292 SkASSERT(oIndex < other->fTs.count());
1295 double oStartT = other->fTs[oIndex].fT;
1296 while (oIndex > 0 && precisely_equal(other->fTs[oIndex - 1].fT, oStartT)) {
1299 SkSTArray<kOutsideTrackedTCount, SkPoint, true> outsidePts;
1300 SkSTArray<kOutsideTrackedTCount, SkPoint, true> oOutsidePts;
1301 SkOpSpan* test = &fTs[index];
1302 const SkPoint* testPt = &test->fPt;
1303 double testT = test->fT;
1304 SkOpSpan* oTest = &other->fTs[oIndex];
1305 const SkPoint* oTestPt = &oTest->fPt;
1306 // paths with extreme data will fail this test and eject out of pathops altogether later on
1307 // SkASSERT(AlmostEqualUlps(*testPt, *oTestPt));
1309 SkASSERT(test->fT < 1);
1310 if (oTest->fT == 1) {
1311 // paths with extreme data may be so mismatched that we fail here
1315 // consolidate the winding count even if done
1316 if ((test->fWindValue == 0 && test->fOppValue == 0)
1317 || (oTest->fWindValue == 0 && oTest->fOppValue == 0)) {
1318 SkDEBUGCODE(int firstWind = test->fWindValue);
1319 SkDEBUGCODE(int firstOpp = test->fOppValue);
1321 SkASSERT(firstWind == fTs[index].fWindValue);
1322 SkASSERT(firstOpp == fTs[index].fOppValue);
1324 SkASSERT(index < fTs.count());
1325 } while (*testPt == fTs[index].fPt);
1326 SkDEBUGCODE(firstWind = oTest->fWindValue);
1327 SkDEBUGCODE(firstOpp = oTest->fOppValue);
1329 SkASSERT(firstWind == other->fTs[oIndex].fWindValue);
1330 SkASSERT(firstOpp == other->fTs[oIndex].fOppValue);
1332 SkASSERT(oIndex < other->fTs.count());
1333 } while (*oTestPt == other->fTs[oIndex].fPt);
1335 if (!binary || test->fWindValue + oTest->fOppValue >= 0) {
1336 if (!bumpCoincidentThis(*oTest, binary, &index, &outsidePts)) {
1339 other->bumpCoincidentOther(*test, &oIndex, &oOutsidePts);
1341 if (!other->bumpCoincidentThis(*test, binary, &oIndex, &oOutsidePts)) {
1344 bumpCoincidentOther(*oTest, &index, &outsidePts);
1348 testPt = &test->fPt;
1350 oTest = &other->fTs[oIndex];
1351 oTestPt = &oTest->fPt;
1352 if (endPt == *testPt || precisely_equal(endT, testT)) {
1355 // SkASSERT(AlmostEqualUlps(*testPt, *oTestPt));
1356 } while (endPt != *oTestPt);
1357 // in rare cases, one may have ended before the other
1358 if (endPt != *testPt && !precisely_equal(endT, testT)) {
1359 int lastWind = test[-1].fWindValue;
1360 int lastOpp = test[-1].fOppValue;
1361 bool zero = lastWind == 0 && lastOpp == 0;
1363 if (test->fWindValue || test->fOppValue) {
1364 test->fWindValue = lastWind;
1365 test->fOppValue = lastOpp;
1371 test = &fTs[++index];
1372 testPt = &test->fPt;
1373 } while (endPt != *testPt);
1375 if (endPt != *oTestPt) {
1376 // look ahead to see if zeroing more spans will allows us to catch up
1377 int oPeekIndex = oIndex;
1378 bool success = true;
1380 int oCount = other->count();
1382 oPeek = &other->fTs[oPeekIndex];
1383 if (++oPeekIndex == oCount) {
1387 } while (endPt != oPeek->fPt);
1389 // make sure the matching point completes the coincidence span
1392 if (oPeek->fOther == this) {
1396 if (++oPeekIndex == oCount) {
1399 oPeek = &other->fTs[oPeekIndex];
1400 } while (endPt == oPeek->fPt);
1404 if (!binary || test->fWindValue + oTest->fOppValue >= 0) {
1405 other->bumpCoincidentOther(*test, &oIndex, &oOutsidePts);
1407 if (!other->bumpCoincidentThis(*test, binary, &oIndex, &oOutsidePts)) {
1411 oTest = &other->fTs[oIndex];
1412 oTestPt = &oTest->fPt;
1413 } while (endPt != *oTestPt);
1416 int outCount = outsidePts.count();
1417 if (!done() && outCount) {
1418 addCoinOutsides(outsidePts[0], endPt, other);
1420 if (!other->done() && oOutsidePts.count()) {
1421 other->addCoinOutsides(oOutsidePts[0], endPt, this);
1423 setCoincidentRange(startPt, endPt, other);
1424 other->setCoincidentRange(startPt, endPt, this);
1428 // FIXME: this doesn't prevent the same span from being added twice
1429 // fix in caller, SkASSERT here?
1430 // FIXME: this may erroneously reject adds for cubic loops
1431 const SkOpSpan* SkOpSegment::addTPair(double t, SkOpSegment* other, double otherT, bool borrowWind,
1432 const SkPoint& pt, const SkPoint& pt2) {
1433 int tCount = fTs.count();
1434 for (int tIndex = 0; tIndex < tCount; ++tIndex) {
1435 const SkOpSpan& span = fTs[tIndex];
1436 if (!approximately_negative(span.fT - t)) {
1439 if (span.fOther == other) {
1440 bool tsMatch = approximately_equal(span.fT, t);
1441 bool otherTsMatch = approximately_equal(span.fOtherT, otherT);
1442 // FIXME: add cubic loop detecting logic here
1443 // if fLoop bit is set on span, that could be enough if addOtherT copies the bit
1444 // or if a new bit is added ala fOtherLoop
1445 if (tsMatch || otherTsMatch) {
1446 #if DEBUG_ADD_T_PAIR
1447 SkDebugf("%s addTPair duplicate this=%d %1.9g other=%d %1.9g\n",
1448 __FUNCTION__, fID, t, other->fID, otherT);
1454 int oCount = other->count();
1455 for (int oIndex = 0; oIndex < oCount; ++oIndex) {
1456 const SkOpSpan& oSpan = other->span(oIndex);
1457 if (!approximately_negative(oSpan.fT - otherT)) {
1460 if (oSpan.fOther == this) {
1461 bool otherTsMatch = approximately_equal(oSpan.fT, otherT);
1462 bool tsMatch = approximately_equal(oSpan.fOtherT, t);
1463 if (otherTsMatch || tsMatch) {
1464 #if DEBUG_ADD_T_PAIR
1465 SkDebugf("%s addTPair other duplicate this=%d %1.9g other=%d %1.9g\n",
1466 __FUNCTION__, fID, t, other->fID, otherT);
1472 #if DEBUG_ADD_T_PAIR
1473 SkDebugf("%s addTPair this=%d %1.9g other=%d %1.9g\n",
1474 __FUNCTION__, fID, t, other->fID, otherT);
1476 SkASSERT(other != this);
1477 int insertedAt = addT(other, pt, t);
1478 int otherInsertedAt = other->addT(this, pt2, otherT);
1479 addOtherT(insertedAt, otherT, otherInsertedAt);
1480 other->addOtherT(otherInsertedAt, t, insertedAt);
1481 matchWindingValue(insertedAt, t, borrowWind);
1482 other->matchWindingValue(otherInsertedAt, otherT, borrowWind);
1483 SkOpSpan& span = this->fTs[insertedAt];
1486 SkOpSpan& oSpan = other->fTs[otherInsertedAt];
1492 const SkOpSpan* SkOpSegment::addTPair(double t, SkOpSegment* other, double otherT, bool borrowWind,
1493 const SkPoint& pt) {
1494 return addTPair(t, other, otherT, borrowWind, pt, pt);
1497 bool SkOpSegment::betweenPoints(double midT, const SkPoint& pt1, const SkPoint& pt2) const {
1498 const SkPoint midPt = ptAtT(midT);
1499 SkPathOpsBounds bounds;
1500 bounds.set(pt1.fX, pt1.fY, pt2.fX, pt2.fY);
1502 return bounds.almostContains(midPt);
1505 bool SkOpSegment::betweenTs(int lesser, double testT, int greater) const {
1506 if (lesser > greater) {
1507 SkTSwap<int>(lesser, greater);
1509 return approximately_between(fTs[lesser].fT, testT, fTs[greater].fT);
1512 // in extreme cases (like the buffer overflow test) return false to abort
1513 // for now, if one t value represents two different points, then the values are too extreme
1514 // to generate meaningful results
1515 bool SkOpSegment::calcAngles() {
1516 int spanCount = fTs.count();
1517 if (spanCount <= 2) {
1518 return spanCount == 2;
1521 const SkOpSpan* firstSpan = &fTs[index];
1522 int activePrior = checkSetAngle(0);
1523 const SkOpSpan* span = &fTs[0];
1524 if (firstSpan->fT == 0 || span->fTiny || span->fOtherT != 1 || span->fOther->multipleEnds()) {
1525 index = findStartSpan(0); // curve start intersects
1526 if (fTs[index].fT == 0) {
1529 SkASSERT(index > 0);
1530 if (activePrior >= 0) {
1531 addStartSpan(index);
1535 int endIndex = spanCount - 1;
1536 span = &fTs[endIndex - 1];
1537 if ((addEnd = span->fT == 1 || span->fTiny)) { // if curve end intersects
1538 endIndex = findEndSpan(endIndex);
1539 SkASSERT(endIndex > 0);
1541 addEnd = fTs[endIndex].fOtherT != 0 || fTs[endIndex].fOther->multipleStarts();
1543 SkASSERT(endIndex >= index);
1545 while (index < endIndex) {
1546 const SkOpSpan& fromSpan = fTs[index]; // for each intermediate intersection
1547 const SkOpSpan* lastSpan;
1552 span = &fTs[++index];
1553 SkASSERT(index < spanCount);
1554 if (!precisely_negative(span->fT - lastSpan->fT) && !lastSpan->fTiny) {
1557 if (!SkDPoint::ApproximatelyEqual(lastSpan->fPt, span->fPt)) {
1561 SkOpAngle* angle = NULL;
1562 SkOpAngle* priorAngle;
1563 if (activePrior >= 0) {
1564 int pActive = firstActive(prior);
1565 SkASSERT(pActive < start);
1566 priorAngle = &fAngles.push_back();
1567 priorAngle->set(this, start, pActive);
1569 int active = checkSetAngle(start);
1571 SkASSERT(active < index);
1572 angle = &fAngles.push_back();
1573 angle->set(this, active, index);
1576 debugCheckPointsEqualish(start, index);
1580 const SkOpSpan* startSpan = &fTs[start - 1];
1581 if (!startSpan->fSmall || isCanceled(start - 1) || startSpan->fFromAngle
1582 || startSpan->fToAngle) {
1586 } while (start > 0);
1588 if (activePrior >= 0) {
1589 SkASSERT(fTs[start].fFromAngle == NULL);
1590 fTs[start].fFromAngle = priorAngle;
1593 SkASSERT(fTs[start].fToAngle == NULL);
1594 fTs[start].fToAngle = angle;
1596 } while (++start < index);
1597 activePrior = active;
1599 if (addEnd && activePrior >= 0) {
1600 addEndSpan(endIndex);
1605 int SkOpSegment::checkSetAngle(int tIndex) const {
1606 const SkOpSpan* span = &fTs[tIndex];
1607 while (span->fTiny /* || span->fSmall */) {
1608 span = &fTs[++tIndex];
1610 return isCanceled(tIndex) ? -1 : tIndex;
1613 // at this point, the span is already ordered, or unorderable
1614 int SkOpSegment::computeSum(int startIndex, int endIndex, SkOpAngle::IncludeType includeType) {
1615 SkASSERT(includeType != SkOpAngle::kUnaryXor);
1616 SkOpAngle* firstAngle = spanToAngle(endIndex, startIndex);
1617 if (NULL == firstAngle || NULL == firstAngle->next()) {
1620 // if all angles have a computed winding,
1621 // or if no adjacent angles are orderable,
1622 // or if adjacent orderable angles have no computed winding,
1623 // there's nothing to do
1624 // if two orderable angles are adjacent, and both are next to orderable angles,
1625 // and one has winding computed, transfer to the other
1626 SkOpAngle* baseAngle = NULL;
1627 bool tryReverse = false;
1628 // look for counterclockwise transfers
1629 SkOpAngle* angle = firstAngle->previous();
1630 SkOpAngle* next = angle->next();
1633 SkOpAngle* prior = angle;
1635 next = angle->next();
1636 SkASSERT(prior->next() == angle);
1637 SkASSERT(angle->next() == next);
1638 if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
1642 int testWinding = angle->segment()->windSum(angle);
1643 if (SK_MinS32 != testWinding) {
1649 ComputeOneSum(baseAngle, angle, includeType);
1650 baseAngle = SK_MinS32 != angle->segment()->windSum(angle) ? angle : NULL;
1652 } while (next != firstAngle);
1653 if (baseAngle && SK_MinS32 == firstAngle->segment()->windSum(firstAngle)) {
1654 firstAngle = baseAngle;
1659 SkOpAngle* prior = firstAngle;
1662 prior = angle->previous();
1663 SkASSERT(prior->next() == angle);
1664 next = angle->next();
1665 if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
1669 int testWinding = angle->segment()->windSum(angle);
1670 if (SK_MinS32 != testWinding) {
1675 ComputeOneSumReverse(baseAngle, angle, includeType);
1676 baseAngle = SK_MinS32 != angle->segment()->windSum(angle) ? angle : NULL;
1678 } while (prior != firstAngle);
1680 int minIndex = SkMin32(startIndex, endIndex);
1681 return windSum(minIndex);
1684 void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
1685 SkOpAngle::IncludeType includeType) {
1686 const SkOpSegment* baseSegment = baseAngle->segment();
1687 int sumMiWinding = baseSegment->updateWindingReverse(baseAngle);
1689 bool binary = includeType >= SkOpAngle::kBinarySingle;
1691 sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle);
1692 if (baseSegment->operand()) {
1693 SkTSwap<int>(sumMiWinding, sumSuWinding);
1696 SkOpSegment* nextSegment = nextAngle->segment();
1697 int maxWinding, sumWinding;
1700 int oppMaxWinding, oppSumWinding;
1701 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
1702 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
1703 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
1706 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
1707 &maxWinding, &sumWinding);
1708 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
1710 nextAngle->setLastMarked(last);
1713 void SkOpSegment::ComputeOneSumReverse(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
1714 SkOpAngle::IncludeType includeType) {
1715 const SkOpSegment* baseSegment = baseAngle->segment();
1716 int sumMiWinding = baseSegment->updateWinding(baseAngle);
1718 bool binary = includeType >= SkOpAngle::kBinarySingle;
1720 sumSuWinding = baseSegment->updateOppWinding(baseAngle);
1721 if (baseSegment->operand()) {
1722 SkTSwap<int>(sumMiWinding, sumSuWinding);
1725 SkOpSegment* nextSegment = nextAngle->segment();
1726 int maxWinding, sumWinding;
1729 int oppMaxWinding, oppSumWinding;
1730 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
1731 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
1732 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
1735 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
1736 &maxWinding, &sumWinding);
1737 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
1739 nextAngle->setLastMarked(last);
1742 bool SkOpSegment::containsPt(const SkPoint& pt, int index, int endIndex) const {
1743 int step = index < endIndex ? 1 : -1;
1745 const SkOpSpan& span = this->span(index);
1746 if (span.fPt == pt) {
1747 const SkOpSpan& endSpan = this->span(endIndex);
1748 return span.fT == endSpan.fT && pt != endSpan.fPt;
1751 } while (index != endIndex);
1755 bool SkOpSegment::containsT(double t, const SkOpSegment* other, double otherT) const {
1756 int count = this->count();
1757 for (int index = 0; index < count; ++index) {
1758 const SkOpSpan& span = fTs[index];
1763 if (other != span.fOther) {
1766 if (other->fVerb != SkPath::kCubic_Verb) {
1769 if (!other->fLoop) {
1772 double otherMidT = (otherT + span.fOtherT) / 2;
1773 SkPoint otherPt = other->ptAtT(otherMidT);
1774 return SkDPoint::ApproximatelyEqual(span.fPt, otherPt);
1780 int SkOpSegment::crossedSpanY(const SkPoint& basePt, SkScalar* bestY, double* hitT,
1781 bool* hitSomething, double mid, bool opp, bool current) const {
1782 SkScalar bottom = fBounds.fBottom;
1783 int bestTIndex = -1;
1784 if (bottom <= *bestY) {
1787 SkScalar top = fBounds.fTop;
1788 if (top >= basePt.fY) {
1791 if (fBounds.fLeft > basePt.fX) {
1794 if (fBounds.fRight < basePt.fX) {
1797 if (fBounds.fLeft == fBounds.fRight) {
1798 // if vertical, and directly above test point, wait for another one
1799 return AlmostEqualUlps(basePt.fX, fBounds.fLeft) ? SK_MinS32 : bestTIndex;
1801 // intersect ray starting at basePt with edge
1802 SkIntersections intersections;
1803 // OPTIMIZE: use specialty function that intersects ray with curve,
1804 // returning t values only for curve (we don't care about t on ray)
1805 intersections.allowNear(false);
1806 int pts = (intersections.*CurveVertical[SkPathOpsVerbToPoints(fVerb)])
1807 (fPts, top, bottom, basePt.fX, false);
1808 if (pts == 0 || (current && pts == 1)) {
1814 double closest = fabs(intersections[0][0] - mid);
1815 for (int idx = 1; idx < pts; ++idx) {
1816 double test = fabs(intersections[0][idx] - mid);
1817 if (closest > test) {
1822 intersections.quickRemoveOne(closestIdx, --pts);
1825 for (int index = 0; index < pts; ++index) {
1826 double foundT = intersections[0][index];
1827 if (approximately_less_than_zero(foundT)
1828 || approximately_greater_than_one(foundT)) {
1831 SkScalar testY = (*CurvePointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, foundT).fY;
1832 if (approximately_negative(testY - *bestY)
1833 || approximately_negative(basePt.fY - testY)) {
1836 if (pts > 1 && fVerb == SkPath::kLine_Verb) {
1837 return SK_MinS32; // if the intersection is edge on, wait for another one
1839 if (fVerb > SkPath::kLine_Verb) {
1840 SkScalar dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, foundT).fX;
1841 if (approximately_zero(dx)) {
1842 return SK_MinS32; // hit vertical, wait for another one
1851 SkASSERT(bestT >= 0);
1852 SkASSERT(bestT <= 1);
1857 end = nextSpan(start, 1);
1858 } while (fTs[end].fT < bestT);
1859 // FIXME: see next candidate for a better pattern to find the next start/end pair
1860 while (start + 1 < end && fTs[start].fDone) {
1863 if (!isCanceled(start)) {
1866 *hitSomething = true;
1871 bool SkOpSegment::decrementSpan(SkOpSpan* span) {
1872 SkASSERT(span->fWindValue > 0);
1873 if (--(span->fWindValue) == 0) {
1874 if (!span->fOppValue && !span->fDone) {
1883 bool SkOpSegment::bumpSpan(SkOpSpan* span, int windDelta, int oppDelta) {
1884 SkASSERT(!span->fDone || span->fTiny || span->fSmall);
1885 span->fWindValue += windDelta;
1886 SkASSERT(span->fWindValue >= 0);
1887 span->fOppValue += oppDelta;
1888 SkASSERT(span->fOppValue >= 0);
1890 span->fWindValue &= 1;
1893 span->fOppValue &= 1;
1895 if (!span->fWindValue && !span->fOppValue) {
1903 const SkOpSpan& SkOpSegment::firstSpan(const SkOpSpan& thisSpan) const {
1904 const SkOpSpan* firstSpan = &thisSpan; // rewind to the start
1905 const SkOpSpan* beginSpan = fTs.begin();
1906 const SkPoint& testPt = thisSpan.fPt;
1907 while (firstSpan > beginSpan && firstSpan[-1].fPt == testPt) {
1913 const SkOpSpan& SkOpSegment::lastSpan(const SkOpSpan& thisSpan) const {
1914 const SkOpSpan* endSpan = fTs.end() - 1; // last can't be small
1915 const SkOpSpan* lastSpan = &thisSpan; // find the end
1916 const SkPoint& testPt = thisSpan.fPt;
1917 while (lastSpan < endSpan && lastSpan[1].fPt == testPt) {
1923 // with a loop, the comparison is move involved
1924 // scan backwards and forwards to count all matching points
1925 // (verify that there are twp scans marked as loops)
1926 // compare that against 2 matching scans for loop plus other results
1927 bool SkOpSegment::calcLoopSpanCount(const SkOpSpan& thisSpan, int* smallCounts) {
1928 const SkOpSpan& firstSpan = this->firstSpan(thisSpan); // rewind to the start
1929 const SkOpSpan& lastSpan = this->lastSpan(thisSpan); // find the end
1930 double firstLoopT = -1, lastLoopT = -1;
1931 const SkOpSpan* testSpan = &firstSpan - 1;
1932 while (++testSpan <= &lastSpan) {
1933 if (testSpan->fLoop) {
1934 firstLoopT = testSpan->fT;
1938 testSpan = &lastSpan + 1;
1939 while (--testSpan >= &firstSpan) {
1940 if (testSpan->fLoop) {
1941 lastLoopT = testSpan->fT;
1945 SkASSERT((firstLoopT == -1) == (lastLoopT == -1));
1946 if (firstLoopT == -1) {
1949 SkASSERT(firstLoopT < lastLoopT);
1950 testSpan = &firstSpan - 1;
1951 smallCounts[0] = smallCounts[1] = 0;
1952 while (++testSpan <= &lastSpan) {
1953 SkASSERT(approximately_equal(testSpan->fT, firstLoopT) +
1954 approximately_equal(testSpan->fT, lastLoopT) == 1);
1955 smallCounts[approximately_equal(testSpan->fT, lastLoopT)]++;
1960 double SkOpSegment::calcMissingTEnd(const SkOpSegment* ref, double loEnd, double min, double max,
1961 double hiEnd, const SkOpSegment* other, int thisStart) {
1965 int end = findOtherT(hiEnd, ref);
1969 double tHi = span(end).fT;
1971 if (thisStart >= 0) {
1972 tLo = span(thisStart).fT;
1975 int start1 = findOtherT(loEnd, ref);
1976 SkASSERT(start1 >= 0);
1977 tLo = span(start1).fT;
1980 double missingT = (max - refLo) / (hiEnd - refLo);
1981 missingT = tLo + missingT * (tHi - tLo);
1985 double SkOpSegment::calcMissingTStart(const SkOpSegment* ref, double loEnd, double min, double max,
1986 double hiEnd, const SkOpSegment* other, int thisEnd) {
1990 int start = findOtherT(loEnd, ref);
1994 double tLo = span(start).fT;
1997 tHi = span(thisEnd).fT;
2000 int end1 = findOtherT(hiEnd, ref);
2004 tHi = span(end1).fT;
2007 double missingT = (min - loEnd) / (refHi - loEnd);
2008 missingT = tLo + missingT * (tHi - tLo);
2012 // see if spans with two or more intersections have the same number on the other end
2013 void SkOpSegment::checkDuplicates() {
2015 SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans;
2021 endIndex = nextExactSpan(index, 1);
2022 if ((endFound = endIndex < 0)) {
2025 int dupCount = endIndex - index;
2030 const SkOpSpan* thisSpan = &fTs[index];
2031 if (thisSpan->fNear) {
2034 SkOpSegment* other = thisSpan->fOther;
2035 int oIndex = thisSpan->fOtherIndex;
2036 int oStart = other->nextExactSpan(oIndex, -1) + 1;
2037 int oEnd = other->nextExactSpan(oIndex, 1);
2039 oEnd = other->count();
2041 int oCount = oEnd - oStart;
2042 // force the other to match its t and this pt if not on an end point
2043 if (oCount != dupCount) {
2044 MissingSpan& missing = missingSpans.push_back();
2045 missing.fOther = NULL;
2046 SkDEBUGCODE(sk_bzero(&missing, sizeof(missing)));
2047 missing.fPt = thisSpan->fPt;
2048 const SkOpSpan& oSpan = other->span(oIndex);
2049 if (oCount > dupCount) {
2050 missing.fSegment = this;
2051 missing.fT = thisSpan->fT;
2052 other->checkLinks(&oSpan, &missingSpans);
2054 missing.fSegment = other;
2055 missing.fT = oSpan.fT;
2056 checkLinks(thisSpan, &missingSpans);
2058 if (!missingSpans.back().fOther) {
2059 missingSpans.pop_back();
2062 } while (++index < endIndex);
2063 } while (!endFound);
2064 int missingCount = missingSpans.count();
2065 if (missingCount == 0) {
2068 SkSTArray<kMissingSpanCount, MissingSpan, true> missingCoincidence;
2069 for (index = 0; index < missingCount; ++index) {
2070 MissingSpan& missing = missingSpans[index];
2071 SkOpSegment* missingOther = missing.fOther;
2072 if (missing.fSegment == missing.fOther) {
2075 #if 0 // FIXME: this eliminates spurious data from skpwww_argus_presse_fr_41 but breaks
2076 // skpwww_fashionscandal_com_94 -- calcAngles complains, but I don't understand why
2077 if (missing.fSegment->containsT(missing.fT, missing.fOther, missing.fOtherT)) {
2078 #if DEBUG_DUPLICATES
2079 SkDebugf("skip 1 id=%d t=%1.9g other=%d otherT=%1.9g\n", missing.fSegment->fID,
2080 missing.fT, missing.fOther->fID, missing.fOtherT);
2084 if (missing.fOther->containsT(missing.fOtherT, missing.fSegment, missing.fT)) {
2085 #if DEBUG_DUPLICATES
2086 SkDebugf("skip 2 id=%d t=%1.9g other=%d otherT=%1.9g\n", missing.fOther->fID,
2087 missing.fOtherT, missing.fSegment->fID, missing.fT);
2092 // skip if adding would insert point into an existing coincindent span
2093 if (missing.fSegment->inCoincidentSpan(missing.fT, missingOther)
2094 && missingOther->inCoincidentSpan(missing.fOtherT, this)) {
2097 // skip if the created coincident spans are small
2098 if (missing.fSegment->coincidentSmall(missing.fPt, missing.fT, missingOther)
2099 && missingOther->coincidentSmall(missing.fPt, missing.fOtherT, missing.fSegment)) {
2102 const SkOpSpan* added = missing.fSegment->addTPair(missing.fT, missingOther,
2103 missing.fOtherT, false, missing.fPt);
2104 if (added && added->fSmall) {
2105 missing.fSegment->checkSmallCoincidence(*added, &missingCoincidence);
2108 for (index = 0; index < missingCount; ++index) {
2109 MissingSpan& missing = missingSpans[index];
2110 missing.fSegment->fixOtherTIndex();
2111 missing.fOther->fixOtherTIndex();
2113 for (index = 0; index < missingCoincidence.count(); ++index) {
2114 MissingSpan& missing = missingCoincidence[index];
2115 missing.fSegment->fixOtherTIndex();
2120 // look to see if the curve end intersects an intermediary that intersects the other
2121 void SkOpSegment::checkEnds() {
2123 SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans;
2124 int count = fTs.count();
2125 for (int index = 0; index < count; ++index) {
2126 const SkOpSpan& span = fTs[index];
2127 double otherT = span.fOtherT;
2128 if (otherT != 0 && otherT != 1) { // only check ends
2131 const SkOpSegment* other = span.fOther;
2132 // peek start/last describe the range of spans that match the other t of this span
2133 int peekStart = span.fOtherIndex;
2134 while (--peekStart >= 0 && other->fTs[peekStart].fT == otherT)
2136 int otherCount = other->fTs.count();
2137 int peekLast = span.fOtherIndex;
2138 while (++peekLast < otherCount && other->fTs[peekLast].fT == otherT)
2140 if (++peekStart == --peekLast) { // if there isn't a range, there's nothing to do
2143 // t start/last describe the range of spans that match the t of this span
2145 double tBottom = -1;
2148 bool lastSmall = false;
2150 for (int inner = 0; inner < count; ++inner) {
2151 double innerT = fTs[inner].fT;
2152 if (innerT <= t && innerT > tBottom) {
2153 if (innerT < t || !lastSmall) {
2158 if (innerT > afterT) {
2159 if (t == afterT && lastSmall) {
2166 lastSmall = innerT <= t ? fTs[inner].fSmall : false;
2168 for (int peekIndex = peekStart; peekIndex <= peekLast; ++peekIndex) {
2169 if (peekIndex == span.fOtherIndex) { // skip the other span pointed to by this span
2172 const SkOpSpan& peekSpan = other->fTs[peekIndex];
2173 SkOpSegment* match = peekSpan.fOther;
2174 if (match->done()) {
2175 continue; // if the edge has already been eaten (likely coincidence), ignore it
2177 const double matchT = peekSpan.fOtherT;
2178 // see if any of the spans match the other spans
2179 for (int tIndex = tStart + 1; tIndex < tLast; ++tIndex) {
2180 const SkOpSpan& tSpan = fTs[tIndex];
2181 if (tSpan.fOther == match) {
2182 if (tSpan.fOtherT == matchT) {
2185 double midT = (tSpan.fOtherT + matchT) / 2;
2186 if (match->betweenPoints(midT, tSpan.fPt, peekSpan.fPt)) {
2191 if (missingSpans.count() > 0) {
2192 const MissingSpan& lastMissing = missingSpans.back();
2193 if (lastMissing.fT == t
2194 && lastMissing.fOther == match
2195 && lastMissing.fOtherT == matchT) {
2196 SkASSERT(lastMissing.fPt == peekSpan.fPt);
2200 #if DEBUG_CHECK_ENDS
2201 SkDebugf("%s id=%d missing t=%1.9g other=%d otherT=%1.9g pt=(%1.9g,%1.9g)\n",
2202 __FUNCTION__, fID, t, match->fID, matchT, peekSpan.fPt.fX, peekSpan.fPt.fY);
2204 // this segment is missing a entry that the other contains
2205 // remember so we can add the missing one and recompute the indices
2207 MissingSpan& missing = missingSpans.push_back();
2208 SkDEBUGCODE(sk_bzero(&missing, sizeof(missing)));
2210 SkASSERT(this != match);
2211 missing.fOther = match;
2212 missing.fOtherT = matchT;
2213 missing.fPt = peekSpan.fPt;
2220 if (missingSpans.count() == 0) {
2225 int missingCount = missingSpans.count();
2226 for (int index = 0; index < missingCount; ++index) {
2227 MissingSpan& missing = missingSpans[index];
2228 if (this != missing.fOther) {
2229 addTPair(missing.fT, missing.fOther, missing.fOtherT, false, missing.fPt);
2233 // OPTIMIZATION: this may fix indices more than once. Build an array of unique segments to
2235 for (int index = 0; index < missingCount; ++index) {
2236 missingSpans[index].fOther->fixOtherTIndex();
2241 void SkOpSegment::checkLinks(const SkOpSpan* base,
2242 SkTArray<MissingSpan, true>* missingSpans) const {
2243 const SkOpSpan* first = fTs.begin();
2244 const SkOpSpan* last = fTs.end() - 1;
2245 SkASSERT(base >= first && last >= base);
2246 const SkOpSegment* other = base->fOther;
2247 const SkOpSpan* oFirst = other->fTs.begin();
2248 const SkOpSpan* oLast = other->fTs.end() - 1;
2249 const SkOpSpan* oSpan = &other->fTs[base->fOtherIndex];
2250 const SkOpSpan* test = base;
2251 const SkOpSpan* missing = NULL;
2252 while (test > first && (--test)->fPt == base->fPt) {
2253 if (this == test->fOther) {
2256 CheckOneLink(test, oSpan, oFirst, oLast, &missing, missingSpans);
2259 while (test < last && (++test)->fPt == base->fPt) {
2260 SkASSERT(this != test->fOther);
2261 CheckOneLink(test, oSpan, oFirst, oLast, &missing, missingSpans);
2265 // see if spans with two or more intersections all agree on common t and point values
2266 void SkOpSegment::checkMultiples() {
2270 while (fTs[++end].fT == 0)
2272 while (fTs[end].fT < 1) {
2273 int start = index = end;
2274 end = nextExactSpan(index, 1);
2276 return; // buffer overflow example triggers this
2278 if (index + 1 == end) {
2281 // force the duplicates to agree on t and pt if not on the end
2282 SkOpSpan& span = fTs[index];
2283 double thisT = span.fT;
2284 const SkPoint& thisPt = span.fPt;
2285 span.fMultiple = true;
2286 bool aligned = false;
2287 while (++index < end) {
2288 aligned |= alignSpan(index, thisT, thisPt);
2291 alignSpanState(start, end);
2298 void SkOpSegment::CheckOneLink(const SkOpSpan* test, const SkOpSpan* oSpan,
2299 const SkOpSpan* oFirst, const SkOpSpan* oLast, const SkOpSpan** missingPtr,
2300 SkTArray<MissingSpan, true>* missingSpans) {
2301 SkASSERT(oSpan->fPt == test->fPt);
2302 const SkOpSpan* oTest = oSpan;
2303 while (oTest > oFirst && (--oTest)->fPt == test->fPt) {
2304 if (oTest->fOther == test->fOther && oTest->fOtherT == test->fOtherT) {
2309 while (oTest < oLast && (++oTest)->fPt == test->fPt) {
2310 if (oTest->fOther == test->fOther && oTest->fOtherT == test->fOtherT) {
2315 missingSpans->push_back();
2317 MissingSpan& lastMissing = missingSpans->back();
2319 lastMissing = missingSpans->end()[-2];
2322 lastMissing.fOther = test->fOther;
2323 lastMissing.fOtherT = test->fOtherT;
2326 bool SkOpSegment::checkSmall(int index) const {
2327 if (fTs[index].fSmall) {
2330 double tBase = fTs[index].fT;
2331 while (index > 0 && precisely_negative(tBase - fTs[--index].fT))
2333 return fTs[index].fSmall;
2336 // a pair of curves may turn into coincident lines -- small may be a hint that that happened
2337 // if a cubic contains a loop, the counts must be adjusted
2338 void SkOpSegment::checkSmall() {
2339 SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans;
2340 const SkOpSpan* beginSpan = fTs.begin();
2341 const SkOpSpan* thisSpan = beginSpan - 1;
2342 const SkOpSpan* endSpan = fTs.end() - 1; // last can't be small
2343 while (++thisSpan < endSpan) {
2344 if (!thisSpan->fSmall) {
2347 if (!thisSpan->fWindValue) {
2350 const SkOpSpan& firstSpan = this->firstSpan(*thisSpan);
2351 const SkOpSpan& lastSpan = this->lastSpan(*thisSpan);
2352 const SkOpSpan* nextSpan = &firstSpan + 1;
2353 ptrdiff_t smallCount = &lastSpan - &firstSpan + 1;
2354 SkASSERT(1 <= smallCount && smallCount < count());
2355 if (smallCount <= 1 && !nextSpan->fSmall) {
2356 SkASSERT(1 == smallCount);
2357 checkSmallCoincidence(firstSpan, NULL);
2360 // at this point, check for missing computed intersections
2361 const SkPoint& testPt = firstSpan.fPt;
2362 thisSpan = &firstSpan - 1;
2363 SkOpSegment* other = NULL;
2364 while (++thisSpan <= &lastSpan) {
2365 other = thisSpan->fOther;
2366 if (other != this) {
2370 SkASSERT(other != this);
2371 int oIndex = thisSpan->fOtherIndex;
2372 const SkOpSpan& oSpan = other->span(oIndex);
2373 const SkOpSpan& oFirstSpan = other->firstSpan(oSpan);
2374 const SkOpSpan& oLastSpan = other->lastSpan(oSpan);
2375 ptrdiff_t oCount = &oLastSpan - &oFirstSpan + 1;
2378 SkASSERT(!other->fLoop); // FIXME: we need more complicated logic for pair of loops
2379 if (calcLoopSpanCount(*thisSpan, smallCounts)) {
2380 if (smallCounts[0] && oCount != smallCounts[0]) {
2381 SkASSERT(0); // FIXME: need a working test case to properly code & debug
2383 if (smallCounts[1] && oCount != smallCounts[1]) {
2384 SkASSERT(0); // FIXME: need a working test case to properly code & debug
2386 goto nextSmallCheck;
2391 if (other->calcLoopSpanCount(other->span(oIndex), otherCounts)) {
2392 if (otherCounts[0] && otherCounts[0] != smallCount) {
2393 SkASSERT(0); // FIXME: need a working test case to properly code & debug
2395 if (otherCounts[1] && otherCounts[1] != smallCount) {
2396 SkASSERT(0); // FIXME: need a working test case to properly code & debug
2398 goto nextSmallCheck;
2401 if (oCount != smallCount) { // check if number of pts in this match other
2402 MissingSpan& missing = missingSpans.push_back();
2403 missing.fOther = NULL;
2404 SkDEBUGCODE(sk_bzero(&missing, sizeof(missing)));
2405 missing.fPt = testPt;
2406 const SkOpSpan& oSpan = other->span(oIndex);
2407 if (oCount > smallCount) {
2408 missing.fSegment = this;
2409 missing.fT = thisSpan->fT;
2410 other->checkLinks(&oSpan, &missingSpans);
2412 missing.fSegment = other;
2413 missing.fT = oSpan.fT;
2414 checkLinks(thisSpan, &missingSpans);
2416 if (!missingSpans.back().fOther || missing.fSegment->done()) {
2417 missingSpans.pop_back();
2421 thisSpan = &lastSpan;
2423 int missingCount = missingSpans.count();
2424 for (int index = 0; index < missingCount; ++index) {
2425 MissingSpan& missing = missingSpans[index];
2426 SkOpSegment* missingOther = missing.fOther;
2427 // note that add t pair may edit span arrays, so prior pointers to spans are no longer valid
2428 if (!missing.fSegment->addTPair(missing.fT, missingOther, missing.fOtherT, false,
2432 int otherTIndex = missingOther->findT(missing.fOtherT, missing.fPt, missing.fSegment);
2433 const SkOpSpan& otherSpan = missingOther->span(otherTIndex);
2434 if (otherSpan.fSmall) {
2435 const SkOpSpan* nextSpan = &otherSpan;
2438 } while (nextSpan->fSmall);
2439 SkAssertResult(missing.fSegment->addTCoincident(missing.fPt, nextSpan->fPt,
2440 nextSpan->fT, missingOther));
2441 } else if (otherSpan.fT > 0) {
2442 const SkOpSpan* priorSpan = &otherSpan;
2445 } while (priorSpan->fT == otherSpan.fT);
2446 if (priorSpan->fSmall) {
2447 missing.fSegment->addTCancel(missing.fPt, priorSpan->fPt, missingOther);
2451 // OPTIMIZATION: this may fix indices more than once. Build an array of unique segments to
2453 for (int index = 0; index < missingCount; ++index) {
2454 MissingSpan& missing = missingSpans[index];
2455 missing.fSegment->fixOtherTIndex();
2456 missing.fOther->fixOtherTIndex();
2461 void SkOpSegment::checkSmallCoincidence(const SkOpSpan& span,
2462 SkTArray<MissingSpan, true>* checkMultiple) {
2463 SkASSERT(span.fSmall);
2464 if (0 && !span.fWindValue) {
2467 SkASSERT(&span < fTs.end() - 1);
2468 const SkOpSpan* next = &span + 1;
2469 SkASSERT(!next->fSmall || checkMultiple);
2470 if (checkMultiple) {
2471 while (next->fSmall) {
2473 SkASSERT(next < fTs.end());
2476 SkOpSegment* other = span.fOther;
2477 while (other != next->fOther) {
2478 if (!checkMultiple) {
2481 const SkOpSpan* test = next + 1;
2482 if (test == fTs.end()) {
2485 if (test->fPt != next->fPt || !precisely_equal(test->fT, next->fT)) {
2490 SkASSERT(span.fT < next->fT);
2491 int oStartIndex = other->findExactT(span.fOtherT, this);
2492 int oEndIndex = other->findExactT(next->fOtherT, this);
2493 // FIXME: be overly conservative by limiting this to the caller that allows multiple smalls
2494 if (!checkMultiple || fVerb != SkPath::kLine_Verb || other->fVerb != SkPath::kLine_Verb) {
2495 SkPoint mid = ptAtT((span.fT + next->fT) / 2);
2496 const SkOpSpan& oSpanStart = other->fTs[oStartIndex];
2497 const SkOpSpan& oSpanEnd = other->fTs[oEndIndex];
2498 SkPoint oMid = other->ptAtT((oSpanStart.fT + oSpanEnd.fT) / 2);
2499 if (!SkDPoint::ApproximatelyEqual(mid, oMid)) {
2503 // FIXME: again, be overly conservative to avoid breaking existing tests
2504 const SkOpSpan& oSpan = oStartIndex < oEndIndex ? other->fTs[oStartIndex]
2505 : other->fTs[oEndIndex];
2506 if (checkMultiple && !oSpan.fSmall) {
2509 // SkASSERT(oSpan.fSmall);
2510 if (oStartIndex < oEndIndex) {
2511 SkAssertResult(addTCoincident(span.fPt, next->fPt, next->fT, other));
2513 addTCancel(span.fPt, next->fPt, other);
2515 if (!checkMultiple) {
2518 // check to see if either segment is coincident with a third segment -- if it is, and if
2519 // the opposite segment is not already coincident with the third, make it so
2520 // OPTIMIZE: to make this check easier, add coincident and cancel could set a coincident bit
2521 if (span.fWindValue != 1 || span.fOppValue != 0) {
2523 // iterate through the spans, looking for the third coincident case
2524 // if we find one, we need to return state to the caller so that the indices can be fixed
2525 // this also suggests that all of this function is fragile since it relies on a valid index
2527 // probably should make this a common function rather than copy/paste code
2528 if (oSpan.fWindValue != 1 || oSpan.fOppValue != 0) {
2529 const SkOpSpan* oTest = &oSpan;
2530 while (--oTest >= other->fTs.begin()) {
2531 if (oTest->fPt != oSpan.fPt || !precisely_equal(oTest->fT, oSpan.fT)) {
2534 SkOpSegment* testOther = oTest->fOther;
2535 SkASSERT(testOther != this);
2536 // look in both directions to see if there is a coincident span
2537 const SkOpSpan* tTest = testOther->fTs.begin();
2538 for (int testIndex = 0; testIndex < testOther->count(); ++testIndex) {
2539 if (tTest->fPt != span.fPt) {
2543 if (testOther->verb() != SkPath::kLine_Verb
2544 || other->verb() != SkPath::kLine_Verb) {
2545 SkPoint mid = ptAtT((span.fT + next->fT) / 2);
2546 SkPoint oMid = other->ptAtT((oTest->fOtherT + tTest->fT) / 2);
2547 if (!SkDPoint::ApproximatelyEqual(mid, oMid)) {
2552 SkDebugf("%s coincident found=%d %1.9g %1.9g\n", __FUNCTION__, testOther->fID,
2553 oTest->fOtherT, tTest->fT);
2555 if (tTest->fT < oTest->fOtherT) {
2556 SkAssertResult(addTCoincident(span.fPt, next->fPt, next->fT, testOther));
2558 addTCancel(span.fPt, next->fPt, testOther);
2560 MissingSpan missing;
2561 missing.fSegment = testOther;
2562 checkMultiple->push_back(missing);
2567 while (++oTest < other->fTs.end()) {
2568 if (oTest->fPt != oSpan.fPt || !precisely_equal(oTest->fT, oSpan.fT)) {
2576 // if pair of spans on either side of tiny have the same end point and mid point, mark
2578 void SkOpSegment::checkTiny() {
2579 SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans;
2580 SkOpSpan* thisSpan = fTs.begin() - 1;
2581 const SkOpSpan* endSpan = fTs.end() - 1; // last can't be tiny
2582 while (++thisSpan < endSpan) {
2583 if (!thisSpan->fTiny) {
2586 SkOpSpan* nextSpan = thisSpan + 1;
2587 double thisT = thisSpan->fT;
2588 double nextT = nextSpan->fT;
2589 if (thisT == nextT) {
2592 SkASSERT(thisT < nextT);
2593 SkASSERT(thisSpan->fPt == nextSpan->fPt);
2594 SkOpSegment* thisOther = thisSpan->fOther;
2595 SkOpSegment* nextOther = nextSpan->fOther;
2596 int oIndex = thisSpan->fOtherIndex;
2597 for (int oStep = -1; oStep <= 1; oStep += 2) {
2598 int oEnd = thisOther->nextExactSpan(oIndex, oStep);
2602 const SkOpSpan& oSpan = thisOther->span(oEnd);
2603 int nIndex = nextSpan->fOtherIndex;
2604 for (int nStep = -1; nStep <= 1; nStep += 2) {
2605 int nEnd = nextOther->nextExactSpan(nIndex, nStep);
2609 const SkOpSpan& nSpan = nextOther->span(nEnd);
2610 if (oSpan.fPt != nSpan.fPt) {
2613 double oMidT = (thisSpan->fOtherT + oSpan.fT) / 2;
2614 const SkPoint& oPt = thisOther->ptAtT(oMidT);
2615 double nMidT = (nextSpan->fOtherT + nSpan.fT) / 2;
2616 const SkPoint& nPt = nextOther->ptAtT(nMidT);
2617 if (!AlmostEqualUlps(oPt, nPt)) {
2620 #if DEBUG_CHECK_TINY
2621 SkDebugf("%s [%d] add coincidence [%d] [%d]\n", __FUNCTION__, fID,
2622 thisOther->fID, nextOther->fID);
2624 // this segment is missing a entry that the other contains
2625 // remember so we can add the missing one and recompute the indices
2626 MissingSpan& missing = missingSpans.push_back();
2627 SkDEBUGCODE(sk_bzero(&missing, sizeof(missing)));
2628 missing.fSegment = thisOther;
2629 missing.fT = thisSpan->fOtherT;
2630 SkASSERT(this != nextOther);
2631 missing.fOther = nextOther;
2632 missing.fOtherT = nextSpan->fOtherT;
2633 missing.fPt = thisSpan->fPt;
2637 int missingCount = missingSpans.count();
2638 if (!missingCount) {
2641 for (int index = 0; index < missingCount; ++index) {
2642 MissingSpan& missing = missingSpans[index];
2643 if (missing.fSegment != missing.fOther) {
2644 missing.fSegment->addTPair(missing.fT, missing.fOther, missing.fOtherT, false,
2648 // OPTIMIZE: consolidate to avoid multiple calls to fix index
2649 for (int index = 0; index < missingCount; ++index) {
2650 MissingSpan& missing = missingSpans[index];
2651 missing.fSegment->fixOtherTIndex();
2652 missing.fOther->fixOtherTIndex();
2656 bool SkOpSegment::coincidentSmall(const SkPoint& pt, double t, const SkOpSegment* other) const {
2657 int count = this->count();
2658 for (int index = 0; index < count; ++index) {
2659 const SkOpSpan& span = this->span(index);
2660 if (span.fOther != other) {
2663 if (span.fPt == pt) {
2666 if (!AlmostEqualUlps(span.fPt, pt)) {
2669 if (fVerb != SkPath::kCubic_Verb) {
2672 double tInterval = t - span.fT;
2673 double tMid = t - tInterval / 2;
2674 SkDPoint midPt = dcubic_xy_at_t(fPts, tMid);
2675 return midPt.approximatelyEqual(xyAtT(t));
2680 bool SkOpSegment::findCoincidentMatch(const SkOpSpan* span, const SkOpSegment* other, int oStart,
2681 int oEnd, int step, SkPoint* startPt, SkPoint* endPt, double* endT) const {
2682 SkASSERT(span->fT == 0 || span->fT == 1);
2683 SkASSERT(span->fOtherT == 0 || span->fOtherT == 1);
2684 const SkOpSpan* otherSpan = &other->span(oEnd);
2685 double refT = otherSpan->fT;
2686 const SkPoint& refPt = otherSpan->fPt;
2687 const SkOpSpan* lastSpan = &other->span(step > 0 ? other->count() - 1 : 0);
2689 const SkOpSegment* match = span->fOther;
2690 if (match == otherSpan->fOther) {
2691 // find start of respective spans and see if both have winding
2692 int startIndex, endIndex;
2693 if (span->fOtherT == 1) {
2694 endIndex = span->fOtherIndex;
2695 startIndex = match->nextExactSpan(endIndex, -1);
2697 startIndex = span->fOtherIndex;
2698 endIndex = match->nextExactSpan(startIndex, 1);
2700 const SkOpSpan& startSpan = match->span(startIndex);
2701 if (startSpan.fWindValue != 0) {
2702 // draw ray from endSpan.fPt perpendicular to end tangent and measure distance
2703 // to other segment.
2704 const SkOpSpan& endSpan = match->span(endIndex);
2707 if (span->fOtherT == 1) {
2708 ray.fPts[0].set(startSpan.fPt);
2709 dxdy = match->dxdy(startIndex);
2711 ray.fPts[0].set(endSpan.fPt);
2712 dxdy = match->dxdy(endIndex);
2714 ray.fPts[1].fX = ray.fPts[0].fX + dxdy.fY;
2715 ray.fPts[1].fY = ray.fPts[0].fY - dxdy.fX;
2717 int roots = (i.*CurveRay[SkPathOpsVerbToPoints(other->verb())])(other->pts(), ray);
2718 for (int index = 0; index < roots; ++index) {
2719 if (ray.fPts[0].approximatelyEqual(i.pt(index))) {
2720 double matchMidT = (match->span(startIndex).fT
2721 + match->span(endIndex).fT) / 2;
2722 SkPoint matchMidPt = match->ptAtT(matchMidT);
2723 double otherMidT = (i[0][index] + other->span(oStart).fT) / 2;
2724 SkPoint otherMidPt = other->ptAtT(otherMidT);
2725 if (SkDPoint::ApproximatelyEqual(matchMidPt, otherMidPt)) {
2726 *startPt = startSpan.fPt;
2727 *endPt = endSpan.fPt;
2736 if (otherSpan == lastSpan) {
2740 } while (otherSpan->fT == refT || otherSpan->fPt == refPt);
2744 int SkOpSegment::findEndSpan(int endIndex) const {
2745 const SkOpSpan* span = &fTs[--endIndex];
2746 const SkPoint& lastPt = span->fPt;
2747 double endT = span->fT;
2749 span = &fTs[--endIndex];
2750 } while (SkDPoint::ApproximatelyEqual(span->fPt, lastPt) && (span->fT == endT || span->fTiny));
2751 return endIndex + 1;
2755 The M and S variable name parts stand for the operators.
2756 Mi stands for Minuend (see wiki subtraction, analogous to difference)
2757 Su stands for Subtrahend
2758 The Opp variable name part designates that the value is for the Opposite operator.
2759 Opposite values result from combining coincident spans.
2761 SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpan*>* chase, int* nextStart, int* nextEnd,
2762 bool* unsortable, SkPathOp op, const int xorMiMask,
2763 const int xorSuMask) {
2764 const int startIndex = *nextStart;
2765 const int endIndex = *nextEnd;
2766 SkASSERT(startIndex != endIndex);
2767 SkDEBUGCODE(const int count = fTs.count());
2768 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
2769 int step = SkSign32(endIndex - startIndex);
2770 *nextStart = startIndex;
2771 SkOpSegment* other = isSimple(nextStart, &step);
2774 // mark the smaller of startIndex, endIndex done, and all adjacent
2775 // spans with the same T value (but not 'other' spans)
2777 SkDebugf("%s simple\n", __FUNCTION__);
2779 int min = SkMin32(startIndex, endIndex);
2780 if (fTs[min].fDone) {
2783 markDoneBinary(min);
2784 double startT = other->fTs[*nextStart].fT;
2785 *nextEnd = *nextStart;
2788 } while (precisely_zero(startT - other->fTs[*nextEnd].fT));
2789 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count());
2790 if (other->isTiny(SkMin32(*nextStart, *nextEnd))) {
2796 const int end = nextExactSpan(startIndex, step);
2798 SkASSERT(startIndex - endIndex != 0);
2799 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2800 // more than one viable candidate -- measure angles to find best
2802 int calcWinding = computeSum(startIndex, end, SkOpAngle::kBinaryOpp);
2803 bool sortable = calcWinding != SK_NaN32;
2806 markDoneBinary(SkMin32(startIndex, endIndex));
2809 SkOpAngle* angle = spanToAngle(end, startIndex);
2810 if (angle->unorderable()) {
2812 markDoneBinary(SkMin32(startIndex, endIndex));
2816 SkDebugf("%s\n", __FUNCTION__);
2819 int sumMiWinding = updateWinding(endIndex, startIndex);
2820 if (sumMiWinding == SK_MinS32) {
2822 markDoneBinary(SkMin32(startIndex, endIndex));
2825 int sumSuWinding = updateOppWinding(endIndex, startIndex);
2827 SkTSwap<int>(sumMiWinding, sumSuWinding);
2829 SkOpAngle* nextAngle = angle->next();
2830 const SkOpAngle* foundAngle = NULL;
2831 bool foundDone = false;
2832 // iterate through the angle, and compute everyone's winding
2833 SkOpSegment* nextSegment;
2834 int activeCount = 0;
2836 nextSegment = nextAngle->segment();
2837 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
2838 nextAngle->end(), op, &sumMiWinding, &sumSuWinding);
2841 if (!foundAngle || (foundDone && activeCount & 1)) {
2842 if (nextSegment->isTiny(nextAngle)) {
2844 markDoneBinary(SkMin32(startIndex, endIndex));
2847 foundAngle = nextAngle;
2848 foundDone = nextSegment->done(nextAngle);
2851 if (nextSegment->done()) {
2854 if (nextSegment->isTiny(nextAngle)) {
2858 (void) nextSegment->markAndChaseDoneBinary(nextAngle->start(), nextAngle->end());
2860 SkOpSpan* last = nextAngle->lastMarked();
2862 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
2863 *chase->append() = last;
2865 SkDebugf("%s chase.append id=%d windSum=%d small=%d\n", __FUNCTION__,
2866 last->fOther->fTs[last->fOtherIndex].fOther->debugID(), last->fWindSum,
2870 } while ((nextAngle = nextAngle->next()) != angle);
2873 foundAngle->debugSameAs(foundAngle);
2877 markDoneBinary(SkMin32(startIndex, endIndex));
2881 *nextStart = foundAngle->start();
2882 *nextEnd = foundAngle->end();
2883 nextSegment = foundAngle->segment();
2885 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2886 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
2891 SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpan*>* chase, int* nextStart,
2892 int* nextEnd, bool* unsortable) {
2893 const int startIndex = *nextStart;
2894 const int endIndex = *nextEnd;
2895 SkASSERT(startIndex != endIndex);
2896 SkDEBUGCODE(const int count = fTs.count());
2897 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
2898 int step = SkSign32(endIndex - startIndex);
2899 *nextStart = startIndex;
2900 SkOpSegment* other = isSimple(nextStart, &step);
2903 // mark the smaller of startIndex, endIndex done, and all adjacent
2904 // spans with the same T value (but not 'other' spans)
2906 SkDebugf("%s simple\n", __FUNCTION__);
2908 int min = SkMin32(startIndex, endIndex);
2909 if (fTs[min].fDone) {
2913 double startT = other->fTs[*nextStart].fT;
2914 *nextEnd = *nextStart;
2917 } while (precisely_zero(startT - other->fTs[*nextEnd].fT));
2918 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count());
2919 if (other->isTiny(SkMin32(*nextStart, *nextEnd))) {
2925 const int end = nextExactSpan(startIndex, step);
2927 SkASSERT(startIndex - endIndex != 0);
2928 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
2929 // more than one viable candidate -- measure angles to find best
2931 int calcWinding = computeSum(startIndex, end, SkOpAngle::kUnaryWinding);
2932 bool sortable = calcWinding != SK_NaN32;
2935 markDoneUnary(SkMin32(startIndex, endIndex));
2938 SkOpAngle* angle = spanToAngle(end, startIndex);
2940 SkDebugf("%s\n", __FUNCTION__);
2943 int sumWinding = updateWinding(endIndex, startIndex);
2944 SkOpAngle* nextAngle = angle->next();
2945 const SkOpAngle* foundAngle = NULL;
2946 bool foundDone = false;
2947 SkOpSegment* nextSegment;
2948 int activeCount = 0;
2950 nextSegment = nextAngle->segment();
2951 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
2955 if (!foundAngle || (foundDone && activeCount & 1)) {
2956 if (nextSegment->isTiny(nextAngle)) {
2958 markDoneUnary(SkMin32(startIndex, endIndex));
2961 foundAngle = nextAngle;
2962 foundDone = nextSegment->done(nextAngle);
2965 if (nextSegment->done()) {
2968 if (nextSegment->isTiny(nextAngle)) {
2972 nextSegment->markAndChaseDoneUnary(nextAngle->start(), nextAngle->end());
2974 SkOpSpan* last = nextAngle->lastMarked();
2976 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
2977 *chase->append() = last;
2979 SkDebugf("%s chase.append id=%d windSum=%d small=%d\n", __FUNCTION__,
2980 last->fOther->fTs[last->fOtherIndex].fOther->debugID(), last->fWindSum,
2984 } while ((nextAngle = nextAngle->next()) != angle);
2985 markDoneUnary(SkMin32(startIndex, endIndex));
2989 *nextStart = foundAngle->start();
2990 *nextEnd = foundAngle->end();
2991 nextSegment = foundAngle->segment();
2993 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
2994 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
2999 SkOpSegment* SkOpSegment::findNextXor(int* nextStart, int* nextEnd, bool* unsortable) {
3000 const int startIndex = *nextStart;
3001 const int endIndex = *nextEnd;
3002 SkASSERT(startIndex != endIndex);
3003 SkDEBUGCODE(int count = fTs.count());
3004 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
3005 int step = SkSign32(endIndex - startIndex);
3006 // Detect cases where all the ends canceled out (e.g.,
3007 // there is no angle) and therefore there's only one valid connection
3008 *nextStart = startIndex;
3009 SkOpSegment* other = isSimple(nextStart, &step);
3013 SkDebugf("%s simple\n", __FUNCTION__);
3015 int min = SkMin32(startIndex, endIndex);
3016 if (fTs[min].fDone) {
3020 double startT = other->fTs[*nextStart].fT;
3021 // FIXME: I don't know why the logic here is difference from the winding case
3022 SkDEBUGCODE(bool firstLoop = true;)
3023 if ((approximately_less_than_zero(startT) && step < 0)
3024 || (approximately_greater_than_one(startT) && step > 0)) {
3026 SkDEBUGCODE(firstLoop = false;)
3029 *nextEnd = *nextStart;
3032 } while (precisely_zero(startT - other->fTs[*nextEnd].fT));
3033 if (other->fTs[SkMin32(*nextStart, *nextEnd)].fWindValue) {
3036 SkASSERT(firstLoop);
3037 SkDEBUGCODE(firstLoop = false;)
3040 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count());
3043 SkASSERT(startIndex - endIndex != 0);
3044 SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
3045 // parallel block above with presorted version
3046 int end = nextExactSpan(startIndex, step);
3048 SkOpAngle* angle = spanToAngle(end, startIndex);
3051 SkDebugf("%s\n", __FUNCTION__);
3054 SkOpAngle* nextAngle = angle->next();
3055 const SkOpAngle* foundAngle = NULL;
3056 bool foundDone = false;
3057 SkOpSegment* nextSegment;
3058 int activeCount = 0;
3060 nextSegment = nextAngle->segment();
3062 if (!foundAngle || (foundDone && activeCount & 1)) {
3063 if (nextSegment->isTiny(nextAngle)) {
3067 foundAngle = nextAngle;
3068 if (!(foundDone = nextSegment->done(nextAngle))) {
3072 nextAngle = nextAngle->next();
3073 } while (nextAngle != angle);
3074 markDone(SkMin32(startIndex, endIndex), 1);
3078 *nextStart = foundAngle->start();
3079 *nextEnd = foundAngle->end();
3080 nextSegment = foundAngle->segment();
3082 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
3083 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
3088 int SkOpSegment::findStartSpan(int startIndex) const {
3089 int index = startIndex;
3090 const SkOpSpan* span = &fTs[index];
3091 const SkPoint& firstPt = span->fPt;
3092 double firstT = span->fT;
3093 const SkOpSpan* prior;
3096 span = &fTs[++index];
3097 } while (SkDPoint::ApproximatelyEqual(span->fPt, firstPt)
3098 && (span->fT == firstT || prior->fTiny));
3102 int SkOpSegment::findExactT(double t, const SkOpSegment* match) const {
3103 int count = this->count();
3104 for (int index = 0; index < count; ++index) {
3105 const SkOpSpan& span = fTs[index];
3106 if (span.fT == t && span.fOther == match) {
3114 int SkOpSegment::findOtherT(double t, const SkOpSegment* match) const {
3115 int count = this->count();
3116 for (int index = 0; index < count; ++index) {
3117 const SkOpSpan& span = fTs[index];
3118 if (span.fOtherT == t && span.fOther == match) {
3125 int SkOpSegment::findT(double t, const SkPoint& pt, const SkOpSegment* match) const {
3126 int count = this->count();
3127 // prefer exact matches over approximate matches
3128 for (int index = 0; index < count; ++index) {
3129 const SkOpSpan& span = fTs[index];
3130 if (span.fT == t && span.fOther == match) {
3134 for (int index = 0; index < count; ++index) {
3135 const SkOpSpan& span = fTs[index];
3136 if (approximately_equal_orderable(span.fT, t) && span.fOther == match) {
3140 // Usually, the pair of ts are an exact match. It's possible that the t values have
3141 // been adjusted to make multiple intersections align. In this rare case, look for a
3142 // matching point / match pair instead.
3143 for (int index = 0; index < count; ++index) {
3144 const SkOpSpan& span = fTs[index];
3145 if (span.fPt == pt && span.fOther == match) {
3153 SkOpSegment* SkOpSegment::findTop(int* tIndexPtr, int* endIndexPtr, bool* unsortable,
3155 // iterate through T intersections and return topmost
3156 // topmost tangent from y-min to first pt is closer to horizontal
3159 /* SkPoint topPt = */ activeLeftTop(&firstT);
3161 *unsortable = !firstPass;
3163 while (fTs[firstT].fDone) {
3164 SkASSERT(firstT < fTs.count());
3167 *tIndexPtr = firstT;
3168 *endIndexPtr = nextExactSpan(firstT, 1);
3171 // sort the edges to find the leftmost
3174 if (span(firstT).fDone || (end = nextSpan(firstT, step)) == -1) {
3176 end = nextSpan(firstT, step);
3177 SkASSERT(end != -1);
3179 // if the topmost T is not on end, or is three-way or more, find left
3180 // look for left-ness from tLeft to firstT (matching y of other)
3181 SkASSERT(firstT - end != 0);
3182 SkOpAngle* markAngle = spanToAngle(firstT, end);
3184 markAngle = addSingletonAngles(step);
3186 markAngle->markStops();
3187 const SkOpAngle* baseAngle = markAngle->next() == markAngle && !isVertical() ? markAngle
3188 : markAngle->findFirst();
3190 return NULL; // nothing to do
3192 SkScalar top = SK_ScalarMax;
3193 const SkOpAngle* firstAngle = NULL;
3194 const SkOpAngle* angle = baseAngle;
3196 if (!angle->unorderable()) {
3197 SkOpSegment* next = angle->segment();
3198 SkPathOpsBounds bounds;
3199 next->subDivideBounds(angle->end(), angle->start(), &bounds);
3200 if (approximately_greater(top, bounds.fTop)) {
3205 angle = angle->next();
3206 } while (angle != baseAngle);
3207 SkASSERT(firstAngle);
3209 SkDebugf("%s\n", __FUNCTION__);
3210 firstAngle->debugLoop();
3212 // skip edges that have already been processed
3214 SkOpSegment* leftSegment = NULL;
3215 bool looped = false;
3217 *unsortable = angle->unorderable();
3218 if (firstPass || !*unsortable) {
3219 leftSegment = angle->segment();
3220 *tIndexPtr = angle->end();
3221 *endIndexPtr = angle->start();
3222 if (!leftSegment->fTs[SkMin32(*tIndexPtr, *endIndexPtr)].fDone) {
3226 angle = angle->next();
3228 } while (angle != firstAngle);
3229 if (angle == firstAngle && looped) {
3232 if (leftSegment->verb() >= SkPath::kQuad_Verb) {
3233 const int tIndex = *tIndexPtr;
3234 const int endIndex = *endIndexPtr;
3236 if (!leftSegment->clockwise(tIndex, endIndex, &swap)) {
3238 SkDebugf("%s swap=%d inflections=%d serpentine=%d controlledbyends=%d monotonic=%d\n",
3240 swap, leftSegment->debugInflections(tIndex, endIndex),
3241 leftSegment->serpentine(tIndex, endIndex),
3242 leftSegment->controlsContainedByEnds(tIndex, endIndex),
3243 leftSegment->monotonicInY(tIndex, endIndex));
3246 // FIXME: I doubt it makes sense to (necessarily) swap if the edge was not the first
3247 // sorted but merely the first not already processed (i.e., not done)
3248 SkTSwap(*tIndexPtr, *endIndexPtr);
3252 SkASSERT(!leftSegment->fTs[SkMin32(*tIndexPtr, *endIndexPtr)].fTiny);
3256 int SkOpSegment::firstActive(int tIndex) const {
3257 while (fTs[tIndex].fTiny) {
3258 SkASSERT(!isCanceled(tIndex));
3264 // FIXME: not crazy about this
3265 // when the intersections are performed, the other index is into an
3266 // incomplete array. As the array grows, the indices become incorrect
3267 // while the following fixes the indices up again, it isn't smart about
3268 // skipping segments whose indices are already correct
3269 // assuming we leave the code that wrote the index in the first place
3270 // FIXME: if called after remove, this needs to correct tiny
3271 void SkOpSegment::fixOtherTIndex() {
3272 int iCount = fTs.count();
3273 for (int i = 0; i < iCount; ++i) {
3274 SkOpSpan& iSpan = fTs[i];
3275 double oT = iSpan.fOtherT;
3276 SkOpSegment* other = iSpan.fOther;
3277 int oCount = other->fTs.count();
3278 SkDEBUGCODE(iSpan.fOtherIndex = -1);
3279 for (int o = 0; o < oCount; ++o) {
3280 SkOpSpan& oSpan = other->fTs[o];
3281 if (oT == oSpan.fT && this == oSpan.fOther && oSpan.fOtherT == iSpan.fT) {
3282 iSpan.fOtherIndex = o;
3283 oSpan.fOtherIndex = i;
3287 SkASSERT(iSpan.fOtherIndex >= 0);
3291 bool SkOpSegment::inCoincidentSpan(double t, const SkOpSegment* other) const {
3293 int count = this->count();
3294 for (int index = 0; index < count; ++index) {
3295 const SkOpSpan& span = this->span(index);
3296 if (span.fCoincident) {
3297 foundEnds |= (span.fOther == other) << ((t > span.fT) + (t >= span.fT));
3300 SkASSERT(foundEnds != 7);
3301 return foundEnds == 0x3 || foundEnds == 0x5 || foundEnds == 0x6; // two bits set
3304 void SkOpSegment::init(const SkPoint pts[], SkPath::Verb verb, bool operand, bool evenOdd) {
3310 fLoop = fMultiples = fSmall = fTiny = false;
3313 void SkOpSegment::initWinding(int start, int end, SkOpAngle::IncludeType angleIncludeType) {
3314 int local = spanSign(start, end);
3315 if (angleIncludeType == SkOpAngle::kBinarySingle) {
3316 int oppLocal = oppSign(start, end);
3317 (void) markAndChaseWinding(start, end, local, oppLocal);
3318 // OPTIMIZATION: the reverse mark and chase could skip the first marking
3319 (void) markAndChaseWinding(end, start, local, oppLocal);
3321 (void) markAndChaseWinding(start, end, local);
3322 // OPTIMIZATION: the reverse mark and chase could skip the first marking
3323 (void) markAndChaseWinding(end, start, local);
3328 when we start with a vertical intersect, we try to use the dx to determine if the edge is to
3329 the left or the right of vertical. This determines if we need to add the span's
3330 sign or not. However, this isn't enough.
3331 If the supplied sign (winding) is zero, then we didn't hit another vertical span, so dx is needed.
3332 If there was a winding, then it may or may not need adjusting. If the span the winding was borrowed
3333 from has the same x direction as this span, the winding should change. If the dx is opposite, then
3334 the same winding is shared by both.
3336 void SkOpSegment::initWinding(int start, int end, double tHit, int winding, SkScalar hitDx,
3337 int oppWind, SkScalar hitOppDx) {
3338 SkASSERT(hitDx || !winding);
3339 SkScalar dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, tHit).fX;
3341 int windVal = windValue(SkMin32(start, end));
3342 #if DEBUG_WINDING_AT_T
3343 SkDebugf("%s id=%d oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, debugID(), winding,
3344 hitDx ? hitDx > 0 ? '+' : '-' : '0', dx > 0 ? '+' : '-', windVal);
3346 int sideWind = winding + (dx < 0 ? windVal : -windVal);
3347 if (abs(winding) < abs(sideWind)) {
3350 SkDEBUGCODE(int oppLocal = oppSign(start, end));
3351 SkASSERT(hitOppDx || !oppWind || !oppLocal);
3352 int oppWindVal = oppValue(SkMin32(start, end));
3354 oppWind = dx < 0 ? oppWindVal : -oppWindVal;
3355 } else if (hitOppDx * dx >= 0) {
3356 int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal);
3357 if (abs(oppWind) < abs(oppSideWind)) {
3358 oppWind = oppSideWind;
3361 #if DEBUG_WINDING_AT_T
3362 SkDebugf(" winding=%d oppWind=%d\n", winding, oppWind);
3364 (void) markAndChaseWinding(start, end, winding, oppWind);
3365 // OPTIMIZATION: the reverse mark and chase could skip the first marking
3366 (void) markAndChaseWinding(end, start, winding, oppWind);
3369 bool SkOpSegment::inLoop(const SkOpAngle* baseAngle, int spanCount, int* indexPtr) const {
3370 if (!baseAngle->inLoop()) {
3373 int index = *indexPtr;
3374 SkOpAngle* from = fTs[index].fFromAngle;
3375 SkOpAngle* to = fTs[index].fToAngle;
3376 while (++index < spanCount) {
3377 SkOpAngle* nextFrom = fTs[index].fFromAngle;
3378 SkOpAngle* nextTo = fTs[index].fToAngle;
3379 if (from != nextFrom || to != nextTo) {
3387 // OPTIMIZE: successive calls could start were the last leaves off
3388 // or calls could specialize to walk forwards or backwards
3389 bool SkOpSegment::isMissing(double startT, const SkPoint& pt) const {
3390 int tCount = fTs.count();
3391 for (int index = 0; index < tCount; ++index) {
3392 const SkOpSpan& span = fTs[index];
3393 if (approximately_zero(startT - span.fT) && pt == span.fPt) {
3401 SkOpSegment* SkOpSegment::isSimple(int* end, int* step) {
3402 return nextChase(end, step, NULL, NULL);
3405 bool SkOpSegment::isTiny(const SkOpAngle* angle) const {
3406 int start = angle->start();
3407 int end = angle->end();
3408 const SkOpSpan& mSpan = fTs[SkMin32(start, end)];
3412 bool SkOpSegment::isTiny(int index) const {
3413 return fTs[index].fTiny;
3416 // look pair of active edges going away from coincident edge
3417 // one of them should be the continuation of other
3418 // if both are active, look to see if they both the connect to another coincident pair
3419 // if at least one is a line, then make the pair coincident
3420 // if neither is a line, test for coincidence
3421 bool SkOpSegment::joinCoincidence(SkOpSegment* other, double otherT, const SkPoint& otherPt,
3422 int step, bool cancel) {
3423 int otherTIndex = other->findT(otherT, otherPt, this);
3424 int next = other->nextExactSpan(otherTIndex, step);
3425 int otherMin = SkMin32(otherTIndex, next);
3426 int otherWind = other->span(otherMin).fWindValue;
3427 if (otherWind == 0) {
3430 SkASSERT(next >= 0);
3433 SkOpSpan* test = &fTs[tIndex];
3434 SkASSERT(test->fT == 0);
3435 if (test->fOther == other || test->fOtherT != 1) {
3438 SkPoint startPt, endPt;
3440 if (findCoincidentMatch(test, other, otherTIndex, next, step, &startPt, &endPt, &endT)) {
3441 SkOpSegment* match = test->fOther;
3443 match->addTCancel(startPt, endPt, other);
3445 SkAssertResult(match->addTCoincident(startPt, endPt, endT, other));
3449 } while (fTs[++tIndex].fT == 0);
3453 // this span is excluded by the winding rule -- chase the ends
3454 // as long as they are unambiguous to mark connections as done
3455 // and give them the same winding value
3457 SkOpSpan* SkOpSegment::markAndChaseDoneBinary(int index, int endIndex) {
3458 int step = SkSign32(endIndex - index);
3459 int min = SkMin32(index, endIndex);
3460 markDoneBinary(min);
3461 SkOpSpan* last = NULL;
3462 SkOpSegment* other = this;
3463 while ((other = other->nextChase(&index, &step, &min, &last))) {
3464 if (other->done()) {
3468 other->markDoneBinary(min);
3473 SkOpSpan* SkOpSegment::markAndChaseDoneUnary(int index, int endIndex) {
3474 int step = SkSign32(endIndex - index);
3475 int min = SkMin32(index, endIndex);
3477 SkOpSpan* last = NULL;
3478 SkOpSegment* other = this;
3479 while ((other = other->nextChase(&index, &step, &min, &last))) {
3480 if (other->done()) {
3484 other->markDoneUnary(min);
3489 SkOpSpan* SkOpSegment::markAndChaseWinding(const SkOpAngle* angle, int winding) {
3490 int index = angle->start();
3491 int endIndex = angle->end();
3492 int step = SkSign32(endIndex - index);
3493 int min = SkMin32(index, endIndex);
3494 markWinding(min, winding);
3495 SkOpSpan* last = NULL;
3496 SkOpSegment* other = this;
3497 while ((other = other->nextChase(&index, &step, &min, &last))) {
3498 if (other->fTs[min].fWindSum != SK_MinS32) {
3499 // SkASSERT(other->fTs[min].fWindSum == winding);
3503 other->markWinding(min, winding);
3508 SkOpSpan* SkOpSegment::markAndChaseWinding(int index, int endIndex, int winding) {
3509 int min = SkMin32(index, endIndex);
3510 int step = SkSign32(endIndex - index);
3511 markWinding(min, winding);
3512 SkOpSpan* last = NULL;
3513 SkOpSegment* other = this;
3514 while ((other = other->nextChase(&index, &step, &min, &last))) {
3515 if (other->fTs[min].fWindSum != SK_MinS32) {
3516 SkASSERT(other->fTs[min].fWindSum == winding || other->fTs[min].fLoop);
3520 other->markWinding(min, winding);
3525 SkOpSpan* SkOpSegment::markAndChaseWinding(int index, int endIndex, int winding, int oppWinding) {
3526 int min = SkMin32(index, endIndex);
3527 int step = SkSign32(endIndex - index);
3528 markWinding(min, winding, oppWinding);
3529 SkOpSpan* last = NULL;
3530 SkOpSegment* other = this;
3531 while ((other = other->nextChase(&index, &step, &min, &last))) {
3532 if (other->fTs[min].fWindSum != SK_MinS32) {
3534 if (!other->fTs[min].fLoop) {
3535 if (fOperand == other->fOperand) {
3536 // FIXME: this is probably a bug -- rects4 asserts here
3537 // SkASSERT(other->fTs[min].fWindSum == winding);
3538 // FIXME: this is probably a bug -- rects3 asserts here
3539 // SkASSERT(other->fTs[min].fOppSum == oppWinding);
3541 // FIXME: this is probably a bug -- issue414409b asserts here
3542 // SkASSERT(other->fTs[min].fWindSum == oppWinding);
3543 // FIXME: this is probably a bug -- skpwww_joomla_org_23 asserts here
3544 // SkASSERT(other->fTs[min].fOppSum == winding);
3551 if (fOperand == other->fOperand) {
3552 other->markWinding(min, winding, oppWinding);
3554 other->markWinding(min, oppWinding, winding);
3560 SkOpSpan* SkOpSegment::markAndChaseWinding(const SkOpAngle* angle, int winding, int oppWinding) {
3561 int start = angle->start();
3562 int end = angle->end();
3563 return markAndChaseWinding(start, end, winding, oppWinding);
3566 SkOpSpan* SkOpSegment::markAngle(int maxWinding, int sumWinding, const SkOpAngle* angle) {
3567 SkASSERT(angle->segment() == this);
3568 if (UseInnerWinding(maxWinding, sumWinding)) {
3569 maxWinding = sumWinding;
3571 SkOpSpan* last = markAndChaseWinding(angle, maxWinding);
3574 SkDebugf("%s last id=%d windSum=", __FUNCTION__,
3575 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
3576 SkPathOpsDebug::WindingPrintf(last->fWindSum);
3577 SkDebugf(" small=%d\n", last->fSmall);
3583 SkOpSpan* SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWinding,
3584 int oppSumWinding, const SkOpAngle* angle) {
3585 SkASSERT(angle->segment() == this);
3586 if (UseInnerWinding(maxWinding, sumWinding)) {
3587 maxWinding = sumWinding;
3589 if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumWinding)) {
3590 oppMaxWinding = oppSumWinding;
3592 SkOpSpan* last = markAndChaseWinding(angle, maxWinding, oppMaxWinding);
3595 SkDebugf("%s last id=%d windSum=", __FUNCTION__,
3596 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
3597 SkPathOpsDebug::WindingPrintf(last->fWindSum);
3598 SkDebugf(" small=%d\n", last->fSmall);
3604 // FIXME: this should also mark spans with equal (x,y)
3605 // This may be called when the segment is already marked done. While this
3606 // wastes time, it shouldn't do any more than spin through the T spans.
3607 // OPTIMIZATION: abort on first done found (assuming that this code is
3608 // always called to mark segments done).
3609 void SkOpSegment::markDone(int index, int winding) {
3610 // SkASSERT(!done());
3612 double referenceT = fTs[index].fT;
3614 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3615 markOneDone(__FUNCTION__, lesser, winding);
3618 markOneDone(__FUNCTION__, index, winding);
3619 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3623 void SkOpSegment::markDoneBinary(int index) {
3624 double referenceT = fTs[index].fT;
3626 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3627 markOneDoneBinary(__FUNCTION__, lesser);
3630 markOneDoneBinary(__FUNCTION__, index);
3631 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3635 void SkOpSegment::markDoneUnary(int index) {
3636 double referenceT = fTs[index].fT;
3638 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3639 markOneDoneUnary(__FUNCTION__, lesser);
3642 markOneDoneUnary(__FUNCTION__, index);
3643 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3647 void SkOpSegment::markOneDone(const char* funName, int tIndex, int winding) {
3648 SkOpSpan* span = markOneWinding(funName, tIndex, winding);
3649 if (!span || span->fDone) {
3656 void SkOpSegment::markOneDoneBinary(const char* funName, int tIndex) {
3657 SkOpSpan* span = verifyOneWinding(funName, tIndex);
3661 SkASSERT(!span->fDone);
3666 void SkOpSegment::markOneDoneUnary(const char* funName, int tIndex) {
3667 SkOpSpan* span = verifyOneWindingU(funName, tIndex);
3671 if (span->fWindSum == SK_MinS32) {
3672 SkDebugf("%s uncomputed\n", __FUNCTION__);
3674 SkASSERT(!span->fDone);
3679 SkOpSpan* SkOpSegment::markOneWinding(const char* funName, int tIndex, int winding) {
3680 SkOpSpan& span = fTs[tIndex];
3681 if (span.fDone && !span.fSmall) {
3685 debugShowNewWinding(funName, span, winding);
3687 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
3688 #if DEBUG_LIMIT_WIND_SUM
3689 SkASSERT(abs(winding) <= DEBUG_LIMIT_WIND_SUM);
3691 span.fWindSum = winding;
3695 SkOpSpan* SkOpSegment::markOneWinding(const char* funName, int tIndex, int winding,
3697 SkOpSpan& span = fTs[tIndex];
3698 if (span.fDone && !span.fSmall) {
3702 debugShowNewWinding(funName, span, winding, oppWinding);
3704 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
3705 #if DEBUG_LIMIT_WIND_SUM
3706 SkASSERT(abs(winding) <= DEBUG_LIMIT_WIND_SUM);
3708 span.fWindSum = winding;
3709 SkASSERT(span.fOppSum == SK_MinS32 || span.fOppSum == oppWinding);
3710 #if DEBUG_LIMIT_WIND_SUM
3711 SkASSERT(abs(oppWinding) <= DEBUG_LIMIT_WIND_SUM);
3713 span.fOppSum = oppWinding;
3718 // from http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of-polygon-points-are-in-clockwise-order
3719 bool SkOpSegment::clockwise(int tStart, int tEnd, bool* swap) const {
3720 SkASSERT(fVerb != SkPath::kLine_Verb);
3722 subDivide(tStart, tEnd, edge);
3723 int points = SkPathOpsVerbToPoints(fVerb);
3724 double sum = (edge[0].fX - edge[points].fX) * (edge[0].fY + edge[points].fY);
3725 bool sumSet = false;
3726 if (fVerb == SkPath::kCubic_Verb) {
3729 double inflectionTs[2];
3730 int inflections = cubic.findInflections(inflectionTs);
3731 // FIXME: this fixes cubicOp114 and breaks cubicOp58d
3732 // the trouble is that cubics with inflections confuse whether the curve breaks towards
3733 // or away, which in turn is used to determine if it is on the far right or left.
3734 // Probably a totally different approach is in order. At one time I tried to project a
3735 // horizontal ray to determine winding, but was confused by how to map the vertically
3736 // oriented winding computation over.
3737 if (0 && inflections) {
3738 double tLo = this->span(tStart).fT;
3739 double tHi = this->span(tEnd).fT;
3740 double tLoStart = tLo;
3741 for (int index = 0; index < inflections; ++index) {
3742 if (between(tLo, inflectionTs[index], tHi)) {
3743 tLo = inflectionTs[index];
3746 if (tLo != tLoStart && tLo != tHi) {
3748 sub[0] = cubic.ptAtT(tLo);
3749 sub[1].set(edge[3]);
3751 SkDCubic::SubDivide(fPts, sub[0], sub[1], tLo, tHi, ctrl);
3752 edge[0] = sub[0].asSkPoint();
3753 edge[1] = ctrl[0].asSkPoint();
3754 edge[2] = ctrl[1].asSkPoint();
3755 sum = (edge[0].fX - edge[3].fX) * (edge[0].fY + edge[3].fY);
3758 SkScalar lesser = SkTMin<SkScalar>(edge[0].fY, edge[3].fY);
3759 if (edge[1].fY < lesser && edge[2].fY < lesser) {
3760 SkDLine tangent1 = {{ {edge[0].fX, edge[0].fY}, {edge[1].fX, edge[1].fY} }};
3761 SkDLine tangent2 = {{ {edge[2].fX, edge[2].fY}, {edge[3].fX, edge[3].fY} }};
3762 if (SkIntersections::Test(tangent1, tangent2)) {
3763 SkPoint topPt = cubic_top(fPts, fTs[tStart].fT, fTs[tEnd].fT);
3764 sum += (topPt.fX - edge[0].fX) * (topPt.fY + edge[0].fY);
3765 sum += (edge[3].fX - topPt.fX) * (edge[3].fY + topPt.fY);
3771 for (int idx = 0; idx < points; ++idx){
3772 sum += (edge[idx + 1].fX - edge[idx].fX) * (edge[idx + 1].fY + edge[idx].fY);
3775 if (fVerb == SkPath::kCubic_Verb) {
3778 *swap = sum > 0 && !cubic.monotonicInY() && !cubic.serpentine();
3782 *swap = sum > 0 && !quad.monotonicInY();
3787 bool SkOpSegment::monotonicInY(int tStart, int tEnd) const {
3788 SkASSERT(fVerb != SkPath::kLine_Verb);
3789 if (fVerb == SkPath::kQuad_Verb) {
3790 SkDQuad dst = SkDQuad::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
3791 return dst.monotonicInY();
3793 SkASSERT(fVerb == SkPath::kCubic_Verb);
3794 SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
3795 return dst.monotonicInY();
3798 bool SkOpSegment::serpentine(int tStart, int tEnd) const {
3799 if (fVerb != SkPath::kCubic_Verb) {
3802 SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
3803 return dst.serpentine();
3806 SkOpSpan* SkOpSegment::verifyOneWinding(const char* funName, int tIndex) {
3807 SkOpSpan& span = fTs[tIndex];
3812 debugShowNewWinding(funName, span, span.fWindSum, span.fOppSum);
3814 // If the prior angle in the sort is unorderable, the winding sum may not be computable.
3815 // To enable the assert, the 'prior is unorderable' state could be
3816 // piped down to this test, but not sure it's worth it.
3817 // (Once the sort order is stored in the span, this test may be feasible.)
3818 // SkASSERT(span.fWindSum != SK_MinS32);
3819 // SkASSERT(span.fOppSum != SK_MinS32);
3823 SkOpSpan* SkOpSegment::verifyOneWindingU(const char* funName, int tIndex) {
3824 SkOpSpan& span = fTs[tIndex];
3829 debugShowNewWinding(funName, span, span.fWindSum);
3831 // If the prior angle in the sort is unorderable, the winding sum may not be computable.
3832 // To enable the assert, the 'prior is unorderable' state could be
3833 // piped down to this test, but not sure it's worth it.
3834 // (Once the sort order is stored in the span, this test may be feasible.)
3835 // SkASSERT(span.fWindSum != SK_MinS32);
3839 void SkOpSegment::markWinding(int index, int winding) {
3840 // SkASSERT(!done());
3842 double referenceT = fTs[index].fT;
3844 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3845 markOneWinding(__FUNCTION__, lesser, winding);
3848 markOneWinding(__FUNCTION__, index, winding);
3849 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3853 void SkOpSegment::markWinding(int index, int winding, int oppWinding) {
3854 // SkASSERT(!done());
3855 SkASSERT(winding || oppWinding);
3856 double referenceT = fTs[index].fT;
3858 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3859 markOneWinding(__FUNCTION__, lesser, winding, oppWinding);
3862 markOneWinding(__FUNCTION__, index, winding, oppWinding);
3863 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
3867 void SkOpSegment::matchWindingValue(int tIndex, double t, bool borrowWind) {
3868 int nextDoorWind = SK_MaxS32;
3869 int nextOppWind = SK_MaxS32;
3870 // prefer exact matches
3872 const SkOpSpan& below = fTs[tIndex - 1];
3873 if (below.fT == t) {
3874 nextDoorWind = below.fWindValue;
3875 nextOppWind = below.fOppValue;
3878 if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) {
3879 const SkOpSpan& above = fTs[tIndex + 1];
3880 if (above.fT == t) {
3881 nextDoorWind = above.fWindValue;
3882 nextOppWind = above.fOppValue;
3885 if (nextDoorWind == SK_MaxS32 && tIndex > 0) {
3886 const SkOpSpan& below = fTs[tIndex - 1];
3887 if (approximately_negative(t - below.fT)) {
3888 nextDoorWind = below.fWindValue;
3889 nextOppWind = below.fOppValue;
3892 if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) {
3893 const SkOpSpan& above = fTs[tIndex + 1];
3894 if (approximately_negative(above.fT - t)) {
3895 nextDoorWind = above.fWindValue;
3896 nextOppWind = above.fOppValue;
3899 if (nextDoorWind == SK_MaxS32 && borrowWind && tIndex > 0 && t < 1) {
3900 const SkOpSpan& below = fTs[tIndex - 1];
3901 nextDoorWind = below.fWindValue;
3902 nextOppWind = below.fOppValue;
3904 if (nextDoorWind != SK_MaxS32) {
3905 SkOpSpan& newSpan = fTs[tIndex];
3906 newSpan.fWindValue = nextDoorWind;
3907 newSpan.fOppValue = nextOppWind;
3908 if (!nextDoorWind && !nextOppWind && !newSpan.fDone) {
3909 newSpan.fDone = true;
3915 bool SkOpSegment::nextCandidate(int* start, int* end) const {
3916 while (fTs[*end].fDone) {
3917 if (fTs[*end].fT == 1) {
3923 *end = nextExactSpan(*start, 1);
3927 static SkOpSegment* set_last(SkOpSpan** last, SkOpSpan* endSpan) {
3928 if (last && !endSpan->fSmall) {
3934 SkOpSegment* SkOpSegment::nextChase(int* indexPtr, int* stepPtr, int* minPtr, SkOpSpan** last) {
3935 int origIndex = *indexPtr;
3936 int step = *stepPtr;
3937 int end = nextExactSpan(origIndex, step);
3939 SkOpSpan& endSpan = fTs[end];
3940 SkOpAngle* angle = step > 0 ? endSpan.fFromAngle : endSpan.fToAngle;
3944 if (angle == NULL) {
3945 if (endSpan.fT != 0 && endSpan.fT != 1) {
3948 other = endSpan.fOther;
3949 foundIndex = endSpan.fOtherIndex;
3950 otherEnd = other->nextExactSpan(foundIndex, step);
3952 int loopCount = angle->loopCount();
3953 if (loopCount > 2) {
3954 return set_last(last, &endSpan);
3956 const SkOpAngle* next = angle->next();
3960 if (angle->sign() != next->sign()) {
3962 SkDebugf("%s mismatched signs\n", __FUNCTION__);
3964 // return set_last(last, &endSpan);
3966 other = next->segment();
3967 foundIndex = end = next->start();
3968 otherEnd = next->end();
3970 int foundStep = foundIndex < otherEnd ? 1 : -1;
3971 if (*stepPtr != foundStep) {
3972 return set_last(last, &endSpan);
3974 SkASSERT(*indexPtr >= 0);
3978 // SkASSERT(otherEnd >= 0);
3980 int origMin = origIndex + (step < 0 ? step : 0);
3981 const SkOpSpan& orig = this->span(origMin);
3983 int foundMin = SkMin32(foundIndex, otherEnd);
3985 const SkOpSpan& found = other->span(foundMin);
3986 if (found.fWindValue != orig.fWindValue || found.fOppValue != orig.fOppValue) {
3987 return set_last(last, &endSpan);
3990 *indexPtr = foundIndex;
3991 *stepPtr = foundStep;
3998 // This has callers for two different situations: one establishes the end
3999 // of the current span, and one establishes the beginning of the next span
4000 // (thus the name). When this is looking for the end of the current span,
4001 // coincidence is found when the beginning Ts contain -step and the end
4002 // contains step. When it is looking for the beginning of the next, the
4003 // first Ts found can be ignored and the last Ts should contain -step.
4004 // OPTIMIZATION: probably should split into two functions
4005 int SkOpSegment::nextSpan(int from, int step) const {
4006 const SkOpSpan& fromSpan = fTs[from];
4007 int count = fTs.count();
4009 while (step > 0 ? ++to < count : --to >= 0) {
4010 const SkOpSpan& span = fTs[to];
4011 if (approximately_zero(span.fT - fromSpan.fT)) {
4020 // this returns at any difference in T, vs. a preset minimum. It may be
4021 // that all callers to nextSpan should use this instead.
4022 int SkOpSegment::nextExactSpan(int from, int step) const {
4025 const SkOpSpan& fromSpan = fTs[from];
4027 const SkOpSpan& span = fTs[to];
4028 if (precisely_negative(fromSpan.fT - span.fT) || span.fTiny) {
4034 while (fTs[from].fTiny) {
4037 const SkOpSpan& fromSpan = fTs[from];
4038 int count = fTs.count();
4039 while (++to < count) {
4040 const SkOpSpan& span = fTs[to];
4041 if (precisely_negative(span.fT - fromSpan.fT)) {
4050 void SkOpSegment::pinT(const SkPoint& pt, double* t) {
4051 if (pt == fPts[0]) {
4054 int count = SkPathOpsVerbToPoints(fVerb);
4055 if (pt == fPts[count]) {
4060 bool SkOpSegment::reversePoints(const SkPoint& p1, const SkPoint& p2) const {
4062 int spanCount = count();
4063 int p1IndexMin = -1;
4064 int p2IndexMax = spanCount;
4065 for (int index = 0; index < spanCount; ++index) {
4066 const SkOpSpan& span = fTs[index];
4067 if (span.fPt == p1) {
4068 if (p1IndexMin < 0) {
4071 } else if (span.fPt == p2) {
4075 return p1IndexMin > p2IndexMax;
4078 void SkOpSegment::setCoincidentRange(const SkPoint& startPt, const SkPoint& endPt,
4079 SkOpSegment* other) {
4080 int count = this->count();
4081 for (int index = 0; index < count; ++index) {
4082 SkOpSpan &span = fTs[index];
4083 if ((startPt == span.fPt || endPt == span.fPt) && other == span.fOther) {
4084 span.fCoincident = true;
4089 void SkOpSegment::setUpWindings(int index, int endIndex, int* sumMiWinding, int* sumSuWinding,
4090 int* maxWinding, int* sumWinding, int* oppMaxWinding, int* oppSumWinding) {
4091 int deltaSum = spanSign(index, endIndex);
4092 int oppDeltaSum = oppSign(index, endIndex);
4094 *maxWinding = *sumSuWinding;
4095 *sumWinding = *sumSuWinding -= deltaSum;
4096 *oppMaxWinding = *sumMiWinding;
4097 *oppSumWinding = *sumMiWinding -= oppDeltaSum;
4099 *maxWinding = *sumMiWinding;
4100 *sumWinding = *sumMiWinding -= deltaSum;
4101 *oppMaxWinding = *sumSuWinding;
4102 *oppSumWinding = *sumSuWinding -= oppDeltaSum;
4104 #if DEBUG_LIMIT_WIND_SUM
4105 SkASSERT(abs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
4106 SkASSERT(abs(*oppSumWinding) <= DEBUG_LIMIT_WIND_SUM);
4110 void SkOpSegment::setUpWindings(int index, int endIndex, int* sumMiWinding,
4111 int* maxWinding, int* sumWinding) {
4112 int deltaSum = spanSign(index, endIndex);
4113 *maxWinding = *sumMiWinding;
4114 *sumWinding = *sumMiWinding -= deltaSum;
4115 #if DEBUG_LIMIT_WIND_SUM
4116 SkASSERT(abs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
4120 void SkOpSegment::sortAngles() {
4121 int spanCount = fTs.count();
4122 if (spanCount <= 2) {
4127 SkOpAngle* fromAngle = fTs[index].fFromAngle;
4128 SkOpAngle* toAngle = fTs[index].fToAngle;
4129 if (!fromAngle && !toAngle) {
4133 SkOpAngle* baseAngle = NULL;
4135 baseAngle = fromAngle;
4136 if (inLoop(baseAngle, spanCount, &index)) {
4141 bool wroteAfterHeader = false;
4145 baseAngle = toAngle;
4146 if (inLoop(baseAngle, spanCount, &index)) {
4150 SkDEBUGCODE(int newIndex = index);
4151 SkASSERT(!inLoop(baseAngle, spanCount, &newIndex) && newIndex == index);
4153 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), fTs[index].fT,
4155 wroteAfterHeader = true;
4157 baseAngle->insert(toAngle);
4160 SkOpAngle* nextFrom, * nextTo;
4161 int firstIndex = index;
4163 SkOpSpan& span = fTs[index];
4164 SkOpSegment* other = span.fOther;
4165 SkOpSpan& oSpan = other->fTs[span.fOtherIndex];
4166 SkOpAngle* oAngle = oSpan.fFromAngle;
4169 if (!wroteAfterHeader) {
4170 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), fTs[index].fT,
4172 wroteAfterHeader = true;
4175 if (!oAngle->loopContains(*baseAngle)) {
4176 baseAngle->insert(oAngle);
4179 oAngle = oSpan.fToAngle;
4182 if (!wroteAfterHeader) {
4183 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), fTs[index].fT,
4185 wroteAfterHeader = true;
4188 if (!oAngle->loopContains(*baseAngle)) {
4189 baseAngle->insert(oAngle);
4192 if (++index == spanCount) {
4195 nextFrom = fTs[index].fFromAngle;
4196 nextTo = fTs[index].fToAngle;
4197 } while (fromAngle == nextFrom && toAngle == nextTo);
4198 if (baseAngle && baseAngle->loopCount() == 1) {
4201 SkOpSpan& span = fTs[index];
4202 span.fFromAngle = span.fToAngle = NULL;
4203 if (++index == spanCount) {
4206 nextFrom = fTs[index].fFromAngle;
4207 nextTo = fTs[index].fToAngle;
4208 } while (fromAngle == nextFrom && toAngle == nextTo);
4212 SkASSERT(!baseAngle || baseAngle->loopCount() > 1);
4214 } while (index < spanCount);
4217 // return true if midpoints were computed
4218 bool SkOpSegment::subDivide(int start, int end, SkPoint edge[4]) const {
4219 SkASSERT(start != end);
4220 edge[0] = fTs[start].fPt;
4221 int points = SkPathOpsVerbToPoints(fVerb);
4222 edge[points] = fTs[end].fPt;
4223 if (fVerb == SkPath::kLine_Verb) {
4226 double startT = fTs[start].fT;
4227 double endT = fTs[end].fT;
4228 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
4229 // don't compute midpoints if we already have them
4230 if (fVerb == SkPath::kQuad_Verb) {
4234 SkASSERT(fVerb == SkPath::kCubic_Verb);
4244 const SkDPoint sub[2] = {{ edge[0].fX, edge[0].fY}, {edge[points].fX, edge[points].fY }};
4245 if (fVerb == SkPath::kQuad_Verb) {
4246 edge[1] = SkDQuad::SubDivide(fPts, sub[0], sub[1], startT, endT).asSkPoint();
4248 SkASSERT(fVerb == SkPath::kCubic_Verb);
4250 SkDCubic::SubDivide(fPts, sub[0], sub[1], startT, endT, ctrl);
4251 edge[1] = ctrl[0].asSkPoint();
4252 edge[2] = ctrl[1].asSkPoint();
4257 // return true if midpoints were computed
4258 bool SkOpSegment::subDivide(int start, int end, SkDCubic* result) const {
4259 SkASSERT(start != end);
4260 (*result)[0].set(fTs[start].fPt);
4261 int points = SkPathOpsVerbToPoints(fVerb);
4262 (*result)[points].set(fTs[end].fPt);
4263 if (fVerb == SkPath::kLine_Verb) {
4266 double startT = fTs[start].fT;
4267 double endT = fTs[end].fT;
4268 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
4269 // don't compute midpoints if we already have them
4270 if (fVerb == SkPath::kQuad_Verb) {
4271 (*result)[1].set(fPts[1]);
4274 SkASSERT(fVerb == SkPath::kCubic_Verb);
4276 (*result)[1].set(fPts[1]);
4277 (*result)[2].set(fPts[2]);
4280 (*result)[1].set(fPts[2]);
4281 (*result)[2].set(fPts[1]);
4284 if (fVerb == SkPath::kQuad_Verb) {
4285 (*result)[1] = SkDQuad::SubDivide(fPts, (*result)[0], (*result)[2], startT, endT);
4287 SkASSERT(fVerb == SkPath::kCubic_Verb);
4288 SkDCubic::SubDivide(fPts, (*result)[0], (*result)[3], startT, endT, &(*result)[1]);
4293 void SkOpSegment::subDivideBounds(int start, int end, SkPathOpsBounds* bounds) const {
4295 subDivide(start, end, edge);
4296 (bounds->*SetCurveBounds[SkPathOpsVerbToPoints(fVerb)])(edge);
4299 void SkOpSegment::TrackOutsidePair(SkTArray<SkPoint, true>* outsidePts, const SkPoint& endPt,
4300 const SkPoint& startPt) {
4301 int outCount = outsidePts->count();
4302 if (outCount == 0 || endPt != (*outsidePts)[outCount - 2]) {
4303 outsidePts->push_back(endPt);
4304 outsidePts->push_back(startPt);
4308 void SkOpSegment::TrackOutside(SkTArray<SkPoint, true>* outsidePts, const SkPoint& startPt) {
4309 int outCount = outsidePts->count();
4310 if (outCount == 0 || startPt != (*outsidePts)[outCount - 1]) {
4311 outsidePts->push_back(startPt);
4315 void SkOpSegment::undoneSpan(int* start, int* end) {
4316 int tCount = fTs.count();
4318 for (index = 0; index < tCount; ++index) {
4319 if (!fTs[index].fDone) {
4323 SkASSERT(index < tCount - 1);
4325 double startT = fTs[index].fT;
4326 while (approximately_negative(fTs[++index].fT - startT))
4327 SkASSERT(index < tCount);
4328 SkASSERT(index < tCount);
4332 int SkOpSegment::updateOppWinding(int index, int endIndex) const {
4333 int lesser = SkMin32(index, endIndex);
4334 int oppWinding = oppSum(lesser);
4335 int oppSpanWinding = oppSign(index, endIndex);
4336 if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWinding)
4337 && oppWinding != SK_MaxS32) {
4338 oppWinding -= oppSpanWinding;
4343 int SkOpSegment::updateOppWinding(const SkOpAngle* angle) const {
4344 int startIndex = angle->start();
4345 int endIndex = angle->end();
4346 return updateOppWinding(endIndex, startIndex);
4349 int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const {
4350 int startIndex = angle->start();
4351 int endIndex = angle->end();
4352 return updateOppWinding(startIndex, endIndex);
4355 int SkOpSegment::updateWinding(int index, int endIndex) const {
4356 int lesser = SkMin32(index, endIndex);
4357 int winding = windSum(lesser);
4358 if (winding == SK_MinS32) {
4361 int spanWinding = spanSign(index, endIndex);
4362 if (winding && UseInnerWinding(winding - spanWinding, winding)
4363 && winding != SK_MaxS32) {
4364 winding -= spanWinding;
4369 int SkOpSegment::updateWinding(const SkOpAngle* angle) const {
4370 int startIndex = angle->start();
4371 int endIndex = angle->end();
4372 return updateWinding(endIndex, startIndex);
4375 int SkOpSegment::updateWindingReverse(int index, int endIndex) const {
4376 int lesser = SkMin32(index, endIndex);
4377 int winding = windSum(lesser);
4378 int spanWinding = spanSign(endIndex, index);
4379 if (winding && UseInnerWindingReverse(winding - spanWinding, winding)
4380 && winding != SK_MaxS32) {
4381 winding -= spanWinding;
4386 int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) const {
4387 int startIndex = angle->start();
4388 int endIndex = angle->end();
4389 return updateWindingReverse(endIndex, startIndex);
4392 // OPTIMIZATION: does the following also work, and is it any faster?
4393 // return outerWinding * innerWinding > 0
4394 // || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
4395 bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) {
4396 SkASSERT(outerWinding != SK_MaxS32);
4397 SkASSERT(innerWinding != SK_MaxS32);
4398 int absOut = abs(outerWinding);
4399 int absIn = abs(innerWinding);
4400 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
4404 bool SkOpSegment::UseInnerWindingReverse(int outerWinding, int innerWinding) {
4405 SkASSERT(outerWinding != SK_MaxS32);
4406 SkASSERT(innerWinding != SK_MaxS32);
4407 int absOut = abs(outerWinding);
4408 int absIn = abs(innerWinding);
4409 bool result = absOut == absIn ? true : absOut < absIn;
4413 int SkOpSegment::windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar* dx) const {
4414 if (approximately_zero(tHit - t(tIndex))) { // if we hit the end of a span, disregard
4417 int winding = crossOpp ? oppSum(tIndex) : windSum(tIndex);
4418 SkASSERT(winding != SK_MinS32);
4419 int windVal = crossOpp ? oppValue(tIndex) : windValue(tIndex);
4420 #if DEBUG_WINDING_AT_T
4421 SkDebugf("%s id=%d opp=%d tHit=%1.9g t=%1.9g oldWinding=%d windValue=%d", __FUNCTION__,
4422 debugID(), crossOpp, tHit, t(tIndex), winding, windVal);
4424 // see if a + change in T results in a +/- change in X (compute x'(T))
4425 *dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, tHit).fX;
4426 if (fVerb > SkPath::kLine_Verb && approximately_zero(*dx)) {
4427 *dx = fPts[2].fX - fPts[1].fX - *dx;
4430 #if DEBUG_WINDING_AT_T
4431 SkDebugf(" dx=0 winding=SK_MinS32\n");
4435 if (windVal < 0) { // reverse sign if opp contour traveled in reverse
4438 if (winding * *dx > 0) { // if same signs, result is negative
4439 winding += *dx > 0 ? -windVal : windVal;
4441 #if DEBUG_WINDING_AT_T
4442 SkDebugf(" dx=%c winding=%d\n", *dx > 0 ? '+' : '-', winding);
4447 int SkOpSegment::windSum(const SkOpAngle* angle) const {
4448 int start = angle->start();
4449 int end = angle->end();
4450 int index = SkMin32(start, end);
4451 return windSum(index);
4454 void SkOpSegment::zeroSpan(SkOpSpan* span) {
4455 SkASSERT(span->fWindValue > 0 || span->fOppValue != 0);
4456 span->fWindValue = 0;
4457 span->fOppValue = 0;
4458 if (span->fTiny || span->fSmall) {
4461 SkASSERT(!span->fDone);