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