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 "SkOpCoincidence.h"
      8 #include "SkOpContour.h"
      9 #include "SkOpSegment.h"
     10 #include "SkPathWriter.h"
     11 
     12 /*
     13 After computing raw intersections, post process all segments to:
     14 - find small collections of points that can be collapsed to a single point
     15 - find missing intersections to resolve differences caused by different algorithms
     16 
     17 Consider segments containing tiny or small intervals. Consider coincident segments
     18 because coincidence finds intersections through distance measurement that non-coincident
     19 intersection tests cannot.
     20  */
     21 
     22 #define F (false)      // discard the edge
     23 #define T (true)       // keep the edge
     24 
     25 static const bool gUnaryActiveEdge[2][2] = {
     26 //  from=0  from=1
     27 //  to=0,1  to=0,1
     28     {F, T}, {T, F},
     29 };
     30 
     31 static const bool gActiveEdge[kXOR_SkPathOp + 1][2][2][2][2] = {
     32 //                 miFrom=0                              miFrom=1
     33 //         miTo=0             miTo=1             miTo=0             miTo=1
     34 //     suFrom=0    1      suFrom=0    1      suFrom=0    1      suFrom=0    1
     35 //   suTo=0,1 suTo=0,1  suTo=0,1 suTo=0,1  suTo=0,1 suTo=0,1  suTo=0,1 suTo=0,1
     36     {{{{F, F}, {F, F}}, {{T, F}, {T, F}}}, {{{T, T}, {F, F}}, {{F, T}, {T, F}}}},  // mi - su
     37     {{{{F, F}, {F, F}}, {{F, T}, {F, T}}}, {{{F, F}, {T, T}}, {{F, T}, {T, F}}}},  // mi & su
     38     {{{{F, T}, {T, F}}, {{T, T}, {F, F}}}, {{{T, F}, {T, F}}, {{F, F}, {F, F}}}},  // mi | su
     39     {{{{F, T}, {T, F}}, {{T, F}, {F, T}}}, {{{T, F}, {F, T}}, {{F, T}, {T, F}}}},  // mi ^ su
     40 };
     41 
     42 #undef F
     43 #undef T
     44 
     45 SkOpAngle* SkOpSegment::activeAngle(SkOpSpanBase* start, SkOpSpanBase** startPtr,
     46         SkOpSpanBase** endPtr, bool* done) {
     47     if (SkOpAngle* result = activeAngleInner(start, startPtr, endPtr, done)) {
     48         return result;
     49     }
     50     if (SkOpAngle* result = activeAngleOther(start, startPtr, endPtr, done)) {
     51         return result;
     52     }
     53     return NULL;
     54 }
     55 
     56 SkOpAngle* SkOpSegment::activeAngleInner(SkOpSpanBase* start, SkOpSpanBase** startPtr,
     57         SkOpSpanBase** endPtr, bool* done) {
     58     SkOpSpan* upSpan = start->upCastable();
     59     if (upSpan) {
     60         if (upSpan->windValue() || upSpan->oppValue()) {
     61             SkOpSpanBase* next = upSpan->next();
     62             if (!*endPtr) {
     63                 *startPtr = start;
     64                 *endPtr = next;
     65             }
     66             if (!upSpan->done()) {
     67                 if (upSpan->windSum() != SK_MinS32) {
     68                     return spanToAngle(start, next);
     69                 }
     70                 *done = false;
     71             }
     72         } else {
     73             SkASSERT(upSpan->done());
     74         }
     75     }
     76     SkOpSpan* downSpan = start->prev();
     77     // edge leading into junction
     78     if (downSpan) {
     79         if (downSpan->windValue() || downSpan->oppValue()) {
     80             if (!*endPtr) {
     81                 *startPtr = start;
     82                 *endPtr = downSpan;
     83             }
     84             if (!downSpan->done()) {
     85                 if (downSpan->windSum() != SK_MinS32) {
     86                     return spanToAngle(start, downSpan);
     87                 }
     88                 *done = false;
     89             }
     90         } else {
     91             SkASSERT(downSpan->done());
     92         }
     93     }
     94     return NULL;
     95 }
     96 
     97 SkOpAngle* SkOpSegment::activeAngleOther(SkOpSpanBase* start, SkOpSpanBase** startPtr,
     98         SkOpSpanBase** endPtr, bool* done) {
     99     SkOpPtT* oPtT = start->ptT()->next();
    100     SkOpSegment* other = oPtT->segment();
    101     SkOpSpanBase* oSpan = oPtT->span();
    102     return other->activeAngleInner(oSpan, startPtr, endPtr, done);
    103 }
    104 
    105 bool SkOpSegment::activeOp(SkOpSpanBase* start, SkOpSpanBase* end, int xorMiMask, int xorSuMask,
    106         SkPathOp op) {
    107     int sumMiWinding = this->updateWinding(end, start);
    108     int sumSuWinding = this->updateOppWinding(end, start);
    109 #if DEBUG_LIMIT_WIND_SUM
    110     SkASSERT(abs(sumMiWinding) <= DEBUG_LIMIT_WIND_SUM);
    111     SkASSERT(abs(sumSuWinding) <= DEBUG_LIMIT_WIND_SUM);
    112 #endif
    113     if (this->operand()) {
    114         SkTSwap<int>(sumMiWinding, sumSuWinding);
    115     }
    116     return this->activeOp(xorMiMask, xorSuMask, start, end, op, &sumMiWinding, &sumSuWinding);
    117 }
    118 
    119 bool SkOpSegment::activeOp(int xorMiMask, int xorSuMask, SkOpSpanBase* start, SkOpSpanBase* end,
    120         SkPathOp op, int* sumMiWinding, int* sumSuWinding) {
    121     int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
    122     this->setUpWindings(start, end, sumMiWinding, sumSuWinding,
    123             &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
    124     bool miFrom;
    125     bool miTo;
    126     bool suFrom;
    127     bool suTo;
    128     if (operand()) {
    129         miFrom = (oppMaxWinding & xorMiMask) != 0;
    130         miTo = (oppSumWinding & xorMiMask) != 0;
    131         suFrom = (maxWinding & xorSuMask) != 0;
    132         suTo = (sumWinding & xorSuMask) != 0;
    133     } else {
    134         miFrom = (maxWinding & xorMiMask) != 0;
    135         miTo = (sumWinding & xorMiMask) != 0;
    136         suFrom = (oppMaxWinding & xorSuMask) != 0;
    137         suTo = (oppSumWinding & xorSuMask) != 0;
    138     }
    139     bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo];
    140 #if DEBUG_ACTIVE_OP
    141     SkDebugf("%s id=%d t=%1.9g tEnd=%1.9g op=%s miFrom=%d miTo=%d suFrom=%d suTo=%d result=%d\n",
    142             __FUNCTION__, debugID(), start->t(), end->t(),
    143             SkPathOpsDebug::kPathOpStr[op], miFrom, miTo, suFrom, suTo, result);
    144 #endif
    145     return result;
    146 }
    147 
    148 bool SkOpSegment::activeWinding(SkOpSpanBase* start, SkOpSpanBase* end) {
    149     int sumWinding = updateWinding(end, start);
    150     return activeWinding(start, end, &sumWinding);
    151 }
    152 
    153 bool SkOpSegment::activeWinding(SkOpSpanBase* start, SkOpSpanBase* end, int* sumWinding) {
    154     int maxWinding;
    155     setUpWinding(start, end, &maxWinding, sumWinding);
    156     bool from = maxWinding != 0;
    157     bool to = *sumWinding  != 0;
    158     bool result = gUnaryActiveEdge[from][to];
    159     return result;
    160 }
    161 
    162 void SkOpSegment::addCurveTo(const SkOpSpanBase* start, const SkOpSpanBase* end,
    163         SkPathWriter* path, bool active) const {
    164     SkOpCurve edge;
    165     const SkPoint* ePtr;
    166     SkScalar eWeight;
    167     if ((start == &fHead && end == &fTail) || (start == &fTail && end == &fHead)) {
    168         ePtr = fPts;
    169         eWeight = fWeight;
    170     } else {
    171     // OPTIMIZE? if not active, skip remainder and return xyAtT(end)
    172         subDivide(start, end, &edge);
    173         ePtr = edge.fPts;
    174         eWeight = edge.fWeight;
    175     }
    176     if (active) {
    177         bool reverse = ePtr == fPts && start != &fHead;
    178         if (reverse) {
    179             path->deferredMoveLine(ePtr[SkPathOpsVerbToPoints(fVerb)]);
    180             switch (fVerb) {
    181                 case SkPath::kLine_Verb:
    182                     path->deferredLine(ePtr[0]);
    183                     break;
    184                 case SkPath::kQuad_Verb:
    185                     path->quadTo(ePtr[1], ePtr[0]);
    186                     break;
    187                 case SkPath::kConic_Verb:
    188                     path->conicTo(ePtr[1], ePtr[0], eWeight);
    189                     break;
    190                 case SkPath::kCubic_Verb:
    191                     path->cubicTo(ePtr[2], ePtr[1], ePtr[0]);
    192                     break;
    193                 default:
    194                     SkASSERT(0);
    195             }
    196        } else {
    197             path->deferredMoveLine(ePtr[0]);
    198             switch (fVerb) {
    199                 case SkPath::kLine_Verb:
    200                     path->deferredLine(ePtr[1]);
    201                     break;
    202                 case SkPath::kQuad_Verb:
    203                     path->quadTo(ePtr[1], ePtr[2]);
    204                     break;
    205                 case SkPath::kConic_Verb:
    206                     path->conicTo(ePtr[1], ePtr[2], eWeight);
    207                     break;
    208                 case SkPath::kCubic_Verb:
    209                     path->cubicTo(ePtr[1], ePtr[2], ePtr[3]);
    210                     break;
    211                 default:
    212                     SkASSERT(0);
    213             }
    214         }
    215     }
    216 }
    217 
    218 SkOpPtT* SkOpSegment::addMissing(double t, SkOpSegment* opp, SkChunkAlloc* allocator) {
    219     SkOpSpanBase* existing = NULL;
    220     SkOpSpanBase* test = &fHead;
    221     double testT;
    222     do {
    223         if ((testT = test->ptT()->fT) >= t) {
    224             if (testT == t) {
    225                 existing = test;
    226             }
    227             break;
    228         }
    229     } while ((test = test->upCast()->next()));
    230     SkOpPtT* result;
    231     if (existing && existing->contains(opp)) {
    232         result = existing->ptT();
    233     } else {
    234         result = this->addT(t, SkOpSegment::kNoAlias, allocator);
    235     }
    236     SkASSERT(result);
    237     return result;
    238 }
    239 
    240 SkOpPtT* SkOpSegment::addT(double t, AllowAlias allowAlias, SkChunkAlloc* allocator) {
    241     debugValidate();
    242     SkPoint pt = this->ptAtT(t);
    243     SkOpSpanBase* span = &fHead;
    244     do {
    245         SkOpPtT* result = span->ptT();
    246         SkOpPtT* loop;
    247         bool duplicatePt;
    248         if (t == result->fT) {
    249             goto bumpSpan;
    250         }
    251         if (this->match(result, this, t, pt)) {
    252             // see if any existing alias matches segment, pt, and t
    253            loop = result->next();
    254             duplicatePt = false;
    255             while (loop != result) {
    256                 bool ptMatch = loop->fPt == pt;
    257                 if (loop->segment() == this && loop->fT == t && ptMatch) {
    258                     goto bumpSpan;
    259                 }
    260                 duplicatePt |= ptMatch;
    261                 loop = loop->next();
    262             }
    263             if (kNoAlias == allowAlias) {
    264     bumpSpan:
    265                 span->bumpSpanAdds();
    266                 return result;
    267             }
    268             SkOpPtT* alias = SkOpTAllocator<SkOpPtT>::Allocate(allocator);
    269             alias->init(result->span(), t, pt, duplicatePt);
    270             result->insert(alias);
    271             result->span()->unaligned();
    272             this->debugValidate();
    273 #if DEBUG_ADD_T
    274             SkDebugf("%s alias t=%1.9g segID=%d spanID=%d\n",  __FUNCTION__, t,
    275                     alias->segment()->debugID(), alias->span()->debugID());
    276 #endif
    277             span->bumpSpanAdds();
    278             return alias;
    279         }
    280         if (t < result->fT) {
    281             SkOpSpan* prev = result->span()->prev();
    282             SkOpSpan* span = insert(prev, allocator);
    283             span->init(this, prev, t, pt);
    284             this->debugValidate();
    285 #if DEBUG_ADD_T
    286             SkDebugf("%s insert t=%1.9g segID=%d spanID=%d\n", __FUNCTION__, t,
    287                     span->segment()->debugID(), span->debugID());
    288 #endif
    289             span->bumpSpanAdds();
    290             return span->ptT();
    291         }
    292         SkASSERT(span != &fTail);
    293     } while ((span = span->upCast()->next()));
    294     SkASSERT(0);
    295     return NULL;
    296 }
    297 
    298 // choose a solitary t and pt value; remove aliases; align the opposite ends
    299 void SkOpSegment::align() {
    300     debugValidate();
    301     SkOpSpanBase* span = &fHead;
    302     if (!span->aligned()) {
    303         span->alignEnd(0, fPts[0]);
    304     }
    305     while ((span = span->upCast()->next())) {
    306         if (span == &fTail) {
    307             break;
    308         }
    309         span->align();
    310     }
    311     if (!span->aligned()) {
    312         span->alignEnd(1, fPts[SkPathOpsVerbToPoints(fVerb)]);
    313     }
    314     if (this->collapsed()) {
    315         SkOpSpan* span = &fHead;
    316         do {
    317             span->setWindValue(0);
    318             span->setOppValue(0);
    319             this->markDone(span);
    320         } while ((span = span->next()->upCastable()));
    321     }
    322     debugValidate();
    323 }
    324 
    325 void SkOpSegment::calcAngles(SkChunkAlloc* allocator) {
    326     bool activePrior = !fHead.isCanceled();
    327     if (activePrior && !fHead.simple()) {
    328         addStartSpan(allocator);
    329     }
    330     SkOpSpan* prior = &fHead;
    331     SkOpSpanBase* spanBase = fHead.next();
    332     while (spanBase != &fTail) {
    333         if (activePrior) {
    334             SkOpAngle* priorAngle = SkOpTAllocator<SkOpAngle>::Allocate(allocator);
    335             priorAngle->set(spanBase, prior);
    336             spanBase->setFromAngle(priorAngle);
    337         }
    338         SkOpSpan* span = spanBase->upCast();
    339         bool active = !span->isCanceled();
    340         SkOpSpanBase* next = span->next();
    341         if (active) {
    342             SkOpAngle* angle = SkOpTAllocator<SkOpAngle>::Allocate(allocator);
    343             angle->set(span, next);
    344             span->setToAngle(angle);
    345         }
    346         activePrior = active;
    347         prior = span;
    348         spanBase = next;
    349     }
    350     if (activePrior && !fTail.simple()) {
    351         addEndSpan(allocator);
    352     }
    353 }
    354 
    355 void SkOpSegment::checkAngleCoin(SkOpCoincidence* coincidences, SkChunkAlloc* allocator) {
    356     SkOpSpanBase* base = &fHead;
    357     SkOpSpan* span;
    358     do {
    359         SkOpAngle* angle = base->fromAngle();
    360         if (angle && angle->fCheckCoincidence) {
    361             angle->checkNearCoincidence();
    362         }
    363         if (base->final()) {
    364              break;
    365         }
    366         span = base->upCast();
    367         angle = span->toAngle();
    368         if (angle && angle->fCheckCoincidence) {
    369             angle->checkNearCoincidence();
    370         }
    371     } while ((base = span->next()));
    372 }
    373 
    374 bool SkOpSegment::collapsed() const {
    375     return fVerb == SkPath::kLine_Verb && fHead.pt() == fTail.pt();
    376 }
    377 
    378 void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
    379         SkOpAngle::IncludeType includeType) {
    380     SkOpSegment* baseSegment = baseAngle->segment();
    381     int sumMiWinding = baseSegment->updateWindingReverse(baseAngle);
    382     int sumSuWinding;
    383     bool binary = includeType >= SkOpAngle::kBinarySingle;
    384     if (binary) {
    385         sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle);
    386         if (baseSegment->operand()) {
    387             SkTSwap<int>(sumMiWinding, sumSuWinding);
    388         }
    389     }
    390     SkOpSegment* nextSegment = nextAngle->segment();
    391     int maxWinding, sumWinding;
    392     SkOpSpanBase* last;
    393     if (binary) {
    394         int oppMaxWinding, oppSumWinding;
    395         nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
    396                 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
    397         last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
    398                 nextAngle);
    399     } else {
    400         nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
    401                 &maxWinding, &sumWinding);
    402         last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
    403     }
    404     nextAngle->setLastMarked(last);
    405 }
    406 
    407 void SkOpSegment::ComputeOneSumReverse(SkOpAngle* baseAngle, SkOpAngle* nextAngle,
    408         SkOpAngle::IncludeType includeType) {
    409     SkOpSegment* baseSegment = baseAngle->segment();
    410     int sumMiWinding = baseSegment->updateWinding(baseAngle);
    411     int sumSuWinding;
    412     bool binary = includeType >= SkOpAngle::kBinarySingle;
    413     if (binary) {
    414         sumSuWinding = baseSegment->updateOppWinding(baseAngle);
    415         if (baseSegment->operand()) {
    416             SkTSwap<int>(sumMiWinding, sumSuWinding);
    417         }
    418     }
    419     SkOpSegment* nextSegment = nextAngle->segment();
    420     int maxWinding, sumWinding;
    421     SkOpSpanBase* last;
    422     if (binary) {
    423         int oppMaxWinding, oppSumWinding;
    424         nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
    425                 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
    426         last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
    427                 nextAngle);
    428     } else {
    429         nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
    430                 &maxWinding, &sumWinding);
    431         last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
    432     }
    433     nextAngle->setLastMarked(last);
    434 }
    435 
    436 // at this point, the span is already ordered, or unorderable
    437 int SkOpSegment::computeSum(SkOpSpanBase* start, SkOpSpanBase* end,
    438         SkOpAngle::IncludeType includeType) {
    439     SkASSERT(includeType != SkOpAngle::kUnaryXor);
    440     SkOpAngle* firstAngle = this->spanToAngle(end, start);
    441     if (NULL == firstAngle || NULL == firstAngle->next()) {
    442         return SK_NaN32;
    443     }
    444     // if all angles have a computed winding,
    445     //  or if no adjacent angles are orderable,
    446     //  or if adjacent orderable angles have no computed winding,
    447     //  there's nothing to do
    448     // if two orderable angles are adjacent, and both are next to orderable angles,
    449     //  and one has winding computed, transfer to the other
    450     SkOpAngle* baseAngle = NULL;
    451     bool tryReverse = false;
    452     // look for counterclockwise transfers
    453     SkOpAngle* angle = firstAngle->previous();
    454     SkOpAngle* next = angle->next();
    455     firstAngle = next;
    456     do {
    457         SkOpAngle* prior = angle;
    458         angle = next;
    459         next = angle->next();
    460         SkASSERT(prior->next() == angle);
    461         SkASSERT(angle->next() == next);
    462         if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
    463             baseAngle = NULL;
    464             continue;
    465         }
    466         int testWinding = angle->starter()->windSum();
    467         if (SK_MinS32 != testWinding) {
    468             baseAngle = angle;
    469             tryReverse = true;
    470             continue;
    471         }
    472         if (baseAngle) {
    473             ComputeOneSum(baseAngle, angle, includeType);
    474             baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : NULL;
    475         }
    476     } while (next != firstAngle);
    477     if (baseAngle && SK_MinS32 == firstAngle->starter()->windSum()) {
    478         firstAngle = baseAngle;
    479         tryReverse = true;
    480     }
    481     if (tryReverse) {
    482         baseAngle = NULL;
    483         SkOpAngle* prior = firstAngle;
    484         do {
    485             angle = prior;
    486             prior = angle->previous();
    487             SkASSERT(prior->next() == angle);
    488             next = angle->next();
    489             if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
    490                 baseAngle = NULL;
    491                 continue;
    492             }
    493             int testWinding = angle->starter()->windSum();
    494             if (SK_MinS32 != testWinding) {
    495                 baseAngle = angle;
    496                 continue;
    497             }
    498             if (baseAngle) {
    499                 ComputeOneSumReverse(baseAngle, angle, includeType);
    500                 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : NULL;
    501             }
    502         } while (prior != firstAngle);
    503     }
    504     return start->starter(end)->windSum();
    505 }
    506 
    507 void SkOpSegment::detach(const SkOpSpan* span) {
    508     if (span->done()) {
    509         --fDoneCount;
    510     }
    511     --fCount;
    512     SkASSERT(fCount >= fDoneCount);
    513 }
    514 
    515 double SkOpSegment::distSq(double t, SkOpAngle* oppAngle) {
    516     SkDPoint testPt = this->dPtAtT(t);
    517     SkDLine testPerp = {{ testPt, testPt }};
    518     SkDVector slope = this->dSlopeAtT(t);
    519     testPerp[1].fX += slope.fY;
    520     testPerp[1].fY -= slope.fX;
    521     SkIntersections i;
    522     SkOpSegment* oppSegment = oppAngle->segment();
    523     (*CurveIntersectRay[oppSegment->verb()])(oppSegment->pts(), oppSegment->weight(), testPerp, &i);
    524     double closestDistSq = SK_ScalarInfinity;
    525     for (int index = 0; index < i.used(); ++index) {
    526         if (!between(oppAngle->start()->t(), i[0][index], oppAngle->end()->t())) {
    527             continue;
    528         }
    529         double testDistSq = testPt.distanceSquared(i.pt(index));
    530         if (closestDistSq > testDistSq) {
    531             closestDistSq = testDistSq;
    532         }
    533     }
    534     return closestDistSq;
    535 }
    536 
    537 /*
    538  The M and S variable name parts stand for the operators.
    539    Mi stands for Minuend (see wiki subtraction, analogous to difference)
    540    Su stands for Subtrahend
    541  The Opp variable name part designates that the value is for the Opposite operator.
    542  Opposite values result from combining coincident spans.
    543  */
    544 SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBase** nextStart,
    545         SkOpSpanBase** nextEnd, bool* unsortable, SkPathOp op, int xorMiMask, int xorSuMask) {
    546     SkOpSpanBase* start = *nextStart;
    547     SkOpSpanBase* end = *nextEnd;
    548     SkASSERT(start != end);
    549     int step = start->step(end);
    550     SkOpSegment* other = this->isSimple(nextStart, &step);  // advances nextStart
    551     if (other) {
    552     // mark the smaller of startIndex, endIndex done, and all adjacent
    553     // spans with the same T value (but not 'other' spans)
    554 #if DEBUG_WINDING
    555         SkDebugf("%s simple\n", __FUNCTION__);
    556 #endif
    557         SkOpSpan* startSpan = start->starter(end);
    558         if (startSpan->done()) {
    559             return NULL;
    560         }
    561         markDone(startSpan);
    562         *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
    563         return other;
    564     }
    565     SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
    566     SkASSERT(endNear == end);  // is this ever not end?
    567     SkASSERT(endNear);
    568     SkASSERT(start != endNear);
    569     SkASSERT((start->t() < endNear->t()) ^ (step < 0));
    570     // more than one viable candidate -- measure angles to find best
    571     int calcWinding = computeSum(start, endNear, SkOpAngle::kBinaryOpp);
    572     bool sortable = calcWinding != SK_NaN32;
    573     if (!sortable) {
    574         *unsortable = true;
    575         markDone(start->starter(end));
    576         return NULL;
    577     }
    578     SkOpAngle* angle = this->spanToAngle(end, start);
    579     if (angle->unorderable()) {
    580         *unsortable = true;
    581         markDone(start->starter(end));
    582         return NULL;
    583     }
    584 #if DEBUG_SORT
    585     SkDebugf("%s\n", __FUNCTION__);
    586     angle->debugLoop();
    587 #endif
    588     int sumMiWinding = updateWinding(end, start);
    589     if (sumMiWinding == SK_MinS32) {
    590         *unsortable = true;
    591         markDone(start->starter(end));
    592         return NULL;
    593     }
    594     int sumSuWinding = updateOppWinding(end, start);
    595     if (operand()) {
    596         SkTSwap<int>(sumMiWinding, sumSuWinding);
    597     }
    598     SkOpAngle* nextAngle = angle->next();
    599     const SkOpAngle* foundAngle = NULL;
    600     bool foundDone = false;
    601     // iterate through the angle, and compute everyone's winding
    602     SkOpSegment* nextSegment;
    603     int activeCount = 0;
    604     do {
    605         nextSegment = nextAngle->segment();
    606         bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
    607                 nextAngle->end(), op, &sumMiWinding, &sumSuWinding);
    608         if (activeAngle) {
    609             ++activeCount;
    610             if (!foundAngle || (foundDone && activeCount & 1)) {
    611                 foundAngle = nextAngle;
    612                 foundDone = nextSegment->done(nextAngle);
    613             }
    614         }
    615         if (nextSegment->done()) {
    616             continue;
    617         }
    618         if (!activeAngle) {
    619             (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end());
    620         }
    621         SkOpSpanBase* last = nextAngle->lastMarked();
    622         if (last) {
    623             SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
    624             *chase->append() = last;
    625 #if DEBUG_WINDING
    626             SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__,
    627                     last->segment()->debugID(), last->debugID());
    628             if (!last->final()) {
    629                 SkDebugf(" windSum=%d", last->upCast()->windSum());
    630             }
    631             SkDebugf("\n");
    632 #endif
    633         }
    634     } while ((nextAngle = nextAngle->next()) != angle);
    635     start->segment()->markDone(start->starter(end));
    636     if (!foundAngle) {
    637         return NULL;
    638     }
    639     *nextStart = foundAngle->start();
    640     *nextEnd = foundAngle->end();
    641     nextSegment = foundAngle->segment();
    642 #if DEBUG_WINDING
    643     SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
    644             __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
    645  #endif
    646     return nextSegment;
    647 }
    648 
    649 SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpanBase*>* chase,
    650         SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd, bool* unsortable) {
    651     SkOpSpanBase* start = *nextStart;
    652     SkOpSpanBase* end = *nextEnd;
    653     SkASSERT(start != end);
    654     int step = start->step(end);
    655     SkOpSegment* other = this->isSimple(nextStart, &step);  // advances nextStart
    656     if (other) {
    657     // mark the smaller of startIndex, endIndex done, and all adjacent
    658     // spans with the same T value (but not 'other' spans)
    659 #if DEBUG_WINDING
    660         SkDebugf("%s simple\n", __FUNCTION__);
    661 #endif
    662         SkOpSpan* startSpan = start->starter(end);
    663         if (startSpan->done()) {
    664             return NULL;
    665         }
    666         markDone(startSpan);
    667         *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
    668         return other;
    669     }
    670     SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
    671     SkASSERT(endNear == end);  // is this ever not end?
    672     SkASSERT(endNear);
    673     SkASSERT(start != endNear);
    674     SkASSERT((start->t() < endNear->t()) ^ (step < 0));
    675     // more than one viable candidate -- measure angles to find best
    676     int calcWinding = computeSum(start, endNear, SkOpAngle::kUnaryWinding);
    677     bool sortable = calcWinding != SK_NaN32;
    678     if (!sortable) {
    679         *unsortable = true;
    680         markDone(start->starter(end));
    681         return NULL;
    682     }
    683     SkOpAngle* angle = this->spanToAngle(end, start);
    684     if (angle->unorderable()) {
    685         *unsortable = true;
    686         markDone(start->starter(end));
    687         return NULL;
    688     }
    689 #if DEBUG_SORT
    690     SkDebugf("%s\n", __FUNCTION__);
    691     angle->debugLoop();
    692 #endif
    693     int sumWinding = updateWinding(end, start);
    694     SkOpAngle* nextAngle = angle->next();
    695     const SkOpAngle* foundAngle = NULL;
    696     bool foundDone = false;
    697     // iterate through the angle, and compute everyone's winding
    698     SkOpSegment* nextSegment;
    699     int activeCount = 0;
    700     do {
    701         nextSegment = nextAngle->segment();
    702         bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
    703                 &sumWinding);
    704         if (activeAngle) {
    705             ++activeCount;
    706             if (!foundAngle || (foundDone && activeCount & 1)) {
    707                 foundAngle = nextAngle;
    708                 foundDone = nextSegment->done(nextAngle);
    709             }
    710         }
    711         if (nextSegment->done()) {
    712             continue;
    713         }
    714         if (!activeAngle) {
    715             (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end());
    716         }
    717         SkOpSpanBase* last = nextAngle->lastMarked();
    718         if (last) {
    719             SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
    720             *chase->append() = last;
    721 #if DEBUG_WINDING
    722             SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__,
    723                     last->segment()->debugID(), last->debugID());
    724             if (!last->final()) {
    725                 SkDebugf(" windSum=%d", last->upCast()->windSum());
    726             }
    727             SkDebugf("\n");
    728 #endif
    729         }
    730     } while ((nextAngle = nextAngle->next()) != angle);
    731     start->segment()->markDone(start->starter(end));
    732     if (!foundAngle) {
    733         return NULL;
    734     }
    735     *nextStart = foundAngle->start();
    736     *nextEnd = foundAngle->end();
    737     nextSegment = foundAngle->segment();
    738 #if DEBUG_WINDING
    739     SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
    740             __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
    741  #endif
    742     return nextSegment;
    743 }
    744 
    745 SkOpSegment* SkOpSegment::findNextXor(SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd,
    746         bool* unsortable) {
    747     SkOpSpanBase* start = *nextStart;
    748     SkOpSpanBase* end = *nextEnd;
    749     SkASSERT(start != end);
    750     int step = start->step(end);
    751     SkOpSegment* other = this->isSimple(nextStart, &step);  // advances nextStart
    752     if (other) {
    753     // mark the smaller of startIndex, endIndex done, and all adjacent
    754     // spans with the same T value (but not 'other' spans)
    755 #if DEBUG_WINDING
    756         SkDebugf("%s simple\n", __FUNCTION__);
    757 #endif
    758         SkOpSpan* startSpan = start->starter(end);
    759         if (startSpan->done()) {
    760             return NULL;
    761         }
    762         markDone(startSpan);
    763         *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
    764         return other;
    765     }
    766     SkDEBUGCODE(SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() \
    767             : (*nextStart)->prev());
    768     SkASSERT(endNear == end);  // is this ever not end?
    769     SkASSERT(endNear);
    770     SkASSERT(start != endNear);
    771     SkASSERT((start->t() < endNear->t()) ^ (step < 0));
    772     SkOpAngle* angle = this->spanToAngle(end, start);
    773     if (angle->unorderable()) {
    774         *unsortable = true;
    775         markDone(start->starter(end));
    776         return NULL;
    777     }
    778 #if DEBUG_SORT
    779     SkDebugf("%s\n", __FUNCTION__);
    780     angle->debugLoop();
    781 #endif
    782     SkOpAngle* nextAngle = angle->next();
    783     const SkOpAngle* foundAngle = NULL;
    784     bool foundDone = false;
    785     // iterate through the angle, and compute everyone's winding
    786     SkOpSegment* nextSegment;
    787     int activeCount = 0;
    788     do {
    789         nextSegment = nextAngle->segment();
    790         ++activeCount;
    791         if (!foundAngle || (foundDone && activeCount & 1)) {
    792             foundAngle = nextAngle;
    793             if (!(foundDone = nextSegment->done(nextAngle))) {
    794                 break;
    795             }
    796         }
    797         nextAngle = nextAngle->next();
    798     } while (nextAngle != angle);
    799     start->segment()->markDone(start->starter(end));
    800     if (!foundAngle) {
    801         return NULL;
    802     }
    803     *nextStart = foundAngle->start();
    804     *nextEnd = foundAngle->end();
    805     nextSegment = foundAngle->segment();
    806 #if DEBUG_WINDING
    807     SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
    808             __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
    809  #endif
    810     return nextSegment;
    811 }
    812 
    813 SkOpGlobalState* SkOpSegment::globalState() const {
    814     return contour()->globalState();
    815 }
    816 
    817 void SkOpSegment::init(SkPoint pts[], SkScalar weight, SkOpContour* contour, SkPath::Verb verb) {
    818     fContour = contour;
    819     fNext = NULL;
    820     fPts = pts;
    821     fWeight = weight;
    822     fVerb = verb;
    823     fCubicType = SkDCubic::kUnsplit_SkDCubicType;
    824     fCount = 0;
    825     fDoneCount = 0;
    826     fTopsFound = false;
    827     fVisited = false;
    828     SkOpSpan* zeroSpan = &fHead;
    829     zeroSpan->init(this, NULL, 0, fPts[0]);
    830     SkOpSpanBase* oneSpan = &fTail;
    831     zeroSpan->setNext(oneSpan);
    832     oneSpan->initBase(this, zeroSpan, 1, fPts[SkPathOpsVerbToPoints(fVerb)]);
    833     SkDEBUGCODE(fID = globalState()->nextSegmentID());
    834 }
    835 
    836 bool SkOpSegment::isClose(double t, const SkOpSegment* opp) const {
    837     SkDPoint cPt = this->dPtAtT(t);
    838     SkDVector dxdy = (*CurveDSlopeAtT[this->verb()])(this->pts(), this->weight(), t);
    839     SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }};
    840     SkIntersections i;
    841     (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(), perp, &i);
    842     int used = i.used();
    843     for (int index = 0; index < used; ++index) {
    844         if (cPt.roughlyEqual(i.pt(index))) {
    845             return true;
    846         }
    847     }
    848     return false;
    849 }
    850 
    851 bool SkOpSegment::isXor() const {
    852     return fContour->isXor();
    853 }
    854 
    855 SkOpSpanBase* SkOpSegment::markAndChaseDone(SkOpSpanBase* start, SkOpSpanBase* end) {
    856     int step = start->step(end);
    857     SkOpSpan* minSpan = start->starter(end);
    858     markDone(minSpan);
    859     SkOpSpanBase* last = NULL;
    860     SkOpSegment* other = this;
    861     while ((other = other->nextChase(&start, &step, &minSpan, &last))) {
    862         if (other->done()) {
    863             SkASSERT(!last);
    864             break;
    865         }
    866         other->markDone(minSpan);
    867     }
    868     return last;
    869 }
    870 
    871 bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end, int winding,
    872         SkOpSpanBase** lastPtr) {
    873     SkOpSpan* spanStart = start->starter(end);
    874     int step = start->step(end);
    875     bool success = markWinding(spanStart, winding);
    876     SkOpSpanBase* last = NULL;
    877     SkOpSegment* other = this;
    878     while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
    879         if (spanStart->windSum() != SK_MinS32) {
    880             SkASSERT(spanStart->windSum() == winding);
    881             SkASSERT(!last);
    882             break;
    883         }
    884         (void) other->markWinding(spanStart, winding);
    885     }
    886     if (lastPtr) {
    887         *lastPtr = last;
    888     }
    889     return success;
    890 }
    891 
    892 bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end,
    893         int winding, int oppWinding, SkOpSpanBase** lastPtr) {
    894     SkOpSpan* spanStart = start->starter(end);
    895     int step = start->step(end);
    896     bool success = markWinding(spanStart, winding, oppWinding);
    897     SkOpSpanBase* last = NULL;
    898     SkOpSegment* other = this;
    899     while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
    900         if (spanStart->windSum() != SK_MinS32) {
    901             if (this->operand() == other->operand()) {
    902                 if (spanStart->windSum() != winding || spanStart->oppSum() != oppWinding) {
    903                     this->globalState()->setWindingFailed();
    904                     return false;
    905                 }
    906             } else {
    907                 SkASSERT(spanStart->windSum() == oppWinding);
    908                 SkASSERT(spanStart->oppSum() == winding);
    909             }
    910             SkASSERT(!last);
    911             break;
    912         }
    913         if (this->operand() == other->operand()) {
    914             (void) other->markWinding(spanStart, winding, oppWinding);
    915         } else {
    916             (void) other->markWinding(spanStart, oppWinding, winding);
    917         }
    918     }
    919     if (lastPtr) {
    920         *lastPtr = last;
    921     }
    922     return success;
    923 }
    924 
    925 SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, const SkOpAngle* angle) {
    926     SkASSERT(angle->segment() == this);
    927     if (UseInnerWinding(maxWinding, sumWinding)) {
    928         maxWinding = sumWinding;
    929     }
    930     SkOpSpanBase* last;
    931     (void) markAndChaseWinding(angle->start(), angle->end(), maxWinding, &last);
    932 #if DEBUG_WINDING
    933     if (last) {
    934         SkDebugf("%s last seg=%d span=%d", __FUNCTION__,
    935                 last->segment()->debugID(), last->debugID());
    936         if (!last->final()) {
    937             SkDebugf(" windSum=");
    938             SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
    939         }
    940         SkDebugf("\n");
    941     }
    942 #endif
    943     return last;
    944 }
    945 
    946 SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWinding,
    947                                    int oppSumWinding, const SkOpAngle* angle) {
    948     SkASSERT(angle->segment() == this);
    949     if (UseInnerWinding(maxWinding, sumWinding)) {
    950         maxWinding = sumWinding;
    951     }
    952     if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumWinding)) {
    953         oppMaxWinding = oppSumWinding;
    954     }
    955     SkOpSpanBase* last = NULL;
    956     // caller doesn't require that this marks anything
    957     (void) markAndChaseWinding(angle->start(), angle->end(), maxWinding, oppMaxWinding, &last);
    958 #if DEBUG_WINDING
    959     if (last) {
    960         SkDebugf("%s last segment=%d span=%d", __FUNCTION__,
    961                 last->segment()->debugID(), last->debugID());
    962         if (!last->final()) {
    963             SkDebugf(" windSum=");
    964             SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
    965         }
    966         SkDebugf(" \n");
    967     }
    968 #endif
    969     return last;
    970 }
    971 
    972 void SkOpSegment::markDone(SkOpSpan* span) {
    973     SkASSERT(this == span->segment());
    974     if (span->done()) {
    975         return;
    976     }
    977 #if DEBUG_MARK_DONE
    978     debugShowNewWinding(__FUNCTION__, span, span->windSum(), span->oppSum());
    979 #endif
    980     span->setDone(true);
    981     ++fDoneCount;
    982     debugValidate();
    983 }
    984 
    985 bool SkOpSegment::markWinding(SkOpSpan* span, int winding) {
    986     SkASSERT(this == span->segment());
    987     SkASSERT(winding);
    988     if (span->done()) {
    989         return false;
    990     }
    991 #if DEBUG_MARK_DONE
    992     debugShowNewWinding(__FUNCTION__, span, winding);
    993 #endif
    994     span->setWindSum(winding);
    995     debugValidate();
    996     return true;
    997 }
    998 
    999 bool SkOpSegment::markWinding(SkOpSpan* span, int winding, int oppWinding) {
   1000     SkASSERT(this == span->segment());
   1001     SkASSERT(winding || oppWinding);
   1002     if (span->done()) {
   1003         return false;
   1004     }
   1005 #if DEBUG_MARK_DONE
   1006     debugShowNewWinding(__FUNCTION__, span, winding, oppWinding);
   1007 #endif
   1008     span->setWindSum(winding);
   1009     span->setOppSum(oppWinding);
   1010     debugValidate();
   1011     return true;
   1012 }
   1013 
   1014 bool SkOpSegment::match(const SkOpPtT* base, const SkOpSegment* testParent, double testT,
   1015         const SkPoint& testPt) const {
   1016     const SkOpSegment* baseParent = base->segment();
   1017     if (this == baseParent && this == testParent && precisely_equal(base->fT, testT)) {
   1018         return true;
   1019     }
   1020     if (!SkDPoint::ApproximatelyEqual(testPt, base->fPt)) {
   1021         return false;
   1022     }
   1023     return !this->ptsDisjoint(base->fT, base->fPt, testT, testPt);
   1024 }
   1025 
   1026 static SkOpSegment* set_last(SkOpSpanBase** last, SkOpSpanBase* endSpan) {
   1027     if (last) {
   1028         *last = endSpan;
   1029     }
   1030     return NULL;
   1031 }
   1032 
   1033 SkOpSegment* SkOpSegment::nextChase(SkOpSpanBase** startPtr, int* stepPtr, SkOpSpan** minPtr,
   1034         SkOpSpanBase** last) const {
   1035     SkOpSpanBase* origStart = *startPtr;
   1036     int step = *stepPtr;
   1037     SkOpSpanBase* endSpan = step > 0 ? origStart->upCast()->next() : origStart->prev();
   1038     SkASSERT(endSpan);
   1039     SkOpAngle* angle = step > 0 ? endSpan->fromAngle() : endSpan->upCast()->toAngle();
   1040     SkOpSpanBase* foundSpan;
   1041     SkOpSpanBase* otherEnd;
   1042     SkOpSegment* other;
   1043     if (angle == NULL) {
   1044         if (endSpan->t() != 0 && endSpan->t() != 1) {
   1045             return NULL;
   1046         }
   1047         SkOpPtT* otherPtT = endSpan->ptT()->next();
   1048         other = otherPtT->segment();
   1049         foundSpan = otherPtT->span();
   1050         otherEnd = step > 0 ? foundSpan->upCast()->next() : foundSpan->prev();
   1051     } else {
   1052         int loopCount = angle->loopCount();
   1053         if (loopCount > 2) {
   1054             return set_last(last, endSpan);
   1055         }
   1056         const SkOpAngle* next = angle->next();
   1057         if (NULL == next) {
   1058             return NULL;
   1059         }
   1060 #if DEBUG_WINDING
   1061         if (angle->debugSign() != next->debugSign() && !angle->segment()->contour()->isXor()
   1062                 && !next->segment()->contour()->isXor()) {
   1063             SkDebugf("%s mismatched signs\n", __FUNCTION__);
   1064         }
   1065 #endif
   1066         other = next->segment();
   1067         foundSpan = endSpan = next->start();
   1068         otherEnd = next->end();
   1069     }
   1070     int foundStep = foundSpan->step(otherEnd);
   1071     if (*stepPtr != foundStep) {
   1072         return set_last(last, endSpan);
   1073     }
   1074     SkASSERT(*startPtr);
   1075     if (!otherEnd) {
   1076         return NULL;
   1077     }
   1078 //    SkASSERT(otherEnd >= 0);
   1079     SkOpSpan* origMin = step < 0 ? origStart->prev() : origStart->upCast();
   1080     SkOpSpan* foundMin = foundSpan->starter(otherEnd);
   1081     if (foundMin->windValue() != origMin->windValue()
   1082             || foundMin->oppValue() != origMin->oppValue()) {
   1083           return set_last(last, endSpan);
   1084     }
   1085     *startPtr = foundSpan;
   1086     *stepPtr = foundStep;
   1087     if (minPtr) {
   1088         *minPtr = foundMin;
   1089     }
   1090     return other;
   1091 }
   1092 
   1093 static void clear_visited(SkOpSpanBase* span) {
   1094     // reset visited flag back to false
   1095     do {
   1096         SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
   1097         while ((ptT = ptT->next()) != stopPtT) {
   1098             SkOpSegment* opp = ptT->segment();
   1099             opp->resetVisited();
   1100         }
   1101     } while (!span->final() && (span = span->upCast()->next()));
   1102 }
   1103 
   1104 // look for pairs of undetected coincident curves
   1105 // assumes that segments going in have visited flag clear
   1106 // curve/curve intersection should now do a pretty good job of finding coincident runs so
   1107 // this may be only be necessary for line/curve pairs -- so skip unless this is a line and the
   1108 // the opp is not a line
   1109 void SkOpSegment::missingCoincidence(SkOpCoincidence* coincidences, SkChunkAlloc* allocator) {
   1110     if (this->verb() != SkPath::kLine_Verb) {
   1111         return;
   1112     }
   1113     if (this->done()) {
   1114         return;
   1115     }
   1116     SkOpSpan* prior = NULL;
   1117     SkOpSpanBase* spanBase = &fHead;
   1118     do {
   1119         SkOpPtT* ptT = spanBase->ptT(), * spanStopPtT = ptT;
   1120         SkASSERT(ptT->span() == spanBase);
   1121         while ((ptT = ptT->next()) != spanStopPtT) {
   1122             if (ptT->deleted()) {
   1123                 continue;
   1124             }
   1125             SkOpSegment* opp = ptT->span()->segment();
   1126             if (opp->verb() == SkPath::kLine_Verb) {
   1127                 continue;
   1128             }
   1129             if (opp->done()) {
   1130                 continue;
   1131             }
   1132             // when opp is encounted the 1st time, continue; on 2nd encounter, look for coincidence
   1133             if (!opp->visited()) {
   1134                 continue;
   1135             }
   1136             if (spanBase == &fHead) {
   1137                 continue;
   1138             }
   1139             SkOpSpan* span = spanBase->upCastable();
   1140             // FIXME?: this assumes that if the opposite segment is coincident then no more
   1141             // coincidence needs to be detected. This may not be true.
   1142             if (span && span->containsCoincidence(opp)) {
   1143                 continue;
   1144             }
   1145             if (spanBase->containsCoinEnd(opp)) {
   1146                 continue;
   1147             }
   1148             SkOpPtT* priorPtT = NULL, * priorStopPtT;
   1149             // find prior span containing opp segment
   1150             SkOpSegment* priorOpp = NULL;
   1151             SkOpSpan* priorTest = spanBase->prev();
   1152             while (!priorOpp && priorTest) {
   1153                 priorStopPtT = priorPtT = priorTest->ptT();
   1154                 while ((priorPtT = priorPtT->next()) != priorStopPtT) {
   1155                     if (priorPtT->deleted()) {
   1156                         continue;
   1157                     }
   1158                     SkOpSegment* segment = priorPtT->span()->segment();
   1159                     if (segment == opp) {
   1160                         prior = priorTest;
   1161                         priorOpp = opp;
   1162                         break;
   1163                     }
   1164                 }
   1165                 priorTest = priorTest->prev();
   1166             }
   1167             if (!priorOpp) {
   1168                 continue;
   1169             }
   1170             SkOpPtT* oppStart = prior->ptT();
   1171             SkOpPtT* oppEnd = spanBase->ptT();
   1172             bool swapped = priorPtT->fT > ptT->fT;
   1173             if (swapped) {
   1174                 SkTSwap(priorPtT, ptT);
   1175                 SkTSwap(oppStart, oppEnd);
   1176             }
   1177             bool flipped = oppStart->fT > oppEnd->fT;
   1178             bool coincident;
   1179             if (coincidences->contains(priorPtT, ptT, oppStart, oppEnd, flipped)) {
   1180                 goto swapBack;
   1181             }
   1182             {
   1183                 // average t, find mid pt
   1184                 double midT = (prior->t() + spanBase->t()) / 2;
   1185                 SkPoint midPt = this->ptAtT(midT);
   1186                 coincident = true;
   1187                 // if the mid pt is not near either end pt, project perpendicular through opp seg
   1188                 if (!SkDPoint::ApproximatelyEqual(priorPtT->fPt, midPt)
   1189                         && !SkDPoint::ApproximatelyEqual(ptT->fPt, midPt)) {
   1190                     coincident = false;
   1191                     SkIntersections i;
   1192                     SkVector dxdy = (*CurveSlopeAtT[fVerb])(this->pts(), this->weight(), midT);
   1193                     SkDLine ray = {{{midPt.fX, midPt.fY},
   1194                             {midPt.fX + dxdy.fY, midPt.fY - dxdy.fX}}};
   1195                     (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(), ray, &i);
   1196                     // measure distance and see if it's small enough to denote coincidence
   1197                     for (int index = 0; index < i.used(); ++index) {
   1198                         SkDPoint oppPt = i.pt(index);
   1199                         if (oppPt.approximatelyEqual(midPt)) {
   1200                             SkVector oppDxdy = (*CurveSlopeAtT[opp->verb()])(opp->pts(),
   1201                                     opp->weight(), i[index][0]);
   1202                             oppDxdy.normalize();
   1203                             dxdy.normalize();
   1204                             SkScalar flatness = SkScalarAbs(dxdy.cross(oppDxdy) / FLT_EPSILON);
   1205                             coincident |= flatness < 5000;  // FIXME: replace with tuned value
   1206                         }
   1207                     }
   1208                 }
   1209             }
   1210             if (coincident) {
   1211             // mark coincidence
   1212                 if (!coincidences->extend(priorPtT, ptT, oppStart, oppEnd)
   1213                         && !coincidences->extend(oppStart, oppEnd, priorPtT, ptT)) {
   1214                     coincidences->add(priorPtT, ptT, oppStart, oppEnd, allocator);
   1215                 }
   1216                 clear_visited(&fHead);
   1217                 return;
   1218             }
   1219     swapBack:
   1220             if (swapped) {
   1221                 SkTSwap(priorPtT, ptT);
   1222             }
   1223         }
   1224     } while ((spanBase = spanBase->final() ? NULL : spanBase->upCast()->next()));
   1225     clear_visited(&fHead);
   1226 }
   1227 
   1228 // if a span has more than one intersection, merge the other segments' span as needed
   1229 void SkOpSegment::moveMultiples() {
   1230     debugValidate();
   1231     SkOpSpanBase* test = &fHead;
   1232     do {
   1233         int addCount = test->spanAddsCount();
   1234         SkASSERT(addCount >= 1);
   1235         if (addCount == 1) {
   1236             continue;
   1237         }
   1238         SkOpPtT* startPtT = test->ptT();
   1239         SkOpPtT* testPtT = startPtT;
   1240         do {  // iterate through all spans associated with start
   1241             SkOpSpanBase* oppSpan = testPtT->span();
   1242             if (oppSpan->spanAddsCount() == addCount) {
   1243                 continue;
   1244             }
   1245             if (oppSpan->deleted()) {
   1246                 continue;
   1247             }
   1248             SkOpSegment* oppSegment = oppSpan->segment();
   1249             if (oppSegment == this) {
   1250                 continue;
   1251             }
   1252             // find range of spans to consider merging
   1253             SkOpSpanBase* oppPrev = oppSpan;
   1254             SkOpSpanBase* oppFirst = oppSpan;
   1255             while ((oppPrev = oppPrev->prev())) {
   1256                 if (!roughly_equal(oppPrev->t(), oppSpan->t())) {
   1257                     break;
   1258                 }
   1259                 if (oppPrev->spanAddsCount() == addCount) {
   1260                     continue;
   1261                 }
   1262                 if (oppPrev->deleted()) {
   1263                     continue;
   1264                 }
   1265                 oppFirst = oppPrev;
   1266             }
   1267             SkOpSpanBase* oppNext = oppSpan;
   1268             SkOpSpanBase* oppLast = oppSpan;
   1269             while ((oppNext = oppNext->final() ? NULL : oppNext->upCast()->next())) {
   1270                 if (!roughly_equal(oppNext->t(), oppSpan->t())) {
   1271                     break;
   1272                 }
   1273                 if (oppNext->spanAddsCount() == addCount) {
   1274                     continue;
   1275                 }
   1276                 if (oppNext->deleted()) {
   1277                     continue;
   1278                 }
   1279                 oppLast = oppNext;
   1280             }
   1281             if (oppFirst == oppLast) {
   1282                 continue;
   1283             }
   1284             SkOpSpanBase* oppTest = oppFirst;
   1285             do {
   1286                 if (oppTest == oppSpan) {
   1287                     continue;
   1288                 }
   1289                 // check to see if the candidate meets specific criteria:
   1290                 // it contains spans of segments in test's loop but not including 'this'
   1291                 SkOpPtT* oppStartPtT = oppTest->ptT();
   1292                 SkOpPtT* oppPtT = oppStartPtT;
   1293                 while ((oppPtT = oppPtT->next()) != oppStartPtT) {
   1294                     SkOpSegment* oppPtTSegment = oppPtT->segment();
   1295                     if (oppPtTSegment == this) {
   1296                         goto tryNextSpan;
   1297                     }
   1298                     SkOpPtT* matchPtT = startPtT;
   1299                     do {
   1300                         if (matchPtT->segment() == oppPtTSegment) {
   1301                             goto foundMatch;
   1302                         }
   1303                     } while ((matchPtT = matchPtT->next()) != startPtT);
   1304                     goto tryNextSpan;
   1305             foundMatch:  // merge oppTest and oppSpan
   1306                     oppSegment->debugValidate();
   1307                     if (oppTest == &oppSegment->fTail || oppTest == &oppSegment->fHead) {
   1308                         SkASSERT(oppSpan != &oppSegment->fHead); // don't expect collapse
   1309                         SkASSERT(oppSpan != &oppSegment->fTail);
   1310                         oppTest->merge(oppSpan->upCast());
   1311                     } else {
   1312                         oppSpan->merge(oppTest->upCast());
   1313                     }
   1314                     oppSegment->debugValidate();
   1315                     goto checkNextSpan;
   1316                 }
   1317         tryNextSpan:
   1318                 ;
   1319             } while (oppTest != oppLast && (oppTest = oppTest->upCast()->next()));
   1320         } while ((testPtT = testPtT->next()) != startPtT);
   1321 checkNextSpan:
   1322         ;
   1323     } while ((test = test->final() ? NULL : test->upCast()->next()));
   1324     debugValidate();
   1325 }
   1326 
   1327 // Move nearby t values and pts so they all hang off the same span. Alignment happens later.
   1328 void SkOpSegment::moveNearby() {
   1329     debugValidate();
   1330     SkOpSpanBase* spanS = &fHead;
   1331     do {
   1332         SkOpSpanBase* test = spanS->upCast()->next();
   1333         SkOpSpanBase* next;
   1334         if (spanS->contains(test)) {
   1335             if (!test->final()) {
   1336                 test->upCast()->detach(spanS->ptT());
   1337                 continue;
   1338             } else if (spanS != &fHead) {
   1339                 spanS->upCast()->detach(test->ptT());
   1340                 spanS = test;
   1341                 continue;
   1342             }
   1343         }
   1344         do {  // iterate through all spans associated with start
   1345             SkOpPtT* startBase = spanS->ptT();
   1346             next = test->final() ? NULL : test->upCast()->next();
   1347             do {
   1348                 SkOpPtT* testBase = test->ptT();
   1349                 do {
   1350                     if (startBase == testBase) {
   1351                         goto checkNextSpan;
   1352                     }
   1353                     if (testBase->duplicate()) {
   1354                         continue;
   1355                     }
   1356                     if (this->match(startBase, testBase->segment(), testBase->fT, testBase->fPt)) {
   1357                         if (test == &this->fTail) {
   1358                             if (spanS == &fHead) {
   1359                                 debugValidate();
   1360                                 return;  // if this span has collapsed, remove it from parent
   1361                             }
   1362                             this->fTail.merge(spanS->upCast());
   1363                             debugValidate();
   1364                             return;
   1365                         }
   1366                         spanS->merge(test->upCast());
   1367                         spanS->upCast()->setNext(next);
   1368                         goto checkNextSpan;
   1369                     }
   1370                 } while ((testBase = testBase->next()) != test->ptT());
   1371             } while ((startBase = startBase->next()) != spanS->ptT());
   1372     checkNextSpan:
   1373             ;
   1374         } while ((test = next));
   1375         spanS = spanS->upCast()->next();
   1376     } while (!spanS->final());
   1377     debugValidate();
   1378 }
   1379 
   1380 bool SkOpSegment::operand() const {
   1381     return fContour->operand();
   1382 }
   1383 
   1384 bool SkOpSegment::oppXor() const {
   1385     return fContour->oppXor();
   1386 }
   1387 
   1388 bool SkOpSegment::ptsDisjoint(double t1, const SkPoint& pt1, double t2, const SkPoint& pt2) const {
   1389     if (fVerb == SkPath::kLine_Verb) {
   1390         return false;
   1391     }
   1392     // quads (and cubics) can loop back to nearly a line so that an opposite curve
   1393     // hits in two places with very different t values.
   1394     // OPTIMIZATION: curves could be preflighted so that, for example, something like
   1395     // 'controls contained by ends' could avoid this check for common curves
   1396     // 'ends are extremes in x or y' is cheaper to compute and real-world common
   1397     // on the other hand, the below check is relatively inexpensive
   1398     double midT = (t1 + t2) / 2;
   1399     SkPoint midPt = this->ptAtT(midT);
   1400     double seDistSq = SkTMax(pt1.distanceToSqd(pt2) * 2, FLT_EPSILON * 2);
   1401     return midPt.distanceToSqd(pt1) > seDistSq || midPt.distanceToSqd(pt2) > seDistSq;
   1402 }
   1403 
   1404 void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
   1405         int* maxWinding, int* sumWinding) {
   1406     int deltaSum = SpanSign(start, end);
   1407     *maxWinding = *sumMiWinding;
   1408     *sumWinding = *sumMiWinding -= deltaSum;
   1409     SkASSERT(!DEBUG_LIMIT_WIND_SUM || abs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
   1410 }
   1411 
   1412 void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
   1413         int* sumSuWinding, int* maxWinding, int* sumWinding, int* oppMaxWinding,
   1414         int* oppSumWinding) {
   1415     int deltaSum = SpanSign(start, end);
   1416     int oppDeltaSum = OppSign(start, end);
   1417     if (operand()) {
   1418         *maxWinding = *sumSuWinding;
   1419         *sumWinding = *sumSuWinding -= deltaSum;
   1420         *oppMaxWinding = *sumMiWinding;
   1421         *oppSumWinding = *sumMiWinding -= oppDeltaSum;
   1422     } else {
   1423         *maxWinding = *sumMiWinding;
   1424         *sumWinding = *sumMiWinding -= deltaSum;
   1425         *oppMaxWinding = *sumSuWinding;
   1426         *oppSumWinding = *sumSuWinding -= oppDeltaSum;
   1427     }
   1428     SkASSERT(!DEBUG_LIMIT_WIND_SUM || abs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
   1429     SkASSERT(!DEBUG_LIMIT_WIND_SUM || abs(*oppSumWinding) <= DEBUG_LIMIT_WIND_SUM);
   1430 }
   1431 
   1432 void SkOpSegment::sortAngles() {
   1433     SkOpSpanBase* span = &this->fHead;
   1434     do {
   1435         SkOpAngle* fromAngle = span->fromAngle();
   1436         SkOpAngle* toAngle = span->final() ? NULL : span->upCast()->toAngle();
   1437         if (!fromAngle && !toAngle) {
   1438             continue;
   1439         }
   1440 #if DEBUG_ANGLE
   1441         bool wroteAfterHeader = false;
   1442 #endif
   1443         SkOpAngle* baseAngle = fromAngle;
   1444         if (fromAngle && toAngle) {
   1445 #if DEBUG_ANGLE
   1446             SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), span->t(),
   1447                     span->debugID());
   1448             wroteAfterHeader = true;
   1449 #endif
   1450             fromAngle->insert(toAngle);
   1451         } else if (!fromAngle) {
   1452             baseAngle = toAngle;
   1453         }
   1454         SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
   1455         do {
   1456             SkOpSpanBase* oSpan = ptT->span();
   1457             if (oSpan == span) {
   1458                 continue;
   1459             }
   1460             SkOpAngle* oAngle = oSpan->fromAngle();
   1461             if (oAngle) {
   1462 #if DEBUG_ANGLE
   1463                 if (!wroteAfterHeader) {
   1464                     SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
   1465                             span->t(), span->debugID());
   1466                     wroteAfterHeader = true;
   1467                 }
   1468 #endif
   1469                 if (!oAngle->loopContains(baseAngle)) {
   1470                     baseAngle->insert(oAngle);
   1471                 }
   1472             }
   1473             if (!oSpan->final()) {
   1474                 oAngle = oSpan->upCast()->toAngle();
   1475                 if (oAngle) {
   1476 #if DEBUG_ANGLE
   1477                     if (!wroteAfterHeader) {
   1478                         SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
   1479                                 span->t(), span->debugID());
   1480                         wroteAfterHeader = true;
   1481                     }
   1482 #endif
   1483                     if (!oAngle->loopContains(baseAngle)) {
   1484                         baseAngle->insert(oAngle);
   1485                     }
   1486                 }
   1487             }
   1488         } while ((ptT = ptT->next()) != stopPtT);
   1489         if (baseAngle->loopCount() == 1) {
   1490             span->setFromAngle(NULL);
   1491             if (toAngle) {
   1492                 span->upCast()->setToAngle(NULL);
   1493             }
   1494             baseAngle = NULL;
   1495         }
   1496 #if DEBUG_SORT
   1497         SkASSERT(!baseAngle || baseAngle->loopCount() > 1);
   1498 #endif
   1499     } while (!span->final() && (span = span->upCast()->next()));
   1500 }
   1501 
   1502 // return true if midpoints were computed
   1503 bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
   1504         SkOpCurve* edge) const {
   1505     SkASSERT(start != end);
   1506     const SkOpPtT& startPtT = *start->ptT();
   1507     const SkOpPtT& endPtT = *end->ptT();
   1508     SkDEBUGCODE(edge->fVerb = fVerb);
   1509     edge->fPts[0] = startPtT.fPt;
   1510     int points = SkPathOpsVerbToPoints(fVerb);
   1511     edge->fPts[points] = endPtT.fPt;
   1512     edge->fWeight = 1;
   1513     if (fVerb == SkPath::kLine_Verb) {
   1514         return false;
   1515     }
   1516     double startT = startPtT.fT;
   1517     double endT = endPtT.fT;
   1518     if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
   1519         // don't compute midpoints if we already have them
   1520         if (fVerb == SkPath::kQuad_Verb) {
   1521             edge->fPts[1] = fPts[1];
   1522             return false;
   1523         }
   1524         if (fVerb == SkPath::kConic_Verb) {
   1525             edge->fPts[1] = fPts[1];
   1526             edge->fWeight = fWeight;
   1527             return false;
   1528         }
   1529         SkASSERT(fVerb == SkPath::kCubic_Verb);
   1530         if (start < end) {
   1531             edge->fPts[1] = fPts[1];
   1532             edge->fPts[2] = fPts[2];
   1533             return false;
   1534         }
   1535         edge->fPts[1] = fPts[2];
   1536         edge->fPts[2] = fPts[1];
   1537         return false;
   1538     }
   1539     const SkDPoint sub[2] = {{ edge->fPts[0].fX, edge->fPts[0].fY},
   1540             {edge->fPts[points].fX, edge->fPts[points].fY }};
   1541     if (fVerb == SkPath::kQuad_Verb) {
   1542         edge->fPts[1] = SkDQuad::SubDivide(fPts, sub[0], sub[1], startT, endT).asSkPoint();
   1543     } else if (fVerb == SkPath::kConic_Verb) {
   1544         edge->fPts[1] = SkDConic::SubDivide(fPts, fWeight, sub[0], sub[1],
   1545                 startT, endT, &edge->fWeight).asSkPoint();
   1546     } else {
   1547         SkASSERT(fVerb == SkPath::kCubic_Verb);
   1548         SkDPoint ctrl[2];
   1549         SkDCubic::SubDivide(fPts, sub[0], sub[1], startT, endT, ctrl);
   1550         edge->fPts[1] = ctrl[0].asSkPoint();
   1551         edge->fPts[2] = ctrl[1].asSkPoint();
   1552     }
   1553     return true;
   1554 }
   1555 
   1556 bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
   1557         SkDCurve* edge) const {
   1558     SkASSERT(start != end);
   1559     const SkOpPtT& startPtT = *start->ptT();
   1560     const SkOpPtT& endPtT = *end->ptT();
   1561     SkDEBUGCODE(edge->fVerb = fVerb);
   1562     edge->fCubic[0].set(startPtT.fPt);
   1563     int points = SkPathOpsVerbToPoints(fVerb);
   1564     edge->fCubic[points].set(endPtT.fPt);
   1565     if (fVerb == SkPath::kLine_Verb) {
   1566         return false;
   1567     }
   1568     double startT = startPtT.fT;
   1569     double endT = endPtT.fT;
   1570     if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
   1571         // don't compute midpoints if we already have them
   1572         if (fVerb == SkPath::kQuad_Verb) {
   1573             edge->fLine[1].set(fPts[1]);
   1574             return false;
   1575         }
   1576         if (fVerb == SkPath::kConic_Verb) {
   1577             edge->fConic[1].set(fPts[1]);
   1578             edge->fConic.fWeight = fWeight;
   1579             return false;
   1580         }
   1581         SkASSERT(fVerb == SkPath::kCubic_Verb);
   1582         if (startT == 0) {
   1583             edge->fCubic[1].set(fPts[1]);
   1584             edge->fCubic[2].set(fPts[2]);
   1585             return false;
   1586         }
   1587         edge->fCubic[1].set(fPts[2]);
   1588         edge->fCubic[2].set(fPts[1]);
   1589         return false;
   1590     }
   1591     if (fVerb == SkPath::kQuad_Verb) {
   1592         edge->fQuad[1] = SkDQuad::SubDivide(fPts, edge->fQuad[0], edge->fQuad[2], startT, endT);
   1593     } else if (fVerb == SkPath::kConic_Verb) {
   1594         edge->fConic[1] = SkDConic::SubDivide(fPts, fWeight, edge->fQuad[0], edge->fQuad[2],
   1595             startT, endT, &edge->fConic.fWeight);
   1596     } else {
   1597         SkASSERT(fVerb == SkPath::kCubic_Verb);
   1598         SkDCubic::SubDivide(fPts, edge->fCubic[0], edge->fCubic[3], startT, endT, &edge->fCubic[1]);
   1599     }
   1600     return true;
   1601 }
   1602 
   1603 void SkOpSegment::undoneSpan(SkOpSpanBase** start, SkOpSpanBase** end) {
   1604     SkOpSpan* span = this->head();
   1605     do {
   1606         if (!span->done()) {
   1607             break;
   1608         }
   1609     } while ((span = span->next()->upCastable()));
   1610     SkASSERT(span);
   1611     *start = span;
   1612     *end = span->next();
   1613 }
   1614 
   1615 int SkOpSegment::updateOppWinding(const SkOpSpanBase* start, const SkOpSpanBase* end) const {
   1616     const SkOpSpan* lesser = start->starter(end);
   1617     int oppWinding = lesser->oppSum();
   1618     int oppSpanWinding = SkOpSegment::OppSign(start, end);
   1619     if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWinding)
   1620             && oppWinding != SK_MaxS32) {
   1621         oppWinding -= oppSpanWinding;
   1622     }
   1623     return oppWinding;
   1624 }
   1625 
   1626 int SkOpSegment::updateOppWinding(const SkOpAngle* angle) const {
   1627     const SkOpSpanBase* startSpan = angle->start();
   1628     const SkOpSpanBase* endSpan = angle->end();
   1629     return updateOppWinding(endSpan, startSpan);
   1630 }
   1631 
   1632 int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const {
   1633     const SkOpSpanBase* startSpan = angle->start();
   1634     const SkOpSpanBase* endSpan = angle->end();
   1635     return updateOppWinding(startSpan, endSpan);
   1636 }
   1637 
   1638 int SkOpSegment::updateWinding(SkOpSpanBase* start, SkOpSpanBase* end) {
   1639     SkOpSpan* lesser = start->starter(end);
   1640     int winding = lesser->windSum();
   1641     if (winding == SK_MinS32) {
   1642         winding = lesser->computeWindSum();
   1643     }
   1644     if (winding == SK_MinS32) {
   1645         return winding;
   1646     }
   1647     int spanWinding = SkOpSegment::SpanSign(start, end);
   1648     if (winding && UseInnerWinding(winding - spanWinding, winding)
   1649             && winding != SK_MaxS32) {
   1650         winding -= spanWinding;
   1651     }
   1652     return winding;
   1653 }
   1654 
   1655 int SkOpSegment::updateWinding(SkOpAngle* angle) {
   1656     SkOpSpanBase* startSpan = angle->start();
   1657     SkOpSpanBase* endSpan = angle->end();
   1658     return updateWinding(endSpan, startSpan);
   1659 }
   1660 
   1661 int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) {
   1662     SkOpSpanBase* startSpan = angle->start();
   1663     SkOpSpanBase* endSpan = angle->end();
   1664     return updateWinding(startSpan, endSpan);
   1665 }
   1666 
   1667 // OPTIMIZATION: does the following also work, and is it any faster?
   1668 // return outerWinding * innerWinding > 0
   1669 //      || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
   1670 bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) {
   1671     SkASSERT(outerWinding != SK_MaxS32);
   1672     SkASSERT(innerWinding != SK_MaxS32);
   1673     int absOut = abs(outerWinding);
   1674     int absIn = abs(innerWinding);
   1675     bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
   1676     return result;
   1677 }
   1678 
   1679 int SkOpSegment::windSum(const SkOpAngle* angle) const {
   1680     const SkOpSpan* minSpan = angle->start()->starter(angle->end());
   1681     return minSpan->windSum();
   1682 }
   1683