blob: 2f9d28f9eed42d17da1a7f2a2724cc5b53a2bcd2 [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());
697 SkASSERT(!oe || !oe->deleted());
698 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();
caryclark81a478c2016-09-09 09:37:57 -0700726 FAIL_IF((ce && ce->deleted()) || (oe && oe->deleted()));
caryclark55888e42016-07-18 10:01:36 -0700727 }
728 if (!ce || !oe) {
729 SkOpPtT* ceWritable = ce ? const_cast<SkOpPtT*>(ce)
caryclark29b25632016-08-25 11:27:17 -0700730 : coinSeg->addT(coinTe);
caryclark55888e42016-07-18 10:01:36 -0700731 SkOpPtT* oeWritable = oe ? const_cast<SkOpPtT*>(oe)
caryclark29b25632016-08-25 11:27:17 -0700732 : oppSeg->addT(oppTe);
caryclark30b9fdd2016-08-31 14:36:29 -0700733 ceWritable->span()->addOpp(oeWritable->span());
caryclark55888e42016-07-18 10:01:36 -0700734 ce = ceWritable;
735 oe = oeWritable;
736 }
737 this->debugValidate();
caryclark81a478c2016-09-09 09:37:57 -0700738 FAIL_IF(cs->deleted());
739 FAIL_IF(os->deleted());
740 FAIL_IF(ce->deleted());
741 FAIL_IF(oe->deleted());
742 FAIL_IF(cs->contains(ce) || os->contains(oe));
caryclark55888e42016-07-18 10:01:36 -0700743 bool result = true;
744 if (overlap) {
745 if (overlap->coinPtTStart()->segment() == coinSeg) {
746 result = overlap->extend(cs, ce, os, oe);
747 } else {
748 if (os->fT > oe->fT) {
749 SkTSwap(cs, ce);
750 SkTSwap(os, oe);
751 }
752 result = overlap->extend(os, oe, cs, ce);
753 }
754#if DEBUG_COINCIDENCE_VERBOSE
755 if (result) {
756 overlaps[0]->debugShow();
757 }
758#endif
759 } else {
760 this->add(cs, ce, os, oe);
761#if DEBUG_COINCIDENCE_VERBOSE
762 fHead->debugShow();
763#endif
764 }
765 this->debugValidate();
caryclark81a478c2016-09-09 09:37:57 -0700766 if (result) {
767 *added = true;
768 }
769 return true;
caryclark55888e42016-07-18 10:01:36 -0700770}
771
772// Please keep this in sync with debugAddMissing()
caryclark27c8eb82015-07-06 11:38:33 -0700773/* detects overlaps of different coincident runs on same segment */
774/* does not detect overlaps for pairs without any segments in common */
caryclark55888e42016-07-18 10:01:36 -0700775// returns true if caller should loop again
Cary Clarkab87d7a2016-10-04 10:01:04 -0400776bool SkOpCoincidence::addMissing(bool* added DEBUG_COIN_DECLARE_PARAMS()) {
caryclark27c8eb82015-07-06 11:38:33 -0700777 SkCoincidentSpans* outer = fHead;
caryclark81a478c2016-09-09 09:37:57 -0700778 *added = false;
caryclark54359292015-03-26 07:52:43 -0700779 if (!outer) {
caryclark81a478c2016-09-09 09:37:57 -0700780 return true;
caryclark54359292015-03-26 07:52:43 -0700781 }
caryclark27c8eb82015-07-06 11:38:33 -0700782 fTop = outer;
halcanary96fcdcc2015-08-27 07:41:13 -0700783 fHead = nullptr;
caryclark54359292015-03-26 07:52:43 -0700784 do {
caryclark27c8eb82015-07-06 11:38:33 -0700785 // addifmissing can modify the list that this is walking
caryclark26ad22a2015-10-16 09:03:38 -0700786 // save head so that walker can iterate over old data unperturbed
787 // addifmissing adds to head freely then add saved head in the end
caryclark8016b262016-09-06 05:59:47 -0700788 const SkOpPtT* ocs = outer->coinPtTStart();
caryclarka35ab3e2016-10-20 08:32:18 -0700789 FAIL_IF(ocs->deleted());
caryclark8016b262016-09-06 05:59:47 -0700790 const SkOpSegment* outerCoin = ocs->segment();
791 SkASSERT(!outerCoin->done()); // if it's done, should have already been removed from list
792 const SkOpPtT* oos = outer->oppPtTStart();
caryclarkb393a492016-09-07 08:21:09 -0700793 if (oos->deleted()) {
caryclark81a478c2016-09-09 09:37:57 -0700794 return true;
caryclarkb393a492016-09-07 08:21:09 -0700795 }
caryclark8016b262016-09-06 05:59:47 -0700796 const SkOpSegment* outerOpp = oos->segment();
Cary Clark4c76c412017-01-20 08:14:33 -0500797 SkOPASSERT(!outerOpp->done());
caryclark8016b262016-09-06 05:59:47 -0700798 SkOpSegment* outerCoinWritable = const_cast<SkOpSegment*>(outerCoin);
799 SkOpSegment* outerOppWritable = const_cast<SkOpSegment*>(outerOpp);
caryclark54359292015-03-26 07:52:43 -0700800 SkCoincidentSpans* inner = outer;
caryclark55888e42016-07-18 10:01:36 -0700801 while ((inner = inner->next())) {
802 this->debugValidate();
caryclark54359292015-03-26 07:52:43 -0700803 double overS, overE;
caryclark8016b262016-09-06 05:59:47 -0700804 const SkOpPtT* ics = inner->coinPtTStart();
caryclark221a4bb2016-10-07 11:15:15 -0700805 FAIL_IF(ics->deleted());
caryclark8016b262016-09-06 05:59:47 -0700806 const SkOpSegment* innerCoin = ics->segment();
caryclarka35ab3e2016-10-20 08:32:18 -0700807 FAIL_IF(innerCoin->done());
caryclark8016b262016-09-06 05:59:47 -0700808 const SkOpPtT* ios = inner->oppPtTStart();
caryclarka35ab3e2016-10-20 08:32:18 -0700809 FAIL_IF(ios->deleted());
caryclark8016b262016-09-06 05:59:47 -0700810 const SkOpSegment* innerOpp = ios->segment();
Cary Clark4c76c412017-01-20 08:14:33 -0500811 SkOPASSERT(!innerOpp->done());
caryclark8016b262016-09-06 05:59:47 -0700812 SkOpSegment* innerCoinWritable = const_cast<SkOpSegment*>(innerCoin);
813 SkOpSegment* innerOppWritable = const_cast<SkOpSegment*>(innerOpp);
caryclark55888e42016-07-18 10:01:36 -0700814 if (outerCoin == innerCoin) {
caryclark8016b262016-09-06 05:59:47 -0700815 const SkOpPtT* oce = outer->coinPtTEnd();
caryclarkb393a492016-09-07 08:21:09 -0700816 if (oce->deleted()) {
caryclark81a478c2016-09-09 09:37:57 -0700817 return true;
caryclarkb393a492016-09-07 08:21:09 -0700818 }
caryclark8016b262016-09-06 05:59:47 -0700819 const SkOpPtT* ice = inner->coinPtTEnd();
caryclark595ac282016-10-24 08:41:45 -0700820 FAIL_IF(ice->deleted());
caryclark8016b262016-09-06 05:59:47 -0700821 if (outerOpp != innerOpp && this->overlap(ocs, oce, ics, ice, &overS, &overE)) {
caryclark81a478c2016-09-09 09:37:57 -0700822 (void) this->addIfMissing(ocs->starter(oce), ics->starter(ice),
823 overS, overE, outerOppWritable, innerOppWritable, added
caryclark8016b262016-09-06 05:59:47 -0700824 SkDEBUGPARAMS(ocs->debugEnder(oce))
825 SkDEBUGPARAMS(ics->debugEnder(ice)));
caryclark55888e42016-07-18 10:01:36 -0700826 }
827 } else if (outerCoin == innerOpp) {
caryclark8016b262016-09-06 05:59:47 -0700828 const SkOpPtT* oce = outer->coinPtTEnd();
829 SkASSERT(!oce->deleted());
830 const SkOpPtT* ioe = inner->oppPtTEnd();
831 SkASSERT(!ioe->deleted());
832 if (outerOpp != innerCoin && this->overlap(ocs, oce, ios, ioe, &overS, &overE)) {
caryclark81a478c2016-09-09 09:37:57 -0700833 (void) this->addIfMissing(ocs->starter(oce), ios->starter(ioe),
834 overS, overE, outerOppWritable, innerCoinWritable, added
caryclark8016b262016-09-06 05:59:47 -0700835 SkDEBUGPARAMS(ocs->debugEnder(oce))
836 SkDEBUGPARAMS(ios->debugEnder(ioe)));
caryclark55888e42016-07-18 10:01:36 -0700837 }
838 } else if (outerOpp == innerCoin) {
caryclark8016b262016-09-06 05:59:47 -0700839 const SkOpPtT* ooe = outer->oppPtTEnd();
840 SkASSERT(!ooe->deleted());
841 const SkOpPtT* ice = inner->coinPtTEnd();
842 SkASSERT(!ice->deleted());
caryclark55888e42016-07-18 10:01:36 -0700843 SkASSERT(outerCoin != innerOpp);
caryclark8016b262016-09-06 05:59:47 -0700844 if (this->overlap(oos, ooe, ics, ice, &overS, &overE)) {
caryclark81a478c2016-09-09 09:37:57 -0700845 (void) this->addIfMissing(oos->starter(ooe), ics->starter(ice),
846 overS, overE, outerCoinWritable, innerOppWritable, added
caryclark8016b262016-09-06 05:59:47 -0700847 SkDEBUGPARAMS(oos->debugEnder(ooe))
848 SkDEBUGPARAMS(ics->debugEnder(ice)));
caryclark55888e42016-07-18 10:01:36 -0700849 }
850 } else if (outerOpp == innerOpp) {
caryclark8016b262016-09-06 05:59:47 -0700851 const SkOpPtT* ooe = outer->oppPtTEnd();
852 SkASSERT(!ooe->deleted());
853 const SkOpPtT* ioe = inner->oppPtTEnd();
caryclarkb393a492016-09-07 08:21:09 -0700854 if (ioe->deleted()) {
caryclark81a478c2016-09-09 09:37:57 -0700855 return true;
caryclarkb393a492016-09-07 08:21:09 -0700856 }
caryclark55888e42016-07-18 10:01:36 -0700857 SkASSERT(outerCoin != innerCoin);
caryclark8016b262016-09-06 05:59:47 -0700858 if (this->overlap(oos, ooe, ios, ioe, &overS, &overE)) {
caryclark81a478c2016-09-09 09:37:57 -0700859 (void) this->addIfMissing(oos->starter(ooe), ios->starter(ioe),
860 overS, overE, outerCoinWritable, innerCoinWritable, added
caryclark8016b262016-09-06 05:59:47 -0700861 SkDEBUGPARAMS(oos->debugEnder(ooe))
862 SkDEBUGPARAMS(ios->debugEnder(ioe)));
caryclark54359292015-03-26 07:52:43 -0700863 }
864 }
caryclark55888e42016-07-18 10:01:36 -0700865 this->debugValidate();
caryclark54359292015-03-26 07:52:43 -0700866 }
caryclark55888e42016-07-18 10:01:36 -0700867 } while ((outer = outer->next()));
868 this->restoreHead();
caryclark81a478c2016-09-09 09:37:57 -0700869 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700870}
871
caryclark55888e42016-07-18 10:01:36 -0700872bool SkOpCoincidence::addOverlap(const SkOpSegment* seg1, const SkOpSegment* seg1o,
873 const SkOpSegment* seg2, const SkOpSegment* seg2o,
874 const SkOpPtT* overS, const SkOpPtT* overE) {
Cary Clarke47ae292016-10-05 08:51:39 -0400875 const SkOpPtT* s1 = overS->find(seg1);
876 const SkOpPtT* e1 = overE->find(seg1);
caryclark08714012016-10-07 12:57:47 -0700877 FAIL_IF(!s1);
Cary Clark40f23782016-10-06 12:04:16 -0400878 FAIL_IF(!e1);
caryclark27c8eb82015-07-06 11:38:33 -0700879 if (!s1->starter(e1)->span()->upCast()->windValue()) {
Cary Clarke47ae292016-10-05 08:51:39 -0400880 s1 = overS->find(seg1o);
881 e1 = overE->find(seg1o);
caryclark221a4bb2016-10-07 11:15:15 -0700882 FAIL_IF(!s1);
Cary Clark40f23782016-10-06 12:04:16 -0400883 FAIL_IF(!e1);
caryclark27c8eb82015-07-06 11:38:33 -0700884 if (!s1->starter(e1)->span()->upCast()->windValue()) {
caryclark3f0753d2016-06-28 09:23:57 -0700885 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700886 }
887 }
Cary Clarke47ae292016-10-05 08:51:39 -0400888 const SkOpPtT* s2 = overS->find(seg2);
889 const SkOpPtT* e2 = overE->find(seg2);
caryclark82616712016-10-24 04:53:22 -0700890 FAIL_IF(!s2);
caryclarka35ab3e2016-10-20 08:32:18 -0700891 FAIL_IF(!e2);
caryclark27c8eb82015-07-06 11:38:33 -0700892 if (!s2->starter(e2)->span()->upCast()->windValue()) {
Cary Clarke47ae292016-10-05 08:51:39 -0400893 s2 = overS->find(seg2o);
894 e2 = overE->find(seg2o);
caryclarka35ab3e2016-10-20 08:32:18 -0700895 FAIL_IF(!s2);
caryclark78a37a52016-10-20 12:36:16 -0700896 FAIL_IF(!e2);
caryclark27c8eb82015-07-06 11:38:33 -0700897 if (!s2->starter(e2)->span()->upCast()->windValue()) {
caryclark3f0753d2016-06-28 09:23:57 -0700898 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700899 }
900 }
901 if (s1->segment() == s2->segment()) {
caryclark3f0753d2016-06-28 09:23:57 -0700902 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700903 }
904 if (s1->fT > e1->fT) {
905 SkTSwap(s1, e1);
906 SkTSwap(s2, e2);
907 }
caryclark55888e42016-07-18 10:01:36 -0700908 this->add(s1, e1, s2, e2);
caryclark3f0753d2016-06-28 09:23:57 -0700909 return true;
caryclark54359292015-03-26 07:52:43 -0700910}
911
caryclark55888e42016-07-18 10:01:36 -0700912bool SkOpCoincidence::contains(const SkOpSegment* seg, const SkOpSegment* opp, double oppT) const {
913 if (this->contains(fHead, seg, opp, oppT)) {
914 return true;
915 }
916 if (this->contains(fTop, seg, opp, oppT)) {
917 return true;
918 }
919 return false;
920}
921
922bool SkOpCoincidence::contains(const SkCoincidentSpans* coin, const SkOpSegment* seg,
923 const SkOpSegment* opp, double oppT) const {
924 if (!coin) {
925 return false;
926 }
927 do {
928 if (coin->coinPtTStart()->segment() == seg && coin->oppPtTStart()->segment() == opp
929 && between(coin->oppPtTStart()->fT, oppT, coin->oppPtTEnd()->fT)) {
caryclark54359292015-03-26 07:52:43 -0700930 return true;
931 }
caryclark55888e42016-07-18 10:01:36 -0700932 if (coin->oppPtTStart()->segment() == seg && coin->coinPtTStart()->segment() == opp
933 && between(coin->coinPtTStart()->fT, oppT, coin->coinPtTEnd()->fT)) {
934 return true;
935 }
936 } while ((coin = coin->next()));
caryclark54359292015-03-26 07:52:43 -0700937 return false;
938}
939
caryclark55888e42016-07-18 10:01:36 -0700940bool SkOpCoincidence::contains(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd,
941 const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) const {
942 const SkCoincidentSpans* test = fHead;
943 if (!test) {
944 return false;
945 }
946 const SkOpSegment* coinSeg = coinPtTStart->segment();
947 const SkOpSegment* oppSeg = oppPtTStart->segment();
948 if (!Ordered(coinPtTStart, oppPtTStart)) {
949 SkTSwap(coinSeg, oppSeg);
950 SkTSwap(coinPtTStart, oppPtTStart);
951 SkTSwap(coinPtTEnd, oppPtTEnd);
952 if (coinPtTStart->fT > coinPtTEnd->fT) {
953 SkTSwap(coinPtTStart, coinPtTEnd);
954 SkTSwap(oppPtTStart, oppPtTEnd);
955 }
956 }
957 double oppMinT = SkTMin(oppPtTStart->fT, oppPtTEnd->fT);
958 double oppMaxT = SkTMax(oppPtTStart->fT, oppPtTEnd->fT);
959 do {
960 if (coinSeg != test->coinPtTStart()->segment()) {
961 continue;
962 }
963 if (coinPtTStart->fT < test->coinPtTStart()->fT) {
964 continue;
965 }
966 if (coinPtTEnd->fT > test->coinPtTEnd()->fT) {
967 continue;
968 }
969 if (oppSeg != test->oppPtTStart()->segment()) {
970 continue;
971 }
972 if (oppMinT < SkTMin(test->oppPtTStart()->fT, test->oppPtTEnd()->fT)) {
973 continue;
974 }
975 if (oppMaxT > SkTMax(test->oppPtTStart()->fT, test->oppPtTEnd()->fT)) {
976 continue;
977 }
978 return true;
979 } while ((test = test->next()));
980 return false;
981}
982
Cary Clarkab87d7a2016-10-04 10:01:04 -0400983void SkOpCoincidence::correctEnds(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
984 DEBUG_SET_PHASE();
caryclark55888e42016-07-18 10:01:36 -0700985 SkCoincidentSpans* coin = fHead;
986 if (!coin) {
987 return;
988 }
989 do {
990 coin->correctEnds();
991 } while ((coin = coin->next()));
992}
993
caryclark54359292015-03-26 07:52:43 -0700994// walk span sets in parallel, moving winding from one to the other
caryclarka35ab3e2016-10-20 08:32:18 -0700995bool SkOpCoincidence::apply(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
Cary Clarkab87d7a2016-10-04 10:01:04 -0400996 DEBUG_SET_PHASE();
caryclark54359292015-03-26 07:52:43 -0700997 SkCoincidentSpans* coin = fHead;
998 if (!coin) {
caryclarka35ab3e2016-10-20 08:32:18 -0700999 return true;
caryclark54359292015-03-26 07:52:43 -07001000 }
1001 do {
Cary Clark5a2057a2017-01-03 10:47:34 -05001002 SkOpSpanBase* startSpan = coin->coinPtTStartWritable()->span();
1003 FAIL_IF(!startSpan->upCastable());
1004 SkOpSpan* start = startSpan->upCast();
caryclark182b4992015-05-14 05:45:54 -07001005 if (start->deleted()) {
1006 continue;
1007 }
caryclark55888e42016-07-18 10:01:36 -07001008 const SkOpSpanBase* end = coin->coinPtTEnd()->span();
caryclark54359292015-03-26 07:52:43 -07001009 SkASSERT(start == start->starter(end));
caryclark55888e42016-07-18 10:01:36 -07001010 bool flipped = coin->flipped();
caryclark96dc1c92016-10-20 11:34:10 -07001011 SkOpSpanBase* oStartBase = (flipped ? coin->oppPtTEndWritable()
1012 : coin->oppPtTStartWritable())->span();
1013 FAIL_IF(!oStartBase->upCastable());
1014 SkOpSpan* oStart = oStartBase->upCast();
caryclark182b4992015-05-14 05:45:54 -07001015 if (oStart->deleted()) {
1016 continue;
1017 }
caryclark55888e42016-07-18 10:01:36 -07001018 const SkOpSpanBase* oEnd = (flipped ? coin->oppPtTStart() : coin->oppPtTEnd())->span();
caryclark54359292015-03-26 07:52:43 -07001019 SkASSERT(oStart == oStart->starter(oEnd));
1020 SkOpSegment* segment = start->segment();
1021 SkOpSegment* oSegment = oStart->segment();
1022 bool operandSwap = segment->operand() != oSegment->operand();
1023 if (flipped) {
caryclark364a0072015-12-14 08:43:21 -08001024 if (oEnd->deleted()) {
1025 continue;
1026 }
caryclark54359292015-03-26 07:52:43 -07001027 do {
1028 SkOpSpanBase* oNext = oStart->next();
1029 if (oNext == oEnd) {
1030 break;
1031 }
Cary Clark26ae5ab2016-12-12 13:57:56 -05001032 FAIL_IF(!oNext->upCastable());
caryclark54359292015-03-26 07:52:43 -07001033 oStart = oNext->upCast();
1034 } while (true);
1035 }
caryclark54359292015-03-26 07:52:43 -07001036 do {
1037 int windValue = start->windValue();
caryclark54359292015-03-26 07:52:43 -07001038 int oppValue = start->oppValue();
caryclark1049f122015-04-20 08:31:59 -07001039 int oWindValue = oStart->windValue();
caryclark54359292015-03-26 07:52:43 -07001040 int oOppValue = oStart->oppValue();
1041 // winding values are added or subtracted depending on direction and wind type
1042 // same or opposite values are summed depending on the operand value
caryclark1049f122015-04-20 08:31:59 -07001043 int windDiff = operandSwap ? oOppValue : oWindValue;
1044 int oWindDiff = operandSwap ? oppValue : windValue;
1045 if (!flipped) {
1046 windDiff = -windDiff;
1047 oWindDiff = -oWindDiff;
1048 }
caryclark55888e42016-07-18 10:01:36 -07001049 bool addToStart = windValue && (windValue > windDiff || (windValue == windDiff
1050 && oWindValue <= oWindDiff));
1051 if (addToStart ? start->done() : oStart->done()) {
1052 addToStart ^= true;
1053 }
1054 if (addToStart) {
caryclark54359292015-03-26 07:52:43 -07001055 if (operandSwap) {
1056 SkTSwap(oWindValue, oOppValue);
1057 }
1058 if (flipped) {
1059 windValue -= oWindValue;
1060 oppValue -= oOppValue;
1061 } else {
1062 windValue += oWindValue;
1063 oppValue += oOppValue;
1064 }
caryclark1049f122015-04-20 08:31:59 -07001065 if (segment->isXor()) {
caryclark54359292015-03-26 07:52:43 -07001066 windValue &= 1;
1067 }
caryclark1049f122015-04-20 08:31:59 -07001068 if (segment->oppXor()) {
caryclark54359292015-03-26 07:52:43 -07001069 oppValue &= 1;
1070 }
1071 oWindValue = oOppValue = 0;
1072 } else {
1073 if (operandSwap) {
1074 SkTSwap(windValue, oppValue);
1075 }
1076 if (flipped) {
1077 oWindValue -= windValue;
1078 oOppValue -= oppValue;
1079 } else {
1080 oWindValue += windValue;
1081 oOppValue += oppValue;
1082 }
caryclark1049f122015-04-20 08:31:59 -07001083 if (oSegment->isXor()) {
caryclark54359292015-03-26 07:52:43 -07001084 oWindValue &= 1;
1085 }
caryclark1049f122015-04-20 08:31:59 -07001086 if (oSegment->oppXor()) {
1087 oOppValue &= 1;
1088 }
caryclark54359292015-03-26 07:52:43 -07001089 windValue = oppValue = 0;
1090 }
caryclark6c3b9cd2016-09-26 05:36:58 -07001091#if 0 && DEBUG_COINCIDENCE
caryclark55888e42016-07-18 10:01:36 -07001092 SkDebugf("seg=%d span=%d windValue=%d oppValue=%d\n", segment->debugID(),
1093 start->debugID(), windValue, oppValue);
1094 SkDebugf("seg=%d span=%d windValue=%d oppValue=%d\n", oSegment->debugID(),
1095 oStart->debugID(), oWindValue, oOppValue);
1096#endif
caryclark54359292015-03-26 07:52:43 -07001097 start->setWindValue(windValue);
1098 start->setOppValue(oppValue);
caryclarka35ab3e2016-10-20 08:32:18 -07001099 FAIL_IF(oWindValue == -1);
caryclark54359292015-03-26 07:52:43 -07001100 oStart->setWindValue(oWindValue);
1101 oStart->setOppValue(oOppValue);
1102 if (!windValue && !oppValue) {
1103 segment->markDone(start);
1104 }
1105 if (!oWindValue && !oOppValue) {
1106 oSegment->markDone(oStart);
1107 }
1108 SkOpSpanBase* next = start->next();
1109 SkOpSpanBase* oNext = flipped ? oStart->prev() : oStart->next();
1110 if (next == end) {
1111 break;
1112 }
caryclark96dc1c92016-10-20 11:34:10 -07001113 FAIL_IF(!next->upCastable());
caryclark54359292015-03-26 07:52:43 -07001114 start = next->upCast();
caryclark1049f122015-04-20 08:31:59 -07001115 // if the opposite ran out too soon, just reuse the last span
1116 if (!oNext || !oNext->upCastable()) {
1117 oNext = oStart;
caryclark54359292015-03-26 07:52:43 -07001118 }
1119 oStart = oNext->upCast();
1120 } while (true);
caryclark55888e42016-07-18 10:01:36 -07001121 } while ((coin = coin->next()));
caryclarka35ab3e2016-10-20 08:32:18 -07001122 return true;
caryclark54359292015-03-26 07:52:43 -07001123}
1124
caryclark55888e42016-07-18 10:01:36 -07001125// Please keep this in sync with debugRelease()
1126bool SkOpCoincidence::release(SkCoincidentSpans* coin, SkCoincidentSpans* remove) {
1127 SkCoincidentSpans* head = coin;
halcanary96fcdcc2015-08-27 07:41:13 -07001128 SkCoincidentSpans* prev = nullptr;
caryclark54359292015-03-26 07:52:43 -07001129 SkCoincidentSpans* next;
1130 do {
caryclark55888e42016-07-18 10:01:36 -07001131 next = coin->next();
caryclark54359292015-03-26 07:52:43 -07001132 if (coin == remove) {
1133 if (prev) {
caryclark55888e42016-07-18 10:01:36 -07001134 prev->setNext(next);
1135 } else if (head == fHead) {
caryclark54359292015-03-26 07:52:43 -07001136 fHead = next;
caryclark55888e42016-07-18 10:01:36 -07001137 } else {
1138 fTop = next;
caryclark54359292015-03-26 07:52:43 -07001139 }
1140 break;
1141 }
1142 prev = coin;
1143 } while ((coin = next));
caryclark55888e42016-07-18 10:01:36 -07001144 return coin != nullptr;
caryclark54359292015-03-26 07:52:43 -07001145}
1146
caryclark30b9fdd2016-08-31 14:36:29 -07001147void SkOpCoincidence::releaseDeleted(SkCoincidentSpans* coin) {
1148 if (!coin) {
1149 return;
1150 }
1151 SkCoincidentSpans* head = coin;
1152 SkCoincidentSpans* prev = nullptr;
1153 SkCoincidentSpans* next;
1154 do {
1155 next = coin->next();
1156 if (coin->coinPtTStart()->deleted()) {
1157 SkOPASSERT(coin->flipped() ? coin->oppPtTEnd()->deleted() :
1158 coin->oppPtTStart()->deleted());
1159 if (prev) {
1160 prev->setNext(next);
1161 } else if (head == fHead) {
1162 fHead = next;
1163 } else {
1164 fTop = next;
1165 }
1166 } else {
1167 SkOPASSERT(coin->flipped() ? !coin->oppPtTEnd()->deleted() :
1168 !coin->oppPtTStart()->deleted());
1169 prev = coin;
1170 }
1171 } while ((coin = next));
1172}
1173
1174void SkOpCoincidence::releaseDeleted() {
1175 this->releaseDeleted(fHead);
1176 this->releaseDeleted(fTop);
1177}
1178
caryclark55888e42016-07-18 10:01:36 -07001179void SkOpCoincidence::restoreHead() {
1180 SkCoincidentSpans** headPtr = &fHead;
1181 while (*headPtr) {
1182 headPtr = (*headPtr)->nextPtr();
1183 }
1184 *headPtr = fTop;
1185 fTop = nullptr;
1186 // segments may have collapsed in the meantime; remove empty referenced segments
1187 headPtr = &fHead;
1188 while (*headPtr) {
1189 SkCoincidentSpans* test = *headPtr;
1190 if (test->coinPtTStart()->segment()->done() || test->oppPtTStart()->segment()->done()) {
1191 *headPtr = test->next();
1192 continue;
1193 }
1194 headPtr = (*headPtr)->nextPtr();
1195 }
1196}
1197
1198// Please keep this in sync with debugExpand()
caryclark30b9fdd2016-08-31 14:36:29 -07001199// expand the range by checking adjacent spans for coincidence
Cary Clarkab87d7a2016-10-04 10:01:04 -04001200bool SkOpCoincidence::expand(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
1201 DEBUG_SET_PHASE();
caryclark54359292015-03-26 07:52:43 -07001202 SkCoincidentSpans* coin = fHead;
1203 if (!coin) {
caryclark27c8eb82015-07-06 11:38:33 -07001204 return false;
caryclark54359292015-03-26 07:52:43 -07001205 }
caryclark27c8eb82015-07-06 11:38:33 -07001206 bool expanded = false;
caryclark54359292015-03-26 07:52:43 -07001207 do {
caryclark55888e42016-07-18 10:01:36 -07001208 if (coin->expand()) {
1209 // check to see if multiple spans expanded so they are now identical
1210 SkCoincidentSpans* test = fHead;
1211 do {
1212 if (coin == test) {
1213 continue;
1214 }
1215 if (coin->coinPtTStart() == test->coinPtTStart()
1216 && coin->oppPtTStart() == test->oppPtTStart()) {
1217 this->release(fHead, test);
1218 break;
1219 }
1220 } while ((test = test->next()));
1221 expanded = true;
caryclark54359292015-03-26 07:52:43 -07001222 }
caryclark55888e42016-07-18 10:01:36 -07001223 } while ((coin = coin->next()));
caryclark27c8eb82015-07-06 11:38:33 -07001224 return expanded;
1225}
1226
Cary Clark40f23782016-10-06 12:04:16 -04001227bool SkOpCoincidence::findOverlaps(SkOpCoincidence* overlaps DEBUG_COIN_DECLARE_PARAMS()) const {
Cary Clarkab87d7a2016-10-04 10:01:04 -04001228 DEBUG_SET_PHASE();
halcanary96fcdcc2015-08-27 07:41:13 -07001229 overlaps->fHead = overlaps->fTop = nullptr;
caryclark27c8eb82015-07-06 11:38:33 -07001230 SkCoincidentSpans* outer = fHead;
1231 while (outer) {
caryclark55888e42016-07-18 10:01:36 -07001232 const SkOpSegment* outerCoin = outer->coinPtTStart()->segment();
1233 const SkOpSegment* outerOpp = outer->oppPtTStart()->segment();
caryclark27c8eb82015-07-06 11:38:33 -07001234 SkCoincidentSpans* inner = outer;
caryclark55888e42016-07-18 10:01:36 -07001235 while ((inner = inner->next())) {
1236 const SkOpSegment* innerCoin = inner->coinPtTStart()->segment();
caryclark27c8eb82015-07-06 11:38:33 -07001237 if (outerCoin == innerCoin) {
1238 continue; // both winners are the same segment, so there's no additional overlap
1239 }
caryclark55888e42016-07-18 10:01:36 -07001240 const SkOpSegment* innerOpp = inner->oppPtTStart()->segment();
1241 const SkOpPtT* overlapS;
1242 const SkOpPtT* overlapE;
1243 if ((outerOpp == innerCoin && SkOpPtT::Overlaps(outer->oppPtTStart(),
1244 outer->oppPtTEnd(),inner->coinPtTStart(), inner->coinPtTEnd(), &overlapS,
1245 &overlapE))
1246 || (outerCoin == innerOpp && SkOpPtT::Overlaps(outer->coinPtTStart(),
1247 outer->coinPtTEnd(), inner->oppPtTStart(), inner->oppPtTEnd(),
caryclark27c8eb82015-07-06 11:38:33 -07001248 &overlapS, &overlapE))
caryclark55888e42016-07-18 10:01:36 -07001249 || (outerOpp == innerOpp && SkOpPtT::Overlaps(outer->oppPtTStart(),
1250 outer->oppPtTEnd(), inner->oppPtTStart(), inner->oppPtTEnd(),
caryclark27c8eb82015-07-06 11:38:33 -07001251 &overlapS, &overlapE))) {
Cary Clark40f23782016-10-06 12:04:16 -04001252 if (!overlaps->addOverlap(outerCoin, outerOpp, innerCoin, innerOpp,
1253 overlapS, overlapE)) {
1254 return false;
1255 }
Cary Clarke47ae292016-10-05 08:51:39 -04001256 }
caryclark27c8eb82015-07-06 11:38:33 -07001257 }
caryclark55888e42016-07-18 10:01:36 -07001258 outer = outer->next();
caryclark27c8eb82015-07-06 11:38:33 -07001259 }
Cary Clark40f23782016-10-06 12:04:16 -04001260 return true;
caryclark27c8eb82015-07-06 11:38:33 -07001261}
1262
caryclark55888e42016-07-18 10:01:36 -07001263void SkOpCoincidence::fixUp(SkOpPtT* deleted, const SkOpPtT* kept) {
caryclarkb393a492016-09-07 08:21:09 -07001264 SkOPASSERT(deleted != kept);
caryclark55888e42016-07-18 10:01:36 -07001265 if (fHead) {
1266 this->fixUp(fHead, deleted, kept);
caryclark54359292015-03-26 07:52:43 -07001267 }
caryclark55888e42016-07-18 10:01:36 -07001268 if (fTop) {
1269 this->fixUp(fTop, deleted, kept);
1270 }
caryclark54359292015-03-26 07:52:43 -07001271}
1272
caryclark55888e42016-07-18 10:01:36 -07001273void SkOpCoincidence::fixUp(SkCoincidentSpans* coin, SkOpPtT* deleted, const SkOpPtT* kept) {
1274 SkCoincidentSpans* head = coin;
1275 do {
1276 if (coin->coinPtTStart() == deleted) {
1277 if (coin->coinPtTEnd()->span() == kept->span()) {
1278 this->release(head, coin);
1279 continue;
1280 }
1281 coin->setCoinPtTStart(kept);
1282 }
1283 if (coin->coinPtTEnd() == deleted) {
1284 if (coin->coinPtTStart()->span() == kept->span()) {
1285 this->release(head, coin);
1286 continue;
1287 }
1288 coin->setCoinPtTEnd(kept);
1289 }
1290 if (coin->oppPtTStart() == deleted) {
1291 if (coin->oppPtTEnd()->span() == kept->span()) {
1292 this->release(head, coin);
1293 continue;
1294 }
1295 coin->setOppPtTStart(kept);
1296 }
1297 if (coin->oppPtTEnd() == deleted) {
1298 if (coin->oppPtTStart()->span() == kept->span()) {
1299 this->release(head, coin);
1300 continue;
1301 }
1302 coin->setOppPtTEnd(kept);
1303 }
1304 } while ((coin = coin->next()));
1305}
1306
1307// Please keep this in sync with debugMark()
caryclark27c8eb82015-07-06 11:38:33 -07001308/* this sets up the coincidence links in the segments when the coincidence crosses multiple spans */
caryclarke6522ea2016-10-17 07:54:33 -07001309bool SkOpCoincidence::mark(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
Cary Clarkab87d7a2016-10-04 10:01:04 -04001310 DEBUG_SET_PHASE();
caryclark54359292015-03-26 07:52:43 -07001311 SkCoincidentSpans* coin = fHead;
1312 if (!coin) {
caryclarke6522ea2016-10-17 07:54:33 -07001313 return true;
caryclark54359292015-03-26 07:52:43 -07001314 }
1315 do {
caryclarke6522ea2016-10-17 07:54:33 -07001316 SkOpSpanBase* startBase = coin->coinPtTStartWritable()->span();
1317 FAIL_IF(!startBase->upCastable());
1318 SkOpSpan* start = startBase->upCast();
caryclarka35ab3e2016-10-20 08:32:18 -07001319 FAIL_IF(start->deleted());
caryclark55888e42016-07-18 10:01:36 -07001320 SkOpSpanBase* end = coin->coinPtTEndWritable()->span();
Cary Clark40f23782016-10-06 12:04:16 -04001321 SkOPASSERT(!end->deleted());
caryclark55888e42016-07-18 10:01:36 -07001322 SkOpSpanBase* oStart = coin->oppPtTStartWritable()->span();
Cary Clark40f23782016-10-06 12:04:16 -04001323 SkOPASSERT(!oStart->deleted());
caryclark55888e42016-07-18 10:01:36 -07001324 SkOpSpanBase* oEnd = coin->oppPtTEndWritable()->span();
1325 SkASSERT(!oEnd->deleted());
1326 bool flipped = coin->flipped();
caryclark54359292015-03-26 07:52:43 -07001327 if (flipped) {
1328 SkTSwap(oStart, oEnd);
1329 }
caryclark55888e42016-07-18 10:01:36 -07001330 /* coin and opp spans may not match up. Mark the ends, and then let the interior
1331 get marked as many times as the spans allow */
Cary Clark9de09762016-11-17 08:47:37 -05001332 FAIL_IF(!oStart->upCastable());
caryclark55888e42016-07-18 10:01:36 -07001333 start->insertCoincidence(oStart->upCast());
1334 end->insertCoinEnd(oEnd);
1335 const SkOpSegment* segment = start->segment();
1336 const SkOpSegment* oSegment = oStart->segment();
caryclark54359292015-03-26 07:52:43 -07001337 SkOpSpanBase* next = start;
1338 SkOpSpanBase* oNext = oStart;
caryclarka35ab3e2016-10-20 08:32:18 -07001339 bool ordered;
1340 FAIL_IF(!coin->ordered(&ordered));
caryclark55888e42016-07-18 10:01:36 -07001341 while ((next = next->upCast()->next()) != end) {
caryclarke6522ea2016-10-17 07:54:33 -07001342 FAIL_IF(!next->upCastable());
Cary Clark59ed4822016-12-08 16:17:56 -05001343 FAIL_IF(!next->upCast()->insertCoincidence(oSegment, flipped, ordered));
caryclark55888e42016-07-18 10:01:36 -07001344 }
1345 while ((oNext = oNext->upCast()->next()) != oEnd) {
caryclark96dc1c92016-10-20 11:34:10 -07001346 FAIL_IF(!oNext->upCastable());
caryclarke6522ea2016-10-17 07:54:33 -07001347 FAIL_IF(!oNext->upCast()->insertCoincidence(segment, flipped, ordered));
caryclark55888e42016-07-18 10:01:36 -07001348 }
1349 } while ((coin = coin->next()));
caryclarke6522ea2016-10-17 07:54:33 -07001350 return true;
caryclark54359292015-03-26 07:52:43 -07001351}
1352
caryclark55888e42016-07-18 10:01:36 -07001353// Please keep in sync with debugMarkCollapsed()
1354void SkOpCoincidence::markCollapsed(SkCoincidentSpans* coin, SkOpPtT* test) {
1355 SkCoincidentSpans* head = coin;
1356 while (coin) {
1357 if (coin->collapsed(test)) {
1358 if (zero_or_one(coin->coinPtTStart()->fT) && zero_or_one(coin->coinPtTEnd()->fT)) {
1359 coin->coinPtTStartWritable()->segment()->markAllDone();
1360 }
1361 if (zero_or_one(coin->oppPtTStart()->fT) && zero_or_one(coin->oppPtTEnd()->fT)) {
1362 coin->oppPtTStartWritable()->segment()->markAllDone();
1363 }
1364 this->release(head, coin);
1365 }
1366 coin = coin->next();
1367 }
1368}
1369
1370// Please keep in sync with debugMarkCollapsed()
1371void SkOpCoincidence::markCollapsed(SkOpPtT* test) {
1372 markCollapsed(fHead, test);
1373 markCollapsed(fTop, test);
1374}
1375
1376bool SkOpCoincidence::Ordered(const SkOpSegment* coinSeg, const SkOpSegment* oppSeg) {
1377 if (coinSeg->verb() < oppSeg->verb()) {
1378 return true;
1379 }
1380 if (coinSeg->verb() > oppSeg->verb()) {
1381 return false;
1382 }
1383 int count = (SkPathOpsVerbToPoints(coinSeg->verb()) + 1) * 2;
1384 const SkScalar* cPt = &coinSeg->pts()[0].fX;
1385 const SkScalar* oPt = &oppSeg->pts()[0].fX;
1386 for (int index = 0; index < count; ++index) {
1387 if (*cPt < *oPt) {
1388 return true;
1389 }
1390 if (*cPt > *oPt) {
1391 return false;
1392 }
1393 ++cPt;
1394 ++oPt;
1395 }
1396 return true;
1397}
1398
1399bool SkOpCoincidence::overlap(const SkOpPtT* coin1s, const SkOpPtT* coin1e,
caryclark54359292015-03-26 07:52:43 -07001400 const SkOpPtT* coin2s, const SkOpPtT* coin2e, double* overS, double* overE) const {
caryclark27c8eb82015-07-06 11:38:33 -07001401 SkASSERT(coin1s->segment() == coin2s->segment());
caryclark54359292015-03-26 07:52:43 -07001402 *overS = SkTMax(SkTMin(coin1s->fT, coin1e->fT), SkTMin(coin2s->fT, coin2e->fT));
1403 *overE = SkTMin(SkTMax(coin1s->fT, coin1e->fT), SkTMax(coin2s->fT, coin2e->fT));
1404 return *overS < *overE;
1405}
caryclark27c8eb82015-07-06 11:38:33 -07001406
caryclark55888e42016-07-18 10:01:36 -07001407// Commented-out lines keep this in sync with debugRelease()
1408void SkOpCoincidence::release(const SkOpSegment* deleted) {
1409 SkCoincidentSpans* coin = fHead;
1410 if (!coin) {
1411 return;
1412 }
1413 do {
1414 if (coin->coinPtTStart()->segment() == deleted
1415 || coin->coinPtTEnd()->segment() == deleted
1416 || coin->oppPtTStart()->segment() == deleted
1417 || coin->oppPtTEnd()->segment() == deleted) {
1418 this->release(fHead, coin);
1419 }
1420 } while ((coin = coin->next()));
1421}