blob: 176d3556c3c0926089df795889fd7b30b1074d13 [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
Ben Wagnerf08d1d02018-06-18 15:11:00 -040011#include <utility>
12
caryclark55888e42016-07-18 10:01:36 -070013// returns true if coincident span's start and end are the same
14bool SkCoincidentSpans::collapsed(const SkOpPtT* test) const {
15 return (fCoinPtTStart == test && fCoinPtTEnd->contains(test))
16 || (fCoinPtTEnd == test && fCoinPtTStart->contains(test))
17 || (fOppPtTStart == test && fOppPtTEnd->contains(test))
18 || (fOppPtTEnd == test && fOppPtTStart->contains(test));
19}
20
Cary Clarkdb8f44f2016-12-15 09:17:31 -050021// out of line since this function is referenced by address
22const SkOpPtT* SkCoincidentSpans::coinPtTEnd() const {
23 return fCoinPtTEnd;
24}
25
26// out of line since this function is referenced by address
27const SkOpPtT* SkCoincidentSpans::coinPtTStart() const {
28 return fCoinPtTStart;
29}
30
caryclark55888e42016-07-18 10:01:36 -070031// sets the span's end to the ptT referenced by the previous-next
32void SkCoincidentSpans::correctOneEnd(
33 const SkOpPtT* (SkCoincidentSpans::* getEnd)() const,
34 void (SkCoincidentSpans::*setEnd)(const SkOpPtT* ptT) ) {
35 const SkOpPtT* origPtT = (this->*getEnd)();
36 const SkOpSpanBase* origSpan = origPtT->span();
37 const SkOpSpan* prev = origSpan->prev();
38 const SkOpPtT* testPtT = prev ? prev->next()->ptT()
39 : origSpan->upCast()->next()->prev()->ptT();
40 if (origPtT != testPtT) {
41 (this->*setEnd)(testPtT);
caryclarkbca19f72015-05-13 08:23:48 -070042 }
caryclark55888e42016-07-18 10:01:36 -070043}
44
Cary Clarkab87d7a2016-10-04 10:01:04 -040045/* Please keep this in sync with debugCorrectEnds */
caryclark55888e42016-07-18 10:01:36 -070046// FIXME: member pointers have fallen out of favor and can be replaced with
47// an alternative approach.
48// makes all span ends agree with the segment's spans that define them
49void SkCoincidentSpans::correctEnds() {
50 this->correctOneEnd(&SkCoincidentSpans::coinPtTStart, &SkCoincidentSpans::setCoinPtTStart);
51 this->correctOneEnd(&SkCoincidentSpans::coinPtTEnd, &SkCoincidentSpans::setCoinPtTEnd);
52 this->correctOneEnd(&SkCoincidentSpans::oppPtTStart, &SkCoincidentSpans::setOppPtTStart);
53 this->correctOneEnd(&SkCoincidentSpans::oppPtTEnd, &SkCoincidentSpans::setOppPtTEnd);
54}
55
56/* Please keep this in sync with debugExpand */
57// expand the range by checking adjacent spans for coincidence
58bool SkCoincidentSpans::expand() {
59 bool expanded = false;
60 const SkOpSegment* segment = coinPtTStart()->segment();
61 const SkOpSegment* oppSegment = oppPtTStart()->segment();
62 do {
63 const SkOpSpan* start = coinPtTStart()->span()->upCast();
64 const SkOpSpan* prev = start->prev();
65 const SkOpPtT* oppPtT;
66 if (!prev || !(oppPtT = prev->contains(oppSegment))) {
67 break;
68 }
69 double midT = (prev->t() + start->t()) / 2;
70 if (!segment->isClose(midT, oppSegment)) {
71 break;
72 }
73 setStarts(prev->ptT(), oppPtT);
74 expanded = true;
75 } while (true);
76 do {
77 const SkOpSpanBase* end = coinPtTEnd()->span();
78 SkOpSpanBase* next = end->final() ? nullptr : end->upCast()->next();
caryclarkc6d855f2016-08-11 11:59:48 -070079 if (next && next->deleted()) {
80 break;
81 }
caryclark55888e42016-07-18 10:01:36 -070082 const SkOpPtT* oppPtT;
83 if (!next || !(oppPtT = next->contains(oppSegment))) {
84 break;
85 }
86 double midT = (end->t() + next->t()) / 2;
87 if (!segment->isClose(midT, oppSegment)) {
88 break;
89 }
90 setEnds(next->ptT(), oppPtT);
91 expanded = true;
92 } while (true);
93 return expanded;
94}
95
96// increase the range of this span
97bool SkCoincidentSpans::extend(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd,
98 const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) {
99 bool result = false;
100 if (fCoinPtTStart->fT > coinPtTStart->fT || (this->flipped()
101 ? fOppPtTStart->fT < oppPtTStart->fT : fOppPtTStart->fT > oppPtTStart->fT)) {
102 this->setStarts(coinPtTStart, oppPtTStart);
103 result = true;
104 }
105 if (fCoinPtTEnd->fT < coinPtTEnd->fT || (this->flipped()
106 ? fOppPtTEnd->fT > oppPtTEnd->fT : fOppPtTEnd->fT < oppPtTEnd->fT)) {
107 this->setEnds(coinPtTEnd, oppPtTEnd);
108 result = true;
109 }
110 return result;
111}
112
113// set the range of this span
114void SkCoincidentSpans::set(SkCoincidentSpans* next, const SkOpPtT* coinPtTStart,
Cary Clarkab87d7a2016-10-04 10:01:04 -0400115 const SkOpPtT* coinPtTEnd, const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) {
caryclark55888e42016-07-18 10:01:36 -0700116 SkASSERT(SkOpCoincidence::Ordered(coinPtTStart, oppPtTStart));
117 fNext = next;
118 this->setStarts(coinPtTStart, oppPtTStart);
119 this->setEnds(coinPtTEnd, oppPtTEnd);
caryclark55888e42016-07-18 10:01:36 -0700120}
121
122// returns true if both points are inside this
123bool SkCoincidentSpans::contains(const SkOpPtT* s, const SkOpPtT* e) const {
124 if (s->fT > e->fT) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400125 using std::swap;
126 swap(s, e);
caryclark55888e42016-07-18 10:01:36 -0700127 }
128 if (s->segment() == fCoinPtTStart->segment()) {
129 return fCoinPtTStart->fT <= s->fT && e->fT <= fCoinPtTEnd->fT;
130 } else {
131 SkASSERT(s->segment() == fOppPtTStart->segment());
132 double oppTs = fOppPtTStart->fT;
133 double oppTe = fOppPtTEnd->fT;
134 if (oppTs > oppTe) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400135 using std::swap;
136 swap(oppTs, oppTe);
caryclark55888e42016-07-18 10:01:36 -0700137 }
138 return oppTs <= s->fT && e->fT <= oppTe;
139 }
140}
141
Cary Clarkdb8f44f2016-12-15 09:17:31 -0500142// out of line since this function is referenced by address
143const SkOpPtT* SkCoincidentSpans::oppPtTStart() const {
144 return fOppPtTStart;
145}
146
147// out of line since this function is referenced by address
148const SkOpPtT* SkCoincidentSpans::oppPtTEnd() const {
149 return fOppPtTEnd;
150}
151
caryclark81a478c2016-09-09 09:37:57 -0700152// A coincident span is unordered if the pairs of points in the main and opposite curves'
153// t values do not ascend or descend. For instance, if a tightly arced quadratic is
154// coincident with another curve, it may intersect it out of order.
caryclarka35ab3e2016-10-20 08:32:18 -0700155bool SkCoincidentSpans::ordered(bool* result) const {
caryclark81a478c2016-09-09 09:37:57 -0700156 const SkOpSpanBase* start = this->coinPtTStart()->span();
157 const SkOpSpanBase* end = this->coinPtTEnd()->span();
158 const SkOpSpanBase* next = start->upCast()->next();
159 if (next == end) {
caryclarka35ab3e2016-10-20 08:32:18 -0700160 *result = true;
caryclark81a478c2016-09-09 09:37:57 -0700161 return true;
162 }
163 bool flipped = this->flipped();
164 const SkOpSegment* oppSeg = this->oppPtTStart()->segment();
165 double oppLastT = fOppPtTStart->fT;
166 do {
167 const SkOpPtT* opp = next->contains(oppSeg);
168 if (!opp) {
Cary Clarkab2d73b2016-12-16 17:17:25 -0500169// SkOPOBJASSERT(start, 0); // may assert if coincident span isn't fully processed
caryclarka35ab3e2016-10-20 08:32:18 -0700170 return false;
caryclark81a478c2016-09-09 09:37:57 -0700171 }
172 if ((oppLastT > opp->fT) != flipped) {
caryclarka35ab3e2016-10-20 08:32:18 -0700173 *result = false;
174 return true;
caryclark81a478c2016-09-09 09:37:57 -0700175 }
176 oppLastT = opp->fT;
177 if (next == end) {
178 break;
179 }
caryclarkbbfe92b2016-09-19 06:00:35 -0700180 if (!next->upCastable()) {
caryclarka35ab3e2016-10-20 08:32:18 -0700181 *result = false;
182 return true;
caryclarkbbfe92b2016-09-19 06:00:35 -0700183 }
caryclark81a478c2016-09-09 09:37:57 -0700184 next = next->upCast()->next();
185 } while (true);
caryclarka35ab3e2016-10-20 08:32:18 -0700186 *result = true;
caryclark81a478c2016-09-09 09:37:57 -0700187 return true;
188}
189
caryclark55888e42016-07-18 10:01:36 -0700190// if there is an existing pair that overlaps the addition, extend it
191bool SkOpCoincidence::extend(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd,
192 const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) {
193 SkCoincidentSpans* test = fHead;
194 if (!test) {
195 return false;
196 }
197 const SkOpSegment* coinSeg = coinPtTStart->segment();
198 const SkOpSegment* oppSeg = oppPtTStart->segment();
199 if (!Ordered(coinPtTStart, oppPtTStart)) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400200 using std::swap;
201 swap(coinSeg, oppSeg);
202 swap(coinPtTStart, oppPtTStart);
203 swap(coinPtTEnd, oppPtTEnd);
caryclark55888e42016-07-18 10:01:36 -0700204 if (coinPtTStart->fT > coinPtTEnd->fT) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400205 swap(coinPtTStart, coinPtTEnd);
206 swap(oppPtTStart, oppPtTEnd);
caryclark55888e42016-07-18 10:01:36 -0700207 }
208 }
209 double oppMinT = SkTMin(oppPtTStart->fT, oppPtTEnd->fT);
210 SkDEBUGCODE(double oppMaxT = SkTMax(oppPtTStart->fT, oppPtTEnd->fT));
211 do {
212 if (coinSeg != test->coinPtTStart()->segment()) {
213 continue;
214 }
215 if (oppSeg != test->oppPtTStart()->segment()) {
216 continue;
217 }
218 double oTestMinT = SkTMin(test->oppPtTStart()->fT, test->oppPtTEnd()->fT);
219 double oTestMaxT = SkTMax(test->oppPtTStart()->fT, test->oppPtTEnd()->fT);
220 // if debug check triggers, caller failed to check if extended already exists
221 SkASSERT(test->coinPtTStart()->fT > coinPtTStart->fT
222 || coinPtTEnd->fT > test->coinPtTEnd()->fT
223 || oTestMinT > oppMinT || oppMaxT > oTestMaxT);
224 if ((test->coinPtTStart()->fT <= coinPtTEnd->fT
225 && coinPtTStart->fT <= test->coinPtTEnd()->fT)
226 || (oTestMinT <= oTestMaxT && oppMinT <= oTestMaxT)) {
227 test->extend(coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd);
228 return true;
229 }
230 } while ((test = test->next()));
231 return false;
caryclark54359292015-03-26 07:52:43 -0700232}
233
caryclark55888e42016-07-18 10:01:36 -0700234// verifies that the coincidence hasn't already been added
235static void DebugCheckAdd(const SkCoincidentSpans* check, const SkOpPtT* coinPtTStart,
236 const SkOpPtT* coinPtTEnd, const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) {
237#if DEBUG_COINCIDENCE
238 while (check) {
239 SkASSERT(check->coinPtTStart() != coinPtTStart || check->coinPtTEnd() != coinPtTEnd
240 || check->oppPtTStart() != oppPtTStart || check->oppPtTEnd() != oppPtTEnd);
241 SkASSERT(check->coinPtTStart() != oppPtTStart || check->coinPtTEnd() != oppPtTEnd
242 || check->oppPtTStart() != coinPtTStart || check->oppPtTEnd() != coinPtTEnd);
243 check = check->next();
244 }
245#endif
246}
247
248// adds a new coincident pair
249void SkOpCoincidence::add(SkOpPtT* coinPtTStart, SkOpPtT* coinPtTEnd, SkOpPtT* oppPtTStart,
250 SkOpPtT* oppPtTEnd) {
251 // OPTIMIZE: caller should have already sorted
252 if (!Ordered(coinPtTStart, oppPtTStart)) {
253 if (oppPtTStart->fT < oppPtTEnd->fT) {
254 this->add(oppPtTStart, oppPtTEnd, coinPtTStart, coinPtTEnd);
255 } else {
256 this->add(oppPtTEnd, oppPtTStart, coinPtTEnd, coinPtTStart);
257 }
258 return;
259 }
260 SkASSERT(Ordered(coinPtTStart, oppPtTStart));
261 // choose the ptT at the front of the list to track
262 coinPtTStart = coinPtTStart->span()->ptT();
263 coinPtTEnd = coinPtTEnd->span()->ptT();
264 oppPtTStart = oppPtTStart->span()->ptT();
265 oppPtTEnd = oppPtTEnd->span()->ptT();
caryclarka35ab3e2016-10-20 08:32:18 -0700266 SkOPASSERT(coinPtTStart->fT < coinPtTEnd->fT);
caryclark96dc1c92016-10-20 11:34:10 -0700267 SkOPASSERT(oppPtTStart->fT != oppPtTEnd->fT);
caryclark30b9fdd2016-08-31 14:36:29 -0700268 SkOPASSERT(!coinPtTStart->deleted());
269 SkOPASSERT(!coinPtTEnd->deleted());
270 SkOPASSERT(!oppPtTStart->deleted());
271 SkOPASSERT(!oppPtTEnd->deleted());
caryclark55888e42016-07-18 10:01:36 -0700272 DebugCheckAdd(fHead, coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd);
273 DebugCheckAdd(fTop, coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd);
Herb Derbyecc364c2017-04-19 15:09:48 -0400274 SkCoincidentSpans* coinRec = this->globalState()->allocator()->make<SkCoincidentSpans>();
caryclarkfc560e02016-07-27 08:46:10 -0700275 coinRec->init(SkDEBUGCODE(fGlobalState));
Cary Clarkab87d7a2016-10-04 10:01:04 -0400276 coinRec->set(this->fHead, coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd);
caryclark55888e42016-07-18 10:01:36 -0700277 fHead = coinRec;
278}
279
280// description below
caryclark15976282016-07-21 05:48:43 -0700281bool SkOpCoincidence::addEndMovedSpans(const SkOpSpan* base, const SkOpSpanBase* testSpan) {
caryclark55888e42016-07-18 10:01:36 -0700282 const SkOpPtT* testPtT = testSpan->ptT();
283 const SkOpPtT* stopPtT = testPtT;
284 const SkOpSegment* baseSeg = base->segment();
Cary Clark4eed4c82017-03-08 17:11:12 -0500285 int escapeHatch = 100000; // this is 100 times larger than the debugLoopLimit test
caryclark55888e42016-07-18 10:01:36 -0700286 while ((testPtT = testPtT->next()) != stopPtT) {
Cary Clark4eed4c82017-03-08 17:11:12 -0500287 if (--escapeHatch <= 0) {
288 return false; // if triggered (likely by a fuzz-generated test) too complex to succeed
289 }
caryclark55888e42016-07-18 10:01:36 -0700290 const SkOpSegment* testSeg = testPtT->segment();
291 if (testPtT->deleted()) {
292 continue;
293 }
294 if (testSeg == baseSeg) {
295 continue;
296 }
caryclarkc6d855f2016-08-11 11:59:48 -0700297 if (testPtT->span()->ptT() != testPtT) {
298 continue;
299 }
caryclark55888e42016-07-18 10:01:36 -0700300 if (this->contains(baseSeg, testSeg, testPtT->fT)) {
301 continue;
302 }
303 // intersect perp with base->ptT() with testPtT->segment()
304 SkDVector dxdy = baseSeg->dSlopeAtT(base->t());
305 const SkPoint& pt = base->pt();
306 SkDLine ray = {{{pt.fX, pt.fY}, {pt.fX + dxdy.fY, pt.fY - dxdy.fX}}};
Cary Clark4c76c412017-01-20 08:14:33 -0500307 SkIntersections i SkDEBUGCODE((this->globalState()));
caryclark55888e42016-07-18 10:01:36 -0700308 (*CurveIntersectRay[testSeg->verb()])(testSeg->pts(), testSeg->weight(), ray, &i);
309 for (int index = 0; index < i.used(); ++index) {
310 double t = i[0][index];
311 if (!between(0, t, 1)) {
312 continue;
313 }
314 SkDPoint oppPt = i.pt(index);
315 if (!oppPt.approximatelyEqual(pt)) {
316 continue;
317 }
318 SkOpSegment* writableSeg = const_cast<SkOpSegment*>(testSeg);
caryclark29b25632016-08-25 11:27:17 -0700319 SkOpPtT* oppStart = writableSeg->addT(t);
caryclark27c015d2016-09-23 05:47:20 -0700320 if (oppStart == testPtT) {
321 continue;
322 }
caryclark55888e42016-07-18 10:01:36 -0700323 SkOpSpan* writableBase = const_cast<SkOpSpan*>(base);
caryclark30b9fdd2016-08-31 14:36:29 -0700324 oppStart->span()->addOpp(writableBase);
caryclark55888e42016-07-18 10:01:36 -0700325 if (oppStart->deleted()) {
326 continue;
327 }
328 SkOpSegment* coinSeg = base->segment();
329 SkOpSegment* oppSeg = oppStart->segment();
330 double coinTs, coinTe, oppTs, oppTe;
caryclark8016b262016-09-06 05:59:47 -0700331 if (Ordered(coinSeg, oppSeg)) {
caryclark55888e42016-07-18 10:01:36 -0700332 coinTs = base->t();
333 coinTe = testSpan->t();
334 oppTs = oppStart->fT;
335 oppTe = testPtT->fT;
336 } else {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400337 using std::swap;
338 swap(coinSeg, oppSeg);
caryclark55888e42016-07-18 10:01:36 -0700339 coinTs = oppStart->fT;
340 coinTe = testPtT->fT;
341 oppTs = base->t();
342 oppTe = testSpan->t();
343 }
344 if (coinTs > coinTe) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400345 using std::swap;
346 swap(coinTs, coinTe);
347 swap(oppTs, oppTe);
caryclark55888e42016-07-18 10:01:36 -0700348 }
caryclark81a478c2016-09-09 09:37:57 -0700349 bool added;
350 if (!this->addOrOverlap(coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, &added)) {
caryclark15976282016-07-21 05:48:43 -0700351 return false;
352 }
caryclark55888e42016-07-18 10:01:36 -0700353 }
354 }
caryclark15976282016-07-21 05:48:43 -0700355 return true;
caryclark55888e42016-07-18 10:01:36 -0700356}
357
358// description below
359bool SkOpCoincidence::addEndMovedSpans(const SkOpPtT* ptT) {
caryclark025b11e2016-08-25 05:21:14 -0700360 FAIL_IF(!ptT->span()->upCastable());
caryclark55888e42016-07-18 10:01:36 -0700361 const SkOpSpan* base = ptT->span()->upCast();
362 const SkOpSpan* prev = base->prev();
caryclark025b11e2016-08-25 05:21:14 -0700363 FAIL_IF(!prev);
caryclark55888e42016-07-18 10:01:36 -0700364 if (!prev->isCanceled()) {
caryclark15976282016-07-21 05:48:43 -0700365 if (!this->addEndMovedSpans(base, base->prev())) {
366 return false;
367 }
caryclark55888e42016-07-18 10:01:36 -0700368 }
369 if (!base->isCanceled()) {
caryclark15976282016-07-21 05:48:43 -0700370 if (!this->addEndMovedSpans(base, base->next())) {
371 return false;
372 }
caryclark55888e42016-07-18 10:01:36 -0700373 }
374 return true;
375}
376
377/* If A is coincident with B and B includes an endpoint, and A's matching point
378 is not the endpoint (i.e., there's an implied line connecting B-end and A)
379 then assume that the same implied line may intersect another curve close to B.
380 Since we only care about coincidence that was undetected, look at the
381 ptT list on B-segment adjacent to the B-end/A ptT loop (not in the loop, but
382 next door) and see if the A matching point is close enough to form another
383 coincident pair. If so, check for a new coincident span between B-end/A ptT loop
384 and the adjacent ptT loop.
385*/
Cary Clarkab87d7a2016-10-04 10:01:04 -0400386bool SkOpCoincidence::addEndMovedSpans(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
387 DEBUG_SET_PHASE();
caryclark55888e42016-07-18 10:01:36 -0700388 SkCoincidentSpans* span = fHead;
389 if (!span) {
390 return true;
391 }
392 fTop = span;
393 fHead = nullptr;
394 do {
395 if (span->coinPtTStart()->fPt != span->oppPtTStart()->fPt) {
caryclark025b11e2016-08-25 05:21:14 -0700396 FAIL_IF(1 == span->coinPtTStart()->fT);
caryclark55888e42016-07-18 10:01:36 -0700397 bool onEnd = span->coinPtTStart()->fT == 0;
398 bool oOnEnd = zero_or_one(span->oppPtTStart()->fT);
399 if (onEnd) {
400 if (!oOnEnd) { // if both are on end, any nearby intersect was already found
401 if (!this->addEndMovedSpans(span->oppPtTStart())) {
402 return false;
403 }
404 }
405 } else if (oOnEnd) {
406 if (!this->addEndMovedSpans(span->coinPtTStart())) {
407 return false;
408 }
409 }
410 }
411 if (span->coinPtTEnd()->fPt != span->oppPtTEnd()->fPt) {
412 bool onEnd = span->coinPtTEnd()->fT == 1;
413 bool oOnEnd = zero_or_one(span->oppPtTEnd()->fT);
414 if (onEnd) {
415 if (!oOnEnd) {
416 if (!this->addEndMovedSpans(span->oppPtTEnd())) {
417 return false;
418 }
419 }
420 } else if (oOnEnd) {
421 if (!this->addEndMovedSpans(span->coinPtTEnd())) {
422 return false;
423 }
424 }
425 }
426 } while ((span = span->next()));
427 this->restoreHead();
428 return true;
429}
430
431/* Please keep this in sync with debugAddExpanded */
432// for each coincident pair, match the spans
433// 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 -0400434bool SkOpCoincidence::addExpanded(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
435 DEBUG_SET_PHASE();
caryclark55888e42016-07-18 10:01:36 -0700436 SkCoincidentSpans* coin = this->fHead;
437 if (!coin) {
438 return true;
439 }
440 do {
441 const SkOpPtT* startPtT = coin->coinPtTStart();
442 const SkOpPtT* oStartPtT = coin->oppPtTStart();
caryclark8016b262016-09-06 05:59:47 -0700443 double priorT = startPtT->fT;
444 double oPriorT = oStartPtT->fT;
caryclarkbbfe92b2016-09-19 06:00:35 -0700445 FAIL_IF(!startPtT->contains(oStartPtT));
caryclarkc6d855f2016-08-11 11:59:48 -0700446 SkOPASSERT(coin->coinPtTEnd()->contains(coin->oppPtTEnd()));
caryclark55888e42016-07-18 10:01:36 -0700447 const SkOpSpanBase* start = startPtT->span();
448 const SkOpSpanBase* oStart = oStartPtT->span();
449 const SkOpSpanBase* end = coin->coinPtTEnd()->span();
450 const SkOpSpanBase* oEnd = coin->oppPtTEnd()->span();
451 FAIL_IF(oEnd->deleted());
caryclarke25a4f62016-07-26 09:26:29 -0700452 FAIL_IF(!start->upCastable());
caryclark55888e42016-07-18 10:01:36 -0700453 const SkOpSpanBase* test = start->upCast()->next();
caryclarke7bb5b22016-09-22 05:20:07 -0700454 FAIL_IF(!coin->flipped() && !oStart->upCastable());
caryclark55888e42016-07-18 10:01:36 -0700455 const SkOpSpanBase* oTest = coin->flipped() ? oStart->prev() : oStart->upCast()->next();
caryclark30b9fdd2016-08-31 14:36:29 -0700456 FAIL_IF(!oTest);
caryclark8016b262016-09-06 05:59:47 -0700457 SkOpSegment* seg = start->segment();
458 SkOpSegment* oSeg = oStart->segment();
caryclark55888e42016-07-18 10:01:36 -0700459 while (test != end || oTest != oEnd) {
caryclark8016b262016-09-06 05:59:47 -0700460 const SkOpPtT* containedOpp = test->ptT()->contains(oSeg);
461 const SkOpPtT* containedThis = oTest->ptT()->contains(seg);
462 if (!containedOpp || !containedThis) {
463 // choose the ends, or the first common pt-t list shared by both
464 double nextT, oNextT;
465 if (containedOpp) {
466 nextT = test->t();
467 oNextT = containedOpp->fT;
468 } else if (containedThis) {
469 nextT = containedThis->fT;
470 oNextT = oTest->t();
471 } else {
472 // iterate through until a pt-t list found that contains the other
473 const SkOpSpanBase* walk = test;
474 const SkOpPtT* walkOpp;
475 do {
476 FAIL_IF(!walk->upCastable());
477 walk = walk->upCast()->next();
478 } while (!(walkOpp = walk->ptT()->contains(oSeg))
479 && walk != coin->coinPtTEnd()->span());
Cary Clark3fdf52c2016-10-04 10:53:31 -0400480 FAIL_IF(!walkOpp);
caryclark8016b262016-09-06 05:59:47 -0700481 nextT = walk->t();
482 oNextT = walkOpp->fT;
483 }
caryclark55888e42016-07-18 10:01:36 -0700484 // use t ranges to guess which one is missing
caryclark8016b262016-09-06 05:59:47 -0700485 double startRange = nextT - priorT;
caryclark55888e42016-07-18 10:01:36 -0700486 FAIL_IF(!startRange);
caryclark8016b262016-09-06 05:59:47 -0700487 double startPart = (test->t() - priorT) / startRange;
488 double oStartRange = oNextT - oPriorT;
caryclark55888e42016-07-18 10:01:36 -0700489 FAIL_IF(!oStartRange);
caryclark8016b262016-09-06 05:59:47 -0700490 double oStartPart = (oTest->t() - oPriorT) / oStartRange;
caryclark55888e42016-07-18 10:01:36 -0700491 FAIL_IF(startPart == oStartPart);
caryclark8016b262016-09-06 05:59:47 -0700492 bool addToOpp = !containedOpp && !containedThis ? startPart < oStartPart
493 : !!containedThis;
caryclark55888e42016-07-18 10:01:36 -0700494 bool startOver = false;
caryclark8016b262016-09-06 05:59:47 -0700495 bool success = addToOpp ? oSeg->addExpanded(
496 oPriorT + oStartRange * startPart, test, &startOver)
497 : seg->addExpanded(
498 priorT + startRange * oStartPart, oTest, &startOver);
caryclark30b9fdd2016-08-31 14:36:29 -0700499 FAIL_IF(!success);
caryclark55888e42016-07-18 10:01:36 -0700500 if (startOver) {
501 test = start;
502 oTest = oStart;
503 }
caryclark30b9fdd2016-08-31 14:36:29 -0700504 end = coin->coinPtTEnd()->span();
505 oEnd = coin->oppPtTEnd()->span();
caryclark55888e42016-07-18 10:01:36 -0700506 }
507 if (test != end) {
caryclark30b9fdd2016-08-31 14:36:29 -0700508 FAIL_IF(!test->upCastable());
caryclark8016b262016-09-06 05:59:47 -0700509 priorT = test->t();
caryclark55888e42016-07-18 10:01:36 -0700510 test = test->upCast()->next();
511 }
512 if (oTest != oEnd) {
caryclark8016b262016-09-06 05:59:47 -0700513 oPriorT = oTest->t();
caryclark78a37a52016-10-20 12:36:16 -0700514 if (coin->flipped()) {
515 oTest = oTest->prev();
516 } else {
517 FAIL_IF(!oTest->upCastable());
518 oTest = oTest->upCast()->next();
519 }
caryclark30b9fdd2016-08-31 14:36:29 -0700520 FAIL_IF(!oTest);
caryclark55888e42016-07-18 10:01:36 -0700521 }
caryclark8016b262016-09-06 05:59:47 -0700522
caryclark55888e42016-07-18 10:01:36 -0700523 }
524 } while ((coin = coin->next()));
525 return true;
526}
527
caryclark55888e42016-07-18 10:01:36 -0700528// given a t span, map the same range on the coincident span
caryclark8016b262016-09-06 05:59:47 -0700529/*
530the curves may not scale linearly, so interpolation may only happen within known points
531remap over1s, over1e, cointPtTStart, coinPtTEnd to smallest range that captures over1s
532then repeat to capture over1e
533*/
534double SkOpCoincidence::TRange(const SkOpPtT* overS, double t,
535 const SkOpSegment* coinSeg SkDEBUGPARAMS(const SkOpPtT* overE)) {
536 const SkOpSpanBase* work = overS->span();
537 const SkOpPtT* foundStart = nullptr;
538 const SkOpPtT* foundEnd = nullptr;
539 const SkOpPtT* coinStart = nullptr;
540 const SkOpPtT* coinEnd = nullptr;
541 do {
542 const SkOpPtT* contained = work->contains(coinSeg);
543 if (!contained) {
caryclarkc9b90d12016-09-09 07:41:36 -0700544 if (work->final()) {
545 break;
caryclarkb393a492016-09-07 08:21:09 -0700546 }
caryclark8016b262016-09-06 05:59:47 -0700547 continue;
548 }
549 if (work->t() <= t) {
550 coinStart = contained;
551 foundStart = work->ptT();
552 }
553 if (work->t() >= t) {
554 coinEnd = contained;
555 foundEnd = work->ptT();
556 break;
557 }
558 SkASSERT(work->ptT() != overE);
559 } while ((work = work->upCast()->next()));
caryclarkc9b90d12016-09-09 07:41:36 -0700560 if (!coinStart || !coinEnd) {
561 return 1;
562 }
caryclark8016b262016-09-06 05:59:47 -0700563 // while overS->fT <=t and overS contains coinSeg
564 double denom = foundEnd->fT - foundStart->fT;
565 double sRatio = denom ? (t - foundStart->fT) / denom : 1;
566 return coinStart->fT + (coinEnd->fT - coinStart->fT) * sRatio;
caryclark54359292015-03-26 07:52:43 -0700567}
568
caryclark55888e42016-07-18 10:01:36 -0700569// return true if span overlaps existing and needs to adjust the coincident list
570bool SkOpCoincidence::checkOverlap(SkCoincidentSpans* check,
571 const SkOpSegment* coinSeg, const SkOpSegment* oppSeg,
572 double coinTs, double coinTe, double oppTs, double oppTe,
573 SkTDArray<SkCoincidentSpans*>* overlaps) const {
574 if (!Ordered(coinSeg, oppSeg)) {
575 if (oppTs < oppTe) {
576 return this->checkOverlap(check, oppSeg, coinSeg, oppTs, oppTe, coinTs, coinTe,
577 overlaps);
578 }
579 return this->checkOverlap(check, oppSeg, coinSeg, oppTe, oppTs, coinTe, coinTs, overlaps);
580 }
581 bool swapOpp = oppTs > oppTe;
582 if (swapOpp) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400583 using std::swap;
584 swap(oppTs, oppTe);
caryclark55888e42016-07-18 10:01:36 -0700585 }
caryclark27c8eb82015-07-06 11:38:33 -0700586 do {
caryclark55888e42016-07-18 10:01:36 -0700587 if (check->coinPtTStart()->segment() != coinSeg) {
588 continue;
caryclark1c9ce612015-11-20 14:06:28 -0800589 }
caryclark55888e42016-07-18 10:01:36 -0700590 if (check->oppPtTStart()->segment() != oppSeg) {
591 continue;
caryclarkdae6b972016-06-08 04:28:19 -0700592 }
caryclark55888e42016-07-18 10:01:36 -0700593 double checkTs = check->coinPtTStart()->fT;
594 double checkTe = check->coinPtTEnd()->fT;
595 bool coinOutside = coinTe < checkTs || coinTs > checkTe;
596 double oCheckTs = check->oppPtTStart()->fT;
597 double oCheckTe = check->oppPtTEnd()->fT;
598 if (swapOpp) {
599 if (oCheckTs <= oCheckTe) {
caryclark81a478c2016-09-09 09:37:57 -0700600 return false;
caryclark27c8eb82015-07-06 11:38:33 -0700601 }
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400602 using std::swap;
603 swap(oCheckTs, oCheckTe);
caryclark27c8eb82015-07-06 11:38:33 -0700604 }
caryclark55888e42016-07-18 10:01:36 -0700605 bool oppOutside = oppTe < oCheckTs || oppTs > oCheckTe;
606 if (coinOutside && oppOutside) {
607 continue;
608 }
609 bool coinInside = coinTe <= checkTe && coinTs >= checkTs;
610 bool oppInside = oppTe <= oCheckTe && oppTs >= oCheckTs;
caryclark81a478c2016-09-09 09:37:57 -0700611 if (coinInside && oppInside) { // already included, do nothing
612 return false;
caryclark55888e42016-07-18 10:01:36 -0700613 }
614 *overlaps->append() = check; // partial overlap, extend existing entry
615 } while ((check = check->next()));
caryclark26ad22a2015-10-16 09:03:38 -0700616 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700617}
618
caryclark55888e42016-07-18 10:01:36 -0700619/* Please keep this in sync with debugAddIfMissing() */
caryclark8016b262016-09-06 05:59:47 -0700620// note that over1s, over1e, over2s, over2e are ordered
621bool SkOpCoincidence::addIfMissing(const SkOpPtT* over1s, const SkOpPtT* over2s,
Herb Derbyecc364c2017-04-19 15:09:48 -0400622 double tStart, double tEnd, SkOpSegment* coinSeg, SkOpSegment* oppSeg, bool* added
caryclark8016b262016-09-06 05:59:47 -0700623 SkDEBUGPARAMS(const SkOpPtT* over1e) SkDEBUGPARAMS(const SkOpPtT* over2e)) {
624 SkASSERT(tStart < tEnd);
625 SkASSERT(over1s->fT < over1e->fT);
626 SkASSERT(between(over1s->fT, tStart, over1e->fT));
627 SkASSERT(between(over1s->fT, tEnd, over1e->fT));
628 SkASSERT(over2s->fT < over2e->fT);
629 SkASSERT(between(over2s->fT, tStart, over2e->fT));
630 SkASSERT(between(over2s->fT, tEnd, over2e->fT));
631 SkASSERT(over1s->segment() == over1e->segment());
632 SkASSERT(over2s->segment() == over2e->segment());
633 SkASSERT(over1s->segment() == over2s->segment());
634 SkASSERT(over1s->segment() != coinSeg);
635 SkASSERT(over1s->segment() != oppSeg);
636 SkASSERT(coinSeg != oppSeg);
caryclark54359292015-03-26 07:52:43 -0700637 double coinTs, coinTe, oppTs, oppTe;
caryclark8016b262016-09-06 05:59:47 -0700638 coinTs = TRange(over1s, tStart, coinSeg SkDEBUGPARAMS(over1e));
639 coinTe = TRange(over1s, tEnd, coinSeg SkDEBUGPARAMS(over1e));
Cary Clarkba610292018-06-19 09:47:15 -0400640 SkOpSpanBase::Collapsed result = coinSeg->collapsed(coinTs, coinTe);
641 if (SkOpSpanBase::Collapsed::kNo != result) {
642 return SkOpSpanBase::Collapsed::kYes == result;
caryclark30b9fdd2016-08-31 14:36:29 -0700643 }
caryclark8016b262016-09-06 05:59:47 -0700644 oppTs = TRange(over2s, tStart, oppSeg SkDEBUGPARAMS(over2e));
645 oppTe = TRange(over2s, tEnd, oppSeg SkDEBUGPARAMS(over2e));
Cary Clarkba610292018-06-19 09:47:15 -0400646 result = oppSeg->collapsed(oppTs, oppTe);
647 if (SkOpSpanBase::Collapsed::kNo != result) {
648 return SkOpSpanBase::Collapsed::kYes == result;
caryclark30b9fdd2016-08-31 14:36:29 -0700649 }
caryclark8016b262016-09-06 05:59:47 -0700650 if (coinTs > coinTe) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400651 using std::swap;
652 swap(coinTs, coinTe);
653 swap(oppTs, oppTe);
caryclark54359292015-03-26 07:52:43 -0700654 }
Cary Clarkba610292018-06-19 09:47:15 -0400655 (void) this->addOrOverlap(coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, added);
656 return true;
caryclark54359292015-03-26 07:52:43 -0700657}
658
caryclark55888e42016-07-18 10:01:36 -0700659/* Please keep this in sync with debugAddOrOverlap() */
caryclark025b11e2016-08-25 05:21:14 -0700660// If this is called by addEndMovedSpans(), a returned false propogates out to an abort.
661// If this is called by AddIfMissing(), a returned false indicates there was nothing to add
caryclark55888e42016-07-18 10:01:36 -0700662bool SkOpCoincidence::addOrOverlap(SkOpSegment* coinSeg, SkOpSegment* oppSeg,
caryclark81a478c2016-09-09 09:37:57 -0700663 double coinTs, double coinTe, double oppTs, double oppTe, bool* added) {
caryclark55888e42016-07-18 10:01:36 -0700664 SkTDArray<SkCoincidentSpans*> overlaps;
caryclark81a478c2016-09-09 09:37:57 -0700665 FAIL_IF(!fTop);
caryclark55888e42016-07-18 10:01:36 -0700666 if (!this->checkOverlap(fTop, coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, &overlaps)) {
caryclark81a478c2016-09-09 09:37:57 -0700667 return true;
caryclark55888e42016-07-18 10:01:36 -0700668 }
669 if (fHead && !this->checkOverlap(fHead, coinSeg, oppSeg, coinTs,
670 coinTe, oppTs, oppTe, &overlaps)) {
caryclark81a478c2016-09-09 09:37:57 -0700671 return true;
caryclark55888e42016-07-18 10:01:36 -0700672 }
673 SkCoincidentSpans* overlap = overlaps.count() ? overlaps[0] : nullptr;
674 for (int index = 1; index < overlaps.count(); ++index) { // combine overlaps before continuing
675 SkCoincidentSpans* test = overlaps[index];
676 if (overlap->coinPtTStart()->fT > test->coinPtTStart()->fT) {
677 overlap->setCoinPtTStart(test->coinPtTStart());
678 }
679 if (overlap->coinPtTEnd()->fT < test->coinPtTEnd()->fT) {
680 overlap->setCoinPtTEnd(test->coinPtTEnd());
681 }
682 if (overlap->flipped()
683 ? overlap->oppPtTStart()->fT < test->oppPtTStart()->fT
684 : overlap->oppPtTStart()->fT > test->oppPtTStart()->fT) {
685 overlap->setOppPtTStart(test->oppPtTStart());
686 }
687 if (overlap->flipped()
688 ? overlap->oppPtTEnd()->fT > test->oppPtTEnd()->fT
689 : overlap->oppPtTEnd()->fT < test->oppPtTEnd()->fT) {
690 overlap->setOppPtTEnd(test->oppPtTEnd());
691 }
692 if (!fHead || !this->release(fHead, test)) {
693 SkAssertResult(this->release(fTop, test));
694 }
695 }
696 const SkOpPtT* cs = coinSeg->existing(coinTs, oppSeg);
697 const SkOpPtT* ce = coinSeg->existing(coinTe, oppSeg);
caryclark81a478c2016-09-09 09:37:57 -0700698 if (overlap && cs && ce && overlap->contains(cs, ce)) {
699 return true;
700 }
701 FAIL_IF(cs == ce && cs);
caryclark55888e42016-07-18 10:01:36 -0700702 const SkOpPtT* os = oppSeg->existing(oppTs, coinSeg);
703 const SkOpPtT* oe = oppSeg->existing(oppTe, coinSeg);
caryclark81a478c2016-09-09 09:37:57 -0700704 if (overlap && os && oe && overlap->contains(os, oe)) {
705 return true;
706 }
Cary Clarkb8421ed2018-03-14 15:55:02 -0400707 FAIL_IF(cs && cs->deleted());
Cary Clark2f06a532018-03-12 14:41:45 -0400708 FAIL_IF(os && os->deleted());
Cary Clark0949bee2018-03-19 09:42:00 -0400709 FAIL_IF(ce && ce->deleted());
Cary Clark74b42902018-03-09 07:38:47 -0500710 FAIL_IF(oe && oe->deleted());
caryclark55888e42016-07-18 10:01:36 -0700711 const SkOpPtT* csExisting = !cs ? coinSeg->existing(coinTs, nullptr) : nullptr;
712 const SkOpPtT* ceExisting = !ce ? coinSeg->existing(coinTe, nullptr) : nullptr;
caryclark81a478c2016-09-09 09:37:57 -0700713 FAIL_IF(csExisting && csExisting == ceExisting);
caryclarke839e782016-09-15 07:48:18 -0700714// FAIL_IF(csExisting && (csExisting == ce ||
715// csExisting->contains(ceExisting ? ceExisting : ce)));
caryclark81a478c2016-09-09 09:37:57 -0700716 FAIL_IF(ceExisting && (ceExisting == cs ||
caryclark025b11e2016-08-25 05:21:14 -0700717 ceExisting->contains(csExisting ? csExisting : cs)));
caryclark55888e42016-07-18 10:01:36 -0700718 const SkOpPtT* osExisting = !os ? oppSeg->existing(oppTs, nullptr) : nullptr;
719 const SkOpPtT* oeExisting = !oe ? oppSeg->existing(oppTe, nullptr) : nullptr;
caryclark81a478c2016-09-09 09:37:57 -0700720 FAIL_IF(osExisting && osExisting == oeExisting);
721 FAIL_IF(osExisting && (osExisting == oe ||
caryclark025b11e2016-08-25 05:21:14 -0700722 osExisting->contains(oeExisting ? oeExisting : oe)));
caryclark81a478c2016-09-09 09:37:57 -0700723 FAIL_IF(oeExisting && (oeExisting == os ||
caryclark025b11e2016-08-25 05:21:14 -0700724 oeExisting->contains(osExisting ? osExisting : os)));
caryclark55888e42016-07-18 10:01:36 -0700725 // extra line in debug code
726 this->debugValidate();
727 if (!cs || !os) {
728 SkOpPtT* csWritable = cs ? const_cast<SkOpPtT*>(cs)
caryclark29b25632016-08-25 11:27:17 -0700729 : coinSeg->addT(coinTs);
caryclarke839e782016-09-15 07:48:18 -0700730 if (csWritable == ce) {
731 return true;
732 }
caryclark55888e42016-07-18 10:01:36 -0700733 SkOpPtT* osWritable = os ? const_cast<SkOpPtT*>(os)
caryclark29b25632016-08-25 11:27:17 -0700734 : oppSeg->addT(oppTs);
caryclark81a478c2016-09-09 09:37:57 -0700735 FAIL_IF(!csWritable || !osWritable);
caryclark30b9fdd2016-08-31 14:36:29 -0700736 csWritable->span()->addOpp(osWritable->span());
caryclark55888e42016-07-18 10:01:36 -0700737 cs = csWritable;
caryclark30b9fdd2016-08-31 14:36:29 -0700738 os = osWritable->active();
Cary Clark74b42902018-03-09 07:38:47 -0500739 FAIL_IF(!os);
caryclark81a478c2016-09-09 09:37:57 -0700740 FAIL_IF((ce && ce->deleted()) || (oe && oe->deleted()));
caryclark55888e42016-07-18 10:01:36 -0700741 }
742 if (!ce || !oe) {
743 SkOpPtT* ceWritable = ce ? const_cast<SkOpPtT*>(ce)
caryclark29b25632016-08-25 11:27:17 -0700744 : coinSeg->addT(coinTe);
caryclark55888e42016-07-18 10:01:36 -0700745 SkOpPtT* oeWritable = oe ? const_cast<SkOpPtT*>(oe)
caryclark29b25632016-08-25 11:27:17 -0700746 : oppSeg->addT(oppTe);
caryclark30b9fdd2016-08-31 14:36:29 -0700747 ceWritable->span()->addOpp(oeWritable->span());
caryclark55888e42016-07-18 10:01:36 -0700748 ce = ceWritable;
749 oe = oeWritable;
750 }
751 this->debugValidate();
caryclark81a478c2016-09-09 09:37:57 -0700752 FAIL_IF(cs->deleted());
753 FAIL_IF(os->deleted());
754 FAIL_IF(ce->deleted());
755 FAIL_IF(oe->deleted());
756 FAIL_IF(cs->contains(ce) || os->contains(oe));
caryclark55888e42016-07-18 10:01:36 -0700757 bool result = true;
758 if (overlap) {
759 if (overlap->coinPtTStart()->segment() == coinSeg) {
760 result = overlap->extend(cs, ce, os, oe);
761 } else {
762 if (os->fT > oe->fT) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400763 using std::swap;
764 swap(cs, ce);
765 swap(os, oe);
caryclark55888e42016-07-18 10:01:36 -0700766 }
767 result = overlap->extend(os, oe, cs, ce);
768 }
769#if DEBUG_COINCIDENCE_VERBOSE
770 if (result) {
771 overlaps[0]->debugShow();
772 }
773#endif
774 } else {
775 this->add(cs, ce, os, oe);
776#if DEBUG_COINCIDENCE_VERBOSE
777 fHead->debugShow();
778#endif
779 }
780 this->debugValidate();
caryclark81a478c2016-09-09 09:37:57 -0700781 if (result) {
782 *added = true;
783 }
784 return true;
caryclark55888e42016-07-18 10:01:36 -0700785}
786
787// Please keep this in sync with debugAddMissing()
caryclark27c8eb82015-07-06 11:38:33 -0700788/* detects overlaps of different coincident runs on same segment */
789/* does not detect overlaps for pairs without any segments in common */
caryclark55888e42016-07-18 10:01:36 -0700790// returns true if caller should loop again
Cary Clarkab87d7a2016-10-04 10:01:04 -0400791bool SkOpCoincidence::addMissing(bool* added DEBUG_COIN_DECLARE_PARAMS()) {
caryclark27c8eb82015-07-06 11:38:33 -0700792 SkCoincidentSpans* outer = fHead;
caryclark81a478c2016-09-09 09:37:57 -0700793 *added = false;
caryclark54359292015-03-26 07:52:43 -0700794 if (!outer) {
caryclark81a478c2016-09-09 09:37:57 -0700795 return true;
caryclark54359292015-03-26 07:52:43 -0700796 }
caryclark27c8eb82015-07-06 11:38:33 -0700797 fTop = outer;
halcanary96fcdcc2015-08-27 07:41:13 -0700798 fHead = nullptr;
caryclark54359292015-03-26 07:52:43 -0700799 do {
caryclark27c8eb82015-07-06 11:38:33 -0700800 // addifmissing can modify the list that this is walking
caryclark26ad22a2015-10-16 09:03:38 -0700801 // save head so that walker can iterate over old data unperturbed
802 // addifmissing adds to head freely then add saved head in the end
caryclark8016b262016-09-06 05:59:47 -0700803 const SkOpPtT* ocs = outer->coinPtTStart();
caryclarka35ab3e2016-10-20 08:32:18 -0700804 FAIL_IF(ocs->deleted());
caryclark8016b262016-09-06 05:59:47 -0700805 const SkOpSegment* outerCoin = ocs->segment();
Cary Clark18562b82018-06-07 08:06:12 -0400806 FAIL_IF(outerCoin->done());
caryclark8016b262016-09-06 05:59:47 -0700807 const SkOpPtT* oos = outer->oppPtTStart();
caryclarkb393a492016-09-07 08:21:09 -0700808 if (oos->deleted()) {
caryclark81a478c2016-09-09 09:37:57 -0700809 return true;
caryclarkb393a492016-09-07 08:21:09 -0700810 }
caryclark8016b262016-09-06 05:59:47 -0700811 const SkOpSegment* outerOpp = oos->segment();
Cary Clark4c76c412017-01-20 08:14:33 -0500812 SkOPASSERT(!outerOpp->done());
caryclark8016b262016-09-06 05:59:47 -0700813 SkOpSegment* outerCoinWritable = const_cast<SkOpSegment*>(outerCoin);
814 SkOpSegment* outerOppWritable = const_cast<SkOpSegment*>(outerOpp);
caryclark54359292015-03-26 07:52:43 -0700815 SkCoincidentSpans* inner = outer;
Cary Clark4929a4a2018-10-17 14:12:41 -0400816#ifdef IS_FUZZING_WITH_LIBFUZZER
817 int safetyNet = 1000;
818#endif
caryclark55888e42016-07-18 10:01:36 -0700819 while ((inner = inner->next())) {
Cary Clark4929a4a2018-10-17 14:12:41 -0400820#ifdef IS_FUZZING_WITH_LIBFUZZER
821 if (!--safetyNet) {
822 return false;
823 }
824#endif
caryclark55888e42016-07-18 10:01:36 -0700825 this->debugValidate();
caryclark54359292015-03-26 07:52:43 -0700826 double overS, overE;
caryclark8016b262016-09-06 05:59:47 -0700827 const SkOpPtT* ics = inner->coinPtTStart();
caryclark221a4bb2016-10-07 11:15:15 -0700828 FAIL_IF(ics->deleted());
caryclark8016b262016-09-06 05:59:47 -0700829 const SkOpSegment* innerCoin = ics->segment();
caryclarka35ab3e2016-10-20 08:32:18 -0700830 FAIL_IF(innerCoin->done());
caryclark8016b262016-09-06 05:59:47 -0700831 const SkOpPtT* ios = inner->oppPtTStart();
caryclarka35ab3e2016-10-20 08:32:18 -0700832 FAIL_IF(ios->deleted());
caryclark8016b262016-09-06 05:59:47 -0700833 const SkOpSegment* innerOpp = ios->segment();
Cary Clark4c76c412017-01-20 08:14:33 -0500834 SkOPASSERT(!innerOpp->done());
caryclark8016b262016-09-06 05:59:47 -0700835 SkOpSegment* innerCoinWritable = const_cast<SkOpSegment*>(innerCoin);
836 SkOpSegment* innerOppWritable = const_cast<SkOpSegment*>(innerOpp);
caryclark55888e42016-07-18 10:01:36 -0700837 if (outerCoin == innerCoin) {
caryclark8016b262016-09-06 05:59:47 -0700838 const SkOpPtT* oce = outer->coinPtTEnd();
caryclarkb393a492016-09-07 08:21:09 -0700839 if (oce->deleted()) {
caryclark81a478c2016-09-09 09:37:57 -0700840 return true;
caryclarkb393a492016-09-07 08:21:09 -0700841 }
caryclark8016b262016-09-06 05:59:47 -0700842 const SkOpPtT* ice = inner->coinPtTEnd();
caryclark595ac282016-10-24 08:41:45 -0700843 FAIL_IF(ice->deleted());
caryclark8016b262016-09-06 05:59:47 -0700844 if (outerOpp != innerOpp && this->overlap(ocs, oce, ics, ice, &overS, &overE)) {
Cary Clarkba610292018-06-19 09:47:15 -0400845 FAIL_IF(!this->addIfMissing(ocs->starter(oce), ics->starter(ice),
caryclark81a478c2016-09-09 09:37:57 -0700846 overS, overE, outerOppWritable, innerOppWritable, added
caryclark8016b262016-09-06 05:59:47 -0700847 SkDEBUGPARAMS(ocs->debugEnder(oce))
Cary Clarkba610292018-06-19 09:47:15 -0400848 SkDEBUGPARAMS(ics->debugEnder(ice))));
caryclark55888e42016-07-18 10:01:36 -0700849 }
850 } else if (outerCoin == innerOpp) {
caryclark8016b262016-09-06 05:59:47 -0700851 const SkOpPtT* oce = outer->coinPtTEnd();
Cary Clark56071432018-06-19 08:33:52 -0400852 FAIL_IF(oce->deleted());
caryclark8016b262016-09-06 05:59:47 -0700853 const SkOpPtT* ioe = inner->oppPtTEnd();
854 SkASSERT(!ioe->deleted());
855 if (outerOpp != innerCoin && this->overlap(ocs, oce, ios, ioe, &overS, &overE)) {
Cary Clarkba610292018-06-19 09:47:15 -0400856 FAIL_IF(!this->addIfMissing(ocs->starter(oce), ios->starter(ioe),
caryclark81a478c2016-09-09 09:37:57 -0700857 overS, overE, outerOppWritable, innerCoinWritable, added
caryclark8016b262016-09-06 05:59:47 -0700858 SkDEBUGPARAMS(ocs->debugEnder(oce))
Cary Clarkba610292018-06-19 09:47:15 -0400859 SkDEBUGPARAMS(ios->debugEnder(ioe))));
caryclark55888e42016-07-18 10:01:36 -0700860 }
861 } else if (outerOpp == innerCoin) {
caryclark8016b262016-09-06 05:59:47 -0700862 const SkOpPtT* ooe = outer->oppPtTEnd();
863 SkASSERT(!ooe->deleted());
864 const SkOpPtT* ice = inner->coinPtTEnd();
865 SkASSERT(!ice->deleted());
caryclark55888e42016-07-18 10:01:36 -0700866 SkASSERT(outerCoin != innerOpp);
caryclark8016b262016-09-06 05:59:47 -0700867 if (this->overlap(oos, ooe, ics, ice, &overS, &overE)) {
Cary Clarkba610292018-06-19 09:47:15 -0400868 FAIL_IF(!this->addIfMissing(oos->starter(ooe), ics->starter(ice),
caryclark81a478c2016-09-09 09:37:57 -0700869 overS, overE, outerCoinWritable, innerOppWritable, added
caryclark8016b262016-09-06 05:59:47 -0700870 SkDEBUGPARAMS(oos->debugEnder(ooe))
Cary Clarkba610292018-06-19 09:47:15 -0400871 SkDEBUGPARAMS(ics->debugEnder(ice))));
caryclark55888e42016-07-18 10:01:36 -0700872 }
873 } else if (outerOpp == innerOpp) {
caryclark8016b262016-09-06 05:59:47 -0700874 const SkOpPtT* ooe = outer->oppPtTEnd();
Cary Clark8d8a5d92018-04-02 12:40:49 -0400875 FAIL_IF(ooe->deleted());
caryclark8016b262016-09-06 05:59:47 -0700876 const SkOpPtT* ioe = inner->oppPtTEnd();
caryclarkb393a492016-09-07 08:21:09 -0700877 if (ioe->deleted()) {
caryclark81a478c2016-09-09 09:37:57 -0700878 return true;
caryclarkb393a492016-09-07 08:21:09 -0700879 }
caryclark55888e42016-07-18 10:01:36 -0700880 SkASSERT(outerCoin != innerCoin);
caryclark8016b262016-09-06 05:59:47 -0700881 if (this->overlap(oos, ooe, ios, ioe, &overS, &overE)) {
Cary Clarkba610292018-06-19 09:47:15 -0400882 FAIL_IF(!this->addIfMissing(oos->starter(ooe), ios->starter(ioe),
caryclark81a478c2016-09-09 09:37:57 -0700883 overS, overE, outerCoinWritable, innerCoinWritable, added
caryclark8016b262016-09-06 05:59:47 -0700884 SkDEBUGPARAMS(oos->debugEnder(ooe))
Cary Clarkba610292018-06-19 09:47:15 -0400885 SkDEBUGPARAMS(ios->debugEnder(ioe))));
caryclark54359292015-03-26 07:52:43 -0700886 }
887 }
caryclark55888e42016-07-18 10:01:36 -0700888 this->debugValidate();
caryclark54359292015-03-26 07:52:43 -0700889 }
caryclark55888e42016-07-18 10:01:36 -0700890 } while ((outer = outer->next()));
891 this->restoreHead();
caryclark81a478c2016-09-09 09:37:57 -0700892 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700893}
894
caryclark55888e42016-07-18 10:01:36 -0700895bool SkOpCoincidence::addOverlap(const SkOpSegment* seg1, const SkOpSegment* seg1o,
896 const SkOpSegment* seg2, const SkOpSegment* seg2o,
897 const SkOpPtT* overS, const SkOpPtT* overE) {
Cary Clarke47ae292016-10-05 08:51:39 -0400898 const SkOpPtT* s1 = overS->find(seg1);
899 const SkOpPtT* e1 = overE->find(seg1);
caryclark08714012016-10-07 12:57:47 -0700900 FAIL_IF(!s1);
Cary Clark40f23782016-10-06 12:04:16 -0400901 FAIL_IF(!e1);
caryclark27c8eb82015-07-06 11:38:33 -0700902 if (!s1->starter(e1)->span()->upCast()->windValue()) {
Cary Clarke47ae292016-10-05 08:51:39 -0400903 s1 = overS->find(seg1o);
904 e1 = overE->find(seg1o);
caryclark221a4bb2016-10-07 11:15:15 -0700905 FAIL_IF(!s1);
Cary Clark40f23782016-10-06 12:04:16 -0400906 FAIL_IF(!e1);
caryclark27c8eb82015-07-06 11:38:33 -0700907 if (!s1->starter(e1)->span()->upCast()->windValue()) {
caryclark3f0753d2016-06-28 09:23:57 -0700908 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700909 }
910 }
Cary Clarke47ae292016-10-05 08:51:39 -0400911 const SkOpPtT* s2 = overS->find(seg2);
912 const SkOpPtT* e2 = overE->find(seg2);
caryclark82616712016-10-24 04:53:22 -0700913 FAIL_IF(!s2);
caryclarka35ab3e2016-10-20 08:32:18 -0700914 FAIL_IF(!e2);
caryclark27c8eb82015-07-06 11:38:33 -0700915 if (!s2->starter(e2)->span()->upCast()->windValue()) {
Cary Clarke47ae292016-10-05 08:51:39 -0400916 s2 = overS->find(seg2o);
917 e2 = overE->find(seg2o);
caryclarka35ab3e2016-10-20 08:32:18 -0700918 FAIL_IF(!s2);
caryclark78a37a52016-10-20 12:36:16 -0700919 FAIL_IF(!e2);
caryclark27c8eb82015-07-06 11:38:33 -0700920 if (!s2->starter(e2)->span()->upCast()->windValue()) {
caryclark3f0753d2016-06-28 09:23:57 -0700921 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700922 }
923 }
924 if (s1->segment() == s2->segment()) {
caryclark3f0753d2016-06-28 09:23:57 -0700925 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700926 }
927 if (s1->fT > e1->fT) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400928 using std::swap;
929 swap(s1, e1);
930 swap(s2, e2);
caryclark27c8eb82015-07-06 11:38:33 -0700931 }
caryclark55888e42016-07-18 10:01:36 -0700932 this->add(s1, e1, s2, e2);
caryclark3f0753d2016-06-28 09:23:57 -0700933 return true;
caryclark54359292015-03-26 07:52:43 -0700934}
935
caryclark55888e42016-07-18 10:01:36 -0700936bool SkOpCoincidence::contains(const SkOpSegment* seg, const SkOpSegment* opp, double oppT) const {
937 if (this->contains(fHead, seg, opp, oppT)) {
938 return true;
939 }
940 if (this->contains(fTop, seg, opp, oppT)) {
941 return true;
942 }
943 return false;
944}
945
946bool SkOpCoincidence::contains(const SkCoincidentSpans* coin, const SkOpSegment* seg,
947 const SkOpSegment* opp, double oppT) const {
948 if (!coin) {
949 return false;
950 }
951 do {
952 if (coin->coinPtTStart()->segment() == seg && coin->oppPtTStart()->segment() == opp
953 && between(coin->oppPtTStart()->fT, oppT, coin->oppPtTEnd()->fT)) {
caryclark54359292015-03-26 07:52:43 -0700954 return true;
955 }
caryclark55888e42016-07-18 10:01:36 -0700956 if (coin->oppPtTStart()->segment() == seg && coin->coinPtTStart()->segment() == opp
957 && between(coin->coinPtTStart()->fT, oppT, coin->coinPtTEnd()->fT)) {
958 return true;
959 }
960 } while ((coin = coin->next()));
caryclark54359292015-03-26 07:52:43 -0700961 return false;
962}
963
caryclark55888e42016-07-18 10:01:36 -0700964bool SkOpCoincidence::contains(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd,
965 const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) const {
966 const SkCoincidentSpans* test = fHead;
967 if (!test) {
968 return false;
969 }
970 const SkOpSegment* coinSeg = coinPtTStart->segment();
971 const SkOpSegment* oppSeg = oppPtTStart->segment();
972 if (!Ordered(coinPtTStart, oppPtTStart)) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400973 using std::swap;
974 swap(coinSeg, oppSeg);
975 swap(coinPtTStart, oppPtTStart);
976 swap(coinPtTEnd, oppPtTEnd);
caryclark55888e42016-07-18 10:01:36 -0700977 if (coinPtTStart->fT > coinPtTEnd->fT) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400978 swap(coinPtTStart, coinPtTEnd);
979 swap(oppPtTStart, oppPtTEnd);
caryclark55888e42016-07-18 10:01:36 -0700980 }
981 }
982 double oppMinT = SkTMin(oppPtTStart->fT, oppPtTEnd->fT);
983 double oppMaxT = SkTMax(oppPtTStart->fT, oppPtTEnd->fT);
984 do {
985 if (coinSeg != test->coinPtTStart()->segment()) {
986 continue;
987 }
988 if (coinPtTStart->fT < test->coinPtTStart()->fT) {
989 continue;
990 }
991 if (coinPtTEnd->fT > test->coinPtTEnd()->fT) {
992 continue;
993 }
994 if (oppSeg != test->oppPtTStart()->segment()) {
995 continue;
996 }
997 if (oppMinT < SkTMin(test->oppPtTStart()->fT, test->oppPtTEnd()->fT)) {
998 continue;
999 }
1000 if (oppMaxT > SkTMax(test->oppPtTStart()->fT, test->oppPtTEnd()->fT)) {
1001 continue;
1002 }
1003 return true;
1004 } while ((test = test->next()));
1005 return false;
1006}
1007
Cary Clarkab87d7a2016-10-04 10:01:04 -04001008void SkOpCoincidence::correctEnds(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
1009 DEBUG_SET_PHASE();
caryclark55888e42016-07-18 10:01:36 -07001010 SkCoincidentSpans* coin = fHead;
1011 if (!coin) {
1012 return;
1013 }
1014 do {
1015 coin->correctEnds();
1016 } while ((coin = coin->next()));
1017}
1018
caryclark54359292015-03-26 07:52:43 -07001019// walk span sets in parallel, moving winding from one to the other
caryclarka35ab3e2016-10-20 08:32:18 -07001020bool SkOpCoincidence::apply(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
Cary Clarkab87d7a2016-10-04 10:01:04 -04001021 DEBUG_SET_PHASE();
caryclark54359292015-03-26 07:52:43 -07001022 SkCoincidentSpans* coin = fHead;
1023 if (!coin) {
caryclarka35ab3e2016-10-20 08:32:18 -07001024 return true;
caryclark54359292015-03-26 07:52:43 -07001025 }
1026 do {
Cary Clark5a2057a2017-01-03 10:47:34 -05001027 SkOpSpanBase* startSpan = coin->coinPtTStartWritable()->span();
1028 FAIL_IF(!startSpan->upCastable());
1029 SkOpSpan* start = startSpan->upCast();
caryclark182b4992015-05-14 05:45:54 -07001030 if (start->deleted()) {
1031 continue;
1032 }
caryclark55888e42016-07-18 10:01:36 -07001033 const SkOpSpanBase* end = coin->coinPtTEnd()->span();
caryclark54359292015-03-26 07:52:43 -07001034 SkASSERT(start == start->starter(end));
caryclark55888e42016-07-18 10:01:36 -07001035 bool flipped = coin->flipped();
caryclark96dc1c92016-10-20 11:34:10 -07001036 SkOpSpanBase* oStartBase = (flipped ? coin->oppPtTEndWritable()
1037 : coin->oppPtTStartWritable())->span();
1038 FAIL_IF(!oStartBase->upCastable());
1039 SkOpSpan* oStart = oStartBase->upCast();
caryclark182b4992015-05-14 05:45:54 -07001040 if (oStart->deleted()) {
1041 continue;
1042 }
caryclark55888e42016-07-18 10:01:36 -07001043 const SkOpSpanBase* oEnd = (flipped ? coin->oppPtTStart() : coin->oppPtTEnd())->span();
caryclark54359292015-03-26 07:52:43 -07001044 SkASSERT(oStart == oStart->starter(oEnd));
1045 SkOpSegment* segment = start->segment();
1046 SkOpSegment* oSegment = oStart->segment();
1047 bool operandSwap = segment->operand() != oSegment->operand();
1048 if (flipped) {
caryclark364a0072015-12-14 08:43:21 -08001049 if (oEnd->deleted()) {
1050 continue;
1051 }
caryclark54359292015-03-26 07:52:43 -07001052 do {
1053 SkOpSpanBase* oNext = oStart->next();
1054 if (oNext == oEnd) {
1055 break;
1056 }
Cary Clark26ae5ab2016-12-12 13:57:56 -05001057 FAIL_IF(!oNext->upCastable());
caryclark54359292015-03-26 07:52:43 -07001058 oStart = oNext->upCast();
1059 } while (true);
1060 }
caryclark54359292015-03-26 07:52:43 -07001061 do {
1062 int windValue = start->windValue();
caryclark54359292015-03-26 07:52:43 -07001063 int oppValue = start->oppValue();
caryclark1049f122015-04-20 08:31:59 -07001064 int oWindValue = oStart->windValue();
caryclark54359292015-03-26 07:52:43 -07001065 int oOppValue = oStart->oppValue();
1066 // winding values are added or subtracted depending on direction and wind type
1067 // same or opposite values are summed depending on the operand value
caryclark1049f122015-04-20 08:31:59 -07001068 int windDiff = operandSwap ? oOppValue : oWindValue;
1069 int oWindDiff = operandSwap ? oppValue : windValue;
1070 if (!flipped) {
1071 windDiff = -windDiff;
1072 oWindDiff = -oWindDiff;
1073 }
caryclark55888e42016-07-18 10:01:36 -07001074 bool addToStart = windValue && (windValue > windDiff || (windValue == windDiff
1075 && oWindValue <= oWindDiff));
1076 if (addToStart ? start->done() : oStart->done()) {
1077 addToStart ^= true;
1078 }
1079 if (addToStart) {
caryclark54359292015-03-26 07:52:43 -07001080 if (operandSwap) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -04001081 using std::swap;
1082 swap(oWindValue, oOppValue);
caryclark54359292015-03-26 07:52:43 -07001083 }
1084 if (flipped) {
1085 windValue -= oWindValue;
1086 oppValue -= oOppValue;
1087 } else {
1088 windValue += oWindValue;
1089 oppValue += oOppValue;
1090 }
caryclark1049f122015-04-20 08:31:59 -07001091 if (segment->isXor()) {
caryclark54359292015-03-26 07:52:43 -07001092 windValue &= 1;
1093 }
caryclark1049f122015-04-20 08:31:59 -07001094 if (segment->oppXor()) {
caryclark54359292015-03-26 07:52:43 -07001095 oppValue &= 1;
1096 }
1097 oWindValue = oOppValue = 0;
1098 } else {
1099 if (operandSwap) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -04001100 using std::swap;
1101 swap(windValue, oppValue);
caryclark54359292015-03-26 07:52:43 -07001102 }
1103 if (flipped) {
1104 oWindValue -= windValue;
1105 oOppValue -= oppValue;
1106 } else {
1107 oWindValue += windValue;
1108 oOppValue += oppValue;
1109 }
caryclark1049f122015-04-20 08:31:59 -07001110 if (oSegment->isXor()) {
caryclark54359292015-03-26 07:52:43 -07001111 oWindValue &= 1;
1112 }
caryclark1049f122015-04-20 08:31:59 -07001113 if (oSegment->oppXor()) {
1114 oOppValue &= 1;
1115 }
caryclark54359292015-03-26 07:52:43 -07001116 windValue = oppValue = 0;
1117 }
caryclark6c3b9cd2016-09-26 05:36:58 -07001118#if 0 && DEBUG_COINCIDENCE
caryclark55888e42016-07-18 10:01:36 -07001119 SkDebugf("seg=%d span=%d windValue=%d oppValue=%d\n", segment->debugID(),
1120 start->debugID(), windValue, oppValue);
1121 SkDebugf("seg=%d span=%d windValue=%d oppValue=%d\n", oSegment->debugID(),
1122 oStart->debugID(), oWindValue, oOppValue);
1123#endif
Cary Clark0949bee2018-03-19 09:42:00 -04001124 FAIL_IF(windValue <= -1);
caryclark54359292015-03-26 07:52:43 -07001125 start->setWindValue(windValue);
1126 start->setOppValue(oppValue);
Cary Clarkb8421ed2018-03-14 15:55:02 -04001127 FAIL_IF(oWindValue <= -1);
caryclark54359292015-03-26 07:52:43 -07001128 oStart->setWindValue(oWindValue);
1129 oStart->setOppValue(oOppValue);
1130 if (!windValue && !oppValue) {
1131 segment->markDone(start);
1132 }
1133 if (!oWindValue && !oOppValue) {
1134 oSegment->markDone(oStart);
1135 }
1136 SkOpSpanBase* next = start->next();
1137 SkOpSpanBase* oNext = flipped ? oStart->prev() : oStart->next();
1138 if (next == end) {
1139 break;
1140 }
caryclark96dc1c92016-10-20 11:34:10 -07001141 FAIL_IF(!next->upCastable());
caryclark54359292015-03-26 07:52:43 -07001142 start = next->upCast();
caryclark1049f122015-04-20 08:31:59 -07001143 // if the opposite ran out too soon, just reuse the last span
1144 if (!oNext || !oNext->upCastable()) {
1145 oNext = oStart;
caryclark54359292015-03-26 07:52:43 -07001146 }
1147 oStart = oNext->upCast();
1148 } while (true);
caryclark55888e42016-07-18 10:01:36 -07001149 } while ((coin = coin->next()));
caryclarka35ab3e2016-10-20 08:32:18 -07001150 return true;
caryclark54359292015-03-26 07:52:43 -07001151}
1152
caryclark55888e42016-07-18 10:01:36 -07001153// Please keep this in sync with debugRelease()
1154bool SkOpCoincidence::release(SkCoincidentSpans* coin, SkCoincidentSpans* remove) {
1155 SkCoincidentSpans* head = coin;
halcanary96fcdcc2015-08-27 07:41:13 -07001156 SkCoincidentSpans* prev = nullptr;
caryclark54359292015-03-26 07:52:43 -07001157 SkCoincidentSpans* next;
1158 do {
caryclark55888e42016-07-18 10:01:36 -07001159 next = coin->next();
caryclark54359292015-03-26 07:52:43 -07001160 if (coin == remove) {
1161 if (prev) {
caryclark55888e42016-07-18 10:01:36 -07001162 prev->setNext(next);
1163 } else if (head == fHead) {
caryclark54359292015-03-26 07:52:43 -07001164 fHead = next;
caryclark55888e42016-07-18 10:01:36 -07001165 } else {
1166 fTop = next;
caryclark54359292015-03-26 07:52:43 -07001167 }
1168 break;
1169 }
1170 prev = coin;
1171 } while ((coin = next));
caryclark55888e42016-07-18 10:01:36 -07001172 return coin != nullptr;
caryclark54359292015-03-26 07:52:43 -07001173}
1174
caryclark30b9fdd2016-08-31 14:36:29 -07001175void SkOpCoincidence::releaseDeleted(SkCoincidentSpans* coin) {
1176 if (!coin) {
1177 return;
1178 }
1179 SkCoincidentSpans* head = coin;
1180 SkCoincidentSpans* prev = nullptr;
1181 SkCoincidentSpans* next;
1182 do {
1183 next = coin->next();
1184 if (coin->coinPtTStart()->deleted()) {
1185 SkOPASSERT(coin->flipped() ? coin->oppPtTEnd()->deleted() :
1186 coin->oppPtTStart()->deleted());
1187 if (prev) {
1188 prev->setNext(next);
1189 } else if (head == fHead) {
1190 fHead = next;
1191 } else {
1192 fTop = next;
1193 }
1194 } else {
1195 SkOPASSERT(coin->flipped() ? !coin->oppPtTEnd()->deleted() :
1196 !coin->oppPtTStart()->deleted());
1197 prev = coin;
1198 }
1199 } while ((coin = next));
1200}
1201
1202void SkOpCoincidence::releaseDeleted() {
1203 this->releaseDeleted(fHead);
1204 this->releaseDeleted(fTop);
1205}
1206
caryclark55888e42016-07-18 10:01:36 -07001207void SkOpCoincidence::restoreHead() {
1208 SkCoincidentSpans** headPtr = &fHead;
1209 while (*headPtr) {
1210 headPtr = (*headPtr)->nextPtr();
1211 }
1212 *headPtr = fTop;
1213 fTop = nullptr;
1214 // segments may have collapsed in the meantime; remove empty referenced segments
1215 headPtr = &fHead;
1216 while (*headPtr) {
1217 SkCoincidentSpans* test = *headPtr;
1218 if (test->coinPtTStart()->segment()->done() || test->oppPtTStart()->segment()->done()) {
1219 *headPtr = test->next();
1220 continue;
1221 }
1222 headPtr = (*headPtr)->nextPtr();
1223 }
1224}
1225
1226// Please keep this in sync with debugExpand()
caryclark30b9fdd2016-08-31 14:36:29 -07001227// expand the range by checking adjacent spans for coincidence
Cary Clarkab87d7a2016-10-04 10:01:04 -04001228bool SkOpCoincidence::expand(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
1229 DEBUG_SET_PHASE();
caryclark54359292015-03-26 07:52:43 -07001230 SkCoincidentSpans* coin = fHead;
1231 if (!coin) {
caryclark27c8eb82015-07-06 11:38:33 -07001232 return false;
caryclark54359292015-03-26 07:52:43 -07001233 }
caryclark27c8eb82015-07-06 11:38:33 -07001234 bool expanded = false;
caryclark54359292015-03-26 07:52:43 -07001235 do {
caryclark55888e42016-07-18 10:01:36 -07001236 if (coin->expand()) {
1237 // check to see if multiple spans expanded so they are now identical
1238 SkCoincidentSpans* test = fHead;
1239 do {
1240 if (coin == test) {
1241 continue;
1242 }
1243 if (coin->coinPtTStart() == test->coinPtTStart()
1244 && coin->oppPtTStart() == test->oppPtTStart()) {
1245 this->release(fHead, test);
1246 break;
1247 }
1248 } while ((test = test->next()));
1249 expanded = true;
caryclark54359292015-03-26 07:52:43 -07001250 }
caryclark55888e42016-07-18 10:01:36 -07001251 } while ((coin = coin->next()));
caryclark27c8eb82015-07-06 11:38:33 -07001252 return expanded;
1253}
1254
Cary Clark40f23782016-10-06 12:04:16 -04001255bool SkOpCoincidence::findOverlaps(SkOpCoincidence* overlaps DEBUG_COIN_DECLARE_PARAMS()) const {
Cary Clarkab87d7a2016-10-04 10:01:04 -04001256 DEBUG_SET_PHASE();
halcanary96fcdcc2015-08-27 07:41:13 -07001257 overlaps->fHead = overlaps->fTop = nullptr;
caryclark27c8eb82015-07-06 11:38:33 -07001258 SkCoincidentSpans* outer = fHead;
1259 while (outer) {
caryclark55888e42016-07-18 10:01:36 -07001260 const SkOpSegment* outerCoin = outer->coinPtTStart()->segment();
1261 const SkOpSegment* outerOpp = outer->oppPtTStart()->segment();
caryclark27c8eb82015-07-06 11:38:33 -07001262 SkCoincidentSpans* inner = outer;
caryclark55888e42016-07-18 10:01:36 -07001263 while ((inner = inner->next())) {
1264 const SkOpSegment* innerCoin = inner->coinPtTStart()->segment();
caryclark27c8eb82015-07-06 11:38:33 -07001265 if (outerCoin == innerCoin) {
1266 continue; // both winners are the same segment, so there's no additional overlap
1267 }
caryclark55888e42016-07-18 10:01:36 -07001268 const SkOpSegment* innerOpp = inner->oppPtTStart()->segment();
1269 const SkOpPtT* overlapS;
1270 const SkOpPtT* overlapE;
1271 if ((outerOpp == innerCoin && SkOpPtT::Overlaps(outer->oppPtTStart(),
1272 outer->oppPtTEnd(),inner->coinPtTStart(), inner->coinPtTEnd(), &overlapS,
1273 &overlapE))
1274 || (outerCoin == innerOpp && SkOpPtT::Overlaps(outer->coinPtTStart(),
1275 outer->coinPtTEnd(), inner->oppPtTStart(), inner->oppPtTEnd(),
caryclark27c8eb82015-07-06 11:38:33 -07001276 &overlapS, &overlapE))
caryclark55888e42016-07-18 10:01:36 -07001277 || (outerOpp == innerOpp && SkOpPtT::Overlaps(outer->oppPtTStart(),
1278 outer->oppPtTEnd(), inner->oppPtTStart(), inner->oppPtTEnd(),
caryclark27c8eb82015-07-06 11:38:33 -07001279 &overlapS, &overlapE))) {
Cary Clark40f23782016-10-06 12:04:16 -04001280 if (!overlaps->addOverlap(outerCoin, outerOpp, innerCoin, innerOpp,
1281 overlapS, overlapE)) {
1282 return false;
1283 }
Cary Clarke47ae292016-10-05 08:51:39 -04001284 }
caryclark27c8eb82015-07-06 11:38:33 -07001285 }
caryclark55888e42016-07-18 10:01:36 -07001286 outer = outer->next();
caryclark27c8eb82015-07-06 11:38:33 -07001287 }
Cary Clark40f23782016-10-06 12:04:16 -04001288 return true;
caryclark27c8eb82015-07-06 11:38:33 -07001289}
1290
caryclark55888e42016-07-18 10:01:36 -07001291void SkOpCoincidence::fixUp(SkOpPtT* deleted, const SkOpPtT* kept) {
caryclarkb393a492016-09-07 08:21:09 -07001292 SkOPASSERT(deleted != kept);
caryclark55888e42016-07-18 10:01:36 -07001293 if (fHead) {
1294 this->fixUp(fHead, deleted, kept);
caryclark54359292015-03-26 07:52:43 -07001295 }
caryclark55888e42016-07-18 10:01:36 -07001296 if (fTop) {
1297 this->fixUp(fTop, deleted, kept);
1298 }
caryclark54359292015-03-26 07:52:43 -07001299}
1300
caryclark55888e42016-07-18 10:01:36 -07001301void SkOpCoincidence::fixUp(SkCoincidentSpans* coin, SkOpPtT* deleted, const SkOpPtT* kept) {
1302 SkCoincidentSpans* head = coin;
1303 do {
1304 if (coin->coinPtTStart() == deleted) {
1305 if (coin->coinPtTEnd()->span() == kept->span()) {
1306 this->release(head, coin);
1307 continue;
1308 }
1309 coin->setCoinPtTStart(kept);
1310 }
1311 if (coin->coinPtTEnd() == deleted) {
1312 if (coin->coinPtTStart()->span() == kept->span()) {
1313 this->release(head, coin);
1314 continue;
1315 }
1316 coin->setCoinPtTEnd(kept);
1317 }
1318 if (coin->oppPtTStart() == deleted) {
1319 if (coin->oppPtTEnd()->span() == kept->span()) {
1320 this->release(head, coin);
1321 continue;
1322 }
1323 coin->setOppPtTStart(kept);
1324 }
1325 if (coin->oppPtTEnd() == deleted) {
1326 if (coin->oppPtTStart()->span() == kept->span()) {
1327 this->release(head, coin);
1328 continue;
1329 }
1330 coin->setOppPtTEnd(kept);
1331 }
1332 } while ((coin = coin->next()));
1333}
1334
1335// Please keep this in sync with debugMark()
caryclark27c8eb82015-07-06 11:38:33 -07001336/* this sets up the coincidence links in the segments when the coincidence crosses multiple spans */
caryclarke6522ea2016-10-17 07:54:33 -07001337bool SkOpCoincidence::mark(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
Cary Clarkab87d7a2016-10-04 10:01:04 -04001338 DEBUG_SET_PHASE();
caryclark54359292015-03-26 07:52:43 -07001339 SkCoincidentSpans* coin = fHead;
1340 if (!coin) {
caryclarke6522ea2016-10-17 07:54:33 -07001341 return true;
caryclark54359292015-03-26 07:52:43 -07001342 }
1343 do {
caryclarke6522ea2016-10-17 07:54:33 -07001344 SkOpSpanBase* startBase = coin->coinPtTStartWritable()->span();
1345 FAIL_IF(!startBase->upCastable());
1346 SkOpSpan* start = startBase->upCast();
caryclarka35ab3e2016-10-20 08:32:18 -07001347 FAIL_IF(start->deleted());
caryclark55888e42016-07-18 10:01:36 -07001348 SkOpSpanBase* end = coin->coinPtTEndWritable()->span();
Cary Clark40f23782016-10-06 12:04:16 -04001349 SkOPASSERT(!end->deleted());
caryclark55888e42016-07-18 10:01:36 -07001350 SkOpSpanBase* oStart = coin->oppPtTStartWritable()->span();
Cary Clark40f23782016-10-06 12:04:16 -04001351 SkOPASSERT(!oStart->deleted());
caryclark55888e42016-07-18 10:01:36 -07001352 SkOpSpanBase* oEnd = coin->oppPtTEndWritable()->span();
Cary Clarkf36b8a32018-03-20 16:08:35 -04001353 FAIL_IF(oEnd->deleted());
caryclark55888e42016-07-18 10:01:36 -07001354 bool flipped = coin->flipped();
caryclark54359292015-03-26 07:52:43 -07001355 if (flipped) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -04001356 using std::swap;
1357 swap(oStart, oEnd);
caryclark54359292015-03-26 07:52:43 -07001358 }
caryclark55888e42016-07-18 10:01:36 -07001359 /* coin and opp spans may not match up. Mark the ends, and then let the interior
1360 get marked as many times as the spans allow */
Cary Clark9de09762016-11-17 08:47:37 -05001361 FAIL_IF(!oStart->upCastable());
caryclark55888e42016-07-18 10:01:36 -07001362 start->insertCoincidence(oStart->upCast());
1363 end->insertCoinEnd(oEnd);
1364 const SkOpSegment* segment = start->segment();
1365 const SkOpSegment* oSegment = oStart->segment();
caryclark54359292015-03-26 07:52:43 -07001366 SkOpSpanBase* next = start;
1367 SkOpSpanBase* oNext = oStart;
caryclarka35ab3e2016-10-20 08:32:18 -07001368 bool ordered;
1369 FAIL_IF(!coin->ordered(&ordered));
caryclark55888e42016-07-18 10:01:36 -07001370 while ((next = next->upCast()->next()) != end) {
caryclarke6522ea2016-10-17 07:54:33 -07001371 FAIL_IF(!next->upCastable());
Cary Clark59ed4822016-12-08 16:17:56 -05001372 FAIL_IF(!next->upCast()->insertCoincidence(oSegment, flipped, ordered));
caryclark55888e42016-07-18 10:01:36 -07001373 }
1374 while ((oNext = oNext->upCast()->next()) != oEnd) {
caryclark96dc1c92016-10-20 11:34:10 -07001375 FAIL_IF(!oNext->upCastable());
caryclarke6522ea2016-10-17 07:54:33 -07001376 FAIL_IF(!oNext->upCast()->insertCoincidence(segment, flipped, ordered));
caryclark55888e42016-07-18 10:01:36 -07001377 }
1378 } while ((coin = coin->next()));
caryclarke6522ea2016-10-17 07:54:33 -07001379 return true;
caryclark54359292015-03-26 07:52:43 -07001380}
1381
caryclark55888e42016-07-18 10:01:36 -07001382// Please keep in sync with debugMarkCollapsed()
1383void SkOpCoincidence::markCollapsed(SkCoincidentSpans* coin, SkOpPtT* test) {
1384 SkCoincidentSpans* head = coin;
1385 while (coin) {
1386 if (coin->collapsed(test)) {
1387 if (zero_or_one(coin->coinPtTStart()->fT) && zero_or_one(coin->coinPtTEnd()->fT)) {
1388 coin->coinPtTStartWritable()->segment()->markAllDone();
1389 }
1390 if (zero_or_one(coin->oppPtTStart()->fT) && zero_or_one(coin->oppPtTEnd()->fT)) {
1391 coin->oppPtTStartWritable()->segment()->markAllDone();
1392 }
1393 this->release(head, coin);
1394 }
1395 coin = coin->next();
1396 }
1397}
1398
1399// Please keep in sync with debugMarkCollapsed()
1400void SkOpCoincidence::markCollapsed(SkOpPtT* test) {
1401 markCollapsed(fHead, test);
1402 markCollapsed(fTop, test);
1403}
1404
1405bool SkOpCoincidence::Ordered(const SkOpSegment* coinSeg, const SkOpSegment* oppSeg) {
1406 if (coinSeg->verb() < oppSeg->verb()) {
1407 return true;
1408 }
1409 if (coinSeg->verb() > oppSeg->verb()) {
1410 return false;
1411 }
1412 int count = (SkPathOpsVerbToPoints(coinSeg->verb()) + 1) * 2;
1413 const SkScalar* cPt = &coinSeg->pts()[0].fX;
1414 const SkScalar* oPt = &oppSeg->pts()[0].fX;
1415 for (int index = 0; index < count; ++index) {
1416 if (*cPt < *oPt) {
1417 return true;
1418 }
1419 if (*cPt > *oPt) {
1420 return false;
1421 }
1422 ++cPt;
1423 ++oPt;
1424 }
1425 return true;
1426}
1427
1428bool SkOpCoincidence::overlap(const SkOpPtT* coin1s, const SkOpPtT* coin1e,
caryclark54359292015-03-26 07:52:43 -07001429 const SkOpPtT* coin2s, const SkOpPtT* coin2e, double* overS, double* overE) const {
caryclark27c8eb82015-07-06 11:38:33 -07001430 SkASSERT(coin1s->segment() == coin2s->segment());
caryclark54359292015-03-26 07:52:43 -07001431 *overS = SkTMax(SkTMin(coin1s->fT, coin1e->fT), SkTMin(coin2s->fT, coin2e->fT));
1432 *overE = SkTMin(SkTMax(coin1s->fT, coin1e->fT), SkTMax(coin2s->fT, coin2e->fT));
1433 return *overS < *overE;
1434}
caryclark27c8eb82015-07-06 11:38:33 -07001435
caryclark55888e42016-07-18 10:01:36 -07001436// Commented-out lines keep this in sync with debugRelease()
1437void SkOpCoincidence::release(const SkOpSegment* deleted) {
1438 SkCoincidentSpans* coin = fHead;
1439 if (!coin) {
1440 return;
1441 }
1442 do {
1443 if (coin->coinPtTStart()->segment() == deleted
1444 || coin->coinPtTEnd()->segment() == deleted
1445 || coin->oppPtTStart()->segment() == deleted
1446 || coin->oppPtTEnd()->segment() == deleted) {
1447 this->release(fHead, coin);
1448 }
1449 } while ((coin = coin->next()));
1450}