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