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