blob: f0857c7ff4873b08600d2b282f7b2d71c2831b75 [file] [log] [blame]
caryclark54359292015-03-26 07:52:43 -07001/*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7#include "SkOpCoincidence.h"
8#include "SkOpSegment.h"
9#include "SkPathOpsTSect.h"
10
Ben Wagnerf08d1d02018-06-18 15:11:00 -040011#include <utility>
12
caryclark55888e42016-07-18 10:01:36 -070013// returns true if coincident span's start and end are the same
14bool SkCoincidentSpans::collapsed(const SkOpPtT* test) const {
15 return (fCoinPtTStart == test && fCoinPtTEnd->contains(test))
16 || (fCoinPtTEnd == test && fCoinPtTStart->contains(test))
17 || (fOppPtTStart == test && fOppPtTEnd->contains(test))
18 || (fOppPtTEnd == test && fOppPtTStart->contains(test));
19}
20
Cary Clarkdb8f44f2016-12-15 09:17:31 -050021// out of line since this function is referenced by address
22const SkOpPtT* SkCoincidentSpans::coinPtTEnd() const {
23 return fCoinPtTEnd;
24}
25
26// out of line since this function is referenced by address
27const SkOpPtT* SkCoincidentSpans::coinPtTStart() const {
28 return fCoinPtTStart;
29}
30
caryclark55888e42016-07-18 10:01:36 -070031// sets the span's end to the ptT referenced by the previous-next
32void SkCoincidentSpans::correctOneEnd(
33 const SkOpPtT* (SkCoincidentSpans::* getEnd)() const,
34 void (SkCoincidentSpans::*setEnd)(const SkOpPtT* ptT) ) {
35 const SkOpPtT* origPtT = (this->*getEnd)();
36 const SkOpSpanBase* origSpan = origPtT->span();
37 const SkOpSpan* prev = origSpan->prev();
38 const SkOpPtT* testPtT = prev ? prev->next()->ptT()
39 : origSpan->upCast()->next()->prev()->ptT();
40 if (origPtT != testPtT) {
41 (this->*setEnd)(testPtT);
caryclarkbca19f72015-05-13 08:23:48 -070042 }
caryclark55888e42016-07-18 10:01:36 -070043}
44
Cary Clarkab87d7a2016-10-04 10:01:04 -040045/* Please keep this in sync with debugCorrectEnds */
caryclark55888e42016-07-18 10:01:36 -070046// FIXME: member pointers have fallen out of favor and can be replaced with
47// an alternative approach.
48// makes all span ends agree with the segment's spans that define them
49void SkCoincidentSpans::correctEnds() {
50 this->correctOneEnd(&SkCoincidentSpans::coinPtTStart, &SkCoincidentSpans::setCoinPtTStart);
51 this->correctOneEnd(&SkCoincidentSpans::coinPtTEnd, &SkCoincidentSpans::setCoinPtTEnd);
52 this->correctOneEnd(&SkCoincidentSpans::oppPtTStart, &SkCoincidentSpans::setOppPtTStart);
53 this->correctOneEnd(&SkCoincidentSpans::oppPtTEnd, &SkCoincidentSpans::setOppPtTEnd);
54}
55
56/* Please keep this in sync with debugExpand */
57// expand the range by checking adjacent spans for coincidence
58bool SkCoincidentSpans::expand() {
59 bool expanded = false;
60 const SkOpSegment* segment = coinPtTStart()->segment();
61 const SkOpSegment* oppSegment = oppPtTStart()->segment();
62 do {
63 const SkOpSpan* start = coinPtTStart()->span()->upCast();
64 const SkOpSpan* prev = start->prev();
65 const SkOpPtT* oppPtT;
66 if (!prev || !(oppPtT = prev->contains(oppSegment))) {
67 break;
68 }
69 double midT = (prev->t() + start->t()) / 2;
70 if (!segment->isClose(midT, oppSegment)) {
71 break;
72 }
73 setStarts(prev->ptT(), oppPtT);
74 expanded = true;
75 } while (true);
76 do {
77 const SkOpSpanBase* end = coinPtTEnd()->span();
78 SkOpSpanBase* next = end->final() ? nullptr : end->upCast()->next();
caryclarkc6d855f2016-08-11 11:59:48 -070079 if (next && next->deleted()) {
80 break;
81 }
caryclark55888e42016-07-18 10:01:36 -070082 const SkOpPtT* oppPtT;
83 if (!next || !(oppPtT = next->contains(oppSegment))) {
84 break;
85 }
86 double midT = (end->t() + next->t()) / 2;
87 if (!segment->isClose(midT, oppSegment)) {
88 break;
89 }
90 setEnds(next->ptT(), oppPtT);
91 expanded = true;
92 } while (true);
93 return expanded;
94}
95
96// increase the range of this span
97bool SkCoincidentSpans::extend(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd,
98 const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) {
99 bool result = false;
100 if (fCoinPtTStart->fT > coinPtTStart->fT || (this->flipped()
101 ? fOppPtTStart->fT < oppPtTStart->fT : fOppPtTStart->fT > oppPtTStart->fT)) {
102 this->setStarts(coinPtTStart, oppPtTStart);
103 result = true;
104 }
105 if (fCoinPtTEnd->fT < coinPtTEnd->fT || (this->flipped()
106 ? fOppPtTEnd->fT > oppPtTEnd->fT : fOppPtTEnd->fT < oppPtTEnd->fT)) {
107 this->setEnds(coinPtTEnd, oppPtTEnd);
108 result = true;
109 }
110 return result;
111}
112
113// set the range of this span
114void SkCoincidentSpans::set(SkCoincidentSpans* next, const SkOpPtT* coinPtTStart,
Cary Clarkab87d7a2016-10-04 10:01:04 -0400115 const SkOpPtT* coinPtTEnd, const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) {
caryclark55888e42016-07-18 10:01:36 -0700116 SkASSERT(SkOpCoincidence::Ordered(coinPtTStart, oppPtTStart));
117 fNext = next;
118 this->setStarts(coinPtTStart, oppPtTStart);
119 this->setEnds(coinPtTEnd, oppPtTEnd);
caryclark55888e42016-07-18 10:01:36 -0700120}
121
122// returns true if both points are inside this
123bool SkCoincidentSpans::contains(const SkOpPtT* s, const SkOpPtT* e) const {
124 if (s->fT > e->fT) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400125 using std::swap;
126 swap(s, e);
caryclark55888e42016-07-18 10:01:36 -0700127 }
128 if (s->segment() == fCoinPtTStart->segment()) {
129 return fCoinPtTStart->fT <= s->fT && e->fT <= fCoinPtTEnd->fT;
130 } else {
131 SkASSERT(s->segment() == fOppPtTStart->segment());
132 double oppTs = fOppPtTStart->fT;
133 double oppTe = fOppPtTEnd->fT;
134 if (oppTs > oppTe) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400135 using std::swap;
136 swap(oppTs, oppTe);
caryclark55888e42016-07-18 10:01:36 -0700137 }
138 return oppTs <= s->fT && e->fT <= oppTe;
139 }
140}
141
Cary Clarkdb8f44f2016-12-15 09:17:31 -0500142// out of line since this function is referenced by address
143const SkOpPtT* SkCoincidentSpans::oppPtTStart() const {
144 return fOppPtTStart;
145}
146
147// out of line since this function is referenced by address
148const SkOpPtT* SkCoincidentSpans::oppPtTEnd() const {
149 return fOppPtTEnd;
150}
151
caryclark81a478c2016-09-09 09:37:57 -0700152// A coincident span is unordered if the pairs of points in the main and opposite curves'
153// t values do not ascend or descend. For instance, if a tightly arced quadratic is
154// coincident with another curve, it may intersect it out of order.
caryclarka35ab3e2016-10-20 08:32:18 -0700155bool SkCoincidentSpans::ordered(bool* result) const {
caryclark81a478c2016-09-09 09:37:57 -0700156 const SkOpSpanBase* start = this->coinPtTStart()->span();
157 const SkOpSpanBase* end = this->coinPtTEnd()->span();
158 const SkOpSpanBase* next = start->upCast()->next();
159 if (next == end) {
caryclarka35ab3e2016-10-20 08:32:18 -0700160 *result = true;
caryclark81a478c2016-09-09 09:37:57 -0700161 return true;
162 }
163 bool flipped = this->flipped();
164 const SkOpSegment* oppSeg = this->oppPtTStart()->segment();
165 double oppLastT = fOppPtTStart->fT;
166 do {
167 const SkOpPtT* opp = next->contains(oppSeg);
168 if (!opp) {
Cary Clarkab2d73b2016-12-16 17:17:25 -0500169// SkOPOBJASSERT(start, 0); // may assert if coincident span isn't fully processed
caryclarka35ab3e2016-10-20 08:32:18 -0700170 return false;
caryclark81a478c2016-09-09 09:37:57 -0700171 }
172 if ((oppLastT > opp->fT) != flipped) {
caryclarka35ab3e2016-10-20 08:32:18 -0700173 *result = false;
174 return true;
caryclark81a478c2016-09-09 09:37:57 -0700175 }
176 oppLastT = opp->fT;
177 if (next == end) {
178 break;
179 }
caryclarkbbfe92b2016-09-19 06:00:35 -0700180 if (!next->upCastable()) {
caryclarka35ab3e2016-10-20 08:32:18 -0700181 *result = false;
182 return true;
caryclarkbbfe92b2016-09-19 06:00:35 -0700183 }
caryclark81a478c2016-09-09 09:37:57 -0700184 next = next->upCast()->next();
185 } while (true);
caryclarka35ab3e2016-10-20 08:32:18 -0700186 *result = true;
caryclark81a478c2016-09-09 09:37:57 -0700187 return true;
188}
189
caryclark55888e42016-07-18 10:01:36 -0700190// if there is an existing pair that overlaps the addition, extend it
191bool SkOpCoincidence::extend(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd,
192 const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) {
193 SkCoincidentSpans* test = fHead;
194 if (!test) {
195 return false;
196 }
197 const SkOpSegment* coinSeg = coinPtTStart->segment();
198 const SkOpSegment* oppSeg = oppPtTStart->segment();
199 if (!Ordered(coinPtTStart, oppPtTStart)) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400200 using std::swap;
201 swap(coinSeg, oppSeg);
202 swap(coinPtTStart, oppPtTStart);
203 swap(coinPtTEnd, oppPtTEnd);
caryclark55888e42016-07-18 10:01:36 -0700204 if (coinPtTStart->fT > coinPtTEnd->fT) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400205 swap(coinPtTStart, coinPtTEnd);
206 swap(oppPtTStart, oppPtTEnd);
caryclark55888e42016-07-18 10:01:36 -0700207 }
208 }
209 double oppMinT = SkTMin(oppPtTStart->fT, oppPtTEnd->fT);
210 SkDEBUGCODE(double oppMaxT = SkTMax(oppPtTStart->fT, oppPtTEnd->fT));
211 do {
212 if (coinSeg != test->coinPtTStart()->segment()) {
213 continue;
214 }
215 if (oppSeg != test->oppPtTStart()->segment()) {
216 continue;
217 }
218 double oTestMinT = SkTMin(test->oppPtTStart()->fT, test->oppPtTEnd()->fT);
219 double oTestMaxT = SkTMax(test->oppPtTStart()->fT, test->oppPtTEnd()->fT);
220 // if debug check triggers, caller failed to check if extended already exists
221 SkASSERT(test->coinPtTStart()->fT > coinPtTStart->fT
222 || coinPtTEnd->fT > test->coinPtTEnd()->fT
223 || oTestMinT > oppMinT || oppMaxT > oTestMaxT);
224 if ((test->coinPtTStart()->fT <= coinPtTEnd->fT
225 && coinPtTStart->fT <= test->coinPtTEnd()->fT)
226 || (oTestMinT <= oTestMaxT && oppMinT <= oTestMaxT)) {
227 test->extend(coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd);
228 return true;
229 }
230 } while ((test = test->next()));
231 return false;
caryclark54359292015-03-26 07:52:43 -0700232}
233
caryclark55888e42016-07-18 10:01:36 -0700234// verifies that the coincidence hasn't already been added
235static void DebugCheckAdd(const SkCoincidentSpans* check, const SkOpPtT* coinPtTStart,
236 const SkOpPtT* coinPtTEnd, const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) {
237#if DEBUG_COINCIDENCE
238 while (check) {
239 SkASSERT(check->coinPtTStart() != coinPtTStart || check->coinPtTEnd() != coinPtTEnd
240 || check->oppPtTStart() != oppPtTStart || check->oppPtTEnd() != oppPtTEnd);
241 SkASSERT(check->coinPtTStart() != oppPtTStart || check->coinPtTEnd() != oppPtTEnd
242 || check->oppPtTStart() != coinPtTStart || check->oppPtTEnd() != coinPtTEnd);
243 check = check->next();
244 }
245#endif
246}
247
248// adds a new coincident pair
249void SkOpCoincidence::add(SkOpPtT* coinPtTStart, SkOpPtT* coinPtTEnd, SkOpPtT* oppPtTStart,
250 SkOpPtT* oppPtTEnd) {
251 // OPTIMIZE: caller should have already sorted
252 if (!Ordered(coinPtTStart, oppPtTStart)) {
253 if (oppPtTStart->fT < oppPtTEnd->fT) {
254 this->add(oppPtTStart, oppPtTEnd, coinPtTStart, coinPtTEnd);
255 } else {
256 this->add(oppPtTEnd, oppPtTStart, coinPtTEnd, coinPtTStart);
257 }
258 return;
259 }
260 SkASSERT(Ordered(coinPtTStart, oppPtTStart));
261 // choose the ptT at the front of the list to track
262 coinPtTStart = coinPtTStart->span()->ptT();
263 coinPtTEnd = coinPtTEnd->span()->ptT();
264 oppPtTStart = oppPtTStart->span()->ptT();
265 oppPtTEnd = oppPtTEnd->span()->ptT();
caryclarka35ab3e2016-10-20 08:32:18 -0700266 SkOPASSERT(coinPtTStart->fT < coinPtTEnd->fT);
caryclark96dc1c92016-10-20 11:34:10 -0700267 SkOPASSERT(oppPtTStart->fT != oppPtTEnd->fT);
caryclark30b9fdd2016-08-31 14:36:29 -0700268 SkOPASSERT(!coinPtTStart->deleted());
269 SkOPASSERT(!coinPtTEnd->deleted());
270 SkOPASSERT(!oppPtTStart->deleted());
271 SkOPASSERT(!oppPtTEnd->deleted());
caryclark55888e42016-07-18 10:01:36 -0700272 DebugCheckAdd(fHead, coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd);
273 DebugCheckAdd(fTop, coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd);
Herb Derbyecc364c2017-04-19 15:09:48 -0400274 SkCoincidentSpans* coinRec = this->globalState()->allocator()->make<SkCoincidentSpans>();
caryclarkfc560e02016-07-27 08:46:10 -0700275 coinRec->init(SkDEBUGCODE(fGlobalState));
Cary Clarkab87d7a2016-10-04 10:01:04 -0400276 coinRec->set(this->fHead, coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd);
caryclark55888e42016-07-18 10:01:36 -0700277 fHead = coinRec;
278}
279
280// description below
caryclark15976282016-07-21 05:48:43 -0700281bool SkOpCoincidence::addEndMovedSpans(const SkOpSpan* base, const SkOpSpanBase* testSpan) {
caryclark55888e42016-07-18 10:01:36 -0700282 const SkOpPtT* testPtT = testSpan->ptT();
283 const SkOpPtT* stopPtT = testPtT;
284 const SkOpSegment* baseSeg = base->segment();
Cary Clark4eed4c82017-03-08 17:11:12 -0500285 int escapeHatch = 100000; // this is 100 times larger than the debugLoopLimit test
caryclark55888e42016-07-18 10:01:36 -0700286 while ((testPtT = testPtT->next()) != stopPtT) {
Cary Clark4eed4c82017-03-08 17:11:12 -0500287 if (--escapeHatch <= 0) {
288 return false; // if triggered (likely by a fuzz-generated test) too complex to succeed
289 }
caryclark55888e42016-07-18 10:01:36 -0700290 const SkOpSegment* testSeg = testPtT->segment();
291 if (testPtT->deleted()) {
292 continue;
293 }
294 if (testSeg == baseSeg) {
295 continue;
296 }
caryclarkc6d855f2016-08-11 11:59:48 -0700297 if (testPtT->span()->ptT() != testPtT) {
298 continue;
299 }
caryclark55888e42016-07-18 10:01:36 -0700300 if (this->contains(baseSeg, testSeg, testPtT->fT)) {
301 continue;
302 }
303 // intersect perp with base->ptT() with testPtT->segment()
304 SkDVector dxdy = baseSeg->dSlopeAtT(base->t());
305 const SkPoint& pt = base->pt();
306 SkDLine ray = {{{pt.fX, pt.fY}, {pt.fX + dxdy.fY, pt.fY - dxdy.fX}}};
Cary Clark4c76c412017-01-20 08:14:33 -0500307 SkIntersections i SkDEBUGCODE((this->globalState()));
caryclark55888e42016-07-18 10:01:36 -0700308 (*CurveIntersectRay[testSeg->verb()])(testSeg->pts(), testSeg->weight(), ray, &i);
309 for (int index = 0; index < i.used(); ++index) {
310 double t = i[0][index];
311 if (!between(0, t, 1)) {
312 continue;
313 }
314 SkDPoint oppPt = i.pt(index);
315 if (!oppPt.approximatelyEqual(pt)) {
316 continue;
317 }
318 SkOpSegment* writableSeg = const_cast<SkOpSegment*>(testSeg);
caryclark29b25632016-08-25 11:27:17 -0700319 SkOpPtT* oppStart = writableSeg->addT(t);
caryclark27c015d2016-09-23 05:47:20 -0700320 if (oppStart == testPtT) {
321 continue;
322 }
caryclark55888e42016-07-18 10:01:36 -0700323 SkOpSpan* writableBase = const_cast<SkOpSpan*>(base);
caryclark30b9fdd2016-08-31 14:36:29 -0700324 oppStart->span()->addOpp(writableBase);
caryclark55888e42016-07-18 10:01:36 -0700325 if (oppStart->deleted()) {
326 continue;
327 }
328 SkOpSegment* coinSeg = base->segment();
329 SkOpSegment* oppSeg = oppStart->segment();
330 double coinTs, coinTe, oppTs, oppTe;
caryclark8016b262016-09-06 05:59:47 -0700331 if (Ordered(coinSeg, oppSeg)) {
caryclark55888e42016-07-18 10:01:36 -0700332 coinTs = base->t();
333 coinTe = testSpan->t();
334 oppTs = oppStart->fT;
335 oppTe = testPtT->fT;
336 } else {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400337 using std::swap;
338 swap(coinSeg, oppSeg);
caryclark55888e42016-07-18 10:01:36 -0700339 coinTs = oppStart->fT;
340 coinTe = testPtT->fT;
341 oppTs = base->t();
342 oppTe = testSpan->t();
343 }
344 if (coinTs > coinTe) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400345 using std::swap;
346 swap(coinTs, coinTe);
347 swap(oppTs, oppTe);
caryclark55888e42016-07-18 10:01:36 -0700348 }
caryclark81a478c2016-09-09 09:37:57 -0700349 bool added;
350 if (!this->addOrOverlap(coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, &added)) {
caryclark15976282016-07-21 05:48:43 -0700351 return false;
352 }
caryclark55888e42016-07-18 10:01:36 -0700353 }
354 }
caryclark15976282016-07-21 05:48:43 -0700355 return true;
caryclark55888e42016-07-18 10:01:36 -0700356}
357
358// description below
359bool SkOpCoincidence::addEndMovedSpans(const SkOpPtT* ptT) {
caryclark025b11e2016-08-25 05:21:14 -0700360 FAIL_IF(!ptT->span()->upCastable());
caryclark55888e42016-07-18 10:01:36 -0700361 const SkOpSpan* base = ptT->span()->upCast();
362 const SkOpSpan* prev = base->prev();
caryclark025b11e2016-08-25 05:21:14 -0700363 FAIL_IF(!prev);
caryclark55888e42016-07-18 10:01:36 -0700364 if (!prev->isCanceled()) {
caryclark15976282016-07-21 05:48:43 -0700365 if (!this->addEndMovedSpans(base, base->prev())) {
366 return false;
367 }
caryclark55888e42016-07-18 10:01:36 -0700368 }
369 if (!base->isCanceled()) {
caryclark15976282016-07-21 05:48:43 -0700370 if (!this->addEndMovedSpans(base, base->next())) {
371 return false;
372 }
caryclark55888e42016-07-18 10:01:36 -0700373 }
374 return true;
375}
376
377/* If A is coincident with B and B includes an endpoint, and A's matching point
378 is not the endpoint (i.e., there's an implied line connecting B-end and A)
379 then assume that the same implied line may intersect another curve close to B.
380 Since we only care about coincidence that was undetected, look at the
381 ptT list on B-segment adjacent to the B-end/A ptT loop (not in the loop, but
382 next door) and see if the A matching point is close enough to form another
383 coincident pair. If so, check for a new coincident span between B-end/A ptT loop
384 and the adjacent ptT loop.
385*/
Cary Clarkab87d7a2016-10-04 10:01:04 -0400386bool SkOpCoincidence::addEndMovedSpans(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
387 DEBUG_SET_PHASE();
caryclark55888e42016-07-18 10:01:36 -0700388 SkCoincidentSpans* span = fHead;
389 if (!span) {
390 return true;
391 }
392 fTop = span;
393 fHead = nullptr;
394 do {
395 if (span->coinPtTStart()->fPt != span->oppPtTStart()->fPt) {
caryclark025b11e2016-08-25 05:21:14 -0700396 FAIL_IF(1 == span->coinPtTStart()->fT);
caryclark55888e42016-07-18 10:01:36 -0700397 bool onEnd = span->coinPtTStart()->fT == 0;
398 bool oOnEnd = zero_or_one(span->oppPtTStart()->fT);
399 if (onEnd) {
400 if (!oOnEnd) { // if both are on end, any nearby intersect was already found
401 if (!this->addEndMovedSpans(span->oppPtTStart())) {
402 return false;
403 }
404 }
405 } else if (oOnEnd) {
406 if (!this->addEndMovedSpans(span->coinPtTStart())) {
407 return false;
408 }
409 }
410 }
411 if (span->coinPtTEnd()->fPt != span->oppPtTEnd()->fPt) {
412 bool onEnd = span->coinPtTEnd()->fT == 1;
413 bool oOnEnd = zero_or_one(span->oppPtTEnd()->fT);
414 if (onEnd) {
415 if (!oOnEnd) {
416 if (!this->addEndMovedSpans(span->oppPtTEnd())) {
417 return false;
418 }
419 }
420 } else if (oOnEnd) {
421 if (!this->addEndMovedSpans(span->coinPtTEnd())) {
422 return false;
423 }
424 }
425 }
426 } while ((span = span->next()));
427 this->restoreHead();
428 return true;
429}
430
431/* Please keep this in sync with debugAddExpanded */
432// for each coincident pair, match the spans
433// if the spans don't match, add the missing pt to the segment and loop it in the opposite span
Cary Clarkab87d7a2016-10-04 10:01:04 -0400434bool SkOpCoincidence::addExpanded(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
435 DEBUG_SET_PHASE();
caryclark55888e42016-07-18 10:01:36 -0700436 SkCoincidentSpans* coin = this->fHead;
437 if (!coin) {
438 return true;
439 }
440 do {
441 const SkOpPtT* startPtT = coin->coinPtTStart();
442 const SkOpPtT* oStartPtT = coin->oppPtTStart();
caryclark8016b262016-09-06 05:59:47 -0700443 double priorT = startPtT->fT;
444 double oPriorT = oStartPtT->fT;
caryclarkbbfe92b2016-09-19 06:00:35 -0700445 FAIL_IF(!startPtT->contains(oStartPtT));
caryclarkc6d855f2016-08-11 11:59:48 -0700446 SkOPASSERT(coin->coinPtTEnd()->contains(coin->oppPtTEnd()));
caryclark55888e42016-07-18 10:01:36 -0700447 const SkOpSpanBase* start = startPtT->span();
448 const SkOpSpanBase* oStart = oStartPtT->span();
449 const SkOpSpanBase* end = coin->coinPtTEnd()->span();
450 const SkOpSpanBase* oEnd = coin->oppPtTEnd()->span();
451 FAIL_IF(oEnd->deleted());
caryclarke25a4f62016-07-26 09:26:29 -0700452 FAIL_IF(!start->upCastable());
caryclark55888e42016-07-18 10:01:36 -0700453 const SkOpSpanBase* test = start->upCast()->next();
caryclarke7bb5b22016-09-22 05:20:07 -0700454 FAIL_IF(!coin->flipped() && !oStart->upCastable());
caryclark55888e42016-07-18 10:01:36 -0700455 const SkOpSpanBase* oTest = coin->flipped() ? oStart->prev() : oStart->upCast()->next();
caryclark30b9fdd2016-08-31 14:36:29 -0700456 FAIL_IF(!oTest);
caryclark8016b262016-09-06 05:59:47 -0700457 SkOpSegment* seg = start->segment();
458 SkOpSegment* oSeg = oStart->segment();
caryclark55888e42016-07-18 10:01:36 -0700459 while (test != end || oTest != oEnd) {
caryclark8016b262016-09-06 05:59:47 -0700460 const SkOpPtT* containedOpp = test->ptT()->contains(oSeg);
461 const SkOpPtT* containedThis = oTest->ptT()->contains(seg);
462 if (!containedOpp || !containedThis) {
463 // choose the ends, or the first common pt-t list shared by both
464 double nextT, oNextT;
465 if (containedOpp) {
466 nextT = test->t();
467 oNextT = containedOpp->fT;
468 } else if (containedThis) {
469 nextT = containedThis->fT;
470 oNextT = oTest->t();
471 } else {
472 // iterate through until a pt-t list found that contains the other
473 const SkOpSpanBase* walk = test;
474 const SkOpPtT* walkOpp;
475 do {
476 FAIL_IF(!walk->upCastable());
477 walk = walk->upCast()->next();
478 } while (!(walkOpp = walk->ptT()->contains(oSeg))
479 && walk != coin->coinPtTEnd()->span());
Cary Clark3fdf52c2016-10-04 10:53:31 -0400480 FAIL_IF(!walkOpp);
caryclark8016b262016-09-06 05:59:47 -0700481 nextT = walk->t();
482 oNextT = walkOpp->fT;
483 }
caryclark55888e42016-07-18 10:01:36 -0700484 // use t ranges to guess which one is missing
caryclark8016b262016-09-06 05:59:47 -0700485 double startRange = nextT - priorT;
caryclark55888e42016-07-18 10:01:36 -0700486 FAIL_IF(!startRange);
caryclark8016b262016-09-06 05:59:47 -0700487 double startPart = (test->t() - priorT) / startRange;
488 double oStartRange = oNextT - oPriorT;
caryclark55888e42016-07-18 10:01:36 -0700489 FAIL_IF(!oStartRange);
caryclark8016b262016-09-06 05:59:47 -0700490 double oStartPart = (oTest->t() - oPriorT) / oStartRange;
caryclark55888e42016-07-18 10:01:36 -0700491 FAIL_IF(startPart == oStartPart);
caryclark8016b262016-09-06 05:59:47 -0700492 bool addToOpp = !containedOpp && !containedThis ? startPart < oStartPart
493 : !!containedThis;
caryclark55888e42016-07-18 10:01:36 -0700494 bool startOver = false;
caryclark8016b262016-09-06 05:59:47 -0700495 bool success = addToOpp ? oSeg->addExpanded(
496 oPriorT + oStartRange * startPart, test, &startOver)
497 : seg->addExpanded(
498 priorT + startRange * oStartPart, oTest, &startOver);
caryclark30b9fdd2016-08-31 14:36:29 -0700499 FAIL_IF(!success);
caryclark55888e42016-07-18 10:01:36 -0700500 if (startOver) {
501 test = start;
502 oTest = oStart;
503 }
caryclark30b9fdd2016-08-31 14:36:29 -0700504 end = coin->coinPtTEnd()->span();
505 oEnd = coin->oppPtTEnd()->span();
caryclark55888e42016-07-18 10:01:36 -0700506 }
507 if (test != end) {
caryclark30b9fdd2016-08-31 14:36:29 -0700508 FAIL_IF(!test->upCastable());
caryclark8016b262016-09-06 05:59:47 -0700509 priorT = test->t();
caryclark55888e42016-07-18 10:01:36 -0700510 test = test->upCast()->next();
511 }
512 if (oTest != oEnd) {
caryclark8016b262016-09-06 05:59:47 -0700513 oPriorT = oTest->t();
caryclark78a37a52016-10-20 12:36:16 -0700514 if (coin->flipped()) {
515 oTest = oTest->prev();
516 } else {
517 FAIL_IF(!oTest->upCastable());
518 oTest = oTest->upCast()->next();
519 }
caryclark30b9fdd2016-08-31 14:36:29 -0700520 FAIL_IF(!oTest);
caryclark55888e42016-07-18 10:01:36 -0700521 }
caryclark8016b262016-09-06 05:59:47 -0700522
caryclark55888e42016-07-18 10:01:36 -0700523 }
524 } while ((coin = coin->next()));
525 return true;
526}
527
caryclark55888e42016-07-18 10:01:36 -0700528// given a t span, map the same range on the coincident span
caryclark8016b262016-09-06 05:59:47 -0700529/*
530the curves may not scale linearly, so interpolation may only happen within known points
531remap over1s, over1e, cointPtTStart, coinPtTEnd to smallest range that captures over1s
532then repeat to capture over1e
533*/
534double SkOpCoincidence::TRange(const SkOpPtT* overS, double t,
535 const SkOpSegment* coinSeg SkDEBUGPARAMS(const SkOpPtT* overE)) {
536 const SkOpSpanBase* work = overS->span();
537 const SkOpPtT* foundStart = nullptr;
538 const SkOpPtT* foundEnd = nullptr;
539 const SkOpPtT* coinStart = nullptr;
540 const SkOpPtT* coinEnd = nullptr;
541 do {
542 const SkOpPtT* contained = work->contains(coinSeg);
543 if (!contained) {
caryclarkc9b90d12016-09-09 07:41:36 -0700544 if (work->final()) {
545 break;
caryclarkb393a492016-09-07 08:21:09 -0700546 }
caryclark8016b262016-09-06 05:59:47 -0700547 continue;
548 }
549 if (work->t() <= t) {
550 coinStart = contained;
551 foundStart = work->ptT();
552 }
553 if (work->t() >= t) {
554 coinEnd = contained;
555 foundEnd = work->ptT();
556 break;
557 }
558 SkASSERT(work->ptT() != overE);
559 } while ((work = work->upCast()->next()));
caryclarkc9b90d12016-09-09 07:41:36 -0700560 if (!coinStart || !coinEnd) {
561 return 1;
562 }
caryclark8016b262016-09-06 05:59:47 -0700563 // while overS->fT <=t and overS contains coinSeg
564 double denom = foundEnd->fT - foundStart->fT;
565 double sRatio = denom ? (t - foundStart->fT) / denom : 1;
566 return coinStart->fT + (coinEnd->fT - coinStart->fT) * sRatio;
caryclark54359292015-03-26 07:52:43 -0700567}
568
caryclark55888e42016-07-18 10:01:36 -0700569// return true if span overlaps existing and needs to adjust the coincident list
570bool SkOpCoincidence::checkOverlap(SkCoincidentSpans* check,
571 const SkOpSegment* coinSeg, const SkOpSegment* oppSeg,
572 double coinTs, double coinTe, double oppTs, double oppTe,
573 SkTDArray<SkCoincidentSpans*>* overlaps) const {
574 if (!Ordered(coinSeg, oppSeg)) {
575 if (oppTs < oppTe) {
576 return this->checkOverlap(check, oppSeg, coinSeg, oppTs, oppTe, coinTs, coinTe,
577 overlaps);
578 }
579 return this->checkOverlap(check, oppSeg, coinSeg, oppTe, oppTs, coinTe, coinTs, overlaps);
580 }
581 bool swapOpp = oppTs > oppTe;
582 if (swapOpp) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400583 using std::swap;
584 swap(oppTs, oppTe);
caryclark55888e42016-07-18 10:01:36 -0700585 }
caryclark27c8eb82015-07-06 11:38:33 -0700586 do {
caryclark55888e42016-07-18 10:01:36 -0700587 if (check->coinPtTStart()->segment() != coinSeg) {
588 continue;
caryclark1c9ce612015-11-20 14:06:28 -0800589 }
caryclark55888e42016-07-18 10:01:36 -0700590 if (check->oppPtTStart()->segment() != oppSeg) {
591 continue;
caryclarkdae6b972016-06-08 04:28:19 -0700592 }
caryclark55888e42016-07-18 10:01:36 -0700593 double checkTs = check->coinPtTStart()->fT;
594 double checkTe = check->coinPtTEnd()->fT;
595 bool coinOutside = coinTe < checkTs || coinTs > checkTe;
596 double oCheckTs = check->oppPtTStart()->fT;
597 double oCheckTe = check->oppPtTEnd()->fT;
598 if (swapOpp) {
599 if (oCheckTs <= oCheckTe) {
caryclark81a478c2016-09-09 09:37:57 -0700600 return false;
caryclark27c8eb82015-07-06 11:38:33 -0700601 }
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400602 using std::swap;
603 swap(oCheckTs, oCheckTe);
caryclark27c8eb82015-07-06 11:38:33 -0700604 }
caryclark55888e42016-07-18 10:01:36 -0700605 bool oppOutside = oppTe < oCheckTs || oppTs > oCheckTe;
606 if (coinOutside && oppOutside) {
607 continue;
608 }
609 bool coinInside = coinTe <= checkTe && coinTs >= checkTs;
610 bool oppInside = oppTe <= oCheckTe && oppTs >= oCheckTs;
caryclark81a478c2016-09-09 09:37:57 -0700611 if (coinInside && oppInside) { // already included, do nothing
612 return false;
caryclark55888e42016-07-18 10:01:36 -0700613 }
614 *overlaps->append() = check; // partial overlap, extend existing entry
615 } while ((check = check->next()));
caryclark26ad22a2015-10-16 09:03:38 -0700616 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700617}
618
caryclark55888e42016-07-18 10:01:36 -0700619/* Please keep this in sync with debugAddIfMissing() */
caryclark8016b262016-09-06 05:59:47 -0700620// note that over1s, over1e, over2s, over2e are ordered
621bool SkOpCoincidence::addIfMissing(const SkOpPtT* over1s, const SkOpPtT* over2s,
Herb Derbyecc364c2017-04-19 15:09:48 -0400622 double tStart, double tEnd, SkOpSegment* coinSeg, SkOpSegment* oppSeg, bool* added
caryclark8016b262016-09-06 05:59:47 -0700623 SkDEBUGPARAMS(const SkOpPtT* over1e) SkDEBUGPARAMS(const SkOpPtT* over2e)) {
624 SkASSERT(tStart < tEnd);
625 SkASSERT(over1s->fT < over1e->fT);
626 SkASSERT(between(over1s->fT, tStart, over1e->fT));
627 SkASSERT(between(over1s->fT, tEnd, over1e->fT));
628 SkASSERT(over2s->fT < over2e->fT);
629 SkASSERT(between(over2s->fT, tStart, over2e->fT));
630 SkASSERT(between(over2s->fT, tEnd, over2e->fT));
631 SkASSERT(over1s->segment() == over1e->segment());
632 SkASSERT(over2s->segment() == over2e->segment());
633 SkASSERT(over1s->segment() == over2s->segment());
634 SkASSERT(over1s->segment() != coinSeg);
635 SkASSERT(over1s->segment() != oppSeg);
636 SkASSERT(coinSeg != oppSeg);
caryclark54359292015-03-26 07:52:43 -0700637 double coinTs, coinTe, oppTs, oppTe;
caryclark8016b262016-09-06 05:59:47 -0700638 coinTs = TRange(over1s, tStart, coinSeg SkDEBUGPARAMS(over1e));
639 coinTe = TRange(over1s, tEnd, coinSeg SkDEBUGPARAMS(over1e));
Cary Clarkba610292018-06-19 09:47:15 -0400640 SkOpSpanBase::Collapsed result = coinSeg->collapsed(coinTs, coinTe);
641 if (SkOpSpanBase::Collapsed::kNo != result) {
642 return SkOpSpanBase::Collapsed::kYes == result;
caryclark30b9fdd2016-08-31 14:36:29 -0700643 }
caryclark8016b262016-09-06 05:59:47 -0700644 oppTs = TRange(over2s, tStart, oppSeg SkDEBUGPARAMS(over2e));
645 oppTe = TRange(over2s, tEnd, oppSeg SkDEBUGPARAMS(over2e));
Cary Clarkba610292018-06-19 09:47:15 -0400646 result = oppSeg->collapsed(oppTs, oppTe);
647 if (SkOpSpanBase::Collapsed::kNo != result) {
648 return SkOpSpanBase::Collapsed::kYes == result;
caryclark30b9fdd2016-08-31 14:36:29 -0700649 }
caryclark8016b262016-09-06 05:59:47 -0700650 if (coinTs > coinTe) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400651 using std::swap;
652 swap(coinTs, coinTe);
653 swap(oppTs, oppTe);
caryclark54359292015-03-26 07:52:43 -0700654 }
Cary Clarkba610292018-06-19 09:47:15 -0400655 (void) this->addOrOverlap(coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, added);
656 return true;
caryclark54359292015-03-26 07:52:43 -0700657}
658
caryclark55888e42016-07-18 10:01:36 -0700659/* Please keep this in sync with debugAddOrOverlap() */
caryclark025b11e2016-08-25 05:21:14 -0700660// If this is called by addEndMovedSpans(), a returned false propogates out to an abort.
661// If this is called by AddIfMissing(), a returned false indicates there was nothing to add
caryclark55888e42016-07-18 10:01:36 -0700662bool SkOpCoincidence::addOrOverlap(SkOpSegment* coinSeg, SkOpSegment* oppSeg,
caryclark81a478c2016-09-09 09:37:57 -0700663 double coinTs, double coinTe, double oppTs, double oppTe, bool* added) {
caryclark55888e42016-07-18 10:01:36 -0700664 SkTDArray<SkCoincidentSpans*> overlaps;
caryclark81a478c2016-09-09 09:37:57 -0700665 FAIL_IF(!fTop);
caryclark55888e42016-07-18 10:01:36 -0700666 if (!this->checkOverlap(fTop, coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, &overlaps)) {
caryclark81a478c2016-09-09 09:37:57 -0700667 return true;
caryclark55888e42016-07-18 10:01:36 -0700668 }
669 if (fHead && !this->checkOverlap(fHead, coinSeg, oppSeg, coinTs,
670 coinTe, oppTs, oppTe, &overlaps)) {
caryclark81a478c2016-09-09 09:37:57 -0700671 return true;
caryclark55888e42016-07-18 10:01:36 -0700672 }
673 SkCoincidentSpans* overlap = overlaps.count() ? overlaps[0] : nullptr;
674 for (int index = 1; index < overlaps.count(); ++index) { // combine overlaps before continuing
675 SkCoincidentSpans* test = overlaps[index];
676 if (overlap->coinPtTStart()->fT > test->coinPtTStart()->fT) {
677 overlap->setCoinPtTStart(test->coinPtTStart());
678 }
679 if (overlap->coinPtTEnd()->fT < test->coinPtTEnd()->fT) {
680 overlap->setCoinPtTEnd(test->coinPtTEnd());
681 }
682 if (overlap->flipped()
683 ? overlap->oppPtTStart()->fT < test->oppPtTStart()->fT
684 : overlap->oppPtTStart()->fT > test->oppPtTStart()->fT) {
685 overlap->setOppPtTStart(test->oppPtTStart());
686 }
687 if (overlap->flipped()
688 ? overlap->oppPtTEnd()->fT > test->oppPtTEnd()->fT
689 : overlap->oppPtTEnd()->fT < test->oppPtTEnd()->fT) {
690 overlap->setOppPtTEnd(test->oppPtTEnd());
691 }
692 if (!fHead || !this->release(fHead, test)) {
693 SkAssertResult(this->release(fTop, test));
694 }
695 }
696 const SkOpPtT* cs = coinSeg->existing(coinTs, oppSeg);
697 const SkOpPtT* ce = coinSeg->existing(coinTe, oppSeg);
caryclark81a478c2016-09-09 09:37:57 -0700698 if (overlap && cs && ce && overlap->contains(cs, ce)) {
699 return true;
700 }
701 FAIL_IF(cs == ce && cs);
caryclark55888e42016-07-18 10:01:36 -0700702 const SkOpPtT* os = oppSeg->existing(oppTs, coinSeg);
703 const SkOpPtT* oe = oppSeg->existing(oppTe, coinSeg);
caryclark81a478c2016-09-09 09:37:57 -0700704 if (overlap && os && oe && overlap->contains(os, oe)) {
705 return true;
706 }
Cary Clarkb8421ed2018-03-14 15:55:02 -0400707 FAIL_IF(cs && cs->deleted());
Cary Clark2f06a532018-03-12 14:41:45 -0400708 FAIL_IF(os && os->deleted());
Cary Clark0949bee2018-03-19 09:42:00 -0400709 FAIL_IF(ce && ce->deleted());
Cary Clark74b42902018-03-09 07:38:47 -0500710 FAIL_IF(oe && oe->deleted());
caryclark55888e42016-07-18 10:01:36 -0700711 const SkOpPtT* csExisting = !cs ? coinSeg->existing(coinTs, nullptr) : nullptr;
712 const SkOpPtT* ceExisting = !ce ? coinSeg->existing(coinTe, nullptr) : nullptr;
caryclark81a478c2016-09-09 09:37:57 -0700713 FAIL_IF(csExisting && csExisting == ceExisting);
caryclarke839e782016-09-15 07:48:18 -0700714// FAIL_IF(csExisting && (csExisting == ce ||
715// csExisting->contains(ceExisting ? ceExisting : ce)));
caryclark81a478c2016-09-09 09:37:57 -0700716 FAIL_IF(ceExisting && (ceExisting == cs ||
caryclark025b11e2016-08-25 05:21:14 -0700717 ceExisting->contains(csExisting ? csExisting : cs)));
caryclark55888e42016-07-18 10:01:36 -0700718 const SkOpPtT* osExisting = !os ? oppSeg->existing(oppTs, nullptr) : nullptr;
719 const SkOpPtT* oeExisting = !oe ? oppSeg->existing(oppTe, nullptr) : nullptr;
caryclark81a478c2016-09-09 09:37:57 -0700720 FAIL_IF(osExisting && osExisting == oeExisting);
721 FAIL_IF(osExisting && (osExisting == oe ||
caryclark025b11e2016-08-25 05:21:14 -0700722 osExisting->contains(oeExisting ? oeExisting : oe)));
caryclark81a478c2016-09-09 09:37:57 -0700723 FAIL_IF(oeExisting && (oeExisting == os ||
caryclark025b11e2016-08-25 05:21:14 -0700724 oeExisting->contains(osExisting ? osExisting : os)));
caryclark55888e42016-07-18 10:01:36 -0700725 // extra line in debug code
726 this->debugValidate();
727 if (!cs || !os) {
728 SkOpPtT* csWritable = cs ? const_cast<SkOpPtT*>(cs)
caryclark29b25632016-08-25 11:27:17 -0700729 : coinSeg->addT(coinTs);
caryclarke839e782016-09-15 07:48:18 -0700730 if (csWritable == ce) {
731 return true;
732 }
caryclark55888e42016-07-18 10:01:36 -0700733 SkOpPtT* osWritable = os ? const_cast<SkOpPtT*>(os)
caryclark29b25632016-08-25 11:27:17 -0700734 : oppSeg->addT(oppTs);
caryclark81a478c2016-09-09 09:37:57 -0700735 FAIL_IF(!csWritable || !osWritable);
caryclark30b9fdd2016-08-31 14:36:29 -0700736 csWritable->span()->addOpp(osWritable->span());
caryclark55888e42016-07-18 10:01:36 -0700737 cs = csWritable;
caryclark30b9fdd2016-08-31 14:36:29 -0700738 os = osWritable->active();
Cary Clark74b42902018-03-09 07:38:47 -0500739 FAIL_IF(!os);
caryclark81a478c2016-09-09 09:37:57 -0700740 FAIL_IF((ce && ce->deleted()) || (oe && oe->deleted()));
caryclark55888e42016-07-18 10:01:36 -0700741 }
742 if (!ce || !oe) {
743 SkOpPtT* ceWritable = ce ? const_cast<SkOpPtT*>(ce)
caryclark29b25632016-08-25 11:27:17 -0700744 : coinSeg->addT(coinTe);
caryclark55888e42016-07-18 10:01:36 -0700745 SkOpPtT* oeWritable = oe ? const_cast<SkOpPtT*>(oe)
caryclark29b25632016-08-25 11:27:17 -0700746 : oppSeg->addT(oppTe);
caryclark30b9fdd2016-08-31 14:36:29 -0700747 ceWritable->span()->addOpp(oeWritable->span());
caryclark55888e42016-07-18 10:01:36 -0700748 ce = ceWritable;
749 oe = oeWritable;
750 }
751 this->debugValidate();
caryclark81a478c2016-09-09 09:37:57 -0700752 FAIL_IF(cs->deleted());
753 FAIL_IF(os->deleted());
754 FAIL_IF(ce->deleted());
755 FAIL_IF(oe->deleted());
756 FAIL_IF(cs->contains(ce) || os->contains(oe));
caryclark55888e42016-07-18 10:01:36 -0700757 bool result = true;
758 if (overlap) {
759 if (overlap->coinPtTStart()->segment() == coinSeg) {
760 result = overlap->extend(cs, ce, os, oe);
761 } else {
762 if (os->fT > oe->fT) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400763 using std::swap;
764 swap(cs, ce);
765 swap(os, oe);
caryclark55888e42016-07-18 10:01:36 -0700766 }
767 result = overlap->extend(os, oe, cs, ce);
768 }
769#if DEBUG_COINCIDENCE_VERBOSE
770 if (result) {
771 overlaps[0]->debugShow();
772 }
773#endif
774 } else {
775 this->add(cs, ce, os, oe);
776#if DEBUG_COINCIDENCE_VERBOSE
777 fHead->debugShow();
778#endif
779 }
780 this->debugValidate();
caryclark81a478c2016-09-09 09:37:57 -0700781 if (result) {
782 *added = true;
783 }
784 return true;
caryclark55888e42016-07-18 10:01:36 -0700785}
786
787// Please keep this in sync with debugAddMissing()
caryclark27c8eb82015-07-06 11:38:33 -0700788/* detects overlaps of different coincident runs on same segment */
789/* does not detect overlaps for pairs without any segments in common */
caryclark55888e42016-07-18 10:01:36 -0700790// returns true if caller should loop again
Cary Clarkab87d7a2016-10-04 10:01:04 -0400791bool SkOpCoincidence::addMissing(bool* added DEBUG_COIN_DECLARE_PARAMS()) {
caryclark27c8eb82015-07-06 11:38:33 -0700792 SkCoincidentSpans* outer = fHead;
caryclark81a478c2016-09-09 09:37:57 -0700793 *added = false;
caryclark54359292015-03-26 07:52:43 -0700794 if (!outer) {
caryclark81a478c2016-09-09 09:37:57 -0700795 return true;
caryclark54359292015-03-26 07:52:43 -0700796 }
caryclark27c8eb82015-07-06 11:38:33 -0700797 fTop = outer;
halcanary96fcdcc2015-08-27 07:41:13 -0700798 fHead = nullptr;
caryclark54359292015-03-26 07:52:43 -0700799 do {
caryclark27c8eb82015-07-06 11:38:33 -0700800 // addifmissing can modify the list that this is walking
caryclark26ad22a2015-10-16 09:03:38 -0700801 // save head so that walker can iterate over old data unperturbed
802 // addifmissing adds to head freely then add saved head in the end
caryclark8016b262016-09-06 05:59:47 -0700803 const SkOpPtT* ocs = outer->coinPtTStart();
caryclarka35ab3e2016-10-20 08:32:18 -0700804 FAIL_IF(ocs->deleted());
caryclark8016b262016-09-06 05:59:47 -0700805 const SkOpSegment* outerCoin = ocs->segment();
Cary Clark18562b82018-06-07 08:06:12 -0400806 FAIL_IF(outerCoin->done());
caryclark8016b262016-09-06 05:59:47 -0700807 const SkOpPtT* oos = outer->oppPtTStart();
caryclarkb393a492016-09-07 08:21:09 -0700808 if (oos->deleted()) {
caryclark81a478c2016-09-09 09:37:57 -0700809 return true;
caryclarkb393a492016-09-07 08:21:09 -0700810 }
caryclark8016b262016-09-06 05:59:47 -0700811 const SkOpSegment* outerOpp = oos->segment();
Cary Clark4c76c412017-01-20 08:14:33 -0500812 SkOPASSERT(!outerOpp->done());
caryclark8016b262016-09-06 05:59:47 -0700813 SkOpSegment* outerCoinWritable = const_cast<SkOpSegment*>(outerCoin);
814 SkOpSegment* outerOppWritable = const_cast<SkOpSegment*>(outerOpp);
caryclark54359292015-03-26 07:52:43 -0700815 SkCoincidentSpans* inner = outer;
caryclark55888e42016-07-18 10:01:36 -0700816 while ((inner = inner->next())) {
817 this->debugValidate();
caryclark54359292015-03-26 07:52:43 -0700818 double overS, overE;
caryclark8016b262016-09-06 05:59:47 -0700819 const SkOpPtT* ics = inner->coinPtTStart();
caryclark221a4bb2016-10-07 11:15:15 -0700820 FAIL_IF(ics->deleted());
caryclark8016b262016-09-06 05:59:47 -0700821 const SkOpSegment* innerCoin = ics->segment();
caryclarka35ab3e2016-10-20 08:32:18 -0700822 FAIL_IF(innerCoin->done());
caryclark8016b262016-09-06 05:59:47 -0700823 const SkOpPtT* ios = inner->oppPtTStart();
caryclarka35ab3e2016-10-20 08:32:18 -0700824 FAIL_IF(ios->deleted());
caryclark8016b262016-09-06 05:59:47 -0700825 const SkOpSegment* innerOpp = ios->segment();
Cary Clark4c76c412017-01-20 08:14:33 -0500826 SkOPASSERT(!innerOpp->done());
caryclark8016b262016-09-06 05:59:47 -0700827 SkOpSegment* innerCoinWritable = const_cast<SkOpSegment*>(innerCoin);
828 SkOpSegment* innerOppWritable = const_cast<SkOpSegment*>(innerOpp);
caryclark55888e42016-07-18 10:01:36 -0700829 if (outerCoin == innerCoin) {
caryclark8016b262016-09-06 05:59:47 -0700830 const SkOpPtT* oce = outer->coinPtTEnd();
caryclarkb393a492016-09-07 08:21:09 -0700831 if (oce->deleted()) {
caryclark81a478c2016-09-09 09:37:57 -0700832 return true;
caryclarkb393a492016-09-07 08:21:09 -0700833 }
caryclark8016b262016-09-06 05:59:47 -0700834 const SkOpPtT* ice = inner->coinPtTEnd();
caryclark595ac282016-10-24 08:41:45 -0700835 FAIL_IF(ice->deleted());
caryclark8016b262016-09-06 05:59:47 -0700836 if (outerOpp != innerOpp && this->overlap(ocs, oce, ics, ice, &overS, &overE)) {
Cary Clarkba610292018-06-19 09:47:15 -0400837 FAIL_IF(!this->addIfMissing(ocs->starter(oce), ics->starter(ice),
caryclark81a478c2016-09-09 09:37:57 -0700838 overS, overE, outerOppWritable, innerOppWritable, added
caryclark8016b262016-09-06 05:59:47 -0700839 SkDEBUGPARAMS(ocs->debugEnder(oce))
Cary Clarkba610292018-06-19 09:47:15 -0400840 SkDEBUGPARAMS(ics->debugEnder(ice))));
caryclark55888e42016-07-18 10:01:36 -0700841 }
842 } else if (outerCoin == innerOpp) {
caryclark8016b262016-09-06 05:59:47 -0700843 const SkOpPtT* oce = outer->coinPtTEnd();
Cary Clark56071432018-06-19 08:33:52 -0400844 FAIL_IF(oce->deleted());
caryclark8016b262016-09-06 05:59:47 -0700845 const SkOpPtT* ioe = inner->oppPtTEnd();
846 SkASSERT(!ioe->deleted());
847 if (outerOpp != innerCoin && this->overlap(ocs, oce, ios, ioe, &overS, &overE)) {
Cary Clarkba610292018-06-19 09:47:15 -0400848 FAIL_IF(!this->addIfMissing(ocs->starter(oce), ios->starter(ioe),
caryclark81a478c2016-09-09 09:37:57 -0700849 overS, overE, outerOppWritable, innerCoinWritable, added
caryclark8016b262016-09-06 05:59:47 -0700850 SkDEBUGPARAMS(ocs->debugEnder(oce))
Cary Clarkba610292018-06-19 09:47:15 -0400851 SkDEBUGPARAMS(ios->debugEnder(ioe))));
caryclark55888e42016-07-18 10:01:36 -0700852 }
853 } else if (outerOpp == innerCoin) {
caryclark8016b262016-09-06 05:59:47 -0700854 const SkOpPtT* ooe = outer->oppPtTEnd();
855 SkASSERT(!ooe->deleted());
856 const SkOpPtT* ice = inner->coinPtTEnd();
857 SkASSERT(!ice->deleted());
caryclark55888e42016-07-18 10:01:36 -0700858 SkASSERT(outerCoin != innerOpp);
caryclark8016b262016-09-06 05:59:47 -0700859 if (this->overlap(oos, ooe, ics, ice, &overS, &overE)) {
Cary Clarkba610292018-06-19 09:47:15 -0400860 FAIL_IF(!this->addIfMissing(oos->starter(ooe), ics->starter(ice),
caryclark81a478c2016-09-09 09:37:57 -0700861 overS, overE, outerCoinWritable, innerOppWritable, added
caryclark8016b262016-09-06 05:59:47 -0700862 SkDEBUGPARAMS(oos->debugEnder(ooe))
Cary Clarkba610292018-06-19 09:47:15 -0400863 SkDEBUGPARAMS(ics->debugEnder(ice))));
caryclark55888e42016-07-18 10:01:36 -0700864 }
865 } else if (outerOpp == innerOpp) {
caryclark8016b262016-09-06 05:59:47 -0700866 const SkOpPtT* ooe = outer->oppPtTEnd();
Cary Clark8d8a5d92018-04-02 12:40:49 -0400867 FAIL_IF(ooe->deleted());
caryclark8016b262016-09-06 05:59:47 -0700868 const SkOpPtT* ioe = inner->oppPtTEnd();
caryclarkb393a492016-09-07 08:21:09 -0700869 if (ioe->deleted()) {
caryclark81a478c2016-09-09 09:37:57 -0700870 return true;
caryclarkb393a492016-09-07 08:21:09 -0700871 }
caryclark55888e42016-07-18 10:01:36 -0700872 SkASSERT(outerCoin != innerCoin);
caryclark8016b262016-09-06 05:59:47 -0700873 if (this->overlap(oos, ooe, ios, ioe, &overS, &overE)) {
Cary Clarkba610292018-06-19 09:47:15 -0400874 FAIL_IF(!this->addIfMissing(oos->starter(ooe), ios->starter(ioe),
caryclark81a478c2016-09-09 09:37:57 -0700875 overS, overE, outerCoinWritable, innerCoinWritable, added
caryclark8016b262016-09-06 05:59:47 -0700876 SkDEBUGPARAMS(oos->debugEnder(ooe))
Cary Clarkba610292018-06-19 09:47:15 -0400877 SkDEBUGPARAMS(ios->debugEnder(ioe))));
caryclark54359292015-03-26 07:52:43 -0700878 }
879 }
caryclark55888e42016-07-18 10:01:36 -0700880 this->debugValidate();
caryclark54359292015-03-26 07:52:43 -0700881 }
caryclark55888e42016-07-18 10:01:36 -0700882 } while ((outer = outer->next()));
883 this->restoreHead();
caryclark81a478c2016-09-09 09:37:57 -0700884 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700885}
886
caryclark55888e42016-07-18 10:01:36 -0700887bool SkOpCoincidence::addOverlap(const SkOpSegment* seg1, const SkOpSegment* seg1o,
888 const SkOpSegment* seg2, const SkOpSegment* seg2o,
889 const SkOpPtT* overS, const SkOpPtT* overE) {
Cary Clarke47ae292016-10-05 08:51:39 -0400890 const SkOpPtT* s1 = overS->find(seg1);
891 const SkOpPtT* e1 = overE->find(seg1);
caryclark08714012016-10-07 12:57:47 -0700892 FAIL_IF(!s1);
Cary Clark40f23782016-10-06 12:04:16 -0400893 FAIL_IF(!e1);
caryclark27c8eb82015-07-06 11:38:33 -0700894 if (!s1->starter(e1)->span()->upCast()->windValue()) {
Cary Clarke47ae292016-10-05 08:51:39 -0400895 s1 = overS->find(seg1o);
896 e1 = overE->find(seg1o);
caryclark221a4bb2016-10-07 11:15:15 -0700897 FAIL_IF(!s1);
Cary Clark40f23782016-10-06 12:04:16 -0400898 FAIL_IF(!e1);
caryclark27c8eb82015-07-06 11:38:33 -0700899 if (!s1->starter(e1)->span()->upCast()->windValue()) {
caryclark3f0753d2016-06-28 09:23:57 -0700900 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700901 }
902 }
Cary Clarke47ae292016-10-05 08:51:39 -0400903 const SkOpPtT* s2 = overS->find(seg2);
904 const SkOpPtT* e2 = overE->find(seg2);
caryclark82616712016-10-24 04:53:22 -0700905 FAIL_IF(!s2);
caryclarka35ab3e2016-10-20 08:32:18 -0700906 FAIL_IF(!e2);
caryclark27c8eb82015-07-06 11:38:33 -0700907 if (!s2->starter(e2)->span()->upCast()->windValue()) {
Cary Clarke47ae292016-10-05 08:51:39 -0400908 s2 = overS->find(seg2o);
909 e2 = overE->find(seg2o);
caryclarka35ab3e2016-10-20 08:32:18 -0700910 FAIL_IF(!s2);
caryclark78a37a52016-10-20 12:36:16 -0700911 FAIL_IF(!e2);
caryclark27c8eb82015-07-06 11:38:33 -0700912 if (!s2->starter(e2)->span()->upCast()->windValue()) {
caryclark3f0753d2016-06-28 09:23:57 -0700913 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700914 }
915 }
916 if (s1->segment() == s2->segment()) {
caryclark3f0753d2016-06-28 09:23:57 -0700917 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700918 }
919 if (s1->fT > e1->fT) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400920 using std::swap;
921 swap(s1, e1);
922 swap(s2, e2);
caryclark27c8eb82015-07-06 11:38:33 -0700923 }
caryclark55888e42016-07-18 10:01:36 -0700924 this->add(s1, e1, s2, e2);
caryclark3f0753d2016-06-28 09:23:57 -0700925 return true;
caryclark54359292015-03-26 07:52:43 -0700926}
927
caryclark55888e42016-07-18 10:01:36 -0700928bool SkOpCoincidence::contains(const SkOpSegment* seg, const SkOpSegment* opp, double oppT) const {
929 if (this->contains(fHead, seg, opp, oppT)) {
930 return true;
931 }
932 if (this->contains(fTop, seg, opp, oppT)) {
933 return true;
934 }
935 return false;
936}
937
938bool SkOpCoincidence::contains(const SkCoincidentSpans* coin, const SkOpSegment* seg,
939 const SkOpSegment* opp, double oppT) const {
940 if (!coin) {
941 return false;
942 }
943 do {
944 if (coin->coinPtTStart()->segment() == seg && coin->oppPtTStart()->segment() == opp
945 && between(coin->oppPtTStart()->fT, oppT, coin->oppPtTEnd()->fT)) {
caryclark54359292015-03-26 07:52:43 -0700946 return true;
947 }
caryclark55888e42016-07-18 10:01:36 -0700948 if (coin->oppPtTStart()->segment() == seg && coin->coinPtTStart()->segment() == opp
949 && between(coin->coinPtTStart()->fT, oppT, coin->coinPtTEnd()->fT)) {
950 return true;
951 }
952 } while ((coin = coin->next()));
caryclark54359292015-03-26 07:52:43 -0700953 return false;
954}
955
caryclark55888e42016-07-18 10:01:36 -0700956bool SkOpCoincidence::contains(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd,
957 const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) const {
958 const SkCoincidentSpans* test = fHead;
959 if (!test) {
960 return false;
961 }
962 const SkOpSegment* coinSeg = coinPtTStart->segment();
963 const SkOpSegment* oppSeg = oppPtTStart->segment();
964 if (!Ordered(coinPtTStart, oppPtTStart)) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400965 using std::swap;
966 swap(coinSeg, oppSeg);
967 swap(coinPtTStart, oppPtTStart);
968 swap(coinPtTEnd, oppPtTEnd);
caryclark55888e42016-07-18 10:01:36 -0700969 if (coinPtTStart->fT > coinPtTEnd->fT) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400970 swap(coinPtTStart, coinPtTEnd);
971 swap(oppPtTStart, oppPtTEnd);
caryclark55888e42016-07-18 10:01:36 -0700972 }
973 }
974 double oppMinT = SkTMin(oppPtTStart->fT, oppPtTEnd->fT);
975 double oppMaxT = SkTMax(oppPtTStart->fT, oppPtTEnd->fT);
976 do {
977 if (coinSeg != test->coinPtTStart()->segment()) {
978 continue;
979 }
980 if (coinPtTStart->fT < test->coinPtTStart()->fT) {
981 continue;
982 }
983 if (coinPtTEnd->fT > test->coinPtTEnd()->fT) {
984 continue;
985 }
986 if (oppSeg != test->oppPtTStart()->segment()) {
987 continue;
988 }
989 if (oppMinT < SkTMin(test->oppPtTStart()->fT, test->oppPtTEnd()->fT)) {
990 continue;
991 }
992 if (oppMaxT > SkTMax(test->oppPtTStart()->fT, test->oppPtTEnd()->fT)) {
993 continue;
994 }
995 return true;
996 } while ((test = test->next()));
997 return false;
998}
999
Cary Clarkab87d7a2016-10-04 10:01:04 -04001000void SkOpCoincidence::correctEnds(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
1001 DEBUG_SET_PHASE();
caryclark55888e42016-07-18 10:01:36 -07001002 SkCoincidentSpans* coin = fHead;
1003 if (!coin) {
1004 return;
1005 }
1006 do {
1007 coin->correctEnds();
1008 } while ((coin = coin->next()));
1009}
1010
caryclark54359292015-03-26 07:52:43 -07001011// walk span sets in parallel, moving winding from one to the other
caryclarka35ab3e2016-10-20 08:32:18 -07001012bool SkOpCoincidence::apply(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
Cary Clarkab87d7a2016-10-04 10:01:04 -04001013 DEBUG_SET_PHASE();
caryclark54359292015-03-26 07:52:43 -07001014 SkCoincidentSpans* coin = fHead;
1015 if (!coin) {
caryclarka35ab3e2016-10-20 08:32:18 -07001016 return true;
caryclark54359292015-03-26 07:52:43 -07001017 }
1018 do {
Cary Clark5a2057a2017-01-03 10:47:34 -05001019 SkOpSpanBase* startSpan = coin->coinPtTStartWritable()->span();
1020 FAIL_IF(!startSpan->upCastable());
1021 SkOpSpan* start = startSpan->upCast();
caryclark182b4992015-05-14 05:45:54 -07001022 if (start->deleted()) {
1023 continue;
1024 }
caryclark55888e42016-07-18 10:01:36 -07001025 const SkOpSpanBase* end = coin->coinPtTEnd()->span();
caryclark54359292015-03-26 07:52:43 -07001026 SkASSERT(start == start->starter(end));
caryclark55888e42016-07-18 10:01:36 -07001027 bool flipped = coin->flipped();
caryclark96dc1c92016-10-20 11:34:10 -07001028 SkOpSpanBase* oStartBase = (flipped ? coin->oppPtTEndWritable()
1029 : coin->oppPtTStartWritable())->span();
1030 FAIL_IF(!oStartBase->upCastable());
1031 SkOpSpan* oStart = oStartBase->upCast();
caryclark182b4992015-05-14 05:45:54 -07001032 if (oStart->deleted()) {
1033 continue;
1034 }
caryclark55888e42016-07-18 10:01:36 -07001035 const SkOpSpanBase* oEnd = (flipped ? coin->oppPtTStart() : coin->oppPtTEnd())->span();
caryclark54359292015-03-26 07:52:43 -07001036 SkASSERT(oStart == oStart->starter(oEnd));
1037 SkOpSegment* segment = start->segment();
1038 SkOpSegment* oSegment = oStart->segment();
1039 bool operandSwap = segment->operand() != oSegment->operand();
1040 if (flipped) {
caryclark364a0072015-12-14 08:43:21 -08001041 if (oEnd->deleted()) {
1042 continue;
1043 }
caryclark54359292015-03-26 07:52:43 -07001044 do {
1045 SkOpSpanBase* oNext = oStart->next();
1046 if (oNext == oEnd) {
1047 break;
1048 }
Cary Clark26ae5ab2016-12-12 13:57:56 -05001049 FAIL_IF(!oNext->upCastable());
caryclark54359292015-03-26 07:52:43 -07001050 oStart = oNext->upCast();
1051 } while (true);
1052 }
caryclark54359292015-03-26 07:52:43 -07001053 do {
1054 int windValue = start->windValue();
caryclark54359292015-03-26 07:52:43 -07001055 int oppValue = start->oppValue();
caryclark1049f122015-04-20 08:31:59 -07001056 int oWindValue = oStart->windValue();
caryclark54359292015-03-26 07:52:43 -07001057 int oOppValue = oStart->oppValue();
1058 // winding values are added or subtracted depending on direction and wind type
1059 // same or opposite values are summed depending on the operand value
caryclark1049f122015-04-20 08:31:59 -07001060 int windDiff = operandSwap ? oOppValue : oWindValue;
1061 int oWindDiff = operandSwap ? oppValue : windValue;
1062 if (!flipped) {
1063 windDiff = -windDiff;
1064 oWindDiff = -oWindDiff;
1065 }
caryclark55888e42016-07-18 10:01:36 -07001066 bool addToStart = windValue && (windValue > windDiff || (windValue == windDiff
1067 && oWindValue <= oWindDiff));
1068 if (addToStart ? start->done() : oStart->done()) {
1069 addToStart ^= true;
1070 }
1071 if (addToStart) {
caryclark54359292015-03-26 07:52:43 -07001072 if (operandSwap) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -04001073 using std::swap;
1074 swap(oWindValue, oOppValue);
caryclark54359292015-03-26 07:52:43 -07001075 }
1076 if (flipped) {
1077 windValue -= oWindValue;
1078 oppValue -= oOppValue;
1079 } else {
1080 windValue += oWindValue;
1081 oppValue += oOppValue;
1082 }
caryclark1049f122015-04-20 08:31:59 -07001083 if (segment->isXor()) {
caryclark54359292015-03-26 07:52:43 -07001084 windValue &= 1;
1085 }
caryclark1049f122015-04-20 08:31:59 -07001086 if (segment->oppXor()) {
caryclark54359292015-03-26 07:52:43 -07001087 oppValue &= 1;
1088 }
1089 oWindValue = oOppValue = 0;
1090 } else {
1091 if (operandSwap) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -04001092 using std::swap;
1093 swap(windValue, oppValue);
caryclark54359292015-03-26 07:52:43 -07001094 }
1095 if (flipped) {
1096 oWindValue -= windValue;
1097 oOppValue -= oppValue;
1098 } else {
1099 oWindValue += windValue;
1100 oOppValue += oppValue;
1101 }
caryclark1049f122015-04-20 08:31:59 -07001102 if (oSegment->isXor()) {
caryclark54359292015-03-26 07:52:43 -07001103 oWindValue &= 1;
1104 }
caryclark1049f122015-04-20 08:31:59 -07001105 if (oSegment->oppXor()) {
1106 oOppValue &= 1;
1107 }
caryclark54359292015-03-26 07:52:43 -07001108 windValue = oppValue = 0;
1109 }
caryclark6c3b9cd2016-09-26 05:36:58 -07001110#if 0 && DEBUG_COINCIDENCE
caryclark55888e42016-07-18 10:01:36 -07001111 SkDebugf("seg=%d span=%d windValue=%d oppValue=%d\n", segment->debugID(),
1112 start->debugID(), windValue, oppValue);
1113 SkDebugf("seg=%d span=%d windValue=%d oppValue=%d\n", oSegment->debugID(),
1114 oStart->debugID(), oWindValue, oOppValue);
1115#endif
Cary Clark0949bee2018-03-19 09:42:00 -04001116 FAIL_IF(windValue <= -1);
caryclark54359292015-03-26 07:52:43 -07001117 start->setWindValue(windValue);
1118 start->setOppValue(oppValue);
Cary Clarkb8421ed2018-03-14 15:55:02 -04001119 FAIL_IF(oWindValue <= -1);
caryclark54359292015-03-26 07:52:43 -07001120 oStart->setWindValue(oWindValue);
1121 oStart->setOppValue(oOppValue);
1122 if (!windValue && !oppValue) {
1123 segment->markDone(start);
1124 }
1125 if (!oWindValue && !oOppValue) {
1126 oSegment->markDone(oStart);
1127 }
1128 SkOpSpanBase* next = start->next();
1129 SkOpSpanBase* oNext = flipped ? oStart->prev() : oStart->next();
1130 if (next == end) {
1131 break;
1132 }
caryclark96dc1c92016-10-20 11:34:10 -07001133 FAIL_IF(!next->upCastable());
caryclark54359292015-03-26 07:52:43 -07001134 start = next->upCast();
caryclark1049f122015-04-20 08:31:59 -07001135 // if the opposite ran out too soon, just reuse the last span
1136 if (!oNext || !oNext->upCastable()) {
1137 oNext = oStart;
caryclark54359292015-03-26 07:52:43 -07001138 }
1139 oStart = oNext->upCast();
1140 } while (true);
caryclark55888e42016-07-18 10:01:36 -07001141 } while ((coin = coin->next()));
caryclarka35ab3e2016-10-20 08:32:18 -07001142 return true;
caryclark54359292015-03-26 07:52:43 -07001143}
1144
caryclark55888e42016-07-18 10:01:36 -07001145// Please keep this in sync with debugRelease()
1146bool SkOpCoincidence::release(SkCoincidentSpans* coin, SkCoincidentSpans* remove) {
1147 SkCoincidentSpans* head = coin;
halcanary96fcdcc2015-08-27 07:41:13 -07001148 SkCoincidentSpans* prev = nullptr;
caryclark54359292015-03-26 07:52:43 -07001149 SkCoincidentSpans* next;
1150 do {
caryclark55888e42016-07-18 10:01:36 -07001151 next = coin->next();
caryclark54359292015-03-26 07:52:43 -07001152 if (coin == remove) {
1153 if (prev) {
caryclark55888e42016-07-18 10:01:36 -07001154 prev->setNext(next);
1155 } else if (head == fHead) {
caryclark54359292015-03-26 07:52:43 -07001156 fHead = next;
caryclark55888e42016-07-18 10:01:36 -07001157 } else {
1158 fTop = next;
caryclark54359292015-03-26 07:52:43 -07001159 }
1160 break;
1161 }
1162 prev = coin;
1163 } while ((coin = next));
caryclark55888e42016-07-18 10:01:36 -07001164 return coin != nullptr;
caryclark54359292015-03-26 07:52:43 -07001165}
1166
caryclark30b9fdd2016-08-31 14:36:29 -07001167void SkOpCoincidence::releaseDeleted(SkCoincidentSpans* coin) {
1168 if (!coin) {
1169 return;
1170 }
1171 SkCoincidentSpans* head = coin;
1172 SkCoincidentSpans* prev = nullptr;
1173 SkCoincidentSpans* next;
1174 do {
1175 next = coin->next();
1176 if (coin->coinPtTStart()->deleted()) {
1177 SkOPASSERT(coin->flipped() ? coin->oppPtTEnd()->deleted() :
1178 coin->oppPtTStart()->deleted());
1179 if (prev) {
1180 prev->setNext(next);
1181 } else if (head == fHead) {
1182 fHead = next;
1183 } else {
1184 fTop = next;
1185 }
1186 } else {
1187 SkOPASSERT(coin->flipped() ? !coin->oppPtTEnd()->deleted() :
1188 !coin->oppPtTStart()->deleted());
1189 prev = coin;
1190 }
1191 } while ((coin = next));
1192}
1193
1194void SkOpCoincidence::releaseDeleted() {
1195 this->releaseDeleted(fHead);
1196 this->releaseDeleted(fTop);
1197}
1198
caryclark55888e42016-07-18 10:01:36 -07001199void SkOpCoincidence::restoreHead() {
1200 SkCoincidentSpans** headPtr = &fHead;
1201 while (*headPtr) {
1202 headPtr = (*headPtr)->nextPtr();
1203 }
1204 *headPtr = fTop;
1205 fTop = nullptr;
1206 // segments may have collapsed in the meantime; remove empty referenced segments
1207 headPtr = &fHead;
1208 while (*headPtr) {
1209 SkCoincidentSpans* test = *headPtr;
1210 if (test->coinPtTStart()->segment()->done() || test->oppPtTStart()->segment()->done()) {
1211 *headPtr = test->next();
1212 continue;
1213 }
1214 headPtr = (*headPtr)->nextPtr();
1215 }
1216}
1217
1218// Please keep this in sync with debugExpand()
caryclark30b9fdd2016-08-31 14:36:29 -07001219// expand the range by checking adjacent spans for coincidence
Cary Clarkab87d7a2016-10-04 10:01:04 -04001220bool SkOpCoincidence::expand(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
1221 DEBUG_SET_PHASE();
caryclark54359292015-03-26 07:52:43 -07001222 SkCoincidentSpans* coin = fHead;
1223 if (!coin) {
caryclark27c8eb82015-07-06 11:38:33 -07001224 return false;
caryclark54359292015-03-26 07:52:43 -07001225 }
caryclark27c8eb82015-07-06 11:38:33 -07001226 bool expanded = false;
caryclark54359292015-03-26 07:52:43 -07001227 do {
caryclark55888e42016-07-18 10:01:36 -07001228 if (coin->expand()) {
1229 // check to see if multiple spans expanded so they are now identical
1230 SkCoincidentSpans* test = fHead;
1231 do {
1232 if (coin == test) {
1233 continue;
1234 }
1235 if (coin->coinPtTStart() == test->coinPtTStart()
1236 && coin->oppPtTStart() == test->oppPtTStart()) {
1237 this->release(fHead, test);
1238 break;
1239 }
1240 } while ((test = test->next()));
1241 expanded = true;
caryclark54359292015-03-26 07:52:43 -07001242 }
caryclark55888e42016-07-18 10:01:36 -07001243 } while ((coin = coin->next()));
caryclark27c8eb82015-07-06 11:38:33 -07001244 return expanded;
1245}
1246
Cary Clark40f23782016-10-06 12:04:16 -04001247bool SkOpCoincidence::findOverlaps(SkOpCoincidence* overlaps DEBUG_COIN_DECLARE_PARAMS()) const {
Cary Clarkab87d7a2016-10-04 10:01:04 -04001248 DEBUG_SET_PHASE();
halcanary96fcdcc2015-08-27 07:41:13 -07001249 overlaps->fHead = overlaps->fTop = nullptr;
caryclark27c8eb82015-07-06 11:38:33 -07001250 SkCoincidentSpans* outer = fHead;
1251 while (outer) {
caryclark55888e42016-07-18 10:01:36 -07001252 const SkOpSegment* outerCoin = outer->coinPtTStart()->segment();
1253 const SkOpSegment* outerOpp = outer->oppPtTStart()->segment();
caryclark27c8eb82015-07-06 11:38:33 -07001254 SkCoincidentSpans* inner = outer;
caryclark55888e42016-07-18 10:01:36 -07001255 while ((inner = inner->next())) {
1256 const SkOpSegment* innerCoin = inner->coinPtTStart()->segment();
caryclark27c8eb82015-07-06 11:38:33 -07001257 if (outerCoin == innerCoin) {
1258 continue; // both winners are the same segment, so there's no additional overlap
1259 }
caryclark55888e42016-07-18 10:01:36 -07001260 const SkOpSegment* innerOpp = inner->oppPtTStart()->segment();
1261 const SkOpPtT* overlapS;
1262 const SkOpPtT* overlapE;
1263 if ((outerOpp == innerCoin && SkOpPtT::Overlaps(outer->oppPtTStart(),
1264 outer->oppPtTEnd(),inner->coinPtTStart(), inner->coinPtTEnd(), &overlapS,
1265 &overlapE))
1266 || (outerCoin == innerOpp && SkOpPtT::Overlaps(outer->coinPtTStart(),
1267 outer->coinPtTEnd(), inner->oppPtTStart(), inner->oppPtTEnd(),
caryclark27c8eb82015-07-06 11:38:33 -07001268 &overlapS, &overlapE))
caryclark55888e42016-07-18 10:01:36 -07001269 || (outerOpp == innerOpp && SkOpPtT::Overlaps(outer->oppPtTStart(),
1270 outer->oppPtTEnd(), inner->oppPtTStart(), inner->oppPtTEnd(),
caryclark27c8eb82015-07-06 11:38:33 -07001271 &overlapS, &overlapE))) {
Cary Clark40f23782016-10-06 12:04:16 -04001272 if (!overlaps->addOverlap(outerCoin, outerOpp, innerCoin, innerOpp,
1273 overlapS, overlapE)) {
1274 return false;
1275 }
Cary Clarke47ae292016-10-05 08:51:39 -04001276 }
caryclark27c8eb82015-07-06 11:38:33 -07001277 }
caryclark55888e42016-07-18 10:01:36 -07001278 outer = outer->next();
caryclark27c8eb82015-07-06 11:38:33 -07001279 }
Cary Clark40f23782016-10-06 12:04:16 -04001280 return true;
caryclark27c8eb82015-07-06 11:38:33 -07001281}
1282
caryclark55888e42016-07-18 10:01:36 -07001283void SkOpCoincidence::fixUp(SkOpPtT* deleted, const SkOpPtT* kept) {
caryclarkb393a492016-09-07 08:21:09 -07001284 SkOPASSERT(deleted != kept);
caryclark55888e42016-07-18 10:01:36 -07001285 if (fHead) {
1286 this->fixUp(fHead, deleted, kept);
caryclark54359292015-03-26 07:52:43 -07001287 }
caryclark55888e42016-07-18 10:01:36 -07001288 if (fTop) {
1289 this->fixUp(fTop, deleted, kept);
1290 }
caryclark54359292015-03-26 07:52:43 -07001291}
1292
caryclark55888e42016-07-18 10:01:36 -07001293void SkOpCoincidence::fixUp(SkCoincidentSpans* coin, SkOpPtT* deleted, const SkOpPtT* kept) {
1294 SkCoincidentSpans* head = coin;
1295 do {
1296 if (coin->coinPtTStart() == deleted) {
1297 if (coin->coinPtTEnd()->span() == kept->span()) {
1298 this->release(head, coin);
1299 continue;
1300 }
1301 coin->setCoinPtTStart(kept);
1302 }
1303 if (coin->coinPtTEnd() == deleted) {
1304 if (coin->coinPtTStart()->span() == kept->span()) {
1305 this->release(head, coin);
1306 continue;
1307 }
1308 coin->setCoinPtTEnd(kept);
1309 }
1310 if (coin->oppPtTStart() == deleted) {
1311 if (coin->oppPtTEnd()->span() == kept->span()) {
1312 this->release(head, coin);
1313 continue;
1314 }
1315 coin->setOppPtTStart(kept);
1316 }
1317 if (coin->oppPtTEnd() == deleted) {
1318 if (coin->oppPtTStart()->span() == kept->span()) {
1319 this->release(head, coin);
1320 continue;
1321 }
1322 coin->setOppPtTEnd(kept);
1323 }
1324 } while ((coin = coin->next()));
1325}
1326
1327// Please keep this in sync with debugMark()
caryclark27c8eb82015-07-06 11:38:33 -07001328/* this sets up the coincidence links in the segments when the coincidence crosses multiple spans */
caryclarke6522ea2016-10-17 07:54:33 -07001329bool SkOpCoincidence::mark(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
Cary Clarkab87d7a2016-10-04 10:01:04 -04001330 DEBUG_SET_PHASE();
caryclark54359292015-03-26 07:52:43 -07001331 SkCoincidentSpans* coin = fHead;
1332 if (!coin) {
caryclarke6522ea2016-10-17 07:54:33 -07001333 return true;
caryclark54359292015-03-26 07:52:43 -07001334 }
1335 do {
caryclarke6522ea2016-10-17 07:54:33 -07001336 SkOpSpanBase* startBase = coin->coinPtTStartWritable()->span();
1337 FAIL_IF(!startBase->upCastable());
1338 SkOpSpan* start = startBase->upCast();
caryclarka35ab3e2016-10-20 08:32:18 -07001339 FAIL_IF(start->deleted());
caryclark55888e42016-07-18 10:01:36 -07001340 SkOpSpanBase* end = coin->coinPtTEndWritable()->span();
Cary Clark40f23782016-10-06 12:04:16 -04001341 SkOPASSERT(!end->deleted());
caryclark55888e42016-07-18 10:01:36 -07001342 SkOpSpanBase* oStart = coin->oppPtTStartWritable()->span();
Cary Clark40f23782016-10-06 12:04:16 -04001343 SkOPASSERT(!oStart->deleted());
caryclark55888e42016-07-18 10:01:36 -07001344 SkOpSpanBase* oEnd = coin->oppPtTEndWritable()->span();
Cary Clarkf36b8a32018-03-20 16:08:35 -04001345 FAIL_IF(oEnd->deleted());
caryclark55888e42016-07-18 10:01:36 -07001346 bool flipped = coin->flipped();
caryclark54359292015-03-26 07:52:43 -07001347 if (flipped) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -04001348 using std::swap;
1349 swap(oStart, oEnd);
caryclark54359292015-03-26 07:52:43 -07001350 }
caryclark55888e42016-07-18 10:01:36 -07001351 /* coin and opp spans may not match up. Mark the ends, and then let the interior
1352 get marked as many times as the spans allow */
Cary Clark9de09762016-11-17 08:47:37 -05001353 FAIL_IF(!oStart->upCastable());
caryclark55888e42016-07-18 10:01:36 -07001354 start->insertCoincidence(oStart->upCast());
1355 end->insertCoinEnd(oEnd);
1356 const SkOpSegment* segment = start->segment();
1357 const SkOpSegment* oSegment = oStart->segment();
caryclark54359292015-03-26 07:52:43 -07001358 SkOpSpanBase* next = start;
1359 SkOpSpanBase* oNext = oStart;
caryclarka35ab3e2016-10-20 08:32:18 -07001360 bool ordered;
1361 FAIL_IF(!coin->ordered(&ordered));
caryclark55888e42016-07-18 10:01:36 -07001362 while ((next = next->upCast()->next()) != end) {
caryclarke6522ea2016-10-17 07:54:33 -07001363 FAIL_IF(!next->upCastable());
Cary Clark59ed4822016-12-08 16:17:56 -05001364 FAIL_IF(!next->upCast()->insertCoincidence(oSegment, flipped, ordered));
caryclark55888e42016-07-18 10:01:36 -07001365 }
1366 while ((oNext = oNext->upCast()->next()) != oEnd) {
caryclark96dc1c92016-10-20 11:34:10 -07001367 FAIL_IF(!oNext->upCastable());
caryclarke6522ea2016-10-17 07:54:33 -07001368 FAIL_IF(!oNext->upCast()->insertCoincidence(segment, flipped, ordered));
caryclark55888e42016-07-18 10:01:36 -07001369 }
1370 } while ((coin = coin->next()));
caryclarke6522ea2016-10-17 07:54:33 -07001371 return true;
caryclark54359292015-03-26 07:52:43 -07001372}
1373
caryclark55888e42016-07-18 10:01:36 -07001374// Please keep in sync with debugMarkCollapsed()
1375void SkOpCoincidence::markCollapsed(SkCoincidentSpans* coin, SkOpPtT* test) {
1376 SkCoincidentSpans* head = coin;
1377 while (coin) {
1378 if (coin->collapsed(test)) {
1379 if (zero_or_one(coin->coinPtTStart()->fT) && zero_or_one(coin->coinPtTEnd()->fT)) {
1380 coin->coinPtTStartWritable()->segment()->markAllDone();
1381 }
1382 if (zero_or_one(coin->oppPtTStart()->fT) && zero_or_one(coin->oppPtTEnd()->fT)) {
1383 coin->oppPtTStartWritable()->segment()->markAllDone();
1384 }
1385 this->release(head, coin);
1386 }
1387 coin = coin->next();
1388 }
1389}
1390
1391// Please keep in sync with debugMarkCollapsed()
1392void SkOpCoincidence::markCollapsed(SkOpPtT* test) {
1393 markCollapsed(fHead, test);
1394 markCollapsed(fTop, test);
1395}
1396
1397bool SkOpCoincidence::Ordered(const SkOpSegment* coinSeg, const SkOpSegment* oppSeg) {
1398 if (coinSeg->verb() < oppSeg->verb()) {
1399 return true;
1400 }
1401 if (coinSeg->verb() > oppSeg->verb()) {
1402 return false;
1403 }
1404 int count = (SkPathOpsVerbToPoints(coinSeg->verb()) + 1) * 2;
1405 const SkScalar* cPt = &coinSeg->pts()[0].fX;
1406 const SkScalar* oPt = &oppSeg->pts()[0].fX;
1407 for (int index = 0; index < count; ++index) {
1408 if (*cPt < *oPt) {
1409 return true;
1410 }
1411 if (*cPt > *oPt) {
1412 return false;
1413 }
1414 ++cPt;
1415 ++oPt;
1416 }
1417 return true;
1418}
1419
1420bool SkOpCoincidence::overlap(const SkOpPtT* coin1s, const SkOpPtT* coin1e,
caryclark54359292015-03-26 07:52:43 -07001421 const SkOpPtT* coin2s, const SkOpPtT* coin2e, double* overS, double* overE) const {
caryclark27c8eb82015-07-06 11:38:33 -07001422 SkASSERT(coin1s->segment() == coin2s->segment());
caryclark54359292015-03-26 07:52:43 -07001423 *overS = SkTMax(SkTMin(coin1s->fT, coin1e->fT), SkTMin(coin2s->fT, coin2e->fT));
1424 *overE = SkTMin(SkTMax(coin1s->fT, coin1e->fT), SkTMax(coin2s->fT, coin2e->fT));
1425 return *overS < *overE;
1426}
caryclark27c8eb82015-07-06 11:38:33 -07001427
caryclark55888e42016-07-18 10:01:36 -07001428// Commented-out lines keep this in sync with debugRelease()
1429void SkOpCoincidence::release(const SkOpSegment* deleted) {
1430 SkCoincidentSpans* coin = fHead;
1431 if (!coin) {
1432 return;
1433 }
1434 do {
1435 if (coin->coinPtTStart()->segment() == deleted
1436 || coin->coinPtTEnd()->segment() == deleted
1437 || coin->oppPtTStart()->segment() == deleted
1438 || coin->oppPtTEnd()->segment() == deleted) {
1439 this->release(fHead, coin);
1440 }
1441 } while ((coin = coin->next()));
1442}