xref: /aosp_15_r20/external/skia/src/pathops/SkOpSpan.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2014 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 "include/core/SkPoint.h"
8*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTemplates.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkOpCoincidence.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkOpContour.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkOpSegment.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkOpSpan.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkPathOpsTypes.h"
15*c8dee2aaSAndroid Build Coastguard Worker 
16*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm>
17*c8dee2aaSAndroid Build Coastguard Worker 
alias() const18*c8dee2aaSAndroid Build Coastguard Worker bool SkOpPtT::alias() const {
19*c8dee2aaSAndroid Build Coastguard Worker     return this->span()->ptT() != this;
20*c8dee2aaSAndroid Build Coastguard Worker }
21*c8dee2aaSAndroid Build Coastguard Worker 
active() const22*c8dee2aaSAndroid Build Coastguard Worker const SkOpPtT* SkOpPtT::active() const {
23*c8dee2aaSAndroid Build Coastguard Worker     if (!fDeleted) {
24*c8dee2aaSAndroid Build Coastguard Worker         return this;
25*c8dee2aaSAndroid Build Coastguard Worker     }
26*c8dee2aaSAndroid Build Coastguard Worker     const SkOpPtT* ptT = this;
27*c8dee2aaSAndroid Build Coastguard Worker     const SkOpPtT* stopPtT = ptT;
28*c8dee2aaSAndroid Build Coastguard Worker     while ((ptT = ptT->next()) != stopPtT) {
29*c8dee2aaSAndroid Build Coastguard Worker         if (ptT->fSpan == fSpan && !ptT->fDeleted) {
30*c8dee2aaSAndroid Build Coastguard Worker             return ptT;
31*c8dee2aaSAndroid Build Coastguard Worker         }
32*c8dee2aaSAndroid Build Coastguard Worker     }
33*c8dee2aaSAndroid Build Coastguard Worker     return nullptr; // should never return deleted; caller must abort
34*c8dee2aaSAndroid Build Coastguard Worker }
35*c8dee2aaSAndroid Build Coastguard Worker 
contains(const SkOpPtT * check) const36*c8dee2aaSAndroid Build Coastguard Worker bool SkOpPtT::contains(const SkOpPtT* check) const {
37*c8dee2aaSAndroid Build Coastguard Worker     SkOPASSERT(this != check);
38*c8dee2aaSAndroid Build Coastguard Worker     const SkOpPtT* ptT = this;
39*c8dee2aaSAndroid Build Coastguard Worker     const SkOpPtT* stopPtT = ptT;
40*c8dee2aaSAndroid Build Coastguard Worker     while ((ptT = ptT->next()) != stopPtT) {
41*c8dee2aaSAndroid Build Coastguard Worker         if (ptT == check) {
42*c8dee2aaSAndroid Build Coastguard Worker             return true;
43*c8dee2aaSAndroid Build Coastguard Worker         }
44*c8dee2aaSAndroid Build Coastguard Worker     }
45*c8dee2aaSAndroid Build Coastguard Worker     return false;
46*c8dee2aaSAndroid Build Coastguard Worker }
47*c8dee2aaSAndroid Build Coastguard Worker 
contains(const SkOpSegment * segment,const SkPoint & pt) const48*c8dee2aaSAndroid Build Coastguard Worker bool SkOpPtT::contains(const SkOpSegment* segment, const SkPoint& pt) const {
49*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(this->segment() != segment);
50*c8dee2aaSAndroid Build Coastguard Worker     const SkOpPtT* ptT = this;
51*c8dee2aaSAndroid Build Coastguard Worker     const SkOpPtT* stopPtT = ptT;
52*c8dee2aaSAndroid Build Coastguard Worker     while ((ptT = ptT->next()) != stopPtT) {
53*c8dee2aaSAndroid Build Coastguard Worker         if (ptT->fPt == pt && ptT->segment() == segment) {
54*c8dee2aaSAndroid Build Coastguard Worker             return true;
55*c8dee2aaSAndroid Build Coastguard Worker         }
56*c8dee2aaSAndroid Build Coastguard Worker     }
57*c8dee2aaSAndroid Build Coastguard Worker     return false;
58*c8dee2aaSAndroid Build Coastguard Worker }
59*c8dee2aaSAndroid Build Coastguard Worker 
contains(const SkOpSegment * segment,double t) const60*c8dee2aaSAndroid Build Coastguard Worker bool SkOpPtT::contains(const SkOpSegment* segment, double t) const {
61*c8dee2aaSAndroid Build Coastguard Worker     const SkOpPtT* ptT = this;
62*c8dee2aaSAndroid Build Coastguard Worker     const SkOpPtT* stopPtT = ptT;
63*c8dee2aaSAndroid Build Coastguard Worker     while ((ptT = ptT->next()) != stopPtT) {
64*c8dee2aaSAndroid Build Coastguard Worker         if (ptT->fT == t && ptT->segment() == segment) {
65*c8dee2aaSAndroid Build Coastguard Worker             return true;
66*c8dee2aaSAndroid Build Coastguard Worker         }
67*c8dee2aaSAndroid Build Coastguard Worker     }
68*c8dee2aaSAndroid Build Coastguard Worker     return false;
69*c8dee2aaSAndroid Build Coastguard Worker }
70*c8dee2aaSAndroid Build Coastguard Worker 
contains(const SkOpSegment * check) const71*c8dee2aaSAndroid Build Coastguard Worker const SkOpPtT* SkOpPtT::contains(const SkOpSegment* check) const {
72*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(this->segment() != check);
73*c8dee2aaSAndroid Build Coastguard Worker     const SkOpPtT* ptT = this;
74*c8dee2aaSAndroid Build Coastguard Worker     const SkOpPtT* stopPtT = ptT;
75*c8dee2aaSAndroid Build Coastguard Worker     while ((ptT = ptT->next()) != stopPtT) {
76*c8dee2aaSAndroid Build Coastguard Worker         if (ptT->segment() == check && !ptT->deleted()) {
77*c8dee2aaSAndroid Build Coastguard Worker             return ptT;
78*c8dee2aaSAndroid Build Coastguard Worker         }
79*c8dee2aaSAndroid Build Coastguard Worker     }
80*c8dee2aaSAndroid Build Coastguard Worker     return nullptr;
81*c8dee2aaSAndroid Build Coastguard Worker }
82*c8dee2aaSAndroid Build Coastguard Worker 
contour() const83*c8dee2aaSAndroid Build Coastguard Worker SkOpContour* SkOpPtT::contour() const {
84*c8dee2aaSAndroid Build Coastguard Worker     return segment()->contour();
85*c8dee2aaSAndroid Build Coastguard Worker }
86*c8dee2aaSAndroid Build Coastguard Worker 
find(const SkOpSegment * segment) const87*c8dee2aaSAndroid Build Coastguard Worker const SkOpPtT* SkOpPtT::find(const SkOpSegment* segment) const {
88*c8dee2aaSAndroid Build Coastguard Worker     const SkOpPtT* ptT = this;
89*c8dee2aaSAndroid Build Coastguard Worker     const SkOpPtT* stopPtT = ptT;
90*c8dee2aaSAndroid Build Coastguard Worker     do {
91*c8dee2aaSAndroid Build Coastguard Worker         if (ptT->segment() == segment && !ptT->deleted()) {
92*c8dee2aaSAndroid Build Coastguard Worker             return ptT;
93*c8dee2aaSAndroid Build Coastguard Worker         }
94*c8dee2aaSAndroid Build Coastguard Worker         ptT = ptT->fNext;
95*c8dee2aaSAndroid Build Coastguard Worker     } while (stopPtT != ptT);
96*c8dee2aaSAndroid Build Coastguard Worker //    SkASSERT(0);
97*c8dee2aaSAndroid Build Coastguard Worker     return nullptr;
98*c8dee2aaSAndroid Build Coastguard Worker }
99*c8dee2aaSAndroid Build Coastguard Worker 
globalState() const100*c8dee2aaSAndroid Build Coastguard Worker SkOpGlobalState* SkOpPtT::globalState() const {
101*c8dee2aaSAndroid Build Coastguard Worker     return contour()->globalState();
102*c8dee2aaSAndroid Build Coastguard Worker }
103*c8dee2aaSAndroid Build Coastguard Worker 
init(SkOpSpanBase * span,double t,const SkPoint & pt,bool duplicate)104*c8dee2aaSAndroid Build Coastguard Worker void SkOpPtT::init(SkOpSpanBase* span, double t, const SkPoint& pt, bool duplicate) {
105*c8dee2aaSAndroid Build Coastguard Worker     fT = t;
106*c8dee2aaSAndroid Build Coastguard Worker     fPt = pt;
107*c8dee2aaSAndroid Build Coastguard Worker     fSpan = span;
108*c8dee2aaSAndroid Build Coastguard Worker     fNext = this;
109*c8dee2aaSAndroid Build Coastguard Worker     fDuplicatePt = duplicate;
110*c8dee2aaSAndroid Build Coastguard Worker     fDeleted = false;
111*c8dee2aaSAndroid Build Coastguard Worker     fCoincident = false;
112*c8dee2aaSAndroid Build Coastguard Worker     SkDEBUGCODE(fID = span->globalState()->nextPtTID());
113*c8dee2aaSAndroid Build Coastguard Worker }
114*c8dee2aaSAndroid Build Coastguard Worker 
onEnd() const115*c8dee2aaSAndroid Build Coastguard Worker bool SkOpPtT::onEnd() const {
116*c8dee2aaSAndroid Build Coastguard Worker     const SkOpSpanBase* span = this->span();
117*c8dee2aaSAndroid Build Coastguard Worker     if (span->ptT() != this) {
118*c8dee2aaSAndroid Build Coastguard Worker         return false;
119*c8dee2aaSAndroid Build Coastguard Worker     }
120*c8dee2aaSAndroid Build Coastguard Worker     const SkOpSegment* segment = this->segment();
121*c8dee2aaSAndroid Build Coastguard Worker     return span == segment->head() || span == segment->tail();
122*c8dee2aaSAndroid Build Coastguard Worker }
123*c8dee2aaSAndroid Build Coastguard Worker 
ptAlreadySeen(const SkOpPtT * check) const124*c8dee2aaSAndroid Build Coastguard Worker bool SkOpPtT::ptAlreadySeen(const SkOpPtT* check) const {
125*c8dee2aaSAndroid Build Coastguard Worker     while (this != check) {
126*c8dee2aaSAndroid Build Coastguard Worker         if (this->fPt == check->fPt) {
127*c8dee2aaSAndroid Build Coastguard Worker             return true;
128*c8dee2aaSAndroid Build Coastguard Worker         }
129*c8dee2aaSAndroid Build Coastguard Worker         check = check->fNext;
130*c8dee2aaSAndroid Build Coastguard Worker     }
131*c8dee2aaSAndroid Build Coastguard Worker     return false;
132*c8dee2aaSAndroid Build Coastguard Worker }
133*c8dee2aaSAndroid Build Coastguard Worker 
prev()134*c8dee2aaSAndroid Build Coastguard Worker SkOpPtT* SkOpPtT::prev() {
135*c8dee2aaSAndroid Build Coastguard Worker     SkOpPtT* result = this;
136*c8dee2aaSAndroid Build Coastguard Worker     SkOpPtT* next = this;
137*c8dee2aaSAndroid Build Coastguard Worker     while ((next = next->fNext) != this) {
138*c8dee2aaSAndroid Build Coastguard Worker         result = next;
139*c8dee2aaSAndroid Build Coastguard Worker     }
140*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(result->fNext == this);
141*c8dee2aaSAndroid Build Coastguard Worker     return result;
142*c8dee2aaSAndroid Build Coastguard Worker }
143*c8dee2aaSAndroid Build Coastguard Worker 
segment() const144*c8dee2aaSAndroid Build Coastguard Worker const SkOpSegment* SkOpPtT::segment() const {
145*c8dee2aaSAndroid Build Coastguard Worker     return span()->segment();
146*c8dee2aaSAndroid Build Coastguard Worker }
147*c8dee2aaSAndroid Build Coastguard Worker 
segment()148*c8dee2aaSAndroid Build Coastguard Worker SkOpSegment* SkOpPtT::segment() {
149*c8dee2aaSAndroid Build Coastguard Worker     return span()->segment();
150*c8dee2aaSAndroid Build Coastguard Worker }
151*c8dee2aaSAndroid Build Coastguard Worker 
setDeleted()152*c8dee2aaSAndroid Build Coastguard Worker void SkOpPtT::setDeleted() {
153*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(this->span()->debugDeleted() || this->span()->ptT() != this);
154*c8dee2aaSAndroid Build Coastguard Worker     SkOPASSERT(!fDeleted);
155*c8dee2aaSAndroid Build Coastguard Worker     fDeleted = true;
156*c8dee2aaSAndroid Build Coastguard Worker }
157*c8dee2aaSAndroid Build Coastguard Worker 
addOpp(SkOpSpanBase * opp)158*c8dee2aaSAndroid Build Coastguard Worker bool SkOpSpanBase::addOpp(SkOpSpanBase* opp) {
159*c8dee2aaSAndroid Build Coastguard Worker     SkOpPtT* oppPrev = this->ptT()->oppPrev(opp->ptT());
160*c8dee2aaSAndroid Build Coastguard Worker     if (!oppPrev) {
161*c8dee2aaSAndroid Build Coastguard Worker         return true;
162*c8dee2aaSAndroid Build Coastguard Worker     }
163*c8dee2aaSAndroid Build Coastguard Worker     FAIL_IF(!this->mergeMatches(opp));
164*c8dee2aaSAndroid Build Coastguard Worker     this->ptT()->addOpp(opp->ptT(), oppPrev);
165*c8dee2aaSAndroid Build Coastguard Worker     this->checkForCollapsedCoincidence();
166*c8dee2aaSAndroid Build Coastguard Worker     return true;
167*c8dee2aaSAndroid Build Coastguard Worker }
168*c8dee2aaSAndroid Build Coastguard Worker 
collapsed(double s,double e) const169*c8dee2aaSAndroid Build Coastguard Worker SkOpSpanBase::Collapsed SkOpSpanBase::collapsed(double s, double e) const {
170*c8dee2aaSAndroid Build Coastguard Worker     const SkOpPtT* start = &fPtT;
171*c8dee2aaSAndroid Build Coastguard Worker     const SkOpPtT* startNext = nullptr;
172*c8dee2aaSAndroid Build Coastguard Worker     const SkOpPtT* walk = start;
173*c8dee2aaSAndroid Build Coastguard Worker     double min = walk->fT;
174*c8dee2aaSAndroid Build Coastguard Worker     double max = min;
175*c8dee2aaSAndroid Build Coastguard Worker     const SkOpSegment* segment = this->segment();
176*c8dee2aaSAndroid Build Coastguard Worker     int safetyNet = 100000;
177*c8dee2aaSAndroid Build Coastguard Worker     while ((walk = walk->next()) != start) {
178*c8dee2aaSAndroid Build Coastguard Worker         if (!--safetyNet) {
179*c8dee2aaSAndroid Build Coastguard Worker             return Collapsed::kError;
180*c8dee2aaSAndroid Build Coastguard Worker         }
181*c8dee2aaSAndroid Build Coastguard Worker         if (walk == startNext) {
182*c8dee2aaSAndroid Build Coastguard Worker             return Collapsed::kError;
183*c8dee2aaSAndroid Build Coastguard Worker         }
184*c8dee2aaSAndroid Build Coastguard Worker         if (walk->segment() != segment) {
185*c8dee2aaSAndroid Build Coastguard Worker             continue;
186*c8dee2aaSAndroid Build Coastguard Worker         }
187*c8dee2aaSAndroid Build Coastguard Worker         min = std::min(min, walk->fT);
188*c8dee2aaSAndroid Build Coastguard Worker         max = std::max(max, walk->fT);
189*c8dee2aaSAndroid Build Coastguard Worker         if (between(min, s, max) && between(min, e, max)) {
190*c8dee2aaSAndroid Build Coastguard Worker             return Collapsed::kYes;
191*c8dee2aaSAndroid Build Coastguard Worker         }
192*c8dee2aaSAndroid Build Coastguard Worker         startNext = start->next();
193*c8dee2aaSAndroid Build Coastguard Worker     }
194*c8dee2aaSAndroid Build Coastguard Worker     return Collapsed::kNo;
195*c8dee2aaSAndroid Build Coastguard Worker }
196*c8dee2aaSAndroid Build Coastguard Worker 
contains(const SkOpSpanBase * span) const197*c8dee2aaSAndroid Build Coastguard Worker bool SkOpSpanBase::contains(const SkOpSpanBase* span) const {
198*c8dee2aaSAndroid Build Coastguard Worker     const SkOpPtT* start = &fPtT;
199*c8dee2aaSAndroid Build Coastguard Worker     const SkOpPtT* check = &span->fPtT;
200*c8dee2aaSAndroid Build Coastguard Worker     SkOPASSERT(start != check);
201*c8dee2aaSAndroid Build Coastguard Worker     const SkOpPtT* walk = start;
202*c8dee2aaSAndroid Build Coastguard Worker     while ((walk = walk->next()) != start) {
203*c8dee2aaSAndroid Build Coastguard Worker         if (walk == check) {
204*c8dee2aaSAndroid Build Coastguard Worker             return true;
205*c8dee2aaSAndroid Build Coastguard Worker         }
206*c8dee2aaSAndroid Build Coastguard Worker     }
207*c8dee2aaSAndroid Build Coastguard Worker     return false;
208*c8dee2aaSAndroid Build Coastguard Worker }
209*c8dee2aaSAndroid Build Coastguard Worker 
contains(const SkOpSegment * segment) const210*c8dee2aaSAndroid Build Coastguard Worker const SkOpPtT* SkOpSpanBase::contains(const SkOpSegment* segment) const {
211*c8dee2aaSAndroid Build Coastguard Worker     const SkOpPtT* start = &fPtT;
212*c8dee2aaSAndroid Build Coastguard Worker     const SkOpPtT* walk = start;
213*c8dee2aaSAndroid Build Coastguard Worker     while ((walk = walk->next()) != start) {
214*c8dee2aaSAndroid Build Coastguard Worker         if (walk->deleted()) {
215*c8dee2aaSAndroid Build Coastguard Worker             continue;
216*c8dee2aaSAndroid Build Coastguard Worker         }
217*c8dee2aaSAndroid Build Coastguard Worker         if (walk->segment() == segment && walk->span()->ptT() == walk) {
218*c8dee2aaSAndroid Build Coastguard Worker             return walk;
219*c8dee2aaSAndroid Build Coastguard Worker         }
220*c8dee2aaSAndroid Build Coastguard Worker     }
221*c8dee2aaSAndroid Build Coastguard Worker     return nullptr;
222*c8dee2aaSAndroid Build Coastguard Worker }
223*c8dee2aaSAndroid Build Coastguard Worker 
containsCoinEnd(const SkOpSegment * segment) const224*c8dee2aaSAndroid Build Coastguard Worker bool SkOpSpanBase::containsCoinEnd(const SkOpSegment* segment) const {
225*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(this->segment() != segment);
226*c8dee2aaSAndroid Build Coastguard Worker     const SkOpSpanBase* next = this;
227*c8dee2aaSAndroid Build Coastguard Worker     while ((next = next->fCoinEnd) != this) {
228*c8dee2aaSAndroid Build Coastguard Worker         if (next->segment() == segment) {
229*c8dee2aaSAndroid Build Coastguard Worker             return true;
230*c8dee2aaSAndroid Build Coastguard Worker         }
231*c8dee2aaSAndroid Build Coastguard Worker     }
232*c8dee2aaSAndroid Build Coastguard Worker     return false;
233*c8dee2aaSAndroid Build Coastguard Worker }
234*c8dee2aaSAndroid Build Coastguard Worker 
contour() const235*c8dee2aaSAndroid Build Coastguard Worker SkOpContour* SkOpSpanBase::contour() const {
236*c8dee2aaSAndroid Build Coastguard Worker     return segment()->contour();
237*c8dee2aaSAndroid Build Coastguard Worker }
238*c8dee2aaSAndroid Build Coastguard Worker 
globalState() const239*c8dee2aaSAndroid Build Coastguard Worker SkOpGlobalState* SkOpSpanBase::globalState() const {
240*c8dee2aaSAndroid Build Coastguard Worker     return contour()->globalState();
241*c8dee2aaSAndroid Build Coastguard Worker }
242*c8dee2aaSAndroid Build Coastguard Worker 
initBase(SkOpSegment * segment,SkOpSpan * prev,double t,const SkPoint & pt)243*c8dee2aaSAndroid Build Coastguard Worker void SkOpSpanBase::initBase(SkOpSegment* segment, SkOpSpan* prev, double t, const SkPoint& pt) {
244*c8dee2aaSAndroid Build Coastguard Worker     fSegment = segment;
245*c8dee2aaSAndroid Build Coastguard Worker     fPtT.init(this, t, pt, false);
246*c8dee2aaSAndroid Build Coastguard Worker     fCoinEnd = this;
247*c8dee2aaSAndroid Build Coastguard Worker     fFromAngle = nullptr;
248*c8dee2aaSAndroid Build Coastguard Worker     fPrev = prev;
249*c8dee2aaSAndroid Build Coastguard Worker     fSpanAdds = 0;
250*c8dee2aaSAndroid Build Coastguard Worker     fAligned = true;
251*c8dee2aaSAndroid Build Coastguard Worker     fChased = false;
252*c8dee2aaSAndroid Build Coastguard Worker     SkDEBUGCODE(fCount = 1);
253*c8dee2aaSAndroid Build Coastguard Worker     SkDEBUGCODE(fID = globalState()->nextSpanID());
254*c8dee2aaSAndroid Build Coastguard Worker     SkDEBUGCODE(fDebugDeleted = false);
255*c8dee2aaSAndroid Build Coastguard Worker }
256*c8dee2aaSAndroid Build Coastguard Worker 
257*c8dee2aaSAndroid Build Coastguard Worker // this pair of spans share a common t value or point; merge them and eliminate duplicates
258*c8dee2aaSAndroid Build Coastguard Worker // this does not compute the best t or pt value; this merely moves all data into a single list
merge(SkOpSpan * span)259*c8dee2aaSAndroid Build Coastguard Worker void SkOpSpanBase::merge(SkOpSpan* span) {
260*c8dee2aaSAndroid Build Coastguard Worker     SkOpPtT* spanPtT = span->ptT();
261*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(this->t() != spanPtT->fT);
262*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(!zero_or_one(spanPtT->fT));
263*c8dee2aaSAndroid Build Coastguard Worker     span->release(this->ptT());
264*c8dee2aaSAndroid Build Coastguard Worker     if (this->contains(span)) {
265*c8dee2aaSAndroid Build Coastguard Worker         SkOPASSERT(0);  // check to see if this ever happens -- should have been found earlier
266*c8dee2aaSAndroid Build Coastguard Worker         return;  // merge is already in the ptT loop
267*c8dee2aaSAndroid Build Coastguard Worker     }
268*c8dee2aaSAndroid Build Coastguard Worker     SkOpPtT* remainder = spanPtT->next();
269*c8dee2aaSAndroid Build Coastguard Worker     this->ptT()->insert(spanPtT);
270*c8dee2aaSAndroid Build Coastguard Worker     while (remainder != spanPtT) {
271*c8dee2aaSAndroid Build Coastguard Worker         SkOpPtT* next = remainder->next();
272*c8dee2aaSAndroid Build Coastguard Worker         SkOpPtT* compare = spanPtT->next();
273*c8dee2aaSAndroid Build Coastguard Worker         while (compare != spanPtT) {
274*c8dee2aaSAndroid Build Coastguard Worker             SkOpPtT* nextC = compare->next();
275*c8dee2aaSAndroid Build Coastguard Worker             if (nextC->span() == remainder->span() && nextC->fT == remainder->fT) {
276*c8dee2aaSAndroid Build Coastguard Worker                 goto tryNextRemainder;
277*c8dee2aaSAndroid Build Coastguard Worker             }
278*c8dee2aaSAndroid Build Coastguard Worker             compare = nextC;
279*c8dee2aaSAndroid Build Coastguard Worker         }
280*c8dee2aaSAndroid Build Coastguard Worker         spanPtT->insert(remainder);
281*c8dee2aaSAndroid Build Coastguard Worker tryNextRemainder:
282*c8dee2aaSAndroid Build Coastguard Worker         remainder = next;
283*c8dee2aaSAndroid Build Coastguard Worker     }
284*c8dee2aaSAndroid Build Coastguard Worker     fSpanAdds += span->fSpanAdds;
285*c8dee2aaSAndroid Build Coastguard Worker }
286*c8dee2aaSAndroid Build Coastguard Worker 
287*c8dee2aaSAndroid Build Coastguard Worker // please keep in sync with debugCheckForCollapsedCoincidence()
checkForCollapsedCoincidence()288*c8dee2aaSAndroid Build Coastguard Worker void SkOpSpanBase::checkForCollapsedCoincidence() {
289*c8dee2aaSAndroid Build Coastguard Worker     SkOpCoincidence* coins = this->globalState()->coincidence();
290*c8dee2aaSAndroid Build Coastguard Worker     if (coins->isEmpty()) {
291*c8dee2aaSAndroid Build Coastguard Worker         return;
292*c8dee2aaSAndroid Build Coastguard Worker     }
293*c8dee2aaSAndroid Build Coastguard Worker // the insert above may have put both ends of a coincident run in the same span
294*c8dee2aaSAndroid Build Coastguard Worker // for each coincident ptT in loop; see if its opposite in is also in the loop
295*c8dee2aaSAndroid Build Coastguard Worker // this implementation is the motivation for marking that a ptT is referenced by a coincident span
296*c8dee2aaSAndroid Build Coastguard Worker     SkOpPtT* head = this->ptT();
297*c8dee2aaSAndroid Build Coastguard Worker     SkOpPtT* test = head;
298*c8dee2aaSAndroid Build Coastguard Worker     do {
299*c8dee2aaSAndroid Build Coastguard Worker         if (!test->coincident()) {
300*c8dee2aaSAndroid Build Coastguard Worker             continue;
301*c8dee2aaSAndroid Build Coastguard Worker         }
302*c8dee2aaSAndroid Build Coastguard Worker         coins->markCollapsed(test);
303*c8dee2aaSAndroid Build Coastguard Worker     } while ((test = test->next()) != head);
304*c8dee2aaSAndroid Build Coastguard Worker     coins->releaseDeleted();
305*c8dee2aaSAndroid Build Coastguard Worker }
306*c8dee2aaSAndroid Build Coastguard Worker 
307*c8dee2aaSAndroid Build Coastguard Worker // please keep in sync with debugMergeMatches()
308*c8dee2aaSAndroid Build Coastguard Worker // Look to see if pt-t linked list contains same segment more than once
309*c8dee2aaSAndroid Build Coastguard Worker // if so, and if each pt-t is directly pointed to by spans in that segment,
310*c8dee2aaSAndroid Build Coastguard Worker // merge them
311*c8dee2aaSAndroid Build Coastguard Worker // keep the points, but remove spans so that the segment doesn't have 2 or more
312*c8dee2aaSAndroid Build Coastguard Worker // spans pointing to the same pt-t loop at different loop elements
mergeMatches(SkOpSpanBase * opp)313*c8dee2aaSAndroid Build Coastguard Worker bool SkOpSpanBase::mergeMatches(SkOpSpanBase* opp) {
314*c8dee2aaSAndroid Build Coastguard Worker     SkOpPtT* test = &fPtT;
315*c8dee2aaSAndroid Build Coastguard Worker     SkOpPtT* testNext;
316*c8dee2aaSAndroid Build Coastguard Worker     const SkOpPtT* stop = test;
317*c8dee2aaSAndroid Build Coastguard Worker     int safetyHatch = 1000000;
318*c8dee2aaSAndroid Build Coastguard Worker     do {
319*c8dee2aaSAndroid Build Coastguard Worker         if (!--safetyHatch) {
320*c8dee2aaSAndroid Build Coastguard Worker             return false;
321*c8dee2aaSAndroid Build Coastguard Worker         }
322*c8dee2aaSAndroid Build Coastguard Worker         testNext = test->next();
323*c8dee2aaSAndroid Build Coastguard Worker         if (test->deleted()) {
324*c8dee2aaSAndroid Build Coastguard Worker             continue;
325*c8dee2aaSAndroid Build Coastguard Worker         }
326*c8dee2aaSAndroid Build Coastguard Worker         SkOpSpanBase* testBase = test->span();
327*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(testBase->ptT() == test);
328*c8dee2aaSAndroid Build Coastguard Worker         SkOpSegment* segment = test->segment();
329*c8dee2aaSAndroid Build Coastguard Worker         if (segment->done()) {
330*c8dee2aaSAndroid Build Coastguard Worker             continue;
331*c8dee2aaSAndroid Build Coastguard Worker         }
332*c8dee2aaSAndroid Build Coastguard Worker         SkOpPtT* inner = opp->ptT();
333*c8dee2aaSAndroid Build Coastguard Worker         const SkOpPtT* innerStop = inner;
334*c8dee2aaSAndroid Build Coastguard Worker         do {
335*c8dee2aaSAndroid Build Coastguard Worker             if (inner->segment() != segment) {
336*c8dee2aaSAndroid Build Coastguard Worker                 continue;
337*c8dee2aaSAndroid Build Coastguard Worker             }
338*c8dee2aaSAndroid Build Coastguard Worker             if (inner->deleted()) {
339*c8dee2aaSAndroid Build Coastguard Worker                 continue;
340*c8dee2aaSAndroid Build Coastguard Worker             }
341*c8dee2aaSAndroid Build Coastguard Worker             SkOpSpanBase* innerBase = inner->span();
342*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(innerBase->ptT() == inner);
343*c8dee2aaSAndroid Build Coastguard Worker             // when the intersection is first detected, the span base is marked if there are
344*c8dee2aaSAndroid Build Coastguard Worker             // more than one point in the intersection.
345*c8dee2aaSAndroid Build Coastguard Worker             if (!zero_or_one(inner->fT)) {
346*c8dee2aaSAndroid Build Coastguard Worker                 innerBase->upCast()->release(test);
347*c8dee2aaSAndroid Build Coastguard Worker             } else {
348*c8dee2aaSAndroid Build Coastguard Worker                 SkOPASSERT(inner->fT != test->fT);
349*c8dee2aaSAndroid Build Coastguard Worker                 if (!zero_or_one(test->fT)) {
350*c8dee2aaSAndroid Build Coastguard Worker                     testBase->upCast()->release(inner);
351*c8dee2aaSAndroid Build Coastguard Worker                 } else {
352*c8dee2aaSAndroid Build Coastguard Worker                     segment->markAllDone();  // mark segment as collapsed
353*c8dee2aaSAndroid Build Coastguard Worker                     SkDEBUGCODE(testBase->debugSetDeleted());
354*c8dee2aaSAndroid Build Coastguard Worker                     test->setDeleted();
355*c8dee2aaSAndroid Build Coastguard Worker                     SkDEBUGCODE(innerBase->debugSetDeleted());
356*c8dee2aaSAndroid Build Coastguard Worker                     inner->setDeleted();
357*c8dee2aaSAndroid Build Coastguard Worker                 }
358*c8dee2aaSAndroid Build Coastguard Worker             }
359*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG   // assert if another undeleted entry points to segment
360*c8dee2aaSAndroid Build Coastguard Worker             const SkOpPtT* debugInner = inner;
361*c8dee2aaSAndroid Build Coastguard Worker             while ((debugInner = debugInner->next()) != innerStop) {
362*c8dee2aaSAndroid Build Coastguard Worker                 if (debugInner->segment() != segment) {
363*c8dee2aaSAndroid Build Coastguard Worker                     continue;
364*c8dee2aaSAndroid Build Coastguard Worker                 }
365*c8dee2aaSAndroid Build Coastguard Worker                 if (debugInner->deleted()) {
366*c8dee2aaSAndroid Build Coastguard Worker                     continue;
367*c8dee2aaSAndroid Build Coastguard Worker                 }
368*c8dee2aaSAndroid Build Coastguard Worker                 SkOPASSERT(0);
369*c8dee2aaSAndroid Build Coastguard Worker             }
370*c8dee2aaSAndroid Build Coastguard Worker #endif
371*c8dee2aaSAndroid Build Coastguard Worker             break;
372*c8dee2aaSAndroid Build Coastguard Worker         } while ((inner = inner->next()) != innerStop);
373*c8dee2aaSAndroid Build Coastguard Worker     } while ((test = testNext) != stop);
374*c8dee2aaSAndroid Build Coastguard Worker     this->checkForCollapsedCoincidence();
375*c8dee2aaSAndroid Build Coastguard Worker     return true;
376*c8dee2aaSAndroid Build Coastguard Worker }
377*c8dee2aaSAndroid Build Coastguard Worker 
computeWindSum()378*c8dee2aaSAndroid Build Coastguard Worker int SkOpSpan::computeWindSum() {
379*c8dee2aaSAndroid Build Coastguard Worker     SkOpGlobalState* globals = this->globalState();
380*c8dee2aaSAndroid Build Coastguard Worker     SkOpContour* contourHead = globals->contourHead();
381*c8dee2aaSAndroid Build Coastguard Worker     int windTry = 0;
382*c8dee2aaSAndroid Build Coastguard Worker     while (!this->sortableTop(contourHead) && ++windTry < SkOpGlobalState::kMaxWindingTries) {
383*c8dee2aaSAndroid Build Coastguard Worker     }
384*c8dee2aaSAndroid Build Coastguard Worker     return this->windSum();
385*c8dee2aaSAndroid Build Coastguard Worker }
386*c8dee2aaSAndroid Build Coastguard Worker 
containsCoincidence(const SkOpSegment * segment) const387*c8dee2aaSAndroid Build Coastguard Worker bool SkOpSpan::containsCoincidence(const SkOpSegment* segment) const {
388*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(this->segment() != segment);
389*c8dee2aaSAndroid Build Coastguard Worker     const SkOpSpan* next = fCoincident;
390*c8dee2aaSAndroid Build Coastguard Worker     do {
391*c8dee2aaSAndroid Build Coastguard Worker         if (next->segment() == segment) {
392*c8dee2aaSAndroid Build Coastguard Worker             return true;
393*c8dee2aaSAndroid Build Coastguard Worker         }
394*c8dee2aaSAndroid Build Coastguard Worker     } while ((next = next->fCoincident) != this);
395*c8dee2aaSAndroid Build Coastguard Worker     return false;
396*c8dee2aaSAndroid Build Coastguard Worker }
397*c8dee2aaSAndroid Build Coastguard Worker 
init(SkOpSegment * segment,SkOpSpan * prev,double t,const SkPoint & pt)398*c8dee2aaSAndroid Build Coastguard Worker void SkOpSpan::init(SkOpSegment* segment, SkOpSpan* prev, double t, const SkPoint& pt) {
399*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(t != 1);
400*c8dee2aaSAndroid Build Coastguard Worker     initBase(segment, prev, t, pt);
401*c8dee2aaSAndroid Build Coastguard Worker     fCoincident = this;
402*c8dee2aaSAndroid Build Coastguard Worker     fToAngle = nullptr;
403*c8dee2aaSAndroid Build Coastguard Worker     fWindSum = fOppSum = SK_MinS32;
404*c8dee2aaSAndroid Build Coastguard Worker     fWindValue = 1;
405*c8dee2aaSAndroid Build Coastguard Worker     fOppValue = 0;
406*c8dee2aaSAndroid Build Coastguard Worker     fTopTTry = 0;
407*c8dee2aaSAndroid Build Coastguard Worker     fChased = fDone = false;
408*c8dee2aaSAndroid Build Coastguard Worker     segment->bumpCount();
409*c8dee2aaSAndroid Build Coastguard Worker     fAlreadyAdded = false;
410*c8dee2aaSAndroid Build Coastguard Worker }
411*c8dee2aaSAndroid Build Coastguard Worker 
412*c8dee2aaSAndroid Build Coastguard Worker // Please keep this in sync with debugInsertCoincidence()
insertCoincidence(const SkOpSegment * segment,bool flipped,bool ordered)413*c8dee2aaSAndroid Build Coastguard Worker bool SkOpSpan::insertCoincidence(const SkOpSegment* segment, bool flipped, bool ordered) {
414*c8dee2aaSAndroid Build Coastguard Worker     if (this->containsCoincidence(segment)) {
415*c8dee2aaSAndroid Build Coastguard Worker         return true;
416*c8dee2aaSAndroid Build Coastguard Worker     }
417*c8dee2aaSAndroid Build Coastguard Worker     SkOpPtT* next = &fPtT;
418*c8dee2aaSAndroid Build Coastguard Worker     while ((next = next->next()) != &fPtT) {
419*c8dee2aaSAndroid Build Coastguard Worker         if (next->segment() == segment) {
420*c8dee2aaSAndroid Build Coastguard Worker             SkOpSpan* span;
421*c8dee2aaSAndroid Build Coastguard Worker             SkOpSpanBase* base = next->span();
422*c8dee2aaSAndroid Build Coastguard Worker             if (!ordered) {
423*c8dee2aaSAndroid Build Coastguard Worker                 const SkOpPtT* spanEndPtT = fNext->contains(segment);
424*c8dee2aaSAndroid Build Coastguard Worker                 FAIL_IF(!spanEndPtT);
425*c8dee2aaSAndroid Build Coastguard Worker                 const SkOpSpanBase* spanEnd = spanEndPtT->span();
426*c8dee2aaSAndroid Build Coastguard Worker                 const SkOpPtT* start = base->ptT()->starter(spanEnd->ptT());
427*c8dee2aaSAndroid Build Coastguard Worker                 FAIL_IF(!start->span()->upCastable());
428*c8dee2aaSAndroid Build Coastguard Worker                 span = const_cast<SkOpSpan*>(start->span()->upCast());
429*c8dee2aaSAndroid Build Coastguard Worker             } else if (flipped) {
430*c8dee2aaSAndroid Build Coastguard Worker                 span = base->prev();
431*c8dee2aaSAndroid Build Coastguard Worker                 FAIL_IF(!span);
432*c8dee2aaSAndroid Build Coastguard Worker             } else {
433*c8dee2aaSAndroid Build Coastguard Worker                 FAIL_IF(!base->upCastable());
434*c8dee2aaSAndroid Build Coastguard Worker                 span = base->upCast();
435*c8dee2aaSAndroid Build Coastguard Worker             }
436*c8dee2aaSAndroid Build Coastguard Worker             this->insertCoincidence(span);
437*c8dee2aaSAndroid Build Coastguard Worker             return true;
438*c8dee2aaSAndroid Build Coastguard Worker         }
439*c8dee2aaSAndroid Build Coastguard Worker     }
440*c8dee2aaSAndroid Build Coastguard Worker #if DEBUG_COINCIDENCE
441*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(0); // FIXME? if we get here, the span is missing its opposite segment...
442*c8dee2aaSAndroid Build Coastguard Worker #endif
443*c8dee2aaSAndroid Build Coastguard Worker     return true;
444*c8dee2aaSAndroid Build Coastguard Worker }
445*c8dee2aaSAndroid Build Coastguard Worker 
release(const SkOpPtT * kept)446*c8dee2aaSAndroid Build Coastguard Worker void SkOpSpan::release(const SkOpPtT* kept) {
447*c8dee2aaSAndroid Build Coastguard Worker     SkDEBUGCODE(fDebugDeleted = true);
448*c8dee2aaSAndroid Build Coastguard Worker     SkOPASSERT(kept->span() != this);
449*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(!final());
450*c8dee2aaSAndroid Build Coastguard Worker     SkOpSpan* prev = this->prev();
451*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(prev);
452*c8dee2aaSAndroid Build Coastguard Worker     SkOpSpanBase* next = this->next();
453*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(next);
454*c8dee2aaSAndroid Build Coastguard Worker     prev->setNext(next);
455*c8dee2aaSAndroid Build Coastguard Worker     next->setPrev(prev);
456*c8dee2aaSAndroid Build Coastguard Worker     this->segment()->release(this);
457*c8dee2aaSAndroid Build Coastguard Worker     SkOpCoincidence* coincidence = this->globalState()->coincidence();
458*c8dee2aaSAndroid Build Coastguard Worker     if (coincidence) {
459*c8dee2aaSAndroid Build Coastguard Worker         coincidence->fixUp(this->ptT(), kept);
460*c8dee2aaSAndroid Build Coastguard Worker     }
461*c8dee2aaSAndroid Build Coastguard Worker     this->ptT()->setDeleted();
462*c8dee2aaSAndroid Build Coastguard Worker     SkOpPtT* stopPtT = this->ptT();
463*c8dee2aaSAndroid Build Coastguard Worker     SkOpPtT* testPtT = stopPtT;
464*c8dee2aaSAndroid Build Coastguard Worker     const SkOpSpanBase* keptSpan = kept->span();
465*c8dee2aaSAndroid Build Coastguard Worker     do {
466*c8dee2aaSAndroid Build Coastguard Worker         if (this == testPtT->span()) {
467*c8dee2aaSAndroid Build Coastguard Worker             testPtT->setSpan(keptSpan);
468*c8dee2aaSAndroid Build Coastguard Worker         }
469*c8dee2aaSAndroid Build Coastguard Worker     } while ((testPtT = testPtT->next()) != stopPtT);
470*c8dee2aaSAndroid Build Coastguard Worker }
471*c8dee2aaSAndroid Build Coastguard Worker 
setOppSum(int oppSum)472*c8dee2aaSAndroid Build Coastguard Worker void SkOpSpan::setOppSum(int oppSum) {
473*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(!final());
474*c8dee2aaSAndroid Build Coastguard Worker     if (fOppSum != SK_MinS32 && fOppSum != oppSum) {
475*c8dee2aaSAndroid Build Coastguard Worker         this->globalState()->setWindingFailed();
476*c8dee2aaSAndroid Build Coastguard Worker         return;
477*c8dee2aaSAndroid Build Coastguard Worker     }
478*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(oppSum) <= DEBUG_LIMIT_WIND_SUM);
479*c8dee2aaSAndroid Build Coastguard Worker     fOppSum = oppSum;
480*c8dee2aaSAndroid Build Coastguard Worker }
481*c8dee2aaSAndroid Build Coastguard Worker 
setWindSum(int windSum)482*c8dee2aaSAndroid Build Coastguard Worker void SkOpSpan::setWindSum(int windSum) {
483*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(!final());
484*c8dee2aaSAndroid Build Coastguard Worker     if (fWindSum != SK_MinS32 && fWindSum != windSum) {
485*c8dee2aaSAndroid Build Coastguard Worker         this->globalState()->setWindingFailed();
486*c8dee2aaSAndroid Build Coastguard Worker         return;
487*c8dee2aaSAndroid Build Coastguard Worker     }
488*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(windSum) <= DEBUG_LIMIT_WIND_SUM);
489*c8dee2aaSAndroid Build Coastguard Worker     fWindSum = windSum;
490*c8dee2aaSAndroid Build Coastguard Worker }
491