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