Home | History | Annotate | Download | only in pathops
      1 /*
      2  * Copyright 2012 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 #include "SkIntersections.h"
      8 #include "SkOpContour.h"
      9 #include "SkOpSegment.h"
     10 #include "SkPathWriter.h"
     11 #include "SkTSort.h"
     12 
     13 #define F (false)      // discard the edge
     14 #define T (true)       // keep the edge
     15 
     16 static const bool gUnaryActiveEdge[2][2] = {
     17 //  from=0  from=1
     18 //  to=0,1  to=0,1
     19     {F, T}, {T, F},
     20 };
     21 
     22 static const bool gActiveEdge[kXOR_PathOp + 1][2][2][2][2] = {
     23 //                 miFrom=0                              miFrom=1
     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
     31 };
     32 
     33 #undef F
     34 #undef T
     35 
     36 enum {
     37     kOutsideTrackedTCount = 16,  // FIXME: determine what this should be
     38     kMissingSpanCount = 4,  // FIXME: determine what this should be
     39 };
     40 
     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)) {
     44         return result;
     45     }
     46     double referenceT = fTs[index].fT;
     47     int lesser = index;
     48     while (--lesser >= 0
     49             && (precisely_negative(referenceT - fTs[lesser].fT) || fTs[lesser].fTiny)) {
     50         if (const SkOpAngle* result = activeAngleOther(lesser, start, end, done, sortable)) {
     51             return result;
     52         }
     53     }
     54     do {
     55         if (const SkOpAngle* result = activeAngleOther(index, start, end, done, sortable)) {
     56             return result;
     57         }
     58         if (++index == fTs.count()) {
     59             break;
     60         }
     61         if (fTs[index - 1].fTiny) {
     62             referenceT = fTs[index].fT;
     63             continue;
     64         }
     65     } while (precisely_negative(fTs[index].fT - referenceT));
     66     return NULL;
     67 }
     68 
     69 const SkOpAngle* SkOpSegment::activeAngleInner(int index, int* start, int* end, bool* done,
     70         bool* sortable) const {
     71     int next = nextExactSpan(index, 1);
     72     if (next > 0) {
     73         const SkOpSpan& upSpan = fTs[index];
     74         if (upSpan.fWindValue || upSpan.fOppValue) {
     75             if (*end < 0) {
     76                 *start = index;
     77                 *end = next;
     78             }
     79             if (!upSpan.fDone) {
     80                 if (upSpan.fWindSum != SK_MinS32) {
     81                     return spanToAngle(index, next);
     82                 }
     83                 *done = false;
     84             }
     85         } else {
     86             SkASSERT(upSpan.fDone);
     87         }
     88     }
     89     int prev = nextExactSpan(index, -1);
     90     // edge leading into junction
     91     if (prev >= 0) {
     92         const SkOpSpan& downSpan = fTs[prev];
     93         if (downSpan.fWindValue || downSpan.fOppValue) {
     94             if (*end < 0) {
     95                 *start = index;
     96                 *end = prev;
     97             }
     98             if (!downSpan.fDone) {
     99                 if (downSpan.fWindSum != SK_MinS32) {
    100                     return spanToAngle(index, prev);
    101                 }
    102                 *done = false;
    103             }
    104         } else {
    105             SkASSERT(downSpan.fDone);
    106         }
    107     }
    108     return NULL;
    109 }
    110 
    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);
    117 }
    118 
    119 SkPoint SkOpSegment::activeLeftTop(int* firstT) const {
    120     SkASSERT(!done());
    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;
    125     double lastT = -1;
    126     for (int index = 0; index < count; ++index) {
    127         const SkOpSpan& span = fTs[index];
    128         if (span.fDone && lastDone) {
    129             goto next;
    130         }
    131         if (approximately_negative(span.fT - lastT)) {
    132             goto next;
    133         }
    134         {
    135             const SkPoint& xy = xyAtT(&span);
    136             if (topPt.fY > xy.fY || (topPt.fY == xy.fY && topPt.fX > xy.fX)) {
    137                 topPt = xy;
    138                 if (firstT) {
    139                     *firstT = index;
    140                 }
    141             }
    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)) {
    146                     topPt = curveTop;
    147                     if (firstT) {
    148                         *firstT = index;
    149                     }
    150                 }
    151             }
    152             lastT = span.fT;
    153         }
    154 next:
    155         lastDone = span.fDone;
    156     }
    157     return topPt;
    158 }
    159 
    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);
    163     if (fOperand) {
    164         SkTSwap<int>(sumMiWinding, sumSuWinding);
    165     }
    166     return activeOp(xorMiMask, xorSuMask, index, endIndex, op, &sumMiWinding, &sumSuWinding);
    167 }
    168 
    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);
    174     bool miFrom;
    175     bool miTo;
    176     bool suFrom;
    177     bool suTo;
    178     if (operand()) {
    179         miFrom = (oppMaxWinding & xorMiMask) != 0;
    180         miTo = (oppSumWinding & xorMiMask) != 0;
    181         suFrom = (maxWinding & xorSuMask) != 0;
    182         suTo = (sumWinding & xorSuMask) != 0;
    183     } else {
    184         miFrom = (maxWinding & xorMiMask) != 0;
    185         miTo = (sumWinding & xorMiMask) != 0;
    186         suFrom = (oppMaxWinding & xorSuMask) != 0;
    187         suTo = (oppSumWinding & xorSuMask) != 0;
    188     }
    189     bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo];
    190 #if DEBUG_ACTIVE_OP
    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);
    194 #endif
    195     return result;
    196 }
    197 
    198 bool SkOpSegment::activeWinding(int index, int endIndex) {
    199     int sumWinding = updateWinding(endIndex, index);
    200     return activeWinding(index, endIndex, &sumWinding);
    201 }
    202 
    203 bool SkOpSegment::activeWinding(int index, int endIndex, int* sumWinding) {
    204     int maxWinding;
    205     setUpWinding(index, endIndex, &maxWinding, sumWinding);
    206     bool from = maxWinding != 0;
    207     bool to = *sumWinding  != 0;
    208     bool result = gUnaryActiveEdge[from][to];
    209     return result;
    210 }
    211 
    212 void SkOpSegment::addCancelOutsides(const SkPoint& startPt, const SkPoint& endPt,
    213         SkOpSegment* other) {
    214     int tIndex = -1;
    215     int tCount = fTs.count();
    216     int oIndex = -1;
    217     int oCount = other->fTs.count();
    218     do {
    219         ++tIndex;
    220     } while (startPt != fTs[tIndex].fPt && tIndex < tCount);
    221     int tIndexStart = tIndex;
    222     do {
    223         ++oIndex;
    224     } while (endPt != other->fTs[oIndex].fPt && oIndex < oCount);
    225     int oIndexStart = oIndex;
    226     const SkPoint* nextPt;
    227     do {
    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;
    233     do {
    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
    242 
    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) {
    248 #if DEBUG_CONCIDENT
    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);
    253 #endif
    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);
    256         }
    257         if (nextT < 1 && fTs[tIndex].fWindValue) {
    258 #if DEBUG_CONCIDENT
    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,
    262                     xyAtT(tIndex).fY);
    263 #endif
    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);
    266         }
    267     } else {
    268         SkASSERT(!other->fTs[oIndexStart].fWindValue);
    269         if (oIndexStart > 0 && other->fTs[oIndexStart - 1].fWindValue) {
    270 #if DEBUG_CONCIDENT
    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);
    276 #endif
    277         }
    278         if (oNextT < 1 && other->fTs[oIndex].fWindValue) {
    279 #if DEBUG_CONCIDENT
    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);
    285 #endif
    286         }
    287     }
    288 }
    289 
    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
    295     int tIndex = -1;
    296     int oIndex = -1;
    297     do {
    298         ++tIndex;
    299     } while (startPt != fTs[tIndex].fPt);
    300     int ttIndex = tIndex;
    301     bool checkOtherTMatch = false;
    302     do {
    303         const SkOpSpan& span = fTs[ttIndex];
    304         if (startPt != span.fPt) {
    305             break;
    306         }
    307         if (span.fOther == other && span.fPt == startPt) {
    308             checkOtherTMatch = true;
    309             break;
    310         }
    311     } while (++ttIndex < count());
    312     do {
    313         ++oIndex;
    314     } while (startPt != other->fTs[oIndex].fPt);
    315     bool skipAdd = false;
    316     if (checkOtherTMatch) {
    317         int ooIndex = oIndex;
    318         do {
    319             const SkOpSpan& oSpan = other->fTs[ooIndex];
    320             if (startPt != oSpan.fPt) {
    321                 break;
    322             }
    323             if (oSpan.fT == fTs[ttIndex].fOtherT) {
    324                 skipAdd = true;
    325                 break;
    326             }
    327         } while (++ooIndex < other->count());
    328     }
    329     if ((tIndex > 0 || oIndex > 0 || fOperand != other->fOperand) && !skipAdd) {
    330         addTPair(fTs[tIndex].fT, other, other->fTs[oIndex].fT, false, startPt);
    331     }
    332     SkPoint nextPt = startPt;
    333     do {
    334         const SkPoint* workPt;
    335         do {
    336             workPt = &fTs[++tIndex].fPt;
    337         } while (nextPt == *workPt);
    338         const SkPoint* oWorkPt;
    339         do {
    340             oWorkPt = &other->fTs[++oIndex].fPt;
    341         } while (nextPt == *oWorkPt);
    342         nextPt = *workPt;
    343         double tStart = fTs[tIndex].fT;
    344         double oStart = other->fTs[oIndex].fT;
    345         if (tStart == 1 && oStart == 1 && fOperand == other->fOperand) {
    346             break;
    347         }
    348         if (*workPt == *oWorkPt) {
    349             addTPair(tStart, other, oStart, false, nextPt);
    350         }
    351     } while (endPt != nextPt);
    352 }
    353 
    354 void SkOpSegment::addCubic(const SkPoint pts[4], bool operand, bool evenOdd) {
    355     init(pts, SkPath::kCubic_Verb, operand, evenOdd);
    356     fBounds.setCubicBounds(pts);
    357 }
    358 
    359 void SkOpSegment::addCurveTo(int start, int end, SkPathWriter* path, bool active) const {
    360     SkPoint edge[4];
    361     const SkPoint* ePtr;
    362     int lastT = fTs.count() - 1;
    363     if (lastT < 0 || (start == 0 && end == lastT) || (start == lastT && end == 0)) {
    364         ePtr = fPts;
    365     } else {
    366     // OPTIMIZE? if not active, skip remainder and return xyAtT(end)
    367         subDivide(start, end, edge);
    368         ePtr = edge;
    369     }
    370     if (active) {
    371         bool reverse = ePtr == fPts && start != 0;
    372         if (reverse) {
    373             path->deferredMoveLine(ePtr[SkPathOpsVerbToPoints(fVerb)]);
    374             switch (fVerb) {
    375                 case SkPath::kLine_Verb:
    376                     path->deferredLine(ePtr[0]);
    377                     break;
    378                 case SkPath::kQuad_Verb:
    379                     path->quadTo(ePtr[1], ePtr[0]);
    380                     break;
    381                 case SkPath::kCubic_Verb:
    382                     path->cubicTo(ePtr[2], ePtr[1], ePtr[0]);
    383                     break;
    384                 default:
    385                     SkASSERT(0);
    386             }
    387    //         return ePtr[0];
    388        } else {
    389             path->deferredMoveLine(ePtr[0]);
    390             switch (fVerb) {
    391                 case SkPath::kLine_Verb:
    392                     path->deferredLine(ePtr[1]);
    393                     break;
    394                 case SkPath::kQuad_Verb:
    395                     path->quadTo(ePtr[1], ePtr[2]);
    396                     break;
    397                 case SkPath::kCubic_Verb:
    398                     path->cubicTo(ePtr[1], ePtr[2], ePtr[3]);
    399                     break;
    400                 default:
    401                     SkASSERT(0);
    402             }
    403         }
    404     }
    405   //  return ePtr[SkPathOpsVerbToPoints(fVerb)];
    406 }
    407 
    408 void SkOpSegment::addEndSpan(int endIndex) {
    409     SkASSERT(span(endIndex).fT == 1 || (span(endIndex).fTiny
    410 //            && approximately_greater_than_one(span(endIndex).fT)
    411     ));
    412     int spanCount = fTs.count();
    413     int startIndex = endIndex - 1;
    414     while (fTs[startIndex].fT == 1 || fTs[startIndex].fTiny) {
    415         --startIndex;
    416         SkASSERT(startIndex > 0);
    417         --endIndex;
    418     }
    419     SkOpAngle& angle = fAngles.push_back();
    420     angle.set(this, spanCount - 1, startIndex);
    421 #if DEBUG_ANGLE
    422     debugCheckPointsEqualish(endIndex, spanCount);
    423 #endif
    424     setFromAngle(endIndex, &angle);
    425 }
    426 
    427 void SkOpSegment::setFromAngle(int endIndex, SkOpAngle* angle) {
    428     int spanCount = fTs.count();
    429     do {
    430         fTs[endIndex].fFromAngle = angle;
    431     } while (++endIndex < spanCount);
    432 }
    433 
    434 void SkOpSegment::addLine(const SkPoint pts[2], bool operand, bool evenOdd) {
    435     init(pts, SkPath::kLine_Verb, operand, evenOdd);
    436     fBounds.set(pts, 2);
    437 }
    438 
    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)) {
    443         otherT = 0;
    444     } else if (precisely_equal(otherT, 1)) {
    445         otherT = 1;
    446     }
    447     span.fOtherT = otherT;
    448     span.fOtherIndex = otherIndex;
    449 }
    450 
    451 void SkOpSegment::addQuad(const SkPoint pts[3], bool operand, bool evenOdd) {
    452     init(pts, SkPath::kQuad_Verb, operand, evenOdd);
    453     fBounds.setQuadBounds(pts);
    454 }
    455 
    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();
    461     *anglePtr = &angle;
    462     angle.set(this, spanIndex, startIndex);
    463     setFromAngle(spanIndex, &angle);
    464     SkOpSegment* other;
    465     int oStartIndex, oEndIndex;
    466     do {
    467         const SkOpSpan& span = fTs[spanIndex];
    468         SkASSERT(span.fT > 0);
    469         other = span.fOther;
    470         oStartIndex = span.fOtherIndex;
    471         oEndIndex = other->nextExactSpan(oStartIndex, 1);
    472         if (oEndIndex > 0 && other->span(oStartIndex).fWindValue) {
    473             break;
    474         }
    475         oEndIndex = oStartIndex;
    476         oStartIndex = other->nextExactSpan(oEndIndex, -1);
    477         --spanIndex;
    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);
    482     *otherPtr = other;
    483     return &oAngle;
    484 }
    485 
    486 SkOpAngle* SkOpSegment::addSingletonAngleUp(SkOpSegment** otherPtr, SkOpAngle** anglePtr) {
    487     int endIndex = nextExactSpan(0, 1);
    488     SkASSERT(endIndex > 0);
    489     SkOpAngle& angle = fAngles.push_back();
    490     *anglePtr = &angle;
    491     angle.set(this, 0, endIndex);
    492     setToAngle(endIndex, &angle);
    493     int spanIndex = 0;
    494     SkOpSegment* other;
    495     int oStartIndex, oEndIndex;
    496     do {
    497         const SkOpSpan& span = fTs[spanIndex];
    498         SkASSERT(span.fT < 1);
    499         other = span.fOther;
    500         oEndIndex = span.fOtherIndex;
    501         oStartIndex = other->nextExactSpan(oEndIndex, -1);
    502         if (oStartIndex >= 0 && other->span(oStartIndex).fWindValue) {
    503             break;
    504         }
    505         oStartIndex = oEndIndex;
    506         oEndIndex = other->nextExactSpan(oStartIndex, 1);
    507         ++spanIndex;
    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);
    512     *otherPtr = other;
    513     return &oAngle;
    514 }
    515 
    516 SkOpAngle* SkOpSegment::addSingletonAngles(int step) {
    517     SkOpSegment* other;
    518     SkOpAngle* angle, * otherAngle;
    519     if (step > 0) {
    520         otherAngle = addSingletonAngleUp(&other, &angle);
    521     } else {
    522         otherAngle = addSingletonAngleDown(&other, &angle);
    523     }
    524     angle->insert(otherAngle);
    525     return angle;
    526 }
    527 
    528 void SkOpSegment::addStartSpan(int endIndex) {
    529     int index = 0;
    530     SkOpAngle& angle = fAngles.push_back();
    531     angle.set(this, index, endIndex);
    532 #if DEBUG_ANGLE
    533     debugCheckPointsEqualish(index, endIndex);
    534 #endif
    535     setToAngle(endIndex, &angle);
    536 }
    537 
    538 void SkOpSegment::setToAngle(int endIndex, SkOpAngle* angle) {
    539     int index = 0;
    540     do {
    541         fTs[index].fToAngle = angle;
    542     } while (++index < endIndex);
    543 }
    544 
    545     // Defer all coincident edge processing until
    546     // after normal intersections have been computed
    547 
    548 // no need to be tricky; insert in normal T order
    549 // resolve overlapping ts when considering coincidence later
    550 
    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));
    556  #endif
    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,
    562     //  binary search?
    563     int insertedAt = -1;
    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) {
    574             insertedAt = index;
    575             break;
    576         }
    577         if (newT == span.fT) {
    578             if (pt == span.fPt) {
    579                 insertedAt = index;
    580                 break;
    581             }
    582             if ((pt == firstPt && newT == 0) || (span.fPt == lastPt && newT == 1)) {
    583                 insertedAt = index;
    584                 break;
    585             }
    586         }
    587     }
    588     SkOpSpan* span;
    589     if (insertedAt >= 0) {
    590         span = fTs.insert(insertedAt);
    591     } else {
    592         insertedAt = tCount;
    593         span = fTs.append();
    594     }
    595     span->fT = newT;
    596     span->fOtherT = -1;
    597     span->fOther = other;
    598     span->fPt = pt;
    599 #if 0
    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));
    603 #endif
    604     span->fFromAngle = NULL;
    605     span->fToAngle = NULL;
    606     span->fWindSum = SK_MinS32;
    607     span->fOppSum = SK_MinS32;
    608     span->fWindValue = 1;
    609     span->fOppValue = 0;
    610     span->fChased = false;
    611     span->fCoincident = false;
    612     span->fLoop = false;
    613     span->fNear = false;
    614     span->fMultiple = false;
    615     span->fSmall = false;
    616     span->fTiny = false;
    617     if ((span->fDone = newT == 1)) {
    618         ++fDoneSpans;
    619     }
    620     int less = -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))) {
    630                 break;
    631             }
    632         }
    633         --less;
    634     }
    635     int more = 1;
    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))) {
    643                 break;
    644             }
    645         }
    646         ++more;
    647     }
    648     ++less;
    649     --more;
    650     while (more - 1 > less && span[more].fPt == span[more - 1].fPt
    651             && span[more].fT == span[more - 1].fT) {
    652         --more;
    653     }
    654     if (less == more) {
    655         return insertedAt;
    656     }
    657     if (precisely_negative(span[more].fT - span[less].fT)) {
    658         return insertedAt;
    659     }
    660 // if the total range of t values is big enough, mark all tiny
    661     bool tiny = span[less].fPt == span[more].fPt;
    662     int index = less;
    663     do {
    664         fSmall = span[index].fSmall = true;
    665         fTiny |= span[index].fTiny = tiny;
    666         if (!span[index].fDone) {
    667             span[index].fDone = true;
    668             ++fDoneSpans;
    669         }
    670     } while (++index < more);
    671     return insertedAt;
    672 }
    673 
    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?
    686 /*                                      |-->                           |-->
    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
    689               ^         ^                 <--|                           <--|
    690            startPt    endPt        test/oTest first pos      test/oTest final pos
    691 */
    692 void SkOpSegment::addTCancel(const SkPoint& startPt, const SkPoint& endPt, SkOpSegment* other) {
    693     bool binary = fOperand != other->fOperand;
    694     int index = 0;
    695     while (startPt != fTs[index].fPt) {
    696         SkASSERT(index < fTs.count());
    697         ++index;
    698     }
    699     while (index > 0 && precisely_equal(fTs[index].fT, fTs[index - 1].fT)) {
    700         --index;
    701     }
    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);
    706     }
    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)) {
    710         if (!oIndex) {
    711             return;  // tiny spans may move in the wrong direction
    712         }
    713     }
    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;
    722     do {
    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;
    728         testPt = &test->fPt;
    729         double testT = test->fT;
    730         oTestPt = &oTest->fPt;
    731         double oTestT = oTest->fT;
    732         do {
    733             if (decrement) {
    734                 if (binary && bigger) {
    735                     test->fOppValue--;
    736                 } else {
    737                     decrementSpan(test);
    738                 }
    739             } else if (track) {
    740                 TrackOutsidePair(&outsidePts, *testPt, *oTestPt);
    741             }
    742             SkASSERT(index < fTs.count() - 1);
    743             test = &fTs[++index];
    744         } while (*testPt == test->fPt || precisely_equal(testT, test->fT));
    745         originalWindValue = oTest->fWindValue;
    746         do {
    747             SkASSERT(oTest->fT < 1);
    748             SkASSERT(originalWindValue == oTest->fWindValue);
    749             if (decrement) {
    750                 if (binary && !bigger) {
    751                     oTest->fOppValue--;
    752                 } else {
    753                     other->decrementSpan(oTest);
    754                 }
    755             } else if (track) {
    756                 TrackOutsidePair(&oOutsidePts, *oTestPt, *testPt);
    757             }
    758             if (!oIndex) {
    759                 break;
    760             }
    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
    766     if (!oFoundEnd) {
    767         for (int oIdx2 = oIndex; oIdx2 >= 0; --oIdx2) {
    768             SkOpSpan* oTst2 = &other->fTs[oIdx2];
    769             if (originalWindValue != oTst2->fWindValue) {
    770                 goto skipAdvanceOtherCancel;
    771             }
    772             if (!oTst2->fWindValue) {
    773                 goto skipAdvanceOtherCancel;
    774             }
    775             if (endPt == other->fTs[oIdx2].fPt) {
    776                 break;
    777             }
    778         }
    779         do {
    780             SkASSERT(originalWindValue == oTest->fWindValue);
    781             if (decrement) {
    782                 if (binary && !bigger) {
    783                     oTest->fOppValue--;
    784                 } else {
    785                     other->decrementSpan(oTest);
    786                 }
    787             } else if (track) {
    788                 TrackOutsidePair(&oOutsidePts, *oTestPt, *testPt);
    789             }
    790             if (!oIndex) {
    791                 break;
    792             }
    793             oTest = &other->fTs[--oIndex];
    794             oFoundEnd |= endPt == oTest->fPt;
    795         } while (!oFoundEnd || endPt == oTest->fPt);
    796     }
    797 skipAdvanceOtherCancel:
    798     int outCount = outsidePts.count();
    799     if (!done() && outCount) {
    800         addCancelOutsides(outsidePts[0], outsidePts[1], other);
    801         if (outCount > 2) {
    802             addCancelOutsides(outsidePts[outCount - 2], outsidePts[outCount - 1], other);
    803         }
    804     }
    805     if (!other->done() && oOutsidePts.count()) {
    806         other->addCancelOutsides(oOutsidePts[0], oOutsidePts[1], this);
    807     }
    808     setCoincidentRange(startPt, endPt, other);
    809     other->setCoincidentRange(startPt, endPt, this);
    810 }
    811 
    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;
    817     return result;
    818 }
    819 
    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];
    826     int idx;
    827     int start, end;
    828     if (span->fT == 0) {
    829         idx = 0;
    830         span = &fTs[0];
    831         do {
    832             if (span->fToAngle) {
    833                 SkASSERT(span->fToAngle->loopCount() == 2);
    834                 SkASSERT(!span->fFromAngle);
    835                 span->fFromAngle = span->fToAngle->next();
    836                 return;
    837             }
    838             span = &fTs[++idx];
    839         } while (span->fT == 0);
    840         SkASSERT(!fTs[0].fTiny && fTs[idx].fT > 0);
    841         addStartSpan(idx);
    842         start = 0;
    843         end = idx;
    844     } else {
    845         idx = count() - 1;
    846         span = &fTs[idx];
    847         do {
    848             if (span->fFromAngle) {
    849                 SkASSERT(span->fFromAngle->loopCount() == 2);
    850                 SkASSERT(!span->fToAngle);
    851                 span->fToAngle = span->fFromAngle->next();
    852                 return;
    853             }
    854             span = &fTs[--idx];
    855         } while (span->fT == 1);
    856         SkASSERT(!fTs[idx].fTiny && fTs[idx].fT < 1);
    857         addEndSpan(++idx);
    858         start = idx;
    859         end = count();
    860     }
    861     SkOpSegment* other;
    862     SkOpSpan* oSpan;
    863     index = start;
    864     do {
    865         span = &fTs[index];
    866         other = span->fOther;
    867         int oFrom = span->fOtherIndex;
    868         oSpan = &other->fTs[oFrom];
    869         if (oSpan->fT < 1 && oSpan->fWindValue) {
    870             break;
    871         }
    872         if (oSpan->fT == 0) {
    873             continue;
    874         }
    875         oFrom = other->nextExactSpan(oFrom, -1);
    876         SkOpSpan* oFromSpan = &other->fTs[oFrom];
    877         SkASSERT(oFromSpan->fT < 1);
    878         if (oFromSpan->fWindValue) {
    879             break;
    880         }
    881     } while (++index < end);
    882     SkOpAngle* angle, * oAngle;
    883     if (span->fT == 0) {
    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;
    892     } else {
    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)));
    898         int oIndex = 1;
    899         do {
    900             const SkOpSpan& osSpan = other->span(oIndex);
    901             if (osSpan.fFromAngle || osSpan.fT > 0) {
    902                 break;
    903             }
    904             ++oIndex;
    905             SkASSERT(oIndex < other->count());
    906         } while (true);
    907         other->addStartSpan(oIndex);
    908         angle = span->fFromAngle;
    909         oAngle = oSpan->fToAngle;
    910     }
    911     angle->insert(oAngle);
    912 }
    913 
    914 void SkOpSegment::alignMultiples(SkTDArray<AlignedSpan>* alignedArray) {
    915     debugValidate();
    916     int count = this->count();
    917     for (int index = 0; index < count; ++index) {
    918         SkOpSpan& span = fTs[index];
    919         if (!span.fMultiple) {
    920             continue;
    921         }
    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) {
    934                         continue;
    935                     }
    936                     if (oSpan.fPt == thisPt) {
    937                         goto skipExactMatches;
    938                     }
    939                 }
    940                 for (int oIdx = 0; oIdx < oCnt; ++oIdx) {
    941                     SkOpSpan& oSpan = other1->fTs[oIdx];
    942                     if (oSpan.fOther != other2) {
    943                         continue;
    944                     }
    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)) {
    949                             return;
    950                         }
    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)) {
    955                             return;
    956                         }
    957                         alignSpan(thisPt, span.fOtherT, other1, span2.fOtherT,
    958                                 other2, &oSpan, alignedArray);
    959                         alignSpan(thisPt, span2.fOtherT, other2, span.fOtherT,
    960                                 other1, &oSpan2, alignedArray);
    961                         break;
    962                     }
    963                 }
    964         skipExactMatches:
    965                 ;
    966             }
    967             ++index;
    968         }
    969     }
    970     debugValidate();
    971 }
    972 
    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;
    980     aligned->fT = newT;
    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));
    985     oSpan->fPt = newPt;
    986 //    SkASSERT(way_roughly_equal(oSpan->fT, newT));
    987     oSpan->fT = newT;
    988 //    SkASSERT(way_roughly_equal(oSpan->fOtherT, otherT));
    989     oSpan->fOtherT = otherT;
    990 }
    991 
    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) {
    999         span->fT = thisT;
   1000         oSpan->fOtherT = thisT;
   1001         aligned = true;
   1002     }
   1003     if (span->fPt != thisPt) {
   1004         span->fPt = thisPt;
   1005         oSpan->fPt = thisPt;
   1006         aligned = true;
   1007     }
   1008     double oT = oSpan->fT;
   1009     if (oT == 0) {
   1010         return aligned;
   1011     }
   1012     int oStart = other->nextSpan(oIndex, -1) + 1;
   1013     oSpan = &other->fTs[oStart];
   1014     int otherIndex = oStart;
   1015     if (oT == 1) {
   1016         if (aligned) {
   1017             while (oSpan->fPt == thisPt && oSpan->fT != 1) {
   1018                 oSpan->fTiny = true;
   1019                 ++oSpan;
   1020             }
   1021         }
   1022         return aligned;
   1023     }
   1024     oT = oSpan->fT;
   1025     int oEnd = other->nextSpan(oIndex, 1);
   1026     bool oAligned = false;
   1027     if (oSpan->fPt != thisPt) {
   1028         oAligned |= other->alignSpan(oStart, oT, thisPt);
   1029     }
   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);
   1034         }
   1035     }
   1036     if (oAligned) {
   1037         other->alignSpanState(oStart, oEnd);
   1038     }
   1039     return aligned;
   1040 }
   1041 
   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);
   1049     int index = start;
   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;
   1057         }
   1058         SkASSERT(span->fWindValue == winding);
   1059         SkASSERT(span->fOppValue == oppWinding);
   1060         ++index;
   1061     }
   1062 }
   1063 
   1064 void SkOpSegment::blindCancel(const SkCoincidence& coincidence, SkOpSegment* other) {
   1065     bool binary = fOperand != other->fOperand;
   1066     int index = 0;
   1067     int last = this->count();
   1068     do {
   1069         SkOpSpan& span = this->fTs[--last];
   1070         if (span.fT != 1 && !span.fSmall) {
   1071             break;
   1072         }
   1073         span.fCoincident = true;
   1074     } while (true);
   1075     int oIndex = other->count();
   1076     do {
   1077         SkOpSpan& oSpan = other->fTs[--oIndex];
   1078         if (oSpan.fT != 1 && !oSpan.fSmall) {
   1079             break;
   1080         }
   1081         oSpan.fCoincident = true;
   1082     } while (true);
   1083     do {
   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) {
   1092                 break;
   1093             }
   1094             endSpan->fCoincident = true;
   1095         }
   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) {
   1103                 break;
   1104             }
   1105             oStartSpan->fCoincident = true;
   1106         }
   1107         bool decrement = baseWind && oBaseWind;
   1108         bool bigger = baseWind >= oBaseWind;
   1109         do {
   1110             SkASSERT(test->fT < 1);
   1111             if (decrement) {
   1112                 if (binary && bigger) {
   1113                     test->fOppValue--;
   1114                 } else {
   1115                     decrementSpan(test);
   1116                 }
   1117             }
   1118             test->fCoincident = true;
   1119             test = &fTs[++index];
   1120         } while (index < endIndex);
   1121         do {
   1122             SkASSERT(oTest->fT < 1);
   1123             if (decrement) {
   1124                 if (binary && !bigger) {
   1125                     oTest->fOppValue--;
   1126                 } else {
   1127                     other->decrementSpan(oTest);
   1128                 }
   1129             }
   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);
   1136 }
   1137 
   1138 void SkOpSegment::blindCoincident(const SkCoincidence& coincidence, SkOpSegment* other) {
   1139     bool binary = fOperand != other->fOperand;
   1140     int index = 0;
   1141     int last = this->count();
   1142     do {
   1143         SkOpSpan& span = this->fTs[--last];
   1144         if (span.fT != 1 && !span.fSmall) {
   1145             break;
   1146         }
   1147         span.fCoincident = true;
   1148     } while (true);
   1149     int oIndex = 0;
   1150     int oLast = other->count();
   1151     do {
   1152         SkOpSpan& oSpan = other->fTs[--oLast];
   1153         if (oSpan.fT != 1 && !oSpan.fSmall) {
   1154             break;
   1155         }
   1156         oSpan.fCoincident = true;
   1157     } while (true);
   1158     do {
   1159         SkOpSpan* test = &this->fTs[index];
   1160         int baseWind = test->fWindValue;
   1161         int baseOpp = test->fOppValue;
   1162         int endIndex = index;
   1163         SkOpSpan* endSpan;
   1164         while (++endIndex <= last) {
   1165             endSpan = &this->fTs[endIndex];
   1166             SkASSERT(endSpan->fT < 1);
   1167             if (endSpan->fWindValue != baseWind || endSpan->fOppValue != baseOpp) {
   1168                 break;
   1169             }
   1170             endSpan->fCoincident = true;
   1171         }
   1172         SkOpSpan* oTest = &other->fTs[oIndex];
   1173         int oBaseWind = oTest->fWindValue;
   1174         int oBaseOpp = oTest->fOppValue;
   1175         int oEndIndex = oIndex;
   1176         SkOpSpan* oEndSpan;
   1177         while (++oEndIndex <= oLast) {
   1178             oEndSpan = &this->fTs[oEndIndex];
   1179             SkASSERT(oEndSpan->fT < 1);
   1180             if (oEndSpan->fWindValue != oBaseWind || oEndSpan->fOppValue != oBaseOpp) {
   1181                 break;
   1182             }
   1183             oEndSpan->fCoincident = true;
   1184         }
   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);
   1190             } else {
   1191                 other->bumpCoincidentBlind(binary, oIndex, oEndIndex);
   1192                 bumpCoincidentOBlind(index, endIndex);
   1193             }
   1194         }
   1195         index = endIndex;
   1196         oIndex = oEndIndex;
   1197     } while (index <= last && oIndex <= oLast);
   1198     SkASSERT(index > last);
   1199     SkASSERT(oIndex > oLast);
   1200 }
   1201 
   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;
   1206     if (binary) {
   1207         SkTSwap<int>(oWindValue, oOppValue);
   1208     }
   1209     do {
   1210         (void) bumpSpan(&fTs[index], oWindValue, oOppValue);
   1211     } while (++index < endIndex);
   1212 }
   1213 
   1214 void 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;
   1219     if (binary) {
   1220         SkTSwap<int>(oWindValue, oOppValue);
   1221     }
   1222     SkOpSpan* const test = &fTs[index];
   1223     SkOpSpan* end = test;
   1224     const SkPoint& oStartPt = oTest.fPt;
   1225     do {
   1226         if (bumpSpan(end, oWindValue, oOppValue)) {
   1227             TrackOutside(outsideTs, oStartPt);
   1228         }
   1229         end = &fTs[++index];
   1230     } while ((end->fPt == test->fPt || precisely_equal(end->fT, test->fT)) && end->fT < 1);
   1231     *indexPtr = index;
   1232 }
   1233 
   1234 void SkOpSegment::bumpCoincidentOBlind(int index, int endIndex) {
   1235     do {
   1236         zeroSpan(&fTs[index]);
   1237     } while (++index < endIndex);
   1238 }
   1239 
   1240 // because of the order in which coincidences are resolved, this and other
   1241 // may not have the same intermediate points. Compute the corresponding
   1242 // intermediate T values (using this as the master, other as the follower)
   1243 // and walk other conditionally -- hoping that it catches up in the end
   1244 void SkOpSegment::bumpCoincidentOther(const SkOpSpan& test, int* oIndexPtr,
   1245         SkTArray<SkPoint, true>* oOutsidePts) {
   1246     int oIndex = *oIndexPtr;
   1247     SkOpSpan* const oTest = &fTs[oIndex];
   1248     SkOpSpan* oEnd = oTest;
   1249     const SkPoint& oStartPt = oTest->fPt;
   1250     double oStartT = oTest->fT;
   1251 #if 0  // FIXME : figure out what disabling this breaks
   1252     const SkPoint& startPt = test.fPt;
   1253     // this is always true since oEnd == oTest && oStartPt == oTest->fPt -- find proper condition
   1254     if (oStartPt == oEnd->fPt || precisely_equal(oStartT, oEnd->fT)) {
   1255         TrackOutside(oOutsidePts, startPt);
   1256     }
   1257 #endif
   1258     while (oStartPt == oEnd->fPt || precisely_equal(oStartT, oEnd->fT)) {
   1259         zeroSpan(oEnd);
   1260         oEnd = &fTs[++oIndex];
   1261     }
   1262     *oIndexPtr = oIndex;
   1263 }
   1264 
   1265 // FIXME: need to test this case:
   1266 // contourA has two segments that are coincident
   1267 // contourB has two segments that are coincident in the same place
   1268 // each ends up with +2/0 pairs for winding count
   1269 // since logic below doesn't transfer count (only increments/decrements) can this be
   1270 // resolved to +4/0 ?
   1271 
   1272 // set spans from start to end to increment the greater by one and decrement
   1273 // the lesser
   1274 bool SkOpSegment::addTCoincident(const SkPoint& startPt, const SkPoint& endPt, double endT,
   1275         SkOpSegment* other) {
   1276     bool binary = fOperand != other->fOperand;
   1277     int index = 0;
   1278     while (startPt != fTs[index].fPt) {
   1279         SkASSERT(index < fTs.count());
   1280         ++index;
   1281     }
   1282     double startT = fTs[index].fT;
   1283     while (index > 0 && precisely_equal(fTs[index - 1].fT, startT)) {
   1284         --index;
   1285     }
   1286     int oIndex = 0;
   1287     while (startPt != other->fTs[oIndex].fPt) {
   1288         SkASSERT(oIndex < other->fTs.count());
   1289         ++oIndex;
   1290     }
   1291     double oStartT = other->fTs[oIndex].fT;
   1292     while (oIndex > 0 && precisely_equal(other->fTs[oIndex - 1].fT, oStartT)) {
   1293         --oIndex;
   1294     }
   1295     SkSTArray<kOutsideTrackedTCount, SkPoint, true> outsidePts;
   1296     SkSTArray<kOutsideTrackedTCount, SkPoint, true> oOutsidePts;
   1297     SkOpSpan* test = &fTs[index];
   1298     const SkPoint* testPt = &test->fPt;
   1299     double testT = test->fT;
   1300     SkOpSpan* oTest = &other->fTs[oIndex];
   1301     const SkPoint* oTestPt = &oTest->fPt;
   1302     // paths with extreme data will fail this test and eject out of pathops altogether later on
   1303     // SkASSERT(AlmostEqualUlps(*testPt, *oTestPt));
   1304     do {
   1305         SkASSERT(test->fT < 1);
   1306         if (oTest->fT == 1) {
   1307             // paths with extreme data may be so mismatched that we fail here
   1308             return false;
   1309         }
   1310 
   1311         // consolidate the winding count even if done
   1312         if ((test->fWindValue == 0 && test->fOppValue == 0)
   1313                 || (oTest->fWindValue == 0 && oTest->fOppValue == 0)) {
   1314             SkDEBUGCODE(int firstWind = test->fWindValue);
   1315             SkDEBUGCODE(int firstOpp = test->fOppValue);
   1316             do {
   1317                 SkASSERT(firstWind == fTs[index].fWindValue);
   1318                 SkASSERT(firstOpp == fTs[index].fOppValue);
   1319                 ++index;
   1320                 SkASSERT(index < fTs.count());
   1321             } while (*testPt == fTs[index].fPt);
   1322             SkDEBUGCODE(firstWind = oTest->fWindValue);
   1323             SkDEBUGCODE(firstOpp = oTest->fOppValue);
   1324             do {
   1325                 SkASSERT(firstWind == other->fTs[oIndex].fWindValue);
   1326                 SkASSERT(firstOpp == other->fTs[oIndex].fOppValue);
   1327                 ++oIndex;
   1328                 SkASSERT(oIndex < other->fTs.count());
   1329             } while (*oTestPt == other->fTs[oIndex].fPt);
   1330         } else {
   1331             if (!binary || test->fWindValue + oTest->fOppValue >= 0) {
   1332                 bumpCoincidentThis(*oTest, binary, &index, &outsidePts);
   1333                 other->bumpCoincidentOther(*test, &oIndex, &oOutsidePts);
   1334             } else {
   1335                 other->bumpCoincidentThis(*test, binary, &oIndex, &oOutsidePts);
   1336                 bumpCoincidentOther(*oTest, &index, &outsidePts);
   1337             }
   1338         }
   1339         test = &fTs[index];
   1340         testPt = &test->fPt;
   1341         testT = test->fT;
   1342         oTest = &other->fTs[oIndex];
   1343         oTestPt = &oTest->fPt;
   1344         if (endPt == *testPt || precisely_equal(endT, testT)) {
   1345             break;
   1346         }
   1347 //        SkASSERT(AlmostEqualUlps(*testPt, *oTestPt));
   1348     } while (endPt != *oTestPt);
   1349     // in rare cases, one may have ended before the other
   1350     if (endPt != *testPt && !precisely_equal(endT, testT)) {
   1351         int lastWind = test[-1].fWindValue;
   1352         int lastOpp = test[-1].fOppValue;
   1353         bool zero = lastWind == 0 && lastOpp == 0;
   1354         do {
   1355             if (test->fWindValue || test->fOppValue) {
   1356                 test->fWindValue = lastWind;
   1357                 test->fOppValue = lastOpp;
   1358                 if (zero) {
   1359                     test->fDone = true;
   1360                     ++fDoneSpans;
   1361                 }
   1362             }
   1363             test = &fTs[++index];
   1364             testPt = &test->fPt;
   1365         } while (endPt != *testPt);
   1366     }
   1367     if (endPt != *oTestPt) {
   1368         // look ahead to see if zeroing more spans will allows us to catch up
   1369         int oPeekIndex = oIndex;
   1370         bool success = true;
   1371         SkOpSpan* oPeek;
   1372         int oCount = other->count();
   1373         do {
   1374             oPeek = &other->fTs[oPeekIndex];
   1375             if (++oPeekIndex == oCount) {
   1376                 success = false;
   1377                 break;
   1378             }
   1379         } while (endPt != oPeek->fPt);
   1380         if (success) {
   1381             // make sure the matching point completes the coincidence span
   1382             success = false;
   1383             do {
   1384                 if (oPeek->fOther == this) {
   1385                     success = true;
   1386                     break;
   1387                 }
   1388                 if (++oPeekIndex == oCount) {
   1389                     break;
   1390                 }
   1391                 oPeek = &other->fTs[oPeekIndex];
   1392             } while (endPt == oPeek->fPt);
   1393         }
   1394         if (success) {
   1395             do {
   1396                 if (!binary || test->fWindValue + oTest->fOppValue >= 0) {
   1397                     other->bumpCoincidentOther(*test, &oIndex, &oOutsidePts);
   1398                 } else {
   1399                     other->bumpCoincidentThis(*test, binary, &oIndex, &oOutsidePts);
   1400                 }
   1401                 oTest = &other->fTs[oIndex];
   1402                 oTestPt = &oTest->fPt;
   1403             } while (endPt != *oTestPt);
   1404         }
   1405     }
   1406     int outCount = outsidePts.count();
   1407     if (!done() && outCount) {
   1408         addCoinOutsides(outsidePts[0], endPt, other);
   1409     }
   1410     if (!other->done() && oOutsidePts.count()) {
   1411         other->addCoinOutsides(oOutsidePts[0], endPt, this);
   1412     }
   1413     setCoincidentRange(startPt, endPt, other);
   1414     other->setCoincidentRange(startPt, endPt, this);
   1415     return true;
   1416 }
   1417 
   1418 // FIXME: this doesn't prevent the same span from being added twice
   1419 // fix in caller, SkASSERT here?
   1420 // FIXME: this may erroneously reject adds for cubic loops
   1421 const SkOpSpan* SkOpSegment::addTPair(double t, SkOpSegment* other, double otherT, bool borrowWind,
   1422         const SkPoint& pt, const SkPoint& pt2) {
   1423     int tCount = fTs.count();
   1424     for (int tIndex = 0; tIndex < tCount; ++tIndex) {
   1425         const SkOpSpan& span = fTs[tIndex];
   1426         if (!approximately_negative(span.fT - t)) {
   1427             break;
   1428         }
   1429         if (span.fOther == other) {
   1430             bool tsMatch = approximately_equal(span.fT, t);
   1431             bool otherTsMatch = approximately_equal(span.fOtherT, otherT);
   1432             // FIXME: add cubic loop detecting logic here
   1433             // if fLoop bit is set on span, that could be enough if addOtherT copies the bit
   1434             // or if a new bit is added ala fOtherLoop
   1435             if (tsMatch || otherTsMatch) {
   1436 #if DEBUG_ADD_T_PAIR
   1437                 SkDebugf("%s addTPair duplicate this=%d %1.9g other=%d %1.9g\n",
   1438                         __FUNCTION__, fID, t, other->fID, otherT);
   1439 #endif
   1440                 return NULL;
   1441             }
   1442         }
   1443     }
   1444     int oCount = other->count();
   1445     for (int oIndex = 0; oIndex < oCount; ++oIndex) {
   1446         const SkOpSpan& oSpan = other->span(oIndex);
   1447         if (!approximately_negative(oSpan.fT - otherT)) {
   1448             break;
   1449         }
   1450         if (oSpan.fOther == this) {
   1451             bool otherTsMatch = approximately_equal(oSpan.fT, otherT);
   1452             bool tsMatch = approximately_equal(oSpan.fOtherT, t);
   1453             if (otherTsMatch || tsMatch) {
   1454 #if DEBUG_ADD_T_PAIR
   1455                 SkDebugf("%s addTPair other duplicate this=%d %1.9g other=%d %1.9g\n",
   1456                         __FUNCTION__, fID, t, other->fID, otherT);
   1457 #endif
   1458                 return NULL;
   1459             }
   1460         }
   1461     }
   1462 #if DEBUG_ADD_T_PAIR
   1463     SkDebugf("%s addTPair this=%d %1.9g other=%d %1.9g\n",
   1464             __FUNCTION__, fID, t, other->fID, otherT);
   1465 #endif
   1466     SkASSERT(other != this);
   1467     int insertedAt = addT(other, pt, t);
   1468     int otherInsertedAt = other->addT(this, pt2, otherT);
   1469     addOtherT(insertedAt, otherT, otherInsertedAt);
   1470     other->addOtherT(otherInsertedAt, t, insertedAt);
   1471     matchWindingValue(insertedAt, t, borrowWind);
   1472     other->matchWindingValue(otherInsertedAt, otherT, borrowWind);
   1473     SkOpSpan& span = this->fTs[insertedAt];
   1474     if (pt != pt2) {
   1475         span.fNear = true;
   1476         SkOpSpan& oSpan = other->fTs[otherInsertedAt];
   1477         oSpan.fNear = true;
   1478     }
   1479     return &span;
   1480 }
   1481 
   1482 const SkOpSpan* SkOpSegment::addTPair(double t, SkOpSegment* other, double otherT, bool borrowWind,
   1483                            const SkPoint& pt) {
   1484     return addTPair(t, other, otherT, borrowWind, pt, pt);
   1485 }
   1486 
   1487 bool SkOpSegment::betweenPoints(double midT, const SkPoint& pt1, const SkPoint& pt2) const {
   1488     const SkPoint midPt = ptAtT(midT);
   1489     SkPathOpsBounds bounds;
   1490     bounds.set(pt1.fX, pt1.fY, pt2.fX, pt2.fY);
   1491     bounds.sort();
   1492     return bounds.almostContains(midPt);
   1493 }
   1494 
   1495 bool SkOpSegment::betweenTs(int lesser, double testT, int greater) const {
   1496     if (lesser > greater) {
   1497         SkTSwap<int>(lesser, greater);
   1498     }
   1499     return approximately_between(fTs[lesser].fT, testT, fTs[greater].fT);
   1500 }
   1501 
   1502 // in extreme cases (like the buffer overflow test) return false to abort
   1503 // for now, if one t value represents two different points, then the values are too extreme
   1504 // to generate meaningful results
   1505 bool SkOpSegment::calcAngles() {
   1506     int spanCount = fTs.count();
   1507     if (spanCount <= 2) {
   1508         return spanCount == 2;
   1509     }
   1510     int index = 1;
   1511     const SkOpSpan* firstSpan = &fTs[index];
   1512     int activePrior = checkSetAngle(0);
   1513     const SkOpSpan* span = &fTs[0];
   1514     if (firstSpan->fT == 0 || span->fTiny || span->fOtherT != 1 || span->fOther->multipleEnds()) {
   1515         index = findStartSpan(0);  // curve start intersects
   1516         if (fTs[index].fT == 0) {
   1517             return false;
   1518         }
   1519         SkASSERT(index > 0);
   1520         if (activePrior >= 0) {
   1521             addStartSpan(index);
   1522         }
   1523     }
   1524     bool addEnd;
   1525     int endIndex = spanCount - 1;
   1526     span = &fTs[endIndex - 1];
   1527     if ((addEnd = span->fT == 1 || span->fTiny)) {  // if curve end intersects
   1528         endIndex = findEndSpan(endIndex);
   1529         SkASSERT(endIndex > 0);
   1530     } else {
   1531         addEnd = fTs[endIndex].fOtherT != 0 || fTs[endIndex].fOther->multipleStarts();
   1532     }
   1533     SkASSERT(endIndex >= index);
   1534     int prior = 0;
   1535     while (index < endIndex) {
   1536         const SkOpSpan& fromSpan = fTs[index];  // for each intermediate intersection
   1537         const SkOpSpan* lastSpan;
   1538         span = &fromSpan;
   1539         int start = index;
   1540         do {
   1541             lastSpan = span;
   1542             span = &fTs[++index];
   1543             SkASSERT(index < spanCount);
   1544             if (!precisely_negative(span->fT - lastSpan->fT) && !lastSpan->fTiny) {
   1545                 break;
   1546             }
   1547             if (!SkDPoint::ApproximatelyEqual(lastSpan->fPt, span->fPt)) {
   1548                 return false;
   1549             }
   1550         } while (true);
   1551         SkOpAngle* angle = NULL;
   1552         SkOpAngle* priorAngle;
   1553         if (activePrior >= 0) {
   1554             int pActive = firstActive(prior);
   1555             SkASSERT(pActive < start);
   1556             priorAngle = &fAngles.push_back();
   1557             priorAngle->set(this, start, pActive);
   1558         }
   1559         int active = checkSetAngle(start);
   1560         if (active >= 0) {
   1561             SkASSERT(active < index);
   1562             angle = &fAngles.push_back();
   1563             angle->set(this, active, index);
   1564         }
   1565     #if DEBUG_ANGLE
   1566         debugCheckPointsEqualish(start, index);
   1567     #endif
   1568         prior = start;
   1569         do {
   1570             const SkOpSpan* startSpan = &fTs[start - 1];
   1571             if (!startSpan->fSmall || isCanceled(start - 1) || startSpan->fFromAngle
   1572                     || startSpan->fToAngle) {
   1573                 break;
   1574             }
   1575             --start;
   1576         } while (start > 0);
   1577         do {
   1578             if (activePrior >= 0) {
   1579                 SkASSERT(fTs[start].fFromAngle == NULL);
   1580                 fTs[start].fFromAngle = priorAngle;
   1581             }
   1582             if (active >= 0) {
   1583                 SkASSERT(fTs[start].fToAngle == NULL);
   1584                 fTs[start].fToAngle = angle;
   1585             }
   1586         } while (++start < index);
   1587         activePrior = active;
   1588     }
   1589     if (addEnd && activePrior >= 0) {
   1590         addEndSpan(endIndex);
   1591     }
   1592     return true;
   1593 }
   1594 
   1595 int SkOpSegment::checkSetAngle(int tIndex) const {
   1596     const SkOpSpan* span = &fTs[tIndex];
   1597     while (span->fTiny /* || span->fSmall */) {
   1598         span = &fTs[++tIndex];
   1599     }
   1600     return isCanceled(tIndex) ? -1 : tIndex;
   1601 }
   1602 
   1603 // at this point, the span is already ordered, or unorderable
   1604 int SkOpSegment::computeSum(int startIndex, int endIndex, SkOpAngle::IncludeType includeType) {
   1605     SkASSERT(includeType != SkOpAngle::kUnaryXor);
   1606     SkOpAngle* firstAngle = spanToAngle(endIndex, startIndex);
   1607     if (NULL == firstAngle || NULL == firstAngle->next()) {
   1608         return SK_NaN32;
   1609     }
   1610     // if all angles have a computed winding,
   1611     //  or if no adjacent angles are orderable,
   1612     //  or if adjacent orderable angles have no computed winding,
   1613     //  there's nothing to do
   1614     // if two orderable angles are adjacent, and both are next to orderable angles,
   1615     //  and one has winding computed, transfer to the other
   1616     SkOpAngle* baseAngle = NULL;
   1617     bool tryReverse = false;
   1618     // look for counterclockwise transfers
   1619     SkOpAngle* angle = firstAngle->previous();
   1620     SkOpAngle* next = angle->next();
   1621     firstAngle = next;
   1622     do {
   1623         SkOpAngle* prior = angle;
   1624         angle = next;
   1625         next = angle->next();
   1626         SkASSERT(prior->next() == angle);
   1627         SkASSERT(angle->next() == next);
   1628         if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
   1629             baseAngle = NULL;
   1630             continue;
   1631         }
   1632         int testWinding = angle->segment()->windSum(angle);
   1633         if (SK_MinS32 != testWinding) {
   1634             baseAngle = angle;
   1635             tryReverse = true;
   1636             continue;
   1637         }
   1638         if (baseAngle) {
   1639             ComputeOneSum(baseAngle, angle, includeType);
   1640             baseAngle = SK_MinS32 != angle->segment()->windSum(angle) ? angle : NULL;
   1641         }
   1642     } while (next != firstAngle);
   1643     if (baseAngle && SK_MinS32 == firstAngle->segment()->windSum(firstAngle)) {
   1644         firstAngle = baseAngle;
   1645         tryReverse = true;
   1646     }
   1647     if (tryReverse) {
   1648         baseAngle = NULL;
   1649         SkOpAngle* prior = firstAngle;
   1650         do {
   1651             angle = prior;
   1652             prior = angle->previous();
   1653             SkASSERT(prior->next() == angle);
   1654             next = angle->next();
   1655             if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
   1656                 baseAngle = NULL;
   1657                 continue;
   1658             }
   1659             int testWinding = angle->segment()->windSum(angle);
   1660             if (SK_MinS32 != testWinding) {
   1661                 baseAngle = angle;
   1662                 continue;
   1663             }
   1664             if (baseAngle) {
   1665                 ComputeOneSumReverse(baseAngle, angle, includeType);
   1666                 baseAngle = SK_MinS32 != angle->segment()->windSum(angle) ? angle : NULL;
   1667             }
   1668         } while (prior != firstAngle);
   1669     }
   1670     int minIndex = SkMin32(startIndex, endIndex);
   1671     return windSum(minIndex);
   1672 }
   1673 
   1674 void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
   1675         SkOpAngle::IncludeType includeType) {
   1676     const SkOpSegment* baseSegment = baseAngle->segment();
   1677     int sumMiWinding = baseSegment->updateWindingReverse(baseAngle);
   1678     int sumSuWinding;
   1679     bool binary = includeType >= SkOpAngle::kBinarySingle;
   1680     if (binary) {
   1681         sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle);
   1682         if (baseSegment->operand()) {
   1683             SkTSwap<int>(sumMiWinding, sumSuWinding);
   1684         }
   1685     }
   1686     SkOpSegment* nextSegment = nextAngle->segment();
   1687     int maxWinding, sumWinding;
   1688     SkOpSpan* last;
   1689     if (binary) {
   1690         int oppMaxWinding, oppSumWinding;
   1691         nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
   1692                 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
   1693         last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
   1694                 nextAngle);
   1695     } else {
   1696         nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
   1697                 &maxWinding, &sumWinding);
   1698         last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
   1699     }
   1700     nextAngle->setLastMarked(last);
   1701 }
   1702 
   1703 void SkOpSegment::ComputeOneSumReverse(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
   1704         SkOpAngle::IncludeType includeType) {
   1705     const SkOpSegment* baseSegment = baseAngle->segment();
   1706     int sumMiWinding = baseSegment->updateWinding(baseAngle);
   1707     int sumSuWinding;
   1708     bool binary = includeType >= SkOpAngle::kBinarySingle;
   1709     if (binary) {
   1710         sumSuWinding = baseSegment->updateOppWinding(baseAngle);
   1711         if (baseSegment->operand()) {
   1712             SkTSwap<int>(sumMiWinding, sumSuWinding);
   1713         }
   1714     }
   1715     SkOpSegment* nextSegment = nextAngle->segment();
   1716     int maxWinding, sumWinding;
   1717     SkOpSpan* last;
   1718     if (binary) {
   1719         int oppMaxWinding, oppSumWinding;
   1720         nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
   1721                 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
   1722         last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
   1723                 nextAngle);
   1724     } else {
   1725         nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
   1726                 &maxWinding, &sumWinding);
   1727         last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
   1728     }
   1729     nextAngle->setLastMarked(last);
   1730 }
   1731 
   1732 bool SkOpSegment::containsPt(const SkPoint& pt, int index, int endIndex) const {
   1733     int step = index < endIndex ? 1 : -1;
   1734     do {
   1735         const SkOpSpan& span = this->span(index);
   1736         if (span.fPt == pt) {
   1737             const SkOpSpan& endSpan = this->span(endIndex);
   1738             return span.fT == endSpan.fT && pt != endSpan.fPt;
   1739         }
   1740         index += step;
   1741     } while (index != endIndex);
   1742     return false;
   1743 }
   1744 
   1745 bool SkOpSegment::containsT(double t, const SkOpSegment* other, double otherT) const {
   1746     int count = this->count();
   1747     for (int index = 0; index < count; ++index) {
   1748         const SkOpSpan& span = fTs[index];
   1749         if (t < span.fT) {
   1750             return false;
   1751         }
   1752         if (t == span.fT) {
   1753             if (other != span.fOther) {
   1754                 continue;
   1755             }
   1756             if (other->fVerb != SkPath::kCubic_Verb) {
   1757                 return true;
   1758             }
   1759             if (!other->fLoop) {
   1760                 return true;
   1761             }
   1762             double otherMidT = (otherT + span.fOtherT) / 2;
   1763             SkPoint otherPt = other->ptAtT(otherMidT);
   1764             return SkDPoint::ApproximatelyEqual(span.fPt, otherPt);
   1765         }
   1766     }
   1767     return false;
   1768 }
   1769 
   1770 int SkOpSegment::crossedSpanY(const SkPoint& basePt, SkScalar* bestY, double* hitT,
   1771                               bool* hitSomething, double mid, bool opp, bool current) const {
   1772     SkScalar bottom = fBounds.fBottom;
   1773     int bestTIndex = -1;
   1774     if (bottom <= *bestY) {
   1775         return bestTIndex;
   1776     }
   1777     SkScalar top = fBounds.fTop;
   1778     if (top >= basePt.fY) {
   1779         return bestTIndex;
   1780     }
   1781     if (fBounds.fLeft > basePt.fX) {
   1782         return bestTIndex;
   1783     }
   1784     if (fBounds.fRight < basePt.fX) {
   1785         return bestTIndex;
   1786     }
   1787     if (fBounds.fLeft == fBounds.fRight) {
   1788         // if vertical, and directly above test point, wait for another one
   1789         return AlmostEqualUlps(basePt.fX, fBounds.fLeft) ? SK_MinS32 : bestTIndex;
   1790     }
   1791     // intersect ray starting at basePt with edge
   1792     SkIntersections intersections;
   1793     // OPTIMIZE: use specialty function that intersects ray with curve,
   1794     // returning t values only for curve (we don't care about t on ray)
   1795     intersections.allowNear(false);
   1796     int pts = (intersections.*CurveVertical[SkPathOpsVerbToPoints(fVerb)])
   1797             (fPts, top, bottom, basePt.fX, false);
   1798     if (pts == 0 || (current && pts == 1)) {
   1799         return bestTIndex;
   1800     }
   1801     if (current) {
   1802         SkASSERT(pts > 1);
   1803         int closestIdx = 0;
   1804         double closest = fabs(intersections[0][0] - mid);
   1805         for (int idx = 1; idx < pts; ++idx) {
   1806             double test = fabs(intersections[0][idx] - mid);
   1807             if (closest > test) {
   1808                 closestIdx = idx;
   1809                 closest = test;
   1810             }
   1811         }
   1812         intersections.quickRemoveOne(closestIdx, --pts);
   1813     }
   1814     double bestT = -1;
   1815     for (int index = 0; index < pts; ++index) {
   1816         double foundT = intersections[0][index];
   1817         if (approximately_less_than_zero(foundT)
   1818                     || approximately_greater_than_one(foundT)) {
   1819             continue;
   1820         }
   1821         SkScalar testY = (*CurvePointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, foundT).fY;
   1822         if (approximately_negative(testY - *bestY)
   1823                 || approximately_negative(basePt.fY - testY)) {
   1824             continue;
   1825         }
   1826         if (pts > 1 && fVerb == SkPath::kLine_Verb) {
   1827             return SK_MinS32;  // if the intersection is edge on, wait for another one
   1828         }
   1829         if (fVerb > SkPath::kLine_Verb) {
   1830             SkScalar dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, foundT).fX;
   1831             if (approximately_zero(dx)) {
   1832                 return SK_MinS32;  // hit vertical, wait for another one
   1833             }
   1834         }
   1835         *bestY = testY;
   1836         bestT = foundT;
   1837     }
   1838     if (bestT < 0) {
   1839         return bestTIndex;
   1840     }
   1841     SkASSERT(bestT >= 0);
   1842     SkASSERT(bestT <= 1);
   1843     int start;
   1844     int end = 0;
   1845     do {
   1846         start = end;
   1847         end = nextSpan(start, 1);
   1848     } while (fTs[end].fT < bestT);
   1849     // FIXME: see next candidate for a better pattern to find the next start/end pair
   1850     while (start + 1 < end && fTs[start].fDone) {
   1851         ++start;
   1852     }
   1853     if (!isCanceled(start)) {
   1854         *hitT = bestT;
   1855         bestTIndex = start;
   1856         *hitSomething = true;
   1857     }
   1858     return bestTIndex;
   1859 }
   1860 
   1861 bool SkOpSegment::decrementSpan(SkOpSpan* span) {
   1862     SkASSERT(span->fWindValue > 0);
   1863     if (--(span->fWindValue) == 0) {
   1864         if (!span->fOppValue && !span->fDone) {
   1865             span->fDone = true;
   1866             ++fDoneSpans;
   1867             return true;
   1868         }
   1869     }
   1870     return false;
   1871 }
   1872 
   1873 bool SkOpSegment::bumpSpan(SkOpSpan* span, int windDelta, int oppDelta) {
   1874     SkASSERT(!span->fDone || span->fTiny || span->fSmall);
   1875     span->fWindValue += windDelta;
   1876     SkASSERT(span->fWindValue >= 0);
   1877     span->fOppValue += oppDelta;
   1878     SkASSERT(span->fOppValue >= 0);
   1879     if (fXor) {
   1880         span->fWindValue &= 1;
   1881     }
   1882     if (fOppXor) {
   1883         span->fOppValue &= 1;
   1884     }
   1885     if (!span->fWindValue && !span->fOppValue) {
   1886         span->fDone = true;
   1887         ++fDoneSpans;
   1888         return true;
   1889     }
   1890     return false;
   1891 }
   1892 
   1893 const SkOpSpan& SkOpSegment::firstSpan(const SkOpSpan& thisSpan) const {
   1894     const SkOpSpan* firstSpan = &thisSpan; // rewind to the start
   1895     const SkOpSpan* beginSpan = fTs.begin();
   1896     const SkPoint& testPt = thisSpan.fPt;
   1897     while (firstSpan > beginSpan && firstSpan[-1].fPt == testPt) {
   1898         --firstSpan;
   1899     }
   1900     return *firstSpan;
   1901 }
   1902 
   1903 const SkOpSpan& SkOpSegment::lastSpan(const SkOpSpan& thisSpan) const {
   1904     const SkOpSpan* endSpan = fTs.end() - 1;  // last can't be small
   1905     const SkOpSpan* lastSpan = &thisSpan;  // find the end
   1906     const SkPoint& testPt = thisSpan.fPt;
   1907     while (lastSpan < endSpan && lastSpan[1].fPt == testPt) {
   1908         ++lastSpan;
   1909     }
   1910     return *lastSpan;
   1911 }
   1912 
   1913 // with a loop, the comparison is move involved
   1914 // scan backwards and forwards to count all matching points
   1915 // (verify that there are twp scans marked as loops)
   1916 // compare that against 2 matching scans for loop plus other results
   1917 bool SkOpSegment::calcLoopSpanCount(const SkOpSpan& thisSpan, int* smallCounts) {
   1918     const SkOpSpan& firstSpan = this->firstSpan(thisSpan); // rewind to the start
   1919     const SkOpSpan& lastSpan = this->lastSpan(thisSpan);  // find the end
   1920     double firstLoopT = -1, lastLoopT = -1;
   1921     const SkOpSpan* testSpan = &firstSpan - 1;
   1922     while (++testSpan <= &lastSpan) {
   1923         if (testSpan->fLoop) {
   1924             firstLoopT = testSpan->fT;
   1925             break;
   1926         }
   1927     }
   1928     testSpan = &lastSpan + 1;
   1929     while (--testSpan >= &firstSpan) {
   1930         if (testSpan->fLoop) {
   1931             lastLoopT = testSpan->fT;
   1932             break;
   1933         }
   1934     }
   1935     SkASSERT((firstLoopT == -1) == (lastLoopT == -1));
   1936     if (firstLoopT == -1) {
   1937         return false;
   1938     }
   1939     SkASSERT(firstLoopT < lastLoopT);
   1940     testSpan = &firstSpan - 1;
   1941     smallCounts[0] = smallCounts[1] = 0;
   1942     while (++testSpan <= &lastSpan) {
   1943         SkASSERT(approximately_equal(testSpan->fT, firstLoopT) +
   1944                 approximately_equal(testSpan->fT, lastLoopT) == 1);
   1945         smallCounts[approximately_equal(testSpan->fT, lastLoopT)]++;
   1946     }
   1947     return true;
   1948 }
   1949 
   1950 double SkOpSegment::calcMissingTEnd(const SkOpSegment* ref, double loEnd, double min, double max,
   1951         double hiEnd, const SkOpSegment* other, int thisStart) {
   1952     if (max >= hiEnd) {
   1953         return -1;
   1954     }
   1955     int end = findOtherT(hiEnd, ref);
   1956     if (end < 0) {
   1957         return -1;
   1958     }
   1959     double tHi = span(end).fT;
   1960     double tLo, refLo;
   1961     if (thisStart >= 0) {
   1962         tLo = span(thisStart).fT;
   1963         refLo = min;
   1964     } else {
   1965         int start1 = findOtherT(loEnd, ref);
   1966         SkASSERT(start1 >= 0);
   1967         tLo = span(start1).fT;
   1968         refLo = loEnd;
   1969     }
   1970     double missingT = (max - refLo) / (hiEnd - refLo);
   1971     missingT = tLo + missingT * (tHi - tLo);
   1972     return missingT;
   1973 }
   1974 
   1975 double SkOpSegment::calcMissingTStart(const SkOpSegment* ref, double loEnd, double min, double max,
   1976         double hiEnd, const SkOpSegment* other, int thisEnd) {
   1977     if (min <= loEnd) {
   1978         return -1;
   1979     }
   1980     int start = findOtherT(loEnd, ref);
   1981     if (start < 0) {
   1982         return -1;
   1983     }
   1984     double tLo = span(start).fT;
   1985     double tHi, refHi;
   1986     if (thisEnd >= 0) {
   1987         tHi = span(thisEnd).fT;
   1988         refHi = max;
   1989     } else {
   1990         int end1 = findOtherT(hiEnd, ref);
   1991         if (end1 < 0) {
   1992             return -1;
   1993         }
   1994         tHi = span(end1).fT;
   1995         refHi = hiEnd;
   1996     }
   1997     double missingT = (min - loEnd) / (refHi - loEnd);
   1998     missingT = tLo + missingT * (tHi - tLo);
   1999     return missingT;
   2000 }
   2001 
   2002 // see if spans with two or more intersections have the same number on the other end
   2003 void SkOpSegment::checkDuplicates() {
   2004     debugValidate();
   2005     SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans;
   2006     int index;
   2007     int endIndex = 0;
   2008     bool endFound;
   2009     do {
   2010         index = endIndex;
   2011         endIndex = nextExactSpan(index, 1);
   2012         if ((endFound = endIndex < 0)) {
   2013             endIndex = count();
   2014         }
   2015         int dupCount = endIndex - index;
   2016         if (dupCount < 2) {
   2017             continue;
   2018         }
   2019         do {
   2020             const SkOpSpan* thisSpan = &fTs[index];
   2021             if (thisSpan->fNear) {
   2022                 continue;
   2023             }
   2024             SkOpSegment* other = thisSpan->fOther;
   2025             int oIndex = thisSpan->fOtherIndex;
   2026             int oStart = other->nextExactSpan(oIndex, -1) + 1;
   2027             int oEnd = other->nextExactSpan(oIndex, 1);
   2028             if (oEnd < 0) {
   2029                 oEnd = other->count();
   2030             }
   2031             int oCount = oEnd - oStart;
   2032             // force the other to match its t and this pt if not on an end point
   2033             if (oCount != dupCount) {
   2034                 MissingSpan& missing = missingSpans.push_back();
   2035                 missing.fOther = NULL;
   2036                 SkDEBUGCODE(sk_bzero(&missing, sizeof(missing)));
   2037                 missing.fPt = thisSpan->fPt;
   2038                 const SkOpSpan& oSpan = other->span(oIndex);
   2039                 if (oCount > dupCount) {
   2040                     missing.fSegment = this;
   2041                     missing.fT = thisSpan->fT;
   2042                     other->checkLinks(&oSpan, &missingSpans);
   2043                 } else {
   2044                     missing.fSegment = other;
   2045                     missing.fT = oSpan.fT;
   2046                     checkLinks(thisSpan, &missingSpans);
   2047                 }
   2048                 if (!missingSpans.back().fOther) {
   2049                     missingSpans.pop_back();
   2050                 }
   2051             }
   2052         } while (++index < endIndex);
   2053     } while (!endFound);
   2054     int missingCount = missingSpans.count();
   2055     if (missingCount == 0) {
   2056         return;
   2057     }
   2058     SkSTArray<kMissingSpanCount, MissingSpan, true> missingCoincidence;
   2059     for (index = 0; index < missingCount; ++index)  {
   2060         MissingSpan& missing = missingSpans[index];
   2061         SkOpSegment* missingOther = missing.fOther;
   2062         if (missing.fSegment == missing.fOther) {
   2063             continue;
   2064         }
   2065 #if 0  // FIXME: this eliminates spurious data from skpwww_argus_presse_fr_41 but breaks
   2066        // skpwww_fashionscandal_com_94 -- calcAngles complains, but I don't understand why
   2067         if (missing.fSegment->containsT(missing.fT, missing.fOther, missing.fOtherT)) {
   2068 #if DEBUG_DUPLICATES
   2069             SkDebugf("skip 1 id=%d t=%1.9g other=%d otherT=%1.9g\n", missing.fSegment->fID,
   2070                     missing.fT, missing.fOther->fID, missing.fOtherT);
   2071 #endif
   2072             continue;
   2073         }
   2074         if (missing.fOther->containsT(missing.fOtherT, missing.fSegment, missing.fT)) {
   2075 #if DEBUG_DUPLICATES
   2076             SkDebugf("skip 2 id=%d t=%1.9g other=%d otherT=%1.9g\n", missing.fOther->fID,
   2077                     missing.fOtherT, missing.fSegment->fID, missing.fT);
   2078 #endif
   2079             continue;
   2080         }
   2081 #endif
   2082         // skip if adding would insert point into an existing coincindent span
   2083         if (missing.fSegment->inCoincidentSpan(missing.fT, missingOther)
   2084                 && missingOther->inCoincidentSpan(missing.fOtherT, this)) {
   2085             continue;
   2086         }
   2087         // skip if the created coincident spans are small
   2088         if (missing.fSegment->coincidentSmall(missing.fPt, missing.fT, missingOther)
   2089                 && missingOther->coincidentSmall(missing.fPt, missing.fOtherT, missing.fSegment)) {
   2090             continue;
   2091         }
   2092         const SkOpSpan* added = missing.fSegment->addTPair(missing.fT, missingOther,
   2093                 missing.fOtherT, false, missing.fPt);
   2094         if (added && added->fSmall) {
   2095             missing.fSegment->checkSmallCoincidence(*added, &missingCoincidence);
   2096         }
   2097     }
   2098     for (index = 0; index < missingCount; ++index)  {
   2099         MissingSpan& missing = missingSpans[index];
   2100         missing.fSegment->fixOtherTIndex();
   2101         missing.fOther->fixOtherTIndex();
   2102     }
   2103     for (index = 0; index < missingCoincidence.count(); ++index) {
   2104         MissingSpan& missing = missingCoincidence[index];
   2105         missing.fSegment->fixOtherTIndex();
   2106     }
   2107     debugValidate();
   2108 }
   2109 
   2110 // look to see if the curve end intersects an intermediary that intersects the other
   2111 void SkOpSegment::checkEnds() {
   2112     debugValidate();
   2113     SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans;
   2114     int count = fTs.count();
   2115     for (int index = 0; index < count; ++index) {
   2116         const SkOpSpan& span = fTs[index];
   2117         double otherT = span.fOtherT;
   2118         if (otherT != 0 && otherT != 1) { // only check ends
   2119             continue;
   2120         }
   2121         const SkOpSegment* other = span.fOther;
   2122         // peek start/last describe the range of spans that match the other t of this span
   2123         int peekStart = span.fOtherIndex;
   2124         while (--peekStart >= 0 && other->fTs[peekStart].fT == otherT)
   2125             ;
   2126         int otherCount = other->fTs.count();
   2127         int peekLast = span.fOtherIndex;
   2128         while (++peekLast < otherCount && other->fTs[peekLast].fT == otherT)
   2129             ;
   2130         if (++peekStart == --peekLast) { // if there isn't a range, there's nothing to do
   2131             continue;
   2132         }
   2133         // t start/last describe the range of spans that match the t of this span
   2134         double t = span.fT;
   2135         double tBottom = -1;
   2136         int tStart = -1;
   2137         int tLast = count;
   2138         bool lastSmall = false;
   2139         double afterT = t;
   2140         for (int inner = 0; inner < count; ++inner) {
   2141             double innerT = fTs[inner].fT;
   2142             if (innerT <= t && innerT > tBottom) {
   2143                 if (innerT < t || !lastSmall) {
   2144                     tStart = inner - 1;
   2145                 }
   2146                 tBottom = innerT;
   2147             }
   2148             if (innerT > afterT) {
   2149                 if (t == afterT && lastSmall) {
   2150                     afterT = innerT;
   2151                 } else {
   2152                     tLast = inner;
   2153                     break;
   2154                 }
   2155             }
   2156             lastSmall = innerT <= t ? fTs[inner].fSmall : false;
   2157         }
   2158         for (int peekIndex = peekStart; peekIndex <= peekLast; ++peekIndex) {
   2159             if (peekIndex == span.fOtherIndex) {  // skip the other span pointed to by this span
   2160                 continue;
   2161             }
   2162             const SkOpSpan& peekSpan = other->fTs[peekIndex];
   2163             SkOpSegment* match = peekSpan.fOther;
   2164             if (match->done()) {
   2165                 continue;  // if the edge has already been eaten (likely coincidence), ignore it
   2166             }
   2167             const double matchT = peekSpan.fOtherT;
   2168             // see if any of the spans match the other spans
   2169             for (int tIndex = tStart + 1; tIndex < tLast; ++tIndex) {
   2170                 const SkOpSpan& tSpan = fTs[tIndex];
   2171                 if (tSpan.fOther == match) {
   2172                     if (tSpan.fOtherT == matchT) {
   2173                         goto nextPeekIndex;
   2174                     }
   2175                     double midT = (tSpan.fOtherT + matchT) / 2;
   2176                     if (match->betweenPoints(midT, tSpan.fPt, peekSpan.fPt)) {
   2177                         goto nextPeekIndex;
   2178                     }
   2179                 }
   2180             }
   2181             if (missingSpans.count() > 0) {
   2182                 const MissingSpan& lastMissing = missingSpans.back();
   2183                 if (lastMissing.fT == t
   2184                         && lastMissing.fOther == match
   2185                         && lastMissing.fOtherT == matchT) {
   2186                     SkASSERT(lastMissing.fPt == peekSpan.fPt);
   2187                     continue;
   2188                 }
   2189             }
   2190 #if DEBUG_CHECK_ENDS
   2191             SkDebugf("%s id=%d missing t=%1.9g other=%d otherT=%1.9g pt=(%1.9g,%1.9g)\n",
   2192                     __FUNCTION__, fID, t, match->fID, matchT, peekSpan.fPt.fX, peekSpan.fPt.fY);
   2193 #endif
   2194             // this segment is missing a entry that the other contains
   2195             // remember so we can add the missing one and recompute the indices
   2196             {
   2197                 MissingSpan& missing = missingSpans.push_back();
   2198                 SkDEBUGCODE(sk_bzero(&missing, sizeof(missing)));
   2199                 missing.fT = t;
   2200                 SkASSERT(this != match);
   2201                 missing.fOther = match;
   2202                 missing.fOtherT = matchT;
   2203                 missing.fPt = peekSpan.fPt;
   2204             }
   2205             break;
   2206 nextPeekIndex:
   2207             ;
   2208         }
   2209     }
   2210     if (missingSpans.count() == 0) {
   2211         debugValidate();
   2212         return;
   2213     }
   2214     debugValidate();
   2215     int missingCount = missingSpans.count();
   2216     for (int index = 0; index < missingCount; ++index)  {
   2217         MissingSpan& missing = missingSpans[index];
   2218         if (this != missing.fOther) {
   2219             addTPair(missing.fT, missing.fOther, missing.fOtherT, false, missing.fPt);
   2220         }
   2221     }
   2222     fixOtherTIndex();
   2223     // OPTIMIZATION: this may fix indices more than once. Build an array of unique segments to
   2224     // avoid this
   2225     for (int index = 0; index < missingCount; ++index)  {
   2226         missingSpans[index].fOther->fixOtherTIndex();
   2227     }
   2228     debugValidate();
   2229 }
   2230 
   2231 void SkOpSegment::checkLinks(const SkOpSpan* base,
   2232         SkTArray<MissingSpan, true>* missingSpans) const {
   2233     const SkOpSpan* first = fTs.begin();
   2234     const SkOpSpan* last = fTs.end() - 1;
   2235     SkASSERT(base >= first && last >= base);
   2236     const SkOpSegment* other = base->fOther;
   2237     const SkOpSpan* oFirst = other->fTs.begin();
   2238     const SkOpSpan* oLast = other->fTs.end() - 1;
   2239     const SkOpSpan* oSpan = &other->fTs[base->fOtherIndex];
   2240     const SkOpSpan* test = base;
   2241     const SkOpSpan* missing = NULL;
   2242     while (test > first && (--test)->fPt == base->fPt) {
   2243         if (this == test->fOther) {
   2244             continue;
   2245         }
   2246         CheckOneLink(test, oSpan, oFirst, oLast, &missing, missingSpans);
   2247     }
   2248     test = base;
   2249     while (test < last && (++test)->fPt == base->fPt) {
   2250         SkASSERT(this != test->fOther);
   2251         CheckOneLink(test, oSpan, oFirst, oLast, &missing, missingSpans);
   2252     }
   2253 }
   2254 
   2255 // see if spans with two or more intersections all agree on common t and point values
   2256 void SkOpSegment::checkMultiples() {
   2257     debugValidate();
   2258     int index;
   2259     int end = 0;
   2260     while (fTs[++end].fT == 0)
   2261         ;
   2262     while (fTs[end].fT < 1) {
   2263         int start = index = end;
   2264         end = nextExactSpan(index, 1);
   2265         if (end <= index) {
   2266             return;  // buffer overflow example triggers this
   2267         }
   2268         if (index + 1 == end) {
   2269             continue;
   2270         }
   2271         // force the duplicates to agree on t and pt if not on the end
   2272         SkOpSpan& span = fTs[index];
   2273         double thisT = span.fT;
   2274         const SkPoint& thisPt = span.fPt;
   2275         span.fMultiple = true;
   2276         bool aligned = false;
   2277         while (++index < end) {
   2278             aligned |= alignSpan(index, thisT, thisPt);
   2279         }
   2280         if (aligned) {
   2281             alignSpanState(start, end);
   2282         }
   2283         fMultiples = true;
   2284     }
   2285     debugValidate();
   2286 }
   2287 
   2288 void SkOpSegment::CheckOneLink(const SkOpSpan* test, const SkOpSpan* oSpan,
   2289         const SkOpSpan* oFirst, const SkOpSpan* oLast, const SkOpSpan** missingPtr,
   2290         SkTArray<MissingSpan, true>* missingSpans) {
   2291     SkASSERT(oSpan->fPt == test->fPt);
   2292     const SkOpSpan* oTest = oSpan;
   2293     while (oTest > oFirst && (--oTest)->fPt == test->fPt) {
   2294         if (oTest->fOther == test->fOther && oTest->fOtherT == test->fOtherT) {
   2295             return;
   2296         }
   2297     }
   2298     oTest = oSpan;
   2299     while (oTest < oLast && (++oTest)->fPt == test->fPt) {
   2300         if (oTest->fOther == test->fOther && oTest->fOtherT == test->fOtherT) {
   2301             return;
   2302         }
   2303     }
   2304     if (*missingPtr) {
   2305         missingSpans->push_back();
   2306     }
   2307     MissingSpan& lastMissing = missingSpans->back();
   2308     if (*missingPtr) {
   2309         lastMissing = missingSpans->end()[-2];
   2310     }
   2311     *missingPtr = test;
   2312     lastMissing.fOther = test->fOther;
   2313     lastMissing.fOtherT = test->fOtherT;
   2314 }
   2315 
   2316 bool SkOpSegment::checkSmall(int index) const {
   2317     if (fTs[index].fSmall) {
   2318         return true;
   2319     }
   2320     double tBase = fTs[index].fT;
   2321     while (index > 0 && precisely_negative(tBase - fTs[--index].fT))
   2322         ;
   2323     return fTs[index].fSmall;
   2324 }
   2325 
   2326 // a pair of curves may turn into coincident lines -- small may be a hint that that happened
   2327 // if a cubic contains a loop, the counts must be adjusted
   2328 void SkOpSegment::checkSmall() {
   2329     SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans;
   2330     const SkOpSpan* beginSpan = fTs.begin();
   2331     const SkOpSpan* thisSpan = beginSpan - 1;
   2332     const SkOpSpan* endSpan = fTs.end() - 1;  // last can't be small
   2333     while (++thisSpan < endSpan) {
   2334         if (!thisSpan->fSmall) {
   2335             continue;
   2336         }
   2337         if (!thisSpan->fWindValue) {
   2338             continue;
   2339         }
   2340         const SkOpSpan& firstSpan = this->firstSpan(*thisSpan);
   2341         const SkOpSpan& lastSpan = this->lastSpan(*thisSpan);
   2342         const SkOpSpan* nextSpan = &firstSpan + 1;
   2343         ptrdiff_t smallCount = &lastSpan - &firstSpan + 1;
   2344         SkASSERT(1 <= smallCount && smallCount < count());
   2345         if (smallCount <= 1 && !nextSpan->fSmall) {
   2346             SkASSERT(1 == smallCount);
   2347             checkSmallCoincidence(firstSpan, NULL);
   2348             continue;
   2349         }
   2350         // at this point, check for missing computed intersections
   2351         const SkPoint& testPt = firstSpan.fPt;
   2352         thisSpan = &firstSpan - 1;
   2353         SkOpSegment* other = NULL;
   2354         while (++thisSpan <= &lastSpan) {
   2355             other = thisSpan->fOther;
   2356             if (other != this) {
   2357                 break;
   2358             }
   2359         }
   2360         SkASSERT(other != this);
   2361         int oIndex = thisSpan->fOtherIndex;
   2362         const SkOpSpan& oSpan = other->span(oIndex);
   2363         const SkOpSpan& oFirstSpan = other->firstSpan(oSpan);
   2364         const SkOpSpan& oLastSpan = other->lastSpan(oSpan);
   2365         ptrdiff_t oCount = &oLastSpan - &oFirstSpan + 1;
   2366         if (fLoop) {
   2367             int smallCounts[2];
   2368             SkASSERT(!other->fLoop);  // FIXME: we need more complicated logic for pair of loops
   2369             if (calcLoopSpanCount(*thisSpan, smallCounts)) {
   2370                 if (smallCounts[0] && oCount != smallCounts[0]) {
   2371                     SkASSERT(0);  // FIXME: need a working test case to properly code & debug
   2372                 }
   2373                 if (smallCounts[1] && oCount != smallCounts[1]) {
   2374                     SkASSERT(0);  // FIXME: need a working test case to properly code & debug
   2375                 }
   2376                 goto nextSmallCheck;
   2377             }
   2378         }
   2379         if (other->fLoop) {
   2380             int otherCounts[2];
   2381             if (other->calcLoopSpanCount(other->span(oIndex), otherCounts)) {
   2382                 if (otherCounts[0] && otherCounts[0] != smallCount) {
   2383                     SkASSERT(0);  // FIXME: need a working test case to properly code & debug
   2384                 }
   2385                 if (otherCounts[1] && otherCounts[1] != smallCount) {
   2386                     SkASSERT(0);  // FIXME: need a working test case to properly code & debug
   2387                 }
   2388                 goto nextSmallCheck;
   2389             }
   2390         }
   2391         if (oCount != smallCount) {  // check if number of pts in this match other
   2392             MissingSpan& missing = missingSpans.push_back();
   2393             missing.fOther = NULL;
   2394             SkDEBUGCODE(sk_bzero(&missing, sizeof(missing)));
   2395             missing.fPt = testPt;
   2396             const SkOpSpan& oSpan = other->span(oIndex);
   2397             if (oCount > smallCount) {
   2398                 missing.fSegment = this;
   2399                 missing.fT = thisSpan->fT;
   2400                 other->checkLinks(&oSpan, &missingSpans);
   2401             } else {
   2402                 missing.fSegment = other;
   2403                 missing.fT = oSpan.fT;
   2404                 checkLinks(thisSpan, &missingSpans);
   2405             }
   2406             if (!missingSpans.back().fOther || missing.fSegment->done()) {
   2407                 missingSpans.pop_back();
   2408             }
   2409         }
   2410 nextSmallCheck:
   2411         thisSpan = &lastSpan;
   2412     }
   2413     int missingCount = missingSpans.count();
   2414     for (int index = 0; index < missingCount; ++index)  {
   2415         MissingSpan& missing = missingSpans[index];
   2416         SkOpSegment* missingOther = missing.fOther;
   2417         // note that add t pair may edit span arrays, so prior pointers to spans are no longer valid
   2418         if (!missing.fSegment->addTPair(missing.fT, missingOther, missing.fOtherT, false,
   2419                 missing.fPt)) {
   2420             continue;
   2421         }
   2422         int otherTIndex = missingOther->findT(missing.fOtherT, missing.fPt, missing.fSegment);
   2423         const SkOpSpan& otherSpan = missingOther->span(otherTIndex);
   2424         if (otherSpan.fSmall) {
   2425             const SkOpSpan* nextSpan = &otherSpan;
   2426             do {
   2427                 ++nextSpan;
   2428             } while (nextSpan->fSmall);
   2429             SkAssertResult(missing.fSegment->addTCoincident(missing.fPt, nextSpan->fPt,
   2430                     nextSpan->fT, missingOther));
   2431         } else if (otherSpan.fT > 0) {
   2432             const SkOpSpan* priorSpan = &otherSpan;
   2433             do {
   2434                 --priorSpan;
   2435             } while (priorSpan->fT == otherSpan.fT);
   2436             if (priorSpan->fSmall) {
   2437                 missing.fSegment->addTCancel(missing.fPt, priorSpan->fPt, missingOther);
   2438             }
   2439         }
   2440     }
   2441     // OPTIMIZATION: this may fix indices more than once. Build an array of unique segments to
   2442     // avoid this
   2443     for (int index = 0; index < missingCount; ++index)  {
   2444         MissingSpan& missing = missingSpans[index];
   2445         missing.fSegment->fixOtherTIndex();
   2446         missing.fOther->fixOtherTIndex();
   2447     }
   2448     debugValidate();
   2449 }
   2450 
   2451 void SkOpSegment::checkSmallCoincidence(const SkOpSpan& span,
   2452         SkTArray<MissingSpan, true>* checkMultiple) {
   2453     SkASSERT(span.fSmall);
   2454     if (0 && !span.fWindValue) {
   2455         return;
   2456     }
   2457     SkASSERT(&span < fTs.end() - 1);
   2458     const SkOpSpan* next = &span + 1;
   2459     SkASSERT(!next->fSmall || checkMultiple);
   2460     if (checkMultiple) {
   2461         while (next->fSmall) {
   2462             ++next;
   2463             SkASSERT(next < fTs.end());
   2464         }
   2465     }
   2466     SkOpSegment* other = span.fOther;
   2467     while (other != next->fOther) {
   2468         if (!checkMultiple) {
   2469             return;
   2470         }
   2471         const SkOpSpan* test = next + 1;
   2472         if (test == fTs.end()) {
   2473             return;
   2474         }
   2475         if (test->fPt != next->fPt || !precisely_equal(test->fT, next->fT)) {
   2476             return;
   2477         }
   2478         next = test;
   2479     }
   2480     SkASSERT(span.fT < next->fT);
   2481     int oStartIndex = other->findExactT(span.fOtherT, this);
   2482     int oEndIndex = other->findExactT(next->fOtherT, this);
   2483     // FIXME: be overly conservative by limiting this to the caller that allows multiple smalls
   2484     if (!checkMultiple || fVerb != SkPath::kLine_Verb || other->fVerb != SkPath::kLine_Verb) {
   2485         SkPoint mid = ptAtT((span.fT + next->fT) / 2);
   2486         const SkOpSpan& oSpanStart = other->fTs[oStartIndex];
   2487         const SkOpSpan& oSpanEnd = other->fTs[oEndIndex];
   2488         SkPoint oMid = other->ptAtT((oSpanStart.fT + oSpanEnd.fT) / 2);
   2489         if (!SkDPoint::ApproximatelyEqual(mid, oMid)) {
   2490             return;
   2491         }
   2492     }
   2493     // FIXME: again, be overly conservative to avoid breaking existing tests
   2494     const SkOpSpan& oSpan = oStartIndex < oEndIndex ? other->fTs[oStartIndex]
   2495             : other->fTs[oEndIndex];
   2496     if (checkMultiple && !oSpan.fSmall) {
   2497         return;
   2498     }
   2499 //    SkASSERT(oSpan.fSmall);
   2500     if (oStartIndex < oEndIndex) {
   2501         SkAssertResult(addTCoincident(span.fPt, next->fPt, next->fT, other));
   2502     } else {
   2503         addTCancel(span.fPt, next->fPt, other);
   2504     }
   2505     if (!checkMultiple) {
   2506         return;
   2507     }
   2508     // check to see if either segment is coincident with a third segment -- if it is, and if
   2509     // the opposite segment is not already coincident with the third, make it so
   2510     // OPTIMIZE: to make this check easier, add coincident and cancel could set a coincident bit
   2511     if (span.fWindValue != 1 || span.fOppValue != 0) {
   2512 //        start here;
   2513         // iterate through the spans, looking for the third coincident case
   2514         // if we find one, we need to return state to the caller so that the indices can be fixed
   2515         // this also suggests that all of this function is fragile since it relies on a valid index
   2516     }
   2517     // probably should make this a common function rather than copy/paste code
   2518     if (oSpan.fWindValue != 1 || oSpan.fOppValue != 0) {
   2519         const SkOpSpan* oTest = &oSpan;
   2520         while (--oTest >= other->fTs.begin()) {
   2521             if (oTest->fPt != oSpan.fPt || !precisely_equal(oTest->fT, oSpan.fT)) {
   2522                 break;
   2523             }
   2524             SkOpSegment* testOther = oTest->fOther;
   2525             SkASSERT(testOther != this);
   2526             // look in both directions to see if there is a coincident span
   2527             const SkOpSpan* tTest = testOther->fTs.begin();
   2528             for (int testIndex = 0; testIndex < testOther->count(); ++testIndex) {
   2529                 if (tTest->fPt != span.fPt) {
   2530                     ++tTest;
   2531                     continue;
   2532                 }
   2533                 if (testOther->verb() != SkPath::kLine_Verb
   2534                         || other->verb() != SkPath::kLine_Verb) {
   2535                     SkPoint mid = ptAtT((span.fT + next->fT) / 2);
   2536                     SkPoint oMid = other->ptAtT((oTest->fOtherT + tTest->fT) / 2);
   2537                     if (!SkDPoint::ApproximatelyEqual(mid, oMid)) {
   2538                         continue;
   2539                     }
   2540                 }
   2541 #if DEBUG_CONCIDENT
   2542                 SkDebugf("%s coincident found=%d %1.9g %1.9g\n", __FUNCTION__, testOther->fID,
   2543                         oTest->fOtherT, tTest->fT);
   2544 #endif
   2545                 if (tTest->fT < oTest->fOtherT) {
   2546                     SkAssertResult(addTCoincident(span.fPt, next->fPt, next->fT, testOther));
   2547                 } else {
   2548                     addTCancel(span.fPt, next->fPt, testOther);
   2549                 }
   2550                 MissingSpan missing;
   2551                 missing.fSegment = testOther;
   2552                 checkMultiple->push_back(missing);
   2553                 break;
   2554             }
   2555         }
   2556         oTest = &oSpan;
   2557         while (++oTest < other->fTs.end()) {
   2558             if (oTest->fPt != oSpan.fPt || !precisely_equal(oTest->fT, oSpan.fT)) {
   2559                 break;
   2560             }
   2561 
   2562         }
   2563     }
   2564 }
   2565 
   2566 // if pair of spans on either side of tiny have the same end point and mid point, mark
   2567 // them as parallel
   2568 void SkOpSegment::checkTiny() {
   2569     SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans;
   2570     SkOpSpan* thisSpan = fTs.begin() - 1;
   2571     const SkOpSpan* endSpan = fTs.end() - 1;  // last can't be tiny
   2572     while (++thisSpan < endSpan) {
   2573         if (!thisSpan->fTiny) {
   2574             continue;
   2575         }
   2576         SkOpSpan* nextSpan = thisSpan + 1;
   2577         double thisT = thisSpan->fT;
   2578         double nextT = nextSpan->fT;
   2579         if (thisT == nextT) {
   2580             continue;
   2581         }
   2582         SkASSERT(thisT < nextT);
   2583         SkASSERT(thisSpan->fPt == nextSpan->fPt);
   2584         SkOpSegment* thisOther = thisSpan->fOther;
   2585         SkOpSegment* nextOther = nextSpan->fOther;
   2586         int oIndex = thisSpan->fOtherIndex;
   2587         for (int oStep = -1; oStep <= 1; oStep += 2) {
   2588             int oEnd = thisOther->nextExactSpan(oIndex, oStep);
   2589             if (oEnd < 0) {
   2590                 continue;
   2591             }
   2592             const SkOpSpan& oSpan = thisOther->span(oEnd);
   2593             int nIndex = nextSpan->fOtherIndex;
   2594             for (int nStep = -1; nStep <= 1; nStep += 2) {
   2595                 int nEnd = nextOther->nextExactSpan(nIndex, nStep);
   2596                 if (nEnd < 0) {
   2597                     continue;
   2598                 }
   2599                 const SkOpSpan& nSpan = nextOther->span(nEnd);
   2600                 if (oSpan.fPt != nSpan.fPt) {
   2601                     continue;
   2602                 }
   2603                 double oMidT = (thisSpan->fOtherT + oSpan.fT) / 2;
   2604                 const SkPoint& oPt = thisOther->ptAtT(oMidT);
   2605                 double nMidT = (nextSpan->fOtherT + nSpan.fT) / 2;
   2606                 const SkPoint& nPt = nextOther->ptAtT(nMidT);
   2607                 if (!AlmostEqualUlps(oPt, nPt)) {
   2608                     continue;
   2609                 }
   2610 #if DEBUG_CHECK_TINY
   2611                 SkDebugf("%s [%d] add coincidence [%d] [%d]\n", __FUNCTION__, fID,
   2612                     thisOther->fID, nextOther->fID);
   2613 #endif
   2614                 // this segment is missing a entry that the other contains
   2615                 // remember so we can add the missing one and recompute the indices
   2616                 MissingSpan& missing = missingSpans.push_back();
   2617                 SkDEBUGCODE(sk_bzero(&missing, sizeof(missing)));
   2618                 missing.fSegment = thisOther;
   2619                 missing.fT = thisSpan->fOtherT;
   2620                 SkASSERT(this != nextOther);
   2621                 missing.fOther = nextOther;
   2622                 missing.fOtherT = nextSpan->fOtherT;
   2623                 missing.fPt = thisSpan->fPt;
   2624             }
   2625         }
   2626     }
   2627     int missingCount = missingSpans.count();
   2628     if (!missingCount) {
   2629         return;
   2630     }
   2631     for (int index = 0; index < missingCount; ++index)  {
   2632         MissingSpan& missing = missingSpans[index];
   2633         if (missing.fSegment != missing.fOther) {
   2634             missing.fSegment->addTPair(missing.fT, missing.fOther, missing.fOtherT, false,
   2635                     missing.fPt);
   2636         }
   2637     }
   2638     // OPTIMIZE: consolidate to avoid multiple calls to fix index
   2639     for (int index = 0; index < missingCount; ++index)  {
   2640         MissingSpan& missing = missingSpans[index];
   2641         missing.fSegment->fixOtherTIndex();
   2642         missing.fOther->fixOtherTIndex();
   2643     }
   2644 }
   2645 
   2646 bool SkOpSegment::coincidentSmall(const SkPoint& pt, double t, const SkOpSegment* other) const {
   2647     int count = this->count();
   2648     for (int index = 0; index < count; ++index) {
   2649         const SkOpSpan& span = this->span(index);
   2650         if (span.fOther != other) {
   2651             continue;
   2652         }
   2653         if (span.fPt == pt) {
   2654             continue;
   2655         }
   2656         if (!AlmostEqualUlps(span.fPt, pt)) {
   2657             continue;
   2658         }
   2659         if (fVerb != SkPath::kCubic_Verb) {
   2660             return true;
   2661         }
   2662         double tInterval = t - span.fT;
   2663         double tMid = t - tInterval / 2;
   2664         SkDPoint midPt = dcubic_xy_at_t(fPts, tMid);
   2665         return midPt.approximatelyEqual(xyAtT(t));
   2666     }
   2667     return false;
   2668 }
   2669 
   2670 bool SkOpSegment::findCoincidentMatch(const SkOpSpan* span, const SkOpSegment* other, int oStart,
   2671         int oEnd, int step, SkPoint* startPt, SkPoint* endPt, double* endT) const {
   2672     SkASSERT(span->fT == 0 || span->fT == 1);
   2673     SkASSERT(span->fOtherT == 0 || span->fOtherT == 1);
   2674     const SkOpSpan* otherSpan = &other->span(oEnd);
   2675     double refT = otherSpan->fT;
   2676     const SkPoint& refPt = otherSpan->fPt;
   2677     const SkOpSpan* lastSpan = &other->span(step > 0 ? other->count() - 1 : 0);
   2678     do {
   2679         const SkOpSegment* match = span->fOther;
   2680         if (match == otherSpan->fOther) {
   2681             // find start of respective spans and see if both have winding
   2682             int startIndex, endIndex;
   2683             if (span->fOtherT == 1) {
   2684                 endIndex = span->fOtherIndex;
   2685                 startIndex = match->nextExactSpan(endIndex, -1);
   2686             } else {
   2687                 startIndex = span->fOtherIndex;
   2688                 endIndex = match->nextExactSpan(startIndex, 1);
   2689             }
   2690             const SkOpSpan& startSpan = match->span(startIndex);
   2691             if (startSpan.fWindValue != 0) {
   2692                 // draw ray from endSpan.fPt perpendicular to end tangent and measure distance
   2693                 // to other segment.
   2694                 const SkOpSpan& endSpan = match->span(endIndex);
   2695                 SkDLine ray;
   2696                 SkVector dxdy;
   2697                 if (span->fOtherT == 1) {
   2698                     ray.fPts[0].set(startSpan.fPt);
   2699                     dxdy = match->dxdy(startIndex);
   2700                 } else {
   2701                     ray.fPts[0].set(endSpan.fPt);
   2702                     dxdy = match->dxdy(endIndex);
   2703                 }
   2704                 ray.fPts[1].fX = ray.fPts[0].fX + dxdy.fY;
   2705                 ray.fPts[1].fY = ray.fPts[0].fY - dxdy.fX;
   2706                 SkIntersections i;
   2707                 int roots = (i.*CurveRay[SkPathOpsVerbToPoints(other->verb())])(other->pts(), ray);
   2708                 for (int index = 0; index < roots; ++index) {
   2709                     if (ray.fPts[0].approximatelyEqual(i.pt(index))) {
   2710                         double matchMidT = (match->span(startIndex).fT
   2711                                 + match->span(endIndex).fT) / 2;
   2712                         SkPoint matchMidPt = match->ptAtT(matchMidT);
   2713                         double otherMidT = (i[0][index] + other->span(oStart).fT) / 2;
   2714                         SkPoint otherMidPt = other->ptAtT(otherMidT);
   2715                         if (SkDPoint::ApproximatelyEqual(matchMidPt, otherMidPt)) {
   2716                             *startPt = startSpan.fPt;
   2717                             *endPt = endSpan.fPt;
   2718                             *endT = endSpan.fT;
   2719                             return true;
   2720                         }
   2721                     }
   2722                 }
   2723             }
   2724             return false;
   2725         }
   2726         if (otherSpan == lastSpan) {
   2727             break;
   2728         }
   2729         otherSpan += step;
   2730     } while (otherSpan->fT == refT || otherSpan->fPt == refPt);
   2731     return false;
   2732 }
   2733 
   2734 int SkOpSegment::findEndSpan(int endIndex) const {
   2735     const SkOpSpan* span = &fTs[--endIndex];
   2736     const SkPoint& lastPt = span->fPt;
   2737     double endT = span->fT;
   2738     do {
   2739         span = &fTs[--endIndex];
   2740     } while (SkDPoint::ApproximatelyEqual(span->fPt, lastPt) && (span->fT == endT || span->fTiny));
   2741     return endIndex + 1;
   2742 }
   2743 
   2744 /*
   2745  The M and S variable name parts stand for the operators.
   2746    Mi stands for Minuend (see wiki subtraction, analogous to difference)
   2747    Su stands for Subtrahend
   2748  The Opp variable name part designates that the value is for the Opposite operator.
   2749  Opposite values result from combining coincident spans.
   2750  */
   2751 SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpan*>* chase, int* nextStart, int* nextEnd,
   2752                                      bool* unsortable, SkPathOp op, const int xorMiMask,
   2753                                      const int xorSuMask) {
   2754     const int startIndex = *nextStart;
   2755     const int endIndex = *nextEnd;
   2756     SkASSERT(startIndex != endIndex);
   2757     SkDEBUGCODE(const int count = fTs.count());
   2758     SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
   2759     int step = SkSign32(endIndex - startIndex);
   2760     *nextStart = startIndex;
   2761     SkOpSegment* other = isSimple(nextStart, &step);
   2762     if (other)
   2763     {
   2764     // mark the smaller of startIndex, endIndex done, and all adjacent
   2765     // spans with the same T value (but not 'other' spans)
   2766 #if DEBUG_WINDING
   2767         SkDebugf("%s simple\n", __FUNCTION__);
   2768 #endif
   2769         int min = SkMin32(startIndex, endIndex);
   2770         if (fTs[min].fDone) {
   2771             return NULL;
   2772         }
   2773         markDoneBinary(min);
   2774         double startT = other->fTs[*nextStart].fT;
   2775         *nextEnd = *nextStart;
   2776         do {
   2777             *nextEnd += step;
   2778         } while (precisely_zero(startT - other->fTs[*nextEnd].fT));
   2779         SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count());
   2780         if (other->isTiny(SkMin32(*nextStart, *nextEnd))) {
   2781             *unsortable = true;
   2782             return NULL;
   2783         }
   2784         return other;
   2785     }
   2786     const int end = nextExactSpan(startIndex, step);
   2787     SkASSERT(end >= 0);
   2788     SkASSERT(startIndex - endIndex != 0);
   2789     SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
   2790     // more than one viable candidate -- measure angles to find best
   2791 
   2792     int calcWinding = computeSum(startIndex, end, SkOpAngle::kBinaryOpp);
   2793     bool sortable = calcWinding != SK_NaN32;
   2794     if (!sortable) {
   2795         *unsortable = true;
   2796         markDoneBinary(SkMin32(startIndex, endIndex));
   2797         return NULL;
   2798     }
   2799     SkOpAngle* angle = spanToAngle(end, startIndex);
   2800     if (angle->unorderable()) {
   2801         *unsortable = true;
   2802         markDoneBinary(SkMin32(startIndex, endIndex));
   2803         return NULL;
   2804     }
   2805 #if DEBUG_SORT
   2806     SkDebugf("%s\n", __FUNCTION__);
   2807     angle->debugLoop();
   2808 #endif
   2809     int sumMiWinding = updateWinding(endIndex, startIndex);
   2810     if (sumMiWinding == SK_MinS32) {
   2811         *unsortable = true;
   2812         markDoneBinary(SkMin32(startIndex, endIndex));
   2813         return NULL;
   2814     }
   2815     int sumSuWinding = updateOppWinding(endIndex, startIndex);
   2816     if (operand()) {
   2817         SkTSwap<int>(sumMiWinding, sumSuWinding);
   2818     }
   2819     SkOpAngle* nextAngle = angle->next();
   2820     const SkOpAngle* foundAngle = NULL;
   2821     bool foundDone = false;
   2822     // iterate through the angle, and compute everyone's winding
   2823     SkOpSegment* nextSegment;
   2824     int activeCount = 0;
   2825     do {
   2826         nextSegment = nextAngle->segment();
   2827         bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
   2828                 nextAngle->end(), op, &sumMiWinding, &sumSuWinding);
   2829         if (activeAngle) {
   2830             ++activeCount;
   2831             if (!foundAngle || (foundDone && activeCount & 1)) {
   2832                 if (nextSegment->isTiny(nextAngle)) {
   2833                     *unsortable = true;
   2834                     markDoneBinary(SkMin32(startIndex, endIndex));
   2835                     return NULL;
   2836                 }
   2837                 foundAngle = nextAngle;
   2838                 foundDone = nextSegment->done(nextAngle);
   2839             }
   2840         }
   2841         if (nextSegment->done()) {
   2842             continue;
   2843         }
   2844         if (nextSegment->isTiny(nextAngle)) {
   2845             continue;
   2846         }
   2847         if (!activeAngle) {
   2848             (void) nextSegment->markAndChaseDoneBinary(nextAngle->start(), nextAngle->end());
   2849         }
   2850         SkOpSpan* last = nextAngle->lastMarked();
   2851         if (last) {
   2852             SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
   2853             *chase->append() = last;
   2854 #if DEBUG_WINDING
   2855             SkDebugf("%s chase.append id=%d windSum=%d small=%d\n", __FUNCTION__,
   2856                     last->fOther->fTs[last->fOtherIndex].fOther->debugID(), last->fWindSum,
   2857                     last->fSmall);
   2858 #endif
   2859         }
   2860     } while ((nextAngle = nextAngle->next()) != angle);
   2861 #if DEBUG_ANGLE
   2862     if (foundAngle) {
   2863         foundAngle->debugSameAs(foundAngle);
   2864     }
   2865 #endif
   2866 
   2867     markDoneBinary(SkMin32(startIndex, endIndex));
   2868     if (!foundAngle) {
   2869         return NULL;
   2870     }
   2871     *nextStart = foundAngle->start();
   2872     *nextEnd = foundAngle->end();
   2873     nextSegment = foundAngle->segment();
   2874 #if DEBUG_WINDING
   2875     SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
   2876             __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
   2877  #endif
   2878     return nextSegment;
   2879 }
   2880 
   2881 SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpan*>* chase, int* nextStart,
   2882                                           int* nextEnd, bool* unsortable) {
   2883     const int startIndex = *nextStart;
   2884     const int endIndex = *nextEnd;
   2885     SkASSERT(startIndex != endIndex);
   2886     SkDEBUGCODE(const int count = fTs.count());
   2887     SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
   2888     int step = SkSign32(endIndex - startIndex);
   2889     *nextStart = startIndex;
   2890     SkOpSegment* other = isSimple(nextStart, &step);
   2891     if (other)
   2892     {
   2893     // mark the smaller of startIndex, endIndex done, and all adjacent
   2894     // spans with the same T value (but not 'other' spans)
   2895 #if DEBUG_WINDING
   2896         SkDebugf("%s simple\n", __FUNCTION__);
   2897 #endif
   2898         int min = SkMin32(startIndex, endIndex);
   2899         if (fTs[min].fDone) {
   2900             return NULL;
   2901         }
   2902         markDoneUnary(min);
   2903         double startT = other->fTs[*nextStart].fT;
   2904         *nextEnd = *nextStart;
   2905         do {
   2906             *nextEnd += step;
   2907         } while (precisely_zero(startT - other->fTs[*nextEnd].fT));
   2908         SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count());
   2909         if (other->isTiny(SkMin32(*nextStart, *nextEnd))) {
   2910             *unsortable = true;
   2911             return NULL;
   2912         }
   2913         return other;
   2914     }
   2915     const int end = nextExactSpan(startIndex, step);
   2916     SkASSERT(end >= 0);
   2917     SkASSERT(startIndex - endIndex != 0);
   2918     SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
   2919     // more than one viable candidate -- measure angles to find best
   2920 
   2921     int calcWinding = computeSum(startIndex, end, SkOpAngle::kUnaryWinding);
   2922     bool sortable = calcWinding != SK_NaN32;
   2923     if (!sortable) {
   2924         *unsortable = true;
   2925         markDoneUnary(SkMin32(startIndex, endIndex));
   2926         return NULL;
   2927     }
   2928     SkOpAngle* angle = spanToAngle(end, startIndex);
   2929 #if DEBUG_SORT
   2930     SkDebugf("%s\n", __FUNCTION__);
   2931     angle->debugLoop();
   2932 #endif
   2933     int sumWinding = updateWinding(endIndex, startIndex);
   2934     SkOpAngle* nextAngle = angle->next();
   2935     const SkOpAngle* foundAngle = NULL;
   2936     bool foundDone = false;
   2937     SkOpSegment* nextSegment;
   2938     int activeCount = 0;
   2939     do {
   2940         nextSegment = nextAngle->segment();
   2941         bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
   2942                 &sumWinding);
   2943         if (activeAngle) {
   2944             ++activeCount;
   2945             if (!foundAngle || (foundDone && activeCount & 1)) {
   2946                 if (nextSegment->isTiny(nextAngle)) {
   2947                     *unsortable = true;
   2948                     markDoneUnary(SkMin32(startIndex, endIndex));
   2949                     return NULL;
   2950                 }
   2951                 foundAngle = nextAngle;
   2952                 foundDone = nextSegment->done(nextAngle);
   2953             }
   2954         }
   2955         if (nextSegment->done()) {
   2956             continue;
   2957         }
   2958         if (nextSegment->isTiny(nextAngle)) {
   2959             continue;
   2960         }
   2961         if (!activeAngle) {
   2962             nextSegment->markAndChaseDoneUnary(nextAngle->start(), nextAngle->end());
   2963         }
   2964         SkOpSpan* last = nextAngle->lastMarked();
   2965         if (last) {
   2966             SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
   2967             *chase->append() = last;
   2968 #if DEBUG_WINDING
   2969             SkDebugf("%s chase.append id=%d windSum=%d small=%d\n", __FUNCTION__,
   2970                     last->fOther->fTs[last->fOtherIndex].fOther->debugID(), last->fWindSum,
   2971                     last->fSmall);
   2972 #endif
   2973         }
   2974     } while ((nextAngle = nextAngle->next()) != angle);
   2975     markDoneUnary(SkMin32(startIndex, endIndex));
   2976     if (!foundAngle) {
   2977         return NULL;
   2978     }
   2979     *nextStart = foundAngle->start();
   2980     *nextEnd = foundAngle->end();
   2981     nextSegment = foundAngle->segment();
   2982 #if DEBUG_WINDING
   2983     SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
   2984             __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
   2985  #endif
   2986     return nextSegment;
   2987 }
   2988 
   2989 SkOpSegment* SkOpSegment::findNextXor(int* nextStart, int* nextEnd, bool* unsortable) {
   2990     const int startIndex = *nextStart;
   2991     const int endIndex = *nextEnd;
   2992     SkASSERT(startIndex != endIndex);
   2993     SkDEBUGCODE(int count = fTs.count());
   2994     SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
   2995     int step = SkSign32(endIndex - startIndex);
   2996 // Detect cases where all the ends canceled out (e.g.,
   2997 // there is no angle) and therefore there's only one valid connection
   2998     *nextStart = startIndex;
   2999     SkOpSegment* other = isSimple(nextStart, &step);
   3000     if (other)
   3001     {
   3002 #if DEBUG_WINDING
   3003         SkDebugf("%s simple\n", __FUNCTION__);
   3004 #endif
   3005         int min = SkMin32(startIndex, endIndex);
   3006         if (fTs[min].fDone) {
   3007             return NULL;
   3008         }
   3009         markDone(min, 1);
   3010         double startT = other->fTs[*nextStart].fT;
   3011         // FIXME: I don't know why the logic here is difference from the winding case
   3012         SkDEBUGCODE(bool firstLoop = true;)
   3013         if ((approximately_less_than_zero(startT) && step < 0)
   3014                 || (approximately_greater_than_one(startT) && step > 0)) {
   3015             step = -step;
   3016             SkDEBUGCODE(firstLoop = false;)
   3017         }
   3018         do {
   3019             *nextEnd = *nextStart;
   3020             do {
   3021                 *nextEnd += step;
   3022             } while (precisely_zero(startT - other->fTs[*nextEnd].fT));
   3023             if (other->fTs[SkMin32(*nextStart, *nextEnd)].fWindValue) {
   3024                 break;
   3025             }
   3026             SkASSERT(firstLoop);
   3027             SkDEBUGCODE(firstLoop = false;)
   3028             step = -step;
   3029         } while (true);
   3030         SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count());
   3031         return other;
   3032     }
   3033     SkASSERT(startIndex - endIndex != 0);
   3034     SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
   3035     // parallel block above with presorted version
   3036     int end = nextExactSpan(startIndex, step);
   3037     SkASSERT(end >= 0);
   3038     SkOpAngle* angle = spanToAngle(end, startIndex);
   3039     SkASSERT(angle);
   3040 #if DEBUG_SORT
   3041     SkDebugf("%s\n", __FUNCTION__);
   3042     angle->debugLoop();
   3043 #endif
   3044     SkOpAngle* nextAngle = angle->next();
   3045     const SkOpAngle* foundAngle = NULL;
   3046     bool foundDone = false;
   3047     SkOpSegment* nextSegment;
   3048     int activeCount = 0;
   3049     do {
   3050         nextSegment = nextAngle->segment();
   3051         ++activeCount;
   3052         if (!foundAngle || (foundDone && activeCount & 1)) {
   3053             if (nextSegment->isTiny(nextAngle)) {
   3054                 *unsortable = true;
   3055                 return NULL;
   3056             }
   3057             foundAngle = nextAngle;
   3058             if (!(foundDone = nextSegment->done(nextAngle))) {
   3059                 break;
   3060             }
   3061         }
   3062         nextAngle = nextAngle->next();
   3063     } while (nextAngle != angle);
   3064     markDone(SkMin32(startIndex, endIndex), 1);
   3065     if (!foundAngle) {
   3066         return NULL;
   3067     }
   3068     *nextStart = foundAngle->start();
   3069     *nextEnd = foundAngle->end();
   3070     nextSegment = foundAngle->segment();
   3071 #if DEBUG_WINDING
   3072     SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
   3073             __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
   3074  #endif
   3075     return nextSegment;
   3076 }
   3077 
   3078 int SkOpSegment::findStartSpan(int startIndex) const {
   3079     int index = startIndex;
   3080     const SkOpSpan* span = &fTs[index];
   3081     const SkPoint& firstPt = span->fPt;
   3082     double firstT = span->fT;
   3083     const SkOpSpan* prior;
   3084     do {
   3085         prior = span;
   3086         span = &fTs[++index];
   3087     } while (SkDPoint::ApproximatelyEqual(span->fPt, firstPt)
   3088             && (span->fT == firstT || prior->fTiny));
   3089     return index;
   3090 }
   3091 
   3092 int SkOpSegment::findExactT(double t, const SkOpSegment* match) const {
   3093     int count = this->count();
   3094     for (int index = 0; index < count; ++index) {
   3095         const SkOpSpan& span = fTs[index];
   3096         if (span.fT == t && span.fOther == match) {
   3097             return index;
   3098         }
   3099     }
   3100     SkASSERT(0);
   3101     return -1;
   3102 }
   3103 
   3104 int SkOpSegment::findOtherT(double t, const SkOpSegment* match) const {
   3105     int count = this->count();
   3106     for (int index = 0; index < count; ++index) {
   3107         const SkOpSpan& span = fTs[index];
   3108         if (span.fOtherT == t && span.fOther == match) {
   3109             return index;
   3110         }
   3111     }
   3112     return -1;
   3113 }
   3114 
   3115 int SkOpSegment::findT(double t, const SkPoint& pt, const SkOpSegment* match) const {
   3116     int count = this->count();
   3117     // prefer exact matches over approximate matches
   3118     for (int index = 0; index < count; ++index) {
   3119         const SkOpSpan& span = fTs[index];
   3120         if (span.fT == t && span.fOther == match) {
   3121             return index;
   3122         }
   3123     }
   3124     for (int index = 0; index < count; ++index) {
   3125         const SkOpSpan& span = fTs[index];
   3126         if (approximately_equal_orderable(span.fT, t) && span.fOther == match) {
   3127             return index;
   3128         }
   3129     }
   3130     // Usually, the pair of ts are an exact match. It's possible that the t values have
   3131     // been adjusted to make multiple intersections align. In this rare case, look for a
   3132     // matching point / match pair instead.
   3133     for (int index = 0; index < count; ++index) {
   3134         const SkOpSpan& span = fTs[index];
   3135         if (span.fPt == pt && span.fOther == match) {
   3136             return index;
   3137         }
   3138     }
   3139     SkASSERT(0);
   3140     return -1;
   3141 }
   3142 
   3143 SkOpSegment* SkOpSegment::findTop(int* tIndexPtr, int* endIndexPtr, bool* unsortable,
   3144         bool firstPass) {
   3145     // iterate through T intersections and return topmost
   3146     // topmost tangent from y-min to first pt is closer to horizontal
   3147     SkASSERT(!done());
   3148     int firstT = -1;
   3149     /* SkPoint topPt = */ activeLeftTop(&firstT);
   3150     if (firstT < 0) {
   3151         *unsortable = !firstPass;
   3152         firstT = 0;
   3153         while (fTs[firstT].fDone) {
   3154             SkASSERT(firstT < fTs.count());
   3155             ++firstT;
   3156         }
   3157         *tIndexPtr = firstT;
   3158         *endIndexPtr = nextExactSpan(firstT, 1);
   3159         return this;
   3160     }
   3161     // sort the edges to find the leftmost
   3162     int step = 1;
   3163     int end;
   3164     if (span(firstT).fDone || (end = nextSpan(firstT, step)) == -1) {
   3165         step = -1;
   3166         end = nextSpan(firstT, step);
   3167         SkASSERT(end != -1);
   3168     }
   3169     // if the topmost T is not on end, or is three-way or more, find left
   3170     // look for left-ness from tLeft to firstT (matching y of other)
   3171     SkASSERT(firstT - end != 0);
   3172     SkOpAngle* markAngle = spanToAngle(firstT, end);
   3173     if (!markAngle) {
   3174         markAngle = addSingletonAngles(step);
   3175     }
   3176     markAngle->markStops();
   3177     const SkOpAngle* baseAngle = markAngle->next() == markAngle && !isVertical() ? markAngle
   3178             : markAngle->findFirst();
   3179     if (!baseAngle) {
   3180         return NULL;  // nothing to do
   3181     }
   3182     SkScalar top = SK_ScalarMax;
   3183     const SkOpAngle* firstAngle = NULL;
   3184     const SkOpAngle* angle = baseAngle;
   3185     do {
   3186         if (!angle->unorderable()) {
   3187             SkOpSegment* next = angle->segment();
   3188             SkPathOpsBounds bounds;
   3189             next->subDivideBounds(angle->end(), angle->start(), &bounds);
   3190             if (approximately_greater(top, bounds.fTop)) {
   3191                 top = bounds.fTop;
   3192                 firstAngle = angle;
   3193             }
   3194         }
   3195         angle = angle->next();
   3196     } while (angle != baseAngle);
   3197     SkASSERT(firstAngle);
   3198 #if DEBUG_SORT
   3199     SkDebugf("%s\n", __FUNCTION__);
   3200     firstAngle->debugLoop();
   3201 #endif
   3202     // skip edges that have already been processed
   3203     angle = firstAngle;
   3204     SkOpSegment* leftSegment = NULL;
   3205     bool looped = false;
   3206     do {
   3207         *unsortable = angle->unorderable();
   3208         if (firstPass || !*unsortable) {
   3209             leftSegment = angle->segment();
   3210             *tIndexPtr = angle->end();
   3211             *endIndexPtr = angle->start();
   3212             if (!leftSegment->fTs[SkMin32(*tIndexPtr, *endIndexPtr)].fDone) {
   3213                 break;
   3214             }
   3215         }
   3216         angle = angle->next();
   3217         looped = true;
   3218     } while (angle != firstAngle);
   3219     if (angle == firstAngle && looped) {
   3220         return NULL;
   3221     }
   3222     if (leftSegment->verb() >= SkPath::kQuad_Verb) {
   3223         const int tIndex = *tIndexPtr;
   3224         const int endIndex = *endIndexPtr;
   3225         bool swap;
   3226         if (!leftSegment->clockwise(tIndex, endIndex, &swap)) {
   3227     #if DEBUG_SWAP_TOP
   3228             SkDebugf("%s swap=%d inflections=%d serpentine=%d controlledbyends=%d monotonic=%d\n",
   3229                     __FUNCTION__,
   3230                     swap, leftSegment->debugInflections(tIndex, endIndex),
   3231                     leftSegment->serpentine(tIndex, endIndex),
   3232                     leftSegment->controlsContainedByEnds(tIndex, endIndex),
   3233                     leftSegment->monotonicInY(tIndex, endIndex));
   3234     #endif
   3235             if (swap) {
   3236     // FIXME: I doubt it makes sense to (necessarily) swap if the edge was not the first
   3237     // sorted but merely the first not already processed (i.e., not done)
   3238                 SkTSwap(*tIndexPtr, *endIndexPtr);
   3239             }
   3240         }
   3241     }
   3242     SkASSERT(!leftSegment->fTs[SkMin32(*tIndexPtr, *endIndexPtr)].fTiny);
   3243     return leftSegment;
   3244 }
   3245 
   3246 int SkOpSegment::firstActive(int tIndex) const {
   3247     while (fTs[tIndex].fTiny) {
   3248         SkASSERT(!isCanceled(tIndex));
   3249         ++tIndex;
   3250     }
   3251     return tIndex;
   3252 }
   3253 
   3254 // FIXME: not crazy about this
   3255 // when the intersections are performed, the other index is into an
   3256 // incomplete array. As the array grows, the indices become incorrect
   3257 // while the following fixes the indices up again, it isn't smart about
   3258 // skipping segments whose indices are already correct
   3259 // assuming we leave the code that wrote the index in the first place
   3260 // FIXME: if called after remove, this needs to correct tiny
   3261 void SkOpSegment::fixOtherTIndex() {
   3262     int iCount = fTs.count();
   3263     for (int i = 0; i < iCount; ++i) {
   3264         SkOpSpan& iSpan = fTs[i];
   3265         double oT = iSpan.fOtherT;
   3266         SkOpSegment* other = iSpan.fOther;
   3267         int oCount = other->fTs.count();
   3268         SkDEBUGCODE(iSpan.fOtherIndex = -1);
   3269         for (int o = 0; o < oCount; ++o) {
   3270             SkOpSpan& oSpan = other->fTs[o];
   3271             if (oT == oSpan.fT && this == oSpan.fOther && oSpan.fOtherT == iSpan.fT) {
   3272                 iSpan.fOtherIndex = o;
   3273                 oSpan.fOtherIndex = i;
   3274                 break;
   3275             }
   3276         }
   3277         SkASSERT(iSpan.fOtherIndex >= 0);
   3278     }
   3279 }
   3280 
   3281 bool SkOpSegment::inCoincidentSpan(double t, const SkOpSegment* other) const {
   3282     int foundEnds = 0;
   3283     int count = this->count();
   3284     for (int index = 0; index < count; ++index) {
   3285         const SkOpSpan& span = this->span(index);
   3286         if (span.fCoincident) {
   3287             foundEnds |= (span.fOther == other) << ((t > span.fT) + (t >= span.fT));
   3288         }
   3289     }
   3290     SkASSERT(foundEnds != 7);
   3291     return foundEnds == 0x3 || foundEnds == 0x5 || foundEnds == 0x6;  // two bits set
   3292 }
   3293 
   3294 void SkOpSegment::init(const SkPoint pts[], SkPath::Verb verb, bool operand, bool evenOdd) {
   3295     fDoneSpans = 0;
   3296     fOperand = operand;
   3297     fXor = evenOdd;
   3298     fPts = pts;
   3299     fVerb = verb;
   3300     fLoop = fMultiples = fSmall = fTiny = false;
   3301 }
   3302 
   3303 void SkOpSegment::initWinding(int start, int end, SkOpAngle::IncludeType angleIncludeType) {
   3304     int local = spanSign(start, end);
   3305     if (angleIncludeType == SkOpAngle::kBinarySingle) {
   3306         int oppLocal = oppSign(start, end);
   3307         (void) markAndChaseWinding(start, end, local, oppLocal);
   3308     // OPTIMIZATION: the reverse mark and chase could skip the first marking
   3309         (void) markAndChaseWinding(end, start, local, oppLocal);
   3310     } else {
   3311         (void) markAndChaseWinding(start, end, local);
   3312     // OPTIMIZATION: the reverse mark and chase could skip the first marking
   3313         (void) markAndChaseWinding(end, start, local);
   3314     }
   3315 }
   3316 
   3317 /*
   3318 when we start with a vertical intersect, we try to use the dx to determine if the edge is to
   3319 the left or the right of vertical. This determines if we need to add the span's
   3320 sign or not. However, this isn't enough.
   3321 If the supplied sign (winding) is zero, then we didn't hit another vertical span, so dx is needed.
   3322 If there was a winding, then it may or may not need adjusting. If the span the winding was borrowed
   3323 from has the same x direction as this span, the winding should change. If the dx is opposite, then
   3324 the same winding is shared by both.
   3325 */
   3326 void SkOpSegment::initWinding(int start, int end, double tHit, int winding, SkScalar hitDx,
   3327                               int oppWind, SkScalar hitOppDx) {
   3328     SkASSERT(hitDx || !winding);
   3329     SkScalar dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, tHit).fX;
   3330     SkASSERT(dx);
   3331     int windVal = windValue(SkMin32(start, end));
   3332 #if DEBUG_WINDING_AT_T
   3333     SkDebugf("%s id=%d oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, debugID(), winding,
   3334             hitDx ? hitDx > 0 ? '+' : '-' : '0', dx > 0 ? '+' : '-', windVal);
   3335 #endif
   3336     int sideWind = winding + (dx < 0 ? windVal : -windVal);
   3337     if (abs(winding) < abs(sideWind)) {
   3338         winding = sideWind;
   3339     }
   3340     SkDEBUGCODE(int oppLocal = oppSign(start, end));
   3341     SkASSERT(hitOppDx || !oppWind || !oppLocal);
   3342     int oppWindVal = oppValue(SkMin32(start, end));
   3343     if (!oppWind) {
   3344         oppWind = dx < 0 ? oppWindVal : -oppWindVal;
   3345     } else if (hitOppDx * dx >= 0) {
   3346         int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal);
   3347         if (abs(oppWind) < abs(oppSideWind)) {
   3348             oppWind = oppSideWind;
   3349         }
   3350     }
   3351 #if DEBUG_WINDING_AT_T
   3352     SkDebugf(" winding=%d oppWind=%d\n", winding, oppWind);
   3353 #endif
   3354     (void) markAndChaseWinding(start, end, winding, oppWind);
   3355     // OPTIMIZATION: the reverse mark and chase could skip the first marking
   3356     (void) markAndChaseWinding(end, start, winding, oppWind);
   3357 }
   3358 
   3359 bool SkOpSegment::inLoop(const SkOpAngle* baseAngle, int spanCount, int* indexPtr) const {
   3360     if (!baseAngle->inLoop()) {
   3361         return false;
   3362     }
   3363     int index = *indexPtr;
   3364     SkOpAngle* from = fTs[index].fFromAngle;
   3365     SkOpAngle* to = fTs[index].fToAngle;
   3366     while (++index < spanCount) {
   3367         SkOpAngle* nextFrom = fTs[index].fFromAngle;
   3368         SkOpAngle* nextTo = fTs[index].fToAngle;
   3369         if (from != nextFrom || to != nextTo) {
   3370             break;
   3371         }
   3372     }
   3373     *indexPtr = index;
   3374     return true;
   3375 }
   3376 
   3377 // OPTIMIZE: successive calls could start were the last leaves off
   3378 // or calls could specialize to walk forwards or backwards
   3379 bool SkOpSegment::isMissing(double startT, const SkPoint& pt) const {
   3380     int tCount = fTs.count();
   3381     for (int index = 0; index < tCount; ++index) {
   3382         const SkOpSpan& span = fTs[index];
   3383         if (approximately_zero(startT - span.fT) && pt == span.fPt) {
   3384             return false;
   3385         }
   3386     }
   3387     return true;
   3388 }
   3389 
   3390 
   3391 SkOpSegment* SkOpSegment::isSimple(int* end, int* step) {
   3392     return nextChase(end, step, NULL, NULL);
   3393 }
   3394 
   3395 bool SkOpSegment::isTiny(const SkOpAngle* angle) const {
   3396     int start = angle->start();
   3397     int end = angle->end();
   3398     const SkOpSpan& mSpan = fTs[SkMin32(start, end)];
   3399     return mSpan.fTiny;
   3400 }
   3401 
   3402 bool SkOpSegment::isTiny(int index) const {
   3403     return fTs[index].fTiny;
   3404 }
   3405 
   3406 // look pair of active edges going away from coincident edge
   3407 // one of them should be the continuation of other
   3408 // if both are active, look to see if they both the connect to another coincident pair
   3409 // if at least one is a line, then make the pair coincident
   3410 // if neither is a line, test for coincidence
   3411 bool SkOpSegment::joinCoincidence(SkOpSegment* other, double otherT, const SkPoint& otherPt,
   3412         int step, bool cancel) {
   3413     int otherTIndex = other->findT(otherT, otherPt, this);
   3414     int next = other->nextExactSpan(otherTIndex, step);
   3415     int otherMin = SkMin32(otherTIndex, next);
   3416     int otherWind = other->span(otherMin).fWindValue;
   3417     if (otherWind == 0) {
   3418         return false;
   3419     }
   3420     SkASSERT(next >= 0);
   3421     int tIndex = 0;
   3422     do {
   3423         SkOpSpan* test = &fTs[tIndex];
   3424         SkASSERT(test->fT == 0);
   3425         if (test->fOther == other || test->fOtherT != 1) {
   3426             continue;
   3427         }
   3428         SkPoint startPt, endPt;
   3429         double endT;
   3430         if (findCoincidentMatch(test, other, otherTIndex, next, step, &startPt, &endPt, &endT)) {
   3431             SkOpSegment* match = test->fOther;
   3432             if (cancel) {
   3433                 match->addTCancel(startPt, endPt, other);
   3434             } else {
   3435                 SkAssertResult(match->addTCoincident(startPt, endPt, endT, other));
   3436             }
   3437             return true;
   3438         }
   3439     } while (fTs[++tIndex].fT == 0);
   3440     return false;
   3441 }
   3442 
   3443 // this span is excluded by the winding rule -- chase the ends
   3444 // as long as they are unambiguous to mark connections as done
   3445 // and give them the same winding value
   3446 
   3447 SkOpSpan* SkOpSegment::markAndChaseDoneBinary(int index, int endIndex) {
   3448     int step = SkSign32(endIndex - index);
   3449     int min = SkMin32(index, endIndex);
   3450     markDoneBinary(min);
   3451     SkOpSpan* last = NULL;
   3452     SkOpSegment* other = this;
   3453     while ((other = other->nextChase(&index, &step, &min, &last))) {
   3454         if (other->done()) {
   3455             SkASSERT(!last);
   3456             break;
   3457         }
   3458         other->markDoneBinary(min);
   3459     }
   3460     return last;
   3461 }
   3462 
   3463 SkOpSpan* SkOpSegment::markAndChaseDoneUnary(int index, int endIndex) {
   3464     int step = SkSign32(endIndex - index);
   3465     int min = SkMin32(index, endIndex);
   3466     markDoneUnary(min);
   3467     SkOpSpan* last = NULL;
   3468     SkOpSegment* other = this;
   3469     while ((other = other->nextChase(&index, &step, &min, &last))) {
   3470         if (other->done()) {
   3471             SkASSERT(!last);
   3472             break;
   3473         }
   3474         other->markDoneUnary(min);
   3475     }
   3476     return last;
   3477 }
   3478 
   3479 SkOpSpan* SkOpSegment::markAndChaseWinding(const SkOpAngle* angle, int winding) {
   3480     int index = angle->start();
   3481     int endIndex = angle->end();
   3482     int step = SkSign32(endIndex - index);
   3483     int min = SkMin32(index, endIndex);
   3484     markWinding(min, winding);
   3485     SkOpSpan* last = NULL;
   3486     SkOpSegment* other = this;
   3487     while ((other = other->nextChase(&index, &step, &min, &last))) {
   3488         if (other->fTs[min].fWindSum != SK_MinS32) {
   3489 //            SkASSERT(other->fTs[min].fWindSum == winding);
   3490             SkASSERT(!last);
   3491             break;
   3492         }
   3493         other->markWinding(min, winding);
   3494     }
   3495     return last;
   3496 }
   3497 
   3498 SkOpSpan* SkOpSegment::markAndChaseWinding(int index, int endIndex, int winding) {
   3499     int min = SkMin32(index, endIndex);
   3500     int step = SkSign32(endIndex - index);
   3501     markWinding(min, winding);
   3502     SkOpSpan* last = NULL;
   3503     SkOpSegment* other = this;
   3504     while ((other = other->nextChase(&index, &step, &min, &last))) {
   3505         if (other->fTs[min].fWindSum != SK_MinS32) {
   3506             SkASSERT(other->fTs[min].fWindSum == winding || other->fTs[min].fLoop);
   3507             SkASSERT(!last);
   3508             break;
   3509         }
   3510         other->markWinding(min, winding);
   3511     }
   3512     return last;
   3513 }
   3514 
   3515 SkOpSpan* SkOpSegment::markAndChaseWinding(int index, int endIndex, int winding, int oppWinding) {
   3516     int min = SkMin32(index, endIndex);
   3517     int step = SkSign32(endIndex - index);
   3518     markWinding(min, winding, oppWinding);
   3519     SkOpSpan* last = NULL;
   3520     SkOpSegment* other = this;
   3521     while ((other = other->nextChase(&index, &step, &min, &last))) {
   3522         if (other->fTs[min].fWindSum != SK_MinS32) {
   3523 #ifdef SK_DEBUG
   3524             if (!other->fTs[min].fLoop) {
   3525                 if (fOperand == other->fOperand) {
   3526 // FIXME: this is probably a bug -- rects4 asserts here
   3527 //                    SkASSERT(other->fTs[min].fWindSum == winding);
   3528 // FIXME: this is probably a bug -- rects3 asserts here
   3529 //                    SkASSERT(other->fTs[min].fOppSum == oppWinding);
   3530                 } else {
   3531 // FIXME: this is probably a bug -- issue414409b asserts here
   3532 //                    SkASSERT(other->fTs[min].fWindSum == oppWinding);
   3533 // FIXME: this is probably a bug -- skpwww_joomla_org_23 asserts here
   3534 //                    SkASSERT(other->fTs[min].fOppSum == winding);
   3535                 }
   3536             }
   3537             SkASSERT(!last);
   3538 #endif
   3539             break;
   3540         }
   3541         if (fOperand == other->fOperand) {
   3542             other->markWinding(min, winding, oppWinding);
   3543         } else {
   3544             other->markWinding(min, oppWinding, winding);
   3545         }
   3546     }
   3547     return last;
   3548 }
   3549 
   3550 SkOpSpan* SkOpSegment::markAndChaseWinding(const SkOpAngle* angle, int winding, int oppWinding) {
   3551     int start = angle->start();
   3552     int end = angle->end();
   3553     return markAndChaseWinding(start, end, winding, oppWinding);
   3554 }
   3555 
   3556 SkOpSpan* SkOpSegment::markAngle(int maxWinding, int sumWinding, const SkOpAngle* angle) {
   3557     SkASSERT(angle->segment() == this);
   3558     if (UseInnerWinding(maxWinding, sumWinding)) {
   3559         maxWinding = sumWinding;
   3560     }
   3561     SkOpSpan* last = markAndChaseWinding(angle, maxWinding);
   3562 #if DEBUG_WINDING
   3563     if (last) {
   3564         SkDebugf("%s last id=%d windSum=", __FUNCTION__,
   3565                 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
   3566         SkPathOpsDebug::WindingPrintf(last->fWindSum);
   3567         SkDebugf(" small=%d\n", last->fSmall);
   3568     }
   3569 #endif
   3570     return last;
   3571 }
   3572 
   3573 SkOpSpan* SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWinding,
   3574                                  int oppSumWinding, const SkOpAngle* angle) {
   3575     SkASSERT(angle->segment() == this);
   3576     if (UseInnerWinding(maxWinding, sumWinding)) {
   3577         maxWinding = sumWinding;
   3578     }
   3579     if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumWinding)) {
   3580         oppMaxWinding = oppSumWinding;
   3581     }
   3582     SkOpSpan* last = markAndChaseWinding(angle, maxWinding, oppMaxWinding);
   3583 #if DEBUG_WINDING
   3584     if (last) {
   3585         SkDebugf("%s last id=%d windSum=", __FUNCTION__,
   3586                 last->fOther->fTs[last->fOtherIndex].fOther->debugID());
   3587         SkPathOpsDebug::WindingPrintf(last->fWindSum);
   3588         SkDebugf(" small=%d\n", last->fSmall);
   3589     }
   3590 #endif
   3591     return last;
   3592 }
   3593 
   3594 // FIXME: this should also mark spans with equal (x,y)
   3595 // This may be called when the segment is already marked done. While this
   3596 // wastes time, it shouldn't do any more than spin through the T spans.
   3597 // OPTIMIZATION: abort on first done found (assuming that this code is
   3598 // always called to mark segments done).
   3599 void SkOpSegment::markDone(int index, int winding) {
   3600   //  SkASSERT(!done());
   3601     SkASSERT(winding);
   3602     double referenceT = fTs[index].fT;
   3603     int lesser = index;
   3604     while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
   3605         markOneDone(__FUNCTION__, lesser, winding);
   3606     }
   3607     do {
   3608         markOneDone(__FUNCTION__, index, winding);
   3609     } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
   3610     debugValidate();
   3611 }
   3612 
   3613 void SkOpSegment::markDoneBinary(int index) {
   3614     double referenceT = fTs[index].fT;
   3615     int lesser = index;
   3616     while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
   3617         markOneDoneBinary(__FUNCTION__, lesser);
   3618     }
   3619     do {
   3620         markOneDoneBinary(__FUNCTION__, index);
   3621     } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
   3622     debugValidate();
   3623 }
   3624 
   3625 void SkOpSegment::markDoneUnary(int index) {
   3626     double referenceT = fTs[index].fT;
   3627     int lesser = index;
   3628     while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
   3629         markOneDoneUnary(__FUNCTION__, lesser);
   3630     }
   3631     do {
   3632         markOneDoneUnary(__FUNCTION__, index);
   3633     } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
   3634     debugValidate();
   3635 }
   3636 
   3637 void SkOpSegment::markOneDone(const char* funName, int tIndex, int winding) {
   3638     SkOpSpan* span = markOneWinding(funName, tIndex, winding);
   3639     if (!span || span->fDone) {
   3640         return;
   3641     }
   3642     span->fDone = true;
   3643     fDoneSpans++;
   3644 }
   3645 
   3646 void SkOpSegment::markOneDoneBinary(const char* funName, int tIndex) {
   3647     SkOpSpan* span = verifyOneWinding(funName, tIndex);
   3648     if (!span) {
   3649         return;
   3650     }
   3651     SkASSERT(!span->fDone);
   3652     span->fDone = true;
   3653     fDoneSpans++;
   3654 }
   3655 
   3656 void SkOpSegment::markOneDoneUnary(const char* funName, int tIndex) {
   3657     SkOpSpan* span = verifyOneWindingU(funName, tIndex);
   3658     if (!span) {
   3659         return;
   3660     }
   3661     if (span->fWindSum == SK_MinS32) {
   3662         SkDebugf("%s uncomputed\n", __FUNCTION__);
   3663     }
   3664     SkASSERT(!span->fDone);
   3665     span->fDone = true;
   3666     fDoneSpans++;
   3667 }
   3668 
   3669 SkOpSpan* SkOpSegment::markOneWinding(const char* funName, int tIndex, int winding) {
   3670     SkOpSpan& span = fTs[tIndex];
   3671     if (span.fDone && !span.fSmall) {
   3672         return NULL;
   3673     }
   3674 #if DEBUG_MARK_DONE
   3675     debugShowNewWinding(funName, span, winding);
   3676 #endif
   3677     SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
   3678 #if DEBUG_LIMIT_WIND_SUM
   3679     SkASSERT(abs(winding) <= DEBUG_LIMIT_WIND_SUM);
   3680 #endif
   3681     span.fWindSum = winding;
   3682     return &span;
   3683 }
   3684 
   3685 SkOpSpan* SkOpSegment::markOneWinding(const char* funName, int tIndex, int winding,
   3686                                       int oppWinding) {
   3687     SkOpSpan& span = fTs[tIndex];
   3688     if (span.fDone && !span.fSmall) {
   3689         return NULL;
   3690     }
   3691 #if DEBUG_MARK_DONE
   3692     debugShowNewWinding(funName, span, winding, oppWinding);
   3693 #endif
   3694     SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
   3695 #if DEBUG_LIMIT_WIND_SUM
   3696     SkASSERT(abs(winding) <= DEBUG_LIMIT_WIND_SUM);
   3697 #endif
   3698     span.fWindSum = winding;
   3699     SkASSERT(span.fOppSum == SK_MinS32 || span.fOppSum == oppWinding);
   3700 #if DEBUG_LIMIT_WIND_SUM
   3701     SkASSERT(abs(oppWinding) <= DEBUG_LIMIT_WIND_SUM);
   3702 #endif
   3703     span.fOppSum = oppWinding;
   3704     debugValidate();
   3705     return &span;
   3706 }
   3707 
   3708 // from http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of-polygon-points-are-in-clockwise-order
   3709 bool SkOpSegment::clockwise(int tStart, int tEnd, bool* swap) const {
   3710     SkASSERT(fVerb != SkPath::kLine_Verb);
   3711     SkPoint edge[4];
   3712     subDivide(tStart, tEnd, edge);
   3713     int points = SkPathOpsVerbToPoints(fVerb);
   3714     double sum = (edge[0].fX - edge[points].fX) * (edge[0].fY + edge[points].fY);
   3715     bool sumSet = false;
   3716     if (fVerb == SkPath::kCubic_Verb) {
   3717         SkDCubic cubic;
   3718         cubic.set(edge);
   3719         double inflectionTs[2];
   3720         int inflections = cubic.findInflections(inflectionTs);
   3721         // FIXME: this fixes cubicOp114 and breaks cubicOp58d
   3722         // the trouble is that cubics with inflections confuse whether the curve breaks towards
   3723         // or away, which in turn is used to determine if it is on the far right or left.
   3724         // Probably a totally different approach is in order. At one time I tried to project a
   3725         // horizontal ray to determine winding, but was confused by how to map the vertically
   3726         // oriented winding computation over.
   3727         if (0 && inflections) {
   3728             double tLo = this->span(tStart).fT;
   3729             double tHi = this->span(tEnd).fT;
   3730             double tLoStart = tLo;
   3731             for (int index = 0; index < inflections; ++index) {
   3732                 if (between(tLo, inflectionTs[index], tHi)) {
   3733                     tLo = inflectionTs[index];
   3734                 }
   3735             }
   3736             if (tLo != tLoStart && tLo != tHi) {
   3737                 SkDPoint sub[2];
   3738                 sub[0] = cubic.ptAtT(tLo);
   3739                 sub[1].set(edge[3]);
   3740                 SkDPoint ctrl[2];
   3741                 SkDCubic::SubDivide(fPts, sub[0], sub[1], tLo, tHi, ctrl);
   3742                 edge[0] = sub[0].asSkPoint();
   3743                 edge[1] = ctrl[0].asSkPoint();
   3744                 edge[2] = ctrl[1].asSkPoint();
   3745                 sum = (edge[0].fX - edge[3].fX) * (edge[0].fY + edge[3].fY);
   3746             }
   3747         }
   3748         SkScalar lesser = SkTMin<SkScalar>(edge[0].fY, edge[3].fY);
   3749         if (edge[1].fY < lesser && edge[2].fY < lesser) {
   3750             SkDLine tangent1 = {{ {edge[0].fX, edge[0].fY}, {edge[1].fX, edge[1].fY} }};
   3751             SkDLine tangent2 = {{ {edge[2].fX, edge[2].fY}, {edge[3].fX, edge[3].fY} }};
   3752             if (SkIntersections::Test(tangent1, tangent2)) {
   3753                 SkPoint topPt = cubic_top(fPts, fTs[tStart].fT, fTs[tEnd].fT);
   3754                 sum += (topPt.fX - edge[0].fX) * (topPt.fY + edge[0].fY);
   3755                 sum += (edge[3].fX - topPt.fX) * (edge[3].fY + topPt.fY);
   3756                 sumSet = true;
   3757             }
   3758         }
   3759     }
   3760     if (!sumSet) {
   3761         for (int idx = 0; idx < points; ++idx){
   3762             sum += (edge[idx + 1].fX - edge[idx].fX) * (edge[idx + 1].fY + edge[idx].fY);
   3763         }
   3764     }
   3765     if (fVerb == SkPath::kCubic_Verb) {
   3766         SkDCubic cubic;
   3767         cubic.set(edge);
   3768          *swap = sum > 0 && !cubic.monotonicInY() && !cubic.serpentine();
   3769     } else {
   3770         SkDQuad quad;
   3771         quad.set(edge);
   3772         *swap = sum > 0 && !quad.monotonicInY();
   3773     }
   3774     return sum <= 0;
   3775 }
   3776 
   3777 bool SkOpSegment::monotonicInY(int tStart, int tEnd) const {
   3778     SkASSERT(fVerb != SkPath::kLine_Verb);
   3779     if (fVerb == SkPath::kQuad_Verb) {
   3780         SkDQuad dst = SkDQuad::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
   3781         return dst.monotonicInY();
   3782     }
   3783     SkASSERT(fVerb == SkPath::kCubic_Verb);
   3784     SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
   3785     return dst.monotonicInY();
   3786 }
   3787 
   3788 bool SkOpSegment::serpentine(int tStart, int tEnd) const {
   3789     if (fVerb != SkPath::kCubic_Verb) {
   3790         return false;
   3791     }
   3792     SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
   3793     return dst.serpentine();
   3794 }
   3795 
   3796 SkOpSpan* SkOpSegment::verifyOneWinding(const char* funName, int tIndex) {
   3797     SkOpSpan& span = fTs[tIndex];
   3798     if (span.fDone) {
   3799         return NULL;
   3800     }
   3801 #if DEBUG_MARK_DONE
   3802     debugShowNewWinding(funName, span, span.fWindSum, span.fOppSum);
   3803 #endif
   3804 // If the prior angle in the sort is unorderable, the winding sum may not be computable.
   3805 // To enable the assert, the 'prior is unorderable' state could be
   3806 // piped down to this test, but not sure it's worth it.
   3807 // (Once the sort order is stored in the span, this test may be feasible.)
   3808 //    SkASSERT(span.fWindSum != SK_MinS32);
   3809 //    SkASSERT(span.fOppSum != SK_MinS32);
   3810     return &span;
   3811 }
   3812 
   3813 SkOpSpan* SkOpSegment::verifyOneWindingU(const char* funName, int tIndex) {
   3814     SkOpSpan& span = fTs[tIndex];
   3815     if (span.fDone) {
   3816         return NULL;
   3817     }
   3818 #if DEBUG_MARK_DONE
   3819     debugShowNewWinding(funName, span, span.fWindSum);
   3820 #endif
   3821 // If the prior angle in the sort is unorderable, the winding sum may not be computable.
   3822 // To enable the assert, the 'prior is unorderable' state could be
   3823 // piped down to this test, but not sure it's worth it.
   3824 // (Once the sort order is stored in the span, this test may be feasible.)
   3825 //    SkASSERT(span.fWindSum != SK_MinS32);
   3826     return &span;
   3827 }
   3828 
   3829 void SkOpSegment::markWinding(int index, int winding) {
   3830 //    SkASSERT(!done());
   3831     SkASSERT(winding);
   3832     double referenceT = fTs[index].fT;
   3833     int lesser = index;
   3834     while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
   3835         markOneWinding(__FUNCTION__, lesser, winding);
   3836     }
   3837     do {
   3838         markOneWinding(__FUNCTION__, index, winding);
   3839    } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
   3840     debugValidate();
   3841 }
   3842 
   3843 void SkOpSegment::markWinding(int index, int winding, int oppWinding) {
   3844 //    SkASSERT(!done());
   3845     SkASSERT(winding || oppWinding);
   3846     double referenceT = fTs[index].fT;
   3847     int lesser = index;
   3848     while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
   3849         markOneWinding(__FUNCTION__, lesser, winding, oppWinding);
   3850     }
   3851     do {
   3852         markOneWinding(__FUNCTION__, index, winding, oppWinding);
   3853    } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
   3854     debugValidate();
   3855 }
   3856 
   3857 void SkOpSegment::matchWindingValue(int tIndex, double t, bool borrowWind) {
   3858     int nextDoorWind = SK_MaxS32;
   3859     int nextOppWind = SK_MaxS32;
   3860     // prefer exact matches
   3861     if (tIndex > 0) {
   3862         const SkOpSpan& below = fTs[tIndex - 1];
   3863         if (below.fT == t) {
   3864             nextDoorWind = below.fWindValue;
   3865             nextOppWind = below.fOppValue;
   3866         }
   3867     }
   3868     if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) {
   3869         const SkOpSpan& above = fTs[tIndex + 1];
   3870         if (above.fT == t) {
   3871             nextDoorWind = above.fWindValue;
   3872             nextOppWind = above.fOppValue;
   3873         }
   3874     }
   3875     if (nextDoorWind == SK_MaxS32 && tIndex > 0) {
   3876         const SkOpSpan& below = fTs[tIndex - 1];
   3877         if (approximately_negative(t - below.fT)) {
   3878             nextDoorWind = below.fWindValue;
   3879             nextOppWind = below.fOppValue;
   3880         }
   3881     }
   3882     if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) {
   3883         const SkOpSpan& above = fTs[tIndex + 1];
   3884         if (approximately_negative(above.fT - t)) {
   3885             nextDoorWind = above.fWindValue;
   3886             nextOppWind = above.fOppValue;
   3887         }
   3888     }
   3889     if (nextDoorWind == SK_MaxS32 && borrowWind && tIndex > 0 && t < 1) {
   3890         const SkOpSpan& below = fTs[tIndex - 1];
   3891         nextDoorWind = below.fWindValue;
   3892         nextOppWind = below.fOppValue;
   3893     }
   3894     if (nextDoorWind != SK_MaxS32) {
   3895         SkOpSpan& newSpan = fTs[tIndex];
   3896         newSpan.fWindValue = nextDoorWind;
   3897         newSpan.fOppValue = nextOppWind;
   3898         if (!nextDoorWind && !nextOppWind && !newSpan.fDone) {
   3899             newSpan.fDone = true;
   3900             ++fDoneSpans;
   3901         }
   3902     }
   3903 }
   3904 
   3905 bool SkOpSegment::nextCandidate(int* start, int* end) const {
   3906     while (fTs[*end].fDone) {
   3907         if (fTs[*end].fT == 1) {
   3908             return false;
   3909         }
   3910         ++(*end);
   3911     }
   3912     *start = *end;
   3913     *end = nextExactSpan(*start, 1);
   3914     return true;
   3915 }
   3916 
   3917 static SkOpSegment* set_last(SkOpSpan** last, SkOpSpan* endSpan) {
   3918     if (last && !endSpan->fSmall) {
   3919         *last = endSpan;
   3920     }
   3921     return NULL;
   3922 }
   3923 
   3924 SkOpSegment* SkOpSegment::nextChase(int* indexPtr, int* stepPtr, int* minPtr, SkOpSpan** last) {
   3925     int origIndex = *indexPtr;
   3926     int step = *stepPtr;
   3927     int end = nextExactSpan(origIndex, step);
   3928     SkASSERT(end >= 0);
   3929     SkOpSpan& endSpan = fTs[end];
   3930     SkOpAngle* angle = step > 0 ? endSpan.fFromAngle : endSpan.fToAngle;
   3931     int foundIndex;
   3932     int otherEnd;
   3933     SkOpSegment* other;
   3934     if (angle == NULL) {
   3935         if (endSpan.fT != 0 && endSpan.fT != 1) {
   3936             return NULL;
   3937         }
   3938         other = endSpan.fOther;
   3939         foundIndex = endSpan.fOtherIndex;
   3940         otherEnd = other->nextExactSpan(foundIndex, step);
   3941     } else {
   3942         int loopCount = angle->loopCount();
   3943         if (loopCount > 2) {
   3944             return set_last(last, &endSpan);
   3945         }
   3946         const SkOpAngle* next = angle->next();
   3947         if (NULL == next) {
   3948             return NULL;
   3949         }
   3950         if (angle->sign() != next->sign()) {
   3951 #if DEBUG_WINDING
   3952             SkDebugf("%s mismatched signs\n", __FUNCTION__);
   3953 #endif
   3954         //    return set_last(last, &endSpan);
   3955         }
   3956         other = next->segment();
   3957         foundIndex = end = next->start();
   3958         otherEnd = next->end();
   3959     }
   3960     int foundStep = foundIndex < otherEnd ? 1 : -1;
   3961     if (*stepPtr != foundStep) {
   3962         return set_last(last, &endSpan);
   3963     }
   3964     SkASSERT(*indexPtr >= 0);
   3965     if (otherEnd < 0) {
   3966         return NULL;
   3967     }
   3968 //    SkASSERT(otherEnd >= 0);
   3969 #if 1
   3970     int origMin = origIndex + (step < 0 ? step : 0);
   3971     const SkOpSpan& orig = this->span(origMin);
   3972 #endif
   3973     int foundMin = SkMin32(foundIndex, otherEnd);
   3974 #if 1
   3975     const SkOpSpan& found = other->span(foundMin);
   3976     if (found.fWindValue != orig.fWindValue || found.fOppValue != orig.fOppValue) {
   3977           return set_last(last, &endSpan);
   3978     }
   3979 #endif
   3980     *indexPtr = foundIndex;
   3981     *stepPtr = foundStep;
   3982     if (minPtr) {
   3983         *minPtr = foundMin;
   3984     }
   3985     return other;
   3986 }
   3987 
   3988 // This has callers for two different situations: one establishes the end
   3989 // of the current span, and one establishes the beginning of the next span
   3990 // (thus the name). When this is looking for the end of the current span,
   3991 // coincidence is found when the beginning Ts contain -step and the end
   3992 // contains step. When it is looking for the beginning of the next, the
   3993 // first Ts found can be ignored and the last Ts should contain -step.
   3994 // OPTIMIZATION: probably should split into two functions
   3995 int SkOpSegment::nextSpan(int from, int step) const {
   3996     const SkOpSpan& fromSpan = fTs[from];
   3997     int count = fTs.count();
   3998     int to = from;
   3999     while (step > 0 ? ++to < count : --to >= 0) {
   4000         const SkOpSpan& span = fTs[to];
   4001         if (approximately_zero(span.fT - fromSpan.fT)) {
   4002             continue;
   4003         }
   4004         return to;
   4005     }
   4006     return -1;
   4007 }
   4008 
   4009 // FIXME
   4010 // this returns at any difference in T, vs. a preset minimum. It may be
   4011 // that all callers to nextSpan should use this instead.
   4012 int SkOpSegment::nextExactSpan(int from, int step) const {
   4013     int to = from;
   4014     if (step < 0) {
   4015         const SkOpSpan& fromSpan = fTs[from];
   4016         while (--to >= 0) {
   4017             const SkOpSpan& span = fTs[to];
   4018             if (precisely_negative(fromSpan.fT - span.fT) || span.fTiny) {
   4019                 continue;
   4020             }
   4021             return to;
   4022         }
   4023     } else {
   4024         while (fTs[from].fTiny) {
   4025             from++;
   4026         }
   4027         const SkOpSpan& fromSpan = fTs[from];
   4028         int count = fTs.count();
   4029         while (++to < count) {
   4030             const SkOpSpan& span = fTs[to];
   4031             if (precisely_negative(span.fT - fromSpan.fT)) {
   4032                 continue;
   4033             }
   4034             return to;
   4035         }
   4036     }
   4037     return -1;
   4038 }
   4039 
   4040 void SkOpSegment::pinT(const SkPoint& pt, double* t) {
   4041     if (pt == fPts[0]) {
   4042         *t = 0;
   4043     }
   4044     int count = SkPathOpsVerbToPoints(fVerb);
   4045     if (pt == fPts[count]) {
   4046         *t = 1;
   4047     }
   4048 }
   4049 
   4050 bool SkOpSegment::reversePoints(const SkPoint& p1, const SkPoint& p2) const {
   4051     SkASSERT(p1 != p2);
   4052     int spanCount = count();
   4053     int p1IndexMin = -1;
   4054     int p2IndexMax = spanCount;
   4055     for (int index = 0; index < spanCount; ++index) {
   4056         const SkOpSpan& span = fTs[index];
   4057         if (span.fPt == p1) {
   4058             if (p1IndexMin < 0) {
   4059                 p1IndexMin = index;
   4060             }
   4061         } else if (span.fPt == p2) {
   4062             p2IndexMax = index;
   4063         }
   4064     }
   4065     return p1IndexMin > p2IndexMax;
   4066 }
   4067 
   4068 void SkOpSegment::setCoincidentRange(const SkPoint& startPt, const SkPoint& endPt,
   4069         SkOpSegment* other) {
   4070     int count = this->count();
   4071     for (int index = 0; index < count; ++index) {
   4072         SkOpSpan &span = fTs[index];
   4073         if ((startPt == span.fPt || endPt == span.fPt) && other == span.fOther) {
   4074             span.fCoincident = true;
   4075         }
   4076     }
   4077 }
   4078 
   4079 void SkOpSegment::setUpWindings(int index, int endIndex, int* sumMiWinding, int* sumSuWinding,
   4080         int* maxWinding, int* sumWinding, int* oppMaxWinding, int* oppSumWinding) {
   4081     int deltaSum = spanSign(index, endIndex);
   4082     int oppDeltaSum = oppSign(index, endIndex);
   4083     if (operand()) {
   4084         *maxWinding = *sumSuWinding;
   4085         *sumWinding = *sumSuWinding -= deltaSum;
   4086         *oppMaxWinding = *sumMiWinding;
   4087         *oppSumWinding = *sumMiWinding -= oppDeltaSum;
   4088     } else {
   4089         *maxWinding = *sumMiWinding;
   4090         *sumWinding = *sumMiWinding -= deltaSum;
   4091         *oppMaxWinding = *sumSuWinding;
   4092         *oppSumWinding = *sumSuWinding -= oppDeltaSum;
   4093     }
   4094 #if DEBUG_LIMIT_WIND_SUM
   4095     SkASSERT(abs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
   4096     SkASSERT(abs(*oppSumWinding) <= DEBUG_LIMIT_WIND_SUM);
   4097 #endif
   4098 }
   4099 
   4100 void SkOpSegment::setUpWindings(int index, int endIndex, int* sumMiWinding,
   4101         int* maxWinding, int* sumWinding) {
   4102     int deltaSum = spanSign(index, endIndex);
   4103     *maxWinding = *sumMiWinding;
   4104     *sumWinding = *sumMiWinding -= deltaSum;
   4105 #if DEBUG_LIMIT_WIND_SUM
   4106     SkASSERT(abs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
   4107 #endif
   4108 }
   4109 
   4110 void SkOpSegment::sortAngles() {
   4111     int spanCount = fTs.count();
   4112     if (spanCount <= 2) {
   4113         return;
   4114     }
   4115     int index = 0;
   4116     do {
   4117         SkOpAngle* fromAngle = fTs[index].fFromAngle;
   4118         SkOpAngle* toAngle = fTs[index].fToAngle;
   4119         if (!fromAngle && !toAngle) {
   4120             index += 1;
   4121             continue;
   4122         }
   4123         SkOpAngle* baseAngle = NULL;
   4124         if (fromAngle) {
   4125             baseAngle = fromAngle;
   4126             if (inLoop(baseAngle, spanCount, &index)) {
   4127                 continue;
   4128             }
   4129         }
   4130 #if DEBUG_ANGLE
   4131         bool wroteAfterHeader = false;
   4132 #endif
   4133         if (toAngle) {
   4134             if (!baseAngle) {
   4135                 baseAngle = toAngle;
   4136                 if (inLoop(baseAngle, spanCount, &index)) {
   4137                     continue;
   4138                 }
   4139             } else {
   4140                 SkDEBUGCODE(int newIndex = index);
   4141                 SkASSERT(!inLoop(baseAngle, spanCount, &newIndex) && newIndex == index);
   4142 #if DEBUG_ANGLE
   4143                 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), fTs[index].fT,
   4144                         index);
   4145                 wroteAfterHeader = true;
   4146 #endif
   4147                 baseAngle->insert(toAngle);
   4148             }
   4149         }
   4150         SkOpAngle* nextFrom, * nextTo;
   4151         int firstIndex = index;
   4152         do {
   4153             SkOpSpan& span = fTs[index];
   4154             SkOpSegment* other = span.fOther;
   4155             SkOpSpan& oSpan = other->fTs[span.fOtherIndex];
   4156             SkOpAngle* oAngle = oSpan.fFromAngle;
   4157             if (oAngle) {
   4158 #if DEBUG_ANGLE
   4159                 if (!wroteAfterHeader) {
   4160                     SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), fTs[index].fT,
   4161                             index);
   4162                     wroteAfterHeader = true;
   4163                 }
   4164 #endif
   4165                 if (!oAngle->loopContains(*baseAngle)) {
   4166                     baseAngle->insert(oAngle);
   4167                 }
   4168             }
   4169             oAngle = oSpan.fToAngle;
   4170             if (oAngle) {
   4171 #if DEBUG_ANGLE
   4172                 if (!wroteAfterHeader) {
   4173                     SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), fTs[index].fT,
   4174                             index);
   4175                     wroteAfterHeader = true;
   4176                 }
   4177 #endif
   4178                 if (!oAngle->loopContains(*baseAngle)) {
   4179                     baseAngle->insert(oAngle);
   4180                 }
   4181             }
   4182             if (++index == spanCount) {
   4183                 break;
   4184             }
   4185             nextFrom = fTs[index].fFromAngle;
   4186             nextTo = fTs[index].fToAngle;
   4187         } while (fromAngle == nextFrom && toAngle == nextTo);
   4188         if (baseAngle && baseAngle->loopCount() == 1) {
   4189             index = firstIndex;
   4190             do {
   4191                 SkOpSpan& span = fTs[index];
   4192                 span.fFromAngle = span.fToAngle = NULL;
   4193                 if (++index == spanCount) {
   4194                     break;
   4195                 }
   4196                 nextFrom = fTs[index].fFromAngle;
   4197                 nextTo = fTs[index].fToAngle;
   4198             } while (fromAngle == nextFrom && toAngle == nextTo);
   4199             baseAngle = NULL;
   4200         }
   4201 #if DEBUG_SORT
   4202         SkASSERT(!baseAngle || baseAngle->loopCount() > 1);
   4203 #endif
   4204     } while (index < spanCount);
   4205 }
   4206 
   4207 // return true if midpoints were computed
   4208 bool SkOpSegment::subDivide(int start, int end, SkPoint edge[4]) const {
   4209     SkASSERT(start != end);
   4210     edge[0] = fTs[start].fPt;
   4211     int points = SkPathOpsVerbToPoints(fVerb);
   4212     edge[points] = fTs[end].fPt;
   4213     if (fVerb == SkPath::kLine_Verb) {
   4214         return false;
   4215     }
   4216     double startT = fTs[start].fT;
   4217     double endT = fTs[end].fT;
   4218     if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
   4219         // don't compute midpoints if we already have them
   4220         if (fVerb == SkPath::kQuad_Verb) {
   4221             edge[1] = fPts[1];
   4222             return false;
   4223         }
   4224         SkASSERT(fVerb == SkPath::kCubic_Verb);
   4225         if (start < end) {
   4226             edge[1] = fPts[1];
   4227             edge[2] = fPts[2];
   4228             return false;
   4229         }
   4230         edge[1] = fPts[2];
   4231         edge[2] = fPts[1];
   4232         return false;
   4233     }
   4234     const SkDPoint sub[2] = {{ edge[0].fX, edge[0].fY}, {edge[points].fX, edge[points].fY }};
   4235     if (fVerb == SkPath::kQuad_Verb) {
   4236         edge[1] = SkDQuad::SubDivide(fPts, sub[0], sub[1], startT, endT).asSkPoint();
   4237     } else {
   4238         SkASSERT(fVerb == SkPath::kCubic_Verb);
   4239         SkDPoint ctrl[2];
   4240         SkDCubic::SubDivide(fPts, sub[0], sub[1], startT, endT, ctrl);
   4241         edge[1] = ctrl[0].asSkPoint();
   4242         edge[2] = ctrl[1].asSkPoint();
   4243     }
   4244     return true;
   4245 }
   4246 
   4247 // return true if midpoints were computed
   4248 bool SkOpSegment::subDivide(int start, int end, SkDCubic* result) const {
   4249     SkASSERT(start != end);
   4250     (*result)[0].set(fTs[start].fPt);
   4251     int points = SkPathOpsVerbToPoints(fVerb);
   4252     (*result)[points].set(fTs[end].fPt);
   4253     if (fVerb == SkPath::kLine_Verb) {
   4254         return false;
   4255     }
   4256     double startT = fTs[start].fT;
   4257     double endT = fTs[end].fT;
   4258     if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
   4259         // don't compute midpoints if we already have them
   4260         if (fVerb == SkPath::kQuad_Verb) {
   4261             (*result)[1].set(fPts[1]);
   4262             return false;
   4263         }
   4264         SkASSERT(fVerb == SkPath::kCubic_Verb);
   4265         if (start < end) {
   4266             (*result)[1].set(fPts[1]);
   4267             (*result)[2].set(fPts[2]);
   4268             return false;
   4269         }
   4270         (*result)[1].set(fPts[2]);
   4271         (*result)[2].set(fPts[1]);
   4272         return false;
   4273     }
   4274     if (fVerb == SkPath::kQuad_Verb) {
   4275         (*result)[1] = SkDQuad::SubDivide(fPts, (*result)[0], (*result)[2], startT, endT);
   4276     } else {
   4277         SkASSERT(fVerb == SkPath::kCubic_Verb);
   4278         SkDCubic::SubDivide(fPts, (*result)[0], (*result)[3], startT, endT, &(*result)[1]);
   4279     }
   4280     return true;
   4281 }
   4282 
   4283 void SkOpSegment::subDivideBounds(int start, int end, SkPathOpsBounds* bounds) const {
   4284     SkPoint edge[4];
   4285     subDivide(start, end, edge);
   4286     (bounds->*SetCurveBounds[SkPathOpsVerbToPoints(fVerb)])(edge);
   4287 }
   4288 
   4289 void SkOpSegment::TrackOutsidePair(SkTArray<SkPoint, true>* outsidePts, const SkPoint& endPt,
   4290         const SkPoint& startPt) {
   4291     int outCount = outsidePts->count();
   4292     if (outCount == 0 || endPt != (*outsidePts)[outCount - 2]) {
   4293         outsidePts->push_back(endPt);
   4294         outsidePts->push_back(startPt);
   4295     }
   4296 }
   4297 
   4298 void SkOpSegment::TrackOutside(SkTArray<SkPoint, true>* outsidePts, const SkPoint& startPt) {
   4299     int outCount = outsidePts->count();
   4300     if (outCount == 0 || startPt != (*outsidePts)[outCount - 1]) {
   4301         outsidePts->push_back(startPt);
   4302     }
   4303 }
   4304 
   4305 void SkOpSegment::undoneSpan(int* start, int* end) {
   4306     int tCount = fTs.count();
   4307     int index;
   4308     for (index = 0; index < tCount; ++index) {
   4309         if (!fTs[index].fDone) {
   4310             break;
   4311         }
   4312     }
   4313     SkASSERT(index < tCount - 1);
   4314     *start = index;
   4315     double startT = fTs[index].fT;
   4316     while (approximately_negative(fTs[++index].fT - startT))
   4317         SkASSERT(index < tCount);
   4318     SkASSERT(index < tCount);
   4319     *end = index;
   4320 }
   4321 
   4322 int SkOpSegment::updateOppWinding(int index, int endIndex) const {
   4323     int lesser = SkMin32(index, endIndex);
   4324     int oppWinding = oppSum(lesser);
   4325     int oppSpanWinding = oppSign(index, endIndex);
   4326     if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWinding)
   4327             && oppWinding != SK_MaxS32) {
   4328         oppWinding -= oppSpanWinding;
   4329     }
   4330     return oppWinding;
   4331 }
   4332 
   4333 int SkOpSegment::updateOppWinding(const SkOpAngle* angle) const {
   4334     int startIndex = angle->start();
   4335     int endIndex = angle->end();
   4336     return updateOppWinding(endIndex, startIndex);
   4337 }
   4338 
   4339 int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const {
   4340     int startIndex = angle->start();
   4341     int endIndex = angle->end();
   4342     return updateOppWinding(startIndex, endIndex);
   4343 }
   4344 
   4345 int SkOpSegment::updateWinding(int index, int endIndex) const {
   4346     int lesser = SkMin32(index, endIndex);
   4347     int winding = windSum(lesser);
   4348     if (winding == SK_MinS32) {
   4349         return winding;
   4350     }
   4351     int spanWinding = spanSign(index, endIndex);
   4352     if (winding && UseInnerWinding(winding - spanWinding, winding)
   4353             && winding != SK_MaxS32) {
   4354         winding -= spanWinding;
   4355     }
   4356     return winding;
   4357 }
   4358 
   4359 int SkOpSegment::updateWinding(const SkOpAngle* angle) const {
   4360     int startIndex = angle->start();
   4361     int endIndex = angle->end();
   4362     return updateWinding(endIndex, startIndex);
   4363 }
   4364 
   4365 int SkOpSegment::updateWindingReverse(int index, int endIndex) const {
   4366     int lesser = SkMin32(index, endIndex);
   4367     int winding = windSum(lesser);
   4368     int spanWinding = spanSign(endIndex, index);
   4369     if (winding && UseInnerWindingReverse(winding - spanWinding, winding)
   4370             && winding != SK_MaxS32) {
   4371         winding -= spanWinding;
   4372     }
   4373     return winding;
   4374 }
   4375 
   4376 int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) const {
   4377     int startIndex = angle->start();
   4378     int endIndex = angle->end();
   4379     return updateWindingReverse(endIndex, startIndex);
   4380 }
   4381 
   4382 // OPTIMIZATION: does the following also work, and is it any faster?
   4383 // return outerWinding * innerWinding > 0
   4384 //      || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
   4385 bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) {
   4386     SkASSERT(outerWinding != SK_MaxS32);
   4387     SkASSERT(innerWinding != SK_MaxS32);
   4388     int absOut = abs(outerWinding);
   4389     int absIn = abs(innerWinding);
   4390     bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
   4391     return result;
   4392 }
   4393 
   4394 bool SkOpSegment::UseInnerWindingReverse(int outerWinding, int innerWinding) {
   4395     SkASSERT(outerWinding != SK_MaxS32);
   4396     SkASSERT(innerWinding != SK_MaxS32);
   4397     int absOut = abs(outerWinding);
   4398     int absIn = abs(innerWinding);
   4399     bool result = absOut == absIn ? true : absOut < absIn;
   4400     return result;
   4401 }
   4402 
   4403 int SkOpSegment::windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar* dx) const {
   4404     if (approximately_zero(tHit - t(tIndex))) {  // if we hit the end of a span, disregard
   4405         return SK_MinS32;
   4406     }
   4407     int winding = crossOpp ? oppSum(tIndex) : windSum(tIndex);
   4408     SkASSERT(winding != SK_MinS32);
   4409     int windVal = crossOpp ? oppValue(tIndex) : windValue(tIndex);
   4410 #if DEBUG_WINDING_AT_T
   4411     SkDebugf("%s id=%d opp=%d tHit=%1.9g t=%1.9g oldWinding=%d windValue=%d", __FUNCTION__,
   4412             debugID(), crossOpp, tHit, t(tIndex), winding, windVal);
   4413 #endif
   4414     // see if a + change in T results in a +/- change in X (compute x'(T))
   4415     *dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, tHit).fX;
   4416     if (fVerb > SkPath::kLine_Verb && approximately_zero(*dx)) {
   4417         *dx = fPts[2].fX - fPts[1].fX - *dx;
   4418     }
   4419     if (*dx == 0) {
   4420 #if DEBUG_WINDING_AT_T
   4421         SkDebugf(" dx=0 winding=SK_MinS32\n");
   4422 #endif
   4423         return SK_MinS32;
   4424     }
   4425     if (windVal < 0) {  // reverse sign if opp contour traveled in reverse
   4426             *dx = -*dx;
   4427     }
   4428     if (winding * *dx > 0) {  // if same signs, result is negative
   4429         winding += *dx > 0 ? -windVal : windVal;
   4430     }
   4431 #if DEBUG_WINDING_AT_T
   4432     SkDebugf(" dx=%c winding=%d\n", *dx > 0 ? '+' : '-', winding);
   4433 #endif
   4434     return winding;
   4435 }
   4436 
   4437 int SkOpSegment::windSum(const SkOpAngle* angle) const {
   4438     int start = angle->start();
   4439     int end = angle->end();
   4440     int index = SkMin32(start, end);
   4441     return windSum(index);
   4442 }
   4443 
   4444 void SkOpSegment::zeroSpan(SkOpSpan* span) {
   4445     SkASSERT(span->fWindValue > 0 || span->fOppValue != 0);
   4446     span->fWindValue = 0;
   4447     span->fOppValue = 0;
   4448     if (span->fTiny || span->fSmall) {
   4449         return;
   4450     }
   4451     SkASSERT(!span->fDone);
   4452     span->fDone = true;
   4453     ++fDoneSpans;
   4454 }
   4455