blob: 31de4f1a3ce8ceb56c0df934b2d3a5978c9a660a [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 */
Mike Kleinc0bd9f92019-04-23 12:05:21 -05007#include "src/pathops/SkOpCoincidence.h"
8#include "src/pathops/SkOpSegment.h"
9#include "src/pathops/SkPathOpsTSect.h"
caryclark54359292015-03-26 07:52:43 -070010
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;
Cary Clarkd058b182018-11-29 09:02:32 -0500350 FAIL_IF(!this->addOrOverlap(coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, &added));
caryclark55888e42016-07-18 10:01:36 -0700351 }
352 }
caryclark15976282016-07-21 05:48:43 -0700353 return true;
caryclark55888e42016-07-18 10:01:36 -0700354}
355
356// description below
357bool SkOpCoincidence::addEndMovedSpans(const SkOpPtT* ptT) {
caryclark025b11e2016-08-25 05:21:14 -0700358 FAIL_IF(!ptT->span()->upCastable());
caryclark55888e42016-07-18 10:01:36 -0700359 const SkOpSpan* base = ptT->span()->upCast();
360 const SkOpSpan* prev = base->prev();
caryclark025b11e2016-08-25 05:21:14 -0700361 FAIL_IF(!prev);
caryclark55888e42016-07-18 10:01:36 -0700362 if (!prev->isCanceled()) {
caryclark15976282016-07-21 05:48:43 -0700363 if (!this->addEndMovedSpans(base, base->prev())) {
364 return false;
365 }
caryclark55888e42016-07-18 10:01:36 -0700366 }
367 if (!base->isCanceled()) {
caryclark15976282016-07-21 05:48:43 -0700368 if (!this->addEndMovedSpans(base, base->next())) {
369 return false;
370 }
caryclark55888e42016-07-18 10:01:36 -0700371 }
372 return true;
373}
374
375/* If A is coincident with B and B includes an endpoint, and A's matching point
376 is not the endpoint (i.e., there's an implied line connecting B-end and A)
377 then assume that the same implied line may intersect another curve close to B.
378 Since we only care about coincidence that was undetected, look at the
379 ptT list on B-segment adjacent to the B-end/A ptT loop (not in the loop, but
380 next door) and see if the A matching point is close enough to form another
381 coincident pair. If so, check for a new coincident span between B-end/A ptT loop
382 and the adjacent ptT loop.
383*/
Cary Clarkab87d7a2016-10-04 10:01:04 -0400384bool SkOpCoincidence::addEndMovedSpans(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
385 DEBUG_SET_PHASE();
caryclark55888e42016-07-18 10:01:36 -0700386 SkCoincidentSpans* span = fHead;
387 if (!span) {
388 return true;
389 }
390 fTop = span;
391 fHead = nullptr;
392 do {
393 if (span->coinPtTStart()->fPt != span->oppPtTStart()->fPt) {
caryclark025b11e2016-08-25 05:21:14 -0700394 FAIL_IF(1 == span->coinPtTStart()->fT);
caryclark55888e42016-07-18 10:01:36 -0700395 bool onEnd = span->coinPtTStart()->fT == 0;
396 bool oOnEnd = zero_or_one(span->oppPtTStart()->fT);
397 if (onEnd) {
398 if (!oOnEnd) { // if both are on end, any nearby intersect was already found
399 if (!this->addEndMovedSpans(span->oppPtTStart())) {
400 return false;
401 }
402 }
403 } else if (oOnEnd) {
404 if (!this->addEndMovedSpans(span->coinPtTStart())) {
405 return false;
406 }
407 }
408 }
409 if (span->coinPtTEnd()->fPt != span->oppPtTEnd()->fPt) {
410 bool onEnd = span->coinPtTEnd()->fT == 1;
411 bool oOnEnd = zero_or_one(span->oppPtTEnd()->fT);
412 if (onEnd) {
413 if (!oOnEnd) {
414 if (!this->addEndMovedSpans(span->oppPtTEnd())) {
415 return false;
416 }
417 }
418 } else if (oOnEnd) {
419 if (!this->addEndMovedSpans(span->coinPtTEnd())) {
420 return false;
421 }
422 }
423 }
424 } while ((span = span->next()));
425 this->restoreHead();
426 return true;
427}
428
429/* Please keep this in sync with debugAddExpanded */
430// for each coincident pair, match the spans
431// 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 -0400432bool SkOpCoincidence::addExpanded(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
433 DEBUG_SET_PHASE();
caryclark55888e42016-07-18 10:01:36 -0700434 SkCoincidentSpans* coin = this->fHead;
435 if (!coin) {
436 return true;
437 }
438 do {
439 const SkOpPtT* startPtT = coin->coinPtTStart();
440 const SkOpPtT* oStartPtT = coin->oppPtTStart();
caryclark8016b262016-09-06 05:59:47 -0700441 double priorT = startPtT->fT;
442 double oPriorT = oStartPtT->fT;
caryclarkbbfe92b2016-09-19 06:00:35 -0700443 FAIL_IF(!startPtT->contains(oStartPtT));
caryclarkc6d855f2016-08-11 11:59:48 -0700444 SkOPASSERT(coin->coinPtTEnd()->contains(coin->oppPtTEnd()));
caryclark55888e42016-07-18 10:01:36 -0700445 const SkOpSpanBase* start = startPtT->span();
446 const SkOpSpanBase* oStart = oStartPtT->span();
447 const SkOpSpanBase* end = coin->coinPtTEnd()->span();
448 const SkOpSpanBase* oEnd = coin->oppPtTEnd()->span();
449 FAIL_IF(oEnd->deleted());
caryclarke25a4f62016-07-26 09:26:29 -0700450 FAIL_IF(!start->upCastable());
caryclark55888e42016-07-18 10:01:36 -0700451 const SkOpSpanBase* test = start->upCast()->next();
caryclarke7bb5b22016-09-22 05:20:07 -0700452 FAIL_IF(!coin->flipped() && !oStart->upCastable());
caryclark55888e42016-07-18 10:01:36 -0700453 const SkOpSpanBase* oTest = coin->flipped() ? oStart->prev() : oStart->upCast()->next();
caryclark30b9fdd2016-08-31 14:36:29 -0700454 FAIL_IF(!oTest);
caryclark8016b262016-09-06 05:59:47 -0700455 SkOpSegment* seg = start->segment();
456 SkOpSegment* oSeg = oStart->segment();
caryclark55888e42016-07-18 10:01:36 -0700457 while (test != end || oTest != oEnd) {
caryclark8016b262016-09-06 05:59:47 -0700458 const SkOpPtT* containedOpp = test->ptT()->contains(oSeg);
459 const SkOpPtT* containedThis = oTest->ptT()->contains(seg);
460 if (!containedOpp || !containedThis) {
461 // choose the ends, or the first common pt-t list shared by both
462 double nextT, oNextT;
463 if (containedOpp) {
464 nextT = test->t();
465 oNextT = containedOpp->fT;
466 } else if (containedThis) {
467 nextT = containedThis->fT;
468 oNextT = oTest->t();
469 } else {
470 // iterate through until a pt-t list found that contains the other
471 const SkOpSpanBase* walk = test;
472 const SkOpPtT* walkOpp;
473 do {
474 FAIL_IF(!walk->upCastable());
475 walk = walk->upCast()->next();
476 } while (!(walkOpp = walk->ptT()->contains(oSeg))
477 && walk != coin->coinPtTEnd()->span());
Cary Clark3fdf52c2016-10-04 10:53:31 -0400478 FAIL_IF(!walkOpp);
caryclark8016b262016-09-06 05:59:47 -0700479 nextT = walk->t();
480 oNextT = walkOpp->fT;
481 }
caryclark55888e42016-07-18 10:01:36 -0700482 // use t ranges to guess which one is missing
caryclark8016b262016-09-06 05:59:47 -0700483 double startRange = nextT - priorT;
caryclark55888e42016-07-18 10:01:36 -0700484 FAIL_IF(!startRange);
caryclark8016b262016-09-06 05:59:47 -0700485 double startPart = (test->t() - priorT) / startRange;
486 double oStartRange = oNextT - oPriorT;
caryclark55888e42016-07-18 10:01:36 -0700487 FAIL_IF(!oStartRange);
caryclark8016b262016-09-06 05:59:47 -0700488 double oStartPart = (oTest->t() - oPriorT) / oStartRange;
caryclark55888e42016-07-18 10:01:36 -0700489 FAIL_IF(startPart == oStartPart);
caryclark8016b262016-09-06 05:59:47 -0700490 bool addToOpp = !containedOpp && !containedThis ? startPart < oStartPart
491 : !!containedThis;
caryclark55888e42016-07-18 10:01:36 -0700492 bool startOver = false;
caryclark8016b262016-09-06 05:59:47 -0700493 bool success = addToOpp ? oSeg->addExpanded(
494 oPriorT + oStartRange * startPart, test, &startOver)
495 : seg->addExpanded(
496 priorT + startRange * oStartPart, oTest, &startOver);
caryclark30b9fdd2016-08-31 14:36:29 -0700497 FAIL_IF(!success);
caryclark55888e42016-07-18 10:01:36 -0700498 if (startOver) {
499 test = start;
500 oTest = oStart;
501 }
caryclark30b9fdd2016-08-31 14:36:29 -0700502 end = coin->coinPtTEnd()->span();
503 oEnd = coin->oppPtTEnd()->span();
caryclark55888e42016-07-18 10:01:36 -0700504 }
505 if (test != end) {
caryclark30b9fdd2016-08-31 14:36:29 -0700506 FAIL_IF(!test->upCastable());
caryclark8016b262016-09-06 05:59:47 -0700507 priorT = test->t();
caryclark55888e42016-07-18 10:01:36 -0700508 test = test->upCast()->next();
509 }
510 if (oTest != oEnd) {
caryclark8016b262016-09-06 05:59:47 -0700511 oPriorT = oTest->t();
caryclark78a37a52016-10-20 12:36:16 -0700512 if (coin->flipped()) {
513 oTest = oTest->prev();
514 } else {
515 FAIL_IF(!oTest->upCastable());
516 oTest = oTest->upCast()->next();
517 }
caryclark30b9fdd2016-08-31 14:36:29 -0700518 FAIL_IF(!oTest);
caryclark55888e42016-07-18 10:01:36 -0700519 }
caryclark8016b262016-09-06 05:59:47 -0700520
caryclark55888e42016-07-18 10:01:36 -0700521 }
522 } while ((coin = coin->next()));
523 return true;
524}
525
caryclark55888e42016-07-18 10:01:36 -0700526// given a t span, map the same range on the coincident span
caryclark8016b262016-09-06 05:59:47 -0700527/*
528the curves may not scale linearly, so interpolation may only happen within known points
529remap over1s, over1e, cointPtTStart, coinPtTEnd to smallest range that captures over1s
530then repeat to capture over1e
531*/
532double SkOpCoincidence::TRange(const SkOpPtT* overS, double t,
533 const SkOpSegment* coinSeg SkDEBUGPARAMS(const SkOpPtT* overE)) {
534 const SkOpSpanBase* work = overS->span();
535 const SkOpPtT* foundStart = nullptr;
536 const SkOpPtT* foundEnd = nullptr;
537 const SkOpPtT* coinStart = nullptr;
538 const SkOpPtT* coinEnd = nullptr;
539 do {
540 const SkOpPtT* contained = work->contains(coinSeg);
541 if (!contained) {
caryclarkc9b90d12016-09-09 07:41:36 -0700542 if (work->final()) {
543 break;
caryclarkb393a492016-09-07 08:21:09 -0700544 }
caryclark8016b262016-09-06 05:59:47 -0700545 continue;
546 }
547 if (work->t() <= t) {
548 coinStart = contained;
549 foundStart = work->ptT();
550 }
551 if (work->t() >= t) {
552 coinEnd = contained;
553 foundEnd = work->ptT();
554 break;
555 }
556 SkASSERT(work->ptT() != overE);
557 } while ((work = work->upCast()->next()));
caryclarkc9b90d12016-09-09 07:41:36 -0700558 if (!coinStart || !coinEnd) {
559 return 1;
560 }
caryclark8016b262016-09-06 05:59:47 -0700561 // while overS->fT <=t and overS contains coinSeg
562 double denom = foundEnd->fT - foundStart->fT;
563 double sRatio = denom ? (t - foundStart->fT) / denom : 1;
564 return coinStart->fT + (coinEnd->fT - coinStart->fT) * sRatio;
caryclark54359292015-03-26 07:52:43 -0700565}
566
caryclark55888e42016-07-18 10:01:36 -0700567// return true if span overlaps existing and needs to adjust the coincident list
568bool SkOpCoincidence::checkOverlap(SkCoincidentSpans* check,
569 const SkOpSegment* coinSeg, const SkOpSegment* oppSeg,
570 double coinTs, double coinTe, double oppTs, double oppTe,
571 SkTDArray<SkCoincidentSpans*>* overlaps) const {
572 if (!Ordered(coinSeg, oppSeg)) {
573 if (oppTs < oppTe) {
574 return this->checkOverlap(check, oppSeg, coinSeg, oppTs, oppTe, coinTs, coinTe,
575 overlaps);
576 }
577 return this->checkOverlap(check, oppSeg, coinSeg, oppTe, oppTs, coinTe, coinTs, overlaps);
578 }
579 bool swapOpp = oppTs > oppTe;
580 if (swapOpp) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400581 using std::swap;
582 swap(oppTs, oppTe);
caryclark55888e42016-07-18 10:01:36 -0700583 }
caryclark27c8eb82015-07-06 11:38:33 -0700584 do {
caryclark55888e42016-07-18 10:01:36 -0700585 if (check->coinPtTStart()->segment() != coinSeg) {
586 continue;
caryclark1c9ce612015-11-20 14:06:28 -0800587 }
caryclark55888e42016-07-18 10:01:36 -0700588 if (check->oppPtTStart()->segment() != oppSeg) {
589 continue;
caryclarkdae6b972016-06-08 04:28:19 -0700590 }
caryclark55888e42016-07-18 10:01:36 -0700591 double checkTs = check->coinPtTStart()->fT;
592 double checkTe = check->coinPtTEnd()->fT;
593 bool coinOutside = coinTe < checkTs || coinTs > checkTe;
594 double oCheckTs = check->oppPtTStart()->fT;
595 double oCheckTe = check->oppPtTEnd()->fT;
596 if (swapOpp) {
597 if (oCheckTs <= oCheckTe) {
caryclark81a478c2016-09-09 09:37:57 -0700598 return false;
caryclark27c8eb82015-07-06 11:38:33 -0700599 }
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400600 using std::swap;
601 swap(oCheckTs, oCheckTe);
caryclark27c8eb82015-07-06 11:38:33 -0700602 }
caryclark55888e42016-07-18 10:01:36 -0700603 bool oppOutside = oppTe < oCheckTs || oppTs > oCheckTe;
604 if (coinOutside && oppOutside) {
605 continue;
606 }
607 bool coinInside = coinTe <= checkTe && coinTs >= checkTs;
608 bool oppInside = oppTe <= oCheckTe && oppTs >= oCheckTs;
caryclark81a478c2016-09-09 09:37:57 -0700609 if (coinInside && oppInside) { // already included, do nothing
610 return false;
caryclark55888e42016-07-18 10:01:36 -0700611 }
612 *overlaps->append() = check; // partial overlap, extend existing entry
613 } while ((check = check->next()));
caryclark26ad22a2015-10-16 09:03:38 -0700614 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700615}
616
caryclark55888e42016-07-18 10:01:36 -0700617/* Please keep this in sync with debugAddIfMissing() */
caryclark8016b262016-09-06 05:59:47 -0700618// note that over1s, over1e, over2s, over2e are ordered
619bool SkOpCoincidence::addIfMissing(const SkOpPtT* over1s, const SkOpPtT* over2s,
Herb Derbyecc364c2017-04-19 15:09:48 -0400620 double tStart, double tEnd, SkOpSegment* coinSeg, SkOpSegment* oppSeg, bool* added
caryclark8016b262016-09-06 05:59:47 -0700621 SkDEBUGPARAMS(const SkOpPtT* over1e) SkDEBUGPARAMS(const SkOpPtT* over2e)) {
622 SkASSERT(tStart < tEnd);
623 SkASSERT(over1s->fT < over1e->fT);
624 SkASSERT(between(over1s->fT, tStart, over1e->fT));
625 SkASSERT(between(over1s->fT, tEnd, over1e->fT));
626 SkASSERT(over2s->fT < over2e->fT);
627 SkASSERT(between(over2s->fT, tStart, over2e->fT));
628 SkASSERT(between(over2s->fT, tEnd, over2e->fT));
629 SkASSERT(over1s->segment() == over1e->segment());
630 SkASSERT(over2s->segment() == over2e->segment());
631 SkASSERT(over1s->segment() == over2s->segment());
632 SkASSERT(over1s->segment() != coinSeg);
633 SkASSERT(over1s->segment() != oppSeg);
634 SkASSERT(coinSeg != oppSeg);
caryclark54359292015-03-26 07:52:43 -0700635 double coinTs, coinTe, oppTs, oppTe;
caryclark8016b262016-09-06 05:59:47 -0700636 coinTs = TRange(over1s, tStart, coinSeg SkDEBUGPARAMS(over1e));
637 coinTe = TRange(over1s, tEnd, coinSeg SkDEBUGPARAMS(over1e));
Cary Clarkba610292018-06-19 09:47:15 -0400638 SkOpSpanBase::Collapsed result = coinSeg->collapsed(coinTs, coinTe);
639 if (SkOpSpanBase::Collapsed::kNo != result) {
640 return SkOpSpanBase::Collapsed::kYes == result;
caryclark30b9fdd2016-08-31 14:36:29 -0700641 }
caryclark8016b262016-09-06 05:59:47 -0700642 oppTs = TRange(over2s, tStart, oppSeg SkDEBUGPARAMS(over2e));
643 oppTe = TRange(over2s, tEnd, oppSeg SkDEBUGPARAMS(over2e));
Cary Clarkba610292018-06-19 09:47:15 -0400644 result = oppSeg->collapsed(oppTs, oppTe);
645 if (SkOpSpanBase::Collapsed::kNo != result) {
646 return SkOpSpanBase::Collapsed::kYes == result;
caryclark30b9fdd2016-08-31 14:36:29 -0700647 }
caryclark8016b262016-09-06 05:59:47 -0700648 if (coinTs > coinTe) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400649 using std::swap;
650 swap(coinTs, coinTe);
651 swap(oppTs, oppTe);
caryclark54359292015-03-26 07:52:43 -0700652 }
Cary Clarkba610292018-06-19 09:47:15 -0400653 (void) this->addOrOverlap(coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, added);
654 return true;
caryclark54359292015-03-26 07:52:43 -0700655}
656
caryclark55888e42016-07-18 10:01:36 -0700657/* Please keep this in sync with debugAddOrOverlap() */
caryclark025b11e2016-08-25 05:21:14 -0700658// If this is called by addEndMovedSpans(), a returned false propogates out to an abort.
659// If this is called by AddIfMissing(), a returned false indicates there was nothing to add
caryclark55888e42016-07-18 10:01:36 -0700660bool SkOpCoincidence::addOrOverlap(SkOpSegment* coinSeg, SkOpSegment* oppSeg,
caryclark81a478c2016-09-09 09:37:57 -0700661 double coinTs, double coinTe, double oppTs, double oppTe, bool* added) {
caryclark55888e42016-07-18 10:01:36 -0700662 SkTDArray<SkCoincidentSpans*> overlaps;
caryclark81a478c2016-09-09 09:37:57 -0700663 FAIL_IF(!fTop);
caryclark55888e42016-07-18 10:01:36 -0700664 if (!this->checkOverlap(fTop, coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, &overlaps)) {
caryclark81a478c2016-09-09 09:37:57 -0700665 return true;
caryclark55888e42016-07-18 10:01:36 -0700666 }
667 if (fHead && !this->checkOverlap(fHead, coinSeg, oppSeg, coinTs,
668 coinTe, oppTs, oppTe, &overlaps)) {
caryclark81a478c2016-09-09 09:37:57 -0700669 return true;
caryclark55888e42016-07-18 10:01:36 -0700670 }
671 SkCoincidentSpans* overlap = overlaps.count() ? overlaps[0] : nullptr;
672 for (int index = 1; index < overlaps.count(); ++index) { // combine overlaps before continuing
673 SkCoincidentSpans* test = overlaps[index];
674 if (overlap->coinPtTStart()->fT > test->coinPtTStart()->fT) {
675 overlap->setCoinPtTStart(test->coinPtTStart());
676 }
677 if (overlap->coinPtTEnd()->fT < test->coinPtTEnd()->fT) {
678 overlap->setCoinPtTEnd(test->coinPtTEnd());
679 }
680 if (overlap->flipped()
681 ? overlap->oppPtTStart()->fT < test->oppPtTStart()->fT
682 : overlap->oppPtTStart()->fT > test->oppPtTStart()->fT) {
683 overlap->setOppPtTStart(test->oppPtTStart());
684 }
685 if (overlap->flipped()
686 ? overlap->oppPtTEnd()->fT > test->oppPtTEnd()->fT
687 : overlap->oppPtTEnd()->fT < test->oppPtTEnd()->fT) {
688 overlap->setOppPtTEnd(test->oppPtTEnd());
689 }
690 if (!fHead || !this->release(fHead, test)) {
691 SkAssertResult(this->release(fTop, test));
692 }
693 }
694 const SkOpPtT* cs = coinSeg->existing(coinTs, oppSeg);
695 const SkOpPtT* ce = coinSeg->existing(coinTe, oppSeg);
caryclark81a478c2016-09-09 09:37:57 -0700696 if (overlap && cs && ce && overlap->contains(cs, ce)) {
697 return true;
698 }
699 FAIL_IF(cs == ce && cs);
caryclark55888e42016-07-18 10:01:36 -0700700 const SkOpPtT* os = oppSeg->existing(oppTs, coinSeg);
701 const SkOpPtT* oe = oppSeg->existing(oppTe, coinSeg);
caryclark81a478c2016-09-09 09:37:57 -0700702 if (overlap && os && oe && overlap->contains(os, oe)) {
703 return true;
704 }
Cary Clarkb8421ed2018-03-14 15:55:02 -0400705 FAIL_IF(cs && cs->deleted());
Cary Clark2f06a532018-03-12 14:41:45 -0400706 FAIL_IF(os && os->deleted());
Cary Clark0949bee2018-03-19 09:42:00 -0400707 FAIL_IF(ce && ce->deleted());
Cary Clark74b42902018-03-09 07:38:47 -0500708 FAIL_IF(oe && oe->deleted());
caryclark55888e42016-07-18 10:01:36 -0700709 const SkOpPtT* csExisting = !cs ? coinSeg->existing(coinTs, nullptr) : nullptr;
710 const SkOpPtT* ceExisting = !ce ? coinSeg->existing(coinTe, nullptr) : nullptr;
caryclark81a478c2016-09-09 09:37:57 -0700711 FAIL_IF(csExisting && csExisting == ceExisting);
caryclarke839e782016-09-15 07:48:18 -0700712// FAIL_IF(csExisting && (csExisting == ce ||
713// csExisting->contains(ceExisting ? ceExisting : ce)));
caryclark81a478c2016-09-09 09:37:57 -0700714 FAIL_IF(ceExisting && (ceExisting == cs ||
caryclark025b11e2016-08-25 05:21:14 -0700715 ceExisting->contains(csExisting ? csExisting : cs)));
caryclark55888e42016-07-18 10:01:36 -0700716 const SkOpPtT* osExisting = !os ? oppSeg->existing(oppTs, nullptr) : nullptr;
717 const SkOpPtT* oeExisting = !oe ? oppSeg->existing(oppTe, nullptr) : nullptr;
caryclark81a478c2016-09-09 09:37:57 -0700718 FAIL_IF(osExisting && osExisting == oeExisting);
719 FAIL_IF(osExisting && (osExisting == oe ||
caryclark025b11e2016-08-25 05:21:14 -0700720 osExisting->contains(oeExisting ? oeExisting : oe)));
caryclark81a478c2016-09-09 09:37:57 -0700721 FAIL_IF(oeExisting && (oeExisting == os ||
caryclark025b11e2016-08-25 05:21:14 -0700722 oeExisting->contains(osExisting ? osExisting : os)));
caryclark55888e42016-07-18 10:01:36 -0700723 // extra line in debug code
724 this->debugValidate();
725 if (!cs || !os) {
726 SkOpPtT* csWritable = cs ? const_cast<SkOpPtT*>(cs)
caryclark29b25632016-08-25 11:27:17 -0700727 : coinSeg->addT(coinTs);
caryclarke839e782016-09-15 07:48:18 -0700728 if (csWritable == ce) {
729 return true;
730 }
caryclark55888e42016-07-18 10:01:36 -0700731 SkOpPtT* osWritable = os ? const_cast<SkOpPtT*>(os)
caryclark29b25632016-08-25 11:27:17 -0700732 : oppSeg->addT(oppTs);
caryclark81a478c2016-09-09 09:37:57 -0700733 FAIL_IF(!csWritable || !osWritable);
caryclark30b9fdd2016-08-31 14:36:29 -0700734 csWritable->span()->addOpp(osWritable->span());
caryclark55888e42016-07-18 10:01:36 -0700735 cs = csWritable;
caryclark30b9fdd2016-08-31 14:36:29 -0700736 os = osWritable->active();
Cary Clark74b42902018-03-09 07:38:47 -0500737 FAIL_IF(!os);
caryclark81a478c2016-09-09 09:37:57 -0700738 FAIL_IF((ce && ce->deleted()) || (oe && oe->deleted()));
caryclark55888e42016-07-18 10:01:36 -0700739 }
740 if (!ce || !oe) {
741 SkOpPtT* ceWritable = ce ? const_cast<SkOpPtT*>(ce)
caryclark29b25632016-08-25 11:27:17 -0700742 : coinSeg->addT(coinTe);
caryclark55888e42016-07-18 10:01:36 -0700743 SkOpPtT* oeWritable = oe ? const_cast<SkOpPtT*>(oe)
caryclark29b25632016-08-25 11:27:17 -0700744 : oppSeg->addT(oppTe);
Cary Clarkd058b182018-11-29 09:02:32 -0500745 FAIL_IF(!ceWritable->span()->addOpp(oeWritable->span()));
caryclark55888e42016-07-18 10:01:36 -0700746 ce = ceWritable;
747 oe = oeWritable;
748 }
749 this->debugValidate();
caryclark81a478c2016-09-09 09:37:57 -0700750 FAIL_IF(cs->deleted());
751 FAIL_IF(os->deleted());
752 FAIL_IF(ce->deleted());
753 FAIL_IF(oe->deleted());
754 FAIL_IF(cs->contains(ce) || os->contains(oe));
caryclark55888e42016-07-18 10:01:36 -0700755 bool result = true;
756 if (overlap) {
757 if (overlap->coinPtTStart()->segment() == coinSeg) {
758 result = overlap->extend(cs, ce, os, oe);
759 } else {
760 if (os->fT > oe->fT) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400761 using std::swap;
762 swap(cs, ce);
763 swap(os, oe);
caryclark55888e42016-07-18 10:01:36 -0700764 }
765 result = overlap->extend(os, oe, cs, ce);
766 }
767#if DEBUG_COINCIDENCE_VERBOSE
768 if (result) {
769 overlaps[0]->debugShow();
770 }
771#endif
772 } else {
773 this->add(cs, ce, os, oe);
774#if DEBUG_COINCIDENCE_VERBOSE
775 fHead->debugShow();
776#endif
777 }
778 this->debugValidate();
caryclark81a478c2016-09-09 09:37:57 -0700779 if (result) {
780 *added = true;
781 }
782 return true;
caryclark55888e42016-07-18 10:01:36 -0700783}
784
785// Please keep this in sync with debugAddMissing()
caryclark27c8eb82015-07-06 11:38:33 -0700786/* detects overlaps of different coincident runs on same segment */
787/* does not detect overlaps for pairs without any segments in common */
caryclark55888e42016-07-18 10:01:36 -0700788// returns true if caller should loop again
Cary Clarkab87d7a2016-10-04 10:01:04 -0400789bool SkOpCoincidence::addMissing(bool* added DEBUG_COIN_DECLARE_PARAMS()) {
caryclark27c8eb82015-07-06 11:38:33 -0700790 SkCoincidentSpans* outer = fHead;
caryclark81a478c2016-09-09 09:37:57 -0700791 *added = false;
caryclark54359292015-03-26 07:52:43 -0700792 if (!outer) {
caryclark81a478c2016-09-09 09:37:57 -0700793 return true;
caryclark54359292015-03-26 07:52:43 -0700794 }
caryclark27c8eb82015-07-06 11:38:33 -0700795 fTop = outer;
halcanary96fcdcc2015-08-27 07:41:13 -0700796 fHead = nullptr;
caryclark54359292015-03-26 07:52:43 -0700797 do {
caryclark27c8eb82015-07-06 11:38:33 -0700798 // addifmissing can modify the list that this is walking
caryclark26ad22a2015-10-16 09:03:38 -0700799 // save head so that walker can iterate over old data unperturbed
800 // addifmissing adds to head freely then add saved head in the end
caryclark8016b262016-09-06 05:59:47 -0700801 const SkOpPtT* ocs = outer->coinPtTStart();
caryclarka35ab3e2016-10-20 08:32:18 -0700802 FAIL_IF(ocs->deleted());
caryclark8016b262016-09-06 05:59:47 -0700803 const SkOpSegment* outerCoin = ocs->segment();
Cary Clark18562b82018-06-07 08:06:12 -0400804 FAIL_IF(outerCoin->done());
caryclark8016b262016-09-06 05:59:47 -0700805 const SkOpPtT* oos = outer->oppPtTStart();
caryclarkb393a492016-09-07 08:21:09 -0700806 if (oos->deleted()) {
caryclark81a478c2016-09-09 09:37:57 -0700807 return true;
caryclarkb393a492016-09-07 08:21:09 -0700808 }
caryclark8016b262016-09-06 05:59:47 -0700809 const SkOpSegment* outerOpp = oos->segment();
Cary Clark4c76c412017-01-20 08:14:33 -0500810 SkOPASSERT(!outerOpp->done());
caryclark8016b262016-09-06 05:59:47 -0700811 SkOpSegment* outerCoinWritable = const_cast<SkOpSegment*>(outerCoin);
812 SkOpSegment* outerOppWritable = const_cast<SkOpSegment*>(outerOpp);
caryclark54359292015-03-26 07:52:43 -0700813 SkCoincidentSpans* inner = outer;
Cary Clark4929a4a2018-10-17 14:12:41 -0400814#ifdef IS_FUZZING_WITH_LIBFUZZER
815 int safetyNet = 1000;
816#endif
caryclark55888e42016-07-18 10:01:36 -0700817 while ((inner = inner->next())) {
Cary Clark4929a4a2018-10-17 14:12:41 -0400818#ifdef IS_FUZZING_WITH_LIBFUZZER
819 if (!--safetyNet) {
820 return false;
821 }
822#endif
caryclark55888e42016-07-18 10:01:36 -0700823 this->debugValidate();
caryclark54359292015-03-26 07:52:43 -0700824 double overS, overE;
caryclark8016b262016-09-06 05:59:47 -0700825 const SkOpPtT* ics = inner->coinPtTStart();
caryclark221a4bb2016-10-07 11:15:15 -0700826 FAIL_IF(ics->deleted());
caryclark8016b262016-09-06 05:59:47 -0700827 const SkOpSegment* innerCoin = ics->segment();
caryclarka35ab3e2016-10-20 08:32:18 -0700828 FAIL_IF(innerCoin->done());
caryclark8016b262016-09-06 05:59:47 -0700829 const SkOpPtT* ios = inner->oppPtTStart();
caryclarka35ab3e2016-10-20 08:32:18 -0700830 FAIL_IF(ios->deleted());
caryclark8016b262016-09-06 05:59:47 -0700831 const SkOpSegment* innerOpp = ios->segment();
Cary Clark4c76c412017-01-20 08:14:33 -0500832 SkOPASSERT(!innerOpp->done());
caryclark8016b262016-09-06 05:59:47 -0700833 SkOpSegment* innerCoinWritable = const_cast<SkOpSegment*>(innerCoin);
834 SkOpSegment* innerOppWritable = const_cast<SkOpSegment*>(innerOpp);
caryclark55888e42016-07-18 10:01:36 -0700835 if (outerCoin == innerCoin) {
caryclark8016b262016-09-06 05:59:47 -0700836 const SkOpPtT* oce = outer->coinPtTEnd();
caryclarkb393a492016-09-07 08:21:09 -0700837 if (oce->deleted()) {
caryclark81a478c2016-09-09 09:37:57 -0700838 return true;
caryclarkb393a492016-09-07 08:21:09 -0700839 }
caryclark8016b262016-09-06 05:59:47 -0700840 const SkOpPtT* ice = inner->coinPtTEnd();
caryclark595ac282016-10-24 08:41:45 -0700841 FAIL_IF(ice->deleted());
caryclark8016b262016-09-06 05:59:47 -0700842 if (outerOpp != innerOpp && this->overlap(ocs, oce, ics, ice, &overS, &overE)) {
Cary Clarkba610292018-06-19 09:47:15 -0400843 FAIL_IF(!this->addIfMissing(ocs->starter(oce), ics->starter(ice),
caryclark81a478c2016-09-09 09:37:57 -0700844 overS, overE, outerOppWritable, innerOppWritable, added
caryclark8016b262016-09-06 05:59:47 -0700845 SkDEBUGPARAMS(ocs->debugEnder(oce))
Cary Clarkba610292018-06-19 09:47:15 -0400846 SkDEBUGPARAMS(ics->debugEnder(ice))));
caryclark55888e42016-07-18 10:01:36 -0700847 }
848 } else if (outerCoin == innerOpp) {
caryclark8016b262016-09-06 05:59:47 -0700849 const SkOpPtT* oce = outer->coinPtTEnd();
Cary Clark56071432018-06-19 08:33:52 -0400850 FAIL_IF(oce->deleted());
caryclark8016b262016-09-06 05:59:47 -0700851 const SkOpPtT* ioe = inner->oppPtTEnd();
Cary Clarkd32b4b82018-11-15 14:09:02 -0500852 FAIL_IF(ioe->deleted());
caryclark8016b262016-09-06 05:59:47 -0700853 if (outerOpp != innerCoin && this->overlap(ocs, oce, ios, ioe, &overS, &overE)) {
Cary Clarkba610292018-06-19 09:47:15 -0400854 FAIL_IF(!this->addIfMissing(ocs->starter(oce), ios->starter(ioe),
caryclark81a478c2016-09-09 09:37:57 -0700855 overS, overE, outerOppWritable, innerCoinWritable, added
caryclark8016b262016-09-06 05:59:47 -0700856 SkDEBUGPARAMS(ocs->debugEnder(oce))
Cary Clarkba610292018-06-19 09:47:15 -0400857 SkDEBUGPARAMS(ios->debugEnder(ioe))));
caryclark55888e42016-07-18 10:01:36 -0700858 }
859 } else if (outerOpp == innerCoin) {
caryclark8016b262016-09-06 05:59:47 -0700860 const SkOpPtT* ooe = outer->oppPtTEnd();
Cary Clark13795082018-11-07 16:18:39 -0500861 FAIL_IF(ooe->deleted());
caryclark8016b262016-09-06 05:59:47 -0700862 const SkOpPtT* ice = inner->coinPtTEnd();
Cary Clark7f2b6fa2018-11-14 08:30:58 -0500863 FAIL_IF(ice->deleted());
caryclark55888e42016-07-18 10:01:36 -0700864 SkASSERT(outerCoin != innerOpp);
caryclark8016b262016-09-06 05:59:47 -0700865 if (this->overlap(oos, ooe, ics, ice, &overS, &overE)) {
Cary Clarkba610292018-06-19 09:47:15 -0400866 FAIL_IF(!this->addIfMissing(oos->starter(ooe), ics->starter(ice),
caryclark81a478c2016-09-09 09:37:57 -0700867 overS, overE, outerCoinWritable, innerOppWritable, added
caryclark8016b262016-09-06 05:59:47 -0700868 SkDEBUGPARAMS(oos->debugEnder(ooe))
Cary Clarkba610292018-06-19 09:47:15 -0400869 SkDEBUGPARAMS(ics->debugEnder(ice))));
caryclark55888e42016-07-18 10:01:36 -0700870 }
871 } else if (outerOpp == innerOpp) {
caryclark8016b262016-09-06 05:59:47 -0700872 const SkOpPtT* ooe = outer->oppPtTEnd();
Cary Clark8d8a5d92018-04-02 12:40:49 -0400873 FAIL_IF(ooe->deleted());
caryclark8016b262016-09-06 05:59:47 -0700874 const SkOpPtT* ioe = inner->oppPtTEnd();
caryclarkb393a492016-09-07 08:21:09 -0700875 if (ioe->deleted()) {
caryclark81a478c2016-09-09 09:37:57 -0700876 return true;
caryclarkb393a492016-09-07 08:21:09 -0700877 }
caryclark55888e42016-07-18 10:01:36 -0700878 SkASSERT(outerCoin != innerCoin);
caryclark8016b262016-09-06 05:59:47 -0700879 if (this->overlap(oos, ooe, ios, ioe, &overS, &overE)) {
Cary Clarkba610292018-06-19 09:47:15 -0400880 FAIL_IF(!this->addIfMissing(oos->starter(ooe), ios->starter(ioe),
caryclark81a478c2016-09-09 09:37:57 -0700881 overS, overE, outerCoinWritable, innerCoinWritable, added
caryclark8016b262016-09-06 05:59:47 -0700882 SkDEBUGPARAMS(oos->debugEnder(ooe))
Cary Clarkba610292018-06-19 09:47:15 -0400883 SkDEBUGPARAMS(ios->debugEnder(ioe))));
caryclark54359292015-03-26 07:52:43 -0700884 }
885 }
caryclark55888e42016-07-18 10:01:36 -0700886 this->debugValidate();
caryclark54359292015-03-26 07:52:43 -0700887 }
caryclark55888e42016-07-18 10:01:36 -0700888 } while ((outer = outer->next()));
889 this->restoreHead();
caryclark81a478c2016-09-09 09:37:57 -0700890 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700891}
892
caryclark55888e42016-07-18 10:01:36 -0700893bool SkOpCoincidence::addOverlap(const SkOpSegment* seg1, const SkOpSegment* seg1o,
894 const SkOpSegment* seg2, const SkOpSegment* seg2o,
895 const SkOpPtT* overS, const SkOpPtT* overE) {
Cary Clarke47ae292016-10-05 08:51:39 -0400896 const SkOpPtT* s1 = overS->find(seg1);
897 const SkOpPtT* e1 = overE->find(seg1);
caryclark08714012016-10-07 12:57:47 -0700898 FAIL_IF(!s1);
Cary Clark40f23782016-10-06 12:04:16 -0400899 FAIL_IF(!e1);
caryclark27c8eb82015-07-06 11:38:33 -0700900 if (!s1->starter(e1)->span()->upCast()->windValue()) {
Cary Clarke47ae292016-10-05 08:51:39 -0400901 s1 = overS->find(seg1o);
902 e1 = overE->find(seg1o);
caryclark221a4bb2016-10-07 11:15:15 -0700903 FAIL_IF(!s1);
Cary Clark40f23782016-10-06 12:04:16 -0400904 FAIL_IF(!e1);
caryclark27c8eb82015-07-06 11:38:33 -0700905 if (!s1->starter(e1)->span()->upCast()->windValue()) {
caryclark3f0753d2016-06-28 09:23:57 -0700906 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700907 }
908 }
Cary Clarke47ae292016-10-05 08:51:39 -0400909 const SkOpPtT* s2 = overS->find(seg2);
910 const SkOpPtT* e2 = overE->find(seg2);
caryclark82616712016-10-24 04:53:22 -0700911 FAIL_IF(!s2);
caryclarka35ab3e2016-10-20 08:32:18 -0700912 FAIL_IF(!e2);
caryclark27c8eb82015-07-06 11:38:33 -0700913 if (!s2->starter(e2)->span()->upCast()->windValue()) {
Cary Clarke47ae292016-10-05 08:51:39 -0400914 s2 = overS->find(seg2o);
915 e2 = overE->find(seg2o);
caryclarka35ab3e2016-10-20 08:32:18 -0700916 FAIL_IF(!s2);
caryclark78a37a52016-10-20 12:36:16 -0700917 FAIL_IF(!e2);
caryclark27c8eb82015-07-06 11:38:33 -0700918 if (!s2->starter(e2)->span()->upCast()->windValue()) {
caryclark3f0753d2016-06-28 09:23:57 -0700919 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700920 }
921 }
922 if (s1->segment() == s2->segment()) {
caryclark3f0753d2016-06-28 09:23:57 -0700923 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700924 }
925 if (s1->fT > e1->fT) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400926 using std::swap;
927 swap(s1, e1);
928 swap(s2, e2);
caryclark27c8eb82015-07-06 11:38:33 -0700929 }
caryclark55888e42016-07-18 10:01:36 -0700930 this->add(s1, e1, s2, e2);
caryclark3f0753d2016-06-28 09:23:57 -0700931 return true;
caryclark54359292015-03-26 07:52:43 -0700932}
933
caryclark55888e42016-07-18 10:01:36 -0700934bool SkOpCoincidence::contains(const SkOpSegment* seg, const SkOpSegment* opp, double oppT) const {
935 if (this->contains(fHead, seg, opp, oppT)) {
936 return true;
937 }
938 if (this->contains(fTop, seg, opp, oppT)) {
939 return true;
940 }
941 return false;
942}
943
944bool SkOpCoincidence::contains(const SkCoincidentSpans* coin, const SkOpSegment* seg,
945 const SkOpSegment* opp, double oppT) const {
946 if (!coin) {
947 return false;
948 }
949 do {
950 if (coin->coinPtTStart()->segment() == seg && coin->oppPtTStart()->segment() == opp
951 && between(coin->oppPtTStart()->fT, oppT, coin->oppPtTEnd()->fT)) {
caryclark54359292015-03-26 07:52:43 -0700952 return true;
953 }
caryclark55888e42016-07-18 10:01:36 -0700954 if (coin->oppPtTStart()->segment() == seg && coin->coinPtTStart()->segment() == opp
955 && between(coin->coinPtTStart()->fT, oppT, coin->coinPtTEnd()->fT)) {
956 return true;
957 }
958 } while ((coin = coin->next()));
caryclark54359292015-03-26 07:52:43 -0700959 return false;
960}
961
caryclark55888e42016-07-18 10:01:36 -0700962bool SkOpCoincidence::contains(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd,
963 const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) const {
964 const SkCoincidentSpans* test = fHead;
965 if (!test) {
966 return false;
967 }
968 const SkOpSegment* coinSeg = coinPtTStart->segment();
969 const SkOpSegment* oppSeg = oppPtTStart->segment();
970 if (!Ordered(coinPtTStart, oppPtTStart)) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400971 using std::swap;
972 swap(coinSeg, oppSeg);
973 swap(coinPtTStart, oppPtTStart);
974 swap(coinPtTEnd, oppPtTEnd);
caryclark55888e42016-07-18 10:01:36 -0700975 if (coinPtTStart->fT > coinPtTEnd->fT) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400976 swap(coinPtTStart, coinPtTEnd);
977 swap(oppPtTStart, oppPtTEnd);
caryclark55888e42016-07-18 10:01:36 -0700978 }
979 }
980 double oppMinT = SkTMin(oppPtTStart->fT, oppPtTEnd->fT);
981 double oppMaxT = SkTMax(oppPtTStart->fT, oppPtTEnd->fT);
982 do {
983 if (coinSeg != test->coinPtTStart()->segment()) {
984 continue;
985 }
986 if (coinPtTStart->fT < test->coinPtTStart()->fT) {
987 continue;
988 }
989 if (coinPtTEnd->fT > test->coinPtTEnd()->fT) {
990 continue;
991 }
992 if (oppSeg != test->oppPtTStart()->segment()) {
993 continue;
994 }
995 if (oppMinT < SkTMin(test->oppPtTStart()->fT, test->oppPtTEnd()->fT)) {
996 continue;
997 }
998 if (oppMaxT > SkTMax(test->oppPtTStart()->fT, test->oppPtTEnd()->fT)) {
999 continue;
1000 }
1001 return true;
1002 } while ((test = test->next()));
1003 return false;
1004}
1005
Cary Clarkab87d7a2016-10-04 10:01:04 -04001006void SkOpCoincidence::correctEnds(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
1007 DEBUG_SET_PHASE();
caryclark55888e42016-07-18 10:01:36 -07001008 SkCoincidentSpans* coin = fHead;
1009 if (!coin) {
1010 return;
1011 }
1012 do {
1013 coin->correctEnds();
1014 } while ((coin = coin->next()));
1015}
1016
caryclark54359292015-03-26 07:52:43 -07001017// walk span sets in parallel, moving winding from one to the other
caryclarka35ab3e2016-10-20 08:32:18 -07001018bool SkOpCoincidence::apply(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
Cary Clarkab87d7a2016-10-04 10:01:04 -04001019 DEBUG_SET_PHASE();
caryclark54359292015-03-26 07:52:43 -07001020 SkCoincidentSpans* coin = fHead;
1021 if (!coin) {
caryclarka35ab3e2016-10-20 08:32:18 -07001022 return true;
caryclark54359292015-03-26 07:52:43 -07001023 }
1024 do {
Cary Clark5a2057a2017-01-03 10:47:34 -05001025 SkOpSpanBase* startSpan = coin->coinPtTStartWritable()->span();
1026 FAIL_IF(!startSpan->upCastable());
1027 SkOpSpan* start = startSpan->upCast();
caryclark182b4992015-05-14 05:45:54 -07001028 if (start->deleted()) {
1029 continue;
1030 }
caryclark55888e42016-07-18 10:01:36 -07001031 const SkOpSpanBase* end = coin->coinPtTEnd()->span();
Cary Clark5369e142018-11-19 14:57:20 -05001032 FAIL_IF(start != start->starter(end));
caryclark55888e42016-07-18 10:01:36 -07001033 bool flipped = coin->flipped();
caryclark96dc1c92016-10-20 11:34:10 -07001034 SkOpSpanBase* oStartBase = (flipped ? coin->oppPtTEndWritable()
1035 : coin->oppPtTStartWritable())->span();
1036 FAIL_IF(!oStartBase->upCastable());
1037 SkOpSpan* oStart = oStartBase->upCast();
caryclark182b4992015-05-14 05:45:54 -07001038 if (oStart->deleted()) {
1039 continue;
1040 }
caryclark55888e42016-07-18 10:01:36 -07001041 const SkOpSpanBase* oEnd = (flipped ? coin->oppPtTStart() : coin->oppPtTEnd())->span();
caryclark54359292015-03-26 07:52:43 -07001042 SkASSERT(oStart == oStart->starter(oEnd));
1043 SkOpSegment* segment = start->segment();
1044 SkOpSegment* oSegment = oStart->segment();
1045 bool operandSwap = segment->operand() != oSegment->operand();
1046 if (flipped) {
caryclark364a0072015-12-14 08:43:21 -08001047 if (oEnd->deleted()) {
1048 continue;
1049 }
caryclark54359292015-03-26 07:52:43 -07001050 do {
1051 SkOpSpanBase* oNext = oStart->next();
1052 if (oNext == oEnd) {
1053 break;
1054 }
Cary Clark26ae5ab2016-12-12 13:57:56 -05001055 FAIL_IF(!oNext->upCastable());
caryclark54359292015-03-26 07:52:43 -07001056 oStart = oNext->upCast();
1057 } while (true);
1058 }
caryclark54359292015-03-26 07:52:43 -07001059 do {
1060 int windValue = start->windValue();
caryclark54359292015-03-26 07:52:43 -07001061 int oppValue = start->oppValue();
caryclark1049f122015-04-20 08:31:59 -07001062 int oWindValue = oStart->windValue();
caryclark54359292015-03-26 07:52:43 -07001063 int oOppValue = oStart->oppValue();
1064 // winding values are added or subtracted depending on direction and wind type
1065 // same or opposite values are summed depending on the operand value
caryclark1049f122015-04-20 08:31:59 -07001066 int windDiff = operandSwap ? oOppValue : oWindValue;
1067 int oWindDiff = operandSwap ? oppValue : windValue;
1068 if (!flipped) {
1069 windDiff = -windDiff;
1070 oWindDiff = -oWindDiff;
1071 }
caryclark55888e42016-07-18 10:01:36 -07001072 bool addToStart = windValue && (windValue > windDiff || (windValue == windDiff
1073 && oWindValue <= oWindDiff));
1074 if (addToStart ? start->done() : oStart->done()) {
1075 addToStart ^= true;
1076 }
1077 if (addToStart) {
caryclark54359292015-03-26 07:52:43 -07001078 if (operandSwap) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -04001079 using std::swap;
1080 swap(oWindValue, oOppValue);
caryclark54359292015-03-26 07:52:43 -07001081 }
1082 if (flipped) {
1083 windValue -= oWindValue;
1084 oppValue -= oOppValue;
1085 } else {
1086 windValue += oWindValue;
1087 oppValue += oOppValue;
1088 }
caryclark1049f122015-04-20 08:31:59 -07001089 if (segment->isXor()) {
caryclark54359292015-03-26 07:52:43 -07001090 windValue &= 1;
1091 }
caryclark1049f122015-04-20 08:31:59 -07001092 if (segment->oppXor()) {
caryclark54359292015-03-26 07:52:43 -07001093 oppValue &= 1;
1094 }
1095 oWindValue = oOppValue = 0;
1096 } else {
1097 if (operandSwap) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -04001098 using std::swap;
1099 swap(windValue, oppValue);
caryclark54359292015-03-26 07:52:43 -07001100 }
1101 if (flipped) {
1102 oWindValue -= windValue;
1103 oOppValue -= oppValue;
1104 } else {
1105 oWindValue += windValue;
1106 oOppValue += oppValue;
1107 }
caryclark1049f122015-04-20 08:31:59 -07001108 if (oSegment->isXor()) {
caryclark54359292015-03-26 07:52:43 -07001109 oWindValue &= 1;
1110 }
caryclark1049f122015-04-20 08:31:59 -07001111 if (oSegment->oppXor()) {
1112 oOppValue &= 1;
1113 }
caryclark54359292015-03-26 07:52:43 -07001114 windValue = oppValue = 0;
1115 }
caryclark6c3b9cd2016-09-26 05:36:58 -07001116#if 0 && DEBUG_COINCIDENCE
caryclark55888e42016-07-18 10:01:36 -07001117 SkDebugf("seg=%d span=%d windValue=%d oppValue=%d\n", segment->debugID(),
1118 start->debugID(), windValue, oppValue);
1119 SkDebugf("seg=%d span=%d windValue=%d oppValue=%d\n", oSegment->debugID(),
1120 oStart->debugID(), oWindValue, oOppValue);
1121#endif
Cary Clark0949bee2018-03-19 09:42:00 -04001122 FAIL_IF(windValue <= -1);
caryclark54359292015-03-26 07:52:43 -07001123 start->setWindValue(windValue);
1124 start->setOppValue(oppValue);
Cary Clarkb8421ed2018-03-14 15:55:02 -04001125 FAIL_IF(oWindValue <= -1);
caryclark54359292015-03-26 07:52:43 -07001126 oStart->setWindValue(oWindValue);
1127 oStart->setOppValue(oOppValue);
1128 if (!windValue && !oppValue) {
1129 segment->markDone(start);
1130 }
1131 if (!oWindValue && !oOppValue) {
1132 oSegment->markDone(oStart);
1133 }
1134 SkOpSpanBase* next = start->next();
1135 SkOpSpanBase* oNext = flipped ? oStart->prev() : oStart->next();
1136 if (next == end) {
1137 break;
1138 }
caryclark96dc1c92016-10-20 11:34:10 -07001139 FAIL_IF(!next->upCastable());
caryclark54359292015-03-26 07:52:43 -07001140 start = next->upCast();
caryclark1049f122015-04-20 08:31:59 -07001141 // if the opposite ran out too soon, just reuse the last span
1142 if (!oNext || !oNext->upCastable()) {
1143 oNext = oStart;
caryclark54359292015-03-26 07:52:43 -07001144 }
1145 oStart = oNext->upCast();
1146 } while (true);
caryclark55888e42016-07-18 10:01:36 -07001147 } while ((coin = coin->next()));
caryclarka35ab3e2016-10-20 08:32:18 -07001148 return true;
caryclark54359292015-03-26 07:52:43 -07001149}
1150
caryclark55888e42016-07-18 10:01:36 -07001151// Please keep this in sync with debugRelease()
1152bool SkOpCoincidence::release(SkCoincidentSpans* coin, SkCoincidentSpans* remove) {
1153 SkCoincidentSpans* head = coin;
halcanary96fcdcc2015-08-27 07:41:13 -07001154 SkCoincidentSpans* prev = nullptr;
caryclark54359292015-03-26 07:52:43 -07001155 SkCoincidentSpans* next;
1156 do {
caryclark55888e42016-07-18 10:01:36 -07001157 next = coin->next();
caryclark54359292015-03-26 07:52:43 -07001158 if (coin == remove) {
1159 if (prev) {
caryclark55888e42016-07-18 10:01:36 -07001160 prev->setNext(next);
1161 } else if (head == fHead) {
caryclark54359292015-03-26 07:52:43 -07001162 fHead = next;
caryclark55888e42016-07-18 10:01:36 -07001163 } else {
1164 fTop = next;
caryclark54359292015-03-26 07:52:43 -07001165 }
1166 break;
1167 }
1168 prev = coin;
1169 } while ((coin = next));
caryclark55888e42016-07-18 10:01:36 -07001170 return coin != nullptr;
caryclark54359292015-03-26 07:52:43 -07001171}
1172
caryclark30b9fdd2016-08-31 14:36:29 -07001173void SkOpCoincidence::releaseDeleted(SkCoincidentSpans* coin) {
1174 if (!coin) {
1175 return;
1176 }
1177 SkCoincidentSpans* head = coin;
1178 SkCoincidentSpans* prev = nullptr;
1179 SkCoincidentSpans* next;
1180 do {
1181 next = coin->next();
1182 if (coin->coinPtTStart()->deleted()) {
1183 SkOPASSERT(coin->flipped() ? coin->oppPtTEnd()->deleted() :
1184 coin->oppPtTStart()->deleted());
1185 if (prev) {
1186 prev->setNext(next);
1187 } else if (head == fHead) {
1188 fHead = next;
1189 } else {
1190 fTop = next;
1191 }
1192 } else {
1193 SkOPASSERT(coin->flipped() ? !coin->oppPtTEnd()->deleted() :
1194 !coin->oppPtTStart()->deleted());
1195 prev = coin;
1196 }
1197 } while ((coin = next));
1198}
1199
1200void SkOpCoincidence::releaseDeleted() {
1201 this->releaseDeleted(fHead);
1202 this->releaseDeleted(fTop);
1203}
1204
caryclark55888e42016-07-18 10:01:36 -07001205void SkOpCoincidence::restoreHead() {
1206 SkCoincidentSpans** headPtr = &fHead;
1207 while (*headPtr) {
1208 headPtr = (*headPtr)->nextPtr();
1209 }
1210 *headPtr = fTop;
1211 fTop = nullptr;
1212 // segments may have collapsed in the meantime; remove empty referenced segments
1213 headPtr = &fHead;
1214 while (*headPtr) {
1215 SkCoincidentSpans* test = *headPtr;
1216 if (test->coinPtTStart()->segment()->done() || test->oppPtTStart()->segment()->done()) {
1217 *headPtr = test->next();
1218 continue;
1219 }
1220 headPtr = (*headPtr)->nextPtr();
1221 }
1222}
1223
1224// Please keep this in sync with debugExpand()
caryclark30b9fdd2016-08-31 14:36:29 -07001225// expand the range by checking adjacent spans for coincidence
Cary Clarkab87d7a2016-10-04 10:01:04 -04001226bool SkOpCoincidence::expand(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
1227 DEBUG_SET_PHASE();
caryclark54359292015-03-26 07:52:43 -07001228 SkCoincidentSpans* coin = fHead;
1229 if (!coin) {
caryclark27c8eb82015-07-06 11:38:33 -07001230 return false;
caryclark54359292015-03-26 07:52:43 -07001231 }
caryclark27c8eb82015-07-06 11:38:33 -07001232 bool expanded = false;
caryclark54359292015-03-26 07:52:43 -07001233 do {
caryclark55888e42016-07-18 10:01:36 -07001234 if (coin->expand()) {
1235 // check to see if multiple spans expanded so they are now identical
1236 SkCoincidentSpans* test = fHead;
1237 do {
1238 if (coin == test) {
1239 continue;
1240 }
1241 if (coin->coinPtTStart() == test->coinPtTStart()
1242 && coin->oppPtTStart() == test->oppPtTStart()) {
1243 this->release(fHead, test);
1244 break;
1245 }
1246 } while ((test = test->next()));
1247 expanded = true;
caryclark54359292015-03-26 07:52:43 -07001248 }
caryclark55888e42016-07-18 10:01:36 -07001249 } while ((coin = coin->next()));
caryclark27c8eb82015-07-06 11:38:33 -07001250 return expanded;
1251}
1252
Cary Clark40f23782016-10-06 12:04:16 -04001253bool SkOpCoincidence::findOverlaps(SkOpCoincidence* overlaps DEBUG_COIN_DECLARE_PARAMS()) const {
Cary Clarkab87d7a2016-10-04 10:01:04 -04001254 DEBUG_SET_PHASE();
halcanary96fcdcc2015-08-27 07:41:13 -07001255 overlaps->fHead = overlaps->fTop = nullptr;
caryclark27c8eb82015-07-06 11:38:33 -07001256 SkCoincidentSpans* outer = fHead;
1257 while (outer) {
caryclark55888e42016-07-18 10:01:36 -07001258 const SkOpSegment* outerCoin = outer->coinPtTStart()->segment();
1259 const SkOpSegment* outerOpp = outer->oppPtTStart()->segment();
caryclark27c8eb82015-07-06 11:38:33 -07001260 SkCoincidentSpans* inner = outer;
caryclark55888e42016-07-18 10:01:36 -07001261 while ((inner = inner->next())) {
1262 const SkOpSegment* innerCoin = inner->coinPtTStart()->segment();
caryclark27c8eb82015-07-06 11:38:33 -07001263 if (outerCoin == innerCoin) {
1264 continue; // both winners are the same segment, so there's no additional overlap
1265 }
caryclark55888e42016-07-18 10:01:36 -07001266 const SkOpSegment* innerOpp = inner->oppPtTStart()->segment();
1267 const SkOpPtT* overlapS;
1268 const SkOpPtT* overlapE;
1269 if ((outerOpp == innerCoin && SkOpPtT::Overlaps(outer->oppPtTStart(),
1270 outer->oppPtTEnd(),inner->coinPtTStart(), inner->coinPtTEnd(), &overlapS,
1271 &overlapE))
1272 || (outerCoin == innerOpp && SkOpPtT::Overlaps(outer->coinPtTStart(),
1273 outer->coinPtTEnd(), inner->oppPtTStart(), inner->oppPtTEnd(),
caryclark27c8eb82015-07-06 11:38:33 -07001274 &overlapS, &overlapE))
caryclark55888e42016-07-18 10:01:36 -07001275 || (outerOpp == innerOpp && SkOpPtT::Overlaps(outer->oppPtTStart(),
1276 outer->oppPtTEnd(), inner->oppPtTStart(), inner->oppPtTEnd(),
caryclark27c8eb82015-07-06 11:38:33 -07001277 &overlapS, &overlapE))) {
Cary Clark40f23782016-10-06 12:04:16 -04001278 if (!overlaps->addOverlap(outerCoin, outerOpp, innerCoin, innerOpp,
1279 overlapS, overlapE)) {
1280 return false;
1281 }
Cary Clarke47ae292016-10-05 08:51:39 -04001282 }
caryclark27c8eb82015-07-06 11:38:33 -07001283 }
caryclark55888e42016-07-18 10:01:36 -07001284 outer = outer->next();
caryclark27c8eb82015-07-06 11:38:33 -07001285 }
Cary Clark40f23782016-10-06 12:04:16 -04001286 return true;
caryclark27c8eb82015-07-06 11:38:33 -07001287}
1288
caryclark55888e42016-07-18 10:01:36 -07001289void SkOpCoincidence::fixUp(SkOpPtT* deleted, const SkOpPtT* kept) {
caryclarkb393a492016-09-07 08:21:09 -07001290 SkOPASSERT(deleted != kept);
caryclark55888e42016-07-18 10:01:36 -07001291 if (fHead) {
1292 this->fixUp(fHead, deleted, kept);
caryclark54359292015-03-26 07:52:43 -07001293 }
caryclark55888e42016-07-18 10:01:36 -07001294 if (fTop) {
1295 this->fixUp(fTop, deleted, kept);
1296 }
caryclark54359292015-03-26 07:52:43 -07001297}
1298
caryclark55888e42016-07-18 10:01:36 -07001299void SkOpCoincidence::fixUp(SkCoincidentSpans* coin, SkOpPtT* deleted, const SkOpPtT* kept) {
1300 SkCoincidentSpans* head = coin;
1301 do {
1302 if (coin->coinPtTStart() == deleted) {
1303 if (coin->coinPtTEnd()->span() == kept->span()) {
1304 this->release(head, coin);
1305 continue;
1306 }
1307 coin->setCoinPtTStart(kept);
1308 }
1309 if (coin->coinPtTEnd() == deleted) {
1310 if (coin->coinPtTStart()->span() == kept->span()) {
1311 this->release(head, coin);
1312 continue;
1313 }
1314 coin->setCoinPtTEnd(kept);
1315 }
1316 if (coin->oppPtTStart() == deleted) {
1317 if (coin->oppPtTEnd()->span() == kept->span()) {
1318 this->release(head, coin);
1319 continue;
1320 }
1321 coin->setOppPtTStart(kept);
1322 }
1323 if (coin->oppPtTEnd() == deleted) {
1324 if (coin->oppPtTStart()->span() == kept->span()) {
1325 this->release(head, coin);
1326 continue;
1327 }
1328 coin->setOppPtTEnd(kept);
1329 }
1330 } while ((coin = coin->next()));
1331}
1332
1333// Please keep this in sync with debugMark()
caryclark27c8eb82015-07-06 11:38:33 -07001334/* this sets up the coincidence links in the segments when the coincidence crosses multiple spans */
caryclarke6522ea2016-10-17 07:54:33 -07001335bool SkOpCoincidence::mark(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
Cary Clarkab87d7a2016-10-04 10:01:04 -04001336 DEBUG_SET_PHASE();
caryclark54359292015-03-26 07:52:43 -07001337 SkCoincidentSpans* coin = fHead;
1338 if (!coin) {
caryclarke6522ea2016-10-17 07:54:33 -07001339 return true;
caryclark54359292015-03-26 07:52:43 -07001340 }
1341 do {
caryclarke6522ea2016-10-17 07:54:33 -07001342 SkOpSpanBase* startBase = coin->coinPtTStartWritable()->span();
1343 FAIL_IF(!startBase->upCastable());
1344 SkOpSpan* start = startBase->upCast();
caryclarka35ab3e2016-10-20 08:32:18 -07001345 FAIL_IF(start->deleted());
caryclark55888e42016-07-18 10:01:36 -07001346 SkOpSpanBase* end = coin->coinPtTEndWritable()->span();
Cary Clark40f23782016-10-06 12:04:16 -04001347 SkOPASSERT(!end->deleted());
caryclark55888e42016-07-18 10:01:36 -07001348 SkOpSpanBase* oStart = coin->oppPtTStartWritable()->span();
Cary Clark40f23782016-10-06 12:04:16 -04001349 SkOPASSERT(!oStart->deleted());
caryclark55888e42016-07-18 10:01:36 -07001350 SkOpSpanBase* oEnd = coin->oppPtTEndWritable()->span();
Cary Clarkf36b8a32018-03-20 16:08:35 -04001351 FAIL_IF(oEnd->deleted());
caryclark55888e42016-07-18 10:01:36 -07001352 bool flipped = coin->flipped();
caryclark54359292015-03-26 07:52:43 -07001353 if (flipped) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -04001354 using std::swap;
1355 swap(oStart, oEnd);
caryclark54359292015-03-26 07:52:43 -07001356 }
caryclark55888e42016-07-18 10:01:36 -07001357 /* coin and opp spans may not match up. Mark the ends, and then let the interior
1358 get marked as many times as the spans allow */
Cary Clark9de09762016-11-17 08:47:37 -05001359 FAIL_IF(!oStart->upCastable());
caryclark55888e42016-07-18 10:01:36 -07001360 start->insertCoincidence(oStart->upCast());
1361 end->insertCoinEnd(oEnd);
1362 const SkOpSegment* segment = start->segment();
1363 const SkOpSegment* oSegment = oStart->segment();
caryclark54359292015-03-26 07:52:43 -07001364 SkOpSpanBase* next = start;
1365 SkOpSpanBase* oNext = oStart;
caryclarka35ab3e2016-10-20 08:32:18 -07001366 bool ordered;
1367 FAIL_IF(!coin->ordered(&ordered));
caryclark55888e42016-07-18 10:01:36 -07001368 while ((next = next->upCast()->next()) != end) {
caryclarke6522ea2016-10-17 07:54:33 -07001369 FAIL_IF(!next->upCastable());
Cary Clark59ed4822016-12-08 16:17:56 -05001370 FAIL_IF(!next->upCast()->insertCoincidence(oSegment, flipped, ordered));
caryclark55888e42016-07-18 10:01:36 -07001371 }
1372 while ((oNext = oNext->upCast()->next()) != oEnd) {
caryclark96dc1c92016-10-20 11:34:10 -07001373 FAIL_IF(!oNext->upCastable());
caryclarke6522ea2016-10-17 07:54:33 -07001374 FAIL_IF(!oNext->upCast()->insertCoincidence(segment, flipped, ordered));
caryclark55888e42016-07-18 10:01:36 -07001375 }
1376 } while ((coin = coin->next()));
caryclarke6522ea2016-10-17 07:54:33 -07001377 return true;
caryclark54359292015-03-26 07:52:43 -07001378}
1379
caryclark55888e42016-07-18 10:01:36 -07001380// Please keep in sync with debugMarkCollapsed()
1381void SkOpCoincidence::markCollapsed(SkCoincidentSpans* coin, SkOpPtT* test) {
1382 SkCoincidentSpans* head = coin;
1383 while (coin) {
1384 if (coin->collapsed(test)) {
1385 if (zero_or_one(coin->coinPtTStart()->fT) && zero_or_one(coin->coinPtTEnd()->fT)) {
1386 coin->coinPtTStartWritable()->segment()->markAllDone();
1387 }
1388 if (zero_or_one(coin->oppPtTStart()->fT) && zero_or_one(coin->oppPtTEnd()->fT)) {
1389 coin->oppPtTStartWritable()->segment()->markAllDone();
1390 }
1391 this->release(head, coin);
1392 }
1393 coin = coin->next();
1394 }
1395}
1396
1397// Please keep in sync with debugMarkCollapsed()
1398void SkOpCoincidence::markCollapsed(SkOpPtT* test) {
1399 markCollapsed(fHead, test);
1400 markCollapsed(fTop, test);
1401}
1402
1403bool SkOpCoincidence::Ordered(const SkOpSegment* coinSeg, const SkOpSegment* oppSeg) {
1404 if (coinSeg->verb() < oppSeg->verb()) {
1405 return true;
1406 }
1407 if (coinSeg->verb() > oppSeg->verb()) {
1408 return false;
1409 }
1410 int count = (SkPathOpsVerbToPoints(coinSeg->verb()) + 1) * 2;
1411 const SkScalar* cPt = &coinSeg->pts()[0].fX;
1412 const SkScalar* oPt = &oppSeg->pts()[0].fX;
1413 for (int index = 0; index < count; ++index) {
1414 if (*cPt < *oPt) {
1415 return true;
1416 }
1417 if (*cPt > *oPt) {
1418 return false;
1419 }
1420 ++cPt;
1421 ++oPt;
1422 }
1423 return true;
1424}
1425
1426bool SkOpCoincidence::overlap(const SkOpPtT* coin1s, const SkOpPtT* coin1e,
caryclark54359292015-03-26 07:52:43 -07001427 const SkOpPtT* coin2s, const SkOpPtT* coin2e, double* overS, double* overE) const {
caryclark27c8eb82015-07-06 11:38:33 -07001428 SkASSERT(coin1s->segment() == coin2s->segment());
caryclark54359292015-03-26 07:52:43 -07001429 *overS = SkTMax(SkTMin(coin1s->fT, coin1e->fT), SkTMin(coin2s->fT, coin2e->fT));
1430 *overE = SkTMin(SkTMax(coin1s->fT, coin1e->fT), SkTMax(coin2s->fT, coin2e->fT));
1431 return *overS < *overE;
1432}
caryclark27c8eb82015-07-06 11:38:33 -07001433
caryclark55888e42016-07-18 10:01:36 -07001434// Commented-out lines keep this in sync with debugRelease()
1435void SkOpCoincidence::release(const SkOpSegment* deleted) {
1436 SkCoincidentSpans* coin = fHead;
1437 if (!coin) {
1438 return;
1439 }
1440 do {
1441 if (coin->coinPtTStart()->segment() == deleted
1442 || coin->coinPtTEnd()->segment() == deleted
1443 || coin->oppPtTStart()->segment() == deleted
1444 || coin->oppPtTEnd()->segment() == deleted) {
1445 this->release(fHead, coin);
1446 }
1447 } while ((coin = coin->next()));
1448}