1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2015 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/pathops/SkOpCoincidence.h"
8cb93a386Sopenharmony_ci#include "src/pathops/SkOpSegment.h"
9cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsTSect.h"
10cb93a386Sopenharmony_ci
11cb93a386Sopenharmony_ci#include <utility>
12cb93a386Sopenharmony_ci
13cb93a386Sopenharmony_ci// returns true if coincident span's start and end are the same
14cb93a386Sopenharmony_cibool SkCoincidentSpans::collapsed(const SkOpPtT* test) const {
15cb93a386Sopenharmony_ci    return (fCoinPtTStart == test && fCoinPtTEnd->contains(test))
16cb93a386Sopenharmony_ci        || (fCoinPtTEnd == test && fCoinPtTStart->contains(test))
17cb93a386Sopenharmony_ci        || (fOppPtTStart == test && fOppPtTEnd->contains(test))
18cb93a386Sopenharmony_ci        || (fOppPtTEnd == test && fOppPtTStart->contains(test));
19cb93a386Sopenharmony_ci}
20cb93a386Sopenharmony_ci
21cb93a386Sopenharmony_ci// out of line since this function is referenced by address
22cb93a386Sopenharmony_ciconst SkOpPtT* SkCoincidentSpans::coinPtTEnd() const {
23cb93a386Sopenharmony_ci    return fCoinPtTEnd;
24cb93a386Sopenharmony_ci}
25cb93a386Sopenharmony_ci
26cb93a386Sopenharmony_ci// out of line since this function is referenced by address
27cb93a386Sopenharmony_ciconst SkOpPtT* SkCoincidentSpans::coinPtTStart() const {
28cb93a386Sopenharmony_ci    return fCoinPtTStart;
29cb93a386Sopenharmony_ci}
30cb93a386Sopenharmony_ci
31cb93a386Sopenharmony_ci// sets the span's end to the ptT referenced by the previous-next
32cb93a386Sopenharmony_civoid SkCoincidentSpans::correctOneEnd(
33cb93a386Sopenharmony_ci        const SkOpPtT* (SkCoincidentSpans::* getEnd)() const,
34cb93a386Sopenharmony_ci        void (SkCoincidentSpans::*setEnd)(const SkOpPtT* ptT) ) {
35cb93a386Sopenharmony_ci    const SkOpPtT* origPtT = (this->*getEnd)();
36cb93a386Sopenharmony_ci    const SkOpSpanBase* origSpan = origPtT->span();
37cb93a386Sopenharmony_ci    const SkOpSpan* prev = origSpan->prev();
38cb93a386Sopenharmony_ci    const SkOpPtT* testPtT = prev ? prev->next()->ptT()
39cb93a386Sopenharmony_ci            : origSpan->upCast()->next()->prev()->ptT();
40cb93a386Sopenharmony_ci    if (origPtT != testPtT) {
41cb93a386Sopenharmony_ci        (this->*setEnd)(testPtT);
42cb93a386Sopenharmony_ci    }
43cb93a386Sopenharmony_ci}
44cb93a386Sopenharmony_ci
45cb93a386Sopenharmony_ci/* Please keep this in sync with debugCorrectEnds */
46cb93a386Sopenharmony_ci// FIXME: member pointers have fallen out of favor and can be replaced with
47cb93a386Sopenharmony_ci// an alternative approach.
48cb93a386Sopenharmony_ci// makes all span ends agree with the segment's spans that define them
49cb93a386Sopenharmony_civoid SkCoincidentSpans::correctEnds() {
50cb93a386Sopenharmony_ci    this->correctOneEnd(&SkCoincidentSpans::coinPtTStart, &SkCoincidentSpans::setCoinPtTStart);
51cb93a386Sopenharmony_ci    this->correctOneEnd(&SkCoincidentSpans::coinPtTEnd, &SkCoincidentSpans::setCoinPtTEnd);
52cb93a386Sopenharmony_ci    this->correctOneEnd(&SkCoincidentSpans::oppPtTStart, &SkCoincidentSpans::setOppPtTStart);
53cb93a386Sopenharmony_ci    this->correctOneEnd(&SkCoincidentSpans::oppPtTEnd, &SkCoincidentSpans::setOppPtTEnd);
54cb93a386Sopenharmony_ci}
55cb93a386Sopenharmony_ci
56cb93a386Sopenharmony_ci/* Please keep this in sync with debugExpand */
57cb93a386Sopenharmony_ci// expand the range by checking adjacent spans for coincidence
58cb93a386Sopenharmony_cibool SkCoincidentSpans::expand() {
59cb93a386Sopenharmony_ci    bool expanded = false;
60cb93a386Sopenharmony_ci    const SkOpSegment* segment = coinPtTStart()->segment();
61cb93a386Sopenharmony_ci    const SkOpSegment* oppSegment = oppPtTStart()->segment();
62cb93a386Sopenharmony_ci    do {
63cb93a386Sopenharmony_ci        const SkOpSpan* start = coinPtTStart()->span()->upCast();
64cb93a386Sopenharmony_ci        const SkOpSpan* prev = start->prev();
65cb93a386Sopenharmony_ci        const SkOpPtT* oppPtT;
66cb93a386Sopenharmony_ci        if (!prev || !(oppPtT = prev->contains(oppSegment))) {
67cb93a386Sopenharmony_ci            break;
68cb93a386Sopenharmony_ci        }
69cb93a386Sopenharmony_ci        double midT = (prev->t() + start->t()) / 2;
70cb93a386Sopenharmony_ci        if (!segment->isClose(midT, oppSegment)) {
71cb93a386Sopenharmony_ci            break;
72cb93a386Sopenharmony_ci        }
73cb93a386Sopenharmony_ci        setStarts(prev->ptT(), oppPtT);
74cb93a386Sopenharmony_ci        expanded = true;
75cb93a386Sopenharmony_ci    } while (true);
76cb93a386Sopenharmony_ci    do {
77cb93a386Sopenharmony_ci        const SkOpSpanBase* end = coinPtTEnd()->span();
78cb93a386Sopenharmony_ci        SkOpSpanBase* next = end->final() ? nullptr : end->upCast()->next();
79cb93a386Sopenharmony_ci        if (next && next->deleted()) {
80cb93a386Sopenharmony_ci            break;
81cb93a386Sopenharmony_ci        }
82cb93a386Sopenharmony_ci        const SkOpPtT* oppPtT;
83cb93a386Sopenharmony_ci        if (!next || !(oppPtT = next->contains(oppSegment))) {
84cb93a386Sopenharmony_ci            break;
85cb93a386Sopenharmony_ci        }
86cb93a386Sopenharmony_ci        double midT = (end->t() + next->t()) / 2;
87cb93a386Sopenharmony_ci        if (!segment->isClose(midT, oppSegment)) {
88cb93a386Sopenharmony_ci            break;
89cb93a386Sopenharmony_ci        }
90cb93a386Sopenharmony_ci        setEnds(next->ptT(), oppPtT);
91cb93a386Sopenharmony_ci        expanded = true;
92cb93a386Sopenharmony_ci    } while (true);
93cb93a386Sopenharmony_ci    return expanded;
94cb93a386Sopenharmony_ci}
95cb93a386Sopenharmony_ci
96cb93a386Sopenharmony_ci// increase the range of this span
97cb93a386Sopenharmony_cibool SkCoincidentSpans::extend(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd,
98cb93a386Sopenharmony_ci        const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) {
99cb93a386Sopenharmony_ci    bool result = false;
100cb93a386Sopenharmony_ci    if (fCoinPtTStart->fT > coinPtTStart->fT || (this->flipped()
101cb93a386Sopenharmony_ci            ? fOppPtTStart->fT < oppPtTStart->fT : fOppPtTStart->fT > oppPtTStart->fT)) {
102cb93a386Sopenharmony_ci        this->setStarts(coinPtTStart, oppPtTStart);
103cb93a386Sopenharmony_ci        result = true;
104cb93a386Sopenharmony_ci    }
105cb93a386Sopenharmony_ci    if (fCoinPtTEnd->fT < coinPtTEnd->fT || (this->flipped()
106cb93a386Sopenharmony_ci            ? fOppPtTEnd->fT > oppPtTEnd->fT : fOppPtTEnd->fT < oppPtTEnd->fT)) {
107cb93a386Sopenharmony_ci        this->setEnds(coinPtTEnd, oppPtTEnd);
108cb93a386Sopenharmony_ci        result = true;
109cb93a386Sopenharmony_ci    }
110cb93a386Sopenharmony_ci    return result;
111cb93a386Sopenharmony_ci}
112cb93a386Sopenharmony_ci
113cb93a386Sopenharmony_ci// set the range of this span
114cb93a386Sopenharmony_civoid SkCoincidentSpans::set(SkCoincidentSpans* next, const SkOpPtT* coinPtTStart,
115cb93a386Sopenharmony_ci        const SkOpPtT* coinPtTEnd, const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) {
116cb93a386Sopenharmony_ci    SkASSERT(SkOpCoincidence::Ordered(coinPtTStart, oppPtTStart));
117cb93a386Sopenharmony_ci    fNext = next;
118cb93a386Sopenharmony_ci    this->setStarts(coinPtTStart, oppPtTStart);
119cb93a386Sopenharmony_ci    this->setEnds(coinPtTEnd, oppPtTEnd);
120cb93a386Sopenharmony_ci}
121cb93a386Sopenharmony_ci
122cb93a386Sopenharmony_ci// returns true if both points are inside this
123cb93a386Sopenharmony_cibool SkCoincidentSpans::contains(const SkOpPtT* s, const SkOpPtT* e) const {
124cb93a386Sopenharmony_ci    if (s->fT > e->fT) {
125cb93a386Sopenharmony_ci        using std::swap;
126cb93a386Sopenharmony_ci        swap(s, e);
127cb93a386Sopenharmony_ci    }
128cb93a386Sopenharmony_ci    if (s->segment() == fCoinPtTStart->segment()) {
129cb93a386Sopenharmony_ci        return fCoinPtTStart->fT <= s->fT && e->fT <= fCoinPtTEnd->fT;
130cb93a386Sopenharmony_ci    } else {
131cb93a386Sopenharmony_ci        SkASSERT(s->segment() == fOppPtTStart->segment());
132cb93a386Sopenharmony_ci        double oppTs = fOppPtTStart->fT;
133cb93a386Sopenharmony_ci        double oppTe = fOppPtTEnd->fT;
134cb93a386Sopenharmony_ci        if (oppTs > oppTe) {
135cb93a386Sopenharmony_ci            using std::swap;
136cb93a386Sopenharmony_ci            swap(oppTs, oppTe);
137cb93a386Sopenharmony_ci        }
138cb93a386Sopenharmony_ci        return oppTs <= s->fT && e->fT <= oppTe;
139cb93a386Sopenharmony_ci    }
140cb93a386Sopenharmony_ci}
141cb93a386Sopenharmony_ci
142cb93a386Sopenharmony_ci// out of line since this function is referenced by address
143cb93a386Sopenharmony_ciconst SkOpPtT* SkCoincidentSpans::oppPtTStart() const {
144cb93a386Sopenharmony_ci    return fOppPtTStart;
145cb93a386Sopenharmony_ci}
146cb93a386Sopenharmony_ci
147cb93a386Sopenharmony_ci// out of line since this function is referenced by address
148cb93a386Sopenharmony_ciconst SkOpPtT* SkCoincidentSpans::oppPtTEnd() const {
149cb93a386Sopenharmony_ci    return fOppPtTEnd;
150cb93a386Sopenharmony_ci}
151cb93a386Sopenharmony_ci
152cb93a386Sopenharmony_ci// A coincident span is unordered if the pairs of points in the main and opposite curves'
153cb93a386Sopenharmony_ci// t values do not ascend or descend. For instance, if a tightly arced quadratic is
154cb93a386Sopenharmony_ci// coincident with another curve, it may intersect it out of order.
155cb93a386Sopenharmony_cibool SkCoincidentSpans::ordered(bool* result) const {
156cb93a386Sopenharmony_ci    const SkOpSpanBase* start = this->coinPtTStart()->span();
157cb93a386Sopenharmony_ci    const SkOpSpanBase* end = this->coinPtTEnd()->span();
158cb93a386Sopenharmony_ci    const SkOpSpanBase* next = start->upCast()->next();
159cb93a386Sopenharmony_ci    if (next == end) {
160cb93a386Sopenharmony_ci        *result = true;
161cb93a386Sopenharmony_ci        return true;
162cb93a386Sopenharmony_ci    }
163cb93a386Sopenharmony_ci    bool flipped = this->flipped();
164cb93a386Sopenharmony_ci    const SkOpSegment* oppSeg = this->oppPtTStart()->segment();
165cb93a386Sopenharmony_ci    double oppLastT = fOppPtTStart->fT;
166cb93a386Sopenharmony_ci    do {
167cb93a386Sopenharmony_ci        const SkOpPtT* opp = next->contains(oppSeg);
168cb93a386Sopenharmony_ci        if (!opp) {
169cb93a386Sopenharmony_ci//            SkOPOBJASSERT(start, 0);  // may assert if coincident span isn't fully processed
170cb93a386Sopenharmony_ci            return false;
171cb93a386Sopenharmony_ci        }
172cb93a386Sopenharmony_ci        if ((oppLastT > opp->fT) != flipped) {
173cb93a386Sopenharmony_ci            *result = false;
174cb93a386Sopenharmony_ci            return true;
175cb93a386Sopenharmony_ci        }
176cb93a386Sopenharmony_ci        oppLastT = opp->fT;
177cb93a386Sopenharmony_ci        if (next == end) {
178cb93a386Sopenharmony_ci            break;
179cb93a386Sopenharmony_ci        }
180cb93a386Sopenharmony_ci        if (!next->upCastable()) {
181cb93a386Sopenharmony_ci            *result = false;
182cb93a386Sopenharmony_ci            return true;
183cb93a386Sopenharmony_ci        }
184cb93a386Sopenharmony_ci        next = next->upCast()->next();
185cb93a386Sopenharmony_ci    } while (true);
186cb93a386Sopenharmony_ci    *result = true;
187cb93a386Sopenharmony_ci    return true;
188cb93a386Sopenharmony_ci}
189cb93a386Sopenharmony_ci
190cb93a386Sopenharmony_ci// if there is an existing pair that overlaps the addition, extend it
191cb93a386Sopenharmony_cibool SkOpCoincidence::extend(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd,
192cb93a386Sopenharmony_ci        const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) {
193cb93a386Sopenharmony_ci    SkCoincidentSpans* test = fHead;
194cb93a386Sopenharmony_ci    if (!test) {
195cb93a386Sopenharmony_ci        return false;
196cb93a386Sopenharmony_ci    }
197cb93a386Sopenharmony_ci    const SkOpSegment* coinSeg = coinPtTStart->segment();
198cb93a386Sopenharmony_ci    const SkOpSegment* oppSeg = oppPtTStart->segment();
199cb93a386Sopenharmony_ci    if (!Ordered(coinPtTStart, oppPtTStart)) {
200cb93a386Sopenharmony_ci        using std::swap;
201cb93a386Sopenharmony_ci        swap(coinSeg, oppSeg);
202cb93a386Sopenharmony_ci        swap(coinPtTStart, oppPtTStart);
203cb93a386Sopenharmony_ci        swap(coinPtTEnd, oppPtTEnd);
204cb93a386Sopenharmony_ci        if (coinPtTStart->fT > coinPtTEnd->fT) {
205cb93a386Sopenharmony_ci            swap(coinPtTStart, coinPtTEnd);
206cb93a386Sopenharmony_ci            swap(oppPtTStart, oppPtTEnd);
207cb93a386Sopenharmony_ci        }
208cb93a386Sopenharmony_ci    }
209cb93a386Sopenharmony_ci    double oppMinT = std::min(oppPtTStart->fT, oppPtTEnd->fT);
210cb93a386Sopenharmony_ci    SkDEBUGCODE(double oppMaxT = std::max(oppPtTStart->fT, oppPtTEnd->fT));
211cb93a386Sopenharmony_ci    do {
212cb93a386Sopenharmony_ci        if (coinSeg != test->coinPtTStart()->segment()) {
213cb93a386Sopenharmony_ci            continue;
214cb93a386Sopenharmony_ci        }
215cb93a386Sopenharmony_ci        if (oppSeg != test->oppPtTStart()->segment()) {
216cb93a386Sopenharmony_ci            continue;
217cb93a386Sopenharmony_ci        }
218cb93a386Sopenharmony_ci        double oTestMinT = std::min(test->oppPtTStart()->fT, test->oppPtTEnd()->fT);
219cb93a386Sopenharmony_ci        double oTestMaxT = std::max(test->oppPtTStart()->fT, test->oppPtTEnd()->fT);
220cb93a386Sopenharmony_ci        // if debug check triggers, caller failed to check if extended already exists
221cb93a386Sopenharmony_ci        SkASSERT(test->coinPtTStart()->fT > coinPtTStart->fT
222cb93a386Sopenharmony_ci                || coinPtTEnd->fT > test->coinPtTEnd()->fT
223cb93a386Sopenharmony_ci                || oTestMinT > oppMinT || oppMaxT > oTestMaxT);
224cb93a386Sopenharmony_ci        if ((test->coinPtTStart()->fT <= coinPtTEnd->fT
225cb93a386Sopenharmony_ci                && coinPtTStart->fT <= test->coinPtTEnd()->fT)
226cb93a386Sopenharmony_ci                || (oTestMinT <= oTestMaxT && oppMinT <= oTestMaxT)) {
227cb93a386Sopenharmony_ci            test->extend(coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd);
228cb93a386Sopenharmony_ci            return true;
229cb93a386Sopenharmony_ci        }
230cb93a386Sopenharmony_ci    } while ((test = test->next()));
231cb93a386Sopenharmony_ci    return false;
232cb93a386Sopenharmony_ci}
233cb93a386Sopenharmony_ci
234cb93a386Sopenharmony_ci// verifies that the coincidence hasn't already been added
235cb93a386Sopenharmony_cistatic void DebugCheckAdd(const SkCoincidentSpans* check, const SkOpPtT* coinPtTStart,
236cb93a386Sopenharmony_ci        const SkOpPtT* coinPtTEnd, const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) {
237cb93a386Sopenharmony_ci#if DEBUG_COINCIDENCE
238cb93a386Sopenharmony_ci    while (check) {
239cb93a386Sopenharmony_ci        SkASSERT(check->coinPtTStart() != coinPtTStart || check->coinPtTEnd() != coinPtTEnd
240cb93a386Sopenharmony_ci                || check->oppPtTStart() != oppPtTStart || check->oppPtTEnd() != oppPtTEnd);
241cb93a386Sopenharmony_ci        SkASSERT(check->coinPtTStart() != oppPtTStart || check->coinPtTEnd() != oppPtTEnd
242cb93a386Sopenharmony_ci                || check->oppPtTStart() != coinPtTStart || check->oppPtTEnd() != coinPtTEnd);
243cb93a386Sopenharmony_ci        check = check->next();
244cb93a386Sopenharmony_ci    }
245cb93a386Sopenharmony_ci#endif
246cb93a386Sopenharmony_ci}
247cb93a386Sopenharmony_ci
248cb93a386Sopenharmony_ci// adds a new coincident pair
249cb93a386Sopenharmony_civoid SkOpCoincidence::add(SkOpPtT* coinPtTStart, SkOpPtT* coinPtTEnd, SkOpPtT* oppPtTStart,
250cb93a386Sopenharmony_ci        SkOpPtT* oppPtTEnd) {
251cb93a386Sopenharmony_ci    // OPTIMIZE: caller should have already sorted
252cb93a386Sopenharmony_ci    if (!Ordered(coinPtTStart, oppPtTStart)) {
253cb93a386Sopenharmony_ci        if (oppPtTStart->fT < oppPtTEnd->fT) {
254cb93a386Sopenharmony_ci            this->add(oppPtTStart, oppPtTEnd, coinPtTStart, coinPtTEnd);
255cb93a386Sopenharmony_ci        } else {
256cb93a386Sopenharmony_ci            this->add(oppPtTEnd, oppPtTStart, coinPtTEnd, coinPtTStart);
257cb93a386Sopenharmony_ci        }
258cb93a386Sopenharmony_ci        return;
259cb93a386Sopenharmony_ci    }
260cb93a386Sopenharmony_ci    SkASSERT(Ordered(coinPtTStart, oppPtTStart));
261cb93a386Sopenharmony_ci    // choose the ptT at the front of the list to track
262cb93a386Sopenharmony_ci    coinPtTStart = coinPtTStart->span()->ptT();
263cb93a386Sopenharmony_ci    coinPtTEnd = coinPtTEnd->span()->ptT();
264cb93a386Sopenharmony_ci    oppPtTStart = oppPtTStart->span()->ptT();
265cb93a386Sopenharmony_ci    oppPtTEnd = oppPtTEnd->span()->ptT();
266cb93a386Sopenharmony_ci    SkOPASSERT(coinPtTStart->fT < coinPtTEnd->fT);
267cb93a386Sopenharmony_ci    SkOPASSERT(oppPtTStart->fT != oppPtTEnd->fT);
268cb93a386Sopenharmony_ci    SkOPASSERT(!coinPtTStart->deleted());
269cb93a386Sopenharmony_ci    SkOPASSERT(!coinPtTEnd->deleted());
270cb93a386Sopenharmony_ci    SkOPASSERT(!oppPtTStart->deleted());
271cb93a386Sopenharmony_ci    SkOPASSERT(!oppPtTEnd->deleted());
272cb93a386Sopenharmony_ci    DebugCheckAdd(fHead, coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd);
273cb93a386Sopenharmony_ci    DebugCheckAdd(fTop, coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd);
274cb93a386Sopenharmony_ci    SkCoincidentSpans* coinRec = this->globalState()->allocator()->make<SkCoincidentSpans>();
275cb93a386Sopenharmony_ci    coinRec->init(SkDEBUGCODE(fGlobalState));
276cb93a386Sopenharmony_ci    coinRec->set(this->fHead, coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd);
277cb93a386Sopenharmony_ci    fHead = coinRec;
278cb93a386Sopenharmony_ci}
279cb93a386Sopenharmony_ci
280cb93a386Sopenharmony_ci// description below
281cb93a386Sopenharmony_cibool SkOpCoincidence::addEndMovedSpans(const SkOpSpan* base, const SkOpSpanBase* testSpan) {
282cb93a386Sopenharmony_ci    const SkOpPtT* testPtT = testSpan->ptT();
283cb93a386Sopenharmony_ci    const SkOpPtT* stopPtT = testPtT;
284cb93a386Sopenharmony_ci    const SkOpSegment* baseSeg = base->segment();
285cb93a386Sopenharmony_ci    int escapeHatch = 100000;  // this is 100 times larger than the debugLoopLimit test
286cb93a386Sopenharmony_ci    while ((testPtT = testPtT->next()) != stopPtT) {
287cb93a386Sopenharmony_ci        if (--escapeHatch <= 0) {
288cb93a386Sopenharmony_ci            return false;  // if triggered (likely by a fuzz-generated test) too complex to succeed
289cb93a386Sopenharmony_ci        }
290cb93a386Sopenharmony_ci        const SkOpSegment* testSeg = testPtT->segment();
291cb93a386Sopenharmony_ci        if (testPtT->deleted()) {
292cb93a386Sopenharmony_ci            continue;
293cb93a386Sopenharmony_ci        }
294cb93a386Sopenharmony_ci        if (testSeg == baseSeg) {
295cb93a386Sopenharmony_ci            continue;
296cb93a386Sopenharmony_ci        }
297cb93a386Sopenharmony_ci        if (testPtT->span()->ptT() != testPtT) {
298cb93a386Sopenharmony_ci            continue;
299cb93a386Sopenharmony_ci        }
300cb93a386Sopenharmony_ci        if (this->contains(baseSeg, testSeg, testPtT->fT)) {
301cb93a386Sopenharmony_ci            continue;
302cb93a386Sopenharmony_ci        }
303cb93a386Sopenharmony_ci        // intersect perp with base->ptT() with testPtT->segment()
304cb93a386Sopenharmony_ci        SkDVector dxdy = baseSeg->dSlopeAtT(base->t());
305cb93a386Sopenharmony_ci        const SkPoint& pt = base->pt();
306cb93a386Sopenharmony_ci        SkDLine ray = {{{pt.fX, pt.fY}, {pt.fX + dxdy.fY, pt.fY - dxdy.fX}}};
307cb93a386Sopenharmony_ci        SkIntersections i  SkDEBUGCODE((this->globalState()));
308cb93a386Sopenharmony_ci        (*CurveIntersectRay[testSeg->verb()])(testSeg->pts(), testSeg->weight(), ray, &i);
309cb93a386Sopenharmony_ci        for (int index = 0; index < i.used(); ++index) {
310cb93a386Sopenharmony_ci            double t = i[0][index];
311cb93a386Sopenharmony_ci            if (!between(0, t, 1)) {
312cb93a386Sopenharmony_ci                continue;
313cb93a386Sopenharmony_ci            }
314cb93a386Sopenharmony_ci            SkDPoint oppPt = i.pt(index);
315cb93a386Sopenharmony_ci            if (!oppPt.approximatelyEqual(pt)) {
316cb93a386Sopenharmony_ci                continue;
317cb93a386Sopenharmony_ci            }
318cb93a386Sopenharmony_ci            SkOpSegment* writableSeg = const_cast<SkOpSegment*>(testSeg);
319cb93a386Sopenharmony_ci            SkOpPtT* oppStart = writableSeg->addT(t);
320cb93a386Sopenharmony_ci            if (oppStart == testPtT) {
321cb93a386Sopenharmony_ci                continue;
322cb93a386Sopenharmony_ci            }
323cb93a386Sopenharmony_ci            SkOpSpan* writableBase = const_cast<SkOpSpan*>(base);
324cb93a386Sopenharmony_ci            oppStart->span()->addOpp(writableBase);
325cb93a386Sopenharmony_ci            if (oppStart->deleted()) {
326cb93a386Sopenharmony_ci                continue;
327cb93a386Sopenharmony_ci            }
328cb93a386Sopenharmony_ci            SkOpSegment* coinSeg = base->segment();
329cb93a386Sopenharmony_ci            SkOpSegment* oppSeg = oppStart->segment();
330cb93a386Sopenharmony_ci            double coinTs, coinTe, oppTs, oppTe;
331cb93a386Sopenharmony_ci            if (Ordered(coinSeg, oppSeg)) {
332cb93a386Sopenharmony_ci                coinTs = base->t();
333cb93a386Sopenharmony_ci                coinTe = testSpan->t();
334cb93a386Sopenharmony_ci                oppTs = oppStart->fT;
335cb93a386Sopenharmony_ci                oppTe = testPtT->fT;
336cb93a386Sopenharmony_ci            } else {
337cb93a386Sopenharmony_ci                using std::swap;
338cb93a386Sopenharmony_ci                swap(coinSeg, oppSeg);
339cb93a386Sopenharmony_ci                coinTs = oppStart->fT;
340cb93a386Sopenharmony_ci                coinTe = testPtT->fT;
341cb93a386Sopenharmony_ci                oppTs = base->t();
342cb93a386Sopenharmony_ci                oppTe = testSpan->t();
343cb93a386Sopenharmony_ci            }
344cb93a386Sopenharmony_ci            if (coinTs > coinTe) {
345cb93a386Sopenharmony_ci                using std::swap;
346cb93a386Sopenharmony_ci                swap(coinTs, coinTe);
347cb93a386Sopenharmony_ci                swap(oppTs, oppTe);
348cb93a386Sopenharmony_ci            }
349cb93a386Sopenharmony_ci            bool added;
350cb93a386Sopenharmony_ci            FAIL_IF(!this->addOrOverlap(coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, &added));
351cb93a386Sopenharmony_ci        }
352cb93a386Sopenharmony_ci    }
353cb93a386Sopenharmony_ci    return true;
354cb93a386Sopenharmony_ci}
355cb93a386Sopenharmony_ci
356cb93a386Sopenharmony_ci// description below
357cb93a386Sopenharmony_cibool SkOpCoincidence::addEndMovedSpans(const SkOpPtT* ptT) {
358cb93a386Sopenharmony_ci    FAIL_IF(!ptT->span()->upCastable());
359cb93a386Sopenharmony_ci    const SkOpSpan* base = ptT->span()->upCast();
360cb93a386Sopenharmony_ci    const SkOpSpan* prev = base->prev();
361cb93a386Sopenharmony_ci    FAIL_IF(!prev);
362cb93a386Sopenharmony_ci    if (!prev->isCanceled()) {
363cb93a386Sopenharmony_ci        if (!this->addEndMovedSpans(base, base->prev())) {
364cb93a386Sopenharmony_ci            return false;
365cb93a386Sopenharmony_ci        }
366cb93a386Sopenharmony_ci    }
367cb93a386Sopenharmony_ci    if (!base->isCanceled()) {
368cb93a386Sopenharmony_ci        if (!this->addEndMovedSpans(base, base->next())) {
369cb93a386Sopenharmony_ci            return false;
370cb93a386Sopenharmony_ci        }
371cb93a386Sopenharmony_ci    }
372cb93a386Sopenharmony_ci    return true;
373cb93a386Sopenharmony_ci}
374cb93a386Sopenharmony_ci
375cb93a386Sopenharmony_ci/*  If A is coincident with B and B includes an endpoint, and A's matching point
376cb93a386Sopenharmony_ci    is not the endpoint (i.e., there's an implied line connecting B-end and A)
377cb93a386Sopenharmony_ci    then assume that the same implied line may intersect another curve close to B.
378cb93a386Sopenharmony_ci    Since we only care about coincidence that was undetected, look at the
379cb93a386Sopenharmony_ci    ptT list on B-segment adjacent to the B-end/A ptT loop (not in the loop, but
380cb93a386Sopenharmony_ci    next door) and see if the A matching point is close enough to form another
381cb93a386Sopenharmony_ci    coincident pair. If so, check for a new coincident span between B-end/A ptT loop
382cb93a386Sopenharmony_ci    and the adjacent ptT loop.
383cb93a386Sopenharmony_ci*/
384cb93a386Sopenharmony_cibool SkOpCoincidence::addEndMovedSpans(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
385cb93a386Sopenharmony_ci    DEBUG_SET_PHASE();
386cb93a386Sopenharmony_ci    SkCoincidentSpans* span = fHead;
387cb93a386Sopenharmony_ci    if (!span) {
388cb93a386Sopenharmony_ci        return true;
389cb93a386Sopenharmony_ci    }
390cb93a386Sopenharmony_ci    fTop = span;
391cb93a386Sopenharmony_ci    fHead = nullptr;
392cb93a386Sopenharmony_ci    do {
393cb93a386Sopenharmony_ci        if (span->coinPtTStart()->fPt != span->oppPtTStart()->fPt) {
394cb93a386Sopenharmony_ci            FAIL_IF(1 == span->coinPtTStart()->fT);
395cb93a386Sopenharmony_ci            bool onEnd = span->coinPtTStart()->fT == 0;
396cb93a386Sopenharmony_ci            bool oOnEnd = zero_or_one(span->oppPtTStart()->fT);
397cb93a386Sopenharmony_ci            if (onEnd) {
398cb93a386Sopenharmony_ci                if (!oOnEnd) {  // if both are on end, any nearby intersect was already found
399cb93a386Sopenharmony_ci                    if (!this->addEndMovedSpans(span->oppPtTStart())) {
400cb93a386Sopenharmony_ci                        return false;
401cb93a386Sopenharmony_ci                    }
402cb93a386Sopenharmony_ci                }
403cb93a386Sopenharmony_ci            } else if (oOnEnd) {
404cb93a386Sopenharmony_ci                if (!this->addEndMovedSpans(span->coinPtTStart())) {
405cb93a386Sopenharmony_ci                    return false;
406cb93a386Sopenharmony_ci                }
407cb93a386Sopenharmony_ci            }
408cb93a386Sopenharmony_ci        }
409cb93a386Sopenharmony_ci        if (span->coinPtTEnd()->fPt != span->oppPtTEnd()->fPt) {
410cb93a386Sopenharmony_ci            bool onEnd = span->coinPtTEnd()->fT == 1;
411cb93a386Sopenharmony_ci            bool oOnEnd = zero_or_one(span->oppPtTEnd()->fT);
412cb93a386Sopenharmony_ci            if (onEnd) {
413cb93a386Sopenharmony_ci                if (!oOnEnd) {
414cb93a386Sopenharmony_ci                    if (!this->addEndMovedSpans(span->oppPtTEnd())) {
415cb93a386Sopenharmony_ci                        return false;
416cb93a386Sopenharmony_ci                    }
417cb93a386Sopenharmony_ci                }
418cb93a386Sopenharmony_ci            } else if (oOnEnd) {
419cb93a386Sopenharmony_ci                if (!this->addEndMovedSpans(span->coinPtTEnd())) {
420cb93a386Sopenharmony_ci                    return false;
421cb93a386Sopenharmony_ci                }
422cb93a386Sopenharmony_ci            }
423cb93a386Sopenharmony_ci        }
424cb93a386Sopenharmony_ci    } while ((span = span->next()));
425cb93a386Sopenharmony_ci    this->restoreHead();
426cb93a386Sopenharmony_ci    return true;
427cb93a386Sopenharmony_ci}
428cb93a386Sopenharmony_ci
429cb93a386Sopenharmony_ci/* Please keep this in sync with debugAddExpanded */
430cb93a386Sopenharmony_ci// for each coincident pair, match the spans
431cb93a386Sopenharmony_ci// if the spans don't match, add the missing pt to the segment and loop it in the opposite span
432cb93a386Sopenharmony_cibool SkOpCoincidence::addExpanded(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
433cb93a386Sopenharmony_ci    DEBUG_SET_PHASE();
434cb93a386Sopenharmony_ci    SkCoincidentSpans* coin = this->fHead;
435cb93a386Sopenharmony_ci    if (!coin) {
436cb93a386Sopenharmony_ci        return true;
437cb93a386Sopenharmony_ci    }
438cb93a386Sopenharmony_ci    do {
439cb93a386Sopenharmony_ci        const SkOpPtT* startPtT = coin->coinPtTStart();
440cb93a386Sopenharmony_ci        const SkOpPtT* oStartPtT = coin->oppPtTStart();
441cb93a386Sopenharmony_ci        double priorT = startPtT->fT;
442cb93a386Sopenharmony_ci        double oPriorT = oStartPtT->fT;
443cb93a386Sopenharmony_ci        FAIL_IF(!startPtT->contains(oStartPtT));
444cb93a386Sopenharmony_ci        SkOPASSERT(coin->coinPtTEnd()->contains(coin->oppPtTEnd()));
445cb93a386Sopenharmony_ci        const SkOpSpanBase* start = startPtT->span();
446cb93a386Sopenharmony_ci        const SkOpSpanBase* oStart = oStartPtT->span();
447cb93a386Sopenharmony_ci        const SkOpSpanBase* end = coin->coinPtTEnd()->span();
448cb93a386Sopenharmony_ci        const SkOpSpanBase* oEnd = coin->oppPtTEnd()->span();
449cb93a386Sopenharmony_ci        FAIL_IF(oEnd->deleted());
450cb93a386Sopenharmony_ci        FAIL_IF(!start->upCastable());
451cb93a386Sopenharmony_ci        const SkOpSpanBase* test = start->upCast()->next();
452cb93a386Sopenharmony_ci        FAIL_IF(!coin->flipped() && !oStart->upCastable());
453cb93a386Sopenharmony_ci        const SkOpSpanBase* oTest = coin->flipped() ? oStart->prev() : oStart->upCast()->next();
454cb93a386Sopenharmony_ci        FAIL_IF(!oTest);
455cb93a386Sopenharmony_ci        SkOpSegment* seg = start->segment();
456cb93a386Sopenharmony_ci        SkOpSegment* oSeg = oStart->segment();
457cb93a386Sopenharmony_ci        while (test != end || oTest != oEnd) {
458cb93a386Sopenharmony_ci            const SkOpPtT* containedOpp = test->ptT()->contains(oSeg);
459cb93a386Sopenharmony_ci            const SkOpPtT* containedThis = oTest->ptT()->contains(seg);
460cb93a386Sopenharmony_ci            if (!containedOpp || !containedThis) {
461cb93a386Sopenharmony_ci                // choose the ends, or the first common pt-t list shared by both
462cb93a386Sopenharmony_ci                double nextT, oNextT;
463cb93a386Sopenharmony_ci                if (containedOpp) {
464cb93a386Sopenharmony_ci                    nextT = test->t();
465cb93a386Sopenharmony_ci                    oNextT = containedOpp->fT;
466cb93a386Sopenharmony_ci                } else if (containedThis) {
467cb93a386Sopenharmony_ci                    nextT = containedThis->fT;
468cb93a386Sopenharmony_ci                    oNextT = oTest->t();
469cb93a386Sopenharmony_ci                } else {
470cb93a386Sopenharmony_ci                    // iterate through until a pt-t list found that contains the other
471cb93a386Sopenharmony_ci                    const SkOpSpanBase* walk = test;
472cb93a386Sopenharmony_ci                    const SkOpPtT* walkOpp;
473cb93a386Sopenharmony_ci                    do {
474cb93a386Sopenharmony_ci                        FAIL_IF(!walk->upCastable());
475cb93a386Sopenharmony_ci                        walk = walk->upCast()->next();
476cb93a386Sopenharmony_ci                    } while (!(walkOpp = walk->ptT()->contains(oSeg))
477cb93a386Sopenharmony_ci                            && walk != coin->coinPtTEnd()->span());
478cb93a386Sopenharmony_ci                    FAIL_IF(!walkOpp);
479cb93a386Sopenharmony_ci                    nextT = walk->t();
480cb93a386Sopenharmony_ci                    oNextT = walkOpp->fT;
481cb93a386Sopenharmony_ci                }
482cb93a386Sopenharmony_ci                // use t ranges to guess which one is missing
483cb93a386Sopenharmony_ci                double startRange = nextT - priorT;
484cb93a386Sopenharmony_ci                FAIL_IF(!startRange);
485cb93a386Sopenharmony_ci                double startPart = (test->t() - priorT) / startRange;
486cb93a386Sopenharmony_ci                double oStartRange = oNextT - oPriorT;
487cb93a386Sopenharmony_ci                FAIL_IF(!oStartRange);
488cb93a386Sopenharmony_ci                double oStartPart = (oTest->t() - oPriorT) / oStartRange;
489cb93a386Sopenharmony_ci                FAIL_IF(startPart == oStartPart);
490cb93a386Sopenharmony_ci                bool addToOpp = !containedOpp && !containedThis ? startPart < oStartPart
491cb93a386Sopenharmony_ci                        : !!containedThis;
492cb93a386Sopenharmony_ci                bool startOver = false;
493cb93a386Sopenharmony_ci                bool success = addToOpp ? oSeg->addExpanded(
494cb93a386Sopenharmony_ci                        oPriorT + oStartRange * startPart, test, &startOver)
495cb93a386Sopenharmony_ci                        : seg->addExpanded(
496cb93a386Sopenharmony_ci                        priorT + startRange * oStartPart, oTest, &startOver);
497cb93a386Sopenharmony_ci                FAIL_IF(!success);
498cb93a386Sopenharmony_ci                if (startOver) {
499cb93a386Sopenharmony_ci                    test = start;
500cb93a386Sopenharmony_ci                    oTest = oStart;
501cb93a386Sopenharmony_ci                }
502cb93a386Sopenharmony_ci                end = coin->coinPtTEnd()->span();
503cb93a386Sopenharmony_ci                oEnd = coin->oppPtTEnd()->span();
504cb93a386Sopenharmony_ci            }
505cb93a386Sopenharmony_ci            if (test != end) {
506cb93a386Sopenharmony_ci                FAIL_IF(!test->upCastable());
507cb93a386Sopenharmony_ci                priorT = test->t();
508cb93a386Sopenharmony_ci                test = test->upCast()->next();
509cb93a386Sopenharmony_ci            }
510cb93a386Sopenharmony_ci            if (oTest != oEnd) {
511cb93a386Sopenharmony_ci                oPriorT = oTest->t();
512cb93a386Sopenharmony_ci                if (coin->flipped()) {
513cb93a386Sopenharmony_ci                    oTest = oTest->prev();
514cb93a386Sopenharmony_ci                } else {
515cb93a386Sopenharmony_ci                    FAIL_IF(!oTest->upCastable());
516cb93a386Sopenharmony_ci                    oTest = oTest->upCast()->next();
517cb93a386Sopenharmony_ci                }
518cb93a386Sopenharmony_ci                FAIL_IF(!oTest);
519cb93a386Sopenharmony_ci            }
520cb93a386Sopenharmony_ci
521cb93a386Sopenharmony_ci        }
522cb93a386Sopenharmony_ci    } while ((coin = coin->next()));
523cb93a386Sopenharmony_ci    return true;
524cb93a386Sopenharmony_ci}
525cb93a386Sopenharmony_ci
526cb93a386Sopenharmony_ci// given a t span, map the same range on the coincident span
527cb93a386Sopenharmony_ci/*
528cb93a386Sopenharmony_cithe curves may not scale linearly, so interpolation may only happen within known points
529cb93a386Sopenharmony_ciremap over1s, over1e, cointPtTStart, coinPtTEnd to smallest range that captures over1s
530cb93a386Sopenharmony_cithen repeat to capture over1e
531cb93a386Sopenharmony_ci*/
532cb93a386Sopenharmony_cidouble SkOpCoincidence::TRange(const SkOpPtT* overS, double t,
533cb93a386Sopenharmony_ci       const SkOpSegment* coinSeg  SkDEBUGPARAMS(const SkOpPtT* overE)) {
534cb93a386Sopenharmony_ci    const SkOpSpanBase* work = overS->span();
535cb93a386Sopenharmony_ci    const SkOpPtT* foundStart = nullptr;
536cb93a386Sopenharmony_ci    const SkOpPtT* foundEnd = nullptr;
537cb93a386Sopenharmony_ci    const SkOpPtT* coinStart = nullptr;
538cb93a386Sopenharmony_ci    const SkOpPtT* coinEnd = nullptr;
539cb93a386Sopenharmony_ci    do {
540cb93a386Sopenharmony_ci        const SkOpPtT* contained = work->contains(coinSeg);
541cb93a386Sopenharmony_ci        if (!contained) {
542cb93a386Sopenharmony_ci            if (work->final()) {
543cb93a386Sopenharmony_ci                break;
544cb93a386Sopenharmony_ci            }
545cb93a386Sopenharmony_ci            continue;
546cb93a386Sopenharmony_ci        }
547cb93a386Sopenharmony_ci        if (work->t() <= t) {
548cb93a386Sopenharmony_ci            coinStart = contained;
549cb93a386Sopenharmony_ci            foundStart = work->ptT();
550cb93a386Sopenharmony_ci        }
551cb93a386Sopenharmony_ci        if (work->t() >= t) {
552cb93a386Sopenharmony_ci            coinEnd = contained;
553cb93a386Sopenharmony_ci            foundEnd = work->ptT();
554cb93a386Sopenharmony_ci            break;
555cb93a386Sopenharmony_ci        }
556cb93a386Sopenharmony_ci        SkASSERT(work->ptT() != overE);
557cb93a386Sopenharmony_ci    } while ((work = work->upCast()->next()));
558cb93a386Sopenharmony_ci    if (!coinStart || !coinEnd) {
559cb93a386Sopenharmony_ci        return 1;
560cb93a386Sopenharmony_ci    }
561cb93a386Sopenharmony_ci    // while overS->fT <=t and overS contains coinSeg
562cb93a386Sopenharmony_ci    double denom = foundEnd->fT - foundStart->fT;
563cb93a386Sopenharmony_ci    double sRatio = denom ? (t - foundStart->fT) / denom : 1;
564cb93a386Sopenharmony_ci    return coinStart->fT + (coinEnd->fT - coinStart->fT) * sRatio;
565cb93a386Sopenharmony_ci}
566cb93a386Sopenharmony_ci
567cb93a386Sopenharmony_ci// return true if span overlaps existing and needs to adjust the coincident list
568cb93a386Sopenharmony_cibool SkOpCoincidence::checkOverlap(SkCoincidentSpans* check,
569cb93a386Sopenharmony_ci        const SkOpSegment* coinSeg, const SkOpSegment* oppSeg,
570cb93a386Sopenharmony_ci        double coinTs, double coinTe, double oppTs, double oppTe,
571cb93a386Sopenharmony_ci        SkTDArray<SkCoincidentSpans*>* overlaps) const {
572cb93a386Sopenharmony_ci    if (!Ordered(coinSeg, oppSeg)) {
573cb93a386Sopenharmony_ci        if (oppTs < oppTe) {
574cb93a386Sopenharmony_ci            return this->checkOverlap(check, oppSeg, coinSeg, oppTs, oppTe, coinTs, coinTe,
575cb93a386Sopenharmony_ci                    overlaps);
576cb93a386Sopenharmony_ci        }
577cb93a386Sopenharmony_ci        return this->checkOverlap(check, oppSeg, coinSeg, oppTe, oppTs, coinTe, coinTs, overlaps);
578cb93a386Sopenharmony_ci    }
579cb93a386Sopenharmony_ci    bool swapOpp = oppTs > oppTe;
580cb93a386Sopenharmony_ci    if (swapOpp) {
581cb93a386Sopenharmony_ci        using std::swap;
582cb93a386Sopenharmony_ci        swap(oppTs, oppTe);
583cb93a386Sopenharmony_ci    }
584cb93a386Sopenharmony_ci    do {
585cb93a386Sopenharmony_ci        if (check->coinPtTStart()->segment() != coinSeg) {
586cb93a386Sopenharmony_ci            continue;
587cb93a386Sopenharmony_ci        }
588cb93a386Sopenharmony_ci        if (check->oppPtTStart()->segment() != oppSeg) {
589cb93a386Sopenharmony_ci            continue;
590cb93a386Sopenharmony_ci        }
591cb93a386Sopenharmony_ci        double checkTs = check->coinPtTStart()->fT;
592cb93a386Sopenharmony_ci        double checkTe = check->coinPtTEnd()->fT;
593cb93a386Sopenharmony_ci        bool coinOutside = coinTe < checkTs || coinTs > checkTe;
594cb93a386Sopenharmony_ci        double oCheckTs = check->oppPtTStart()->fT;
595cb93a386Sopenharmony_ci        double oCheckTe = check->oppPtTEnd()->fT;
596cb93a386Sopenharmony_ci        if (swapOpp) {
597cb93a386Sopenharmony_ci            if (oCheckTs <= oCheckTe) {
598cb93a386Sopenharmony_ci                return false;
599cb93a386Sopenharmony_ci            }
600cb93a386Sopenharmony_ci            using std::swap;
601cb93a386Sopenharmony_ci            swap(oCheckTs, oCheckTe);
602cb93a386Sopenharmony_ci        }
603cb93a386Sopenharmony_ci        bool oppOutside = oppTe < oCheckTs || oppTs > oCheckTe;
604cb93a386Sopenharmony_ci        if (coinOutside && oppOutside) {
605cb93a386Sopenharmony_ci            continue;
606cb93a386Sopenharmony_ci        }
607cb93a386Sopenharmony_ci        bool coinInside = coinTe <= checkTe && coinTs >= checkTs;
608cb93a386Sopenharmony_ci        bool oppInside = oppTe <= oCheckTe && oppTs >= oCheckTs;
609cb93a386Sopenharmony_ci        if (coinInside && oppInside) {  // already included, do nothing
610cb93a386Sopenharmony_ci            return false;
611cb93a386Sopenharmony_ci        }
612cb93a386Sopenharmony_ci        *overlaps->append() = check; // partial overlap, extend existing entry
613cb93a386Sopenharmony_ci    } while ((check = check->next()));
614cb93a386Sopenharmony_ci    return true;
615cb93a386Sopenharmony_ci}
616cb93a386Sopenharmony_ci
617cb93a386Sopenharmony_ci/* Please keep this in sync with debugAddIfMissing() */
618cb93a386Sopenharmony_ci// note that over1s, over1e, over2s, over2e are ordered
619cb93a386Sopenharmony_cibool SkOpCoincidence::addIfMissing(const SkOpPtT* over1s, const SkOpPtT* over2s,
620cb93a386Sopenharmony_ci        double tStart, double tEnd, SkOpSegment* coinSeg, SkOpSegment* oppSeg, bool* added
621cb93a386Sopenharmony_ci        SkDEBUGPARAMS(const SkOpPtT* over1e) SkDEBUGPARAMS(const SkOpPtT* over2e)) {
622cb93a386Sopenharmony_ci    SkASSERT(tStart < tEnd);
623cb93a386Sopenharmony_ci    SkASSERT(over1s->fT < over1e->fT);
624cb93a386Sopenharmony_ci    SkASSERT(between(over1s->fT, tStart, over1e->fT));
625cb93a386Sopenharmony_ci    SkASSERT(between(over1s->fT, tEnd, over1e->fT));
626cb93a386Sopenharmony_ci    SkASSERT(over2s->fT < over2e->fT);
627cb93a386Sopenharmony_ci    SkASSERT(between(over2s->fT, tStart, over2e->fT));
628cb93a386Sopenharmony_ci    SkASSERT(between(over2s->fT, tEnd, over2e->fT));
629cb93a386Sopenharmony_ci    SkASSERT(over1s->segment() == over1e->segment());
630cb93a386Sopenharmony_ci    SkASSERT(over2s->segment() == over2e->segment());
631cb93a386Sopenharmony_ci    SkASSERT(over1s->segment() == over2s->segment());
632cb93a386Sopenharmony_ci    SkASSERT(over1s->segment() != coinSeg);
633cb93a386Sopenharmony_ci    SkASSERT(over1s->segment() != oppSeg);
634cb93a386Sopenharmony_ci    SkASSERT(coinSeg != oppSeg);
635cb93a386Sopenharmony_ci    double coinTs, coinTe, oppTs, oppTe;
636cb93a386Sopenharmony_ci    coinTs = TRange(over1s, tStart, coinSeg  SkDEBUGPARAMS(over1e));
637cb93a386Sopenharmony_ci    coinTe = TRange(over1s, tEnd, coinSeg  SkDEBUGPARAMS(over1e));
638cb93a386Sopenharmony_ci    SkOpSpanBase::Collapsed result = coinSeg->collapsed(coinTs, coinTe);
639cb93a386Sopenharmony_ci    if (SkOpSpanBase::Collapsed::kNo != result) {
640cb93a386Sopenharmony_ci        return SkOpSpanBase::Collapsed::kYes == result;
641cb93a386Sopenharmony_ci    }
642cb93a386Sopenharmony_ci    oppTs = TRange(over2s, tStart, oppSeg  SkDEBUGPARAMS(over2e));
643cb93a386Sopenharmony_ci    oppTe = TRange(over2s, tEnd, oppSeg  SkDEBUGPARAMS(over2e));
644cb93a386Sopenharmony_ci    result = oppSeg->collapsed(oppTs, oppTe);
645cb93a386Sopenharmony_ci    if (SkOpSpanBase::Collapsed::kNo != result) {
646cb93a386Sopenharmony_ci        return SkOpSpanBase::Collapsed::kYes == result;
647cb93a386Sopenharmony_ci    }
648cb93a386Sopenharmony_ci    if (coinTs > coinTe) {
649cb93a386Sopenharmony_ci        using std::swap;
650cb93a386Sopenharmony_ci        swap(coinTs, coinTe);
651cb93a386Sopenharmony_ci        swap(oppTs, oppTe);
652cb93a386Sopenharmony_ci    }
653cb93a386Sopenharmony_ci    (void) this->addOrOverlap(coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, added);
654cb93a386Sopenharmony_ci    return true;
655cb93a386Sopenharmony_ci}
656cb93a386Sopenharmony_ci
657cb93a386Sopenharmony_ci/* Please keep this in sync with debugAddOrOverlap() */
658cb93a386Sopenharmony_ci// If this is called by addEndMovedSpans(), a returned false propogates out to an abort.
659cb93a386Sopenharmony_ci// If this is called by AddIfMissing(), a returned false indicates there was nothing to add
660cb93a386Sopenharmony_cibool SkOpCoincidence::addOrOverlap(SkOpSegment* coinSeg, SkOpSegment* oppSeg,
661cb93a386Sopenharmony_ci        double coinTs, double coinTe, double oppTs, double oppTe, bool* added) {
662cb93a386Sopenharmony_ci    SkTDArray<SkCoincidentSpans*> overlaps;
663cb93a386Sopenharmony_ci    FAIL_IF(!fTop);
664cb93a386Sopenharmony_ci    if (!this->checkOverlap(fTop, coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, &overlaps)) {
665cb93a386Sopenharmony_ci        return true;
666cb93a386Sopenharmony_ci    }
667cb93a386Sopenharmony_ci    if (fHead && !this->checkOverlap(fHead, coinSeg, oppSeg, coinTs,
668cb93a386Sopenharmony_ci            coinTe, oppTs, oppTe, &overlaps)) {
669cb93a386Sopenharmony_ci        return true;
670cb93a386Sopenharmony_ci    }
671cb93a386Sopenharmony_ci    SkCoincidentSpans* overlap = overlaps.count() ? overlaps[0] : nullptr;
672cb93a386Sopenharmony_ci    for (int index = 1; index < overlaps.count(); ++index) { // combine overlaps before continuing
673cb93a386Sopenharmony_ci        SkCoincidentSpans* test = overlaps[index];
674cb93a386Sopenharmony_ci        if (overlap->coinPtTStart()->fT > test->coinPtTStart()->fT) {
675cb93a386Sopenharmony_ci            overlap->setCoinPtTStart(test->coinPtTStart());
676cb93a386Sopenharmony_ci        }
677cb93a386Sopenharmony_ci        if (overlap->coinPtTEnd()->fT < test->coinPtTEnd()->fT) {
678cb93a386Sopenharmony_ci            overlap->setCoinPtTEnd(test->coinPtTEnd());
679cb93a386Sopenharmony_ci        }
680cb93a386Sopenharmony_ci        if (overlap->flipped()
681cb93a386Sopenharmony_ci                ? overlap->oppPtTStart()->fT < test->oppPtTStart()->fT
682cb93a386Sopenharmony_ci                : overlap->oppPtTStart()->fT > test->oppPtTStart()->fT) {
683cb93a386Sopenharmony_ci            overlap->setOppPtTStart(test->oppPtTStart());
684cb93a386Sopenharmony_ci        }
685cb93a386Sopenharmony_ci        if (overlap->flipped()
686cb93a386Sopenharmony_ci                ? overlap->oppPtTEnd()->fT > test->oppPtTEnd()->fT
687cb93a386Sopenharmony_ci                : overlap->oppPtTEnd()->fT < test->oppPtTEnd()->fT) {
688cb93a386Sopenharmony_ci            overlap->setOppPtTEnd(test->oppPtTEnd());
689cb93a386Sopenharmony_ci        }
690cb93a386Sopenharmony_ci        if (!fHead || !this->release(fHead, test)) {
691cb93a386Sopenharmony_ci            SkAssertResult(this->release(fTop, test));
692cb93a386Sopenharmony_ci        }
693cb93a386Sopenharmony_ci    }
694cb93a386Sopenharmony_ci    const SkOpPtT* cs = coinSeg->existing(coinTs, oppSeg);
695cb93a386Sopenharmony_ci    const SkOpPtT* ce = coinSeg->existing(coinTe, oppSeg);
696cb93a386Sopenharmony_ci    if (overlap && cs && ce && overlap->contains(cs, ce)) {
697cb93a386Sopenharmony_ci        return true;
698cb93a386Sopenharmony_ci    }
699cb93a386Sopenharmony_ci    FAIL_IF(cs == ce && cs);
700cb93a386Sopenharmony_ci    const SkOpPtT* os = oppSeg->existing(oppTs, coinSeg);
701cb93a386Sopenharmony_ci    const SkOpPtT* oe = oppSeg->existing(oppTe, coinSeg);
702cb93a386Sopenharmony_ci    if (overlap && os && oe && overlap->contains(os, oe)) {
703cb93a386Sopenharmony_ci        return true;
704cb93a386Sopenharmony_ci    }
705cb93a386Sopenharmony_ci    FAIL_IF(cs && cs->deleted());
706cb93a386Sopenharmony_ci    FAIL_IF(os && os->deleted());
707cb93a386Sopenharmony_ci    FAIL_IF(ce && ce->deleted());
708cb93a386Sopenharmony_ci    FAIL_IF(oe && oe->deleted());
709cb93a386Sopenharmony_ci    const SkOpPtT* csExisting = !cs ? coinSeg->existing(coinTs, nullptr) : nullptr;
710cb93a386Sopenharmony_ci    const SkOpPtT* ceExisting = !ce ? coinSeg->existing(coinTe, nullptr) : nullptr;
711cb93a386Sopenharmony_ci    FAIL_IF(csExisting && csExisting == ceExisting);
712cb93a386Sopenharmony_ci//    FAIL_IF(csExisting && (csExisting == ce ||
713cb93a386Sopenharmony_ci//            csExisting->contains(ceExisting ? ceExisting : ce)));
714cb93a386Sopenharmony_ci    FAIL_IF(ceExisting && (ceExisting == cs ||
715cb93a386Sopenharmony_ci            ceExisting->contains(csExisting ? csExisting : cs)));
716cb93a386Sopenharmony_ci    const SkOpPtT* osExisting = !os ? oppSeg->existing(oppTs, nullptr) : nullptr;
717cb93a386Sopenharmony_ci    const SkOpPtT* oeExisting = !oe ? oppSeg->existing(oppTe, nullptr) : nullptr;
718cb93a386Sopenharmony_ci    FAIL_IF(osExisting && osExisting == oeExisting);
719cb93a386Sopenharmony_ci    FAIL_IF(osExisting && (osExisting == oe ||
720cb93a386Sopenharmony_ci            osExisting->contains(oeExisting ? oeExisting : oe)));
721cb93a386Sopenharmony_ci    FAIL_IF(oeExisting && (oeExisting == os ||
722cb93a386Sopenharmony_ci            oeExisting->contains(osExisting ? osExisting : os)));
723cb93a386Sopenharmony_ci    // extra line in debug code
724cb93a386Sopenharmony_ci    this->debugValidate();
725cb93a386Sopenharmony_ci    if (!cs || !os) {
726cb93a386Sopenharmony_ci        SkOpPtT* csWritable = cs ? const_cast<SkOpPtT*>(cs)
727cb93a386Sopenharmony_ci            : coinSeg->addT(coinTs);
728cb93a386Sopenharmony_ci        if (csWritable == ce) {
729cb93a386Sopenharmony_ci            return true;
730cb93a386Sopenharmony_ci        }
731cb93a386Sopenharmony_ci        SkOpPtT* osWritable = os ? const_cast<SkOpPtT*>(os)
732cb93a386Sopenharmony_ci            : oppSeg->addT(oppTs);
733cb93a386Sopenharmony_ci        FAIL_IF(!csWritable || !osWritable);
734cb93a386Sopenharmony_ci        csWritable->span()->addOpp(osWritable->span());
735cb93a386Sopenharmony_ci        cs = csWritable;
736cb93a386Sopenharmony_ci        os = osWritable->active();
737cb93a386Sopenharmony_ci        FAIL_IF(!os);
738cb93a386Sopenharmony_ci        FAIL_IF((ce && ce->deleted()) || (oe && oe->deleted()));
739cb93a386Sopenharmony_ci    }
740cb93a386Sopenharmony_ci    if (!ce || !oe) {
741cb93a386Sopenharmony_ci        SkOpPtT* ceWritable = ce ? const_cast<SkOpPtT*>(ce)
742cb93a386Sopenharmony_ci            : coinSeg->addT(coinTe);
743cb93a386Sopenharmony_ci        SkOpPtT* oeWritable = oe ? const_cast<SkOpPtT*>(oe)
744cb93a386Sopenharmony_ci            : oppSeg->addT(oppTe);
745cb93a386Sopenharmony_ci        FAIL_IF(!ceWritable->span()->addOpp(oeWritable->span()));
746cb93a386Sopenharmony_ci        ce = ceWritable;
747cb93a386Sopenharmony_ci        oe = oeWritable;
748cb93a386Sopenharmony_ci    }
749cb93a386Sopenharmony_ci    this->debugValidate();
750cb93a386Sopenharmony_ci    FAIL_IF(cs->deleted());
751cb93a386Sopenharmony_ci    FAIL_IF(os->deleted());
752cb93a386Sopenharmony_ci    FAIL_IF(ce->deleted());
753cb93a386Sopenharmony_ci    FAIL_IF(oe->deleted());
754cb93a386Sopenharmony_ci    FAIL_IF(cs->contains(ce) || os->contains(oe));
755cb93a386Sopenharmony_ci    bool result = true;
756cb93a386Sopenharmony_ci    if (overlap) {
757cb93a386Sopenharmony_ci        if (overlap->coinPtTStart()->segment() == coinSeg) {
758cb93a386Sopenharmony_ci            result = overlap->extend(cs, ce, os, oe);
759cb93a386Sopenharmony_ci        } else {
760cb93a386Sopenharmony_ci            if (os->fT > oe->fT) {
761cb93a386Sopenharmony_ci                using std::swap;
762cb93a386Sopenharmony_ci                swap(cs, ce);
763cb93a386Sopenharmony_ci                swap(os, oe);
764cb93a386Sopenharmony_ci            }
765cb93a386Sopenharmony_ci            result = overlap->extend(os, oe, cs, ce);
766cb93a386Sopenharmony_ci        }
767cb93a386Sopenharmony_ci#if DEBUG_COINCIDENCE_VERBOSE
768cb93a386Sopenharmony_ci        if (result) {
769cb93a386Sopenharmony_ci            overlaps[0]->debugShow();
770cb93a386Sopenharmony_ci        }
771cb93a386Sopenharmony_ci#endif
772cb93a386Sopenharmony_ci    } else {
773cb93a386Sopenharmony_ci        this->add(cs, ce, os, oe);
774cb93a386Sopenharmony_ci#if DEBUG_COINCIDENCE_VERBOSE
775cb93a386Sopenharmony_ci        fHead->debugShow();
776cb93a386Sopenharmony_ci#endif
777cb93a386Sopenharmony_ci    }
778cb93a386Sopenharmony_ci    this->debugValidate();
779cb93a386Sopenharmony_ci    if (result) {
780cb93a386Sopenharmony_ci        *added = true;
781cb93a386Sopenharmony_ci    }
782cb93a386Sopenharmony_ci    return true;
783cb93a386Sopenharmony_ci}
784cb93a386Sopenharmony_ci
785cb93a386Sopenharmony_ci// Please keep this in sync with debugAddMissing()
786cb93a386Sopenharmony_ci/* detects overlaps of different coincident runs on same segment */
787cb93a386Sopenharmony_ci/* does not detect overlaps for pairs without any segments in common */
788cb93a386Sopenharmony_ci// returns true if caller should loop again
789cb93a386Sopenharmony_cibool SkOpCoincidence::addMissing(bool* added  DEBUG_COIN_DECLARE_PARAMS()) {
790cb93a386Sopenharmony_ci    SkCoincidentSpans* outer = fHead;
791cb93a386Sopenharmony_ci    *added = false;
792cb93a386Sopenharmony_ci    if (!outer) {
793cb93a386Sopenharmony_ci        return true;
794cb93a386Sopenharmony_ci    }
795cb93a386Sopenharmony_ci    fTop = outer;
796cb93a386Sopenharmony_ci    fHead = nullptr;
797cb93a386Sopenharmony_ci    do {
798cb93a386Sopenharmony_ci    // addifmissing can modify the list that this is walking
799cb93a386Sopenharmony_ci    // save head so that walker can iterate over old data unperturbed
800cb93a386Sopenharmony_ci    // addifmissing adds to head freely then add saved head in the end
801cb93a386Sopenharmony_ci        const SkOpPtT* ocs = outer->coinPtTStart();
802cb93a386Sopenharmony_ci        FAIL_IF(ocs->deleted());
803cb93a386Sopenharmony_ci        const SkOpSegment* outerCoin = ocs->segment();
804cb93a386Sopenharmony_ci        FAIL_IF(outerCoin->done());
805cb93a386Sopenharmony_ci        const SkOpPtT* oos = outer->oppPtTStart();
806cb93a386Sopenharmony_ci        if (oos->deleted()) {
807cb93a386Sopenharmony_ci            return true;
808cb93a386Sopenharmony_ci        }
809cb93a386Sopenharmony_ci        const SkOpSegment* outerOpp = oos->segment();
810cb93a386Sopenharmony_ci        SkOPASSERT(!outerOpp->done());
811cb93a386Sopenharmony_ci        SkOpSegment* outerCoinWritable = const_cast<SkOpSegment*>(outerCoin);
812cb93a386Sopenharmony_ci        SkOpSegment* outerOppWritable = const_cast<SkOpSegment*>(outerOpp);
813cb93a386Sopenharmony_ci        SkCoincidentSpans* inner = outer;
814cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_FUZZER
815cb93a386Sopenharmony_ci        int safetyNet = 1000;
816cb93a386Sopenharmony_ci#endif
817cb93a386Sopenharmony_ci        while ((inner = inner->next())) {
818cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_FUZZER
819cb93a386Sopenharmony_ci            if (!--safetyNet) {
820cb93a386Sopenharmony_ci                return false;
821cb93a386Sopenharmony_ci            }
822cb93a386Sopenharmony_ci#endif
823cb93a386Sopenharmony_ci            this->debugValidate();
824cb93a386Sopenharmony_ci            double overS, overE;
825cb93a386Sopenharmony_ci            const SkOpPtT* ics = inner->coinPtTStart();
826cb93a386Sopenharmony_ci            FAIL_IF(ics->deleted());
827cb93a386Sopenharmony_ci            const SkOpSegment* innerCoin = ics->segment();
828cb93a386Sopenharmony_ci            FAIL_IF(innerCoin->done());
829cb93a386Sopenharmony_ci            const SkOpPtT* ios = inner->oppPtTStart();
830cb93a386Sopenharmony_ci            FAIL_IF(ios->deleted());
831cb93a386Sopenharmony_ci            const SkOpSegment* innerOpp = ios->segment();
832cb93a386Sopenharmony_ci            SkOPASSERT(!innerOpp->done());
833cb93a386Sopenharmony_ci            SkOpSegment* innerCoinWritable = const_cast<SkOpSegment*>(innerCoin);
834cb93a386Sopenharmony_ci            SkOpSegment* innerOppWritable = const_cast<SkOpSegment*>(innerOpp);
835cb93a386Sopenharmony_ci            if (outerCoin == innerCoin) {
836cb93a386Sopenharmony_ci                const SkOpPtT* oce = outer->coinPtTEnd();
837cb93a386Sopenharmony_ci                if (oce->deleted()) {
838cb93a386Sopenharmony_ci                    return true;
839cb93a386Sopenharmony_ci                }
840cb93a386Sopenharmony_ci                const SkOpPtT* ice = inner->coinPtTEnd();
841cb93a386Sopenharmony_ci                FAIL_IF(ice->deleted());
842cb93a386Sopenharmony_ci                if (outerOpp != innerOpp && this->overlap(ocs, oce, ics, ice, &overS, &overE)) {
843cb93a386Sopenharmony_ci                    FAIL_IF(!this->addIfMissing(ocs->starter(oce), ics->starter(ice),
844cb93a386Sopenharmony_ci                            overS, overE, outerOppWritable, innerOppWritable, added
845cb93a386Sopenharmony_ci                            SkDEBUGPARAMS(ocs->debugEnder(oce))
846cb93a386Sopenharmony_ci                            SkDEBUGPARAMS(ics->debugEnder(ice))));
847cb93a386Sopenharmony_ci                }
848cb93a386Sopenharmony_ci            } else if (outerCoin == innerOpp) {
849cb93a386Sopenharmony_ci                const SkOpPtT* oce = outer->coinPtTEnd();
850cb93a386Sopenharmony_ci                FAIL_IF(oce->deleted());
851cb93a386Sopenharmony_ci                const SkOpPtT* ioe = inner->oppPtTEnd();
852cb93a386Sopenharmony_ci                FAIL_IF(ioe->deleted());
853cb93a386Sopenharmony_ci                if (outerOpp != innerCoin && this->overlap(ocs, oce, ios, ioe, &overS, &overE)) {
854cb93a386Sopenharmony_ci                    FAIL_IF(!this->addIfMissing(ocs->starter(oce), ios->starter(ioe),
855cb93a386Sopenharmony_ci                            overS, overE, outerOppWritable, innerCoinWritable, added
856cb93a386Sopenharmony_ci                            SkDEBUGPARAMS(ocs->debugEnder(oce))
857cb93a386Sopenharmony_ci                            SkDEBUGPARAMS(ios->debugEnder(ioe))));
858cb93a386Sopenharmony_ci                }
859cb93a386Sopenharmony_ci            } else if (outerOpp == innerCoin) {
860cb93a386Sopenharmony_ci                const SkOpPtT* ooe = outer->oppPtTEnd();
861cb93a386Sopenharmony_ci                FAIL_IF(ooe->deleted());
862cb93a386Sopenharmony_ci                const SkOpPtT* ice = inner->coinPtTEnd();
863cb93a386Sopenharmony_ci                FAIL_IF(ice->deleted());
864cb93a386Sopenharmony_ci                SkASSERT(outerCoin != innerOpp);
865cb93a386Sopenharmony_ci                if (this->overlap(oos, ooe, ics, ice, &overS, &overE)) {
866cb93a386Sopenharmony_ci                    FAIL_IF(!this->addIfMissing(oos->starter(ooe), ics->starter(ice),
867cb93a386Sopenharmony_ci                            overS, overE, outerCoinWritable, innerOppWritable, added
868cb93a386Sopenharmony_ci                            SkDEBUGPARAMS(oos->debugEnder(ooe))
869cb93a386Sopenharmony_ci                            SkDEBUGPARAMS(ics->debugEnder(ice))));
870cb93a386Sopenharmony_ci                }
871cb93a386Sopenharmony_ci            } else if (outerOpp == innerOpp) {
872cb93a386Sopenharmony_ci                const SkOpPtT* ooe = outer->oppPtTEnd();
873cb93a386Sopenharmony_ci                FAIL_IF(ooe->deleted());
874cb93a386Sopenharmony_ci                const SkOpPtT* ioe = inner->oppPtTEnd();
875cb93a386Sopenharmony_ci                if (ioe->deleted()) {
876cb93a386Sopenharmony_ci                    return true;
877cb93a386Sopenharmony_ci                }
878cb93a386Sopenharmony_ci                SkASSERT(outerCoin != innerCoin);
879cb93a386Sopenharmony_ci                if (this->overlap(oos, ooe, ios, ioe, &overS, &overE)) {
880cb93a386Sopenharmony_ci                    FAIL_IF(!this->addIfMissing(oos->starter(ooe), ios->starter(ioe),
881cb93a386Sopenharmony_ci                            overS, overE, outerCoinWritable, innerCoinWritable, added
882cb93a386Sopenharmony_ci                            SkDEBUGPARAMS(oos->debugEnder(ooe))
883cb93a386Sopenharmony_ci                            SkDEBUGPARAMS(ios->debugEnder(ioe))));
884cb93a386Sopenharmony_ci                }
885cb93a386Sopenharmony_ci            }
886cb93a386Sopenharmony_ci            this->debugValidate();
887cb93a386Sopenharmony_ci        }
888cb93a386Sopenharmony_ci    } while ((outer = outer->next()));
889cb93a386Sopenharmony_ci    this->restoreHead();
890cb93a386Sopenharmony_ci    return true;
891cb93a386Sopenharmony_ci}
892cb93a386Sopenharmony_ci
893cb93a386Sopenharmony_cibool SkOpCoincidence::addOverlap(const SkOpSegment* seg1, const SkOpSegment* seg1o,
894cb93a386Sopenharmony_ci        const SkOpSegment* seg2, const SkOpSegment* seg2o,
895cb93a386Sopenharmony_ci        const SkOpPtT* overS, const SkOpPtT* overE) {
896cb93a386Sopenharmony_ci    const SkOpPtT* s1 = overS->find(seg1);
897cb93a386Sopenharmony_ci    const SkOpPtT* e1 = overE->find(seg1);
898cb93a386Sopenharmony_ci    FAIL_IF(!s1);
899cb93a386Sopenharmony_ci    FAIL_IF(!e1);
900cb93a386Sopenharmony_ci    if (!s1->starter(e1)->span()->upCast()->windValue()) {
901cb93a386Sopenharmony_ci        s1 = overS->find(seg1o);
902cb93a386Sopenharmony_ci        e1 = overE->find(seg1o);
903cb93a386Sopenharmony_ci        FAIL_IF(!s1);
904cb93a386Sopenharmony_ci        FAIL_IF(!e1);
905cb93a386Sopenharmony_ci        if (!s1->starter(e1)->span()->upCast()->windValue()) {
906cb93a386Sopenharmony_ci            return true;
907cb93a386Sopenharmony_ci        }
908cb93a386Sopenharmony_ci    }
909cb93a386Sopenharmony_ci    const SkOpPtT* s2 = overS->find(seg2);
910cb93a386Sopenharmony_ci    const SkOpPtT* e2 = overE->find(seg2);
911cb93a386Sopenharmony_ci    FAIL_IF(!s2);
912cb93a386Sopenharmony_ci    FAIL_IF(!e2);
913cb93a386Sopenharmony_ci    if (!s2->starter(e2)->span()->upCast()->windValue()) {
914cb93a386Sopenharmony_ci        s2 = overS->find(seg2o);
915cb93a386Sopenharmony_ci        e2 = overE->find(seg2o);
916cb93a386Sopenharmony_ci        FAIL_IF(!s2);
917cb93a386Sopenharmony_ci        FAIL_IF(!e2);
918cb93a386Sopenharmony_ci        if (!s2->starter(e2)->span()->upCast()->windValue()) {
919cb93a386Sopenharmony_ci            return true;
920cb93a386Sopenharmony_ci        }
921cb93a386Sopenharmony_ci    }
922cb93a386Sopenharmony_ci    if (s1->segment() == s2->segment()) {
923cb93a386Sopenharmony_ci        return true;
924cb93a386Sopenharmony_ci    }
925cb93a386Sopenharmony_ci    if (s1->fT > e1->fT) {
926cb93a386Sopenharmony_ci        using std::swap;
927cb93a386Sopenharmony_ci        swap(s1, e1);
928cb93a386Sopenharmony_ci        swap(s2, e2);
929cb93a386Sopenharmony_ci    }
930cb93a386Sopenharmony_ci    this->add(s1, e1, s2, e2);
931cb93a386Sopenharmony_ci    return true;
932cb93a386Sopenharmony_ci}
933cb93a386Sopenharmony_ci
934cb93a386Sopenharmony_cibool SkOpCoincidence::contains(const SkOpSegment* seg, const SkOpSegment* opp, double oppT) const {
935cb93a386Sopenharmony_ci    if (this->contains(fHead, seg, opp, oppT)) {
936cb93a386Sopenharmony_ci        return true;
937cb93a386Sopenharmony_ci    }
938cb93a386Sopenharmony_ci    if (this->contains(fTop, seg, opp, oppT)) {
939cb93a386Sopenharmony_ci        return true;
940cb93a386Sopenharmony_ci    }
941cb93a386Sopenharmony_ci    return false;
942cb93a386Sopenharmony_ci}
943cb93a386Sopenharmony_ci
944cb93a386Sopenharmony_cibool SkOpCoincidence::contains(const SkCoincidentSpans* coin, const SkOpSegment* seg,
945cb93a386Sopenharmony_ci        const SkOpSegment* opp, double oppT) const {
946cb93a386Sopenharmony_ci    if (!coin) {
947cb93a386Sopenharmony_ci        return false;
948cb93a386Sopenharmony_ci   }
949cb93a386Sopenharmony_ci    do {
950cb93a386Sopenharmony_ci        if (coin->coinPtTStart()->segment() == seg && coin->oppPtTStart()->segment() == opp
951cb93a386Sopenharmony_ci                && between(coin->oppPtTStart()->fT, oppT, coin->oppPtTEnd()->fT)) {
952cb93a386Sopenharmony_ci            return true;
953cb93a386Sopenharmony_ci        }
954cb93a386Sopenharmony_ci        if (coin->oppPtTStart()->segment() == seg && coin->coinPtTStart()->segment() == opp
955cb93a386Sopenharmony_ci                && between(coin->coinPtTStart()->fT, oppT, coin->coinPtTEnd()->fT)) {
956cb93a386Sopenharmony_ci            return true;
957cb93a386Sopenharmony_ci        }
958cb93a386Sopenharmony_ci    } while ((coin = coin->next()));
959cb93a386Sopenharmony_ci    return false;
960cb93a386Sopenharmony_ci}
961cb93a386Sopenharmony_ci
962cb93a386Sopenharmony_cibool SkOpCoincidence::contains(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd,
963cb93a386Sopenharmony_ci        const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) const {
964cb93a386Sopenharmony_ci    const SkCoincidentSpans* test = fHead;
965cb93a386Sopenharmony_ci    if (!test) {
966cb93a386Sopenharmony_ci        return false;
967cb93a386Sopenharmony_ci    }
968cb93a386Sopenharmony_ci    const SkOpSegment* coinSeg = coinPtTStart->segment();
969cb93a386Sopenharmony_ci    const SkOpSegment* oppSeg = oppPtTStart->segment();
970cb93a386Sopenharmony_ci    if (!Ordered(coinPtTStart, oppPtTStart)) {
971cb93a386Sopenharmony_ci        using std::swap;
972cb93a386Sopenharmony_ci        swap(coinSeg, oppSeg);
973cb93a386Sopenharmony_ci        swap(coinPtTStart, oppPtTStart);
974cb93a386Sopenharmony_ci        swap(coinPtTEnd, oppPtTEnd);
975cb93a386Sopenharmony_ci        if (coinPtTStart->fT > coinPtTEnd->fT) {
976cb93a386Sopenharmony_ci            swap(coinPtTStart, coinPtTEnd);
977cb93a386Sopenharmony_ci            swap(oppPtTStart, oppPtTEnd);
978cb93a386Sopenharmony_ci        }
979cb93a386Sopenharmony_ci    }
980cb93a386Sopenharmony_ci    double oppMinT = std::min(oppPtTStart->fT, oppPtTEnd->fT);
981cb93a386Sopenharmony_ci    double oppMaxT = std::max(oppPtTStart->fT, oppPtTEnd->fT);
982cb93a386Sopenharmony_ci    do {
983cb93a386Sopenharmony_ci        if (coinSeg != test->coinPtTStart()->segment()) {
984cb93a386Sopenharmony_ci            continue;
985cb93a386Sopenharmony_ci        }
986cb93a386Sopenharmony_ci        if (coinPtTStart->fT < test->coinPtTStart()->fT) {
987cb93a386Sopenharmony_ci            continue;
988cb93a386Sopenharmony_ci        }
989cb93a386Sopenharmony_ci        if (coinPtTEnd->fT > test->coinPtTEnd()->fT) {
990cb93a386Sopenharmony_ci            continue;
991cb93a386Sopenharmony_ci        }
992cb93a386Sopenharmony_ci        if (oppSeg != test->oppPtTStart()->segment()) {
993cb93a386Sopenharmony_ci            continue;
994cb93a386Sopenharmony_ci        }
995cb93a386Sopenharmony_ci        if (oppMinT < std::min(test->oppPtTStart()->fT, test->oppPtTEnd()->fT)) {
996cb93a386Sopenharmony_ci            continue;
997cb93a386Sopenharmony_ci        }
998cb93a386Sopenharmony_ci        if (oppMaxT > std::max(test->oppPtTStart()->fT, test->oppPtTEnd()->fT)) {
999cb93a386Sopenharmony_ci            continue;
1000cb93a386Sopenharmony_ci        }
1001cb93a386Sopenharmony_ci        return true;
1002cb93a386Sopenharmony_ci    } while ((test = test->next()));
1003cb93a386Sopenharmony_ci    return false;
1004cb93a386Sopenharmony_ci}
1005cb93a386Sopenharmony_ci
1006cb93a386Sopenharmony_civoid SkOpCoincidence::correctEnds(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
1007cb93a386Sopenharmony_ci    DEBUG_SET_PHASE();
1008cb93a386Sopenharmony_ci    SkCoincidentSpans* coin = fHead;
1009cb93a386Sopenharmony_ci    if (!coin) {
1010cb93a386Sopenharmony_ci        return;
1011cb93a386Sopenharmony_ci    }
1012cb93a386Sopenharmony_ci    do {
1013cb93a386Sopenharmony_ci        coin->correctEnds();
1014cb93a386Sopenharmony_ci    } while ((coin = coin->next()));
1015cb93a386Sopenharmony_ci}
1016cb93a386Sopenharmony_ci
1017cb93a386Sopenharmony_ci// walk span sets in parallel, moving winding from one to the other
1018cb93a386Sopenharmony_cibool SkOpCoincidence::apply(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
1019cb93a386Sopenharmony_ci    DEBUG_SET_PHASE();
1020cb93a386Sopenharmony_ci    SkCoincidentSpans* coin = fHead;
1021cb93a386Sopenharmony_ci    if (!coin) {
1022cb93a386Sopenharmony_ci        return true;
1023cb93a386Sopenharmony_ci    }
1024cb93a386Sopenharmony_ci    do {
1025cb93a386Sopenharmony_ci        SkOpSpanBase* startSpan = coin->coinPtTStartWritable()->span();
1026cb93a386Sopenharmony_ci        FAIL_IF(!startSpan->upCastable());
1027cb93a386Sopenharmony_ci        SkOpSpan* start = startSpan->upCast();
1028cb93a386Sopenharmony_ci        if (start->deleted()) {
1029cb93a386Sopenharmony_ci            continue;
1030cb93a386Sopenharmony_ci        }
1031cb93a386Sopenharmony_ci        const SkOpSpanBase* end = coin->coinPtTEnd()->span();
1032cb93a386Sopenharmony_ci        FAIL_IF(start != start->starter(end));
1033cb93a386Sopenharmony_ci        bool flipped = coin->flipped();
1034cb93a386Sopenharmony_ci        SkOpSpanBase* oStartBase = (flipped ? coin->oppPtTEndWritable()
1035cb93a386Sopenharmony_ci                : coin->oppPtTStartWritable())->span();
1036cb93a386Sopenharmony_ci        FAIL_IF(!oStartBase->upCastable());
1037cb93a386Sopenharmony_ci        SkOpSpan* oStart = oStartBase->upCast();
1038cb93a386Sopenharmony_ci        if (oStart->deleted()) {
1039cb93a386Sopenharmony_ci            continue;
1040cb93a386Sopenharmony_ci        }
1041cb93a386Sopenharmony_ci        const SkOpSpanBase* oEnd = (flipped ? coin->oppPtTStart() : coin->oppPtTEnd())->span();
1042cb93a386Sopenharmony_ci        SkASSERT(oStart == oStart->starter(oEnd));
1043cb93a386Sopenharmony_ci        SkOpSegment* segment = start->segment();
1044cb93a386Sopenharmony_ci        SkOpSegment* oSegment = oStart->segment();
1045cb93a386Sopenharmony_ci        bool operandSwap = segment->operand() != oSegment->operand();
1046cb93a386Sopenharmony_ci        if (flipped) {
1047cb93a386Sopenharmony_ci            if (oEnd->deleted()) {
1048cb93a386Sopenharmony_ci                continue;
1049cb93a386Sopenharmony_ci            }
1050cb93a386Sopenharmony_ci            do {
1051cb93a386Sopenharmony_ci                SkOpSpanBase* oNext = oStart->next();
1052cb93a386Sopenharmony_ci                if (oNext == oEnd) {
1053cb93a386Sopenharmony_ci                    break;
1054cb93a386Sopenharmony_ci                }
1055cb93a386Sopenharmony_ci                FAIL_IF(!oNext->upCastable());
1056cb93a386Sopenharmony_ci                oStart = oNext->upCast();
1057cb93a386Sopenharmony_ci            } while (true);
1058cb93a386Sopenharmony_ci        }
1059cb93a386Sopenharmony_ci        do {
1060cb93a386Sopenharmony_ci            int windValue = start->windValue();
1061cb93a386Sopenharmony_ci            int oppValue = start->oppValue();
1062cb93a386Sopenharmony_ci            int oWindValue = oStart->windValue();
1063cb93a386Sopenharmony_ci            int oOppValue = oStart->oppValue();
1064cb93a386Sopenharmony_ci            // winding values are added or subtracted depending on direction and wind type
1065cb93a386Sopenharmony_ci            // same or opposite values are summed depending on the operand value
1066cb93a386Sopenharmony_ci            int windDiff = operandSwap ? oOppValue : oWindValue;
1067cb93a386Sopenharmony_ci            int oWindDiff = operandSwap ? oppValue : windValue;
1068cb93a386Sopenharmony_ci            if (!flipped) {
1069cb93a386Sopenharmony_ci                windDiff = -windDiff;
1070cb93a386Sopenharmony_ci                oWindDiff = -oWindDiff;
1071cb93a386Sopenharmony_ci            }
1072cb93a386Sopenharmony_ci            bool addToStart = windValue && (windValue > windDiff || (windValue == windDiff
1073cb93a386Sopenharmony_ci                    && oWindValue <= oWindDiff));
1074cb93a386Sopenharmony_ci            if (addToStart ? start->done() : oStart->done()) {
1075cb93a386Sopenharmony_ci                addToStart ^= true;
1076cb93a386Sopenharmony_ci            }
1077cb93a386Sopenharmony_ci            if (addToStart) {
1078cb93a386Sopenharmony_ci                if (operandSwap) {
1079cb93a386Sopenharmony_ci                    using std::swap;
1080cb93a386Sopenharmony_ci                    swap(oWindValue, oOppValue);
1081cb93a386Sopenharmony_ci                }
1082cb93a386Sopenharmony_ci                if (flipped) {
1083cb93a386Sopenharmony_ci                    windValue -= oWindValue;
1084cb93a386Sopenharmony_ci                    oppValue -= oOppValue;
1085cb93a386Sopenharmony_ci                } else {
1086cb93a386Sopenharmony_ci                    windValue += oWindValue;
1087cb93a386Sopenharmony_ci                    oppValue += oOppValue;
1088cb93a386Sopenharmony_ci                }
1089cb93a386Sopenharmony_ci                if (segment->isXor()) {
1090cb93a386Sopenharmony_ci                    windValue &= 1;
1091cb93a386Sopenharmony_ci                }
1092cb93a386Sopenharmony_ci                if (segment->oppXor()) {
1093cb93a386Sopenharmony_ci                    oppValue &= 1;
1094cb93a386Sopenharmony_ci                }
1095cb93a386Sopenharmony_ci                oWindValue = oOppValue = 0;
1096cb93a386Sopenharmony_ci            } else {
1097cb93a386Sopenharmony_ci                if (operandSwap) {
1098cb93a386Sopenharmony_ci                    using std::swap;
1099cb93a386Sopenharmony_ci                    swap(windValue, oppValue);
1100cb93a386Sopenharmony_ci                }
1101cb93a386Sopenharmony_ci                if (flipped) {
1102cb93a386Sopenharmony_ci                    oWindValue -= windValue;
1103cb93a386Sopenharmony_ci                    oOppValue -= oppValue;
1104cb93a386Sopenharmony_ci                } else {
1105cb93a386Sopenharmony_ci                    oWindValue += windValue;
1106cb93a386Sopenharmony_ci                    oOppValue += oppValue;
1107cb93a386Sopenharmony_ci                }
1108cb93a386Sopenharmony_ci                if (oSegment->isXor()) {
1109cb93a386Sopenharmony_ci                    oWindValue &= 1;
1110cb93a386Sopenharmony_ci                }
1111cb93a386Sopenharmony_ci                if (oSegment->oppXor()) {
1112cb93a386Sopenharmony_ci                    oOppValue &= 1;
1113cb93a386Sopenharmony_ci                }
1114cb93a386Sopenharmony_ci                windValue = oppValue = 0;
1115cb93a386Sopenharmony_ci            }
1116cb93a386Sopenharmony_ci#if 0 && DEBUG_COINCIDENCE
1117cb93a386Sopenharmony_ci            SkDebugf("seg=%d span=%d windValue=%d oppValue=%d\n", segment->debugID(),
1118cb93a386Sopenharmony_ci                    start->debugID(), windValue, oppValue);
1119cb93a386Sopenharmony_ci            SkDebugf("seg=%d span=%d windValue=%d oppValue=%d\n", oSegment->debugID(),
1120cb93a386Sopenharmony_ci                    oStart->debugID(), oWindValue, oOppValue);
1121cb93a386Sopenharmony_ci#endif
1122cb93a386Sopenharmony_ci            FAIL_IF(windValue <= -1);
1123cb93a386Sopenharmony_ci            start->setWindValue(windValue);
1124cb93a386Sopenharmony_ci            start->setOppValue(oppValue);
1125cb93a386Sopenharmony_ci            FAIL_IF(oWindValue <= -1);
1126cb93a386Sopenharmony_ci            oStart->setWindValue(oWindValue);
1127cb93a386Sopenharmony_ci            oStart->setOppValue(oOppValue);
1128cb93a386Sopenharmony_ci            if (!windValue && !oppValue) {
1129cb93a386Sopenharmony_ci                segment->markDone(start);
1130cb93a386Sopenharmony_ci            }
1131cb93a386Sopenharmony_ci            if (!oWindValue && !oOppValue) {
1132cb93a386Sopenharmony_ci                oSegment->markDone(oStart);
1133cb93a386Sopenharmony_ci            }
1134cb93a386Sopenharmony_ci            SkOpSpanBase* next = start->next();
1135cb93a386Sopenharmony_ci            SkOpSpanBase* oNext = flipped ? oStart->prev() : oStart->next();
1136cb93a386Sopenharmony_ci            if (next == end) {
1137cb93a386Sopenharmony_ci                break;
1138cb93a386Sopenharmony_ci            }
1139cb93a386Sopenharmony_ci            FAIL_IF(!next->upCastable());
1140cb93a386Sopenharmony_ci            start = next->upCast();
1141cb93a386Sopenharmony_ci            // if the opposite ran out too soon, just reuse the last span
1142cb93a386Sopenharmony_ci            if (!oNext || !oNext->upCastable()) {
1143cb93a386Sopenharmony_ci               oNext = oStart;
1144cb93a386Sopenharmony_ci            }
1145cb93a386Sopenharmony_ci            oStart = oNext->upCast();
1146cb93a386Sopenharmony_ci        } while (true);
1147cb93a386Sopenharmony_ci    } while ((coin = coin->next()));
1148cb93a386Sopenharmony_ci    return true;
1149cb93a386Sopenharmony_ci}
1150cb93a386Sopenharmony_ci
1151cb93a386Sopenharmony_ci// Please keep this in sync with debugRelease()
1152cb93a386Sopenharmony_cibool SkOpCoincidence::release(SkCoincidentSpans* coin, SkCoincidentSpans* remove)  {
1153cb93a386Sopenharmony_ci    SkCoincidentSpans* head = coin;
1154cb93a386Sopenharmony_ci    SkCoincidentSpans* prev = nullptr;
1155cb93a386Sopenharmony_ci    SkCoincidentSpans* next;
1156cb93a386Sopenharmony_ci    do {
1157cb93a386Sopenharmony_ci        next = coin->next();
1158cb93a386Sopenharmony_ci        if (coin == remove) {
1159cb93a386Sopenharmony_ci            if (prev) {
1160cb93a386Sopenharmony_ci                prev->setNext(next);
1161cb93a386Sopenharmony_ci            } else if (head == fHead) {
1162cb93a386Sopenharmony_ci                fHead = next;
1163cb93a386Sopenharmony_ci            } else {
1164cb93a386Sopenharmony_ci                fTop = next;
1165cb93a386Sopenharmony_ci            }
1166cb93a386Sopenharmony_ci            break;
1167cb93a386Sopenharmony_ci        }
1168cb93a386Sopenharmony_ci        prev = coin;
1169cb93a386Sopenharmony_ci    } while ((coin = next));
1170cb93a386Sopenharmony_ci    return coin != nullptr;
1171cb93a386Sopenharmony_ci}
1172cb93a386Sopenharmony_ci
1173cb93a386Sopenharmony_civoid SkOpCoincidence::releaseDeleted(SkCoincidentSpans* coin) {
1174cb93a386Sopenharmony_ci    if (!coin) {
1175cb93a386Sopenharmony_ci        return;
1176cb93a386Sopenharmony_ci    }
1177cb93a386Sopenharmony_ci    SkCoincidentSpans* head = coin;
1178cb93a386Sopenharmony_ci    SkCoincidentSpans* prev = nullptr;
1179cb93a386Sopenharmony_ci    SkCoincidentSpans* next;
1180cb93a386Sopenharmony_ci    do {
1181cb93a386Sopenharmony_ci        next = coin->next();
1182cb93a386Sopenharmony_ci        if (coin->coinPtTStart()->deleted()) {
1183cb93a386Sopenharmony_ci            SkOPASSERT(coin->flipped() ? coin->oppPtTEnd()->deleted() :
1184cb93a386Sopenharmony_ci                    coin->oppPtTStart()->deleted());
1185cb93a386Sopenharmony_ci            if (prev) {
1186cb93a386Sopenharmony_ci                prev->setNext(next);
1187cb93a386Sopenharmony_ci            } else if (head == fHead) {
1188cb93a386Sopenharmony_ci                fHead = next;
1189cb93a386Sopenharmony_ci            } else {
1190cb93a386Sopenharmony_ci                fTop = next;
1191cb93a386Sopenharmony_ci            }
1192cb93a386Sopenharmony_ci        } else {
1193cb93a386Sopenharmony_ci             SkOPASSERT(coin->flipped() ? !coin->oppPtTEnd()->deleted() :
1194cb93a386Sopenharmony_ci                    !coin->oppPtTStart()->deleted());
1195cb93a386Sopenharmony_ci            prev = coin;
1196cb93a386Sopenharmony_ci        }
1197cb93a386Sopenharmony_ci    } while ((coin = next));
1198cb93a386Sopenharmony_ci}
1199cb93a386Sopenharmony_ci
1200cb93a386Sopenharmony_civoid SkOpCoincidence::releaseDeleted() {
1201cb93a386Sopenharmony_ci    this->releaseDeleted(fHead);
1202cb93a386Sopenharmony_ci    this->releaseDeleted(fTop);
1203cb93a386Sopenharmony_ci}
1204cb93a386Sopenharmony_ci
1205cb93a386Sopenharmony_civoid SkOpCoincidence::restoreHead() {
1206cb93a386Sopenharmony_ci    SkCoincidentSpans** headPtr = &fHead;
1207cb93a386Sopenharmony_ci    while (*headPtr) {
1208cb93a386Sopenharmony_ci        headPtr = (*headPtr)->nextPtr();
1209cb93a386Sopenharmony_ci    }
1210cb93a386Sopenharmony_ci    *headPtr = fTop;
1211cb93a386Sopenharmony_ci    fTop = nullptr;
1212cb93a386Sopenharmony_ci    // segments may have collapsed in the meantime; remove empty referenced segments
1213cb93a386Sopenharmony_ci    headPtr = &fHead;
1214cb93a386Sopenharmony_ci    while (*headPtr) {
1215cb93a386Sopenharmony_ci        SkCoincidentSpans* test = *headPtr;
1216cb93a386Sopenharmony_ci        if (test->coinPtTStart()->segment()->done() || test->oppPtTStart()->segment()->done()) {
1217cb93a386Sopenharmony_ci            *headPtr = test->next();
1218cb93a386Sopenharmony_ci            continue;
1219cb93a386Sopenharmony_ci        }
1220cb93a386Sopenharmony_ci        headPtr = (*headPtr)->nextPtr();
1221cb93a386Sopenharmony_ci    }
1222cb93a386Sopenharmony_ci}
1223cb93a386Sopenharmony_ci
1224cb93a386Sopenharmony_ci// Please keep this in sync with debugExpand()
1225cb93a386Sopenharmony_ci// expand the range by checking adjacent spans for coincidence
1226cb93a386Sopenharmony_cibool SkOpCoincidence::expand(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
1227cb93a386Sopenharmony_ci    DEBUG_SET_PHASE();
1228cb93a386Sopenharmony_ci    SkCoincidentSpans* coin = fHead;
1229cb93a386Sopenharmony_ci    if (!coin) {
1230cb93a386Sopenharmony_ci        return false;
1231cb93a386Sopenharmony_ci    }
1232cb93a386Sopenharmony_ci    bool expanded = false;
1233cb93a386Sopenharmony_ci    do {
1234cb93a386Sopenharmony_ci        if (coin->expand()) {
1235cb93a386Sopenharmony_ci            // check to see if multiple spans expanded so they are now identical
1236cb93a386Sopenharmony_ci            SkCoincidentSpans* test = fHead;
1237cb93a386Sopenharmony_ci            do {
1238cb93a386Sopenharmony_ci                if (coin == test) {
1239cb93a386Sopenharmony_ci                    continue;
1240cb93a386Sopenharmony_ci                }
1241cb93a386Sopenharmony_ci                if (coin->coinPtTStart() == test->coinPtTStart()
1242cb93a386Sopenharmony_ci                        && coin->oppPtTStart() == test->oppPtTStart()) {
1243cb93a386Sopenharmony_ci                    this->release(fHead, test);
1244cb93a386Sopenharmony_ci                    break;
1245cb93a386Sopenharmony_ci                }
1246cb93a386Sopenharmony_ci            } while ((test = test->next()));
1247cb93a386Sopenharmony_ci            expanded = true;
1248cb93a386Sopenharmony_ci        }
1249cb93a386Sopenharmony_ci    } while ((coin = coin->next()));
1250cb93a386Sopenharmony_ci    return expanded;
1251cb93a386Sopenharmony_ci}
1252cb93a386Sopenharmony_ci
1253cb93a386Sopenharmony_cibool SkOpCoincidence::findOverlaps(SkOpCoincidence* overlaps  DEBUG_COIN_DECLARE_PARAMS()) const {
1254cb93a386Sopenharmony_ci    DEBUG_SET_PHASE();
1255cb93a386Sopenharmony_ci    overlaps->fHead = overlaps->fTop = nullptr;
1256cb93a386Sopenharmony_ci    SkCoincidentSpans* outer = fHead;
1257cb93a386Sopenharmony_ci    while (outer) {
1258cb93a386Sopenharmony_ci        const SkOpSegment* outerCoin = outer->coinPtTStart()->segment();
1259cb93a386Sopenharmony_ci        const SkOpSegment* outerOpp = outer->oppPtTStart()->segment();
1260cb93a386Sopenharmony_ci        SkCoincidentSpans* inner = outer;
1261cb93a386Sopenharmony_ci        while ((inner = inner->next())) {
1262cb93a386Sopenharmony_ci            const SkOpSegment* innerCoin = inner->coinPtTStart()->segment();
1263cb93a386Sopenharmony_ci            if (outerCoin == innerCoin) {
1264cb93a386Sopenharmony_ci                continue;  // both winners are the same segment, so there's no additional overlap
1265cb93a386Sopenharmony_ci            }
1266cb93a386Sopenharmony_ci            const SkOpSegment* innerOpp = inner->oppPtTStart()->segment();
1267cb93a386Sopenharmony_ci            const SkOpPtT* overlapS;
1268cb93a386Sopenharmony_ci            const SkOpPtT* overlapE;
1269cb93a386Sopenharmony_ci            if ((outerOpp == innerCoin && SkOpPtT::Overlaps(outer->oppPtTStart(),
1270cb93a386Sopenharmony_ci                    outer->oppPtTEnd(),inner->coinPtTStart(), inner->coinPtTEnd(), &overlapS,
1271cb93a386Sopenharmony_ci                    &overlapE))
1272cb93a386Sopenharmony_ci                    || (outerCoin == innerOpp && SkOpPtT::Overlaps(outer->coinPtTStart(),
1273cb93a386Sopenharmony_ci                    outer->coinPtTEnd(), inner->oppPtTStart(), inner->oppPtTEnd(),
1274cb93a386Sopenharmony_ci                    &overlapS, &overlapE))
1275cb93a386Sopenharmony_ci                    || (outerOpp == innerOpp && SkOpPtT::Overlaps(outer->oppPtTStart(),
1276cb93a386Sopenharmony_ci                    outer->oppPtTEnd(), inner->oppPtTStart(), inner->oppPtTEnd(),
1277cb93a386Sopenharmony_ci                    &overlapS, &overlapE))) {
1278cb93a386Sopenharmony_ci                if (!overlaps->addOverlap(outerCoin, outerOpp, innerCoin, innerOpp,
1279cb93a386Sopenharmony_ci                        overlapS, overlapE)) {
1280cb93a386Sopenharmony_ci                    return false;
1281cb93a386Sopenharmony_ci                }
1282cb93a386Sopenharmony_ci             }
1283cb93a386Sopenharmony_ci        }
1284cb93a386Sopenharmony_ci        outer = outer->next();
1285cb93a386Sopenharmony_ci    }
1286cb93a386Sopenharmony_ci    return true;
1287cb93a386Sopenharmony_ci}
1288cb93a386Sopenharmony_ci
1289cb93a386Sopenharmony_civoid SkOpCoincidence::fixUp(SkOpPtT* deleted, const SkOpPtT* kept) {
1290cb93a386Sopenharmony_ci    SkOPASSERT(deleted != kept);
1291cb93a386Sopenharmony_ci    if (fHead) {
1292cb93a386Sopenharmony_ci        this->fixUp(fHead, deleted, kept);
1293cb93a386Sopenharmony_ci    }
1294cb93a386Sopenharmony_ci    if (fTop) {
1295cb93a386Sopenharmony_ci        this->fixUp(fTop, deleted, kept);
1296cb93a386Sopenharmony_ci    }
1297cb93a386Sopenharmony_ci}
1298cb93a386Sopenharmony_ci
1299cb93a386Sopenharmony_civoid SkOpCoincidence::fixUp(SkCoincidentSpans* coin, SkOpPtT* deleted, const SkOpPtT* kept) {
1300cb93a386Sopenharmony_ci    SkCoincidentSpans* head = coin;
1301cb93a386Sopenharmony_ci    do {
1302cb93a386Sopenharmony_ci        if (coin->coinPtTStart() == deleted) {
1303cb93a386Sopenharmony_ci            if (coin->coinPtTEnd()->span() == kept->span()) {
1304cb93a386Sopenharmony_ci                this->release(head, coin);
1305cb93a386Sopenharmony_ci                continue;
1306cb93a386Sopenharmony_ci            }
1307cb93a386Sopenharmony_ci            coin->setCoinPtTStart(kept);
1308cb93a386Sopenharmony_ci        }
1309cb93a386Sopenharmony_ci        if (coin->coinPtTEnd() == deleted) {
1310cb93a386Sopenharmony_ci            if (coin->coinPtTStart()->span() == kept->span()) {
1311cb93a386Sopenharmony_ci                this->release(head, coin);
1312cb93a386Sopenharmony_ci                continue;
1313cb93a386Sopenharmony_ci            }
1314cb93a386Sopenharmony_ci            coin->setCoinPtTEnd(kept);
1315cb93a386Sopenharmony_ci       }
1316cb93a386Sopenharmony_ci        if (coin->oppPtTStart() == deleted) {
1317cb93a386Sopenharmony_ci            if (coin->oppPtTEnd()->span() == kept->span()) {
1318cb93a386Sopenharmony_ci                this->release(head, coin);
1319cb93a386Sopenharmony_ci                continue;
1320cb93a386Sopenharmony_ci            }
1321cb93a386Sopenharmony_ci            coin->setOppPtTStart(kept);
1322cb93a386Sopenharmony_ci        }
1323cb93a386Sopenharmony_ci        if (coin->oppPtTEnd() == deleted) {
1324cb93a386Sopenharmony_ci            if (coin->oppPtTStart()->span() == kept->span()) {
1325cb93a386Sopenharmony_ci                this->release(head, coin);
1326cb93a386Sopenharmony_ci                continue;
1327cb93a386Sopenharmony_ci            }
1328cb93a386Sopenharmony_ci            coin->setOppPtTEnd(kept);
1329cb93a386Sopenharmony_ci        }
1330cb93a386Sopenharmony_ci    } while ((coin = coin->next()));
1331cb93a386Sopenharmony_ci}
1332cb93a386Sopenharmony_ci
1333cb93a386Sopenharmony_ci// Please keep this in sync with debugMark()
1334cb93a386Sopenharmony_ci/* this sets up the coincidence links in the segments when the coincidence crosses multiple spans */
1335cb93a386Sopenharmony_cibool SkOpCoincidence::mark(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
1336cb93a386Sopenharmony_ci    DEBUG_SET_PHASE();
1337cb93a386Sopenharmony_ci    SkCoincidentSpans* coin = fHead;
1338cb93a386Sopenharmony_ci    if (!coin) {
1339cb93a386Sopenharmony_ci        return true;
1340cb93a386Sopenharmony_ci    }
1341cb93a386Sopenharmony_ci    do {
1342cb93a386Sopenharmony_ci        SkOpSpanBase* startBase = coin->coinPtTStartWritable()->span();
1343cb93a386Sopenharmony_ci        FAIL_IF(!startBase->upCastable());
1344cb93a386Sopenharmony_ci        SkOpSpan* start = startBase->upCast();
1345cb93a386Sopenharmony_ci        FAIL_IF(start->deleted());
1346cb93a386Sopenharmony_ci        SkOpSpanBase* end = coin->coinPtTEndWritable()->span();
1347cb93a386Sopenharmony_ci        SkOPASSERT(!end->deleted());
1348cb93a386Sopenharmony_ci        SkOpSpanBase* oStart = coin->oppPtTStartWritable()->span();
1349cb93a386Sopenharmony_ci        SkOPASSERT(!oStart->deleted());
1350cb93a386Sopenharmony_ci        SkOpSpanBase* oEnd = coin->oppPtTEndWritable()->span();
1351cb93a386Sopenharmony_ci        FAIL_IF(oEnd->deleted());
1352cb93a386Sopenharmony_ci        bool flipped = coin->flipped();
1353cb93a386Sopenharmony_ci        if (flipped) {
1354cb93a386Sopenharmony_ci            using std::swap;
1355cb93a386Sopenharmony_ci            swap(oStart, oEnd);
1356cb93a386Sopenharmony_ci        }
1357cb93a386Sopenharmony_ci        /* coin and opp spans may not match up. Mark the ends, and then let the interior
1358cb93a386Sopenharmony_ci           get marked as many times as the spans allow */
1359cb93a386Sopenharmony_ci        FAIL_IF(!oStart->upCastable());
1360cb93a386Sopenharmony_ci        start->insertCoincidence(oStart->upCast());
1361cb93a386Sopenharmony_ci        end->insertCoinEnd(oEnd);
1362cb93a386Sopenharmony_ci        const SkOpSegment* segment = start->segment();
1363cb93a386Sopenharmony_ci        const SkOpSegment* oSegment = oStart->segment();
1364cb93a386Sopenharmony_ci        SkOpSpanBase* next = start;
1365cb93a386Sopenharmony_ci        SkOpSpanBase* oNext = oStart;
1366cb93a386Sopenharmony_ci        bool ordered;
1367cb93a386Sopenharmony_ci        FAIL_IF(!coin->ordered(&ordered));
1368cb93a386Sopenharmony_ci        while ((next = next->upCast()->next()) != end) {
1369cb93a386Sopenharmony_ci            FAIL_IF(!next->upCastable());
1370cb93a386Sopenharmony_ci            FAIL_IF(!next->upCast()->insertCoincidence(oSegment, flipped, ordered));
1371cb93a386Sopenharmony_ci        }
1372cb93a386Sopenharmony_ci        while ((oNext = oNext->upCast()->next()) != oEnd) {
1373cb93a386Sopenharmony_ci            FAIL_IF(!oNext->upCastable());
1374cb93a386Sopenharmony_ci            FAIL_IF(!oNext->upCast()->insertCoincidence(segment, flipped, ordered));
1375cb93a386Sopenharmony_ci        }
1376cb93a386Sopenharmony_ci    } while ((coin = coin->next()));
1377cb93a386Sopenharmony_ci    return true;
1378cb93a386Sopenharmony_ci}
1379cb93a386Sopenharmony_ci
1380cb93a386Sopenharmony_ci// Please keep in sync with debugMarkCollapsed()
1381cb93a386Sopenharmony_civoid SkOpCoincidence::markCollapsed(SkCoincidentSpans* coin, SkOpPtT* test) {
1382cb93a386Sopenharmony_ci    SkCoincidentSpans* head = coin;
1383cb93a386Sopenharmony_ci    while (coin) {
1384cb93a386Sopenharmony_ci        if (coin->collapsed(test)) {
1385cb93a386Sopenharmony_ci            if (zero_or_one(coin->coinPtTStart()->fT) && zero_or_one(coin->coinPtTEnd()->fT)) {
1386cb93a386Sopenharmony_ci                coin->coinPtTStartWritable()->segment()->markAllDone();
1387cb93a386Sopenharmony_ci            }
1388cb93a386Sopenharmony_ci            if (zero_or_one(coin->oppPtTStart()->fT) && zero_or_one(coin->oppPtTEnd()->fT)) {
1389cb93a386Sopenharmony_ci                coin->oppPtTStartWritable()->segment()->markAllDone();
1390cb93a386Sopenharmony_ci            }
1391cb93a386Sopenharmony_ci            this->release(head, coin);
1392cb93a386Sopenharmony_ci        }
1393cb93a386Sopenharmony_ci        coin = coin->next();
1394cb93a386Sopenharmony_ci    }
1395cb93a386Sopenharmony_ci}
1396cb93a386Sopenharmony_ci
1397cb93a386Sopenharmony_ci// Please keep in sync with debugMarkCollapsed()
1398cb93a386Sopenharmony_civoid SkOpCoincidence::markCollapsed(SkOpPtT* test) {
1399cb93a386Sopenharmony_ci    markCollapsed(fHead, test);
1400cb93a386Sopenharmony_ci    markCollapsed(fTop, test);
1401cb93a386Sopenharmony_ci}
1402cb93a386Sopenharmony_ci
1403cb93a386Sopenharmony_cibool SkOpCoincidence::Ordered(const SkOpSegment* coinSeg, const SkOpSegment* oppSeg) {
1404cb93a386Sopenharmony_ci    if (coinSeg->verb() < oppSeg->verb()) {
1405cb93a386Sopenharmony_ci        return true;
1406cb93a386Sopenharmony_ci    }
1407cb93a386Sopenharmony_ci    if (coinSeg->verb() > oppSeg->verb()) {
1408cb93a386Sopenharmony_ci        return false;
1409cb93a386Sopenharmony_ci    }
1410cb93a386Sopenharmony_ci    int count = (SkPathOpsVerbToPoints(coinSeg->verb()) + 1) * 2;
1411cb93a386Sopenharmony_ci    const SkScalar* cPt = &coinSeg->pts()[0].fX;
1412cb93a386Sopenharmony_ci    const SkScalar* oPt = &oppSeg->pts()[0].fX;
1413cb93a386Sopenharmony_ci    for (int index = 0; index < count; ++index) {
1414cb93a386Sopenharmony_ci        if (*cPt < *oPt) {
1415cb93a386Sopenharmony_ci            return true;
1416cb93a386Sopenharmony_ci        }
1417cb93a386Sopenharmony_ci        if (*cPt > *oPt) {
1418cb93a386Sopenharmony_ci            return false;
1419cb93a386Sopenharmony_ci        }
1420cb93a386Sopenharmony_ci        ++cPt;
1421cb93a386Sopenharmony_ci        ++oPt;
1422cb93a386Sopenharmony_ci    }
1423cb93a386Sopenharmony_ci    return true;
1424cb93a386Sopenharmony_ci}
1425cb93a386Sopenharmony_ci
1426cb93a386Sopenharmony_cibool SkOpCoincidence::overlap(const SkOpPtT* coin1s, const SkOpPtT* coin1e,
1427cb93a386Sopenharmony_ci        const SkOpPtT* coin2s, const SkOpPtT* coin2e, double* overS, double* overE) const {
1428cb93a386Sopenharmony_ci    SkASSERT(coin1s->segment() == coin2s->segment());
1429cb93a386Sopenharmony_ci    *overS = std::max(std::min(coin1s->fT, coin1e->fT), std::min(coin2s->fT, coin2e->fT));
1430cb93a386Sopenharmony_ci    *overE = std::min(std::max(coin1s->fT, coin1e->fT), std::max(coin2s->fT, coin2e->fT));
1431cb93a386Sopenharmony_ci    return *overS < *overE;
1432cb93a386Sopenharmony_ci}
1433cb93a386Sopenharmony_ci
1434cb93a386Sopenharmony_ci// Commented-out lines keep this in sync with debugRelease()
1435cb93a386Sopenharmony_civoid SkOpCoincidence::release(const SkOpSegment* deleted) {
1436cb93a386Sopenharmony_ci    SkCoincidentSpans* coin = fHead;
1437cb93a386Sopenharmony_ci    if (!coin) {
1438cb93a386Sopenharmony_ci        return;
1439cb93a386Sopenharmony_ci    }
1440cb93a386Sopenharmony_ci    do {
1441cb93a386Sopenharmony_ci        if (coin->coinPtTStart()->segment() == deleted
1442cb93a386Sopenharmony_ci                || coin->coinPtTEnd()->segment() == deleted
1443cb93a386Sopenharmony_ci                || coin->oppPtTStart()->segment() == deleted
1444cb93a386Sopenharmony_ci                || coin->oppPtTEnd()->segment() == deleted) {
1445cb93a386Sopenharmony_ci            this->release(fHead, coin);
1446cb93a386Sopenharmony_ci        }
1447cb93a386Sopenharmony_ci    } while ((coin = coin->next()));
1448cb93a386Sopenharmony_ci}
1449