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