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