blob: 93d0e403ffda8f1819aab8dec0418c9b6954dff0 [file] [log] [blame]
caryclark54359292015-03-26 07:52:43 -07001/*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7#include "SkOpCoincidence.h"
8#include "SkOpSegment.h"
9#include "SkPathOpsTSect.h"
10
caryclark55888e42016-07-18 10:01:36 -070011// returns true if coincident span's start and end are the same
12bool SkCoincidentSpans::collapsed(const SkOpPtT* test) const {
13 return (fCoinPtTStart == test && fCoinPtTEnd->contains(test))
14 || (fCoinPtTEnd == test && fCoinPtTStart->contains(test))
15 || (fOppPtTStart == test && fOppPtTEnd->contains(test))
16 || (fOppPtTEnd == test && fOppPtTStart->contains(test));
17}
18
Cary Clarkdb8f44f2016-12-15 09:17:31 -050019// out of line since this function is referenced by address
20const SkOpPtT* SkCoincidentSpans::coinPtTEnd() const {
21 return fCoinPtTEnd;
22}
23
24// out of line since this function is referenced by address
25const SkOpPtT* SkCoincidentSpans::coinPtTStart() const {
26 return fCoinPtTStart;
27}
28
caryclark55888e42016-07-18 10:01:36 -070029// sets the span's end to the ptT referenced by the previous-next
30void SkCoincidentSpans::correctOneEnd(
31 const SkOpPtT* (SkCoincidentSpans::* getEnd)() const,
32 void (SkCoincidentSpans::*setEnd)(const SkOpPtT* ptT) ) {
33 const SkOpPtT* origPtT = (this->*getEnd)();
34 const SkOpSpanBase* origSpan = origPtT->span();
35 const SkOpSpan* prev = origSpan->prev();
36 const SkOpPtT* testPtT = prev ? prev->next()->ptT()
37 : origSpan->upCast()->next()->prev()->ptT();
38 if (origPtT != testPtT) {
39 (this->*setEnd)(testPtT);
caryclarkbca19f72015-05-13 08:23:48 -070040 }
caryclark55888e42016-07-18 10:01:36 -070041}
42
Cary Clarkab87d7a2016-10-04 10:01:04 -040043/* Please keep this in sync with debugCorrectEnds */
caryclark55888e42016-07-18 10:01:36 -070044// FIXME: member pointers have fallen out of favor and can be replaced with
45// an alternative approach.
46// makes all span ends agree with the segment's spans that define them
47void SkCoincidentSpans::correctEnds() {
48 this->correctOneEnd(&SkCoincidentSpans::coinPtTStart, &SkCoincidentSpans::setCoinPtTStart);
49 this->correctOneEnd(&SkCoincidentSpans::coinPtTEnd, &SkCoincidentSpans::setCoinPtTEnd);
50 this->correctOneEnd(&SkCoincidentSpans::oppPtTStart, &SkCoincidentSpans::setOppPtTStart);
51 this->correctOneEnd(&SkCoincidentSpans::oppPtTEnd, &SkCoincidentSpans::setOppPtTEnd);
52}
53
54/* Please keep this in sync with debugExpand */
55// expand the range by checking adjacent spans for coincidence
56bool SkCoincidentSpans::expand() {
57 bool expanded = false;
58 const SkOpSegment* segment = coinPtTStart()->segment();
59 const SkOpSegment* oppSegment = oppPtTStart()->segment();
60 do {
61 const SkOpSpan* start = coinPtTStart()->span()->upCast();
62 const SkOpSpan* prev = start->prev();
63 const SkOpPtT* oppPtT;
64 if (!prev || !(oppPtT = prev->contains(oppSegment))) {
65 break;
66 }
67 double midT = (prev->t() + start->t()) / 2;
68 if (!segment->isClose(midT, oppSegment)) {
69 break;
70 }
71 setStarts(prev->ptT(), oppPtT);
72 expanded = true;
73 } while (true);
74 do {
75 const SkOpSpanBase* end = coinPtTEnd()->span();
76 SkOpSpanBase* next = end->final() ? nullptr : end->upCast()->next();
caryclarkc6d855f2016-08-11 11:59:48 -070077 if (next && next->deleted()) {
78 break;
79 }
caryclark55888e42016-07-18 10:01:36 -070080 const SkOpPtT* oppPtT;
81 if (!next || !(oppPtT = next->contains(oppSegment))) {
82 break;
83 }
84 double midT = (end->t() + next->t()) / 2;
85 if (!segment->isClose(midT, oppSegment)) {
86 break;
87 }
88 setEnds(next->ptT(), oppPtT);
89 expanded = true;
90 } while (true);
91 return expanded;
92}
93
94// increase the range of this span
95bool SkCoincidentSpans::extend(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd,
96 const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) {
97 bool result = false;
98 if (fCoinPtTStart->fT > coinPtTStart->fT || (this->flipped()
99 ? fOppPtTStart->fT < oppPtTStart->fT : fOppPtTStart->fT > oppPtTStart->fT)) {
100 this->setStarts(coinPtTStart, oppPtTStart);
101 result = true;
102 }
103 if (fCoinPtTEnd->fT < coinPtTEnd->fT || (this->flipped()
104 ? fOppPtTEnd->fT > oppPtTEnd->fT : fOppPtTEnd->fT < oppPtTEnd->fT)) {
105 this->setEnds(coinPtTEnd, oppPtTEnd);
106 result = true;
107 }
108 return result;
109}
110
111// set the range of this span
112void SkCoincidentSpans::set(SkCoincidentSpans* next, const SkOpPtT* coinPtTStart,
Cary Clarkab87d7a2016-10-04 10:01:04 -0400113 const SkOpPtT* coinPtTEnd, const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) {
caryclark55888e42016-07-18 10:01:36 -0700114 SkASSERT(SkOpCoincidence::Ordered(coinPtTStart, oppPtTStart));
115 fNext = next;
116 this->setStarts(coinPtTStart, oppPtTStart);
117 this->setEnds(coinPtTEnd, oppPtTEnd);
caryclark55888e42016-07-18 10:01:36 -0700118}
119
120// returns true if both points are inside this
121bool SkCoincidentSpans::contains(const SkOpPtT* s, const SkOpPtT* e) const {
122 if (s->fT > e->fT) {
123 SkTSwap(s, e);
124 }
125 if (s->segment() == fCoinPtTStart->segment()) {
126 return fCoinPtTStart->fT <= s->fT && e->fT <= fCoinPtTEnd->fT;
127 } else {
128 SkASSERT(s->segment() == fOppPtTStart->segment());
129 double oppTs = fOppPtTStart->fT;
130 double oppTe = fOppPtTEnd->fT;
131 if (oppTs > oppTe) {
132 SkTSwap(oppTs, oppTe);
133 }
134 return oppTs <= s->fT && e->fT <= oppTe;
135 }
136}
137
Cary Clarkdb8f44f2016-12-15 09:17:31 -0500138// out of line since this function is referenced by address
139const SkOpPtT* SkCoincidentSpans::oppPtTStart() const {
140 return fOppPtTStart;
141}
142
143// out of line since this function is referenced by address
144const SkOpPtT* SkCoincidentSpans::oppPtTEnd() const {
145 return fOppPtTEnd;
146}
147
caryclark81a478c2016-09-09 09:37:57 -0700148// A coincident span is unordered if the pairs of points in the main and opposite curves'
149// t values do not ascend or descend. For instance, if a tightly arced quadratic is
150// coincident with another curve, it may intersect it out of order.
caryclarka35ab3e2016-10-20 08:32:18 -0700151bool SkCoincidentSpans::ordered(bool* result) const {
caryclark81a478c2016-09-09 09:37:57 -0700152 const SkOpSpanBase* start = this->coinPtTStart()->span();
153 const SkOpSpanBase* end = this->coinPtTEnd()->span();
154 const SkOpSpanBase* next = start->upCast()->next();
155 if (next == end) {
caryclarka35ab3e2016-10-20 08:32:18 -0700156 *result = true;
caryclark81a478c2016-09-09 09:37:57 -0700157 return true;
158 }
159 bool flipped = this->flipped();
160 const SkOpSegment* oppSeg = this->oppPtTStart()->segment();
161 double oppLastT = fOppPtTStart->fT;
162 do {
163 const SkOpPtT* opp = next->contains(oppSeg);
164 if (!opp) {
Cary Clarkab2d73b2016-12-16 17:17:25 -0500165// SkOPOBJASSERT(start, 0); // may assert if coincident span isn't fully processed
caryclarka35ab3e2016-10-20 08:32:18 -0700166 return false;
caryclark81a478c2016-09-09 09:37:57 -0700167 }
168 if ((oppLastT > opp->fT) != flipped) {
caryclarka35ab3e2016-10-20 08:32:18 -0700169 *result = false;
170 return true;
caryclark81a478c2016-09-09 09:37:57 -0700171 }
172 oppLastT = opp->fT;
173 if (next == end) {
174 break;
175 }
caryclarkbbfe92b2016-09-19 06:00:35 -0700176 if (!next->upCastable()) {
caryclarka35ab3e2016-10-20 08:32:18 -0700177 *result = false;
178 return true;
caryclarkbbfe92b2016-09-19 06:00:35 -0700179 }
caryclark81a478c2016-09-09 09:37:57 -0700180 next = next->upCast()->next();
181 } while (true);
caryclarka35ab3e2016-10-20 08:32:18 -0700182 *result = true;
caryclark81a478c2016-09-09 09:37:57 -0700183 return true;
184}
185
caryclark55888e42016-07-18 10:01:36 -0700186// if there is an existing pair that overlaps the addition, extend it
187bool SkOpCoincidence::extend(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd,
188 const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) {
189 SkCoincidentSpans* test = fHead;
190 if (!test) {
191 return false;
192 }
193 const SkOpSegment* coinSeg = coinPtTStart->segment();
194 const SkOpSegment* oppSeg = oppPtTStart->segment();
195 if (!Ordered(coinPtTStart, oppPtTStart)) {
196 SkTSwap(coinSeg, oppSeg);
197 SkTSwap(coinPtTStart, oppPtTStart);
198 SkTSwap(coinPtTEnd, oppPtTEnd);
199 if (coinPtTStart->fT > coinPtTEnd->fT) {
200 SkTSwap(coinPtTStart, coinPtTEnd);
201 SkTSwap(oppPtTStart, oppPtTEnd);
202 }
203 }
204 double oppMinT = SkTMin(oppPtTStart->fT, oppPtTEnd->fT);
205 SkDEBUGCODE(double oppMaxT = SkTMax(oppPtTStart->fT, oppPtTEnd->fT));
206 do {
207 if (coinSeg != test->coinPtTStart()->segment()) {
208 continue;
209 }
210 if (oppSeg != test->oppPtTStart()->segment()) {
211 continue;
212 }
213 double oTestMinT = SkTMin(test->oppPtTStart()->fT, test->oppPtTEnd()->fT);
214 double oTestMaxT = SkTMax(test->oppPtTStart()->fT, test->oppPtTEnd()->fT);
215 // if debug check triggers, caller failed to check if extended already exists
216 SkASSERT(test->coinPtTStart()->fT > coinPtTStart->fT
217 || coinPtTEnd->fT > test->coinPtTEnd()->fT
218 || oTestMinT > oppMinT || oppMaxT > oTestMaxT);
219 if ((test->coinPtTStart()->fT <= coinPtTEnd->fT
220 && coinPtTStart->fT <= test->coinPtTEnd()->fT)
221 || (oTestMinT <= oTestMaxT && oppMinT <= oTestMaxT)) {
222 test->extend(coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd);
223 return true;
224 }
225 } while ((test = test->next()));
226 return false;
caryclark54359292015-03-26 07:52:43 -0700227}
228
caryclark55888e42016-07-18 10:01:36 -0700229// verifies that the coincidence hasn't already been added
230static void DebugCheckAdd(const SkCoincidentSpans* check, const SkOpPtT* coinPtTStart,
231 const SkOpPtT* coinPtTEnd, const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) {
232#if DEBUG_COINCIDENCE
233 while (check) {
234 SkASSERT(check->coinPtTStart() != coinPtTStart || check->coinPtTEnd() != coinPtTEnd
235 || check->oppPtTStart() != oppPtTStart || check->oppPtTEnd() != oppPtTEnd);
236 SkASSERT(check->coinPtTStart() != oppPtTStart || check->coinPtTEnd() != oppPtTEnd
237 || check->oppPtTStart() != coinPtTStart || check->oppPtTEnd() != coinPtTEnd);
238 check = check->next();
239 }
240#endif
241}
242
243// adds a new coincident pair
244void SkOpCoincidence::add(SkOpPtT* coinPtTStart, SkOpPtT* coinPtTEnd, SkOpPtT* oppPtTStart,
245 SkOpPtT* oppPtTEnd) {
246 // OPTIMIZE: caller should have already sorted
247 if (!Ordered(coinPtTStart, oppPtTStart)) {
248 if (oppPtTStart->fT < oppPtTEnd->fT) {
249 this->add(oppPtTStart, oppPtTEnd, coinPtTStart, coinPtTEnd);
250 } else {
251 this->add(oppPtTEnd, oppPtTStart, coinPtTEnd, coinPtTStart);
252 }
253 return;
254 }
255 SkASSERT(Ordered(coinPtTStart, oppPtTStart));
256 // choose the ptT at the front of the list to track
257 coinPtTStart = coinPtTStart->span()->ptT();
258 coinPtTEnd = coinPtTEnd->span()->ptT();
259 oppPtTStart = oppPtTStart->span()->ptT();
260 oppPtTEnd = oppPtTEnd->span()->ptT();
caryclarka35ab3e2016-10-20 08:32:18 -0700261 SkOPASSERT(coinPtTStart->fT < coinPtTEnd->fT);
caryclark96dc1c92016-10-20 11:34:10 -0700262 SkOPASSERT(oppPtTStart->fT != oppPtTEnd->fT);
caryclark30b9fdd2016-08-31 14:36:29 -0700263 SkOPASSERT(!coinPtTStart->deleted());
264 SkOPASSERT(!coinPtTEnd->deleted());
265 SkOPASSERT(!oppPtTStart->deleted());
266 SkOPASSERT(!oppPtTEnd->deleted());
caryclark55888e42016-07-18 10:01:36 -0700267 DebugCheckAdd(fHead, coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd);
268 DebugCheckAdd(fTop, coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd);
Herb Derbyecc364c2017-04-19 15:09:48 -0400269 SkCoincidentSpans* coinRec = this->globalState()->allocator()->make<SkCoincidentSpans>();
caryclarkfc560e02016-07-27 08:46:10 -0700270 coinRec->init(SkDEBUGCODE(fGlobalState));
Cary Clarkab87d7a2016-10-04 10:01:04 -0400271 coinRec->set(this->fHead, coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd);
caryclark55888e42016-07-18 10:01:36 -0700272 fHead = coinRec;
273}
274
275// description below
caryclark15976282016-07-21 05:48:43 -0700276bool SkOpCoincidence::addEndMovedSpans(const SkOpSpan* base, const SkOpSpanBase* testSpan) {
caryclark55888e42016-07-18 10:01:36 -0700277 const SkOpPtT* testPtT = testSpan->ptT();
278 const SkOpPtT* stopPtT = testPtT;
279 const SkOpSegment* baseSeg = base->segment();
Cary Clark4eed4c82017-03-08 17:11:12 -0500280 int escapeHatch = 100000; // this is 100 times larger than the debugLoopLimit test
caryclark55888e42016-07-18 10:01:36 -0700281 while ((testPtT = testPtT->next()) != stopPtT) {
Cary Clark4eed4c82017-03-08 17:11:12 -0500282 if (--escapeHatch <= 0) {
283 return false; // if triggered (likely by a fuzz-generated test) too complex to succeed
284 }
caryclark55888e42016-07-18 10:01:36 -0700285 const SkOpSegment* testSeg = testPtT->segment();
286 if (testPtT->deleted()) {
287 continue;
288 }
289 if (testSeg == baseSeg) {
290 continue;
291 }
caryclarkc6d855f2016-08-11 11:59:48 -0700292 if (testPtT->span()->ptT() != testPtT) {
293 continue;
294 }
caryclark55888e42016-07-18 10:01:36 -0700295 if (this->contains(baseSeg, testSeg, testPtT->fT)) {
296 continue;
297 }
298 // intersect perp with base->ptT() with testPtT->segment()
299 SkDVector dxdy = baseSeg->dSlopeAtT(base->t());
300 const SkPoint& pt = base->pt();
301 SkDLine ray = {{{pt.fX, pt.fY}, {pt.fX + dxdy.fY, pt.fY - dxdy.fX}}};
Cary Clark4c76c412017-01-20 08:14:33 -0500302 SkIntersections i SkDEBUGCODE((this->globalState()));
caryclark55888e42016-07-18 10:01:36 -0700303 (*CurveIntersectRay[testSeg->verb()])(testSeg->pts(), testSeg->weight(), ray, &i);
304 for (int index = 0; index < i.used(); ++index) {
305 double t = i[0][index];
306 if (!between(0, t, 1)) {
307 continue;
308 }
309 SkDPoint oppPt = i.pt(index);
310 if (!oppPt.approximatelyEqual(pt)) {
311 continue;
312 }
313 SkOpSegment* writableSeg = const_cast<SkOpSegment*>(testSeg);
caryclark29b25632016-08-25 11:27:17 -0700314 SkOpPtT* oppStart = writableSeg->addT(t);
caryclark27c015d2016-09-23 05:47:20 -0700315 if (oppStart == testPtT) {
316 continue;
317 }
caryclark55888e42016-07-18 10:01:36 -0700318 SkOpSpan* writableBase = const_cast<SkOpSpan*>(base);
caryclark30b9fdd2016-08-31 14:36:29 -0700319 oppStart->span()->addOpp(writableBase);
caryclark55888e42016-07-18 10:01:36 -0700320 if (oppStart->deleted()) {
321 continue;
322 }
323 SkOpSegment* coinSeg = base->segment();
324 SkOpSegment* oppSeg = oppStart->segment();
325 double coinTs, coinTe, oppTs, oppTe;
caryclark8016b262016-09-06 05:59:47 -0700326 if (Ordered(coinSeg, oppSeg)) {
caryclark55888e42016-07-18 10:01:36 -0700327 coinTs = base->t();
328 coinTe = testSpan->t();
329 oppTs = oppStart->fT;
330 oppTe = testPtT->fT;
331 } else {
332 SkTSwap(coinSeg, oppSeg);
333 coinTs = oppStart->fT;
334 coinTe = testPtT->fT;
335 oppTs = base->t();
336 oppTe = testSpan->t();
337 }
338 if (coinTs > coinTe) {
339 SkTSwap(coinTs, coinTe);
340 SkTSwap(oppTs, oppTe);
341 }
caryclark81a478c2016-09-09 09:37:57 -0700342 bool added;
343 if (!this->addOrOverlap(coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, &added)) {
caryclark15976282016-07-21 05:48:43 -0700344 return false;
345 }
caryclark55888e42016-07-18 10:01:36 -0700346 }
347 }
caryclark15976282016-07-21 05:48:43 -0700348 return true;
caryclark55888e42016-07-18 10:01:36 -0700349}
350
351// description below
352bool SkOpCoincidence::addEndMovedSpans(const SkOpPtT* ptT) {
caryclark025b11e2016-08-25 05:21:14 -0700353 FAIL_IF(!ptT->span()->upCastable());
caryclark55888e42016-07-18 10:01:36 -0700354 const SkOpSpan* base = ptT->span()->upCast();
355 const SkOpSpan* prev = base->prev();
caryclark025b11e2016-08-25 05:21:14 -0700356 FAIL_IF(!prev);
caryclark55888e42016-07-18 10:01:36 -0700357 if (!prev->isCanceled()) {
caryclark15976282016-07-21 05:48:43 -0700358 if (!this->addEndMovedSpans(base, base->prev())) {
359 return false;
360 }
caryclark55888e42016-07-18 10:01:36 -0700361 }
362 if (!base->isCanceled()) {
caryclark15976282016-07-21 05:48:43 -0700363 if (!this->addEndMovedSpans(base, base->next())) {
364 return false;
365 }
caryclark55888e42016-07-18 10:01:36 -0700366 }
367 return true;
368}
369
370/* If A is coincident with B and B includes an endpoint, and A's matching point
371 is not the endpoint (i.e., there's an implied line connecting B-end and A)
372 then assume that the same implied line may intersect another curve close to B.
373 Since we only care about coincidence that was undetected, look at the
374 ptT list on B-segment adjacent to the B-end/A ptT loop (not in the loop, but
375 next door) and see if the A matching point is close enough to form another
376 coincident pair. If so, check for a new coincident span between B-end/A ptT loop
377 and the adjacent ptT loop.
378*/
Cary Clarkab87d7a2016-10-04 10:01:04 -0400379bool SkOpCoincidence::addEndMovedSpans(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
380 DEBUG_SET_PHASE();
caryclark55888e42016-07-18 10:01:36 -0700381 SkCoincidentSpans* span = fHead;
382 if (!span) {
383 return true;
384 }
385 fTop = span;
386 fHead = nullptr;
387 do {
388 if (span->coinPtTStart()->fPt != span->oppPtTStart()->fPt) {
caryclark025b11e2016-08-25 05:21:14 -0700389 FAIL_IF(1 == span->coinPtTStart()->fT);
caryclark55888e42016-07-18 10:01:36 -0700390 bool onEnd = span->coinPtTStart()->fT == 0;
391 bool oOnEnd = zero_or_one(span->oppPtTStart()->fT);
392 if (onEnd) {
393 if (!oOnEnd) { // if both are on end, any nearby intersect was already found
394 if (!this->addEndMovedSpans(span->oppPtTStart())) {
395 return false;
396 }
397 }
398 } else if (oOnEnd) {
399 if (!this->addEndMovedSpans(span->coinPtTStart())) {
400 return false;
401 }
402 }
403 }
404 if (span->coinPtTEnd()->fPt != span->oppPtTEnd()->fPt) {
405 bool onEnd = span->coinPtTEnd()->fT == 1;
406 bool oOnEnd = zero_or_one(span->oppPtTEnd()->fT);
407 if (onEnd) {
408 if (!oOnEnd) {
409 if (!this->addEndMovedSpans(span->oppPtTEnd())) {
410 return false;
411 }
412 }
413 } else if (oOnEnd) {
414 if (!this->addEndMovedSpans(span->coinPtTEnd())) {
415 return false;
416 }
417 }
418 }
419 } while ((span = span->next()));
420 this->restoreHead();
421 return true;
422}
423
424/* Please keep this in sync with debugAddExpanded */
425// for each coincident pair, match the spans
426// if the spans don't match, add the missing pt to the segment and loop it in the opposite span
Cary Clarkab87d7a2016-10-04 10:01:04 -0400427bool SkOpCoincidence::addExpanded(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
428 DEBUG_SET_PHASE();
caryclark55888e42016-07-18 10:01:36 -0700429 SkCoincidentSpans* coin = this->fHead;
430 if (!coin) {
431 return true;
432 }
433 do {
434 const SkOpPtT* startPtT = coin->coinPtTStart();
435 const SkOpPtT* oStartPtT = coin->oppPtTStart();
caryclark8016b262016-09-06 05:59:47 -0700436 double priorT = startPtT->fT;
437 double oPriorT = oStartPtT->fT;
caryclarkbbfe92b2016-09-19 06:00:35 -0700438 FAIL_IF(!startPtT->contains(oStartPtT));
caryclarkc6d855f2016-08-11 11:59:48 -0700439 SkOPASSERT(coin->coinPtTEnd()->contains(coin->oppPtTEnd()));
caryclark55888e42016-07-18 10:01:36 -0700440 const SkOpSpanBase* start = startPtT->span();
441 const SkOpSpanBase* oStart = oStartPtT->span();
442 const SkOpSpanBase* end = coin->coinPtTEnd()->span();
443 const SkOpSpanBase* oEnd = coin->oppPtTEnd()->span();
444 FAIL_IF(oEnd->deleted());
caryclarke25a4f62016-07-26 09:26:29 -0700445 FAIL_IF(!start->upCastable());
caryclark55888e42016-07-18 10:01:36 -0700446 const SkOpSpanBase* test = start->upCast()->next();
caryclarke7bb5b22016-09-22 05:20:07 -0700447 FAIL_IF(!coin->flipped() && !oStart->upCastable());
caryclark55888e42016-07-18 10:01:36 -0700448 const SkOpSpanBase* oTest = coin->flipped() ? oStart->prev() : oStart->upCast()->next();
caryclark30b9fdd2016-08-31 14:36:29 -0700449 FAIL_IF(!oTest);
caryclark8016b262016-09-06 05:59:47 -0700450 SkOpSegment* seg = start->segment();
451 SkOpSegment* oSeg = oStart->segment();
caryclark55888e42016-07-18 10:01:36 -0700452 while (test != end || oTest != oEnd) {
caryclark8016b262016-09-06 05:59:47 -0700453 const SkOpPtT* containedOpp = test->ptT()->contains(oSeg);
454 const SkOpPtT* containedThis = oTest->ptT()->contains(seg);
455 if (!containedOpp || !containedThis) {
456 // choose the ends, or the first common pt-t list shared by both
457 double nextT, oNextT;
458 if (containedOpp) {
459 nextT = test->t();
460 oNextT = containedOpp->fT;
461 } else if (containedThis) {
462 nextT = containedThis->fT;
463 oNextT = oTest->t();
464 } else {
465 // iterate through until a pt-t list found that contains the other
466 const SkOpSpanBase* walk = test;
467 const SkOpPtT* walkOpp;
468 do {
469 FAIL_IF(!walk->upCastable());
470 walk = walk->upCast()->next();
471 } while (!(walkOpp = walk->ptT()->contains(oSeg))
472 && walk != coin->coinPtTEnd()->span());
Cary Clark3fdf52c2016-10-04 10:53:31 -0400473 FAIL_IF(!walkOpp);
caryclark8016b262016-09-06 05:59:47 -0700474 nextT = walk->t();
475 oNextT = walkOpp->fT;
476 }
caryclark55888e42016-07-18 10:01:36 -0700477 // use t ranges to guess which one is missing
caryclark8016b262016-09-06 05:59:47 -0700478 double startRange = nextT - priorT;
caryclark55888e42016-07-18 10:01:36 -0700479 FAIL_IF(!startRange);
caryclark8016b262016-09-06 05:59:47 -0700480 double startPart = (test->t() - priorT) / startRange;
481 double oStartRange = oNextT - oPriorT;
caryclark55888e42016-07-18 10:01:36 -0700482 FAIL_IF(!oStartRange);
caryclark8016b262016-09-06 05:59:47 -0700483 double oStartPart = (oTest->t() - oPriorT) / oStartRange;
caryclark55888e42016-07-18 10:01:36 -0700484 FAIL_IF(startPart == oStartPart);
caryclark8016b262016-09-06 05:59:47 -0700485 bool addToOpp = !containedOpp && !containedThis ? startPart < oStartPart
486 : !!containedThis;
caryclark55888e42016-07-18 10:01:36 -0700487 bool startOver = false;
caryclark8016b262016-09-06 05:59:47 -0700488 bool success = addToOpp ? oSeg->addExpanded(
489 oPriorT + oStartRange * startPart, test, &startOver)
490 : seg->addExpanded(
491 priorT + startRange * oStartPart, oTest, &startOver);
caryclark30b9fdd2016-08-31 14:36:29 -0700492 FAIL_IF(!success);
caryclark55888e42016-07-18 10:01:36 -0700493 if (startOver) {
494 test = start;
495 oTest = oStart;
496 }
caryclark30b9fdd2016-08-31 14:36:29 -0700497 end = coin->coinPtTEnd()->span();
498 oEnd = coin->oppPtTEnd()->span();
caryclark55888e42016-07-18 10:01:36 -0700499 }
500 if (test != end) {
caryclark30b9fdd2016-08-31 14:36:29 -0700501 FAIL_IF(!test->upCastable());
caryclark8016b262016-09-06 05:59:47 -0700502 priorT = test->t();
caryclark55888e42016-07-18 10:01:36 -0700503 test = test->upCast()->next();
504 }
505 if (oTest != oEnd) {
caryclark8016b262016-09-06 05:59:47 -0700506 oPriorT = oTest->t();
caryclark78a37a52016-10-20 12:36:16 -0700507 if (coin->flipped()) {
508 oTest = oTest->prev();
509 } else {
510 FAIL_IF(!oTest->upCastable());
511 oTest = oTest->upCast()->next();
512 }
caryclark30b9fdd2016-08-31 14:36:29 -0700513 FAIL_IF(!oTest);
caryclark55888e42016-07-18 10:01:36 -0700514 }
caryclark8016b262016-09-06 05:59:47 -0700515
caryclark55888e42016-07-18 10:01:36 -0700516 }
517 } while ((coin = coin->next()));
518 return true;
519}
520
caryclark55888e42016-07-18 10:01:36 -0700521// given a t span, map the same range on the coincident span
caryclark8016b262016-09-06 05:59:47 -0700522/*
523the curves may not scale linearly, so interpolation may only happen within known points
524remap over1s, over1e, cointPtTStart, coinPtTEnd to smallest range that captures over1s
525then repeat to capture over1e
526*/
527double SkOpCoincidence::TRange(const SkOpPtT* overS, double t,
528 const SkOpSegment* coinSeg SkDEBUGPARAMS(const SkOpPtT* overE)) {
529 const SkOpSpanBase* work = overS->span();
530 const SkOpPtT* foundStart = nullptr;
531 const SkOpPtT* foundEnd = nullptr;
532 const SkOpPtT* coinStart = nullptr;
533 const SkOpPtT* coinEnd = nullptr;
534 do {
535 const SkOpPtT* contained = work->contains(coinSeg);
536 if (!contained) {
caryclarkc9b90d12016-09-09 07:41:36 -0700537 if (work->final()) {
538 break;
caryclarkb393a492016-09-07 08:21:09 -0700539 }
caryclark8016b262016-09-06 05:59:47 -0700540 continue;
541 }
542 if (work->t() <= t) {
543 coinStart = contained;
544 foundStart = work->ptT();
545 }
546 if (work->t() >= t) {
547 coinEnd = contained;
548 foundEnd = work->ptT();
549 break;
550 }
551 SkASSERT(work->ptT() != overE);
552 } while ((work = work->upCast()->next()));
caryclarkc9b90d12016-09-09 07:41:36 -0700553 if (!coinStart || !coinEnd) {
554 return 1;
555 }
caryclark8016b262016-09-06 05:59:47 -0700556 // while overS->fT <=t and overS contains coinSeg
557 double denom = foundEnd->fT - foundStart->fT;
558 double sRatio = denom ? (t - foundStart->fT) / denom : 1;
559 return coinStart->fT + (coinEnd->fT - coinStart->fT) * sRatio;
caryclark54359292015-03-26 07:52:43 -0700560}
561
caryclark55888e42016-07-18 10:01:36 -0700562// return true if span overlaps existing and needs to adjust the coincident list
563bool SkOpCoincidence::checkOverlap(SkCoincidentSpans* check,
564 const SkOpSegment* coinSeg, const SkOpSegment* oppSeg,
565 double coinTs, double coinTe, double oppTs, double oppTe,
566 SkTDArray<SkCoincidentSpans*>* overlaps) const {
567 if (!Ordered(coinSeg, oppSeg)) {
568 if (oppTs < oppTe) {
569 return this->checkOverlap(check, oppSeg, coinSeg, oppTs, oppTe, coinTs, coinTe,
570 overlaps);
571 }
572 return this->checkOverlap(check, oppSeg, coinSeg, oppTe, oppTs, coinTe, coinTs, overlaps);
573 }
574 bool swapOpp = oppTs > oppTe;
575 if (swapOpp) {
576 SkTSwap(oppTs, oppTe);
577 }
caryclark27c8eb82015-07-06 11:38:33 -0700578 do {
caryclark55888e42016-07-18 10:01:36 -0700579 if (check->coinPtTStart()->segment() != coinSeg) {
580 continue;
caryclark1c9ce612015-11-20 14:06:28 -0800581 }
caryclark55888e42016-07-18 10:01:36 -0700582 if (check->oppPtTStart()->segment() != oppSeg) {
583 continue;
caryclarkdae6b972016-06-08 04:28:19 -0700584 }
caryclark55888e42016-07-18 10:01:36 -0700585 double checkTs = check->coinPtTStart()->fT;
586 double checkTe = check->coinPtTEnd()->fT;
587 bool coinOutside = coinTe < checkTs || coinTs > checkTe;
588 double oCheckTs = check->oppPtTStart()->fT;
589 double oCheckTe = check->oppPtTEnd()->fT;
590 if (swapOpp) {
591 if (oCheckTs <= oCheckTe) {
caryclark81a478c2016-09-09 09:37:57 -0700592 return false;
caryclark27c8eb82015-07-06 11:38:33 -0700593 }
caryclark55888e42016-07-18 10:01:36 -0700594 SkTSwap(oCheckTs, oCheckTe);
caryclark27c8eb82015-07-06 11:38:33 -0700595 }
caryclark55888e42016-07-18 10:01:36 -0700596 bool oppOutside = oppTe < oCheckTs || oppTs > oCheckTe;
597 if (coinOutside && oppOutside) {
598 continue;
599 }
600 bool coinInside = coinTe <= checkTe && coinTs >= checkTs;
601 bool oppInside = oppTe <= oCheckTe && oppTs >= oCheckTs;
caryclark81a478c2016-09-09 09:37:57 -0700602 if (coinInside && oppInside) { // already included, do nothing
603 return false;
caryclark55888e42016-07-18 10:01:36 -0700604 }
605 *overlaps->append() = check; // partial overlap, extend existing entry
606 } while ((check = check->next()));
caryclark26ad22a2015-10-16 09:03:38 -0700607 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700608}
609
caryclark55888e42016-07-18 10:01:36 -0700610/* Please keep this in sync with debugAddIfMissing() */
caryclark8016b262016-09-06 05:59:47 -0700611// note that over1s, over1e, over2s, over2e are ordered
612bool SkOpCoincidence::addIfMissing(const SkOpPtT* over1s, const SkOpPtT* over2s,
Herb Derbyecc364c2017-04-19 15:09:48 -0400613 double tStart, double tEnd, SkOpSegment* coinSeg, SkOpSegment* oppSeg, bool* added
caryclark8016b262016-09-06 05:59:47 -0700614 SkDEBUGPARAMS(const SkOpPtT* over1e) SkDEBUGPARAMS(const SkOpPtT* over2e)) {
615 SkASSERT(tStart < tEnd);
616 SkASSERT(over1s->fT < over1e->fT);
617 SkASSERT(between(over1s->fT, tStart, over1e->fT));
618 SkASSERT(between(over1s->fT, tEnd, over1e->fT));
619 SkASSERT(over2s->fT < over2e->fT);
620 SkASSERT(between(over2s->fT, tStart, over2e->fT));
621 SkASSERT(between(over2s->fT, tEnd, over2e->fT));
622 SkASSERT(over1s->segment() == over1e->segment());
623 SkASSERT(over2s->segment() == over2e->segment());
624 SkASSERT(over1s->segment() == over2s->segment());
625 SkASSERT(over1s->segment() != coinSeg);
626 SkASSERT(over1s->segment() != oppSeg);
627 SkASSERT(coinSeg != oppSeg);
caryclark54359292015-03-26 07:52:43 -0700628 double coinTs, coinTe, oppTs, oppTe;
caryclark8016b262016-09-06 05:59:47 -0700629 coinTs = TRange(over1s, tStart, coinSeg SkDEBUGPARAMS(over1e));
630 coinTe = TRange(over1s, tEnd, coinSeg SkDEBUGPARAMS(over1e));
caryclark30b9fdd2016-08-31 14:36:29 -0700631 if (coinSeg->collapsed(coinTs, coinTe)) {
caryclark81a478c2016-09-09 09:37:57 -0700632 return true;
caryclark30b9fdd2016-08-31 14:36:29 -0700633 }
caryclark8016b262016-09-06 05:59:47 -0700634 oppTs = TRange(over2s, tStart, oppSeg SkDEBUGPARAMS(over2e));
635 oppTe = TRange(over2s, tEnd, oppSeg SkDEBUGPARAMS(over2e));
caryclark30b9fdd2016-08-31 14:36:29 -0700636 if (oppSeg->collapsed(oppTs, oppTe)) {
caryclark81a478c2016-09-09 09:37:57 -0700637 return true;
caryclark30b9fdd2016-08-31 14:36:29 -0700638 }
caryclark8016b262016-09-06 05:59:47 -0700639 if (coinTs > coinTe) {
caryclark55888e42016-07-18 10:01:36 -0700640 SkTSwap(coinTs, coinTe);
caryclark54359292015-03-26 07:52:43 -0700641 SkTSwap(oppTs, oppTe);
642 }
caryclark81a478c2016-09-09 09:37:57 -0700643 return this->addOrOverlap(coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, added);
caryclark54359292015-03-26 07:52:43 -0700644}
645
caryclark55888e42016-07-18 10:01:36 -0700646/* Please keep this in sync with debugAddOrOverlap() */
caryclark025b11e2016-08-25 05:21:14 -0700647// If this is called by addEndMovedSpans(), a returned false propogates out to an abort.
648// If this is called by AddIfMissing(), a returned false indicates there was nothing to add
caryclark55888e42016-07-18 10:01:36 -0700649bool SkOpCoincidence::addOrOverlap(SkOpSegment* coinSeg, SkOpSegment* oppSeg,
caryclark81a478c2016-09-09 09:37:57 -0700650 double coinTs, double coinTe, double oppTs, double oppTe, bool* added) {
caryclark55888e42016-07-18 10:01:36 -0700651 SkTDArray<SkCoincidentSpans*> overlaps;
caryclark81a478c2016-09-09 09:37:57 -0700652 FAIL_IF(!fTop);
caryclark55888e42016-07-18 10:01:36 -0700653 if (!this->checkOverlap(fTop, coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, &overlaps)) {
caryclark81a478c2016-09-09 09:37:57 -0700654 return true;
caryclark55888e42016-07-18 10:01:36 -0700655 }
656 if (fHead && !this->checkOverlap(fHead, coinSeg, oppSeg, coinTs,
657 coinTe, oppTs, oppTe, &overlaps)) {
caryclark81a478c2016-09-09 09:37:57 -0700658 return true;
caryclark55888e42016-07-18 10:01:36 -0700659 }
660 SkCoincidentSpans* overlap = overlaps.count() ? overlaps[0] : nullptr;
661 for (int index = 1; index < overlaps.count(); ++index) { // combine overlaps before continuing
662 SkCoincidentSpans* test = overlaps[index];
663 if (overlap->coinPtTStart()->fT > test->coinPtTStart()->fT) {
664 overlap->setCoinPtTStart(test->coinPtTStart());
665 }
666 if (overlap->coinPtTEnd()->fT < test->coinPtTEnd()->fT) {
667 overlap->setCoinPtTEnd(test->coinPtTEnd());
668 }
669 if (overlap->flipped()
670 ? overlap->oppPtTStart()->fT < test->oppPtTStart()->fT
671 : overlap->oppPtTStart()->fT > test->oppPtTStart()->fT) {
672 overlap->setOppPtTStart(test->oppPtTStart());
673 }
674 if (overlap->flipped()
675 ? overlap->oppPtTEnd()->fT > test->oppPtTEnd()->fT
676 : overlap->oppPtTEnd()->fT < test->oppPtTEnd()->fT) {
677 overlap->setOppPtTEnd(test->oppPtTEnd());
678 }
679 if (!fHead || !this->release(fHead, test)) {
680 SkAssertResult(this->release(fTop, test));
681 }
682 }
683 const SkOpPtT* cs = coinSeg->existing(coinTs, oppSeg);
684 const SkOpPtT* ce = coinSeg->existing(coinTe, oppSeg);
caryclark81a478c2016-09-09 09:37:57 -0700685 if (overlap && cs && ce && overlap->contains(cs, ce)) {
686 return true;
687 }
688 FAIL_IF(cs == ce && cs);
caryclark55888e42016-07-18 10:01:36 -0700689 const SkOpPtT* os = oppSeg->existing(oppTs, coinSeg);
690 const SkOpPtT* oe = oppSeg->existing(oppTe, coinSeg);
caryclark81a478c2016-09-09 09:37:57 -0700691 if (overlap && os && oe && overlap->contains(os, oe)) {
692 return true;
693 }
Cary Clarkb8421ed2018-03-14 15:55:02 -0400694 FAIL_IF(cs && cs->deleted());
Cary Clark2f06a532018-03-12 14:41:45 -0400695 FAIL_IF(os && os->deleted());
Cary Clark0949bee2018-03-19 09:42:00 -0400696 FAIL_IF(ce && ce->deleted());
Cary Clark74b42902018-03-09 07:38:47 -0500697 FAIL_IF(oe && oe->deleted());
caryclark55888e42016-07-18 10:01:36 -0700698 const SkOpPtT* csExisting = !cs ? coinSeg->existing(coinTs, nullptr) : nullptr;
699 const SkOpPtT* ceExisting = !ce ? coinSeg->existing(coinTe, nullptr) : nullptr;
caryclark81a478c2016-09-09 09:37:57 -0700700 FAIL_IF(csExisting && csExisting == ceExisting);
caryclarke839e782016-09-15 07:48:18 -0700701// FAIL_IF(csExisting && (csExisting == ce ||
702// csExisting->contains(ceExisting ? ceExisting : ce)));
caryclark81a478c2016-09-09 09:37:57 -0700703 FAIL_IF(ceExisting && (ceExisting == cs ||
caryclark025b11e2016-08-25 05:21:14 -0700704 ceExisting->contains(csExisting ? csExisting : cs)));
caryclark55888e42016-07-18 10:01:36 -0700705 const SkOpPtT* osExisting = !os ? oppSeg->existing(oppTs, nullptr) : nullptr;
706 const SkOpPtT* oeExisting = !oe ? oppSeg->existing(oppTe, nullptr) : nullptr;
caryclark81a478c2016-09-09 09:37:57 -0700707 FAIL_IF(osExisting && osExisting == oeExisting);
708 FAIL_IF(osExisting && (osExisting == oe ||
caryclark025b11e2016-08-25 05:21:14 -0700709 osExisting->contains(oeExisting ? oeExisting : oe)));
caryclark81a478c2016-09-09 09:37:57 -0700710 FAIL_IF(oeExisting && (oeExisting == os ||
caryclark025b11e2016-08-25 05:21:14 -0700711 oeExisting->contains(osExisting ? osExisting : os)));
caryclark55888e42016-07-18 10:01:36 -0700712 // extra line in debug code
713 this->debugValidate();
714 if (!cs || !os) {
715 SkOpPtT* csWritable = cs ? const_cast<SkOpPtT*>(cs)
caryclark29b25632016-08-25 11:27:17 -0700716 : coinSeg->addT(coinTs);
caryclarke839e782016-09-15 07:48:18 -0700717 if (csWritable == ce) {
718 return true;
719 }
caryclark55888e42016-07-18 10:01:36 -0700720 SkOpPtT* osWritable = os ? const_cast<SkOpPtT*>(os)
caryclark29b25632016-08-25 11:27:17 -0700721 : oppSeg->addT(oppTs);
caryclark81a478c2016-09-09 09:37:57 -0700722 FAIL_IF(!csWritable || !osWritable);
caryclark30b9fdd2016-08-31 14:36:29 -0700723 csWritable->span()->addOpp(osWritable->span());
caryclark55888e42016-07-18 10:01:36 -0700724 cs = csWritable;
caryclark30b9fdd2016-08-31 14:36:29 -0700725 os = osWritable->active();
Cary Clark74b42902018-03-09 07:38:47 -0500726 FAIL_IF(!os);
caryclark81a478c2016-09-09 09:37:57 -0700727 FAIL_IF((ce && ce->deleted()) || (oe && oe->deleted()));
caryclark55888e42016-07-18 10:01:36 -0700728 }
729 if (!ce || !oe) {
730 SkOpPtT* ceWritable = ce ? const_cast<SkOpPtT*>(ce)
caryclark29b25632016-08-25 11:27:17 -0700731 : coinSeg->addT(coinTe);
caryclark55888e42016-07-18 10:01:36 -0700732 SkOpPtT* oeWritable = oe ? const_cast<SkOpPtT*>(oe)
caryclark29b25632016-08-25 11:27:17 -0700733 : oppSeg->addT(oppTe);
caryclark30b9fdd2016-08-31 14:36:29 -0700734 ceWritable->span()->addOpp(oeWritable->span());
caryclark55888e42016-07-18 10:01:36 -0700735 ce = ceWritable;
736 oe = oeWritable;
737 }
738 this->debugValidate();
caryclark81a478c2016-09-09 09:37:57 -0700739 FAIL_IF(cs->deleted());
740 FAIL_IF(os->deleted());
741 FAIL_IF(ce->deleted());
742 FAIL_IF(oe->deleted());
743 FAIL_IF(cs->contains(ce) || os->contains(oe));
caryclark55888e42016-07-18 10:01:36 -0700744 bool result = true;
745 if (overlap) {
746 if (overlap->coinPtTStart()->segment() == coinSeg) {
747 result = overlap->extend(cs, ce, os, oe);
748 } else {
749 if (os->fT > oe->fT) {
750 SkTSwap(cs, ce);
751 SkTSwap(os, oe);
752 }
753 result = overlap->extend(os, oe, cs, ce);
754 }
755#if DEBUG_COINCIDENCE_VERBOSE
756 if (result) {
757 overlaps[0]->debugShow();
758 }
759#endif
760 } else {
761 this->add(cs, ce, os, oe);
762#if DEBUG_COINCIDENCE_VERBOSE
763 fHead->debugShow();
764#endif
765 }
766 this->debugValidate();
caryclark81a478c2016-09-09 09:37:57 -0700767 if (result) {
768 *added = true;
769 }
770 return true;
caryclark55888e42016-07-18 10:01:36 -0700771}
772
773// Please keep this in sync with debugAddMissing()
caryclark27c8eb82015-07-06 11:38:33 -0700774/* detects overlaps of different coincident runs on same segment */
775/* does not detect overlaps for pairs without any segments in common */
caryclark55888e42016-07-18 10:01:36 -0700776// returns true if caller should loop again
Cary Clarkab87d7a2016-10-04 10:01:04 -0400777bool SkOpCoincidence::addMissing(bool* added DEBUG_COIN_DECLARE_PARAMS()) {
caryclark27c8eb82015-07-06 11:38:33 -0700778 SkCoincidentSpans* outer = fHead;
caryclark81a478c2016-09-09 09:37:57 -0700779 *added = false;
caryclark54359292015-03-26 07:52:43 -0700780 if (!outer) {
caryclark81a478c2016-09-09 09:37:57 -0700781 return true;
caryclark54359292015-03-26 07:52:43 -0700782 }
caryclark27c8eb82015-07-06 11:38:33 -0700783 fTop = outer;
halcanary96fcdcc2015-08-27 07:41:13 -0700784 fHead = nullptr;
caryclark54359292015-03-26 07:52:43 -0700785 do {
caryclark27c8eb82015-07-06 11:38:33 -0700786 // addifmissing can modify the list that this is walking
caryclark26ad22a2015-10-16 09:03:38 -0700787 // save head so that walker can iterate over old data unperturbed
788 // addifmissing adds to head freely then add saved head in the end
caryclark8016b262016-09-06 05:59:47 -0700789 const SkOpPtT* ocs = outer->coinPtTStart();
caryclarka35ab3e2016-10-20 08:32:18 -0700790 FAIL_IF(ocs->deleted());
caryclark8016b262016-09-06 05:59:47 -0700791 const SkOpSegment* outerCoin = ocs->segment();
Cary Clark18562b82018-06-07 08:06:12 -0400792 FAIL_IF(outerCoin->done());
caryclark8016b262016-09-06 05:59:47 -0700793 const SkOpPtT* oos = outer->oppPtTStart();
caryclarkb393a492016-09-07 08:21:09 -0700794 if (oos->deleted()) {
caryclark81a478c2016-09-09 09:37:57 -0700795 return true;
caryclarkb393a492016-09-07 08:21:09 -0700796 }
caryclark8016b262016-09-06 05:59:47 -0700797 const SkOpSegment* outerOpp = oos->segment();
Cary Clark4c76c412017-01-20 08:14:33 -0500798 SkOPASSERT(!outerOpp->done());
caryclark8016b262016-09-06 05:59:47 -0700799 SkOpSegment* outerCoinWritable = const_cast<SkOpSegment*>(outerCoin);
800 SkOpSegment* outerOppWritable = const_cast<SkOpSegment*>(outerOpp);
caryclark54359292015-03-26 07:52:43 -0700801 SkCoincidentSpans* inner = outer;
caryclark55888e42016-07-18 10:01:36 -0700802 while ((inner = inner->next())) {
803 this->debugValidate();
caryclark54359292015-03-26 07:52:43 -0700804 double overS, overE;
caryclark8016b262016-09-06 05:59:47 -0700805 const SkOpPtT* ics = inner->coinPtTStart();
caryclark221a4bb2016-10-07 11:15:15 -0700806 FAIL_IF(ics->deleted());
caryclark8016b262016-09-06 05:59:47 -0700807 const SkOpSegment* innerCoin = ics->segment();
caryclarka35ab3e2016-10-20 08:32:18 -0700808 FAIL_IF(innerCoin->done());
caryclark8016b262016-09-06 05:59:47 -0700809 const SkOpPtT* ios = inner->oppPtTStart();
caryclarka35ab3e2016-10-20 08:32:18 -0700810 FAIL_IF(ios->deleted());
caryclark8016b262016-09-06 05:59:47 -0700811 const SkOpSegment* innerOpp = ios->segment();
Cary Clark4c76c412017-01-20 08:14:33 -0500812 SkOPASSERT(!innerOpp->done());
caryclark8016b262016-09-06 05:59:47 -0700813 SkOpSegment* innerCoinWritable = const_cast<SkOpSegment*>(innerCoin);
814 SkOpSegment* innerOppWritable = const_cast<SkOpSegment*>(innerOpp);
caryclark55888e42016-07-18 10:01:36 -0700815 if (outerCoin == innerCoin) {
caryclark8016b262016-09-06 05:59:47 -0700816 const SkOpPtT* oce = outer->coinPtTEnd();
caryclarkb393a492016-09-07 08:21:09 -0700817 if (oce->deleted()) {
caryclark81a478c2016-09-09 09:37:57 -0700818 return true;
caryclarkb393a492016-09-07 08:21:09 -0700819 }
caryclark8016b262016-09-06 05:59:47 -0700820 const SkOpPtT* ice = inner->coinPtTEnd();
caryclark595ac282016-10-24 08:41:45 -0700821 FAIL_IF(ice->deleted());
caryclark8016b262016-09-06 05:59:47 -0700822 if (outerOpp != innerOpp && this->overlap(ocs, oce, ics, ice, &overS, &overE)) {
caryclark81a478c2016-09-09 09:37:57 -0700823 (void) this->addIfMissing(ocs->starter(oce), ics->starter(ice),
824 overS, overE, outerOppWritable, innerOppWritable, added
caryclark8016b262016-09-06 05:59:47 -0700825 SkDEBUGPARAMS(ocs->debugEnder(oce))
826 SkDEBUGPARAMS(ics->debugEnder(ice)));
caryclark55888e42016-07-18 10:01:36 -0700827 }
828 } else if (outerCoin == innerOpp) {
caryclark8016b262016-09-06 05:59:47 -0700829 const SkOpPtT* oce = outer->coinPtTEnd();
830 SkASSERT(!oce->deleted());
831 const SkOpPtT* ioe = inner->oppPtTEnd();
832 SkASSERT(!ioe->deleted());
833 if (outerOpp != innerCoin && this->overlap(ocs, oce, ios, ioe, &overS, &overE)) {
caryclark81a478c2016-09-09 09:37:57 -0700834 (void) this->addIfMissing(ocs->starter(oce), ios->starter(ioe),
835 overS, overE, outerOppWritable, innerCoinWritable, added
caryclark8016b262016-09-06 05:59:47 -0700836 SkDEBUGPARAMS(ocs->debugEnder(oce))
837 SkDEBUGPARAMS(ios->debugEnder(ioe)));
caryclark55888e42016-07-18 10:01:36 -0700838 }
839 } else if (outerOpp == innerCoin) {
caryclark8016b262016-09-06 05:59:47 -0700840 const SkOpPtT* ooe = outer->oppPtTEnd();
841 SkASSERT(!ooe->deleted());
842 const SkOpPtT* ice = inner->coinPtTEnd();
843 SkASSERT(!ice->deleted());
caryclark55888e42016-07-18 10:01:36 -0700844 SkASSERT(outerCoin != innerOpp);
caryclark8016b262016-09-06 05:59:47 -0700845 if (this->overlap(oos, ooe, ics, ice, &overS, &overE)) {
caryclark81a478c2016-09-09 09:37:57 -0700846 (void) this->addIfMissing(oos->starter(ooe), ics->starter(ice),
847 overS, overE, outerCoinWritable, innerOppWritable, added
caryclark8016b262016-09-06 05:59:47 -0700848 SkDEBUGPARAMS(oos->debugEnder(ooe))
849 SkDEBUGPARAMS(ics->debugEnder(ice)));
caryclark55888e42016-07-18 10:01:36 -0700850 }
851 } else if (outerOpp == innerOpp) {
caryclark8016b262016-09-06 05:59:47 -0700852 const SkOpPtT* ooe = outer->oppPtTEnd();
Cary Clark8d8a5d92018-04-02 12:40:49 -0400853 FAIL_IF(ooe->deleted());
caryclark8016b262016-09-06 05:59:47 -0700854 const SkOpPtT* ioe = inner->oppPtTEnd();
caryclarkb393a492016-09-07 08:21:09 -0700855 if (ioe->deleted()) {
caryclark81a478c2016-09-09 09:37:57 -0700856 return true;
caryclarkb393a492016-09-07 08:21:09 -0700857 }
caryclark55888e42016-07-18 10:01:36 -0700858 SkASSERT(outerCoin != innerCoin);
caryclark8016b262016-09-06 05:59:47 -0700859 if (this->overlap(oos, ooe, ios, ioe, &overS, &overE)) {
caryclark81a478c2016-09-09 09:37:57 -0700860 (void) this->addIfMissing(oos->starter(ooe), ios->starter(ioe),
861 overS, overE, outerCoinWritable, innerCoinWritable, added
caryclark8016b262016-09-06 05:59:47 -0700862 SkDEBUGPARAMS(oos->debugEnder(ooe))
863 SkDEBUGPARAMS(ios->debugEnder(ioe)));
caryclark54359292015-03-26 07:52:43 -0700864 }
865 }
caryclark55888e42016-07-18 10:01:36 -0700866 this->debugValidate();
caryclark54359292015-03-26 07:52:43 -0700867 }
caryclark55888e42016-07-18 10:01:36 -0700868 } while ((outer = outer->next()));
869 this->restoreHead();
caryclark81a478c2016-09-09 09:37:57 -0700870 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700871}
872
caryclark55888e42016-07-18 10:01:36 -0700873bool SkOpCoincidence::addOverlap(const SkOpSegment* seg1, const SkOpSegment* seg1o,
874 const SkOpSegment* seg2, const SkOpSegment* seg2o,
875 const SkOpPtT* overS, const SkOpPtT* overE) {
Cary Clarke47ae292016-10-05 08:51:39 -0400876 const SkOpPtT* s1 = overS->find(seg1);
877 const SkOpPtT* e1 = overE->find(seg1);
caryclark08714012016-10-07 12:57:47 -0700878 FAIL_IF(!s1);
Cary Clark40f23782016-10-06 12:04:16 -0400879 FAIL_IF(!e1);
caryclark27c8eb82015-07-06 11:38:33 -0700880 if (!s1->starter(e1)->span()->upCast()->windValue()) {
Cary Clarke47ae292016-10-05 08:51:39 -0400881 s1 = overS->find(seg1o);
882 e1 = overE->find(seg1o);
caryclark221a4bb2016-10-07 11:15:15 -0700883 FAIL_IF(!s1);
Cary Clark40f23782016-10-06 12:04:16 -0400884 FAIL_IF(!e1);
caryclark27c8eb82015-07-06 11:38:33 -0700885 if (!s1->starter(e1)->span()->upCast()->windValue()) {
caryclark3f0753d2016-06-28 09:23:57 -0700886 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700887 }
888 }
Cary Clarke47ae292016-10-05 08:51:39 -0400889 const SkOpPtT* s2 = overS->find(seg2);
890 const SkOpPtT* e2 = overE->find(seg2);
caryclark82616712016-10-24 04:53:22 -0700891 FAIL_IF(!s2);
caryclarka35ab3e2016-10-20 08:32:18 -0700892 FAIL_IF(!e2);
caryclark27c8eb82015-07-06 11:38:33 -0700893 if (!s2->starter(e2)->span()->upCast()->windValue()) {
Cary Clarke47ae292016-10-05 08:51:39 -0400894 s2 = overS->find(seg2o);
895 e2 = overE->find(seg2o);
caryclarka35ab3e2016-10-20 08:32:18 -0700896 FAIL_IF(!s2);
caryclark78a37a52016-10-20 12:36:16 -0700897 FAIL_IF(!e2);
caryclark27c8eb82015-07-06 11:38:33 -0700898 if (!s2->starter(e2)->span()->upCast()->windValue()) {
caryclark3f0753d2016-06-28 09:23:57 -0700899 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700900 }
901 }
902 if (s1->segment() == s2->segment()) {
caryclark3f0753d2016-06-28 09:23:57 -0700903 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700904 }
905 if (s1->fT > e1->fT) {
906 SkTSwap(s1, e1);
907 SkTSwap(s2, e2);
908 }
caryclark55888e42016-07-18 10:01:36 -0700909 this->add(s1, e1, s2, e2);
caryclark3f0753d2016-06-28 09:23:57 -0700910 return true;
caryclark54359292015-03-26 07:52:43 -0700911}
912
caryclark55888e42016-07-18 10:01:36 -0700913bool SkOpCoincidence::contains(const SkOpSegment* seg, const SkOpSegment* opp, double oppT) const {
914 if (this->contains(fHead, seg, opp, oppT)) {
915 return true;
916 }
917 if (this->contains(fTop, seg, opp, oppT)) {
918 return true;
919 }
920 return false;
921}
922
923bool SkOpCoincidence::contains(const SkCoincidentSpans* coin, const SkOpSegment* seg,
924 const SkOpSegment* opp, double oppT) const {
925 if (!coin) {
926 return false;
927 }
928 do {
929 if (coin->coinPtTStart()->segment() == seg && coin->oppPtTStart()->segment() == opp
930 && between(coin->oppPtTStart()->fT, oppT, coin->oppPtTEnd()->fT)) {
caryclark54359292015-03-26 07:52:43 -0700931 return true;
932 }
caryclark55888e42016-07-18 10:01:36 -0700933 if (coin->oppPtTStart()->segment() == seg && coin->coinPtTStart()->segment() == opp
934 && between(coin->coinPtTStart()->fT, oppT, coin->coinPtTEnd()->fT)) {
935 return true;
936 }
937 } while ((coin = coin->next()));
caryclark54359292015-03-26 07:52:43 -0700938 return false;
939}
940
caryclark55888e42016-07-18 10:01:36 -0700941bool SkOpCoincidence::contains(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd,
942 const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) const {
943 const SkCoincidentSpans* test = fHead;
944 if (!test) {
945 return false;
946 }
947 const SkOpSegment* coinSeg = coinPtTStart->segment();
948 const SkOpSegment* oppSeg = oppPtTStart->segment();
949 if (!Ordered(coinPtTStart, oppPtTStart)) {
950 SkTSwap(coinSeg, oppSeg);
951 SkTSwap(coinPtTStart, oppPtTStart);
952 SkTSwap(coinPtTEnd, oppPtTEnd);
953 if (coinPtTStart->fT > coinPtTEnd->fT) {
954 SkTSwap(coinPtTStart, coinPtTEnd);
955 SkTSwap(oppPtTStart, oppPtTEnd);
956 }
957 }
958 double oppMinT = SkTMin(oppPtTStart->fT, oppPtTEnd->fT);
959 double oppMaxT = SkTMax(oppPtTStart->fT, oppPtTEnd->fT);
960 do {
961 if (coinSeg != test->coinPtTStart()->segment()) {
962 continue;
963 }
964 if (coinPtTStart->fT < test->coinPtTStart()->fT) {
965 continue;
966 }
967 if (coinPtTEnd->fT > test->coinPtTEnd()->fT) {
968 continue;
969 }
970 if (oppSeg != test->oppPtTStart()->segment()) {
971 continue;
972 }
973 if (oppMinT < SkTMin(test->oppPtTStart()->fT, test->oppPtTEnd()->fT)) {
974 continue;
975 }
976 if (oppMaxT > SkTMax(test->oppPtTStart()->fT, test->oppPtTEnd()->fT)) {
977 continue;
978 }
979 return true;
980 } while ((test = test->next()));
981 return false;
982}
983
Cary Clarkab87d7a2016-10-04 10:01:04 -0400984void SkOpCoincidence::correctEnds(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
985 DEBUG_SET_PHASE();
caryclark55888e42016-07-18 10:01:36 -0700986 SkCoincidentSpans* coin = fHead;
987 if (!coin) {
988 return;
989 }
990 do {
991 coin->correctEnds();
992 } while ((coin = coin->next()));
993}
994
caryclark54359292015-03-26 07:52:43 -0700995// walk span sets in parallel, moving winding from one to the other
caryclarka35ab3e2016-10-20 08:32:18 -0700996bool SkOpCoincidence::apply(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
Cary Clarkab87d7a2016-10-04 10:01:04 -0400997 DEBUG_SET_PHASE();
caryclark54359292015-03-26 07:52:43 -0700998 SkCoincidentSpans* coin = fHead;
999 if (!coin) {
caryclarka35ab3e2016-10-20 08:32:18 -07001000 return true;
caryclark54359292015-03-26 07:52:43 -07001001 }
1002 do {
Cary Clark5a2057a2017-01-03 10:47:34 -05001003 SkOpSpanBase* startSpan = coin->coinPtTStartWritable()->span();
1004 FAIL_IF(!startSpan->upCastable());
1005 SkOpSpan* start = startSpan->upCast();
caryclark182b4992015-05-14 05:45:54 -07001006 if (start->deleted()) {
1007 continue;
1008 }
caryclark55888e42016-07-18 10:01:36 -07001009 const SkOpSpanBase* end = coin->coinPtTEnd()->span();
caryclark54359292015-03-26 07:52:43 -07001010 SkASSERT(start == start->starter(end));
caryclark55888e42016-07-18 10:01:36 -07001011 bool flipped = coin->flipped();
caryclark96dc1c92016-10-20 11:34:10 -07001012 SkOpSpanBase* oStartBase = (flipped ? coin->oppPtTEndWritable()
1013 : coin->oppPtTStartWritable())->span();
1014 FAIL_IF(!oStartBase->upCastable());
1015 SkOpSpan* oStart = oStartBase->upCast();
caryclark182b4992015-05-14 05:45:54 -07001016 if (oStart->deleted()) {
1017 continue;
1018 }
caryclark55888e42016-07-18 10:01:36 -07001019 const SkOpSpanBase* oEnd = (flipped ? coin->oppPtTStart() : coin->oppPtTEnd())->span();
caryclark54359292015-03-26 07:52:43 -07001020 SkASSERT(oStart == oStart->starter(oEnd));
1021 SkOpSegment* segment = start->segment();
1022 SkOpSegment* oSegment = oStart->segment();
1023 bool operandSwap = segment->operand() != oSegment->operand();
1024 if (flipped) {
caryclark364a0072015-12-14 08:43:21 -08001025 if (oEnd->deleted()) {
1026 continue;
1027 }
caryclark54359292015-03-26 07:52:43 -07001028 do {
1029 SkOpSpanBase* oNext = oStart->next();
1030 if (oNext == oEnd) {
1031 break;
1032 }
Cary Clark26ae5ab2016-12-12 13:57:56 -05001033 FAIL_IF(!oNext->upCastable());
caryclark54359292015-03-26 07:52:43 -07001034 oStart = oNext->upCast();
1035 } while (true);
1036 }
caryclark54359292015-03-26 07:52:43 -07001037 do {
1038 int windValue = start->windValue();
caryclark54359292015-03-26 07:52:43 -07001039 int oppValue = start->oppValue();
caryclark1049f122015-04-20 08:31:59 -07001040 int oWindValue = oStart->windValue();
caryclark54359292015-03-26 07:52:43 -07001041 int oOppValue = oStart->oppValue();
1042 // winding values are added or subtracted depending on direction and wind type
1043 // same or opposite values are summed depending on the operand value
caryclark1049f122015-04-20 08:31:59 -07001044 int windDiff = operandSwap ? oOppValue : oWindValue;
1045 int oWindDiff = operandSwap ? oppValue : windValue;
1046 if (!flipped) {
1047 windDiff = -windDiff;
1048 oWindDiff = -oWindDiff;
1049 }
caryclark55888e42016-07-18 10:01:36 -07001050 bool addToStart = windValue && (windValue > windDiff || (windValue == windDiff
1051 && oWindValue <= oWindDiff));
1052 if (addToStart ? start->done() : oStart->done()) {
1053 addToStart ^= true;
1054 }
1055 if (addToStart) {
caryclark54359292015-03-26 07:52:43 -07001056 if (operandSwap) {
1057 SkTSwap(oWindValue, oOppValue);
1058 }
1059 if (flipped) {
1060 windValue -= oWindValue;
1061 oppValue -= oOppValue;
1062 } else {
1063 windValue += oWindValue;
1064 oppValue += oOppValue;
1065 }
caryclark1049f122015-04-20 08:31:59 -07001066 if (segment->isXor()) {
caryclark54359292015-03-26 07:52:43 -07001067 windValue &= 1;
1068 }
caryclark1049f122015-04-20 08:31:59 -07001069 if (segment->oppXor()) {
caryclark54359292015-03-26 07:52:43 -07001070 oppValue &= 1;
1071 }
1072 oWindValue = oOppValue = 0;
1073 } else {
1074 if (operandSwap) {
1075 SkTSwap(windValue, oppValue);
1076 }
1077 if (flipped) {
1078 oWindValue -= windValue;
1079 oOppValue -= oppValue;
1080 } else {
1081 oWindValue += windValue;
1082 oOppValue += oppValue;
1083 }
caryclark1049f122015-04-20 08:31:59 -07001084 if (oSegment->isXor()) {
caryclark54359292015-03-26 07:52:43 -07001085 oWindValue &= 1;
1086 }
caryclark1049f122015-04-20 08:31:59 -07001087 if (oSegment->oppXor()) {
1088 oOppValue &= 1;
1089 }
caryclark54359292015-03-26 07:52:43 -07001090 windValue = oppValue = 0;
1091 }
caryclark6c3b9cd2016-09-26 05:36:58 -07001092#if 0 && DEBUG_COINCIDENCE
caryclark55888e42016-07-18 10:01:36 -07001093 SkDebugf("seg=%d span=%d windValue=%d oppValue=%d\n", segment->debugID(),
1094 start->debugID(), windValue, oppValue);
1095 SkDebugf("seg=%d span=%d windValue=%d oppValue=%d\n", oSegment->debugID(),
1096 oStart->debugID(), oWindValue, oOppValue);
1097#endif
Cary Clark0949bee2018-03-19 09:42:00 -04001098 FAIL_IF(windValue <= -1);
caryclark54359292015-03-26 07:52:43 -07001099 start->setWindValue(windValue);
1100 start->setOppValue(oppValue);
Cary Clarkb8421ed2018-03-14 15:55:02 -04001101 FAIL_IF(oWindValue <= -1);
caryclark54359292015-03-26 07:52:43 -07001102 oStart->setWindValue(oWindValue);
1103 oStart->setOppValue(oOppValue);
1104 if (!windValue && !oppValue) {
1105 segment->markDone(start);
1106 }
1107 if (!oWindValue && !oOppValue) {
1108 oSegment->markDone(oStart);
1109 }
1110 SkOpSpanBase* next = start->next();
1111 SkOpSpanBase* oNext = flipped ? oStart->prev() : oStart->next();
1112 if (next == end) {
1113 break;
1114 }
caryclark96dc1c92016-10-20 11:34:10 -07001115 FAIL_IF(!next->upCastable());
caryclark54359292015-03-26 07:52:43 -07001116 start = next->upCast();
caryclark1049f122015-04-20 08:31:59 -07001117 // if the opposite ran out too soon, just reuse the last span
1118 if (!oNext || !oNext->upCastable()) {
1119 oNext = oStart;
caryclark54359292015-03-26 07:52:43 -07001120 }
1121 oStart = oNext->upCast();
1122 } while (true);
caryclark55888e42016-07-18 10:01:36 -07001123 } while ((coin = coin->next()));
caryclarka35ab3e2016-10-20 08:32:18 -07001124 return true;
caryclark54359292015-03-26 07:52:43 -07001125}
1126
caryclark55888e42016-07-18 10:01:36 -07001127// Please keep this in sync with debugRelease()
1128bool SkOpCoincidence::release(SkCoincidentSpans* coin, SkCoincidentSpans* remove) {
1129 SkCoincidentSpans* head = coin;
halcanary96fcdcc2015-08-27 07:41:13 -07001130 SkCoincidentSpans* prev = nullptr;
caryclark54359292015-03-26 07:52:43 -07001131 SkCoincidentSpans* next;
1132 do {
caryclark55888e42016-07-18 10:01:36 -07001133 next = coin->next();
caryclark54359292015-03-26 07:52:43 -07001134 if (coin == remove) {
1135 if (prev) {
caryclark55888e42016-07-18 10:01:36 -07001136 prev->setNext(next);
1137 } else if (head == fHead) {
caryclark54359292015-03-26 07:52:43 -07001138 fHead = next;
caryclark55888e42016-07-18 10:01:36 -07001139 } else {
1140 fTop = next;
caryclark54359292015-03-26 07:52:43 -07001141 }
1142 break;
1143 }
1144 prev = coin;
1145 } while ((coin = next));
caryclark55888e42016-07-18 10:01:36 -07001146 return coin != nullptr;
caryclark54359292015-03-26 07:52:43 -07001147}
1148
caryclark30b9fdd2016-08-31 14:36:29 -07001149void SkOpCoincidence::releaseDeleted(SkCoincidentSpans* coin) {
1150 if (!coin) {
1151 return;
1152 }
1153 SkCoincidentSpans* head = coin;
1154 SkCoincidentSpans* prev = nullptr;
1155 SkCoincidentSpans* next;
1156 do {
1157 next = coin->next();
1158 if (coin->coinPtTStart()->deleted()) {
1159 SkOPASSERT(coin->flipped() ? coin->oppPtTEnd()->deleted() :
1160 coin->oppPtTStart()->deleted());
1161 if (prev) {
1162 prev->setNext(next);
1163 } else if (head == fHead) {
1164 fHead = next;
1165 } else {
1166 fTop = next;
1167 }
1168 } else {
1169 SkOPASSERT(coin->flipped() ? !coin->oppPtTEnd()->deleted() :
1170 !coin->oppPtTStart()->deleted());
1171 prev = coin;
1172 }
1173 } while ((coin = next));
1174}
1175
1176void SkOpCoincidence::releaseDeleted() {
1177 this->releaseDeleted(fHead);
1178 this->releaseDeleted(fTop);
1179}
1180
caryclark55888e42016-07-18 10:01:36 -07001181void SkOpCoincidence::restoreHead() {
1182 SkCoincidentSpans** headPtr = &fHead;
1183 while (*headPtr) {
1184 headPtr = (*headPtr)->nextPtr();
1185 }
1186 *headPtr = fTop;
1187 fTop = nullptr;
1188 // segments may have collapsed in the meantime; remove empty referenced segments
1189 headPtr = &fHead;
1190 while (*headPtr) {
1191 SkCoincidentSpans* test = *headPtr;
1192 if (test->coinPtTStart()->segment()->done() || test->oppPtTStart()->segment()->done()) {
1193 *headPtr = test->next();
1194 continue;
1195 }
1196 headPtr = (*headPtr)->nextPtr();
1197 }
1198}
1199
1200// Please keep this in sync with debugExpand()
caryclark30b9fdd2016-08-31 14:36:29 -07001201// expand the range by checking adjacent spans for coincidence
Cary Clarkab87d7a2016-10-04 10:01:04 -04001202bool SkOpCoincidence::expand(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
1203 DEBUG_SET_PHASE();
caryclark54359292015-03-26 07:52:43 -07001204 SkCoincidentSpans* coin = fHead;
1205 if (!coin) {
caryclark27c8eb82015-07-06 11:38:33 -07001206 return false;
caryclark54359292015-03-26 07:52:43 -07001207 }
caryclark27c8eb82015-07-06 11:38:33 -07001208 bool expanded = false;
caryclark54359292015-03-26 07:52:43 -07001209 do {
caryclark55888e42016-07-18 10:01:36 -07001210 if (coin->expand()) {
1211 // check to see if multiple spans expanded so they are now identical
1212 SkCoincidentSpans* test = fHead;
1213 do {
1214 if (coin == test) {
1215 continue;
1216 }
1217 if (coin->coinPtTStart() == test->coinPtTStart()
1218 && coin->oppPtTStart() == test->oppPtTStart()) {
1219 this->release(fHead, test);
1220 break;
1221 }
1222 } while ((test = test->next()));
1223 expanded = true;
caryclark54359292015-03-26 07:52:43 -07001224 }
caryclark55888e42016-07-18 10:01:36 -07001225 } while ((coin = coin->next()));
caryclark27c8eb82015-07-06 11:38:33 -07001226 return expanded;
1227}
1228
Cary Clark40f23782016-10-06 12:04:16 -04001229bool SkOpCoincidence::findOverlaps(SkOpCoincidence* overlaps DEBUG_COIN_DECLARE_PARAMS()) const {
Cary Clarkab87d7a2016-10-04 10:01:04 -04001230 DEBUG_SET_PHASE();
halcanary96fcdcc2015-08-27 07:41:13 -07001231 overlaps->fHead = overlaps->fTop = nullptr;
caryclark27c8eb82015-07-06 11:38:33 -07001232 SkCoincidentSpans* outer = fHead;
1233 while (outer) {
caryclark55888e42016-07-18 10:01:36 -07001234 const SkOpSegment* outerCoin = outer->coinPtTStart()->segment();
1235 const SkOpSegment* outerOpp = outer->oppPtTStart()->segment();
caryclark27c8eb82015-07-06 11:38:33 -07001236 SkCoincidentSpans* inner = outer;
caryclark55888e42016-07-18 10:01:36 -07001237 while ((inner = inner->next())) {
1238 const SkOpSegment* innerCoin = inner->coinPtTStart()->segment();
caryclark27c8eb82015-07-06 11:38:33 -07001239 if (outerCoin == innerCoin) {
1240 continue; // both winners are the same segment, so there's no additional overlap
1241 }
caryclark55888e42016-07-18 10:01:36 -07001242 const SkOpSegment* innerOpp = inner->oppPtTStart()->segment();
1243 const SkOpPtT* overlapS;
1244 const SkOpPtT* overlapE;
1245 if ((outerOpp == innerCoin && SkOpPtT::Overlaps(outer->oppPtTStart(),
1246 outer->oppPtTEnd(),inner->coinPtTStart(), inner->coinPtTEnd(), &overlapS,
1247 &overlapE))
1248 || (outerCoin == innerOpp && SkOpPtT::Overlaps(outer->coinPtTStart(),
1249 outer->coinPtTEnd(), inner->oppPtTStart(), inner->oppPtTEnd(),
caryclark27c8eb82015-07-06 11:38:33 -07001250 &overlapS, &overlapE))
caryclark55888e42016-07-18 10:01:36 -07001251 || (outerOpp == innerOpp && SkOpPtT::Overlaps(outer->oppPtTStart(),
1252 outer->oppPtTEnd(), inner->oppPtTStart(), inner->oppPtTEnd(),
caryclark27c8eb82015-07-06 11:38:33 -07001253 &overlapS, &overlapE))) {
Cary Clark40f23782016-10-06 12:04:16 -04001254 if (!overlaps->addOverlap(outerCoin, outerOpp, innerCoin, innerOpp,
1255 overlapS, overlapE)) {
1256 return false;
1257 }
Cary Clarke47ae292016-10-05 08:51:39 -04001258 }
caryclark27c8eb82015-07-06 11:38:33 -07001259 }
caryclark55888e42016-07-18 10:01:36 -07001260 outer = outer->next();
caryclark27c8eb82015-07-06 11:38:33 -07001261 }
Cary Clark40f23782016-10-06 12:04:16 -04001262 return true;
caryclark27c8eb82015-07-06 11:38:33 -07001263}
1264
caryclark55888e42016-07-18 10:01:36 -07001265void SkOpCoincidence::fixUp(SkOpPtT* deleted, const SkOpPtT* kept) {
caryclarkb393a492016-09-07 08:21:09 -07001266 SkOPASSERT(deleted != kept);
caryclark55888e42016-07-18 10:01:36 -07001267 if (fHead) {
1268 this->fixUp(fHead, deleted, kept);
caryclark54359292015-03-26 07:52:43 -07001269 }
caryclark55888e42016-07-18 10:01:36 -07001270 if (fTop) {
1271 this->fixUp(fTop, deleted, kept);
1272 }
caryclark54359292015-03-26 07:52:43 -07001273}
1274
caryclark55888e42016-07-18 10:01:36 -07001275void SkOpCoincidence::fixUp(SkCoincidentSpans* coin, SkOpPtT* deleted, const SkOpPtT* kept) {
1276 SkCoincidentSpans* head = coin;
1277 do {
1278 if (coin->coinPtTStart() == deleted) {
1279 if (coin->coinPtTEnd()->span() == kept->span()) {
1280 this->release(head, coin);
1281 continue;
1282 }
1283 coin->setCoinPtTStart(kept);
1284 }
1285 if (coin->coinPtTEnd() == deleted) {
1286 if (coin->coinPtTStart()->span() == kept->span()) {
1287 this->release(head, coin);
1288 continue;
1289 }
1290 coin->setCoinPtTEnd(kept);
1291 }
1292 if (coin->oppPtTStart() == deleted) {
1293 if (coin->oppPtTEnd()->span() == kept->span()) {
1294 this->release(head, coin);
1295 continue;
1296 }
1297 coin->setOppPtTStart(kept);
1298 }
1299 if (coin->oppPtTEnd() == deleted) {
1300 if (coin->oppPtTStart()->span() == kept->span()) {
1301 this->release(head, coin);
1302 continue;
1303 }
1304 coin->setOppPtTEnd(kept);
1305 }
1306 } while ((coin = coin->next()));
1307}
1308
1309// Please keep this in sync with debugMark()
caryclark27c8eb82015-07-06 11:38:33 -07001310/* this sets up the coincidence links in the segments when the coincidence crosses multiple spans */
caryclarke6522ea2016-10-17 07:54:33 -07001311bool SkOpCoincidence::mark(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
Cary Clarkab87d7a2016-10-04 10:01:04 -04001312 DEBUG_SET_PHASE();
caryclark54359292015-03-26 07:52:43 -07001313 SkCoincidentSpans* coin = fHead;
1314 if (!coin) {
caryclarke6522ea2016-10-17 07:54:33 -07001315 return true;
caryclark54359292015-03-26 07:52:43 -07001316 }
1317 do {
caryclarke6522ea2016-10-17 07:54:33 -07001318 SkOpSpanBase* startBase = coin->coinPtTStartWritable()->span();
1319 FAIL_IF(!startBase->upCastable());
1320 SkOpSpan* start = startBase->upCast();
caryclarka35ab3e2016-10-20 08:32:18 -07001321 FAIL_IF(start->deleted());
caryclark55888e42016-07-18 10:01:36 -07001322 SkOpSpanBase* end = coin->coinPtTEndWritable()->span();
Cary Clark40f23782016-10-06 12:04:16 -04001323 SkOPASSERT(!end->deleted());
caryclark55888e42016-07-18 10:01:36 -07001324 SkOpSpanBase* oStart = coin->oppPtTStartWritable()->span();
Cary Clark40f23782016-10-06 12:04:16 -04001325 SkOPASSERT(!oStart->deleted());
caryclark55888e42016-07-18 10:01:36 -07001326 SkOpSpanBase* oEnd = coin->oppPtTEndWritable()->span();
Cary Clarkf36b8a32018-03-20 16:08:35 -04001327 FAIL_IF(oEnd->deleted());
caryclark55888e42016-07-18 10:01:36 -07001328 bool flipped = coin->flipped();
caryclark54359292015-03-26 07:52:43 -07001329 if (flipped) {
1330 SkTSwap(oStart, oEnd);
1331 }
caryclark55888e42016-07-18 10:01:36 -07001332 /* coin and opp spans may not match up. Mark the ends, and then let the interior
1333 get marked as many times as the spans allow */
Cary Clark9de09762016-11-17 08:47:37 -05001334 FAIL_IF(!oStart->upCastable());
caryclark55888e42016-07-18 10:01:36 -07001335 start->insertCoincidence(oStart->upCast());
1336 end->insertCoinEnd(oEnd);
1337 const SkOpSegment* segment = start->segment();
1338 const SkOpSegment* oSegment = oStart->segment();
caryclark54359292015-03-26 07:52:43 -07001339 SkOpSpanBase* next = start;
1340 SkOpSpanBase* oNext = oStart;
caryclarka35ab3e2016-10-20 08:32:18 -07001341 bool ordered;
1342 FAIL_IF(!coin->ordered(&ordered));
caryclark55888e42016-07-18 10:01:36 -07001343 while ((next = next->upCast()->next()) != end) {
caryclarke6522ea2016-10-17 07:54:33 -07001344 FAIL_IF(!next->upCastable());
Cary Clark59ed4822016-12-08 16:17:56 -05001345 FAIL_IF(!next->upCast()->insertCoincidence(oSegment, flipped, ordered));
caryclark55888e42016-07-18 10:01:36 -07001346 }
1347 while ((oNext = oNext->upCast()->next()) != oEnd) {
caryclark96dc1c92016-10-20 11:34:10 -07001348 FAIL_IF(!oNext->upCastable());
caryclarke6522ea2016-10-17 07:54:33 -07001349 FAIL_IF(!oNext->upCast()->insertCoincidence(segment, flipped, ordered));
caryclark55888e42016-07-18 10:01:36 -07001350 }
1351 } while ((coin = coin->next()));
caryclarke6522ea2016-10-17 07:54:33 -07001352 return true;
caryclark54359292015-03-26 07:52:43 -07001353}
1354
caryclark55888e42016-07-18 10:01:36 -07001355// Please keep in sync with debugMarkCollapsed()
1356void SkOpCoincidence::markCollapsed(SkCoincidentSpans* coin, SkOpPtT* test) {
1357 SkCoincidentSpans* head = coin;
1358 while (coin) {
1359 if (coin->collapsed(test)) {
1360 if (zero_or_one(coin->coinPtTStart()->fT) && zero_or_one(coin->coinPtTEnd()->fT)) {
1361 coin->coinPtTStartWritable()->segment()->markAllDone();
1362 }
1363 if (zero_or_one(coin->oppPtTStart()->fT) && zero_or_one(coin->oppPtTEnd()->fT)) {
1364 coin->oppPtTStartWritable()->segment()->markAllDone();
1365 }
1366 this->release(head, coin);
1367 }
1368 coin = coin->next();
1369 }
1370}
1371
1372// Please keep in sync with debugMarkCollapsed()
1373void SkOpCoincidence::markCollapsed(SkOpPtT* test) {
1374 markCollapsed(fHead, test);
1375 markCollapsed(fTop, test);
1376}
1377
1378bool SkOpCoincidence::Ordered(const SkOpSegment* coinSeg, const SkOpSegment* oppSeg) {
1379 if (coinSeg->verb() < oppSeg->verb()) {
1380 return true;
1381 }
1382 if (coinSeg->verb() > oppSeg->verb()) {
1383 return false;
1384 }
1385 int count = (SkPathOpsVerbToPoints(coinSeg->verb()) + 1) * 2;
1386 const SkScalar* cPt = &coinSeg->pts()[0].fX;
1387 const SkScalar* oPt = &oppSeg->pts()[0].fX;
1388 for (int index = 0; index < count; ++index) {
1389 if (*cPt < *oPt) {
1390 return true;
1391 }
1392 if (*cPt > *oPt) {
1393 return false;
1394 }
1395 ++cPt;
1396 ++oPt;
1397 }
1398 return true;
1399}
1400
1401bool SkOpCoincidence::overlap(const SkOpPtT* coin1s, const SkOpPtT* coin1e,
caryclark54359292015-03-26 07:52:43 -07001402 const SkOpPtT* coin2s, const SkOpPtT* coin2e, double* overS, double* overE) const {
caryclark27c8eb82015-07-06 11:38:33 -07001403 SkASSERT(coin1s->segment() == coin2s->segment());
caryclark54359292015-03-26 07:52:43 -07001404 *overS = SkTMax(SkTMin(coin1s->fT, coin1e->fT), SkTMin(coin2s->fT, coin2e->fT));
1405 *overE = SkTMin(SkTMax(coin1s->fT, coin1e->fT), SkTMax(coin2s->fT, coin2e->fT));
1406 return *overS < *overE;
1407}
caryclark27c8eb82015-07-06 11:38:33 -07001408
caryclark55888e42016-07-18 10:01:36 -07001409// Commented-out lines keep this in sync with debugRelease()
1410void SkOpCoincidence::release(const SkOpSegment* deleted) {
1411 SkCoincidentSpans* coin = fHead;
1412 if (!coin) {
1413 return;
1414 }
1415 do {
1416 if (coin->coinPtTStart()->segment() == deleted
1417 || coin->coinPtTEnd()->segment() == deleted
1418 || coin->oppPtTStart()->segment() == deleted
1419 || coin->oppPtTEnd()->segment() == deleted) {
1420 this->release(fHead, coin);
1421 }
1422 } while ((coin = coin->next()));
1423}