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