blob: 5677b021aa59aa93792ad66cc41775c6a467024d [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));
caryclark30b9fdd2016-08-31 14:36:29 -0700640 if (coinSeg->collapsed(coinTs, coinTe)) {
caryclark81a478c2016-09-09 09:37:57 -0700641 return true;
caryclark30b9fdd2016-08-31 14:36:29 -0700642 }
caryclark8016b262016-09-06 05:59:47 -0700643 oppTs = TRange(over2s, tStart, oppSeg SkDEBUGPARAMS(over2e));
644 oppTe = TRange(over2s, tEnd, oppSeg SkDEBUGPARAMS(over2e));
caryclark30b9fdd2016-08-31 14:36:29 -0700645 if (oppSeg->collapsed(oppTs, oppTe)) {
caryclark81a478c2016-09-09 09:37:57 -0700646 return true;
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 }
caryclark81a478c2016-09-09 09:37:57 -0700653 return this->addOrOverlap(coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, added);
caryclark54359292015-03-26 07:52:43 -0700654}
655
caryclark55888e42016-07-18 10:01:36 -0700656/* Please keep this in sync with debugAddOrOverlap() */
caryclark025b11e2016-08-25 05:21:14 -0700657// If this is called by addEndMovedSpans(), a returned false propogates out to an abort.
658// If this is called by AddIfMissing(), a returned false indicates there was nothing to add
caryclark55888e42016-07-18 10:01:36 -0700659bool SkOpCoincidence::addOrOverlap(SkOpSegment* coinSeg, SkOpSegment* oppSeg,
caryclark81a478c2016-09-09 09:37:57 -0700660 double coinTs, double coinTe, double oppTs, double oppTe, bool* added) {
caryclark55888e42016-07-18 10:01:36 -0700661 SkTDArray<SkCoincidentSpans*> overlaps;
caryclark81a478c2016-09-09 09:37:57 -0700662 FAIL_IF(!fTop);
caryclark55888e42016-07-18 10:01:36 -0700663 if (!this->checkOverlap(fTop, coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, &overlaps)) {
caryclark81a478c2016-09-09 09:37:57 -0700664 return true;
caryclark55888e42016-07-18 10:01:36 -0700665 }
666 if (fHead && !this->checkOverlap(fHead, coinSeg, oppSeg, coinTs,
667 coinTe, oppTs, oppTe, &overlaps)) {
caryclark81a478c2016-09-09 09:37:57 -0700668 return true;
caryclark55888e42016-07-18 10:01:36 -0700669 }
670 SkCoincidentSpans* overlap = overlaps.count() ? overlaps[0] : nullptr;
671 for (int index = 1; index < overlaps.count(); ++index) { // combine overlaps before continuing
672 SkCoincidentSpans* test = overlaps[index];
673 if (overlap->coinPtTStart()->fT > test->coinPtTStart()->fT) {
674 overlap->setCoinPtTStart(test->coinPtTStart());
675 }
676 if (overlap->coinPtTEnd()->fT < test->coinPtTEnd()->fT) {
677 overlap->setCoinPtTEnd(test->coinPtTEnd());
678 }
679 if (overlap->flipped()
680 ? overlap->oppPtTStart()->fT < test->oppPtTStart()->fT
681 : overlap->oppPtTStart()->fT > test->oppPtTStart()->fT) {
682 overlap->setOppPtTStart(test->oppPtTStart());
683 }
684 if (overlap->flipped()
685 ? overlap->oppPtTEnd()->fT > test->oppPtTEnd()->fT
686 : overlap->oppPtTEnd()->fT < test->oppPtTEnd()->fT) {
687 overlap->setOppPtTEnd(test->oppPtTEnd());
688 }
689 if (!fHead || !this->release(fHead, test)) {
690 SkAssertResult(this->release(fTop, test));
691 }
692 }
693 const SkOpPtT* cs = coinSeg->existing(coinTs, oppSeg);
694 const SkOpPtT* ce = coinSeg->existing(coinTe, oppSeg);
caryclark81a478c2016-09-09 09:37:57 -0700695 if (overlap && cs && ce && overlap->contains(cs, ce)) {
696 return true;
697 }
698 FAIL_IF(cs == ce && cs);
caryclark55888e42016-07-18 10:01:36 -0700699 const SkOpPtT* os = oppSeg->existing(oppTs, coinSeg);
700 const SkOpPtT* oe = oppSeg->existing(oppTe, coinSeg);
caryclark81a478c2016-09-09 09:37:57 -0700701 if (overlap && os && oe && overlap->contains(os, oe)) {
702 return true;
703 }
Cary Clarkb8421ed2018-03-14 15:55:02 -0400704 FAIL_IF(cs && cs->deleted());
Cary Clark2f06a532018-03-12 14:41:45 -0400705 FAIL_IF(os && os->deleted());
Cary Clark0949bee2018-03-19 09:42:00 -0400706 FAIL_IF(ce && ce->deleted());
Cary Clark74b42902018-03-09 07:38:47 -0500707 FAIL_IF(oe && oe->deleted());
caryclark55888e42016-07-18 10:01:36 -0700708 const SkOpPtT* csExisting = !cs ? coinSeg->existing(coinTs, nullptr) : nullptr;
709 const SkOpPtT* ceExisting = !ce ? coinSeg->existing(coinTe, nullptr) : nullptr;
caryclark81a478c2016-09-09 09:37:57 -0700710 FAIL_IF(csExisting && csExisting == ceExisting);
caryclarke839e782016-09-15 07:48:18 -0700711// FAIL_IF(csExisting && (csExisting == ce ||
712// csExisting->contains(ceExisting ? ceExisting : ce)));
caryclark81a478c2016-09-09 09:37:57 -0700713 FAIL_IF(ceExisting && (ceExisting == cs ||
caryclark025b11e2016-08-25 05:21:14 -0700714 ceExisting->contains(csExisting ? csExisting : cs)));
caryclark55888e42016-07-18 10:01:36 -0700715 const SkOpPtT* osExisting = !os ? oppSeg->existing(oppTs, nullptr) : nullptr;
716 const SkOpPtT* oeExisting = !oe ? oppSeg->existing(oppTe, nullptr) : nullptr;
caryclark81a478c2016-09-09 09:37:57 -0700717 FAIL_IF(osExisting && osExisting == oeExisting);
718 FAIL_IF(osExisting && (osExisting == oe ||
caryclark025b11e2016-08-25 05:21:14 -0700719 osExisting->contains(oeExisting ? oeExisting : oe)));
caryclark81a478c2016-09-09 09:37:57 -0700720 FAIL_IF(oeExisting && (oeExisting == os ||
caryclark025b11e2016-08-25 05:21:14 -0700721 oeExisting->contains(osExisting ? osExisting : os)));
caryclark55888e42016-07-18 10:01:36 -0700722 // extra line in debug code
723 this->debugValidate();
724 if (!cs || !os) {
725 SkOpPtT* csWritable = cs ? const_cast<SkOpPtT*>(cs)
caryclark29b25632016-08-25 11:27:17 -0700726 : coinSeg->addT(coinTs);
caryclarke839e782016-09-15 07:48:18 -0700727 if (csWritable == ce) {
728 return true;
729 }
caryclark55888e42016-07-18 10:01:36 -0700730 SkOpPtT* osWritable = os ? const_cast<SkOpPtT*>(os)
caryclark29b25632016-08-25 11:27:17 -0700731 : oppSeg->addT(oppTs);
caryclark81a478c2016-09-09 09:37:57 -0700732 FAIL_IF(!csWritable || !osWritable);
caryclark30b9fdd2016-08-31 14:36:29 -0700733 csWritable->span()->addOpp(osWritable->span());
caryclark55888e42016-07-18 10:01:36 -0700734 cs = csWritable;
caryclark30b9fdd2016-08-31 14:36:29 -0700735 os = osWritable->active();
Cary Clark74b42902018-03-09 07:38:47 -0500736 FAIL_IF(!os);
caryclark81a478c2016-09-09 09:37:57 -0700737 FAIL_IF((ce && ce->deleted()) || (oe && oe->deleted()));
caryclark55888e42016-07-18 10:01:36 -0700738 }
739 if (!ce || !oe) {
740 SkOpPtT* ceWritable = ce ? const_cast<SkOpPtT*>(ce)
caryclark29b25632016-08-25 11:27:17 -0700741 : coinSeg->addT(coinTe);
caryclark55888e42016-07-18 10:01:36 -0700742 SkOpPtT* oeWritable = oe ? const_cast<SkOpPtT*>(oe)
caryclark29b25632016-08-25 11:27:17 -0700743 : oppSeg->addT(oppTe);
caryclark30b9fdd2016-08-31 14:36:29 -0700744 ceWritable->span()->addOpp(oeWritable->span());
caryclark55888e42016-07-18 10:01:36 -0700745 ce = ceWritable;
746 oe = oeWritable;
747 }
748 this->debugValidate();
caryclark81a478c2016-09-09 09:37:57 -0700749 FAIL_IF(cs->deleted());
750 FAIL_IF(os->deleted());
751 FAIL_IF(ce->deleted());
752 FAIL_IF(oe->deleted());
753 FAIL_IF(cs->contains(ce) || os->contains(oe));
caryclark55888e42016-07-18 10:01:36 -0700754 bool result = true;
755 if (overlap) {
756 if (overlap->coinPtTStart()->segment() == coinSeg) {
757 result = overlap->extend(cs, ce, os, oe);
758 } else {
759 if (os->fT > oe->fT) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400760 using std::swap;
761 swap(cs, ce);
762 swap(os, oe);
caryclark55888e42016-07-18 10:01:36 -0700763 }
764 result = overlap->extend(os, oe, cs, ce);
765 }
766#if DEBUG_COINCIDENCE_VERBOSE
767 if (result) {
768 overlaps[0]->debugShow();
769 }
770#endif
771 } else {
772 this->add(cs, ce, os, oe);
773#if DEBUG_COINCIDENCE_VERBOSE
774 fHead->debugShow();
775#endif
776 }
777 this->debugValidate();
caryclark81a478c2016-09-09 09:37:57 -0700778 if (result) {
779 *added = true;
780 }
781 return true;
caryclark55888e42016-07-18 10:01:36 -0700782}
783
784// Please keep this in sync with debugAddMissing()
caryclark27c8eb82015-07-06 11:38:33 -0700785/* detects overlaps of different coincident runs on same segment */
786/* does not detect overlaps for pairs without any segments in common */
caryclark55888e42016-07-18 10:01:36 -0700787// returns true if caller should loop again
Cary Clarkab87d7a2016-10-04 10:01:04 -0400788bool SkOpCoincidence::addMissing(bool* added DEBUG_COIN_DECLARE_PARAMS()) {
caryclark27c8eb82015-07-06 11:38:33 -0700789 SkCoincidentSpans* outer = fHead;
caryclark81a478c2016-09-09 09:37:57 -0700790 *added = false;
caryclark54359292015-03-26 07:52:43 -0700791 if (!outer) {
caryclark81a478c2016-09-09 09:37:57 -0700792 return true;
caryclark54359292015-03-26 07:52:43 -0700793 }
caryclark27c8eb82015-07-06 11:38:33 -0700794 fTop = outer;
halcanary96fcdcc2015-08-27 07:41:13 -0700795 fHead = nullptr;
caryclark54359292015-03-26 07:52:43 -0700796 do {
caryclark27c8eb82015-07-06 11:38:33 -0700797 // addifmissing can modify the list that this is walking
caryclark26ad22a2015-10-16 09:03:38 -0700798 // save head so that walker can iterate over old data unperturbed
799 // addifmissing adds to head freely then add saved head in the end
caryclark8016b262016-09-06 05:59:47 -0700800 const SkOpPtT* ocs = outer->coinPtTStart();
caryclarka35ab3e2016-10-20 08:32:18 -0700801 FAIL_IF(ocs->deleted());
caryclark8016b262016-09-06 05:59:47 -0700802 const SkOpSegment* outerCoin = ocs->segment();
Cary Clark18562b82018-06-07 08:06:12 -0400803 FAIL_IF(outerCoin->done());
caryclark8016b262016-09-06 05:59:47 -0700804 const SkOpPtT* oos = outer->oppPtTStart();
caryclarkb393a492016-09-07 08:21:09 -0700805 if (oos->deleted()) {
caryclark81a478c2016-09-09 09:37:57 -0700806 return true;
caryclarkb393a492016-09-07 08:21:09 -0700807 }
caryclark8016b262016-09-06 05:59:47 -0700808 const SkOpSegment* outerOpp = oos->segment();
Cary Clark4c76c412017-01-20 08:14:33 -0500809 SkOPASSERT(!outerOpp->done());
caryclark8016b262016-09-06 05:59:47 -0700810 SkOpSegment* outerCoinWritable = const_cast<SkOpSegment*>(outerCoin);
811 SkOpSegment* outerOppWritable = const_cast<SkOpSegment*>(outerOpp);
caryclark54359292015-03-26 07:52:43 -0700812 SkCoincidentSpans* inner = outer;
caryclark55888e42016-07-18 10:01:36 -0700813 while ((inner = inner->next())) {
814 this->debugValidate();
caryclark54359292015-03-26 07:52:43 -0700815 double overS, overE;
caryclark8016b262016-09-06 05:59:47 -0700816 const SkOpPtT* ics = inner->coinPtTStart();
caryclark221a4bb2016-10-07 11:15:15 -0700817 FAIL_IF(ics->deleted());
caryclark8016b262016-09-06 05:59:47 -0700818 const SkOpSegment* innerCoin = ics->segment();
caryclarka35ab3e2016-10-20 08:32:18 -0700819 FAIL_IF(innerCoin->done());
caryclark8016b262016-09-06 05:59:47 -0700820 const SkOpPtT* ios = inner->oppPtTStart();
caryclarka35ab3e2016-10-20 08:32:18 -0700821 FAIL_IF(ios->deleted());
caryclark8016b262016-09-06 05:59:47 -0700822 const SkOpSegment* innerOpp = ios->segment();
Cary Clark4c76c412017-01-20 08:14:33 -0500823 SkOPASSERT(!innerOpp->done());
caryclark8016b262016-09-06 05:59:47 -0700824 SkOpSegment* innerCoinWritable = const_cast<SkOpSegment*>(innerCoin);
825 SkOpSegment* innerOppWritable = const_cast<SkOpSegment*>(innerOpp);
caryclark55888e42016-07-18 10:01:36 -0700826 if (outerCoin == innerCoin) {
caryclark8016b262016-09-06 05:59:47 -0700827 const SkOpPtT* oce = outer->coinPtTEnd();
caryclarkb393a492016-09-07 08:21:09 -0700828 if (oce->deleted()) {
caryclark81a478c2016-09-09 09:37:57 -0700829 return true;
caryclarkb393a492016-09-07 08:21:09 -0700830 }
caryclark8016b262016-09-06 05:59:47 -0700831 const SkOpPtT* ice = inner->coinPtTEnd();
caryclark595ac282016-10-24 08:41:45 -0700832 FAIL_IF(ice->deleted());
caryclark8016b262016-09-06 05:59:47 -0700833 if (outerOpp != innerOpp && this->overlap(ocs, oce, ics, ice, &overS, &overE)) {
caryclark81a478c2016-09-09 09:37:57 -0700834 (void) this->addIfMissing(ocs->starter(oce), ics->starter(ice),
835 overS, overE, outerOppWritable, innerOppWritable, added
caryclark8016b262016-09-06 05:59:47 -0700836 SkDEBUGPARAMS(ocs->debugEnder(oce))
837 SkDEBUGPARAMS(ics->debugEnder(ice)));
caryclark55888e42016-07-18 10:01:36 -0700838 }
839 } else if (outerCoin == innerOpp) {
caryclark8016b262016-09-06 05:59:47 -0700840 const SkOpPtT* oce = outer->coinPtTEnd();
Cary Clark56071432018-06-19 08:33:52 -0400841 FAIL_IF(oce->deleted());
caryclark8016b262016-09-06 05:59:47 -0700842 const SkOpPtT* ioe = inner->oppPtTEnd();
843 SkASSERT(!ioe->deleted());
844 if (outerOpp != innerCoin && this->overlap(ocs, oce, ios, ioe, &overS, &overE)) {
caryclark81a478c2016-09-09 09:37:57 -0700845 (void) this->addIfMissing(ocs->starter(oce), ios->starter(ioe),
846 overS, overE, outerOppWritable, innerCoinWritable, added
caryclark8016b262016-09-06 05:59:47 -0700847 SkDEBUGPARAMS(ocs->debugEnder(oce))
848 SkDEBUGPARAMS(ios->debugEnder(ioe)));
caryclark55888e42016-07-18 10:01:36 -0700849 }
850 } else if (outerOpp == innerCoin) {
caryclark8016b262016-09-06 05:59:47 -0700851 const SkOpPtT* ooe = outer->oppPtTEnd();
852 SkASSERT(!ooe->deleted());
853 const SkOpPtT* ice = inner->coinPtTEnd();
854 SkASSERT(!ice->deleted());
caryclark55888e42016-07-18 10:01:36 -0700855 SkASSERT(outerCoin != innerOpp);
caryclark8016b262016-09-06 05:59:47 -0700856 if (this->overlap(oos, ooe, ics, ice, &overS, &overE)) {
caryclark81a478c2016-09-09 09:37:57 -0700857 (void) this->addIfMissing(oos->starter(ooe), ics->starter(ice),
858 overS, overE, outerCoinWritable, innerOppWritable, added
caryclark8016b262016-09-06 05:59:47 -0700859 SkDEBUGPARAMS(oos->debugEnder(ooe))
860 SkDEBUGPARAMS(ics->debugEnder(ice)));
caryclark55888e42016-07-18 10:01:36 -0700861 }
862 } else if (outerOpp == innerOpp) {
caryclark8016b262016-09-06 05:59:47 -0700863 const SkOpPtT* ooe = outer->oppPtTEnd();
Cary Clark8d8a5d92018-04-02 12:40:49 -0400864 FAIL_IF(ooe->deleted());
caryclark8016b262016-09-06 05:59:47 -0700865 const SkOpPtT* ioe = inner->oppPtTEnd();
caryclarkb393a492016-09-07 08:21:09 -0700866 if (ioe->deleted()) {
caryclark81a478c2016-09-09 09:37:57 -0700867 return true;
caryclarkb393a492016-09-07 08:21:09 -0700868 }
caryclark55888e42016-07-18 10:01:36 -0700869 SkASSERT(outerCoin != innerCoin);
caryclark8016b262016-09-06 05:59:47 -0700870 if (this->overlap(oos, ooe, ios, ioe, &overS, &overE)) {
caryclark81a478c2016-09-09 09:37:57 -0700871 (void) this->addIfMissing(oos->starter(ooe), ios->starter(ioe),
872 overS, overE, outerCoinWritable, innerCoinWritable, added
caryclark8016b262016-09-06 05:59:47 -0700873 SkDEBUGPARAMS(oos->debugEnder(ooe))
874 SkDEBUGPARAMS(ios->debugEnder(ioe)));
caryclark54359292015-03-26 07:52:43 -0700875 }
876 }
caryclark55888e42016-07-18 10:01:36 -0700877 this->debugValidate();
caryclark54359292015-03-26 07:52:43 -0700878 }
caryclark55888e42016-07-18 10:01:36 -0700879 } while ((outer = outer->next()));
880 this->restoreHead();
caryclark81a478c2016-09-09 09:37:57 -0700881 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700882}
883
caryclark55888e42016-07-18 10:01:36 -0700884bool SkOpCoincidence::addOverlap(const SkOpSegment* seg1, const SkOpSegment* seg1o,
885 const SkOpSegment* seg2, const SkOpSegment* seg2o,
886 const SkOpPtT* overS, const SkOpPtT* overE) {
Cary Clarke47ae292016-10-05 08:51:39 -0400887 const SkOpPtT* s1 = overS->find(seg1);
888 const SkOpPtT* e1 = overE->find(seg1);
caryclark08714012016-10-07 12:57:47 -0700889 FAIL_IF(!s1);
Cary Clark40f23782016-10-06 12:04:16 -0400890 FAIL_IF(!e1);
caryclark27c8eb82015-07-06 11:38:33 -0700891 if (!s1->starter(e1)->span()->upCast()->windValue()) {
Cary Clarke47ae292016-10-05 08:51:39 -0400892 s1 = overS->find(seg1o);
893 e1 = overE->find(seg1o);
caryclark221a4bb2016-10-07 11:15:15 -0700894 FAIL_IF(!s1);
Cary Clark40f23782016-10-06 12:04:16 -0400895 FAIL_IF(!e1);
caryclark27c8eb82015-07-06 11:38:33 -0700896 if (!s1->starter(e1)->span()->upCast()->windValue()) {
caryclark3f0753d2016-06-28 09:23:57 -0700897 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700898 }
899 }
Cary Clarke47ae292016-10-05 08:51:39 -0400900 const SkOpPtT* s2 = overS->find(seg2);
901 const SkOpPtT* e2 = overE->find(seg2);
caryclark82616712016-10-24 04:53:22 -0700902 FAIL_IF(!s2);
caryclarka35ab3e2016-10-20 08:32:18 -0700903 FAIL_IF(!e2);
caryclark27c8eb82015-07-06 11:38:33 -0700904 if (!s2->starter(e2)->span()->upCast()->windValue()) {
Cary Clarke47ae292016-10-05 08:51:39 -0400905 s2 = overS->find(seg2o);
906 e2 = overE->find(seg2o);
caryclarka35ab3e2016-10-20 08:32:18 -0700907 FAIL_IF(!s2);
caryclark78a37a52016-10-20 12:36:16 -0700908 FAIL_IF(!e2);
caryclark27c8eb82015-07-06 11:38:33 -0700909 if (!s2->starter(e2)->span()->upCast()->windValue()) {
caryclark3f0753d2016-06-28 09:23:57 -0700910 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700911 }
912 }
913 if (s1->segment() == s2->segment()) {
caryclark3f0753d2016-06-28 09:23:57 -0700914 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700915 }
916 if (s1->fT > e1->fT) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400917 using std::swap;
918 swap(s1, e1);
919 swap(s2, e2);
caryclark27c8eb82015-07-06 11:38:33 -0700920 }
caryclark55888e42016-07-18 10:01:36 -0700921 this->add(s1, e1, s2, e2);
caryclark3f0753d2016-06-28 09:23:57 -0700922 return true;
caryclark54359292015-03-26 07:52:43 -0700923}
924
caryclark55888e42016-07-18 10:01:36 -0700925bool SkOpCoincidence::contains(const SkOpSegment* seg, const SkOpSegment* opp, double oppT) const {
926 if (this->contains(fHead, seg, opp, oppT)) {
927 return true;
928 }
929 if (this->contains(fTop, seg, opp, oppT)) {
930 return true;
931 }
932 return false;
933}
934
935bool SkOpCoincidence::contains(const SkCoincidentSpans* coin, const SkOpSegment* seg,
936 const SkOpSegment* opp, double oppT) const {
937 if (!coin) {
938 return false;
939 }
940 do {
941 if (coin->coinPtTStart()->segment() == seg && coin->oppPtTStart()->segment() == opp
942 && between(coin->oppPtTStart()->fT, oppT, coin->oppPtTEnd()->fT)) {
caryclark54359292015-03-26 07:52:43 -0700943 return true;
944 }
caryclark55888e42016-07-18 10:01:36 -0700945 if (coin->oppPtTStart()->segment() == seg && coin->coinPtTStart()->segment() == opp
946 && between(coin->coinPtTStart()->fT, oppT, coin->coinPtTEnd()->fT)) {
947 return true;
948 }
949 } while ((coin = coin->next()));
caryclark54359292015-03-26 07:52:43 -0700950 return false;
951}
952
caryclark55888e42016-07-18 10:01:36 -0700953bool SkOpCoincidence::contains(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd,
954 const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) const {
955 const SkCoincidentSpans* test = fHead;
956 if (!test) {
957 return false;
958 }
959 const SkOpSegment* coinSeg = coinPtTStart->segment();
960 const SkOpSegment* oppSeg = oppPtTStart->segment();
961 if (!Ordered(coinPtTStart, oppPtTStart)) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400962 using std::swap;
963 swap(coinSeg, oppSeg);
964 swap(coinPtTStart, oppPtTStart);
965 swap(coinPtTEnd, oppPtTEnd);
caryclark55888e42016-07-18 10:01:36 -0700966 if (coinPtTStart->fT > coinPtTEnd->fT) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400967 swap(coinPtTStart, coinPtTEnd);
968 swap(oppPtTStart, oppPtTEnd);
caryclark55888e42016-07-18 10:01:36 -0700969 }
970 }
971 double oppMinT = SkTMin(oppPtTStart->fT, oppPtTEnd->fT);
972 double oppMaxT = SkTMax(oppPtTStart->fT, oppPtTEnd->fT);
973 do {
974 if (coinSeg != test->coinPtTStart()->segment()) {
975 continue;
976 }
977 if (coinPtTStart->fT < test->coinPtTStart()->fT) {
978 continue;
979 }
980 if (coinPtTEnd->fT > test->coinPtTEnd()->fT) {
981 continue;
982 }
983 if (oppSeg != test->oppPtTStart()->segment()) {
984 continue;
985 }
986 if (oppMinT < SkTMin(test->oppPtTStart()->fT, test->oppPtTEnd()->fT)) {
987 continue;
988 }
989 if (oppMaxT > SkTMax(test->oppPtTStart()->fT, test->oppPtTEnd()->fT)) {
990 continue;
991 }
992 return true;
993 } while ((test = test->next()));
994 return false;
995}
996
Cary Clarkab87d7a2016-10-04 10:01:04 -0400997void SkOpCoincidence::correctEnds(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
998 DEBUG_SET_PHASE();
caryclark55888e42016-07-18 10:01:36 -0700999 SkCoincidentSpans* coin = fHead;
1000 if (!coin) {
1001 return;
1002 }
1003 do {
1004 coin->correctEnds();
1005 } while ((coin = coin->next()));
1006}
1007
caryclark54359292015-03-26 07:52:43 -07001008// walk span sets in parallel, moving winding from one to the other
caryclarka35ab3e2016-10-20 08:32:18 -07001009bool SkOpCoincidence::apply(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
Cary Clarkab87d7a2016-10-04 10:01:04 -04001010 DEBUG_SET_PHASE();
caryclark54359292015-03-26 07:52:43 -07001011 SkCoincidentSpans* coin = fHead;
1012 if (!coin) {
caryclarka35ab3e2016-10-20 08:32:18 -07001013 return true;
caryclark54359292015-03-26 07:52:43 -07001014 }
1015 do {
Cary Clark5a2057a2017-01-03 10:47:34 -05001016 SkOpSpanBase* startSpan = coin->coinPtTStartWritable()->span();
1017 FAIL_IF(!startSpan->upCastable());
1018 SkOpSpan* start = startSpan->upCast();
caryclark182b4992015-05-14 05:45:54 -07001019 if (start->deleted()) {
1020 continue;
1021 }
caryclark55888e42016-07-18 10:01:36 -07001022 const SkOpSpanBase* end = coin->coinPtTEnd()->span();
caryclark54359292015-03-26 07:52:43 -07001023 SkASSERT(start == start->starter(end));
caryclark55888e42016-07-18 10:01:36 -07001024 bool flipped = coin->flipped();
caryclark96dc1c92016-10-20 11:34:10 -07001025 SkOpSpanBase* oStartBase = (flipped ? coin->oppPtTEndWritable()
1026 : coin->oppPtTStartWritable())->span();
1027 FAIL_IF(!oStartBase->upCastable());
1028 SkOpSpan* oStart = oStartBase->upCast();
caryclark182b4992015-05-14 05:45:54 -07001029 if (oStart->deleted()) {
1030 continue;
1031 }
caryclark55888e42016-07-18 10:01:36 -07001032 const SkOpSpanBase* oEnd = (flipped ? coin->oppPtTStart() : coin->oppPtTEnd())->span();
caryclark54359292015-03-26 07:52:43 -07001033 SkASSERT(oStart == oStart->starter(oEnd));
1034 SkOpSegment* segment = start->segment();
1035 SkOpSegment* oSegment = oStart->segment();
1036 bool operandSwap = segment->operand() != oSegment->operand();
1037 if (flipped) {
caryclark364a0072015-12-14 08:43:21 -08001038 if (oEnd->deleted()) {
1039 continue;
1040 }
caryclark54359292015-03-26 07:52:43 -07001041 do {
1042 SkOpSpanBase* oNext = oStart->next();
1043 if (oNext == oEnd) {
1044 break;
1045 }
Cary Clark26ae5ab2016-12-12 13:57:56 -05001046 FAIL_IF(!oNext->upCastable());
caryclark54359292015-03-26 07:52:43 -07001047 oStart = oNext->upCast();
1048 } while (true);
1049 }
caryclark54359292015-03-26 07:52:43 -07001050 do {
1051 int windValue = start->windValue();
caryclark54359292015-03-26 07:52:43 -07001052 int oppValue = start->oppValue();
caryclark1049f122015-04-20 08:31:59 -07001053 int oWindValue = oStart->windValue();
caryclark54359292015-03-26 07:52:43 -07001054 int oOppValue = oStart->oppValue();
1055 // winding values are added or subtracted depending on direction and wind type
1056 // same or opposite values are summed depending on the operand value
caryclark1049f122015-04-20 08:31:59 -07001057 int windDiff = operandSwap ? oOppValue : oWindValue;
1058 int oWindDiff = operandSwap ? oppValue : windValue;
1059 if (!flipped) {
1060 windDiff = -windDiff;
1061 oWindDiff = -oWindDiff;
1062 }
caryclark55888e42016-07-18 10:01:36 -07001063 bool addToStart = windValue && (windValue > windDiff || (windValue == windDiff
1064 && oWindValue <= oWindDiff));
1065 if (addToStart ? start->done() : oStart->done()) {
1066 addToStart ^= true;
1067 }
1068 if (addToStart) {
caryclark54359292015-03-26 07:52:43 -07001069 if (operandSwap) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -04001070 using std::swap;
1071 swap(oWindValue, oOppValue);
caryclark54359292015-03-26 07:52:43 -07001072 }
1073 if (flipped) {
1074 windValue -= oWindValue;
1075 oppValue -= oOppValue;
1076 } else {
1077 windValue += oWindValue;
1078 oppValue += oOppValue;
1079 }
caryclark1049f122015-04-20 08:31:59 -07001080 if (segment->isXor()) {
caryclark54359292015-03-26 07:52:43 -07001081 windValue &= 1;
1082 }
caryclark1049f122015-04-20 08:31:59 -07001083 if (segment->oppXor()) {
caryclark54359292015-03-26 07:52:43 -07001084 oppValue &= 1;
1085 }
1086 oWindValue = oOppValue = 0;
1087 } else {
1088 if (operandSwap) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -04001089 using std::swap;
1090 swap(windValue, oppValue);
caryclark54359292015-03-26 07:52:43 -07001091 }
1092 if (flipped) {
1093 oWindValue -= windValue;
1094 oOppValue -= oppValue;
1095 } else {
1096 oWindValue += windValue;
1097 oOppValue += oppValue;
1098 }
caryclark1049f122015-04-20 08:31:59 -07001099 if (oSegment->isXor()) {
caryclark54359292015-03-26 07:52:43 -07001100 oWindValue &= 1;
1101 }
caryclark1049f122015-04-20 08:31:59 -07001102 if (oSegment->oppXor()) {
1103 oOppValue &= 1;
1104 }
caryclark54359292015-03-26 07:52:43 -07001105 windValue = oppValue = 0;
1106 }
caryclark6c3b9cd2016-09-26 05:36:58 -07001107#if 0 && DEBUG_COINCIDENCE
caryclark55888e42016-07-18 10:01:36 -07001108 SkDebugf("seg=%d span=%d windValue=%d oppValue=%d\n", segment->debugID(),
1109 start->debugID(), windValue, oppValue);
1110 SkDebugf("seg=%d span=%d windValue=%d oppValue=%d\n", oSegment->debugID(),
1111 oStart->debugID(), oWindValue, oOppValue);
1112#endif
Cary Clark0949bee2018-03-19 09:42:00 -04001113 FAIL_IF(windValue <= -1);
caryclark54359292015-03-26 07:52:43 -07001114 start->setWindValue(windValue);
1115 start->setOppValue(oppValue);
Cary Clarkb8421ed2018-03-14 15:55:02 -04001116 FAIL_IF(oWindValue <= -1);
caryclark54359292015-03-26 07:52:43 -07001117 oStart->setWindValue(oWindValue);
1118 oStart->setOppValue(oOppValue);
1119 if (!windValue && !oppValue) {
1120 segment->markDone(start);
1121 }
1122 if (!oWindValue && !oOppValue) {
1123 oSegment->markDone(oStart);
1124 }
1125 SkOpSpanBase* next = start->next();
1126 SkOpSpanBase* oNext = flipped ? oStart->prev() : oStart->next();
1127 if (next == end) {
1128 break;
1129 }
caryclark96dc1c92016-10-20 11:34:10 -07001130 FAIL_IF(!next->upCastable());
caryclark54359292015-03-26 07:52:43 -07001131 start = next->upCast();
caryclark1049f122015-04-20 08:31:59 -07001132 // if the opposite ran out too soon, just reuse the last span
1133 if (!oNext || !oNext->upCastable()) {
1134 oNext = oStart;
caryclark54359292015-03-26 07:52:43 -07001135 }
1136 oStart = oNext->upCast();
1137 } while (true);
caryclark55888e42016-07-18 10:01:36 -07001138 } while ((coin = coin->next()));
caryclarka35ab3e2016-10-20 08:32:18 -07001139 return true;
caryclark54359292015-03-26 07:52:43 -07001140}
1141
caryclark55888e42016-07-18 10:01:36 -07001142// Please keep this in sync with debugRelease()
1143bool SkOpCoincidence::release(SkCoincidentSpans* coin, SkCoincidentSpans* remove) {
1144 SkCoincidentSpans* head = coin;
halcanary96fcdcc2015-08-27 07:41:13 -07001145 SkCoincidentSpans* prev = nullptr;
caryclark54359292015-03-26 07:52:43 -07001146 SkCoincidentSpans* next;
1147 do {
caryclark55888e42016-07-18 10:01:36 -07001148 next = coin->next();
caryclark54359292015-03-26 07:52:43 -07001149 if (coin == remove) {
1150 if (prev) {
caryclark55888e42016-07-18 10:01:36 -07001151 prev->setNext(next);
1152 } else if (head == fHead) {
caryclark54359292015-03-26 07:52:43 -07001153 fHead = next;
caryclark55888e42016-07-18 10:01:36 -07001154 } else {
1155 fTop = next;
caryclark54359292015-03-26 07:52:43 -07001156 }
1157 break;
1158 }
1159 prev = coin;
1160 } while ((coin = next));
caryclark55888e42016-07-18 10:01:36 -07001161 return coin != nullptr;
caryclark54359292015-03-26 07:52:43 -07001162}
1163
caryclark30b9fdd2016-08-31 14:36:29 -07001164void SkOpCoincidence::releaseDeleted(SkCoincidentSpans* coin) {
1165 if (!coin) {
1166 return;
1167 }
1168 SkCoincidentSpans* head = coin;
1169 SkCoincidentSpans* prev = nullptr;
1170 SkCoincidentSpans* next;
1171 do {
1172 next = coin->next();
1173 if (coin->coinPtTStart()->deleted()) {
1174 SkOPASSERT(coin->flipped() ? coin->oppPtTEnd()->deleted() :
1175 coin->oppPtTStart()->deleted());
1176 if (prev) {
1177 prev->setNext(next);
1178 } else if (head == fHead) {
1179 fHead = next;
1180 } else {
1181 fTop = next;
1182 }
1183 } else {
1184 SkOPASSERT(coin->flipped() ? !coin->oppPtTEnd()->deleted() :
1185 !coin->oppPtTStart()->deleted());
1186 prev = coin;
1187 }
1188 } while ((coin = next));
1189}
1190
1191void SkOpCoincidence::releaseDeleted() {
1192 this->releaseDeleted(fHead);
1193 this->releaseDeleted(fTop);
1194}
1195
caryclark55888e42016-07-18 10:01:36 -07001196void SkOpCoincidence::restoreHead() {
1197 SkCoincidentSpans** headPtr = &fHead;
1198 while (*headPtr) {
1199 headPtr = (*headPtr)->nextPtr();
1200 }
1201 *headPtr = fTop;
1202 fTop = nullptr;
1203 // segments may have collapsed in the meantime; remove empty referenced segments
1204 headPtr = &fHead;
1205 while (*headPtr) {
1206 SkCoincidentSpans* test = *headPtr;
1207 if (test->coinPtTStart()->segment()->done() || test->oppPtTStart()->segment()->done()) {
1208 *headPtr = test->next();
1209 continue;
1210 }
1211 headPtr = (*headPtr)->nextPtr();
1212 }
1213}
1214
1215// Please keep this in sync with debugExpand()
caryclark30b9fdd2016-08-31 14:36:29 -07001216// expand the range by checking adjacent spans for coincidence
Cary Clarkab87d7a2016-10-04 10:01:04 -04001217bool SkOpCoincidence::expand(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
1218 DEBUG_SET_PHASE();
caryclark54359292015-03-26 07:52:43 -07001219 SkCoincidentSpans* coin = fHead;
1220 if (!coin) {
caryclark27c8eb82015-07-06 11:38:33 -07001221 return false;
caryclark54359292015-03-26 07:52:43 -07001222 }
caryclark27c8eb82015-07-06 11:38:33 -07001223 bool expanded = false;
caryclark54359292015-03-26 07:52:43 -07001224 do {
caryclark55888e42016-07-18 10:01:36 -07001225 if (coin->expand()) {
1226 // check to see if multiple spans expanded so they are now identical
1227 SkCoincidentSpans* test = fHead;
1228 do {
1229 if (coin == test) {
1230 continue;
1231 }
1232 if (coin->coinPtTStart() == test->coinPtTStart()
1233 && coin->oppPtTStart() == test->oppPtTStart()) {
1234 this->release(fHead, test);
1235 break;
1236 }
1237 } while ((test = test->next()));
1238 expanded = true;
caryclark54359292015-03-26 07:52:43 -07001239 }
caryclark55888e42016-07-18 10:01:36 -07001240 } while ((coin = coin->next()));
caryclark27c8eb82015-07-06 11:38:33 -07001241 return expanded;
1242}
1243
Cary Clark40f23782016-10-06 12:04:16 -04001244bool SkOpCoincidence::findOverlaps(SkOpCoincidence* overlaps DEBUG_COIN_DECLARE_PARAMS()) const {
Cary Clarkab87d7a2016-10-04 10:01:04 -04001245 DEBUG_SET_PHASE();
halcanary96fcdcc2015-08-27 07:41:13 -07001246 overlaps->fHead = overlaps->fTop = nullptr;
caryclark27c8eb82015-07-06 11:38:33 -07001247 SkCoincidentSpans* outer = fHead;
1248 while (outer) {
caryclark55888e42016-07-18 10:01:36 -07001249 const SkOpSegment* outerCoin = outer->coinPtTStart()->segment();
1250 const SkOpSegment* outerOpp = outer->oppPtTStart()->segment();
caryclark27c8eb82015-07-06 11:38:33 -07001251 SkCoincidentSpans* inner = outer;
caryclark55888e42016-07-18 10:01:36 -07001252 while ((inner = inner->next())) {
1253 const SkOpSegment* innerCoin = inner->coinPtTStart()->segment();
caryclark27c8eb82015-07-06 11:38:33 -07001254 if (outerCoin == innerCoin) {
1255 continue; // both winners are the same segment, so there's no additional overlap
1256 }
caryclark55888e42016-07-18 10:01:36 -07001257 const SkOpSegment* innerOpp = inner->oppPtTStart()->segment();
1258 const SkOpPtT* overlapS;
1259 const SkOpPtT* overlapE;
1260 if ((outerOpp == innerCoin && SkOpPtT::Overlaps(outer->oppPtTStart(),
1261 outer->oppPtTEnd(),inner->coinPtTStart(), inner->coinPtTEnd(), &overlapS,
1262 &overlapE))
1263 || (outerCoin == innerOpp && SkOpPtT::Overlaps(outer->coinPtTStart(),
1264 outer->coinPtTEnd(), inner->oppPtTStart(), inner->oppPtTEnd(),
caryclark27c8eb82015-07-06 11:38:33 -07001265 &overlapS, &overlapE))
caryclark55888e42016-07-18 10:01:36 -07001266 || (outerOpp == innerOpp && SkOpPtT::Overlaps(outer->oppPtTStart(),
1267 outer->oppPtTEnd(), inner->oppPtTStart(), inner->oppPtTEnd(),
caryclark27c8eb82015-07-06 11:38:33 -07001268 &overlapS, &overlapE))) {
Cary Clark40f23782016-10-06 12:04:16 -04001269 if (!overlaps->addOverlap(outerCoin, outerOpp, innerCoin, innerOpp,
1270 overlapS, overlapE)) {
1271 return false;
1272 }
Cary Clarke47ae292016-10-05 08:51:39 -04001273 }
caryclark27c8eb82015-07-06 11:38:33 -07001274 }
caryclark55888e42016-07-18 10:01:36 -07001275 outer = outer->next();
caryclark27c8eb82015-07-06 11:38:33 -07001276 }
Cary Clark40f23782016-10-06 12:04:16 -04001277 return true;
caryclark27c8eb82015-07-06 11:38:33 -07001278}
1279
caryclark55888e42016-07-18 10:01:36 -07001280void SkOpCoincidence::fixUp(SkOpPtT* deleted, const SkOpPtT* kept) {
caryclarkb393a492016-09-07 08:21:09 -07001281 SkOPASSERT(deleted != kept);
caryclark55888e42016-07-18 10:01:36 -07001282 if (fHead) {
1283 this->fixUp(fHead, deleted, kept);
caryclark54359292015-03-26 07:52:43 -07001284 }
caryclark55888e42016-07-18 10:01:36 -07001285 if (fTop) {
1286 this->fixUp(fTop, deleted, kept);
1287 }
caryclark54359292015-03-26 07:52:43 -07001288}
1289
caryclark55888e42016-07-18 10:01:36 -07001290void SkOpCoincidence::fixUp(SkCoincidentSpans* coin, SkOpPtT* deleted, const SkOpPtT* kept) {
1291 SkCoincidentSpans* head = coin;
1292 do {
1293 if (coin->coinPtTStart() == deleted) {
1294 if (coin->coinPtTEnd()->span() == kept->span()) {
1295 this->release(head, coin);
1296 continue;
1297 }
1298 coin->setCoinPtTStart(kept);
1299 }
1300 if (coin->coinPtTEnd() == deleted) {
1301 if (coin->coinPtTStart()->span() == kept->span()) {
1302 this->release(head, coin);
1303 continue;
1304 }
1305 coin->setCoinPtTEnd(kept);
1306 }
1307 if (coin->oppPtTStart() == deleted) {
1308 if (coin->oppPtTEnd()->span() == kept->span()) {
1309 this->release(head, coin);
1310 continue;
1311 }
1312 coin->setOppPtTStart(kept);
1313 }
1314 if (coin->oppPtTEnd() == deleted) {
1315 if (coin->oppPtTStart()->span() == kept->span()) {
1316 this->release(head, coin);
1317 continue;
1318 }
1319 coin->setOppPtTEnd(kept);
1320 }
1321 } while ((coin = coin->next()));
1322}
1323
1324// Please keep this in sync with debugMark()
caryclark27c8eb82015-07-06 11:38:33 -07001325/* this sets up the coincidence links in the segments when the coincidence crosses multiple spans */
caryclarke6522ea2016-10-17 07:54:33 -07001326bool SkOpCoincidence::mark(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
Cary Clarkab87d7a2016-10-04 10:01:04 -04001327 DEBUG_SET_PHASE();
caryclark54359292015-03-26 07:52:43 -07001328 SkCoincidentSpans* coin = fHead;
1329 if (!coin) {
caryclarke6522ea2016-10-17 07:54:33 -07001330 return true;
caryclark54359292015-03-26 07:52:43 -07001331 }
1332 do {
caryclarke6522ea2016-10-17 07:54:33 -07001333 SkOpSpanBase* startBase = coin->coinPtTStartWritable()->span();
1334 FAIL_IF(!startBase->upCastable());
1335 SkOpSpan* start = startBase->upCast();
caryclarka35ab3e2016-10-20 08:32:18 -07001336 FAIL_IF(start->deleted());
caryclark55888e42016-07-18 10:01:36 -07001337 SkOpSpanBase* end = coin->coinPtTEndWritable()->span();
Cary Clark40f23782016-10-06 12:04:16 -04001338 SkOPASSERT(!end->deleted());
caryclark55888e42016-07-18 10:01:36 -07001339 SkOpSpanBase* oStart = coin->oppPtTStartWritable()->span();
Cary Clark40f23782016-10-06 12:04:16 -04001340 SkOPASSERT(!oStart->deleted());
caryclark55888e42016-07-18 10:01:36 -07001341 SkOpSpanBase* oEnd = coin->oppPtTEndWritable()->span();
Cary Clarkf36b8a32018-03-20 16:08:35 -04001342 FAIL_IF(oEnd->deleted());
caryclark55888e42016-07-18 10:01:36 -07001343 bool flipped = coin->flipped();
caryclark54359292015-03-26 07:52:43 -07001344 if (flipped) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -04001345 using std::swap;
1346 swap(oStart, oEnd);
caryclark54359292015-03-26 07:52:43 -07001347 }
caryclark55888e42016-07-18 10:01:36 -07001348 /* coin and opp spans may not match up. Mark the ends, and then let the interior
1349 get marked as many times as the spans allow */
Cary Clark9de09762016-11-17 08:47:37 -05001350 FAIL_IF(!oStart->upCastable());
caryclark55888e42016-07-18 10:01:36 -07001351 start->insertCoincidence(oStart->upCast());
1352 end->insertCoinEnd(oEnd);
1353 const SkOpSegment* segment = start->segment();
1354 const SkOpSegment* oSegment = oStart->segment();
caryclark54359292015-03-26 07:52:43 -07001355 SkOpSpanBase* next = start;
1356 SkOpSpanBase* oNext = oStart;
caryclarka35ab3e2016-10-20 08:32:18 -07001357 bool ordered;
1358 FAIL_IF(!coin->ordered(&ordered));
caryclark55888e42016-07-18 10:01:36 -07001359 while ((next = next->upCast()->next()) != end) {
caryclarke6522ea2016-10-17 07:54:33 -07001360 FAIL_IF(!next->upCastable());
Cary Clark59ed4822016-12-08 16:17:56 -05001361 FAIL_IF(!next->upCast()->insertCoincidence(oSegment, flipped, ordered));
caryclark55888e42016-07-18 10:01:36 -07001362 }
1363 while ((oNext = oNext->upCast()->next()) != oEnd) {
caryclark96dc1c92016-10-20 11:34:10 -07001364 FAIL_IF(!oNext->upCastable());
caryclarke6522ea2016-10-17 07:54:33 -07001365 FAIL_IF(!oNext->upCast()->insertCoincidence(segment, flipped, ordered));
caryclark55888e42016-07-18 10:01:36 -07001366 }
1367 } while ((coin = coin->next()));
caryclarke6522ea2016-10-17 07:54:33 -07001368 return true;
caryclark54359292015-03-26 07:52:43 -07001369}
1370
caryclark55888e42016-07-18 10:01:36 -07001371// Please keep in sync with debugMarkCollapsed()
1372void SkOpCoincidence::markCollapsed(SkCoincidentSpans* coin, SkOpPtT* test) {
1373 SkCoincidentSpans* head = coin;
1374 while (coin) {
1375 if (coin->collapsed(test)) {
1376 if (zero_or_one(coin->coinPtTStart()->fT) && zero_or_one(coin->coinPtTEnd()->fT)) {
1377 coin->coinPtTStartWritable()->segment()->markAllDone();
1378 }
1379 if (zero_or_one(coin->oppPtTStart()->fT) && zero_or_one(coin->oppPtTEnd()->fT)) {
1380 coin->oppPtTStartWritable()->segment()->markAllDone();
1381 }
1382 this->release(head, coin);
1383 }
1384 coin = coin->next();
1385 }
1386}
1387
1388// Please keep in sync with debugMarkCollapsed()
1389void SkOpCoincidence::markCollapsed(SkOpPtT* test) {
1390 markCollapsed(fHead, test);
1391 markCollapsed(fTop, test);
1392}
1393
1394bool SkOpCoincidence::Ordered(const SkOpSegment* coinSeg, const SkOpSegment* oppSeg) {
1395 if (coinSeg->verb() < oppSeg->verb()) {
1396 return true;
1397 }
1398 if (coinSeg->verb() > oppSeg->verb()) {
1399 return false;
1400 }
1401 int count = (SkPathOpsVerbToPoints(coinSeg->verb()) + 1) * 2;
1402 const SkScalar* cPt = &coinSeg->pts()[0].fX;
1403 const SkScalar* oPt = &oppSeg->pts()[0].fX;
1404 for (int index = 0; index < count; ++index) {
1405 if (*cPt < *oPt) {
1406 return true;
1407 }
1408 if (*cPt > *oPt) {
1409 return false;
1410 }
1411 ++cPt;
1412 ++oPt;
1413 }
1414 return true;
1415}
1416
1417bool SkOpCoincidence::overlap(const SkOpPtT* coin1s, const SkOpPtT* coin1e,
caryclark54359292015-03-26 07:52:43 -07001418 const SkOpPtT* coin2s, const SkOpPtT* coin2e, double* overS, double* overE) const {
caryclark27c8eb82015-07-06 11:38:33 -07001419 SkASSERT(coin1s->segment() == coin2s->segment());
caryclark54359292015-03-26 07:52:43 -07001420 *overS = SkTMax(SkTMin(coin1s->fT, coin1e->fT), SkTMin(coin2s->fT, coin2e->fT));
1421 *overE = SkTMin(SkTMax(coin1s->fT, coin1e->fT), SkTMax(coin2s->fT, coin2e->fT));
1422 return *overS < *overE;
1423}
caryclark27c8eb82015-07-06 11:38:33 -07001424
caryclark55888e42016-07-18 10:01:36 -07001425// Commented-out lines keep this in sync with debugRelease()
1426void SkOpCoincidence::release(const SkOpSegment* deleted) {
1427 SkCoincidentSpans* coin = fHead;
1428 if (!coin) {
1429 return;
1430 }
1431 do {
1432 if (coin->coinPtTStart()->segment() == deleted
1433 || coin->coinPtTEnd()->segment() == deleted
1434 || coin->oppPtTStart()->segment() == deleted
1435 || coin->oppPtTEnd()->segment() == deleted) {
1436 this->release(fHead, coin);
1437 }
1438 } while ((coin = coin->next()));
1439}