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