blob: b4854a801afa7903bf754a340dda90d824341507 [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);
269 SkCoincidentSpans* coinRec = SkOpTAllocator<SkCoincidentSpans>::Allocate(
270 this->globalState()->allocator());
caryclarkfc560e02016-07-27 08:46:10 -0700271 coinRec->init(SkDEBUGCODE(fGlobalState));
Cary Clarkab87d7a2016-10-04 10:01:04 -0400272 coinRec->set(this->fHead, coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd);
caryclark55888e42016-07-18 10:01:36 -0700273 fHead = coinRec;
274}
275
276// description below
caryclark15976282016-07-21 05:48:43 -0700277bool SkOpCoincidence::addEndMovedSpans(const SkOpSpan* base, const SkOpSpanBase* testSpan) {
caryclark55888e42016-07-18 10:01:36 -0700278 const SkOpPtT* testPtT = testSpan->ptT();
279 const SkOpPtT* stopPtT = testPtT;
280 const SkOpSegment* baseSeg = base->segment();
281 while ((testPtT = testPtT->next()) != stopPtT) {
282 const SkOpSegment* testSeg = testPtT->segment();
283 if (testPtT->deleted()) {
284 continue;
285 }
286 if (testSeg == baseSeg) {
287 continue;
288 }
caryclarkc6d855f2016-08-11 11:59:48 -0700289 if (testPtT->span()->ptT() != testPtT) {
290 continue;
291 }
caryclark55888e42016-07-18 10:01:36 -0700292 if (this->contains(baseSeg, testSeg, testPtT->fT)) {
293 continue;
294 }
295 // intersect perp with base->ptT() with testPtT->segment()
296 SkDVector dxdy = baseSeg->dSlopeAtT(base->t());
297 const SkPoint& pt = base->pt();
298 SkDLine ray = {{{pt.fX, pt.fY}, {pt.fX + dxdy.fY, pt.fY - dxdy.fX}}};
Cary Clark4c76c412017-01-20 08:14:33 -0500299 SkIntersections i SkDEBUGCODE((this->globalState()));
caryclark55888e42016-07-18 10:01:36 -0700300 (*CurveIntersectRay[testSeg->verb()])(testSeg->pts(), testSeg->weight(), ray, &i);
301 for (int index = 0; index < i.used(); ++index) {
302 double t = i[0][index];
303 if (!between(0, t, 1)) {
304 continue;
305 }
306 SkDPoint oppPt = i.pt(index);
307 if (!oppPt.approximatelyEqual(pt)) {
308 continue;
309 }
310 SkOpSegment* writableSeg = const_cast<SkOpSegment*>(testSeg);
caryclark29b25632016-08-25 11:27:17 -0700311 SkOpPtT* oppStart = writableSeg->addT(t);
caryclark27c015d2016-09-23 05:47:20 -0700312 if (oppStart == testPtT) {
313 continue;
314 }
caryclark55888e42016-07-18 10:01:36 -0700315 SkOpSpan* writableBase = const_cast<SkOpSpan*>(base);
caryclark30b9fdd2016-08-31 14:36:29 -0700316 oppStart->span()->addOpp(writableBase);
caryclark55888e42016-07-18 10:01:36 -0700317 if (oppStart->deleted()) {
318 continue;
319 }
320 SkOpSegment* coinSeg = base->segment();
321 SkOpSegment* oppSeg = oppStart->segment();
322 double coinTs, coinTe, oppTs, oppTe;
caryclark8016b262016-09-06 05:59:47 -0700323 if (Ordered(coinSeg, oppSeg)) {
caryclark55888e42016-07-18 10:01:36 -0700324 coinTs = base->t();
325 coinTe = testSpan->t();
326 oppTs = oppStart->fT;
327 oppTe = testPtT->fT;
328 } else {
329 SkTSwap(coinSeg, oppSeg);
330 coinTs = oppStart->fT;
331 coinTe = testPtT->fT;
332 oppTs = base->t();
333 oppTe = testSpan->t();
334 }
335 if (coinTs > coinTe) {
336 SkTSwap(coinTs, coinTe);
337 SkTSwap(oppTs, oppTe);
338 }
caryclark81a478c2016-09-09 09:37:57 -0700339 bool added;
340 if (!this->addOrOverlap(coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, &added)) {
caryclark15976282016-07-21 05:48:43 -0700341 return false;
342 }
caryclark55888e42016-07-18 10:01:36 -0700343 }
344 }
caryclark15976282016-07-21 05:48:43 -0700345 return true;
caryclark55888e42016-07-18 10:01:36 -0700346}
347
348// description below
349bool SkOpCoincidence::addEndMovedSpans(const SkOpPtT* ptT) {
caryclark025b11e2016-08-25 05:21:14 -0700350 FAIL_IF(!ptT->span()->upCastable());
caryclark55888e42016-07-18 10:01:36 -0700351 const SkOpSpan* base = ptT->span()->upCast();
352 const SkOpSpan* prev = base->prev();
caryclark025b11e2016-08-25 05:21:14 -0700353 FAIL_IF(!prev);
caryclark55888e42016-07-18 10:01:36 -0700354 if (!prev->isCanceled()) {
caryclark15976282016-07-21 05:48:43 -0700355 if (!this->addEndMovedSpans(base, base->prev())) {
356 return false;
357 }
caryclark55888e42016-07-18 10:01:36 -0700358 }
359 if (!base->isCanceled()) {
caryclark15976282016-07-21 05:48:43 -0700360 if (!this->addEndMovedSpans(base, base->next())) {
361 return false;
362 }
caryclark55888e42016-07-18 10:01:36 -0700363 }
364 return true;
365}
366
367/* If A is coincident with B and B includes an endpoint, and A's matching point
368 is not the endpoint (i.e., there's an implied line connecting B-end and A)
369 then assume that the same implied line may intersect another curve close to B.
370 Since we only care about coincidence that was undetected, look at the
371 ptT list on B-segment adjacent to the B-end/A ptT loop (not in the loop, but
372 next door) and see if the A matching point is close enough to form another
373 coincident pair. If so, check for a new coincident span between B-end/A ptT loop
374 and the adjacent ptT loop.
375*/
Cary Clarkab87d7a2016-10-04 10:01:04 -0400376bool SkOpCoincidence::addEndMovedSpans(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
377 DEBUG_SET_PHASE();
caryclark55888e42016-07-18 10:01:36 -0700378 SkCoincidentSpans* span = fHead;
379 if (!span) {
380 return true;
381 }
382 fTop = span;
383 fHead = nullptr;
384 do {
385 if (span->coinPtTStart()->fPt != span->oppPtTStart()->fPt) {
caryclark025b11e2016-08-25 05:21:14 -0700386 FAIL_IF(1 == span->coinPtTStart()->fT);
caryclark55888e42016-07-18 10:01:36 -0700387 bool onEnd = span->coinPtTStart()->fT == 0;
388 bool oOnEnd = zero_or_one(span->oppPtTStart()->fT);
389 if (onEnd) {
390 if (!oOnEnd) { // if both are on end, any nearby intersect was already found
391 if (!this->addEndMovedSpans(span->oppPtTStart())) {
392 return false;
393 }
394 }
395 } else if (oOnEnd) {
396 if (!this->addEndMovedSpans(span->coinPtTStart())) {
397 return false;
398 }
399 }
400 }
401 if (span->coinPtTEnd()->fPt != span->oppPtTEnd()->fPt) {
402 bool onEnd = span->coinPtTEnd()->fT == 1;
403 bool oOnEnd = zero_or_one(span->oppPtTEnd()->fT);
404 if (onEnd) {
405 if (!oOnEnd) {
406 if (!this->addEndMovedSpans(span->oppPtTEnd())) {
407 return false;
408 }
409 }
410 } else if (oOnEnd) {
411 if (!this->addEndMovedSpans(span->coinPtTEnd())) {
412 return false;
413 }
414 }
415 }
416 } while ((span = span->next()));
417 this->restoreHead();
418 return true;
419}
420
421/* Please keep this in sync with debugAddExpanded */
422// for each coincident pair, match the spans
423// 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 -0400424bool SkOpCoincidence::addExpanded(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
425 DEBUG_SET_PHASE();
caryclark55888e42016-07-18 10:01:36 -0700426 SkCoincidentSpans* coin = this->fHead;
427 if (!coin) {
428 return true;
429 }
430 do {
431 const SkOpPtT* startPtT = coin->coinPtTStart();
432 const SkOpPtT* oStartPtT = coin->oppPtTStart();
caryclark8016b262016-09-06 05:59:47 -0700433 double priorT = startPtT->fT;
434 double oPriorT = oStartPtT->fT;
caryclarkbbfe92b2016-09-19 06:00:35 -0700435 FAIL_IF(!startPtT->contains(oStartPtT));
caryclarkc6d855f2016-08-11 11:59:48 -0700436 SkOPASSERT(coin->coinPtTEnd()->contains(coin->oppPtTEnd()));
caryclark55888e42016-07-18 10:01:36 -0700437 const SkOpSpanBase* start = startPtT->span();
438 const SkOpSpanBase* oStart = oStartPtT->span();
439 const SkOpSpanBase* end = coin->coinPtTEnd()->span();
440 const SkOpSpanBase* oEnd = coin->oppPtTEnd()->span();
441 FAIL_IF(oEnd->deleted());
caryclarke25a4f62016-07-26 09:26:29 -0700442 FAIL_IF(!start->upCastable());
caryclark55888e42016-07-18 10:01:36 -0700443 const SkOpSpanBase* test = start->upCast()->next();
caryclarke7bb5b22016-09-22 05:20:07 -0700444 FAIL_IF(!coin->flipped() && !oStart->upCastable());
caryclark55888e42016-07-18 10:01:36 -0700445 const SkOpSpanBase* oTest = coin->flipped() ? oStart->prev() : oStart->upCast()->next();
caryclark30b9fdd2016-08-31 14:36:29 -0700446 FAIL_IF(!oTest);
caryclark8016b262016-09-06 05:59:47 -0700447 SkOpSegment* seg = start->segment();
448 SkOpSegment* oSeg = oStart->segment();
caryclark55888e42016-07-18 10:01:36 -0700449 while (test != end || oTest != oEnd) {
caryclark8016b262016-09-06 05:59:47 -0700450 const SkOpPtT* containedOpp = test->ptT()->contains(oSeg);
451 const SkOpPtT* containedThis = oTest->ptT()->contains(seg);
452 if (!containedOpp || !containedThis) {
453 // choose the ends, or the first common pt-t list shared by both
454 double nextT, oNextT;
455 if (containedOpp) {
456 nextT = test->t();
457 oNextT = containedOpp->fT;
458 } else if (containedThis) {
459 nextT = containedThis->fT;
460 oNextT = oTest->t();
461 } else {
462 // iterate through until a pt-t list found that contains the other
463 const SkOpSpanBase* walk = test;
464 const SkOpPtT* walkOpp;
465 do {
466 FAIL_IF(!walk->upCastable());
467 walk = walk->upCast()->next();
468 } while (!(walkOpp = walk->ptT()->contains(oSeg))
469 && walk != coin->coinPtTEnd()->span());
Cary Clark3fdf52c2016-10-04 10:53:31 -0400470 FAIL_IF(!walkOpp);
caryclark8016b262016-09-06 05:59:47 -0700471 nextT = walk->t();
472 oNextT = walkOpp->fT;
473 }
caryclark55888e42016-07-18 10:01:36 -0700474 // use t ranges to guess which one is missing
caryclark8016b262016-09-06 05:59:47 -0700475 double startRange = nextT - priorT;
caryclark55888e42016-07-18 10:01:36 -0700476 FAIL_IF(!startRange);
caryclark8016b262016-09-06 05:59:47 -0700477 double startPart = (test->t() - priorT) / startRange;
478 double oStartRange = oNextT - oPriorT;
caryclark55888e42016-07-18 10:01:36 -0700479 FAIL_IF(!oStartRange);
caryclark8016b262016-09-06 05:59:47 -0700480 double oStartPart = (oTest->t() - oPriorT) / oStartRange;
caryclark55888e42016-07-18 10:01:36 -0700481 FAIL_IF(startPart == oStartPart);
caryclark8016b262016-09-06 05:59:47 -0700482 bool addToOpp = !containedOpp && !containedThis ? startPart < oStartPart
483 : !!containedThis;
caryclark55888e42016-07-18 10:01:36 -0700484 bool startOver = false;
caryclark8016b262016-09-06 05:59:47 -0700485 bool success = addToOpp ? oSeg->addExpanded(
486 oPriorT + oStartRange * startPart, test, &startOver)
487 : seg->addExpanded(
488 priorT + startRange * oStartPart, oTest, &startOver);
caryclark30b9fdd2016-08-31 14:36:29 -0700489 FAIL_IF(!success);
caryclark55888e42016-07-18 10:01:36 -0700490 if (startOver) {
491 test = start;
492 oTest = oStart;
493 }
caryclark30b9fdd2016-08-31 14:36:29 -0700494 end = coin->coinPtTEnd()->span();
495 oEnd = coin->oppPtTEnd()->span();
caryclark55888e42016-07-18 10:01:36 -0700496 }
497 if (test != end) {
caryclark30b9fdd2016-08-31 14:36:29 -0700498 FAIL_IF(!test->upCastable());
caryclark8016b262016-09-06 05:59:47 -0700499 priorT = test->t();
caryclark55888e42016-07-18 10:01:36 -0700500 test = test->upCast()->next();
501 }
502 if (oTest != oEnd) {
caryclark8016b262016-09-06 05:59:47 -0700503 oPriorT = oTest->t();
caryclark78a37a52016-10-20 12:36:16 -0700504 if (coin->flipped()) {
505 oTest = oTest->prev();
506 } else {
507 FAIL_IF(!oTest->upCastable());
508 oTest = oTest->upCast()->next();
509 }
caryclark30b9fdd2016-08-31 14:36:29 -0700510 FAIL_IF(!oTest);
caryclark55888e42016-07-18 10:01:36 -0700511 }
caryclark8016b262016-09-06 05:59:47 -0700512
caryclark55888e42016-07-18 10:01:36 -0700513 }
514 } while ((coin = coin->next()));
515 return true;
516}
517
caryclark55888e42016-07-18 10:01:36 -0700518// given a t span, map the same range on the coincident span
caryclark8016b262016-09-06 05:59:47 -0700519/*
520the curves may not scale linearly, so interpolation may only happen within known points
521remap over1s, over1e, cointPtTStart, coinPtTEnd to smallest range that captures over1s
522then repeat to capture over1e
523*/
524double SkOpCoincidence::TRange(const SkOpPtT* overS, double t,
525 const SkOpSegment* coinSeg SkDEBUGPARAMS(const SkOpPtT* overE)) {
526 const SkOpSpanBase* work = overS->span();
527 const SkOpPtT* foundStart = nullptr;
528 const SkOpPtT* foundEnd = nullptr;
529 const SkOpPtT* coinStart = nullptr;
530 const SkOpPtT* coinEnd = nullptr;
531 do {
532 const SkOpPtT* contained = work->contains(coinSeg);
533 if (!contained) {
caryclarkc9b90d12016-09-09 07:41:36 -0700534 if (work->final()) {
535 break;
caryclarkb393a492016-09-07 08:21:09 -0700536 }
caryclark8016b262016-09-06 05:59:47 -0700537 continue;
538 }
539 if (work->t() <= t) {
540 coinStart = contained;
541 foundStart = work->ptT();
542 }
543 if (work->t() >= t) {
544 coinEnd = contained;
545 foundEnd = work->ptT();
546 break;
547 }
548 SkASSERT(work->ptT() != overE);
549 } while ((work = work->upCast()->next()));
caryclarkc9b90d12016-09-09 07:41:36 -0700550 if (!coinStart || !coinEnd) {
551 return 1;
552 }
caryclark8016b262016-09-06 05:59:47 -0700553 // while overS->fT <=t and overS contains coinSeg
554 double denom = foundEnd->fT - foundStart->fT;
555 double sRatio = denom ? (t - foundStart->fT) / denom : 1;
556 return coinStart->fT + (coinEnd->fT - coinStart->fT) * sRatio;
caryclark54359292015-03-26 07:52:43 -0700557}
558
caryclark55888e42016-07-18 10:01:36 -0700559// return true if span overlaps existing and needs to adjust the coincident list
560bool SkOpCoincidence::checkOverlap(SkCoincidentSpans* check,
561 const SkOpSegment* coinSeg, const SkOpSegment* oppSeg,
562 double coinTs, double coinTe, double oppTs, double oppTe,
563 SkTDArray<SkCoincidentSpans*>* overlaps) const {
564 if (!Ordered(coinSeg, oppSeg)) {
565 if (oppTs < oppTe) {
566 return this->checkOverlap(check, oppSeg, coinSeg, oppTs, oppTe, coinTs, coinTe,
567 overlaps);
568 }
569 return this->checkOverlap(check, oppSeg, coinSeg, oppTe, oppTs, coinTe, coinTs, overlaps);
570 }
571 bool swapOpp = oppTs > oppTe;
572 if (swapOpp) {
573 SkTSwap(oppTs, oppTe);
574 }
caryclark27c8eb82015-07-06 11:38:33 -0700575 do {
caryclark55888e42016-07-18 10:01:36 -0700576 if (check->coinPtTStart()->segment() != coinSeg) {
577 continue;
caryclark1c9ce612015-11-20 14:06:28 -0800578 }
caryclark55888e42016-07-18 10:01:36 -0700579 if (check->oppPtTStart()->segment() != oppSeg) {
580 continue;
caryclarkdae6b972016-06-08 04:28:19 -0700581 }
caryclark55888e42016-07-18 10:01:36 -0700582 double checkTs = check->coinPtTStart()->fT;
583 double checkTe = check->coinPtTEnd()->fT;
584 bool coinOutside = coinTe < checkTs || coinTs > checkTe;
585 double oCheckTs = check->oppPtTStart()->fT;
586 double oCheckTe = check->oppPtTEnd()->fT;
587 if (swapOpp) {
588 if (oCheckTs <= oCheckTe) {
caryclark81a478c2016-09-09 09:37:57 -0700589 return false;
caryclark27c8eb82015-07-06 11:38:33 -0700590 }
caryclark55888e42016-07-18 10:01:36 -0700591 SkTSwap(oCheckTs, oCheckTe);
caryclark27c8eb82015-07-06 11:38:33 -0700592 }
caryclark55888e42016-07-18 10:01:36 -0700593 bool oppOutside = oppTe < oCheckTs || oppTs > oCheckTe;
594 if (coinOutside && oppOutside) {
595 continue;
596 }
597 bool coinInside = coinTe <= checkTe && coinTs >= checkTs;
598 bool oppInside = oppTe <= oCheckTe && oppTs >= oCheckTs;
caryclark81a478c2016-09-09 09:37:57 -0700599 if (coinInside && oppInside) { // already included, do nothing
600 return false;
caryclark55888e42016-07-18 10:01:36 -0700601 }
602 *overlaps->append() = check; // partial overlap, extend existing entry
603 } while ((check = check->next()));
caryclark26ad22a2015-10-16 09:03:38 -0700604 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700605}
606
caryclark55888e42016-07-18 10:01:36 -0700607/* Please keep this in sync with debugAddIfMissing() */
caryclark8016b262016-09-06 05:59:47 -0700608// note that over1s, over1e, over2s, over2e are ordered
609bool SkOpCoincidence::addIfMissing(const SkOpPtT* over1s, const SkOpPtT* over2s,
caryclark81a478c2016-09-09 09:37:57 -0700610 double tStart, double tEnd, SkOpSegment* coinSeg, SkOpSegment* oppSeg, bool* added
caryclark8016b262016-09-06 05:59:47 -0700611 SkDEBUGPARAMS(const SkOpPtT* over1e) SkDEBUGPARAMS(const SkOpPtT* over2e)) {
612 SkASSERT(tStart < tEnd);
613 SkASSERT(over1s->fT < over1e->fT);
614 SkASSERT(between(over1s->fT, tStart, over1e->fT));
615 SkASSERT(between(over1s->fT, tEnd, over1e->fT));
616 SkASSERT(over2s->fT < over2e->fT);
617 SkASSERT(between(over2s->fT, tStart, over2e->fT));
618 SkASSERT(between(over2s->fT, tEnd, over2e->fT));
619 SkASSERT(over1s->segment() == over1e->segment());
620 SkASSERT(over2s->segment() == over2e->segment());
621 SkASSERT(over1s->segment() == over2s->segment());
622 SkASSERT(over1s->segment() != coinSeg);
623 SkASSERT(over1s->segment() != oppSeg);
624 SkASSERT(coinSeg != oppSeg);
caryclark54359292015-03-26 07:52:43 -0700625 double coinTs, coinTe, oppTs, oppTe;
caryclark8016b262016-09-06 05:59:47 -0700626 coinTs = TRange(over1s, tStart, coinSeg SkDEBUGPARAMS(over1e));
627 coinTe = TRange(over1s, tEnd, coinSeg SkDEBUGPARAMS(over1e));
caryclark30b9fdd2016-08-31 14:36:29 -0700628 if (coinSeg->collapsed(coinTs, coinTe)) {
caryclark81a478c2016-09-09 09:37:57 -0700629 return true;
caryclark30b9fdd2016-08-31 14:36:29 -0700630 }
caryclark8016b262016-09-06 05:59:47 -0700631 oppTs = TRange(over2s, tStart, oppSeg SkDEBUGPARAMS(over2e));
632 oppTe = TRange(over2s, tEnd, oppSeg SkDEBUGPARAMS(over2e));
caryclark30b9fdd2016-08-31 14:36:29 -0700633 if (oppSeg->collapsed(oppTs, oppTe)) {
caryclark81a478c2016-09-09 09:37:57 -0700634 return true;
caryclark30b9fdd2016-08-31 14:36:29 -0700635 }
caryclark8016b262016-09-06 05:59:47 -0700636 if (coinTs > coinTe) {
caryclark55888e42016-07-18 10:01:36 -0700637 SkTSwap(coinTs, coinTe);
caryclark54359292015-03-26 07:52:43 -0700638 SkTSwap(oppTs, oppTe);
639 }
caryclark81a478c2016-09-09 09:37:57 -0700640 return this->addOrOverlap(coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, added);
caryclark54359292015-03-26 07:52:43 -0700641}
642
caryclark55888e42016-07-18 10:01:36 -0700643/* Please keep this in sync with debugAddOrOverlap() */
caryclark025b11e2016-08-25 05:21:14 -0700644// If this is called by addEndMovedSpans(), a returned false propogates out to an abort.
645// If this is called by AddIfMissing(), a returned false indicates there was nothing to add
caryclark55888e42016-07-18 10:01:36 -0700646bool SkOpCoincidence::addOrOverlap(SkOpSegment* coinSeg, SkOpSegment* oppSeg,
caryclark81a478c2016-09-09 09:37:57 -0700647 double coinTs, double coinTe, double oppTs, double oppTe, bool* added) {
caryclark55888e42016-07-18 10:01:36 -0700648 SkTDArray<SkCoincidentSpans*> overlaps;
caryclark81a478c2016-09-09 09:37:57 -0700649 FAIL_IF(!fTop);
caryclark55888e42016-07-18 10:01:36 -0700650 if (!this->checkOverlap(fTop, coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, &overlaps)) {
caryclark81a478c2016-09-09 09:37:57 -0700651 return true;
caryclark55888e42016-07-18 10:01:36 -0700652 }
653 if (fHead && !this->checkOverlap(fHead, coinSeg, oppSeg, coinTs,
654 coinTe, oppTs, oppTe, &overlaps)) {
caryclark81a478c2016-09-09 09:37:57 -0700655 return true;
caryclark55888e42016-07-18 10:01:36 -0700656 }
657 SkCoincidentSpans* overlap = overlaps.count() ? overlaps[0] : nullptr;
658 for (int index = 1; index < overlaps.count(); ++index) { // combine overlaps before continuing
659 SkCoincidentSpans* test = overlaps[index];
660 if (overlap->coinPtTStart()->fT > test->coinPtTStart()->fT) {
661 overlap->setCoinPtTStart(test->coinPtTStart());
662 }
663 if (overlap->coinPtTEnd()->fT < test->coinPtTEnd()->fT) {
664 overlap->setCoinPtTEnd(test->coinPtTEnd());
665 }
666 if (overlap->flipped()
667 ? overlap->oppPtTStart()->fT < test->oppPtTStart()->fT
668 : overlap->oppPtTStart()->fT > test->oppPtTStart()->fT) {
669 overlap->setOppPtTStart(test->oppPtTStart());
670 }
671 if (overlap->flipped()
672 ? overlap->oppPtTEnd()->fT > test->oppPtTEnd()->fT
673 : overlap->oppPtTEnd()->fT < test->oppPtTEnd()->fT) {
674 overlap->setOppPtTEnd(test->oppPtTEnd());
675 }
676 if (!fHead || !this->release(fHead, test)) {
677 SkAssertResult(this->release(fTop, test));
678 }
679 }
680 const SkOpPtT* cs = coinSeg->existing(coinTs, oppSeg);
681 const SkOpPtT* ce = coinSeg->existing(coinTe, oppSeg);
caryclark81a478c2016-09-09 09:37:57 -0700682 if (overlap && cs && ce && overlap->contains(cs, ce)) {
683 return true;
684 }
685 FAIL_IF(cs == ce && cs);
caryclark55888e42016-07-18 10:01:36 -0700686 const SkOpPtT* os = oppSeg->existing(oppTs, coinSeg);
687 const SkOpPtT* oe = oppSeg->existing(oppTe, coinSeg);
caryclark81a478c2016-09-09 09:37:57 -0700688 if (overlap && os && oe && overlap->contains(os, oe)) {
689 return true;
690 }
caryclark55888e42016-07-18 10:01:36 -0700691 SkASSERT(!cs || !cs->deleted());
692 SkASSERT(!os || !os->deleted());
693 SkASSERT(!ce || !ce->deleted());
694 SkASSERT(!oe || !oe->deleted());
695 const SkOpPtT* csExisting = !cs ? coinSeg->existing(coinTs, nullptr) : nullptr;
696 const SkOpPtT* ceExisting = !ce ? coinSeg->existing(coinTe, nullptr) : nullptr;
caryclark81a478c2016-09-09 09:37:57 -0700697 FAIL_IF(csExisting && csExisting == ceExisting);
caryclarke839e782016-09-15 07:48:18 -0700698// FAIL_IF(csExisting && (csExisting == ce ||
699// csExisting->contains(ceExisting ? ceExisting : ce)));
caryclark81a478c2016-09-09 09:37:57 -0700700 FAIL_IF(ceExisting && (ceExisting == cs ||
caryclark025b11e2016-08-25 05:21:14 -0700701 ceExisting->contains(csExisting ? csExisting : cs)));
caryclark55888e42016-07-18 10:01:36 -0700702 const SkOpPtT* osExisting = !os ? oppSeg->existing(oppTs, nullptr) : nullptr;
703 const SkOpPtT* oeExisting = !oe ? oppSeg->existing(oppTe, nullptr) : nullptr;
caryclark81a478c2016-09-09 09:37:57 -0700704 FAIL_IF(osExisting && osExisting == oeExisting);
705 FAIL_IF(osExisting && (osExisting == oe ||
caryclark025b11e2016-08-25 05:21:14 -0700706 osExisting->contains(oeExisting ? oeExisting : oe)));
caryclark81a478c2016-09-09 09:37:57 -0700707 FAIL_IF(oeExisting && (oeExisting == os ||
caryclark025b11e2016-08-25 05:21:14 -0700708 oeExisting->contains(osExisting ? osExisting : os)));
caryclark55888e42016-07-18 10:01:36 -0700709 // extra line in debug code
710 this->debugValidate();
711 if (!cs || !os) {
712 SkOpPtT* csWritable = cs ? const_cast<SkOpPtT*>(cs)
caryclark29b25632016-08-25 11:27:17 -0700713 : coinSeg->addT(coinTs);
caryclarke839e782016-09-15 07:48:18 -0700714 if (csWritable == ce) {
715 return true;
716 }
caryclark55888e42016-07-18 10:01:36 -0700717 SkOpPtT* osWritable = os ? const_cast<SkOpPtT*>(os)
caryclark29b25632016-08-25 11:27:17 -0700718 : oppSeg->addT(oppTs);
caryclark81a478c2016-09-09 09:37:57 -0700719 FAIL_IF(!csWritable || !osWritable);
caryclark30b9fdd2016-08-31 14:36:29 -0700720 csWritable->span()->addOpp(osWritable->span());
caryclark55888e42016-07-18 10:01:36 -0700721 cs = csWritable;
caryclark30b9fdd2016-08-31 14:36:29 -0700722 os = osWritable->active();
caryclark81a478c2016-09-09 09:37:57 -0700723 FAIL_IF((ce && ce->deleted()) || (oe && oe->deleted()));
caryclark55888e42016-07-18 10:01:36 -0700724 }
725 if (!ce || !oe) {
726 SkOpPtT* ceWritable = ce ? const_cast<SkOpPtT*>(ce)
caryclark29b25632016-08-25 11:27:17 -0700727 : coinSeg->addT(coinTe);
caryclark55888e42016-07-18 10:01:36 -0700728 SkOpPtT* oeWritable = oe ? const_cast<SkOpPtT*>(oe)
caryclark29b25632016-08-25 11:27:17 -0700729 : oppSeg->addT(oppTe);
caryclark30b9fdd2016-08-31 14:36:29 -0700730 ceWritable->span()->addOpp(oeWritable->span());
caryclark55888e42016-07-18 10:01:36 -0700731 ce = ceWritable;
732 oe = oeWritable;
733 }
734 this->debugValidate();
caryclark81a478c2016-09-09 09:37:57 -0700735 FAIL_IF(cs->deleted());
736 FAIL_IF(os->deleted());
737 FAIL_IF(ce->deleted());
738 FAIL_IF(oe->deleted());
739 FAIL_IF(cs->contains(ce) || os->contains(oe));
caryclark55888e42016-07-18 10:01:36 -0700740 bool result = true;
741 if (overlap) {
742 if (overlap->coinPtTStart()->segment() == coinSeg) {
743 result = overlap->extend(cs, ce, os, oe);
744 } else {
745 if (os->fT > oe->fT) {
746 SkTSwap(cs, ce);
747 SkTSwap(os, oe);
748 }
749 result = overlap->extend(os, oe, cs, ce);
750 }
751#if DEBUG_COINCIDENCE_VERBOSE
752 if (result) {
753 overlaps[0]->debugShow();
754 }
755#endif
756 } else {
757 this->add(cs, ce, os, oe);
758#if DEBUG_COINCIDENCE_VERBOSE
759 fHead->debugShow();
760#endif
761 }
762 this->debugValidate();
caryclark81a478c2016-09-09 09:37:57 -0700763 if (result) {
764 *added = true;
765 }
766 return true;
caryclark55888e42016-07-18 10:01:36 -0700767}
768
769// Please keep this in sync with debugAddMissing()
caryclark27c8eb82015-07-06 11:38:33 -0700770/* detects overlaps of different coincident runs on same segment */
771/* does not detect overlaps for pairs without any segments in common */
caryclark55888e42016-07-18 10:01:36 -0700772// returns true if caller should loop again
Cary Clarkab87d7a2016-10-04 10:01:04 -0400773bool SkOpCoincidence::addMissing(bool* added DEBUG_COIN_DECLARE_PARAMS()) {
caryclark27c8eb82015-07-06 11:38:33 -0700774 SkCoincidentSpans* outer = fHead;
caryclark81a478c2016-09-09 09:37:57 -0700775 *added = false;
caryclark54359292015-03-26 07:52:43 -0700776 if (!outer) {
caryclark81a478c2016-09-09 09:37:57 -0700777 return true;
caryclark54359292015-03-26 07:52:43 -0700778 }
caryclark27c8eb82015-07-06 11:38:33 -0700779 fTop = outer;
halcanary96fcdcc2015-08-27 07:41:13 -0700780 fHead = nullptr;
caryclark54359292015-03-26 07:52:43 -0700781 do {
caryclark27c8eb82015-07-06 11:38:33 -0700782 // addifmissing can modify the list that this is walking
caryclark26ad22a2015-10-16 09:03:38 -0700783 // save head so that walker can iterate over old data unperturbed
784 // addifmissing adds to head freely then add saved head in the end
caryclark8016b262016-09-06 05:59:47 -0700785 const SkOpPtT* ocs = outer->coinPtTStart();
caryclarka35ab3e2016-10-20 08:32:18 -0700786 FAIL_IF(ocs->deleted());
caryclark8016b262016-09-06 05:59:47 -0700787 const SkOpSegment* outerCoin = ocs->segment();
788 SkASSERT(!outerCoin->done()); // if it's done, should have already been removed from list
789 const SkOpPtT* oos = outer->oppPtTStart();
caryclarkb393a492016-09-07 08:21:09 -0700790 if (oos->deleted()) {
caryclark81a478c2016-09-09 09:37:57 -0700791 return true;
caryclarkb393a492016-09-07 08:21:09 -0700792 }
caryclark8016b262016-09-06 05:59:47 -0700793 const SkOpSegment* outerOpp = oos->segment();
Cary Clark4c76c412017-01-20 08:14:33 -0500794 SkOPASSERT(!outerOpp->done());
caryclark8016b262016-09-06 05:59:47 -0700795 SkOpSegment* outerCoinWritable = const_cast<SkOpSegment*>(outerCoin);
796 SkOpSegment* outerOppWritable = const_cast<SkOpSegment*>(outerOpp);
caryclark54359292015-03-26 07:52:43 -0700797 SkCoincidentSpans* inner = outer;
caryclark55888e42016-07-18 10:01:36 -0700798 while ((inner = inner->next())) {
799 this->debugValidate();
caryclark54359292015-03-26 07:52:43 -0700800 double overS, overE;
caryclark8016b262016-09-06 05:59:47 -0700801 const SkOpPtT* ics = inner->coinPtTStart();
caryclark221a4bb2016-10-07 11:15:15 -0700802 FAIL_IF(ics->deleted());
caryclark8016b262016-09-06 05:59:47 -0700803 const SkOpSegment* innerCoin = ics->segment();
caryclarka35ab3e2016-10-20 08:32:18 -0700804 FAIL_IF(innerCoin->done());
caryclark8016b262016-09-06 05:59:47 -0700805 const SkOpPtT* ios = inner->oppPtTStart();
caryclarka35ab3e2016-10-20 08:32:18 -0700806 FAIL_IF(ios->deleted());
caryclark8016b262016-09-06 05:59:47 -0700807 const SkOpSegment* innerOpp = ios->segment();
Cary Clark4c76c412017-01-20 08:14:33 -0500808 SkOPASSERT(!innerOpp->done());
caryclark8016b262016-09-06 05:59:47 -0700809 SkOpSegment* innerCoinWritable = const_cast<SkOpSegment*>(innerCoin);
810 SkOpSegment* innerOppWritable = const_cast<SkOpSegment*>(innerOpp);
caryclark55888e42016-07-18 10:01:36 -0700811 if (outerCoin == innerCoin) {
caryclark8016b262016-09-06 05:59:47 -0700812 const SkOpPtT* oce = outer->coinPtTEnd();
caryclarkb393a492016-09-07 08:21:09 -0700813 if (oce->deleted()) {
caryclark81a478c2016-09-09 09:37:57 -0700814 return true;
caryclarkb393a492016-09-07 08:21:09 -0700815 }
caryclark8016b262016-09-06 05:59:47 -0700816 const SkOpPtT* ice = inner->coinPtTEnd();
caryclark595ac282016-10-24 08:41:45 -0700817 FAIL_IF(ice->deleted());
caryclark8016b262016-09-06 05:59:47 -0700818 if (outerOpp != innerOpp && this->overlap(ocs, oce, ics, ice, &overS, &overE)) {
caryclark81a478c2016-09-09 09:37:57 -0700819 (void) this->addIfMissing(ocs->starter(oce), ics->starter(ice),
820 overS, overE, outerOppWritable, innerOppWritable, added
caryclark8016b262016-09-06 05:59:47 -0700821 SkDEBUGPARAMS(ocs->debugEnder(oce))
822 SkDEBUGPARAMS(ics->debugEnder(ice)));
caryclark55888e42016-07-18 10:01:36 -0700823 }
824 } else if (outerCoin == innerOpp) {
caryclark8016b262016-09-06 05:59:47 -0700825 const SkOpPtT* oce = outer->coinPtTEnd();
826 SkASSERT(!oce->deleted());
827 const SkOpPtT* ioe = inner->oppPtTEnd();
828 SkASSERT(!ioe->deleted());
829 if (outerOpp != innerCoin && this->overlap(ocs, oce, ios, ioe, &overS, &overE)) {
caryclark81a478c2016-09-09 09:37:57 -0700830 (void) this->addIfMissing(ocs->starter(oce), ios->starter(ioe),
831 overS, overE, outerOppWritable, innerCoinWritable, added
caryclark8016b262016-09-06 05:59:47 -0700832 SkDEBUGPARAMS(ocs->debugEnder(oce))
833 SkDEBUGPARAMS(ios->debugEnder(ioe)));
caryclark55888e42016-07-18 10:01:36 -0700834 }
835 } else if (outerOpp == innerCoin) {
caryclark8016b262016-09-06 05:59:47 -0700836 const SkOpPtT* ooe = outer->oppPtTEnd();
837 SkASSERT(!ooe->deleted());
838 const SkOpPtT* ice = inner->coinPtTEnd();
839 SkASSERT(!ice->deleted());
caryclark55888e42016-07-18 10:01:36 -0700840 SkASSERT(outerCoin != innerOpp);
caryclark8016b262016-09-06 05:59:47 -0700841 if (this->overlap(oos, ooe, ics, ice, &overS, &overE)) {
caryclark81a478c2016-09-09 09:37:57 -0700842 (void) this->addIfMissing(oos->starter(ooe), ics->starter(ice),
843 overS, overE, outerCoinWritable, innerOppWritable, added
caryclark8016b262016-09-06 05:59:47 -0700844 SkDEBUGPARAMS(oos->debugEnder(ooe))
845 SkDEBUGPARAMS(ics->debugEnder(ice)));
caryclark55888e42016-07-18 10:01:36 -0700846 }
847 } else if (outerOpp == innerOpp) {
caryclark8016b262016-09-06 05:59:47 -0700848 const SkOpPtT* ooe = outer->oppPtTEnd();
849 SkASSERT(!ooe->deleted());
850 const SkOpPtT* ioe = inner->oppPtTEnd();
caryclarkb393a492016-09-07 08:21:09 -0700851 if (ioe->deleted()) {
caryclark81a478c2016-09-09 09:37:57 -0700852 return true;
caryclarkb393a492016-09-07 08:21:09 -0700853 }
caryclark55888e42016-07-18 10:01:36 -0700854 SkASSERT(outerCoin != innerCoin);
caryclark8016b262016-09-06 05:59:47 -0700855 if (this->overlap(oos, ooe, ios, ioe, &overS, &overE)) {
caryclark81a478c2016-09-09 09:37:57 -0700856 (void) this->addIfMissing(oos->starter(ooe), ios->starter(ioe),
857 overS, overE, outerCoinWritable, innerCoinWritable, added
caryclark8016b262016-09-06 05:59:47 -0700858 SkDEBUGPARAMS(oos->debugEnder(ooe))
859 SkDEBUGPARAMS(ios->debugEnder(ioe)));
caryclark54359292015-03-26 07:52:43 -0700860 }
861 }
caryclark55888e42016-07-18 10:01:36 -0700862 this->debugValidate();
caryclark54359292015-03-26 07:52:43 -0700863 }
caryclark55888e42016-07-18 10:01:36 -0700864 } while ((outer = outer->next()));
865 this->restoreHead();
caryclark81a478c2016-09-09 09:37:57 -0700866 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700867}
868
caryclark55888e42016-07-18 10:01:36 -0700869bool SkOpCoincidence::addOverlap(const SkOpSegment* seg1, const SkOpSegment* seg1o,
870 const SkOpSegment* seg2, const SkOpSegment* seg2o,
871 const SkOpPtT* overS, const SkOpPtT* overE) {
Cary Clarke47ae292016-10-05 08:51:39 -0400872 const SkOpPtT* s1 = overS->find(seg1);
873 const SkOpPtT* e1 = overE->find(seg1);
caryclark08714012016-10-07 12:57:47 -0700874 FAIL_IF(!s1);
Cary Clark40f23782016-10-06 12:04:16 -0400875 FAIL_IF(!e1);
caryclark27c8eb82015-07-06 11:38:33 -0700876 if (!s1->starter(e1)->span()->upCast()->windValue()) {
Cary Clarke47ae292016-10-05 08:51:39 -0400877 s1 = overS->find(seg1o);
878 e1 = overE->find(seg1o);
caryclark221a4bb2016-10-07 11:15:15 -0700879 FAIL_IF(!s1);
Cary Clark40f23782016-10-06 12:04:16 -0400880 FAIL_IF(!e1);
caryclark27c8eb82015-07-06 11:38:33 -0700881 if (!s1->starter(e1)->span()->upCast()->windValue()) {
caryclark3f0753d2016-06-28 09:23:57 -0700882 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700883 }
884 }
Cary Clarke47ae292016-10-05 08:51:39 -0400885 const SkOpPtT* s2 = overS->find(seg2);
886 const SkOpPtT* e2 = overE->find(seg2);
caryclark82616712016-10-24 04:53:22 -0700887 FAIL_IF(!s2);
caryclarka35ab3e2016-10-20 08:32:18 -0700888 FAIL_IF(!e2);
caryclark27c8eb82015-07-06 11:38:33 -0700889 if (!s2->starter(e2)->span()->upCast()->windValue()) {
Cary Clarke47ae292016-10-05 08:51:39 -0400890 s2 = overS->find(seg2o);
891 e2 = overE->find(seg2o);
caryclarka35ab3e2016-10-20 08:32:18 -0700892 FAIL_IF(!s2);
caryclark78a37a52016-10-20 12:36:16 -0700893 FAIL_IF(!e2);
caryclark27c8eb82015-07-06 11:38:33 -0700894 if (!s2->starter(e2)->span()->upCast()->windValue()) {
caryclark3f0753d2016-06-28 09:23:57 -0700895 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700896 }
897 }
898 if (s1->segment() == s2->segment()) {
caryclark3f0753d2016-06-28 09:23:57 -0700899 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700900 }
901 if (s1->fT > e1->fT) {
902 SkTSwap(s1, e1);
903 SkTSwap(s2, e2);
904 }
caryclark55888e42016-07-18 10:01:36 -0700905 this->add(s1, e1, s2, e2);
caryclark3f0753d2016-06-28 09:23:57 -0700906 return true;
caryclark54359292015-03-26 07:52:43 -0700907}
908
caryclark55888e42016-07-18 10:01:36 -0700909bool SkOpCoincidence::contains(const SkOpSegment* seg, const SkOpSegment* opp, double oppT) const {
910 if (this->contains(fHead, seg, opp, oppT)) {
911 return true;
912 }
913 if (this->contains(fTop, seg, opp, oppT)) {
914 return true;
915 }
916 return false;
917}
918
919bool SkOpCoincidence::contains(const SkCoincidentSpans* coin, const SkOpSegment* seg,
920 const SkOpSegment* opp, double oppT) const {
921 if (!coin) {
922 return false;
923 }
924 do {
925 if (coin->coinPtTStart()->segment() == seg && coin->oppPtTStart()->segment() == opp
926 && between(coin->oppPtTStart()->fT, oppT, coin->oppPtTEnd()->fT)) {
caryclark54359292015-03-26 07:52:43 -0700927 return true;
928 }
caryclark55888e42016-07-18 10:01:36 -0700929 if (coin->oppPtTStart()->segment() == seg && coin->coinPtTStart()->segment() == opp
930 && between(coin->coinPtTStart()->fT, oppT, coin->coinPtTEnd()->fT)) {
931 return true;
932 }
933 } while ((coin = coin->next()));
caryclark54359292015-03-26 07:52:43 -0700934 return false;
935}
936
caryclark55888e42016-07-18 10:01:36 -0700937bool SkOpCoincidence::contains(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd,
938 const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) const {
939 const SkCoincidentSpans* test = fHead;
940 if (!test) {
941 return false;
942 }
943 const SkOpSegment* coinSeg = coinPtTStart->segment();
944 const SkOpSegment* oppSeg = oppPtTStart->segment();
945 if (!Ordered(coinPtTStart, oppPtTStart)) {
946 SkTSwap(coinSeg, oppSeg);
947 SkTSwap(coinPtTStart, oppPtTStart);
948 SkTSwap(coinPtTEnd, oppPtTEnd);
949 if (coinPtTStart->fT > coinPtTEnd->fT) {
950 SkTSwap(coinPtTStart, coinPtTEnd);
951 SkTSwap(oppPtTStart, oppPtTEnd);
952 }
953 }
954 double oppMinT = SkTMin(oppPtTStart->fT, oppPtTEnd->fT);
955 double oppMaxT = SkTMax(oppPtTStart->fT, oppPtTEnd->fT);
956 do {
957 if (coinSeg != test->coinPtTStart()->segment()) {
958 continue;
959 }
960 if (coinPtTStart->fT < test->coinPtTStart()->fT) {
961 continue;
962 }
963 if (coinPtTEnd->fT > test->coinPtTEnd()->fT) {
964 continue;
965 }
966 if (oppSeg != test->oppPtTStart()->segment()) {
967 continue;
968 }
969 if (oppMinT < SkTMin(test->oppPtTStart()->fT, test->oppPtTEnd()->fT)) {
970 continue;
971 }
972 if (oppMaxT > SkTMax(test->oppPtTStart()->fT, test->oppPtTEnd()->fT)) {
973 continue;
974 }
975 return true;
976 } while ((test = test->next()));
977 return false;
978}
979
Cary Clarkab87d7a2016-10-04 10:01:04 -0400980void SkOpCoincidence::correctEnds(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
981 DEBUG_SET_PHASE();
caryclark55888e42016-07-18 10:01:36 -0700982 SkCoincidentSpans* coin = fHead;
983 if (!coin) {
984 return;
985 }
986 do {
987 coin->correctEnds();
988 } while ((coin = coin->next()));
989}
990
caryclark54359292015-03-26 07:52:43 -0700991// walk span sets in parallel, moving winding from one to the other
caryclarka35ab3e2016-10-20 08:32:18 -0700992bool SkOpCoincidence::apply(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
Cary Clarkab87d7a2016-10-04 10:01:04 -0400993 DEBUG_SET_PHASE();
caryclark54359292015-03-26 07:52:43 -0700994 SkCoincidentSpans* coin = fHead;
995 if (!coin) {
caryclarka35ab3e2016-10-20 08:32:18 -0700996 return true;
caryclark54359292015-03-26 07:52:43 -0700997 }
998 do {
Cary Clark5a2057a2017-01-03 10:47:34 -0500999 SkOpSpanBase* startSpan = coin->coinPtTStartWritable()->span();
1000 FAIL_IF(!startSpan->upCastable());
1001 SkOpSpan* start = startSpan->upCast();
caryclark182b4992015-05-14 05:45:54 -07001002 if (start->deleted()) {
1003 continue;
1004 }
caryclark55888e42016-07-18 10:01:36 -07001005 const SkOpSpanBase* end = coin->coinPtTEnd()->span();
caryclark54359292015-03-26 07:52:43 -07001006 SkASSERT(start == start->starter(end));
caryclark55888e42016-07-18 10:01:36 -07001007 bool flipped = coin->flipped();
caryclark96dc1c92016-10-20 11:34:10 -07001008 SkOpSpanBase* oStartBase = (flipped ? coin->oppPtTEndWritable()
1009 : coin->oppPtTStartWritable())->span();
1010 FAIL_IF(!oStartBase->upCastable());
1011 SkOpSpan* oStart = oStartBase->upCast();
caryclark182b4992015-05-14 05:45:54 -07001012 if (oStart->deleted()) {
1013 continue;
1014 }
caryclark55888e42016-07-18 10:01:36 -07001015 const SkOpSpanBase* oEnd = (flipped ? coin->oppPtTStart() : coin->oppPtTEnd())->span();
caryclark54359292015-03-26 07:52:43 -07001016 SkASSERT(oStart == oStart->starter(oEnd));
1017 SkOpSegment* segment = start->segment();
1018 SkOpSegment* oSegment = oStart->segment();
1019 bool operandSwap = segment->operand() != oSegment->operand();
1020 if (flipped) {
caryclark364a0072015-12-14 08:43:21 -08001021 if (oEnd->deleted()) {
1022 continue;
1023 }
caryclark54359292015-03-26 07:52:43 -07001024 do {
1025 SkOpSpanBase* oNext = oStart->next();
1026 if (oNext == oEnd) {
1027 break;
1028 }
Cary Clark26ae5ab2016-12-12 13:57:56 -05001029 FAIL_IF(!oNext->upCastable());
caryclark54359292015-03-26 07:52:43 -07001030 oStart = oNext->upCast();
1031 } while (true);
1032 }
caryclark54359292015-03-26 07:52:43 -07001033 do {
1034 int windValue = start->windValue();
caryclark54359292015-03-26 07:52:43 -07001035 int oppValue = start->oppValue();
caryclark1049f122015-04-20 08:31:59 -07001036 int oWindValue = oStart->windValue();
caryclark54359292015-03-26 07:52:43 -07001037 int oOppValue = oStart->oppValue();
1038 // winding values are added or subtracted depending on direction and wind type
1039 // same or opposite values are summed depending on the operand value
caryclark1049f122015-04-20 08:31:59 -07001040 int windDiff = operandSwap ? oOppValue : oWindValue;
1041 int oWindDiff = operandSwap ? oppValue : windValue;
1042 if (!flipped) {
1043 windDiff = -windDiff;
1044 oWindDiff = -oWindDiff;
1045 }
caryclark55888e42016-07-18 10:01:36 -07001046 bool addToStart = windValue && (windValue > windDiff || (windValue == windDiff
1047 && oWindValue <= oWindDiff));
1048 if (addToStart ? start->done() : oStart->done()) {
1049 addToStart ^= true;
1050 }
1051 if (addToStart) {
caryclark54359292015-03-26 07:52:43 -07001052 if (operandSwap) {
1053 SkTSwap(oWindValue, oOppValue);
1054 }
1055 if (flipped) {
1056 windValue -= oWindValue;
1057 oppValue -= oOppValue;
1058 } else {
1059 windValue += oWindValue;
1060 oppValue += oOppValue;
1061 }
caryclark1049f122015-04-20 08:31:59 -07001062 if (segment->isXor()) {
caryclark54359292015-03-26 07:52:43 -07001063 windValue &= 1;
1064 }
caryclark1049f122015-04-20 08:31:59 -07001065 if (segment->oppXor()) {
caryclark54359292015-03-26 07:52:43 -07001066 oppValue &= 1;
1067 }
1068 oWindValue = oOppValue = 0;
1069 } else {
1070 if (operandSwap) {
1071 SkTSwap(windValue, oppValue);
1072 }
1073 if (flipped) {
1074 oWindValue -= windValue;
1075 oOppValue -= oppValue;
1076 } else {
1077 oWindValue += windValue;
1078 oOppValue += oppValue;
1079 }
caryclark1049f122015-04-20 08:31:59 -07001080 if (oSegment->isXor()) {
caryclark54359292015-03-26 07:52:43 -07001081 oWindValue &= 1;
1082 }
caryclark1049f122015-04-20 08:31:59 -07001083 if (oSegment->oppXor()) {
1084 oOppValue &= 1;
1085 }
caryclark54359292015-03-26 07:52:43 -07001086 windValue = oppValue = 0;
1087 }
caryclark6c3b9cd2016-09-26 05:36:58 -07001088#if 0 && DEBUG_COINCIDENCE
caryclark55888e42016-07-18 10:01:36 -07001089 SkDebugf("seg=%d span=%d windValue=%d oppValue=%d\n", segment->debugID(),
1090 start->debugID(), windValue, oppValue);
1091 SkDebugf("seg=%d span=%d windValue=%d oppValue=%d\n", oSegment->debugID(),
1092 oStart->debugID(), oWindValue, oOppValue);
1093#endif
caryclark54359292015-03-26 07:52:43 -07001094 start->setWindValue(windValue);
1095 start->setOppValue(oppValue);
caryclarka35ab3e2016-10-20 08:32:18 -07001096 FAIL_IF(oWindValue == -1);
caryclark54359292015-03-26 07:52:43 -07001097 oStart->setWindValue(oWindValue);
1098 oStart->setOppValue(oOppValue);
1099 if (!windValue && !oppValue) {
1100 segment->markDone(start);
1101 }
1102 if (!oWindValue && !oOppValue) {
1103 oSegment->markDone(oStart);
1104 }
1105 SkOpSpanBase* next = start->next();
1106 SkOpSpanBase* oNext = flipped ? oStart->prev() : oStart->next();
1107 if (next == end) {
1108 break;
1109 }
caryclark96dc1c92016-10-20 11:34:10 -07001110 FAIL_IF(!next->upCastable());
caryclark54359292015-03-26 07:52:43 -07001111 start = next->upCast();
caryclark1049f122015-04-20 08:31:59 -07001112 // if the opposite ran out too soon, just reuse the last span
1113 if (!oNext || !oNext->upCastable()) {
1114 oNext = oStart;
caryclark54359292015-03-26 07:52:43 -07001115 }
1116 oStart = oNext->upCast();
1117 } while (true);
caryclark55888e42016-07-18 10:01:36 -07001118 } while ((coin = coin->next()));
caryclarka35ab3e2016-10-20 08:32:18 -07001119 return true;
caryclark54359292015-03-26 07:52:43 -07001120}
1121
caryclark55888e42016-07-18 10:01:36 -07001122// Please keep this in sync with debugRelease()
1123bool SkOpCoincidence::release(SkCoincidentSpans* coin, SkCoincidentSpans* remove) {
1124 SkCoincidentSpans* head = coin;
halcanary96fcdcc2015-08-27 07:41:13 -07001125 SkCoincidentSpans* prev = nullptr;
caryclark54359292015-03-26 07:52:43 -07001126 SkCoincidentSpans* next;
1127 do {
caryclark55888e42016-07-18 10:01:36 -07001128 next = coin->next();
caryclark54359292015-03-26 07:52:43 -07001129 if (coin == remove) {
1130 if (prev) {
caryclark55888e42016-07-18 10:01:36 -07001131 prev->setNext(next);
1132 } else if (head == fHead) {
caryclark54359292015-03-26 07:52:43 -07001133 fHead = next;
caryclark55888e42016-07-18 10:01:36 -07001134 } else {
1135 fTop = next;
caryclark54359292015-03-26 07:52:43 -07001136 }
1137 break;
1138 }
1139 prev = coin;
1140 } while ((coin = next));
caryclark55888e42016-07-18 10:01:36 -07001141 return coin != nullptr;
caryclark54359292015-03-26 07:52:43 -07001142}
1143
caryclark30b9fdd2016-08-31 14:36:29 -07001144void SkOpCoincidence::releaseDeleted(SkCoincidentSpans* coin) {
1145 if (!coin) {
1146 return;
1147 }
1148 SkCoincidentSpans* head = coin;
1149 SkCoincidentSpans* prev = nullptr;
1150 SkCoincidentSpans* next;
1151 do {
1152 next = coin->next();
1153 if (coin->coinPtTStart()->deleted()) {
1154 SkOPASSERT(coin->flipped() ? coin->oppPtTEnd()->deleted() :
1155 coin->oppPtTStart()->deleted());
1156 if (prev) {
1157 prev->setNext(next);
1158 } else if (head == fHead) {
1159 fHead = next;
1160 } else {
1161 fTop = next;
1162 }
1163 } else {
1164 SkOPASSERT(coin->flipped() ? !coin->oppPtTEnd()->deleted() :
1165 !coin->oppPtTStart()->deleted());
1166 prev = coin;
1167 }
1168 } while ((coin = next));
1169}
1170
1171void SkOpCoincidence::releaseDeleted() {
1172 this->releaseDeleted(fHead);
1173 this->releaseDeleted(fTop);
1174}
1175
caryclark55888e42016-07-18 10:01:36 -07001176void SkOpCoincidence::restoreHead() {
1177 SkCoincidentSpans** headPtr = &fHead;
1178 while (*headPtr) {
1179 headPtr = (*headPtr)->nextPtr();
1180 }
1181 *headPtr = fTop;
1182 fTop = nullptr;
1183 // segments may have collapsed in the meantime; remove empty referenced segments
1184 headPtr = &fHead;
1185 while (*headPtr) {
1186 SkCoincidentSpans* test = *headPtr;
1187 if (test->coinPtTStart()->segment()->done() || test->oppPtTStart()->segment()->done()) {
1188 *headPtr = test->next();
1189 continue;
1190 }
1191 headPtr = (*headPtr)->nextPtr();
1192 }
1193}
1194
1195// Please keep this in sync with debugExpand()
caryclark30b9fdd2016-08-31 14:36:29 -07001196// expand the range by checking adjacent spans for coincidence
Cary Clarkab87d7a2016-10-04 10:01:04 -04001197bool SkOpCoincidence::expand(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
1198 DEBUG_SET_PHASE();
caryclark54359292015-03-26 07:52:43 -07001199 SkCoincidentSpans* coin = fHead;
1200 if (!coin) {
caryclark27c8eb82015-07-06 11:38:33 -07001201 return false;
caryclark54359292015-03-26 07:52:43 -07001202 }
caryclark27c8eb82015-07-06 11:38:33 -07001203 bool expanded = false;
caryclark54359292015-03-26 07:52:43 -07001204 do {
caryclark55888e42016-07-18 10:01:36 -07001205 if (coin->expand()) {
1206 // check to see if multiple spans expanded so they are now identical
1207 SkCoincidentSpans* test = fHead;
1208 do {
1209 if (coin == test) {
1210 continue;
1211 }
1212 if (coin->coinPtTStart() == test->coinPtTStart()
1213 && coin->oppPtTStart() == test->oppPtTStart()) {
1214 this->release(fHead, test);
1215 break;
1216 }
1217 } while ((test = test->next()));
1218 expanded = true;
caryclark54359292015-03-26 07:52:43 -07001219 }
caryclark55888e42016-07-18 10:01:36 -07001220 } while ((coin = coin->next()));
caryclark27c8eb82015-07-06 11:38:33 -07001221 return expanded;
1222}
1223
Cary Clark40f23782016-10-06 12:04:16 -04001224bool SkOpCoincidence::findOverlaps(SkOpCoincidence* overlaps DEBUG_COIN_DECLARE_PARAMS()) const {
Cary Clarkab87d7a2016-10-04 10:01:04 -04001225 DEBUG_SET_PHASE();
halcanary96fcdcc2015-08-27 07:41:13 -07001226 overlaps->fHead = overlaps->fTop = nullptr;
caryclark27c8eb82015-07-06 11:38:33 -07001227 SkCoincidentSpans* outer = fHead;
1228 while (outer) {
caryclark55888e42016-07-18 10:01:36 -07001229 const SkOpSegment* outerCoin = outer->coinPtTStart()->segment();
1230 const SkOpSegment* outerOpp = outer->oppPtTStart()->segment();
caryclark27c8eb82015-07-06 11:38:33 -07001231 SkCoincidentSpans* inner = outer;
caryclark55888e42016-07-18 10:01:36 -07001232 while ((inner = inner->next())) {
1233 const SkOpSegment* innerCoin = inner->coinPtTStart()->segment();
caryclark27c8eb82015-07-06 11:38:33 -07001234 if (outerCoin == innerCoin) {
1235 continue; // both winners are the same segment, so there's no additional overlap
1236 }
caryclark55888e42016-07-18 10:01:36 -07001237 const SkOpSegment* innerOpp = inner->oppPtTStart()->segment();
1238 const SkOpPtT* overlapS;
1239 const SkOpPtT* overlapE;
1240 if ((outerOpp == innerCoin && SkOpPtT::Overlaps(outer->oppPtTStart(),
1241 outer->oppPtTEnd(),inner->coinPtTStart(), inner->coinPtTEnd(), &overlapS,
1242 &overlapE))
1243 || (outerCoin == innerOpp && SkOpPtT::Overlaps(outer->coinPtTStart(),
1244 outer->coinPtTEnd(), inner->oppPtTStart(), inner->oppPtTEnd(),
caryclark27c8eb82015-07-06 11:38:33 -07001245 &overlapS, &overlapE))
caryclark55888e42016-07-18 10:01:36 -07001246 || (outerOpp == innerOpp && SkOpPtT::Overlaps(outer->oppPtTStart(),
1247 outer->oppPtTEnd(), inner->oppPtTStart(), inner->oppPtTEnd(),
caryclark27c8eb82015-07-06 11:38:33 -07001248 &overlapS, &overlapE))) {
Cary Clark40f23782016-10-06 12:04:16 -04001249 if (!overlaps->addOverlap(outerCoin, outerOpp, innerCoin, innerOpp,
1250 overlapS, overlapE)) {
1251 return false;
1252 }
Cary Clarke47ae292016-10-05 08:51:39 -04001253 }
caryclark27c8eb82015-07-06 11:38:33 -07001254 }
caryclark55888e42016-07-18 10:01:36 -07001255 outer = outer->next();
caryclark27c8eb82015-07-06 11:38:33 -07001256 }
Cary Clark40f23782016-10-06 12:04:16 -04001257 return true;
caryclark27c8eb82015-07-06 11:38:33 -07001258}
1259
caryclark55888e42016-07-18 10:01:36 -07001260void SkOpCoincidence::fixUp(SkOpPtT* deleted, const SkOpPtT* kept) {
caryclarkb393a492016-09-07 08:21:09 -07001261 SkOPASSERT(deleted != kept);
caryclark55888e42016-07-18 10:01:36 -07001262 if (fHead) {
1263 this->fixUp(fHead, deleted, kept);
caryclark54359292015-03-26 07:52:43 -07001264 }
caryclark55888e42016-07-18 10:01:36 -07001265 if (fTop) {
1266 this->fixUp(fTop, deleted, kept);
1267 }
caryclark54359292015-03-26 07:52:43 -07001268}
1269
caryclark55888e42016-07-18 10:01:36 -07001270void SkOpCoincidence::fixUp(SkCoincidentSpans* coin, SkOpPtT* deleted, const SkOpPtT* kept) {
1271 SkCoincidentSpans* head = coin;
1272 do {
1273 if (coin->coinPtTStart() == deleted) {
1274 if (coin->coinPtTEnd()->span() == kept->span()) {
1275 this->release(head, coin);
1276 continue;
1277 }
1278 coin->setCoinPtTStart(kept);
1279 }
1280 if (coin->coinPtTEnd() == deleted) {
1281 if (coin->coinPtTStart()->span() == kept->span()) {
1282 this->release(head, coin);
1283 continue;
1284 }
1285 coin->setCoinPtTEnd(kept);
1286 }
1287 if (coin->oppPtTStart() == deleted) {
1288 if (coin->oppPtTEnd()->span() == kept->span()) {
1289 this->release(head, coin);
1290 continue;
1291 }
1292 coin->setOppPtTStart(kept);
1293 }
1294 if (coin->oppPtTEnd() == deleted) {
1295 if (coin->oppPtTStart()->span() == kept->span()) {
1296 this->release(head, coin);
1297 continue;
1298 }
1299 coin->setOppPtTEnd(kept);
1300 }
1301 } while ((coin = coin->next()));
1302}
1303
1304// Please keep this in sync with debugMark()
caryclark27c8eb82015-07-06 11:38:33 -07001305/* this sets up the coincidence links in the segments when the coincidence crosses multiple spans */
caryclarke6522ea2016-10-17 07:54:33 -07001306bool SkOpCoincidence::mark(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
Cary Clarkab87d7a2016-10-04 10:01:04 -04001307 DEBUG_SET_PHASE();
caryclark54359292015-03-26 07:52:43 -07001308 SkCoincidentSpans* coin = fHead;
1309 if (!coin) {
caryclarke6522ea2016-10-17 07:54:33 -07001310 return true;
caryclark54359292015-03-26 07:52:43 -07001311 }
1312 do {
caryclarke6522ea2016-10-17 07:54:33 -07001313 SkOpSpanBase* startBase = coin->coinPtTStartWritable()->span();
1314 FAIL_IF(!startBase->upCastable());
1315 SkOpSpan* start = startBase->upCast();
caryclarka35ab3e2016-10-20 08:32:18 -07001316 FAIL_IF(start->deleted());
caryclark55888e42016-07-18 10:01:36 -07001317 SkOpSpanBase* end = coin->coinPtTEndWritable()->span();
Cary Clark40f23782016-10-06 12:04:16 -04001318 SkOPASSERT(!end->deleted());
caryclark55888e42016-07-18 10:01:36 -07001319 SkOpSpanBase* oStart = coin->oppPtTStartWritable()->span();
Cary Clark40f23782016-10-06 12:04:16 -04001320 SkOPASSERT(!oStart->deleted());
caryclark55888e42016-07-18 10:01:36 -07001321 SkOpSpanBase* oEnd = coin->oppPtTEndWritable()->span();
1322 SkASSERT(!oEnd->deleted());
1323 bool flipped = coin->flipped();
caryclark54359292015-03-26 07:52:43 -07001324 if (flipped) {
1325 SkTSwap(oStart, oEnd);
1326 }
caryclark55888e42016-07-18 10:01:36 -07001327 /* coin and opp spans may not match up. Mark the ends, and then let the interior
1328 get marked as many times as the spans allow */
Cary Clark9de09762016-11-17 08:47:37 -05001329 FAIL_IF(!oStart->upCastable());
caryclark55888e42016-07-18 10:01:36 -07001330 start->insertCoincidence(oStart->upCast());
1331 end->insertCoinEnd(oEnd);
1332 const SkOpSegment* segment = start->segment();
1333 const SkOpSegment* oSegment = oStart->segment();
caryclark54359292015-03-26 07:52:43 -07001334 SkOpSpanBase* next = start;
1335 SkOpSpanBase* oNext = oStart;
caryclarka35ab3e2016-10-20 08:32:18 -07001336 bool ordered;
1337 FAIL_IF(!coin->ordered(&ordered));
caryclark55888e42016-07-18 10:01:36 -07001338 while ((next = next->upCast()->next()) != end) {
caryclarke6522ea2016-10-17 07:54:33 -07001339 FAIL_IF(!next->upCastable());
Cary Clark59ed4822016-12-08 16:17:56 -05001340 FAIL_IF(!next->upCast()->insertCoincidence(oSegment, flipped, ordered));
caryclark55888e42016-07-18 10:01:36 -07001341 }
1342 while ((oNext = oNext->upCast()->next()) != oEnd) {
caryclark96dc1c92016-10-20 11:34:10 -07001343 FAIL_IF(!oNext->upCastable());
caryclarke6522ea2016-10-17 07:54:33 -07001344 FAIL_IF(!oNext->upCast()->insertCoincidence(segment, flipped, ordered));
caryclark55888e42016-07-18 10:01:36 -07001345 }
1346 } while ((coin = coin->next()));
caryclarke6522ea2016-10-17 07:54:33 -07001347 return true;
caryclark54359292015-03-26 07:52:43 -07001348}
1349
caryclark55888e42016-07-18 10:01:36 -07001350// Please keep in sync with debugMarkCollapsed()
1351void SkOpCoincidence::markCollapsed(SkCoincidentSpans* coin, SkOpPtT* test) {
1352 SkCoincidentSpans* head = coin;
1353 while (coin) {
1354 if (coin->collapsed(test)) {
1355 if (zero_or_one(coin->coinPtTStart()->fT) && zero_or_one(coin->coinPtTEnd()->fT)) {
1356 coin->coinPtTStartWritable()->segment()->markAllDone();
1357 }
1358 if (zero_or_one(coin->oppPtTStart()->fT) && zero_or_one(coin->oppPtTEnd()->fT)) {
1359 coin->oppPtTStartWritable()->segment()->markAllDone();
1360 }
1361 this->release(head, coin);
1362 }
1363 coin = coin->next();
1364 }
1365}
1366
1367// Please keep in sync with debugMarkCollapsed()
1368void SkOpCoincidence::markCollapsed(SkOpPtT* test) {
1369 markCollapsed(fHead, test);
1370 markCollapsed(fTop, test);
1371}
1372
1373bool SkOpCoincidence::Ordered(const SkOpSegment* coinSeg, const SkOpSegment* oppSeg) {
1374 if (coinSeg->verb() < oppSeg->verb()) {
1375 return true;
1376 }
1377 if (coinSeg->verb() > oppSeg->verb()) {
1378 return false;
1379 }
1380 int count = (SkPathOpsVerbToPoints(coinSeg->verb()) + 1) * 2;
1381 const SkScalar* cPt = &coinSeg->pts()[0].fX;
1382 const SkScalar* oPt = &oppSeg->pts()[0].fX;
1383 for (int index = 0; index < count; ++index) {
1384 if (*cPt < *oPt) {
1385 return true;
1386 }
1387 if (*cPt > *oPt) {
1388 return false;
1389 }
1390 ++cPt;
1391 ++oPt;
1392 }
1393 return true;
1394}
1395
1396bool SkOpCoincidence::overlap(const SkOpPtT* coin1s, const SkOpPtT* coin1e,
caryclark54359292015-03-26 07:52:43 -07001397 const SkOpPtT* coin2s, const SkOpPtT* coin2e, double* overS, double* overE) const {
caryclark27c8eb82015-07-06 11:38:33 -07001398 SkASSERT(coin1s->segment() == coin2s->segment());
caryclark54359292015-03-26 07:52:43 -07001399 *overS = SkTMax(SkTMin(coin1s->fT, coin1e->fT), SkTMin(coin2s->fT, coin2e->fT));
1400 *overE = SkTMin(SkTMax(coin1s->fT, coin1e->fT), SkTMax(coin2s->fT, coin2e->fT));
1401 return *overS < *overE;
1402}
caryclark27c8eb82015-07-06 11:38:33 -07001403
caryclark55888e42016-07-18 10:01:36 -07001404// Commented-out lines keep this in sync with debugRelease()
1405void SkOpCoincidence::release(const SkOpSegment* deleted) {
1406 SkCoincidentSpans* coin = fHead;
1407 if (!coin) {
1408 return;
1409 }
1410 do {
1411 if (coin->coinPtTStart()->segment() == deleted
1412 || coin->coinPtTEnd()->segment() == deleted
1413 || coin->oppPtTStart()->segment() == deleted
1414 || coin->oppPtTEnd()->segment() == deleted) {
1415 this->release(fHead, coin);
1416 }
1417 } while ((coin = coin->next()));
1418}