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