blob: d16f6f86421883789b0a2395f986794bb9548623 [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
19// sets the span's end to the ptT referenced by the previous-next
20void SkCoincidentSpans::correctOneEnd(
21 const SkOpPtT* (SkCoincidentSpans::* getEnd)() const,
22 void (SkCoincidentSpans::*setEnd)(const SkOpPtT* ptT) ) {
23 const SkOpPtT* origPtT = (this->*getEnd)();
24 const SkOpSpanBase* origSpan = origPtT->span();
25 const SkOpSpan* prev = origSpan->prev();
26 const SkOpPtT* testPtT = prev ? prev->next()->ptT()
27 : origSpan->upCast()->next()->prev()->ptT();
28 if (origPtT != testPtT) {
29 (this->*setEnd)(testPtT);
caryclarkbca19f72015-05-13 08:23:48 -070030 }
caryclark55888e42016-07-18 10:01:36 -070031}
32
Cary Clarkab87d7a2016-10-04 10:01:04 -040033/* Please keep this in sync with debugCorrectEnds */
caryclark55888e42016-07-18 10:01:36 -070034// FIXME: member pointers have fallen out of favor and can be replaced with
35// an alternative approach.
36// makes all span ends agree with the segment's spans that define them
37void SkCoincidentSpans::correctEnds() {
38 this->correctOneEnd(&SkCoincidentSpans::coinPtTStart, &SkCoincidentSpans::setCoinPtTStart);
39 this->correctOneEnd(&SkCoincidentSpans::coinPtTEnd, &SkCoincidentSpans::setCoinPtTEnd);
40 this->correctOneEnd(&SkCoincidentSpans::oppPtTStart, &SkCoincidentSpans::setOppPtTStart);
41 this->correctOneEnd(&SkCoincidentSpans::oppPtTEnd, &SkCoincidentSpans::setOppPtTEnd);
42}
43
44/* Please keep this in sync with debugExpand */
45// expand the range by checking adjacent spans for coincidence
46bool SkCoincidentSpans::expand() {
47 bool expanded = false;
48 const SkOpSegment* segment = coinPtTStart()->segment();
49 const SkOpSegment* oppSegment = oppPtTStart()->segment();
50 do {
51 const SkOpSpan* start = coinPtTStart()->span()->upCast();
52 const SkOpSpan* prev = start->prev();
53 const SkOpPtT* oppPtT;
54 if (!prev || !(oppPtT = prev->contains(oppSegment))) {
55 break;
56 }
57 double midT = (prev->t() + start->t()) / 2;
58 if (!segment->isClose(midT, oppSegment)) {
59 break;
60 }
61 setStarts(prev->ptT(), oppPtT);
62 expanded = true;
63 } while (true);
64 do {
65 const SkOpSpanBase* end = coinPtTEnd()->span();
66 SkOpSpanBase* next = end->final() ? nullptr : end->upCast()->next();
caryclarkc6d855f2016-08-11 11:59:48 -070067 if (next && next->deleted()) {
68 break;
69 }
caryclark55888e42016-07-18 10:01:36 -070070 const SkOpPtT* oppPtT;
71 if (!next || !(oppPtT = next->contains(oppSegment))) {
72 break;
73 }
74 double midT = (end->t() + next->t()) / 2;
75 if (!segment->isClose(midT, oppSegment)) {
76 break;
77 }
78 setEnds(next->ptT(), oppPtT);
79 expanded = true;
80 } while (true);
81 return expanded;
82}
83
84// increase the range of this span
85bool SkCoincidentSpans::extend(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd,
86 const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) {
87 bool result = false;
88 if (fCoinPtTStart->fT > coinPtTStart->fT || (this->flipped()
89 ? fOppPtTStart->fT < oppPtTStart->fT : fOppPtTStart->fT > oppPtTStart->fT)) {
90 this->setStarts(coinPtTStart, oppPtTStart);
91 result = true;
92 }
93 if (fCoinPtTEnd->fT < coinPtTEnd->fT || (this->flipped()
94 ? fOppPtTEnd->fT > oppPtTEnd->fT : fOppPtTEnd->fT < oppPtTEnd->fT)) {
95 this->setEnds(coinPtTEnd, oppPtTEnd);
96 result = true;
97 }
98 return result;
99}
100
101// set the range of this span
102void SkCoincidentSpans::set(SkCoincidentSpans* next, const SkOpPtT* coinPtTStart,
Cary Clarkab87d7a2016-10-04 10:01:04 -0400103 const SkOpPtT* coinPtTEnd, const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) {
caryclark55888e42016-07-18 10:01:36 -0700104 SkASSERT(SkOpCoincidence::Ordered(coinPtTStart, oppPtTStart));
105 fNext = next;
106 this->setStarts(coinPtTStart, oppPtTStart);
107 this->setEnds(coinPtTEnd, oppPtTEnd);
caryclark55888e42016-07-18 10:01:36 -0700108}
109
110// returns true if both points are inside this
111bool SkCoincidentSpans::contains(const SkOpPtT* s, const SkOpPtT* e) const {
112 if (s->fT > e->fT) {
113 SkTSwap(s, e);
114 }
115 if (s->segment() == fCoinPtTStart->segment()) {
116 return fCoinPtTStart->fT <= s->fT && e->fT <= fCoinPtTEnd->fT;
117 } else {
118 SkASSERT(s->segment() == fOppPtTStart->segment());
119 double oppTs = fOppPtTStart->fT;
120 double oppTe = fOppPtTEnd->fT;
121 if (oppTs > oppTe) {
122 SkTSwap(oppTs, oppTe);
123 }
124 return oppTs <= s->fT && e->fT <= oppTe;
125 }
126}
127
caryclark81a478c2016-09-09 09:37:57 -0700128// A coincident span is unordered if the pairs of points in the main and opposite curves'
129// t values do not ascend or descend. For instance, if a tightly arced quadratic is
130// coincident with another curve, it may intersect it out of order.
caryclarka35ab3e2016-10-20 08:32:18 -0700131bool SkCoincidentSpans::ordered(bool* result) const {
caryclark81a478c2016-09-09 09:37:57 -0700132 const SkOpSpanBase* start = this->coinPtTStart()->span();
133 const SkOpSpanBase* end = this->coinPtTEnd()->span();
134 const SkOpSpanBase* next = start->upCast()->next();
135 if (next == end) {
caryclarka35ab3e2016-10-20 08:32:18 -0700136 *result = true;
caryclark81a478c2016-09-09 09:37:57 -0700137 return true;
138 }
139 bool flipped = this->flipped();
140 const SkOpSegment* oppSeg = this->oppPtTStart()->segment();
141 double oppLastT = fOppPtTStart->fT;
142 do {
143 const SkOpPtT* opp = next->contains(oppSeg);
144 if (!opp) {
caryclarka35ab3e2016-10-20 08:32:18 -0700145 SkOPOBJASSERT(start, 0); // may assert if coincident span isn't fully processed
146 return false;
caryclark81a478c2016-09-09 09:37:57 -0700147 }
148 if ((oppLastT > opp->fT) != flipped) {
caryclarka35ab3e2016-10-20 08:32:18 -0700149 *result = false;
150 return true;
caryclark81a478c2016-09-09 09:37:57 -0700151 }
152 oppLastT = opp->fT;
153 if (next == end) {
154 break;
155 }
caryclarkbbfe92b2016-09-19 06:00:35 -0700156 if (!next->upCastable()) {
caryclarka35ab3e2016-10-20 08:32:18 -0700157 *result = false;
158 return true;
caryclarkbbfe92b2016-09-19 06:00:35 -0700159 }
caryclark81a478c2016-09-09 09:37:57 -0700160 next = next->upCast()->next();
161 } while (true);
caryclarka35ab3e2016-10-20 08:32:18 -0700162 *result = true;
caryclark81a478c2016-09-09 09:37:57 -0700163 return true;
164}
165
caryclark55888e42016-07-18 10:01:36 -0700166// if there is an existing pair that overlaps the addition, extend it
167bool SkOpCoincidence::extend(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd,
168 const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) {
169 SkCoincidentSpans* test = fHead;
170 if (!test) {
171 return false;
172 }
173 const SkOpSegment* coinSeg = coinPtTStart->segment();
174 const SkOpSegment* oppSeg = oppPtTStart->segment();
175 if (!Ordered(coinPtTStart, oppPtTStart)) {
176 SkTSwap(coinSeg, oppSeg);
177 SkTSwap(coinPtTStart, oppPtTStart);
178 SkTSwap(coinPtTEnd, oppPtTEnd);
179 if (coinPtTStart->fT > coinPtTEnd->fT) {
180 SkTSwap(coinPtTStart, coinPtTEnd);
181 SkTSwap(oppPtTStart, oppPtTEnd);
182 }
183 }
184 double oppMinT = SkTMin(oppPtTStart->fT, oppPtTEnd->fT);
185 SkDEBUGCODE(double oppMaxT = SkTMax(oppPtTStart->fT, oppPtTEnd->fT));
186 do {
187 if (coinSeg != test->coinPtTStart()->segment()) {
188 continue;
189 }
190 if (oppSeg != test->oppPtTStart()->segment()) {
191 continue;
192 }
193 double oTestMinT = SkTMin(test->oppPtTStart()->fT, test->oppPtTEnd()->fT);
194 double oTestMaxT = SkTMax(test->oppPtTStart()->fT, test->oppPtTEnd()->fT);
195 // if debug check triggers, caller failed to check if extended already exists
196 SkASSERT(test->coinPtTStart()->fT > coinPtTStart->fT
197 || coinPtTEnd->fT > test->coinPtTEnd()->fT
198 || oTestMinT > oppMinT || oppMaxT > oTestMaxT);
199 if ((test->coinPtTStart()->fT <= coinPtTEnd->fT
200 && coinPtTStart->fT <= test->coinPtTEnd()->fT)
201 || (oTestMinT <= oTestMaxT && oppMinT <= oTestMaxT)) {
202 test->extend(coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd);
203 return true;
204 }
205 } while ((test = test->next()));
206 return false;
caryclark54359292015-03-26 07:52:43 -0700207}
208
caryclark55888e42016-07-18 10:01:36 -0700209// verifies that the coincidence hasn't already been added
210static void DebugCheckAdd(const SkCoincidentSpans* check, const SkOpPtT* coinPtTStart,
211 const SkOpPtT* coinPtTEnd, const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) {
212#if DEBUG_COINCIDENCE
213 while (check) {
214 SkASSERT(check->coinPtTStart() != coinPtTStart || check->coinPtTEnd() != coinPtTEnd
215 || check->oppPtTStart() != oppPtTStart || check->oppPtTEnd() != oppPtTEnd);
216 SkASSERT(check->coinPtTStart() != oppPtTStart || check->coinPtTEnd() != oppPtTEnd
217 || check->oppPtTStart() != coinPtTStart || check->oppPtTEnd() != coinPtTEnd);
218 check = check->next();
219 }
220#endif
221}
222
223// adds a new coincident pair
224void SkOpCoincidence::add(SkOpPtT* coinPtTStart, SkOpPtT* coinPtTEnd, SkOpPtT* oppPtTStart,
225 SkOpPtT* oppPtTEnd) {
226 // OPTIMIZE: caller should have already sorted
227 if (!Ordered(coinPtTStart, oppPtTStart)) {
228 if (oppPtTStart->fT < oppPtTEnd->fT) {
229 this->add(oppPtTStart, oppPtTEnd, coinPtTStart, coinPtTEnd);
230 } else {
231 this->add(oppPtTEnd, oppPtTStart, coinPtTEnd, coinPtTStart);
232 }
233 return;
234 }
235 SkASSERT(Ordered(coinPtTStart, oppPtTStart));
236 // choose the ptT at the front of the list to track
237 coinPtTStart = coinPtTStart->span()->ptT();
238 coinPtTEnd = coinPtTEnd->span()->ptT();
239 oppPtTStart = oppPtTStart->span()->ptT();
240 oppPtTEnd = oppPtTEnd->span()->ptT();
caryclarka35ab3e2016-10-20 08:32:18 -0700241 SkOPASSERT(coinPtTStart->fT < coinPtTEnd->fT);
caryclark55888e42016-07-18 10:01:36 -0700242 SkASSERT(oppPtTStart->fT != oppPtTEnd->fT);
caryclark30b9fdd2016-08-31 14:36:29 -0700243 SkOPASSERT(!coinPtTStart->deleted());
244 SkOPASSERT(!coinPtTEnd->deleted());
245 SkOPASSERT(!oppPtTStart->deleted());
246 SkOPASSERT(!oppPtTEnd->deleted());
caryclark55888e42016-07-18 10:01:36 -0700247 DebugCheckAdd(fHead, coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd);
248 DebugCheckAdd(fTop, coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd);
249 SkCoincidentSpans* coinRec = SkOpTAllocator<SkCoincidentSpans>::Allocate(
250 this->globalState()->allocator());
caryclarkfc560e02016-07-27 08:46:10 -0700251 coinRec->init(SkDEBUGCODE(fGlobalState));
Cary Clarkab87d7a2016-10-04 10:01:04 -0400252 coinRec->set(this->fHead, coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd);
caryclark55888e42016-07-18 10:01:36 -0700253 fHead = coinRec;
254}
255
256// description below
caryclark15976282016-07-21 05:48:43 -0700257bool SkOpCoincidence::addEndMovedSpans(const SkOpSpan* base, const SkOpSpanBase* testSpan) {
caryclark55888e42016-07-18 10:01:36 -0700258 const SkOpPtT* testPtT = testSpan->ptT();
259 const SkOpPtT* stopPtT = testPtT;
260 const SkOpSegment* baseSeg = base->segment();
261 while ((testPtT = testPtT->next()) != stopPtT) {
262 const SkOpSegment* testSeg = testPtT->segment();
263 if (testPtT->deleted()) {
264 continue;
265 }
266 if (testSeg == baseSeg) {
267 continue;
268 }
caryclarkc6d855f2016-08-11 11:59:48 -0700269 if (testPtT->span()->ptT() != testPtT) {
270 continue;
271 }
caryclark55888e42016-07-18 10:01:36 -0700272 if (this->contains(baseSeg, testSeg, testPtT->fT)) {
273 continue;
274 }
275 // intersect perp with base->ptT() with testPtT->segment()
276 SkDVector dxdy = baseSeg->dSlopeAtT(base->t());
277 const SkPoint& pt = base->pt();
278 SkDLine ray = {{{pt.fX, pt.fY}, {pt.fX + dxdy.fY, pt.fY - dxdy.fX}}};
279 SkIntersections i;
280 (*CurveIntersectRay[testSeg->verb()])(testSeg->pts(), testSeg->weight(), ray, &i);
281 for (int index = 0; index < i.used(); ++index) {
282 double t = i[0][index];
283 if (!between(0, t, 1)) {
284 continue;
285 }
286 SkDPoint oppPt = i.pt(index);
287 if (!oppPt.approximatelyEqual(pt)) {
288 continue;
289 }
290 SkOpSegment* writableSeg = const_cast<SkOpSegment*>(testSeg);
caryclark29b25632016-08-25 11:27:17 -0700291 SkOpPtT* oppStart = writableSeg->addT(t);
caryclark27c015d2016-09-23 05:47:20 -0700292 if (oppStart == testPtT) {
293 continue;
294 }
caryclark55888e42016-07-18 10:01:36 -0700295 SkOpSpan* writableBase = const_cast<SkOpSpan*>(base);
caryclark30b9fdd2016-08-31 14:36:29 -0700296 oppStart->span()->addOpp(writableBase);
caryclark55888e42016-07-18 10:01:36 -0700297 if (oppStart->deleted()) {
298 continue;
299 }
300 SkOpSegment* coinSeg = base->segment();
301 SkOpSegment* oppSeg = oppStart->segment();
302 double coinTs, coinTe, oppTs, oppTe;
caryclark8016b262016-09-06 05:59:47 -0700303 if (Ordered(coinSeg, oppSeg)) {
caryclark55888e42016-07-18 10:01:36 -0700304 coinTs = base->t();
305 coinTe = testSpan->t();
306 oppTs = oppStart->fT;
307 oppTe = testPtT->fT;
308 } else {
309 SkTSwap(coinSeg, oppSeg);
310 coinTs = oppStart->fT;
311 coinTe = testPtT->fT;
312 oppTs = base->t();
313 oppTe = testSpan->t();
314 }
315 if (coinTs > coinTe) {
316 SkTSwap(coinTs, coinTe);
317 SkTSwap(oppTs, oppTe);
318 }
caryclark81a478c2016-09-09 09:37:57 -0700319 bool added;
320 if (!this->addOrOverlap(coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, &added)) {
caryclark15976282016-07-21 05:48:43 -0700321 return false;
322 }
caryclark55888e42016-07-18 10:01:36 -0700323 }
324 }
caryclark15976282016-07-21 05:48:43 -0700325 return true;
caryclark55888e42016-07-18 10:01:36 -0700326}
327
328// description below
329bool SkOpCoincidence::addEndMovedSpans(const SkOpPtT* ptT) {
caryclark025b11e2016-08-25 05:21:14 -0700330 FAIL_IF(!ptT->span()->upCastable());
caryclark55888e42016-07-18 10:01:36 -0700331 const SkOpSpan* base = ptT->span()->upCast();
332 const SkOpSpan* prev = base->prev();
caryclark025b11e2016-08-25 05:21:14 -0700333 FAIL_IF(!prev);
caryclark55888e42016-07-18 10:01:36 -0700334 if (!prev->isCanceled()) {
caryclark15976282016-07-21 05:48:43 -0700335 if (!this->addEndMovedSpans(base, base->prev())) {
336 return false;
337 }
caryclark55888e42016-07-18 10:01:36 -0700338 }
339 if (!base->isCanceled()) {
caryclark15976282016-07-21 05:48:43 -0700340 if (!this->addEndMovedSpans(base, base->next())) {
341 return false;
342 }
caryclark55888e42016-07-18 10:01:36 -0700343 }
344 return true;
345}
346
347/* If A is coincident with B and B includes an endpoint, and A's matching point
348 is not the endpoint (i.e., there's an implied line connecting B-end and A)
349 then assume that the same implied line may intersect another curve close to B.
350 Since we only care about coincidence that was undetected, look at the
351 ptT list on B-segment adjacent to the B-end/A ptT loop (not in the loop, but
352 next door) and see if the A matching point is close enough to form another
353 coincident pair. If so, check for a new coincident span between B-end/A ptT loop
354 and the adjacent ptT loop.
355*/
Cary Clarkab87d7a2016-10-04 10:01:04 -0400356bool SkOpCoincidence::addEndMovedSpans(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
357 DEBUG_SET_PHASE();
caryclark55888e42016-07-18 10:01:36 -0700358 SkCoincidentSpans* span = fHead;
359 if (!span) {
360 return true;
361 }
362 fTop = span;
363 fHead = nullptr;
364 do {
365 if (span->coinPtTStart()->fPt != span->oppPtTStart()->fPt) {
caryclark025b11e2016-08-25 05:21:14 -0700366 FAIL_IF(1 == span->coinPtTStart()->fT);
caryclark55888e42016-07-18 10:01:36 -0700367 bool onEnd = span->coinPtTStart()->fT == 0;
368 bool oOnEnd = zero_or_one(span->oppPtTStart()->fT);
369 if (onEnd) {
370 if (!oOnEnd) { // if both are on end, any nearby intersect was already found
371 if (!this->addEndMovedSpans(span->oppPtTStart())) {
372 return false;
373 }
374 }
375 } else if (oOnEnd) {
376 if (!this->addEndMovedSpans(span->coinPtTStart())) {
377 return false;
378 }
379 }
380 }
381 if (span->coinPtTEnd()->fPt != span->oppPtTEnd()->fPt) {
382 bool onEnd = span->coinPtTEnd()->fT == 1;
383 bool oOnEnd = zero_or_one(span->oppPtTEnd()->fT);
384 if (onEnd) {
385 if (!oOnEnd) {
386 if (!this->addEndMovedSpans(span->oppPtTEnd())) {
387 return false;
388 }
389 }
390 } else if (oOnEnd) {
391 if (!this->addEndMovedSpans(span->coinPtTEnd())) {
392 return false;
393 }
394 }
395 }
396 } while ((span = span->next()));
397 this->restoreHead();
398 return true;
399}
400
401/* Please keep this in sync with debugAddExpanded */
402// for each coincident pair, match the spans
403// 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 -0400404bool SkOpCoincidence::addExpanded(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
405 DEBUG_SET_PHASE();
caryclark55888e42016-07-18 10:01:36 -0700406 SkCoincidentSpans* coin = this->fHead;
407 if (!coin) {
408 return true;
409 }
410 do {
411 const SkOpPtT* startPtT = coin->coinPtTStart();
412 const SkOpPtT* oStartPtT = coin->oppPtTStart();
caryclark8016b262016-09-06 05:59:47 -0700413 double priorT = startPtT->fT;
414 double oPriorT = oStartPtT->fT;
caryclarkbbfe92b2016-09-19 06:00:35 -0700415 FAIL_IF(!startPtT->contains(oStartPtT));
caryclarkc6d855f2016-08-11 11:59:48 -0700416 SkOPASSERT(coin->coinPtTEnd()->contains(coin->oppPtTEnd()));
caryclark55888e42016-07-18 10:01:36 -0700417 const SkOpSpanBase* start = startPtT->span();
418 const SkOpSpanBase* oStart = oStartPtT->span();
419 const SkOpSpanBase* end = coin->coinPtTEnd()->span();
420 const SkOpSpanBase* oEnd = coin->oppPtTEnd()->span();
421 FAIL_IF(oEnd->deleted());
caryclarke25a4f62016-07-26 09:26:29 -0700422 FAIL_IF(!start->upCastable());
caryclark55888e42016-07-18 10:01:36 -0700423 const SkOpSpanBase* test = start->upCast()->next();
caryclarke7bb5b22016-09-22 05:20:07 -0700424 FAIL_IF(!coin->flipped() && !oStart->upCastable());
caryclark55888e42016-07-18 10:01:36 -0700425 const SkOpSpanBase* oTest = coin->flipped() ? oStart->prev() : oStart->upCast()->next();
caryclark30b9fdd2016-08-31 14:36:29 -0700426 FAIL_IF(!oTest);
caryclark8016b262016-09-06 05:59:47 -0700427 SkOpSegment* seg = start->segment();
428 SkOpSegment* oSeg = oStart->segment();
caryclark55888e42016-07-18 10:01:36 -0700429 while (test != end || oTest != oEnd) {
caryclark8016b262016-09-06 05:59:47 -0700430 const SkOpPtT* containedOpp = test->ptT()->contains(oSeg);
431 const SkOpPtT* containedThis = oTest->ptT()->contains(seg);
432 if (!containedOpp || !containedThis) {
433 // choose the ends, or the first common pt-t list shared by both
434 double nextT, oNextT;
435 if (containedOpp) {
436 nextT = test->t();
437 oNextT = containedOpp->fT;
438 } else if (containedThis) {
439 nextT = containedThis->fT;
440 oNextT = oTest->t();
441 } else {
442 // iterate through until a pt-t list found that contains the other
443 const SkOpSpanBase* walk = test;
444 const SkOpPtT* walkOpp;
445 do {
446 FAIL_IF(!walk->upCastable());
447 walk = walk->upCast()->next();
448 } while (!(walkOpp = walk->ptT()->contains(oSeg))
449 && walk != coin->coinPtTEnd()->span());
Cary Clark3fdf52c2016-10-04 10:53:31 -0400450 FAIL_IF(!walkOpp);
caryclark8016b262016-09-06 05:59:47 -0700451 nextT = walk->t();
452 oNextT = walkOpp->fT;
453 }
caryclark55888e42016-07-18 10:01:36 -0700454 // use t ranges to guess which one is missing
caryclark8016b262016-09-06 05:59:47 -0700455 double startRange = nextT - priorT;
caryclark55888e42016-07-18 10:01:36 -0700456 FAIL_IF(!startRange);
caryclark8016b262016-09-06 05:59:47 -0700457 double startPart = (test->t() - priorT) / startRange;
458 double oStartRange = oNextT - oPriorT;
caryclark55888e42016-07-18 10:01:36 -0700459 FAIL_IF(!oStartRange);
caryclark8016b262016-09-06 05:59:47 -0700460 double oStartPart = (oTest->t() - oPriorT) / oStartRange;
caryclark55888e42016-07-18 10:01:36 -0700461 FAIL_IF(startPart == oStartPart);
caryclark8016b262016-09-06 05:59:47 -0700462 bool addToOpp = !containedOpp && !containedThis ? startPart < oStartPart
463 : !!containedThis;
caryclark55888e42016-07-18 10:01:36 -0700464 bool startOver = false;
caryclark8016b262016-09-06 05:59:47 -0700465 bool success = addToOpp ? oSeg->addExpanded(
466 oPriorT + oStartRange * startPart, test, &startOver)
467 : seg->addExpanded(
468 priorT + startRange * oStartPart, oTest, &startOver);
caryclark30b9fdd2016-08-31 14:36:29 -0700469 FAIL_IF(!success);
caryclark55888e42016-07-18 10:01:36 -0700470 if (startOver) {
471 test = start;
472 oTest = oStart;
473 }
caryclark30b9fdd2016-08-31 14:36:29 -0700474 end = coin->coinPtTEnd()->span();
475 oEnd = coin->oppPtTEnd()->span();
caryclark55888e42016-07-18 10:01:36 -0700476 }
477 if (test != end) {
caryclark30b9fdd2016-08-31 14:36:29 -0700478 FAIL_IF(!test->upCastable());
caryclark8016b262016-09-06 05:59:47 -0700479 priorT = test->t();
caryclark55888e42016-07-18 10:01:36 -0700480 test = test->upCast()->next();
481 }
482 if (oTest != oEnd) {
caryclark8016b262016-09-06 05:59:47 -0700483 oPriorT = oTest->t();
caryclark55888e42016-07-18 10:01:36 -0700484 oTest = coin->flipped() ? oTest->prev() : oTest->upCast()->next();
caryclark30b9fdd2016-08-31 14:36:29 -0700485 FAIL_IF(!oTest);
caryclark55888e42016-07-18 10:01:36 -0700486 }
caryclark8016b262016-09-06 05:59:47 -0700487
caryclark55888e42016-07-18 10:01:36 -0700488 }
489 } while ((coin = coin->next()));
490 return true;
491}
492
caryclark55888e42016-07-18 10:01:36 -0700493// given a t span, map the same range on the coincident span
caryclark8016b262016-09-06 05:59:47 -0700494/*
495the curves may not scale linearly, so interpolation may only happen within known points
496remap over1s, over1e, cointPtTStart, coinPtTEnd to smallest range that captures over1s
497then repeat to capture over1e
498*/
499double SkOpCoincidence::TRange(const SkOpPtT* overS, double t,
500 const SkOpSegment* coinSeg SkDEBUGPARAMS(const SkOpPtT* overE)) {
501 const SkOpSpanBase* work = overS->span();
502 const SkOpPtT* foundStart = nullptr;
503 const SkOpPtT* foundEnd = nullptr;
504 const SkOpPtT* coinStart = nullptr;
505 const SkOpPtT* coinEnd = nullptr;
506 do {
507 const SkOpPtT* contained = work->contains(coinSeg);
508 if (!contained) {
caryclarkc9b90d12016-09-09 07:41:36 -0700509 if (work->final()) {
510 break;
caryclarkb393a492016-09-07 08:21:09 -0700511 }
caryclark8016b262016-09-06 05:59:47 -0700512 continue;
513 }
514 if (work->t() <= t) {
515 coinStart = contained;
516 foundStart = work->ptT();
517 }
518 if (work->t() >= t) {
519 coinEnd = contained;
520 foundEnd = work->ptT();
521 break;
522 }
523 SkASSERT(work->ptT() != overE);
524 } while ((work = work->upCast()->next()));
caryclarkc9b90d12016-09-09 07:41:36 -0700525 if (!coinStart || !coinEnd) {
526 return 1;
527 }
caryclark8016b262016-09-06 05:59:47 -0700528 // while overS->fT <=t and overS contains coinSeg
529 double denom = foundEnd->fT - foundStart->fT;
530 double sRatio = denom ? (t - foundStart->fT) / denom : 1;
531 return coinStart->fT + (coinEnd->fT - coinStart->fT) * sRatio;
caryclark54359292015-03-26 07:52:43 -0700532}
533
caryclark55888e42016-07-18 10:01:36 -0700534// return true if span overlaps existing and needs to adjust the coincident list
535bool SkOpCoincidence::checkOverlap(SkCoincidentSpans* check,
536 const SkOpSegment* coinSeg, const SkOpSegment* oppSeg,
537 double coinTs, double coinTe, double oppTs, double oppTe,
538 SkTDArray<SkCoincidentSpans*>* overlaps) const {
539 if (!Ordered(coinSeg, oppSeg)) {
540 if (oppTs < oppTe) {
541 return this->checkOverlap(check, oppSeg, coinSeg, oppTs, oppTe, coinTs, coinTe,
542 overlaps);
543 }
544 return this->checkOverlap(check, oppSeg, coinSeg, oppTe, oppTs, coinTe, coinTs, overlaps);
545 }
546 bool swapOpp = oppTs > oppTe;
547 if (swapOpp) {
548 SkTSwap(oppTs, oppTe);
549 }
caryclark27c8eb82015-07-06 11:38:33 -0700550 do {
caryclark55888e42016-07-18 10:01:36 -0700551 if (check->coinPtTStart()->segment() != coinSeg) {
552 continue;
caryclark1c9ce612015-11-20 14:06:28 -0800553 }
caryclark55888e42016-07-18 10:01:36 -0700554 if (check->oppPtTStart()->segment() != oppSeg) {
555 continue;
caryclarkdae6b972016-06-08 04:28:19 -0700556 }
caryclark55888e42016-07-18 10:01:36 -0700557 double checkTs = check->coinPtTStart()->fT;
558 double checkTe = check->coinPtTEnd()->fT;
559 bool coinOutside = coinTe < checkTs || coinTs > checkTe;
560 double oCheckTs = check->oppPtTStart()->fT;
561 double oCheckTe = check->oppPtTEnd()->fT;
562 if (swapOpp) {
563 if (oCheckTs <= oCheckTe) {
caryclark81a478c2016-09-09 09:37:57 -0700564 return false;
caryclark27c8eb82015-07-06 11:38:33 -0700565 }
caryclark55888e42016-07-18 10:01:36 -0700566 SkTSwap(oCheckTs, oCheckTe);
caryclark27c8eb82015-07-06 11:38:33 -0700567 }
caryclark55888e42016-07-18 10:01:36 -0700568 bool oppOutside = oppTe < oCheckTs || oppTs > oCheckTe;
569 if (coinOutside && oppOutside) {
570 continue;
571 }
572 bool coinInside = coinTe <= checkTe && coinTs >= checkTs;
573 bool oppInside = oppTe <= oCheckTe && oppTs >= oCheckTs;
caryclark81a478c2016-09-09 09:37:57 -0700574 if (coinInside && oppInside) { // already included, do nothing
575 return false;
caryclark55888e42016-07-18 10:01:36 -0700576 }
577 *overlaps->append() = check; // partial overlap, extend existing entry
578 } while ((check = check->next()));
caryclark26ad22a2015-10-16 09:03:38 -0700579 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700580}
581
caryclark55888e42016-07-18 10:01:36 -0700582/* Please keep this in sync with debugAddIfMissing() */
caryclark8016b262016-09-06 05:59:47 -0700583// note that over1s, over1e, over2s, over2e are ordered
584bool SkOpCoincidence::addIfMissing(const SkOpPtT* over1s, const SkOpPtT* over2s,
caryclark81a478c2016-09-09 09:37:57 -0700585 double tStart, double tEnd, SkOpSegment* coinSeg, SkOpSegment* oppSeg, bool* added
caryclark8016b262016-09-06 05:59:47 -0700586 SkDEBUGPARAMS(const SkOpPtT* over1e) SkDEBUGPARAMS(const SkOpPtT* over2e)) {
587 SkASSERT(tStart < tEnd);
588 SkASSERT(over1s->fT < over1e->fT);
589 SkASSERT(between(over1s->fT, tStart, over1e->fT));
590 SkASSERT(between(over1s->fT, tEnd, over1e->fT));
591 SkASSERT(over2s->fT < over2e->fT);
592 SkASSERT(between(over2s->fT, tStart, over2e->fT));
593 SkASSERT(between(over2s->fT, tEnd, over2e->fT));
594 SkASSERT(over1s->segment() == over1e->segment());
595 SkASSERT(over2s->segment() == over2e->segment());
596 SkASSERT(over1s->segment() == over2s->segment());
597 SkASSERT(over1s->segment() != coinSeg);
598 SkASSERT(over1s->segment() != oppSeg);
599 SkASSERT(coinSeg != oppSeg);
caryclark54359292015-03-26 07:52:43 -0700600 double coinTs, coinTe, oppTs, oppTe;
caryclark8016b262016-09-06 05:59:47 -0700601 coinTs = TRange(over1s, tStart, coinSeg SkDEBUGPARAMS(over1e));
602 coinTe = TRange(over1s, tEnd, coinSeg SkDEBUGPARAMS(over1e));
caryclark30b9fdd2016-08-31 14:36:29 -0700603 if (coinSeg->collapsed(coinTs, coinTe)) {
caryclark81a478c2016-09-09 09:37:57 -0700604 return true;
caryclark30b9fdd2016-08-31 14:36:29 -0700605 }
caryclark8016b262016-09-06 05:59:47 -0700606 oppTs = TRange(over2s, tStart, oppSeg SkDEBUGPARAMS(over2e));
607 oppTe = TRange(over2s, tEnd, oppSeg SkDEBUGPARAMS(over2e));
caryclark30b9fdd2016-08-31 14:36:29 -0700608 if (oppSeg->collapsed(oppTs, oppTe)) {
caryclark81a478c2016-09-09 09:37:57 -0700609 return true;
caryclark30b9fdd2016-08-31 14:36:29 -0700610 }
caryclark8016b262016-09-06 05:59:47 -0700611 if (coinTs > coinTe) {
caryclark55888e42016-07-18 10:01:36 -0700612 SkTSwap(coinTs, coinTe);
caryclark54359292015-03-26 07:52:43 -0700613 SkTSwap(oppTs, oppTe);
614 }
caryclark81a478c2016-09-09 09:37:57 -0700615 return this->addOrOverlap(coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, added);
caryclark54359292015-03-26 07:52:43 -0700616}
617
caryclark55888e42016-07-18 10:01:36 -0700618/* Please keep this in sync with debugAddOrOverlap() */
caryclark025b11e2016-08-25 05:21:14 -0700619// If this is called by addEndMovedSpans(), a returned false propogates out to an abort.
620// If this is called by AddIfMissing(), a returned false indicates there was nothing to add
caryclark55888e42016-07-18 10:01:36 -0700621bool SkOpCoincidence::addOrOverlap(SkOpSegment* coinSeg, SkOpSegment* oppSeg,
caryclark81a478c2016-09-09 09:37:57 -0700622 double coinTs, double coinTe, double oppTs, double oppTe, bool* added) {
caryclark55888e42016-07-18 10:01:36 -0700623 SkTDArray<SkCoincidentSpans*> overlaps;
caryclark81a478c2016-09-09 09:37:57 -0700624 FAIL_IF(!fTop);
caryclark55888e42016-07-18 10:01:36 -0700625 if (!this->checkOverlap(fTop, coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, &overlaps)) {
caryclark81a478c2016-09-09 09:37:57 -0700626 return true;
caryclark55888e42016-07-18 10:01:36 -0700627 }
628 if (fHead && !this->checkOverlap(fHead, coinSeg, oppSeg, coinTs,
629 coinTe, oppTs, oppTe, &overlaps)) {
caryclark81a478c2016-09-09 09:37:57 -0700630 return true;
caryclark55888e42016-07-18 10:01:36 -0700631 }
632 SkCoincidentSpans* overlap = overlaps.count() ? overlaps[0] : nullptr;
633 for (int index = 1; index < overlaps.count(); ++index) { // combine overlaps before continuing
634 SkCoincidentSpans* test = overlaps[index];
635 if (overlap->coinPtTStart()->fT > test->coinPtTStart()->fT) {
636 overlap->setCoinPtTStart(test->coinPtTStart());
637 }
638 if (overlap->coinPtTEnd()->fT < test->coinPtTEnd()->fT) {
639 overlap->setCoinPtTEnd(test->coinPtTEnd());
640 }
641 if (overlap->flipped()
642 ? overlap->oppPtTStart()->fT < test->oppPtTStart()->fT
643 : overlap->oppPtTStart()->fT > test->oppPtTStart()->fT) {
644 overlap->setOppPtTStart(test->oppPtTStart());
645 }
646 if (overlap->flipped()
647 ? overlap->oppPtTEnd()->fT > test->oppPtTEnd()->fT
648 : overlap->oppPtTEnd()->fT < test->oppPtTEnd()->fT) {
649 overlap->setOppPtTEnd(test->oppPtTEnd());
650 }
651 if (!fHead || !this->release(fHead, test)) {
652 SkAssertResult(this->release(fTop, test));
653 }
654 }
655 const SkOpPtT* cs = coinSeg->existing(coinTs, oppSeg);
656 const SkOpPtT* ce = coinSeg->existing(coinTe, oppSeg);
caryclark81a478c2016-09-09 09:37:57 -0700657 if (overlap && cs && ce && overlap->contains(cs, ce)) {
658 return true;
659 }
660 FAIL_IF(cs == ce && cs);
caryclark55888e42016-07-18 10:01:36 -0700661 const SkOpPtT* os = oppSeg->existing(oppTs, coinSeg);
662 const SkOpPtT* oe = oppSeg->existing(oppTe, coinSeg);
caryclark81a478c2016-09-09 09:37:57 -0700663 if (overlap && os && oe && overlap->contains(os, oe)) {
664 return true;
665 }
caryclark55888e42016-07-18 10:01:36 -0700666 SkASSERT(!cs || !cs->deleted());
667 SkASSERT(!os || !os->deleted());
668 SkASSERT(!ce || !ce->deleted());
669 SkASSERT(!oe || !oe->deleted());
670 const SkOpPtT* csExisting = !cs ? coinSeg->existing(coinTs, nullptr) : nullptr;
671 const SkOpPtT* ceExisting = !ce ? coinSeg->existing(coinTe, nullptr) : nullptr;
caryclark81a478c2016-09-09 09:37:57 -0700672 FAIL_IF(csExisting && csExisting == ceExisting);
caryclarke839e782016-09-15 07:48:18 -0700673// FAIL_IF(csExisting && (csExisting == ce ||
674// csExisting->contains(ceExisting ? ceExisting : ce)));
caryclark81a478c2016-09-09 09:37:57 -0700675 FAIL_IF(ceExisting && (ceExisting == cs ||
caryclark025b11e2016-08-25 05:21:14 -0700676 ceExisting->contains(csExisting ? csExisting : cs)));
caryclark55888e42016-07-18 10:01:36 -0700677 const SkOpPtT* osExisting = !os ? oppSeg->existing(oppTs, nullptr) : nullptr;
678 const SkOpPtT* oeExisting = !oe ? oppSeg->existing(oppTe, nullptr) : nullptr;
caryclark81a478c2016-09-09 09:37:57 -0700679 FAIL_IF(osExisting && osExisting == oeExisting);
680 FAIL_IF(osExisting && (osExisting == oe ||
caryclark025b11e2016-08-25 05:21:14 -0700681 osExisting->contains(oeExisting ? oeExisting : oe)));
caryclark81a478c2016-09-09 09:37:57 -0700682 FAIL_IF(oeExisting && (oeExisting == os ||
caryclark025b11e2016-08-25 05:21:14 -0700683 oeExisting->contains(osExisting ? osExisting : os)));
caryclark55888e42016-07-18 10:01:36 -0700684 // extra line in debug code
685 this->debugValidate();
686 if (!cs || !os) {
687 SkOpPtT* csWritable = cs ? const_cast<SkOpPtT*>(cs)
caryclark29b25632016-08-25 11:27:17 -0700688 : coinSeg->addT(coinTs);
caryclarke839e782016-09-15 07:48:18 -0700689 if (csWritable == ce) {
690 return true;
691 }
caryclark55888e42016-07-18 10:01:36 -0700692 SkOpPtT* osWritable = os ? const_cast<SkOpPtT*>(os)
caryclark29b25632016-08-25 11:27:17 -0700693 : oppSeg->addT(oppTs);
caryclark81a478c2016-09-09 09:37:57 -0700694 FAIL_IF(!csWritable || !osWritable);
caryclark30b9fdd2016-08-31 14:36:29 -0700695 csWritable->span()->addOpp(osWritable->span());
caryclark55888e42016-07-18 10:01:36 -0700696 cs = csWritable;
caryclark30b9fdd2016-08-31 14:36:29 -0700697 os = osWritable->active();
caryclark81a478c2016-09-09 09:37:57 -0700698 FAIL_IF((ce && ce->deleted()) || (oe && oe->deleted()));
caryclark55888e42016-07-18 10:01:36 -0700699 }
700 if (!ce || !oe) {
701 SkOpPtT* ceWritable = ce ? const_cast<SkOpPtT*>(ce)
caryclark29b25632016-08-25 11:27:17 -0700702 : coinSeg->addT(coinTe);
caryclark55888e42016-07-18 10:01:36 -0700703 SkOpPtT* oeWritable = oe ? const_cast<SkOpPtT*>(oe)
caryclark29b25632016-08-25 11:27:17 -0700704 : oppSeg->addT(oppTe);
caryclark30b9fdd2016-08-31 14:36:29 -0700705 ceWritable->span()->addOpp(oeWritable->span());
caryclark55888e42016-07-18 10:01:36 -0700706 ce = ceWritable;
707 oe = oeWritable;
708 }
709 this->debugValidate();
caryclark81a478c2016-09-09 09:37:57 -0700710 FAIL_IF(cs->deleted());
711 FAIL_IF(os->deleted());
712 FAIL_IF(ce->deleted());
713 FAIL_IF(oe->deleted());
714 FAIL_IF(cs->contains(ce) || os->contains(oe));
caryclark55888e42016-07-18 10:01:36 -0700715 bool result = true;
716 if (overlap) {
717 if (overlap->coinPtTStart()->segment() == coinSeg) {
718 result = overlap->extend(cs, ce, os, oe);
719 } else {
720 if (os->fT > oe->fT) {
721 SkTSwap(cs, ce);
722 SkTSwap(os, oe);
723 }
724 result = overlap->extend(os, oe, cs, ce);
725 }
726#if DEBUG_COINCIDENCE_VERBOSE
727 if (result) {
728 overlaps[0]->debugShow();
729 }
730#endif
731 } else {
732 this->add(cs, ce, os, oe);
733#if DEBUG_COINCIDENCE_VERBOSE
734 fHead->debugShow();
735#endif
736 }
737 this->debugValidate();
caryclark81a478c2016-09-09 09:37:57 -0700738 if (result) {
739 *added = true;
740 }
741 return true;
caryclark55888e42016-07-18 10:01:36 -0700742}
743
744// Please keep this in sync with debugAddMissing()
caryclark27c8eb82015-07-06 11:38:33 -0700745/* detects overlaps of different coincident runs on same segment */
746/* does not detect overlaps for pairs without any segments in common */
caryclark55888e42016-07-18 10:01:36 -0700747// returns true if caller should loop again
Cary Clarkab87d7a2016-10-04 10:01:04 -0400748bool SkOpCoincidence::addMissing(bool* added DEBUG_COIN_DECLARE_PARAMS()) {
caryclark27c8eb82015-07-06 11:38:33 -0700749 SkCoincidentSpans* outer = fHead;
caryclark81a478c2016-09-09 09:37:57 -0700750 *added = false;
caryclark54359292015-03-26 07:52:43 -0700751 if (!outer) {
caryclark81a478c2016-09-09 09:37:57 -0700752 return true;
caryclark54359292015-03-26 07:52:43 -0700753 }
caryclark27c8eb82015-07-06 11:38:33 -0700754 fTop = outer;
halcanary96fcdcc2015-08-27 07:41:13 -0700755 fHead = nullptr;
caryclark54359292015-03-26 07:52:43 -0700756 do {
caryclark27c8eb82015-07-06 11:38:33 -0700757 // addifmissing can modify the list that this is walking
caryclark26ad22a2015-10-16 09:03:38 -0700758 // save head so that walker can iterate over old data unperturbed
759 // addifmissing adds to head freely then add saved head in the end
caryclark8016b262016-09-06 05:59:47 -0700760 const SkOpPtT* ocs = outer->coinPtTStart();
caryclarka35ab3e2016-10-20 08:32:18 -0700761 FAIL_IF(ocs->deleted());
caryclark8016b262016-09-06 05:59:47 -0700762 const SkOpSegment* outerCoin = ocs->segment();
763 SkASSERT(!outerCoin->done()); // if it's done, should have already been removed from list
764 const SkOpPtT* oos = outer->oppPtTStart();
caryclarkb393a492016-09-07 08:21:09 -0700765 if (oos->deleted()) {
caryclark81a478c2016-09-09 09:37:57 -0700766 return true;
caryclarkb393a492016-09-07 08:21:09 -0700767 }
caryclark8016b262016-09-06 05:59:47 -0700768 const SkOpSegment* outerOpp = oos->segment();
769 SkASSERT(!outerOpp->done());
770 SkOpSegment* outerCoinWritable = const_cast<SkOpSegment*>(outerCoin);
771 SkOpSegment* outerOppWritable = const_cast<SkOpSegment*>(outerOpp);
caryclark54359292015-03-26 07:52:43 -0700772 SkCoincidentSpans* inner = outer;
caryclark55888e42016-07-18 10:01:36 -0700773 while ((inner = inner->next())) {
774 this->debugValidate();
caryclark54359292015-03-26 07:52:43 -0700775 double overS, overE;
caryclark8016b262016-09-06 05:59:47 -0700776 const SkOpPtT* ics = inner->coinPtTStart();
caryclark221a4bb2016-10-07 11:15:15 -0700777 FAIL_IF(ics->deleted());
caryclark8016b262016-09-06 05:59:47 -0700778 const SkOpSegment* innerCoin = ics->segment();
caryclarka35ab3e2016-10-20 08:32:18 -0700779 FAIL_IF(innerCoin->done());
caryclark8016b262016-09-06 05:59:47 -0700780 const SkOpPtT* ios = inner->oppPtTStart();
caryclarka35ab3e2016-10-20 08:32:18 -0700781 FAIL_IF(ios->deleted());
caryclark8016b262016-09-06 05:59:47 -0700782 const SkOpSegment* innerOpp = ios->segment();
783 SkASSERT(!innerOpp->done());
784 SkOpSegment* innerCoinWritable = const_cast<SkOpSegment*>(innerCoin);
785 SkOpSegment* innerOppWritable = const_cast<SkOpSegment*>(innerOpp);
caryclark55888e42016-07-18 10:01:36 -0700786 if (outerCoin == innerCoin) {
caryclark8016b262016-09-06 05:59:47 -0700787 const SkOpPtT* oce = outer->coinPtTEnd();
caryclarkb393a492016-09-07 08:21:09 -0700788 if (oce->deleted()) {
caryclark81a478c2016-09-09 09:37:57 -0700789 return true;
caryclarkb393a492016-09-07 08:21:09 -0700790 }
caryclark8016b262016-09-06 05:59:47 -0700791 const SkOpPtT* ice = inner->coinPtTEnd();
792 SkASSERT(!ice->deleted());
793 if (outerOpp != innerOpp && this->overlap(ocs, oce, ics, ice, &overS, &overE)) {
caryclark81a478c2016-09-09 09:37:57 -0700794 (void) this->addIfMissing(ocs->starter(oce), ics->starter(ice),
795 overS, overE, outerOppWritable, innerOppWritable, added
caryclark8016b262016-09-06 05:59:47 -0700796 SkDEBUGPARAMS(ocs->debugEnder(oce))
797 SkDEBUGPARAMS(ics->debugEnder(ice)));
caryclark55888e42016-07-18 10:01:36 -0700798 }
799 } else if (outerCoin == innerOpp) {
caryclark8016b262016-09-06 05:59:47 -0700800 const SkOpPtT* oce = outer->coinPtTEnd();
801 SkASSERT(!oce->deleted());
802 const SkOpPtT* ioe = inner->oppPtTEnd();
803 SkASSERT(!ioe->deleted());
804 if (outerOpp != innerCoin && this->overlap(ocs, oce, ios, ioe, &overS, &overE)) {
caryclark81a478c2016-09-09 09:37:57 -0700805 (void) this->addIfMissing(ocs->starter(oce), ios->starter(ioe),
806 overS, overE, outerOppWritable, innerCoinWritable, added
caryclark8016b262016-09-06 05:59:47 -0700807 SkDEBUGPARAMS(ocs->debugEnder(oce))
808 SkDEBUGPARAMS(ios->debugEnder(ioe)));
caryclark55888e42016-07-18 10:01:36 -0700809 }
810 } else if (outerOpp == innerCoin) {
caryclark8016b262016-09-06 05:59:47 -0700811 const SkOpPtT* ooe = outer->oppPtTEnd();
812 SkASSERT(!ooe->deleted());
813 const SkOpPtT* ice = inner->coinPtTEnd();
814 SkASSERT(!ice->deleted());
caryclark55888e42016-07-18 10:01:36 -0700815 SkASSERT(outerCoin != innerOpp);
caryclark8016b262016-09-06 05:59:47 -0700816 if (this->overlap(oos, ooe, ics, ice, &overS, &overE)) {
caryclark81a478c2016-09-09 09:37:57 -0700817 (void) this->addIfMissing(oos->starter(ooe), ics->starter(ice),
818 overS, overE, outerCoinWritable, innerOppWritable, added
caryclark8016b262016-09-06 05:59:47 -0700819 SkDEBUGPARAMS(oos->debugEnder(ooe))
820 SkDEBUGPARAMS(ics->debugEnder(ice)));
caryclark55888e42016-07-18 10:01:36 -0700821 }
822 } else if (outerOpp == innerOpp) {
caryclark8016b262016-09-06 05:59:47 -0700823 const SkOpPtT* ooe = outer->oppPtTEnd();
824 SkASSERT(!ooe->deleted());
825 const SkOpPtT* ioe = inner->oppPtTEnd();
caryclarkb393a492016-09-07 08:21:09 -0700826 if (ioe->deleted()) {
caryclark81a478c2016-09-09 09:37:57 -0700827 return true;
caryclarkb393a492016-09-07 08:21:09 -0700828 }
caryclark55888e42016-07-18 10:01:36 -0700829 SkASSERT(outerCoin != innerCoin);
caryclark8016b262016-09-06 05:59:47 -0700830 if (this->overlap(oos, ooe, ios, ioe, &overS, &overE)) {
caryclark81a478c2016-09-09 09:37:57 -0700831 (void) this->addIfMissing(oos->starter(ooe), ios->starter(ioe),
832 overS, overE, outerCoinWritable, innerCoinWritable, added
caryclark8016b262016-09-06 05:59:47 -0700833 SkDEBUGPARAMS(oos->debugEnder(ooe))
834 SkDEBUGPARAMS(ios->debugEnder(ioe)));
caryclark54359292015-03-26 07:52:43 -0700835 }
836 }
caryclark55888e42016-07-18 10:01:36 -0700837 this->debugValidate();
caryclark54359292015-03-26 07:52:43 -0700838 }
caryclark55888e42016-07-18 10:01:36 -0700839 } while ((outer = outer->next()));
840 this->restoreHead();
caryclark81a478c2016-09-09 09:37:57 -0700841 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700842}
843
caryclark55888e42016-07-18 10:01:36 -0700844bool SkOpCoincidence::addOverlap(const SkOpSegment* seg1, const SkOpSegment* seg1o,
845 const SkOpSegment* seg2, const SkOpSegment* seg2o,
846 const SkOpPtT* overS, const SkOpPtT* overE) {
Cary Clarke47ae292016-10-05 08:51:39 -0400847 const SkOpPtT* s1 = overS->find(seg1);
848 const SkOpPtT* e1 = overE->find(seg1);
caryclark08714012016-10-07 12:57:47 -0700849 FAIL_IF(!s1);
Cary Clark40f23782016-10-06 12:04:16 -0400850 FAIL_IF(!e1);
caryclark27c8eb82015-07-06 11:38:33 -0700851 if (!s1->starter(e1)->span()->upCast()->windValue()) {
Cary Clarke47ae292016-10-05 08:51:39 -0400852 s1 = overS->find(seg1o);
853 e1 = overE->find(seg1o);
caryclark221a4bb2016-10-07 11:15:15 -0700854 FAIL_IF(!s1);
Cary Clark40f23782016-10-06 12:04:16 -0400855 FAIL_IF(!e1);
caryclark27c8eb82015-07-06 11:38:33 -0700856 if (!s1->starter(e1)->span()->upCast()->windValue()) {
caryclark3f0753d2016-06-28 09:23:57 -0700857 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700858 }
859 }
Cary Clarke47ae292016-10-05 08:51:39 -0400860 const SkOpPtT* s2 = overS->find(seg2);
861 const SkOpPtT* e2 = overE->find(seg2);
caryclarka35ab3e2016-10-20 08:32:18 -0700862 FAIL_IF(!e2);
caryclark27c8eb82015-07-06 11:38:33 -0700863 if (!s2->starter(e2)->span()->upCast()->windValue()) {
Cary Clarke47ae292016-10-05 08:51:39 -0400864 s2 = overS->find(seg2o);
865 e2 = overE->find(seg2o);
caryclarka35ab3e2016-10-20 08:32:18 -0700866 FAIL_IF(!s2);
caryclark27c8eb82015-07-06 11:38:33 -0700867 if (!s2->starter(e2)->span()->upCast()->windValue()) {
caryclark3f0753d2016-06-28 09:23:57 -0700868 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700869 }
870 }
871 if (s1->segment() == s2->segment()) {
caryclark3f0753d2016-06-28 09:23:57 -0700872 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700873 }
874 if (s1->fT > e1->fT) {
875 SkTSwap(s1, e1);
876 SkTSwap(s2, e2);
877 }
caryclark55888e42016-07-18 10:01:36 -0700878 this->add(s1, e1, s2, e2);
caryclark3f0753d2016-06-28 09:23:57 -0700879 return true;
caryclark54359292015-03-26 07:52:43 -0700880}
881
caryclark55888e42016-07-18 10:01:36 -0700882bool SkOpCoincidence::contains(const SkOpSegment* seg, const SkOpSegment* opp, double oppT) const {
883 if (this->contains(fHead, seg, opp, oppT)) {
884 return true;
885 }
886 if (this->contains(fTop, seg, opp, oppT)) {
887 return true;
888 }
889 return false;
890}
891
892bool SkOpCoincidence::contains(const SkCoincidentSpans* coin, const SkOpSegment* seg,
893 const SkOpSegment* opp, double oppT) const {
894 if (!coin) {
895 return false;
896 }
897 do {
898 if (coin->coinPtTStart()->segment() == seg && coin->oppPtTStart()->segment() == opp
899 && between(coin->oppPtTStart()->fT, oppT, coin->oppPtTEnd()->fT)) {
caryclark54359292015-03-26 07:52:43 -0700900 return true;
901 }
caryclark55888e42016-07-18 10:01:36 -0700902 if (coin->oppPtTStart()->segment() == seg && coin->coinPtTStart()->segment() == opp
903 && between(coin->coinPtTStart()->fT, oppT, coin->coinPtTEnd()->fT)) {
904 return true;
905 }
906 } while ((coin = coin->next()));
caryclark54359292015-03-26 07:52:43 -0700907 return false;
908}
909
caryclark55888e42016-07-18 10:01:36 -0700910bool SkOpCoincidence::contains(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd,
911 const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) const {
912 const SkCoincidentSpans* test = fHead;
913 if (!test) {
914 return false;
915 }
916 const SkOpSegment* coinSeg = coinPtTStart->segment();
917 const SkOpSegment* oppSeg = oppPtTStart->segment();
918 if (!Ordered(coinPtTStart, oppPtTStart)) {
919 SkTSwap(coinSeg, oppSeg);
920 SkTSwap(coinPtTStart, oppPtTStart);
921 SkTSwap(coinPtTEnd, oppPtTEnd);
922 if (coinPtTStart->fT > coinPtTEnd->fT) {
923 SkTSwap(coinPtTStart, coinPtTEnd);
924 SkTSwap(oppPtTStart, oppPtTEnd);
925 }
926 }
927 double oppMinT = SkTMin(oppPtTStart->fT, oppPtTEnd->fT);
928 double oppMaxT = SkTMax(oppPtTStart->fT, oppPtTEnd->fT);
929 do {
930 if (coinSeg != test->coinPtTStart()->segment()) {
931 continue;
932 }
933 if (coinPtTStart->fT < test->coinPtTStart()->fT) {
934 continue;
935 }
936 if (coinPtTEnd->fT > test->coinPtTEnd()->fT) {
937 continue;
938 }
939 if (oppSeg != test->oppPtTStart()->segment()) {
940 continue;
941 }
942 if (oppMinT < SkTMin(test->oppPtTStart()->fT, test->oppPtTEnd()->fT)) {
943 continue;
944 }
945 if (oppMaxT > SkTMax(test->oppPtTStart()->fT, test->oppPtTEnd()->fT)) {
946 continue;
947 }
948 return true;
949 } while ((test = test->next()));
950 return false;
951}
952
Cary Clarkab87d7a2016-10-04 10:01:04 -0400953void SkOpCoincidence::correctEnds(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
954 DEBUG_SET_PHASE();
caryclark55888e42016-07-18 10:01:36 -0700955 SkCoincidentSpans* coin = fHead;
956 if (!coin) {
957 return;
958 }
959 do {
960 coin->correctEnds();
961 } while ((coin = coin->next()));
962}
963
caryclark54359292015-03-26 07:52:43 -0700964// walk span sets in parallel, moving winding from one to the other
caryclarka35ab3e2016-10-20 08:32:18 -0700965bool SkOpCoincidence::apply(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
Cary Clarkab87d7a2016-10-04 10:01:04 -0400966 DEBUG_SET_PHASE();
caryclark54359292015-03-26 07:52:43 -0700967 SkCoincidentSpans* coin = fHead;
968 if (!coin) {
caryclarka35ab3e2016-10-20 08:32:18 -0700969 return true;
caryclark54359292015-03-26 07:52:43 -0700970 }
971 do {
caryclark55888e42016-07-18 10:01:36 -0700972 SkOpSpan* start = coin->coinPtTStartWritable()->span()->upCast();
caryclark182b4992015-05-14 05:45:54 -0700973 if (start->deleted()) {
974 continue;
975 }
caryclark55888e42016-07-18 10:01:36 -0700976 const SkOpSpanBase* end = coin->coinPtTEnd()->span();
caryclark54359292015-03-26 07:52:43 -0700977 SkASSERT(start == start->starter(end));
caryclark55888e42016-07-18 10:01:36 -0700978 bool flipped = coin->flipped();
979 SkOpSpan* oStart = (flipped ? coin->oppPtTEndWritable()
980 : coin->oppPtTStartWritable())->span()->upCast();
caryclark182b4992015-05-14 05:45:54 -0700981 if (oStart->deleted()) {
982 continue;
983 }
caryclark55888e42016-07-18 10:01:36 -0700984 const SkOpSpanBase* oEnd = (flipped ? coin->oppPtTStart() : coin->oppPtTEnd())->span();
caryclark54359292015-03-26 07:52:43 -0700985 SkASSERT(oStart == oStart->starter(oEnd));
986 SkOpSegment* segment = start->segment();
987 SkOpSegment* oSegment = oStart->segment();
988 bool operandSwap = segment->operand() != oSegment->operand();
989 if (flipped) {
caryclark364a0072015-12-14 08:43:21 -0800990 if (oEnd->deleted()) {
991 continue;
992 }
caryclark54359292015-03-26 07:52:43 -0700993 do {
994 SkOpSpanBase* oNext = oStart->next();
995 if (oNext == oEnd) {
996 break;
997 }
998 oStart = oNext->upCast();
999 } while (true);
1000 }
caryclark54359292015-03-26 07:52:43 -07001001 do {
1002 int windValue = start->windValue();
caryclark54359292015-03-26 07:52:43 -07001003 int oppValue = start->oppValue();
caryclark1049f122015-04-20 08:31:59 -07001004 int oWindValue = oStart->windValue();
caryclark54359292015-03-26 07:52:43 -07001005 int oOppValue = oStart->oppValue();
1006 // winding values are added or subtracted depending on direction and wind type
1007 // same or opposite values are summed depending on the operand value
caryclark1049f122015-04-20 08:31:59 -07001008 int windDiff = operandSwap ? oOppValue : oWindValue;
1009 int oWindDiff = operandSwap ? oppValue : windValue;
1010 if (!flipped) {
1011 windDiff = -windDiff;
1012 oWindDiff = -oWindDiff;
1013 }
caryclark55888e42016-07-18 10:01:36 -07001014 bool addToStart = windValue && (windValue > windDiff || (windValue == windDiff
1015 && oWindValue <= oWindDiff));
1016 if (addToStart ? start->done() : oStart->done()) {
1017 addToStart ^= true;
1018 }
1019 if (addToStart) {
caryclark54359292015-03-26 07:52:43 -07001020 if (operandSwap) {
1021 SkTSwap(oWindValue, oOppValue);
1022 }
1023 if (flipped) {
1024 windValue -= oWindValue;
1025 oppValue -= oOppValue;
1026 } else {
1027 windValue += oWindValue;
1028 oppValue += oOppValue;
1029 }
caryclark1049f122015-04-20 08:31:59 -07001030 if (segment->isXor()) {
caryclark54359292015-03-26 07:52:43 -07001031 windValue &= 1;
1032 }
caryclark1049f122015-04-20 08:31:59 -07001033 if (segment->oppXor()) {
caryclark54359292015-03-26 07:52:43 -07001034 oppValue &= 1;
1035 }
1036 oWindValue = oOppValue = 0;
1037 } else {
1038 if (operandSwap) {
1039 SkTSwap(windValue, oppValue);
1040 }
1041 if (flipped) {
1042 oWindValue -= windValue;
1043 oOppValue -= oppValue;
1044 } else {
1045 oWindValue += windValue;
1046 oOppValue += oppValue;
1047 }
caryclark1049f122015-04-20 08:31:59 -07001048 if (oSegment->isXor()) {
caryclark54359292015-03-26 07:52:43 -07001049 oWindValue &= 1;
1050 }
caryclark1049f122015-04-20 08:31:59 -07001051 if (oSegment->oppXor()) {
1052 oOppValue &= 1;
1053 }
caryclark54359292015-03-26 07:52:43 -07001054 windValue = oppValue = 0;
1055 }
caryclark6c3b9cd2016-09-26 05:36:58 -07001056#if 0 && DEBUG_COINCIDENCE
caryclark55888e42016-07-18 10:01:36 -07001057 SkDebugf("seg=%d span=%d windValue=%d oppValue=%d\n", segment->debugID(),
1058 start->debugID(), windValue, oppValue);
1059 SkDebugf("seg=%d span=%d windValue=%d oppValue=%d\n", oSegment->debugID(),
1060 oStart->debugID(), oWindValue, oOppValue);
1061#endif
caryclark54359292015-03-26 07:52:43 -07001062 start->setWindValue(windValue);
1063 start->setOppValue(oppValue);
caryclarka35ab3e2016-10-20 08:32:18 -07001064 FAIL_IF(oWindValue == -1);
caryclark54359292015-03-26 07:52:43 -07001065 oStart->setWindValue(oWindValue);
1066 oStart->setOppValue(oOppValue);
1067 if (!windValue && !oppValue) {
1068 segment->markDone(start);
1069 }
1070 if (!oWindValue && !oOppValue) {
1071 oSegment->markDone(oStart);
1072 }
1073 SkOpSpanBase* next = start->next();
1074 SkOpSpanBase* oNext = flipped ? oStart->prev() : oStart->next();
1075 if (next == end) {
1076 break;
1077 }
1078 start = next->upCast();
caryclark1049f122015-04-20 08:31:59 -07001079 // if the opposite ran out too soon, just reuse the last span
1080 if (!oNext || !oNext->upCastable()) {
1081 oNext = oStart;
caryclark54359292015-03-26 07:52:43 -07001082 }
1083 oStart = oNext->upCast();
1084 } while (true);
caryclark55888e42016-07-18 10:01:36 -07001085 } while ((coin = coin->next()));
caryclarka35ab3e2016-10-20 08:32:18 -07001086 return true;
caryclark54359292015-03-26 07:52:43 -07001087}
1088
caryclark55888e42016-07-18 10:01:36 -07001089// Please keep this in sync with debugRelease()
1090bool SkOpCoincidence::release(SkCoincidentSpans* coin, SkCoincidentSpans* remove) {
1091 SkCoincidentSpans* head = coin;
halcanary96fcdcc2015-08-27 07:41:13 -07001092 SkCoincidentSpans* prev = nullptr;
caryclark54359292015-03-26 07:52:43 -07001093 SkCoincidentSpans* next;
1094 do {
caryclark55888e42016-07-18 10:01:36 -07001095 next = coin->next();
caryclark54359292015-03-26 07:52:43 -07001096 if (coin == remove) {
1097 if (prev) {
caryclark55888e42016-07-18 10:01:36 -07001098 prev->setNext(next);
1099 } else if (head == fHead) {
caryclark54359292015-03-26 07:52:43 -07001100 fHead = next;
caryclark55888e42016-07-18 10:01:36 -07001101 } else {
1102 fTop = next;
caryclark54359292015-03-26 07:52:43 -07001103 }
1104 break;
1105 }
1106 prev = coin;
1107 } while ((coin = next));
caryclark55888e42016-07-18 10:01:36 -07001108 return coin != nullptr;
caryclark54359292015-03-26 07:52:43 -07001109}
1110
caryclark30b9fdd2016-08-31 14:36:29 -07001111void SkOpCoincidence::releaseDeleted(SkCoincidentSpans* coin) {
1112 if (!coin) {
1113 return;
1114 }
1115 SkCoincidentSpans* head = coin;
1116 SkCoincidentSpans* prev = nullptr;
1117 SkCoincidentSpans* next;
1118 do {
1119 next = coin->next();
1120 if (coin->coinPtTStart()->deleted()) {
1121 SkOPASSERT(coin->flipped() ? coin->oppPtTEnd()->deleted() :
1122 coin->oppPtTStart()->deleted());
1123 if (prev) {
1124 prev->setNext(next);
1125 } else if (head == fHead) {
1126 fHead = next;
1127 } else {
1128 fTop = next;
1129 }
1130 } else {
1131 SkOPASSERT(coin->flipped() ? !coin->oppPtTEnd()->deleted() :
1132 !coin->oppPtTStart()->deleted());
1133 prev = coin;
1134 }
1135 } while ((coin = next));
1136}
1137
1138void SkOpCoincidence::releaseDeleted() {
1139 this->releaseDeleted(fHead);
1140 this->releaseDeleted(fTop);
1141}
1142
caryclark55888e42016-07-18 10:01:36 -07001143void SkOpCoincidence::restoreHead() {
1144 SkCoincidentSpans** headPtr = &fHead;
1145 while (*headPtr) {
1146 headPtr = (*headPtr)->nextPtr();
1147 }
1148 *headPtr = fTop;
1149 fTop = nullptr;
1150 // segments may have collapsed in the meantime; remove empty referenced segments
1151 headPtr = &fHead;
1152 while (*headPtr) {
1153 SkCoincidentSpans* test = *headPtr;
1154 if (test->coinPtTStart()->segment()->done() || test->oppPtTStart()->segment()->done()) {
1155 *headPtr = test->next();
1156 continue;
1157 }
1158 headPtr = (*headPtr)->nextPtr();
1159 }
1160}
1161
1162// Please keep this in sync with debugExpand()
caryclark30b9fdd2016-08-31 14:36:29 -07001163// expand the range by checking adjacent spans for coincidence
Cary Clarkab87d7a2016-10-04 10:01:04 -04001164bool SkOpCoincidence::expand(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
1165 DEBUG_SET_PHASE();
caryclark54359292015-03-26 07:52:43 -07001166 SkCoincidentSpans* coin = fHead;
1167 if (!coin) {
caryclark27c8eb82015-07-06 11:38:33 -07001168 return false;
caryclark54359292015-03-26 07:52:43 -07001169 }
caryclark27c8eb82015-07-06 11:38:33 -07001170 bool expanded = false;
caryclark54359292015-03-26 07:52:43 -07001171 do {
caryclark55888e42016-07-18 10:01:36 -07001172 if (coin->expand()) {
1173 // check to see if multiple spans expanded so they are now identical
1174 SkCoincidentSpans* test = fHead;
1175 do {
1176 if (coin == test) {
1177 continue;
1178 }
1179 if (coin->coinPtTStart() == test->coinPtTStart()
1180 && coin->oppPtTStart() == test->oppPtTStart()) {
1181 this->release(fHead, test);
1182 break;
1183 }
1184 } while ((test = test->next()));
1185 expanded = true;
caryclark54359292015-03-26 07:52:43 -07001186 }
caryclark55888e42016-07-18 10:01:36 -07001187 } while ((coin = coin->next()));
caryclark27c8eb82015-07-06 11:38:33 -07001188 return expanded;
1189}
1190
Cary Clark40f23782016-10-06 12:04:16 -04001191bool SkOpCoincidence::findOverlaps(SkOpCoincidence* overlaps DEBUG_COIN_DECLARE_PARAMS()) const {
Cary Clarkab87d7a2016-10-04 10:01:04 -04001192 DEBUG_SET_PHASE();
halcanary96fcdcc2015-08-27 07:41:13 -07001193 overlaps->fHead = overlaps->fTop = nullptr;
caryclark27c8eb82015-07-06 11:38:33 -07001194 SkCoincidentSpans* outer = fHead;
1195 while (outer) {
caryclark55888e42016-07-18 10:01:36 -07001196 const SkOpSegment* outerCoin = outer->coinPtTStart()->segment();
1197 const SkOpSegment* outerOpp = outer->oppPtTStart()->segment();
caryclark27c8eb82015-07-06 11:38:33 -07001198 SkCoincidentSpans* inner = outer;
caryclark55888e42016-07-18 10:01:36 -07001199 while ((inner = inner->next())) {
1200 const SkOpSegment* innerCoin = inner->coinPtTStart()->segment();
caryclark27c8eb82015-07-06 11:38:33 -07001201 if (outerCoin == innerCoin) {
1202 continue; // both winners are the same segment, so there's no additional overlap
1203 }
caryclark55888e42016-07-18 10:01:36 -07001204 const SkOpSegment* innerOpp = inner->oppPtTStart()->segment();
1205 const SkOpPtT* overlapS;
1206 const SkOpPtT* overlapE;
1207 if ((outerOpp == innerCoin && SkOpPtT::Overlaps(outer->oppPtTStart(),
1208 outer->oppPtTEnd(),inner->coinPtTStart(), inner->coinPtTEnd(), &overlapS,
1209 &overlapE))
1210 || (outerCoin == innerOpp && SkOpPtT::Overlaps(outer->coinPtTStart(),
1211 outer->coinPtTEnd(), inner->oppPtTStart(), inner->oppPtTEnd(),
caryclark27c8eb82015-07-06 11:38:33 -07001212 &overlapS, &overlapE))
caryclark55888e42016-07-18 10:01:36 -07001213 || (outerOpp == innerOpp && SkOpPtT::Overlaps(outer->oppPtTStart(),
1214 outer->oppPtTEnd(), inner->oppPtTStart(), inner->oppPtTEnd(),
caryclark27c8eb82015-07-06 11:38:33 -07001215 &overlapS, &overlapE))) {
Cary Clark40f23782016-10-06 12:04:16 -04001216 if (!overlaps->addOverlap(outerCoin, outerOpp, innerCoin, innerOpp,
1217 overlapS, overlapE)) {
1218 return false;
1219 }
Cary Clarke47ae292016-10-05 08:51:39 -04001220 }
caryclark27c8eb82015-07-06 11:38:33 -07001221 }
caryclark55888e42016-07-18 10:01:36 -07001222 outer = outer->next();
caryclark27c8eb82015-07-06 11:38:33 -07001223 }
Cary Clark40f23782016-10-06 12:04:16 -04001224 return true;
caryclark27c8eb82015-07-06 11:38:33 -07001225}
1226
caryclark55888e42016-07-18 10:01:36 -07001227void SkOpCoincidence::fixUp(SkOpPtT* deleted, const SkOpPtT* kept) {
caryclarkb393a492016-09-07 08:21:09 -07001228 SkOPASSERT(deleted != kept);
caryclark55888e42016-07-18 10:01:36 -07001229 if (fHead) {
1230 this->fixUp(fHead, deleted, kept);
caryclark54359292015-03-26 07:52:43 -07001231 }
caryclark55888e42016-07-18 10:01:36 -07001232 if (fTop) {
1233 this->fixUp(fTop, deleted, kept);
1234 }
caryclark54359292015-03-26 07:52:43 -07001235}
1236
caryclark55888e42016-07-18 10:01:36 -07001237void SkOpCoincidence::fixUp(SkCoincidentSpans* coin, SkOpPtT* deleted, const SkOpPtT* kept) {
1238 SkCoincidentSpans* head = coin;
1239 do {
1240 if (coin->coinPtTStart() == deleted) {
1241 if (coin->coinPtTEnd()->span() == kept->span()) {
1242 this->release(head, coin);
1243 continue;
1244 }
1245 coin->setCoinPtTStart(kept);
1246 }
1247 if (coin->coinPtTEnd() == deleted) {
1248 if (coin->coinPtTStart()->span() == kept->span()) {
1249 this->release(head, coin);
1250 continue;
1251 }
1252 coin->setCoinPtTEnd(kept);
1253 }
1254 if (coin->oppPtTStart() == deleted) {
1255 if (coin->oppPtTEnd()->span() == kept->span()) {
1256 this->release(head, coin);
1257 continue;
1258 }
1259 coin->setOppPtTStart(kept);
1260 }
1261 if (coin->oppPtTEnd() == deleted) {
1262 if (coin->oppPtTStart()->span() == kept->span()) {
1263 this->release(head, coin);
1264 continue;
1265 }
1266 coin->setOppPtTEnd(kept);
1267 }
1268 } while ((coin = coin->next()));
1269}
1270
1271// Please keep this in sync with debugMark()
caryclark27c8eb82015-07-06 11:38:33 -07001272/* this sets up the coincidence links in the segments when the coincidence crosses multiple spans */
caryclarke6522ea2016-10-17 07:54:33 -07001273bool SkOpCoincidence::mark(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
Cary Clarkab87d7a2016-10-04 10:01:04 -04001274 DEBUG_SET_PHASE();
caryclark54359292015-03-26 07:52:43 -07001275 SkCoincidentSpans* coin = fHead;
1276 if (!coin) {
caryclarke6522ea2016-10-17 07:54:33 -07001277 return true;
caryclark54359292015-03-26 07:52:43 -07001278 }
1279 do {
caryclarke6522ea2016-10-17 07:54:33 -07001280 SkOpSpanBase* startBase = coin->coinPtTStartWritable()->span();
1281 FAIL_IF(!startBase->upCastable());
1282 SkOpSpan* start = startBase->upCast();
caryclarka35ab3e2016-10-20 08:32:18 -07001283 FAIL_IF(start->deleted());
caryclark55888e42016-07-18 10:01:36 -07001284 SkOpSpanBase* end = coin->coinPtTEndWritable()->span();
Cary Clark40f23782016-10-06 12:04:16 -04001285 SkOPASSERT(!end->deleted());
caryclark55888e42016-07-18 10:01:36 -07001286 SkOpSpanBase* oStart = coin->oppPtTStartWritable()->span();
Cary Clark40f23782016-10-06 12:04:16 -04001287 SkOPASSERT(!oStart->deleted());
caryclark55888e42016-07-18 10:01:36 -07001288 SkOpSpanBase* oEnd = coin->oppPtTEndWritable()->span();
1289 SkASSERT(!oEnd->deleted());
1290 bool flipped = coin->flipped();
caryclark54359292015-03-26 07:52:43 -07001291 if (flipped) {
1292 SkTSwap(oStart, oEnd);
1293 }
caryclark55888e42016-07-18 10:01:36 -07001294 /* coin and opp spans may not match up. Mark the ends, and then let the interior
1295 get marked as many times as the spans allow */
1296 start->insertCoincidence(oStart->upCast());
1297 end->insertCoinEnd(oEnd);
1298 const SkOpSegment* segment = start->segment();
1299 const SkOpSegment* oSegment = oStart->segment();
caryclark54359292015-03-26 07:52:43 -07001300 SkOpSpanBase* next = start;
1301 SkOpSpanBase* oNext = oStart;
caryclarka35ab3e2016-10-20 08:32:18 -07001302 bool ordered;
1303 FAIL_IF(!coin->ordered(&ordered));
caryclark55888e42016-07-18 10:01:36 -07001304 while ((next = next->upCast()->next()) != end) {
caryclarke6522ea2016-10-17 07:54:33 -07001305 FAIL_IF(!next->upCastable());
Cary Clarke47ae292016-10-05 08:51:39 -04001306 SkAssertResult(next->upCast()->insertCoincidence(oSegment, flipped, ordered));
caryclark55888e42016-07-18 10:01:36 -07001307 }
1308 while ((oNext = oNext->upCast()->next()) != oEnd) {
caryclarke6522ea2016-10-17 07:54:33 -07001309 FAIL_IF(!oNext->upCast()->insertCoincidence(segment, flipped, ordered));
caryclark55888e42016-07-18 10:01:36 -07001310 }
1311 } while ((coin = coin->next()));
caryclarke6522ea2016-10-17 07:54:33 -07001312 return true;
caryclark54359292015-03-26 07:52:43 -07001313}
1314
caryclark55888e42016-07-18 10:01:36 -07001315// Please keep in sync with debugMarkCollapsed()
1316void SkOpCoincidence::markCollapsed(SkCoincidentSpans* coin, SkOpPtT* test) {
1317 SkCoincidentSpans* head = coin;
1318 while (coin) {
1319 if (coin->collapsed(test)) {
1320 if (zero_or_one(coin->coinPtTStart()->fT) && zero_or_one(coin->coinPtTEnd()->fT)) {
1321 coin->coinPtTStartWritable()->segment()->markAllDone();
1322 }
1323 if (zero_or_one(coin->oppPtTStart()->fT) && zero_or_one(coin->oppPtTEnd()->fT)) {
1324 coin->oppPtTStartWritable()->segment()->markAllDone();
1325 }
1326 this->release(head, coin);
1327 }
1328 coin = coin->next();
1329 }
1330}
1331
1332// Please keep in sync with debugMarkCollapsed()
1333void SkOpCoincidence::markCollapsed(SkOpPtT* test) {
1334 markCollapsed(fHead, test);
1335 markCollapsed(fTop, test);
1336}
1337
1338bool SkOpCoincidence::Ordered(const SkOpSegment* coinSeg, const SkOpSegment* oppSeg) {
1339 if (coinSeg->verb() < oppSeg->verb()) {
1340 return true;
1341 }
1342 if (coinSeg->verb() > oppSeg->verb()) {
1343 return false;
1344 }
1345 int count = (SkPathOpsVerbToPoints(coinSeg->verb()) + 1) * 2;
1346 const SkScalar* cPt = &coinSeg->pts()[0].fX;
1347 const SkScalar* oPt = &oppSeg->pts()[0].fX;
1348 for (int index = 0; index < count; ++index) {
1349 if (*cPt < *oPt) {
1350 return true;
1351 }
1352 if (*cPt > *oPt) {
1353 return false;
1354 }
1355 ++cPt;
1356 ++oPt;
1357 }
1358 return true;
1359}
1360
1361bool SkOpCoincidence::overlap(const SkOpPtT* coin1s, const SkOpPtT* coin1e,
caryclark54359292015-03-26 07:52:43 -07001362 const SkOpPtT* coin2s, const SkOpPtT* coin2e, double* overS, double* overE) const {
caryclark27c8eb82015-07-06 11:38:33 -07001363 SkASSERT(coin1s->segment() == coin2s->segment());
caryclark54359292015-03-26 07:52:43 -07001364 *overS = SkTMax(SkTMin(coin1s->fT, coin1e->fT), SkTMin(coin2s->fT, coin2e->fT));
1365 *overE = SkTMin(SkTMax(coin1s->fT, coin1e->fT), SkTMax(coin2s->fT, coin2e->fT));
1366 return *overS < *overE;
1367}
caryclark27c8eb82015-07-06 11:38:33 -07001368
caryclark55888e42016-07-18 10:01:36 -07001369// Commented-out lines keep this in sync with debugRelease()
1370void SkOpCoincidence::release(const SkOpSegment* deleted) {
1371 SkCoincidentSpans* coin = fHead;
1372 if (!coin) {
1373 return;
1374 }
1375 do {
1376 if (coin->coinPtTStart()->segment() == deleted
1377 || coin->coinPtTEnd()->segment() == deleted
1378 || coin->oppPtTStart()->segment() == deleted
1379 || coin->oppPtTEnd()->segment() == deleted) {
1380 this->release(fHead, coin);
1381 }
1382 } while ((coin = coin->next()));
1383}