blob: aa5f5bfba7240062640d65f3366db549b5417174 [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.
131bool SkCoincidentSpans::ordered() const {
132 const SkOpSpanBase* start = this->coinPtTStart()->span();
133 const SkOpSpanBase* end = this->coinPtTEnd()->span();
134 const SkOpSpanBase* next = start->upCast()->next();
135 if (next == end) {
136 return true;
137 }
138 bool flipped = this->flipped();
139 const SkOpSegment* oppSeg = this->oppPtTStart()->segment();
140 double oppLastT = fOppPtTStart->fT;
141 do {
142 const SkOpPtT* opp = next->contains(oppSeg);
143 if (!opp) {
144 SkASSERT(0); // may assert if coincident span isn't fully processed
145 continue;
146 }
147 if ((oppLastT > opp->fT) != flipped) {
148 return false;
149 }
150 oppLastT = opp->fT;
151 if (next == end) {
152 break;
153 }
caryclarkbbfe92b2016-09-19 06:00:35 -0700154 if (!next->upCastable()) {
155 return false;
156 }
caryclark81a478c2016-09-09 09:37:57 -0700157 next = next->upCast()->next();
158 } while (true);
159 return true;
160}
161
caryclark55888e42016-07-18 10:01:36 -0700162// if there is an existing pair that overlaps the addition, extend it
163bool SkOpCoincidence::extend(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd,
164 const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) {
165 SkCoincidentSpans* test = fHead;
166 if (!test) {
167 return false;
168 }
169 const SkOpSegment* coinSeg = coinPtTStart->segment();
170 const SkOpSegment* oppSeg = oppPtTStart->segment();
171 if (!Ordered(coinPtTStart, oppPtTStart)) {
172 SkTSwap(coinSeg, oppSeg);
173 SkTSwap(coinPtTStart, oppPtTStart);
174 SkTSwap(coinPtTEnd, oppPtTEnd);
175 if (coinPtTStart->fT > coinPtTEnd->fT) {
176 SkTSwap(coinPtTStart, coinPtTEnd);
177 SkTSwap(oppPtTStart, oppPtTEnd);
178 }
179 }
180 double oppMinT = SkTMin(oppPtTStart->fT, oppPtTEnd->fT);
181 SkDEBUGCODE(double oppMaxT = SkTMax(oppPtTStart->fT, oppPtTEnd->fT));
182 do {
183 if (coinSeg != test->coinPtTStart()->segment()) {
184 continue;
185 }
186 if (oppSeg != test->oppPtTStart()->segment()) {
187 continue;
188 }
189 double oTestMinT = SkTMin(test->oppPtTStart()->fT, test->oppPtTEnd()->fT);
190 double oTestMaxT = SkTMax(test->oppPtTStart()->fT, test->oppPtTEnd()->fT);
191 // if debug check triggers, caller failed to check if extended already exists
192 SkASSERT(test->coinPtTStart()->fT > coinPtTStart->fT
193 || coinPtTEnd->fT > test->coinPtTEnd()->fT
194 || oTestMinT > oppMinT || oppMaxT > oTestMaxT);
195 if ((test->coinPtTStart()->fT <= coinPtTEnd->fT
196 && coinPtTStart->fT <= test->coinPtTEnd()->fT)
197 || (oTestMinT <= oTestMaxT && oppMinT <= oTestMaxT)) {
198 test->extend(coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd);
199 return true;
200 }
201 } while ((test = test->next()));
202 return false;
caryclark54359292015-03-26 07:52:43 -0700203}
204
caryclark55888e42016-07-18 10:01:36 -0700205// verifies that the coincidence hasn't already been added
206static void DebugCheckAdd(const SkCoincidentSpans* check, const SkOpPtT* coinPtTStart,
207 const SkOpPtT* coinPtTEnd, const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) {
208#if DEBUG_COINCIDENCE
209 while (check) {
210 SkASSERT(check->coinPtTStart() != coinPtTStart || check->coinPtTEnd() != coinPtTEnd
211 || check->oppPtTStart() != oppPtTStart || check->oppPtTEnd() != oppPtTEnd);
212 SkASSERT(check->coinPtTStart() != oppPtTStart || check->coinPtTEnd() != oppPtTEnd
213 || check->oppPtTStart() != coinPtTStart || check->oppPtTEnd() != coinPtTEnd);
214 check = check->next();
215 }
216#endif
217}
218
219// adds a new coincident pair
220void SkOpCoincidence::add(SkOpPtT* coinPtTStart, SkOpPtT* coinPtTEnd, SkOpPtT* oppPtTStart,
221 SkOpPtT* oppPtTEnd) {
222 // OPTIMIZE: caller should have already sorted
223 if (!Ordered(coinPtTStart, oppPtTStart)) {
224 if (oppPtTStart->fT < oppPtTEnd->fT) {
225 this->add(oppPtTStart, oppPtTEnd, coinPtTStart, coinPtTEnd);
226 } else {
227 this->add(oppPtTEnd, oppPtTStart, coinPtTEnd, coinPtTStart);
228 }
229 return;
230 }
231 SkASSERT(Ordered(coinPtTStart, oppPtTStart));
232 // choose the ptT at the front of the list to track
233 coinPtTStart = coinPtTStart->span()->ptT();
234 coinPtTEnd = coinPtTEnd->span()->ptT();
235 oppPtTStart = oppPtTStart->span()->ptT();
236 oppPtTEnd = oppPtTEnd->span()->ptT();
237 SkASSERT(coinPtTStart->fT < coinPtTEnd->fT);
238 SkASSERT(oppPtTStart->fT != oppPtTEnd->fT);
caryclark30b9fdd2016-08-31 14:36:29 -0700239 SkOPASSERT(!coinPtTStart->deleted());
240 SkOPASSERT(!coinPtTEnd->deleted());
241 SkOPASSERT(!oppPtTStart->deleted());
242 SkOPASSERT(!oppPtTEnd->deleted());
caryclark55888e42016-07-18 10:01:36 -0700243 DebugCheckAdd(fHead, coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd);
244 DebugCheckAdd(fTop, coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd);
245 SkCoincidentSpans* coinRec = SkOpTAllocator<SkCoincidentSpans>::Allocate(
246 this->globalState()->allocator());
caryclarkfc560e02016-07-27 08:46:10 -0700247 coinRec->init(SkDEBUGCODE(fGlobalState));
Cary Clarkab87d7a2016-10-04 10:01:04 -0400248 coinRec->set(this->fHead, coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd);
caryclark55888e42016-07-18 10:01:36 -0700249 fHead = coinRec;
250}
251
252// description below
caryclark15976282016-07-21 05:48:43 -0700253bool SkOpCoincidence::addEndMovedSpans(const SkOpSpan* base, const SkOpSpanBase* testSpan) {
caryclark55888e42016-07-18 10:01:36 -0700254 const SkOpPtT* testPtT = testSpan->ptT();
255 const SkOpPtT* stopPtT = testPtT;
256 const SkOpSegment* baseSeg = base->segment();
257 while ((testPtT = testPtT->next()) != stopPtT) {
258 const SkOpSegment* testSeg = testPtT->segment();
259 if (testPtT->deleted()) {
260 continue;
261 }
262 if (testSeg == baseSeg) {
263 continue;
264 }
caryclarkc6d855f2016-08-11 11:59:48 -0700265 if (testPtT->span()->ptT() != testPtT) {
266 continue;
267 }
caryclark55888e42016-07-18 10:01:36 -0700268 if (this->contains(baseSeg, testSeg, testPtT->fT)) {
269 continue;
270 }
271 // intersect perp with base->ptT() with testPtT->segment()
272 SkDVector dxdy = baseSeg->dSlopeAtT(base->t());
273 const SkPoint& pt = base->pt();
274 SkDLine ray = {{{pt.fX, pt.fY}, {pt.fX + dxdy.fY, pt.fY - dxdy.fX}}};
275 SkIntersections i;
276 (*CurveIntersectRay[testSeg->verb()])(testSeg->pts(), testSeg->weight(), ray, &i);
277 for (int index = 0; index < i.used(); ++index) {
278 double t = i[0][index];
279 if (!between(0, t, 1)) {
280 continue;
281 }
282 SkDPoint oppPt = i.pt(index);
283 if (!oppPt.approximatelyEqual(pt)) {
284 continue;
285 }
286 SkOpSegment* writableSeg = const_cast<SkOpSegment*>(testSeg);
caryclark29b25632016-08-25 11:27:17 -0700287 SkOpPtT* oppStart = writableSeg->addT(t);
caryclark27c015d2016-09-23 05:47:20 -0700288 if (oppStart == testPtT) {
289 continue;
290 }
caryclark55888e42016-07-18 10:01:36 -0700291 SkOpSpan* writableBase = const_cast<SkOpSpan*>(base);
caryclark30b9fdd2016-08-31 14:36:29 -0700292 oppStart->span()->addOpp(writableBase);
caryclark55888e42016-07-18 10:01:36 -0700293 if (oppStart->deleted()) {
294 continue;
295 }
296 SkOpSegment* coinSeg = base->segment();
297 SkOpSegment* oppSeg = oppStart->segment();
298 double coinTs, coinTe, oppTs, oppTe;
caryclark8016b262016-09-06 05:59:47 -0700299 if (Ordered(coinSeg, oppSeg)) {
caryclark55888e42016-07-18 10:01:36 -0700300 coinTs = base->t();
301 coinTe = testSpan->t();
302 oppTs = oppStart->fT;
303 oppTe = testPtT->fT;
304 } else {
305 SkTSwap(coinSeg, oppSeg);
306 coinTs = oppStart->fT;
307 coinTe = testPtT->fT;
308 oppTs = base->t();
309 oppTe = testSpan->t();
310 }
311 if (coinTs > coinTe) {
312 SkTSwap(coinTs, coinTe);
313 SkTSwap(oppTs, oppTe);
314 }
caryclark81a478c2016-09-09 09:37:57 -0700315 bool added;
316 if (!this->addOrOverlap(coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, &added)) {
caryclark15976282016-07-21 05:48:43 -0700317 return false;
318 }
caryclark55888e42016-07-18 10:01:36 -0700319 }
320 }
caryclark15976282016-07-21 05:48:43 -0700321 return true;
caryclark55888e42016-07-18 10:01:36 -0700322}
323
324// description below
325bool SkOpCoincidence::addEndMovedSpans(const SkOpPtT* ptT) {
caryclark025b11e2016-08-25 05:21:14 -0700326 FAIL_IF(!ptT->span()->upCastable());
caryclark55888e42016-07-18 10:01:36 -0700327 const SkOpSpan* base = ptT->span()->upCast();
328 const SkOpSpan* prev = base->prev();
caryclark025b11e2016-08-25 05:21:14 -0700329 FAIL_IF(!prev);
caryclark55888e42016-07-18 10:01:36 -0700330 if (!prev->isCanceled()) {
caryclark15976282016-07-21 05:48:43 -0700331 if (!this->addEndMovedSpans(base, base->prev())) {
332 return false;
333 }
caryclark55888e42016-07-18 10:01:36 -0700334 }
335 if (!base->isCanceled()) {
caryclark15976282016-07-21 05:48:43 -0700336 if (!this->addEndMovedSpans(base, base->next())) {
337 return false;
338 }
caryclark55888e42016-07-18 10:01:36 -0700339 }
340 return true;
341}
342
343/* If A is coincident with B and B includes an endpoint, and A's matching point
344 is not the endpoint (i.e., there's an implied line connecting B-end and A)
345 then assume that the same implied line may intersect another curve close to B.
346 Since we only care about coincidence that was undetected, look at the
347 ptT list on B-segment adjacent to the B-end/A ptT loop (not in the loop, but
348 next door) and see if the A matching point is close enough to form another
349 coincident pair. If so, check for a new coincident span between B-end/A ptT loop
350 and the adjacent ptT loop.
351*/
Cary Clarkab87d7a2016-10-04 10:01:04 -0400352bool SkOpCoincidence::addEndMovedSpans(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
353 DEBUG_SET_PHASE();
caryclark55888e42016-07-18 10:01:36 -0700354 SkCoincidentSpans* span = fHead;
355 if (!span) {
356 return true;
357 }
358 fTop = span;
359 fHead = nullptr;
360 do {
361 if (span->coinPtTStart()->fPt != span->oppPtTStart()->fPt) {
caryclark025b11e2016-08-25 05:21:14 -0700362 FAIL_IF(1 == span->coinPtTStart()->fT);
caryclark55888e42016-07-18 10:01:36 -0700363 bool onEnd = span->coinPtTStart()->fT == 0;
364 bool oOnEnd = zero_or_one(span->oppPtTStart()->fT);
365 if (onEnd) {
366 if (!oOnEnd) { // if both are on end, any nearby intersect was already found
367 if (!this->addEndMovedSpans(span->oppPtTStart())) {
368 return false;
369 }
370 }
371 } else if (oOnEnd) {
372 if (!this->addEndMovedSpans(span->coinPtTStart())) {
373 return false;
374 }
375 }
376 }
377 if (span->coinPtTEnd()->fPt != span->oppPtTEnd()->fPt) {
378 bool onEnd = span->coinPtTEnd()->fT == 1;
379 bool oOnEnd = zero_or_one(span->oppPtTEnd()->fT);
380 if (onEnd) {
381 if (!oOnEnd) {
382 if (!this->addEndMovedSpans(span->oppPtTEnd())) {
383 return false;
384 }
385 }
386 } else if (oOnEnd) {
387 if (!this->addEndMovedSpans(span->coinPtTEnd())) {
388 return false;
389 }
390 }
391 }
392 } while ((span = span->next()));
393 this->restoreHead();
394 return true;
395}
396
397/* Please keep this in sync with debugAddExpanded */
398// for each coincident pair, match the spans
399// 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 -0400400bool SkOpCoincidence::addExpanded(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
401 DEBUG_SET_PHASE();
caryclark55888e42016-07-18 10:01:36 -0700402 SkCoincidentSpans* coin = this->fHead;
403 if (!coin) {
404 return true;
405 }
406 do {
407 const SkOpPtT* startPtT = coin->coinPtTStart();
408 const SkOpPtT* oStartPtT = coin->oppPtTStart();
caryclark8016b262016-09-06 05:59:47 -0700409 double priorT = startPtT->fT;
410 double oPriorT = oStartPtT->fT;
caryclarkbbfe92b2016-09-19 06:00:35 -0700411 FAIL_IF(!startPtT->contains(oStartPtT));
caryclarkc6d855f2016-08-11 11:59:48 -0700412 SkOPASSERT(coin->coinPtTEnd()->contains(coin->oppPtTEnd()));
caryclark55888e42016-07-18 10:01:36 -0700413 const SkOpSpanBase* start = startPtT->span();
414 const SkOpSpanBase* oStart = oStartPtT->span();
415 const SkOpSpanBase* end = coin->coinPtTEnd()->span();
416 const SkOpSpanBase* oEnd = coin->oppPtTEnd()->span();
417 FAIL_IF(oEnd->deleted());
caryclarke25a4f62016-07-26 09:26:29 -0700418 FAIL_IF(!start->upCastable());
caryclark55888e42016-07-18 10:01:36 -0700419 const SkOpSpanBase* test = start->upCast()->next();
caryclarke7bb5b22016-09-22 05:20:07 -0700420 FAIL_IF(!coin->flipped() && !oStart->upCastable());
caryclark55888e42016-07-18 10:01:36 -0700421 const SkOpSpanBase* oTest = coin->flipped() ? oStart->prev() : oStart->upCast()->next();
caryclark30b9fdd2016-08-31 14:36:29 -0700422 FAIL_IF(!oTest);
caryclark8016b262016-09-06 05:59:47 -0700423 SkOpSegment* seg = start->segment();
424 SkOpSegment* oSeg = oStart->segment();
caryclark55888e42016-07-18 10:01:36 -0700425 while (test != end || oTest != oEnd) {
caryclark8016b262016-09-06 05:59:47 -0700426 const SkOpPtT* containedOpp = test->ptT()->contains(oSeg);
427 const SkOpPtT* containedThis = oTest->ptT()->contains(seg);
428 if (!containedOpp || !containedThis) {
429 // choose the ends, or the first common pt-t list shared by both
430 double nextT, oNextT;
431 if (containedOpp) {
432 nextT = test->t();
433 oNextT = containedOpp->fT;
434 } else if (containedThis) {
435 nextT = containedThis->fT;
436 oNextT = oTest->t();
437 } else {
438 // iterate through until a pt-t list found that contains the other
439 const SkOpSpanBase* walk = test;
440 const SkOpPtT* walkOpp;
441 do {
442 FAIL_IF(!walk->upCastable());
443 walk = walk->upCast()->next();
444 } while (!(walkOpp = walk->ptT()->contains(oSeg))
445 && walk != coin->coinPtTEnd()->span());
Cary Clark3fdf52c2016-10-04 10:53:31 -0400446 FAIL_IF(!walkOpp);
caryclark8016b262016-09-06 05:59:47 -0700447 nextT = walk->t();
448 oNextT = walkOpp->fT;
449 }
caryclark55888e42016-07-18 10:01:36 -0700450 // use t ranges to guess which one is missing
caryclark8016b262016-09-06 05:59:47 -0700451 double startRange = nextT - priorT;
caryclark55888e42016-07-18 10:01:36 -0700452 FAIL_IF(!startRange);
caryclark8016b262016-09-06 05:59:47 -0700453 double startPart = (test->t() - priorT) / startRange;
454 double oStartRange = oNextT - oPriorT;
caryclark55888e42016-07-18 10:01:36 -0700455 FAIL_IF(!oStartRange);
caryclark8016b262016-09-06 05:59:47 -0700456 double oStartPart = (oTest->t() - oPriorT) / oStartRange;
caryclark55888e42016-07-18 10:01:36 -0700457 FAIL_IF(startPart == oStartPart);
caryclark8016b262016-09-06 05:59:47 -0700458 bool addToOpp = !containedOpp && !containedThis ? startPart < oStartPart
459 : !!containedThis;
caryclark55888e42016-07-18 10:01:36 -0700460 bool startOver = false;
caryclark8016b262016-09-06 05:59:47 -0700461 bool success = addToOpp ? oSeg->addExpanded(
462 oPriorT + oStartRange * startPart, test, &startOver)
463 : seg->addExpanded(
464 priorT + startRange * oStartPart, oTest, &startOver);
caryclark30b9fdd2016-08-31 14:36:29 -0700465 FAIL_IF(!success);
caryclark55888e42016-07-18 10:01:36 -0700466 if (startOver) {
467 test = start;
468 oTest = oStart;
469 }
caryclark30b9fdd2016-08-31 14:36:29 -0700470 end = coin->coinPtTEnd()->span();
471 oEnd = coin->oppPtTEnd()->span();
caryclark55888e42016-07-18 10:01:36 -0700472 }
473 if (test != end) {
caryclark30b9fdd2016-08-31 14:36:29 -0700474 FAIL_IF(!test->upCastable());
caryclark8016b262016-09-06 05:59:47 -0700475 priorT = test->t();
caryclark55888e42016-07-18 10:01:36 -0700476 test = test->upCast()->next();
477 }
478 if (oTest != oEnd) {
caryclark8016b262016-09-06 05:59:47 -0700479 oPriorT = oTest->t();
caryclark55888e42016-07-18 10:01:36 -0700480 oTest = coin->flipped() ? oTest->prev() : oTest->upCast()->next();
caryclark30b9fdd2016-08-31 14:36:29 -0700481 FAIL_IF(!oTest);
caryclark55888e42016-07-18 10:01:36 -0700482 }
caryclark8016b262016-09-06 05:59:47 -0700483
caryclark55888e42016-07-18 10:01:36 -0700484 }
485 } while ((coin = coin->next()));
486 return true;
487}
488
caryclark55888e42016-07-18 10:01:36 -0700489// given a t span, map the same range on the coincident span
caryclark8016b262016-09-06 05:59:47 -0700490/*
491the curves may not scale linearly, so interpolation may only happen within known points
492remap over1s, over1e, cointPtTStart, coinPtTEnd to smallest range that captures over1s
493then repeat to capture over1e
494*/
495double SkOpCoincidence::TRange(const SkOpPtT* overS, double t,
496 const SkOpSegment* coinSeg SkDEBUGPARAMS(const SkOpPtT* overE)) {
497 const SkOpSpanBase* work = overS->span();
498 const SkOpPtT* foundStart = nullptr;
499 const SkOpPtT* foundEnd = nullptr;
500 const SkOpPtT* coinStart = nullptr;
501 const SkOpPtT* coinEnd = nullptr;
502 do {
503 const SkOpPtT* contained = work->contains(coinSeg);
504 if (!contained) {
caryclarkc9b90d12016-09-09 07:41:36 -0700505 if (work->final()) {
506 break;
caryclarkb393a492016-09-07 08:21:09 -0700507 }
caryclark8016b262016-09-06 05:59:47 -0700508 continue;
509 }
510 if (work->t() <= t) {
511 coinStart = contained;
512 foundStart = work->ptT();
513 }
514 if (work->t() >= t) {
515 coinEnd = contained;
516 foundEnd = work->ptT();
517 break;
518 }
519 SkASSERT(work->ptT() != overE);
520 } while ((work = work->upCast()->next()));
caryclarkc9b90d12016-09-09 07:41:36 -0700521 if (!coinStart || !coinEnd) {
522 return 1;
523 }
caryclark8016b262016-09-06 05:59:47 -0700524 // while overS->fT <=t and overS contains coinSeg
525 double denom = foundEnd->fT - foundStart->fT;
526 double sRatio = denom ? (t - foundStart->fT) / denom : 1;
527 return coinStart->fT + (coinEnd->fT - coinStart->fT) * sRatio;
caryclark54359292015-03-26 07:52:43 -0700528}
529
caryclark55888e42016-07-18 10:01:36 -0700530// return true if span overlaps existing and needs to adjust the coincident list
531bool SkOpCoincidence::checkOverlap(SkCoincidentSpans* check,
532 const SkOpSegment* coinSeg, const SkOpSegment* oppSeg,
533 double coinTs, double coinTe, double oppTs, double oppTe,
534 SkTDArray<SkCoincidentSpans*>* overlaps) const {
535 if (!Ordered(coinSeg, oppSeg)) {
536 if (oppTs < oppTe) {
537 return this->checkOverlap(check, oppSeg, coinSeg, oppTs, oppTe, coinTs, coinTe,
538 overlaps);
539 }
540 return this->checkOverlap(check, oppSeg, coinSeg, oppTe, oppTs, coinTe, coinTs, overlaps);
541 }
542 bool swapOpp = oppTs > oppTe;
543 if (swapOpp) {
544 SkTSwap(oppTs, oppTe);
545 }
caryclark27c8eb82015-07-06 11:38:33 -0700546 do {
caryclark55888e42016-07-18 10:01:36 -0700547 if (check->coinPtTStart()->segment() != coinSeg) {
548 continue;
caryclark1c9ce612015-11-20 14:06:28 -0800549 }
caryclark55888e42016-07-18 10:01:36 -0700550 if (check->oppPtTStart()->segment() != oppSeg) {
551 continue;
caryclarkdae6b972016-06-08 04:28:19 -0700552 }
caryclark55888e42016-07-18 10:01:36 -0700553 double checkTs = check->coinPtTStart()->fT;
554 double checkTe = check->coinPtTEnd()->fT;
555 bool coinOutside = coinTe < checkTs || coinTs > checkTe;
556 double oCheckTs = check->oppPtTStart()->fT;
557 double oCheckTe = check->oppPtTEnd()->fT;
558 if (swapOpp) {
559 if (oCheckTs <= oCheckTe) {
caryclark81a478c2016-09-09 09:37:57 -0700560 return false;
caryclark27c8eb82015-07-06 11:38:33 -0700561 }
caryclark55888e42016-07-18 10:01:36 -0700562 SkTSwap(oCheckTs, oCheckTe);
caryclark27c8eb82015-07-06 11:38:33 -0700563 }
caryclark55888e42016-07-18 10:01:36 -0700564 bool oppOutside = oppTe < oCheckTs || oppTs > oCheckTe;
565 if (coinOutside && oppOutside) {
566 continue;
567 }
568 bool coinInside = coinTe <= checkTe && coinTs >= checkTs;
569 bool oppInside = oppTe <= oCheckTe && oppTs >= oCheckTs;
caryclark81a478c2016-09-09 09:37:57 -0700570 if (coinInside && oppInside) { // already included, do nothing
571 return false;
caryclark55888e42016-07-18 10:01:36 -0700572 }
573 *overlaps->append() = check; // partial overlap, extend existing entry
574 } while ((check = check->next()));
caryclark26ad22a2015-10-16 09:03:38 -0700575 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700576}
577
caryclark55888e42016-07-18 10:01:36 -0700578/* Please keep this in sync with debugAddIfMissing() */
caryclark8016b262016-09-06 05:59:47 -0700579// note that over1s, over1e, over2s, over2e are ordered
580bool SkOpCoincidence::addIfMissing(const SkOpPtT* over1s, const SkOpPtT* over2s,
caryclark81a478c2016-09-09 09:37:57 -0700581 double tStart, double tEnd, SkOpSegment* coinSeg, SkOpSegment* oppSeg, bool* added
caryclark8016b262016-09-06 05:59:47 -0700582 SkDEBUGPARAMS(const SkOpPtT* over1e) SkDEBUGPARAMS(const SkOpPtT* over2e)) {
583 SkASSERT(tStart < tEnd);
584 SkASSERT(over1s->fT < over1e->fT);
585 SkASSERT(between(over1s->fT, tStart, over1e->fT));
586 SkASSERT(between(over1s->fT, tEnd, over1e->fT));
587 SkASSERT(over2s->fT < over2e->fT);
588 SkASSERT(between(over2s->fT, tStart, over2e->fT));
589 SkASSERT(between(over2s->fT, tEnd, over2e->fT));
590 SkASSERT(over1s->segment() == over1e->segment());
591 SkASSERT(over2s->segment() == over2e->segment());
592 SkASSERT(over1s->segment() == over2s->segment());
593 SkASSERT(over1s->segment() != coinSeg);
594 SkASSERT(over1s->segment() != oppSeg);
595 SkASSERT(coinSeg != oppSeg);
caryclark54359292015-03-26 07:52:43 -0700596 double coinTs, coinTe, oppTs, oppTe;
caryclark8016b262016-09-06 05:59:47 -0700597 coinTs = TRange(over1s, tStart, coinSeg SkDEBUGPARAMS(over1e));
598 coinTe = TRange(over1s, tEnd, coinSeg SkDEBUGPARAMS(over1e));
caryclark30b9fdd2016-08-31 14:36:29 -0700599 if (coinSeg->collapsed(coinTs, coinTe)) {
caryclark81a478c2016-09-09 09:37:57 -0700600 return true;
caryclark30b9fdd2016-08-31 14:36:29 -0700601 }
caryclark8016b262016-09-06 05:59:47 -0700602 oppTs = TRange(over2s, tStart, oppSeg SkDEBUGPARAMS(over2e));
603 oppTe = TRange(over2s, tEnd, oppSeg SkDEBUGPARAMS(over2e));
caryclark30b9fdd2016-08-31 14:36:29 -0700604 if (oppSeg->collapsed(oppTs, oppTe)) {
caryclark81a478c2016-09-09 09:37:57 -0700605 return true;
caryclark30b9fdd2016-08-31 14:36:29 -0700606 }
caryclark8016b262016-09-06 05:59:47 -0700607 if (coinTs > coinTe) {
caryclark55888e42016-07-18 10:01:36 -0700608 SkTSwap(coinTs, coinTe);
caryclark54359292015-03-26 07:52:43 -0700609 SkTSwap(oppTs, oppTe);
610 }
caryclark81a478c2016-09-09 09:37:57 -0700611 return this->addOrOverlap(coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, added);
caryclark54359292015-03-26 07:52:43 -0700612}
613
caryclark55888e42016-07-18 10:01:36 -0700614/* Please keep this in sync with debugAddOrOverlap() */
caryclark025b11e2016-08-25 05:21:14 -0700615// If this is called by addEndMovedSpans(), a returned false propogates out to an abort.
616// If this is called by AddIfMissing(), a returned false indicates there was nothing to add
caryclark55888e42016-07-18 10:01:36 -0700617bool SkOpCoincidence::addOrOverlap(SkOpSegment* coinSeg, SkOpSegment* oppSeg,
caryclark81a478c2016-09-09 09:37:57 -0700618 double coinTs, double coinTe, double oppTs, double oppTe, bool* added) {
caryclark55888e42016-07-18 10:01:36 -0700619 SkTDArray<SkCoincidentSpans*> overlaps;
caryclark81a478c2016-09-09 09:37:57 -0700620 FAIL_IF(!fTop);
caryclark55888e42016-07-18 10:01:36 -0700621 if (!this->checkOverlap(fTop, coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, &overlaps)) {
caryclark81a478c2016-09-09 09:37:57 -0700622 return true;
caryclark55888e42016-07-18 10:01:36 -0700623 }
624 if (fHead && !this->checkOverlap(fHead, coinSeg, oppSeg, coinTs,
625 coinTe, oppTs, oppTe, &overlaps)) {
caryclark81a478c2016-09-09 09:37:57 -0700626 return true;
caryclark55888e42016-07-18 10:01:36 -0700627 }
628 SkCoincidentSpans* overlap = overlaps.count() ? overlaps[0] : nullptr;
629 for (int index = 1; index < overlaps.count(); ++index) { // combine overlaps before continuing
630 SkCoincidentSpans* test = overlaps[index];
631 if (overlap->coinPtTStart()->fT > test->coinPtTStart()->fT) {
632 overlap->setCoinPtTStart(test->coinPtTStart());
633 }
634 if (overlap->coinPtTEnd()->fT < test->coinPtTEnd()->fT) {
635 overlap->setCoinPtTEnd(test->coinPtTEnd());
636 }
637 if (overlap->flipped()
638 ? overlap->oppPtTStart()->fT < test->oppPtTStart()->fT
639 : overlap->oppPtTStart()->fT > test->oppPtTStart()->fT) {
640 overlap->setOppPtTStart(test->oppPtTStart());
641 }
642 if (overlap->flipped()
643 ? overlap->oppPtTEnd()->fT > test->oppPtTEnd()->fT
644 : overlap->oppPtTEnd()->fT < test->oppPtTEnd()->fT) {
645 overlap->setOppPtTEnd(test->oppPtTEnd());
646 }
647 if (!fHead || !this->release(fHead, test)) {
648 SkAssertResult(this->release(fTop, test));
649 }
650 }
651 const SkOpPtT* cs = coinSeg->existing(coinTs, oppSeg);
652 const SkOpPtT* ce = coinSeg->existing(coinTe, oppSeg);
caryclark81a478c2016-09-09 09:37:57 -0700653 if (overlap && cs && ce && overlap->contains(cs, ce)) {
654 return true;
655 }
656 FAIL_IF(cs == ce && cs);
caryclark55888e42016-07-18 10:01:36 -0700657 const SkOpPtT* os = oppSeg->existing(oppTs, coinSeg);
658 const SkOpPtT* oe = oppSeg->existing(oppTe, coinSeg);
caryclark81a478c2016-09-09 09:37:57 -0700659 if (overlap && os && oe && overlap->contains(os, oe)) {
660 return true;
661 }
caryclark55888e42016-07-18 10:01:36 -0700662 SkASSERT(!cs || !cs->deleted());
663 SkASSERT(!os || !os->deleted());
664 SkASSERT(!ce || !ce->deleted());
665 SkASSERT(!oe || !oe->deleted());
666 const SkOpPtT* csExisting = !cs ? coinSeg->existing(coinTs, nullptr) : nullptr;
667 const SkOpPtT* ceExisting = !ce ? coinSeg->existing(coinTe, nullptr) : nullptr;
caryclark81a478c2016-09-09 09:37:57 -0700668 FAIL_IF(csExisting && csExisting == ceExisting);
caryclarke839e782016-09-15 07:48:18 -0700669// FAIL_IF(csExisting && (csExisting == ce ||
670// csExisting->contains(ceExisting ? ceExisting : ce)));
caryclark81a478c2016-09-09 09:37:57 -0700671 FAIL_IF(ceExisting && (ceExisting == cs ||
caryclark025b11e2016-08-25 05:21:14 -0700672 ceExisting->contains(csExisting ? csExisting : cs)));
caryclark55888e42016-07-18 10:01:36 -0700673 const SkOpPtT* osExisting = !os ? oppSeg->existing(oppTs, nullptr) : nullptr;
674 const SkOpPtT* oeExisting = !oe ? oppSeg->existing(oppTe, nullptr) : nullptr;
caryclark81a478c2016-09-09 09:37:57 -0700675 FAIL_IF(osExisting && osExisting == oeExisting);
676 FAIL_IF(osExisting && (osExisting == oe ||
caryclark025b11e2016-08-25 05:21:14 -0700677 osExisting->contains(oeExisting ? oeExisting : oe)));
caryclark81a478c2016-09-09 09:37:57 -0700678 FAIL_IF(oeExisting && (oeExisting == os ||
caryclark025b11e2016-08-25 05:21:14 -0700679 oeExisting->contains(osExisting ? osExisting : os)));
caryclark55888e42016-07-18 10:01:36 -0700680 // extra line in debug code
681 this->debugValidate();
682 if (!cs || !os) {
683 SkOpPtT* csWritable = cs ? const_cast<SkOpPtT*>(cs)
caryclark29b25632016-08-25 11:27:17 -0700684 : coinSeg->addT(coinTs);
caryclarke839e782016-09-15 07:48:18 -0700685 if (csWritable == ce) {
686 return true;
687 }
caryclark55888e42016-07-18 10:01:36 -0700688 SkOpPtT* osWritable = os ? const_cast<SkOpPtT*>(os)
caryclark29b25632016-08-25 11:27:17 -0700689 : oppSeg->addT(oppTs);
caryclark81a478c2016-09-09 09:37:57 -0700690 FAIL_IF(!csWritable || !osWritable);
caryclark30b9fdd2016-08-31 14:36:29 -0700691 csWritable->span()->addOpp(osWritable->span());
caryclark55888e42016-07-18 10:01:36 -0700692 cs = csWritable;
caryclark30b9fdd2016-08-31 14:36:29 -0700693 os = osWritable->active();
caryclark81a478c2016-09-09 09:37:57 -0700694 FAIL_IF((ce && ce->deleted()) || (oe && oe->deleted()));
caryclark55888e42016-07-18 10:01:36 -0700695 }
696 if (!ce || !oe) {
697 SkOpPtT* ceWritable = ce ? const_cast<SkOpPtT*>(ce)
caryclark29b25632016-08-25 11:27:17 -0700698 : coinSeg->addT(coinTe);
caryclark55888e42016-07-18 10:01:36 -0700699 SkOpPtT* oeWritable = oe ? const_cast<SkOpPtT*>(oe)
caryclark29b25632016-08-25 11:27:17 -0700700 : oppSeg->addT(oppTe);
caryclark30b9fdd2016-08-31 14:36:29 -0700701 ceWritable->span()->addOpp(oeWritable->span());
caryclark55888e42016-07-18 10:01:36 -0700702 ce = ceWritable;
703 oe = oeWritable;
704 }
705 this->debugValidate();
caryclark81a478c2016-09-09 09:37:57 -0700706 FAIL_IF(cs->deleted());
707 FAIL_IF(os->deleted());
708 FAIL_IF(ce->deleted());
709 FAIL_IF(oe->deleted());
710 FAIL_IF(cs->contains(ce) || os->contains(oe));
caryclark55888e42016-07-18 10:01:36 -0700711 bool result = true;
712 if (overlap) {
713 if (overlap->coinPtTStart()->segment() == coinSeg) {
714 result = overlap->extend(cs, ce, os, oe);
715 } else {
716 if (os->fT > oe->fT) {
717 SkTSwap(cs, ce);
718 SkTSwap(os, oe);
719 }
720 result = overlap->extend(os, oe, cs, ce);
721 }
722#if DEBUG_COINCIDENCE_VERBOSE
723 if (result) {
724 overlaps[0]->debugShow();
725 }
726#endif
727 } else {
728 this->add(cs, ce, os, oe);
729#if DEBUG_COINCIDENCE_VERBOSE
730 fHead->debugShow();
731#endif
732 }
733 this->debugValidate();
caryclark81a478c2016-09-09 09:37:57 -0700734 if (result) {
735 *added = true;
736 }
737 return true;
caryclark55888e42016-07-18 10:01:36 -0700738}
739
740// Please keep this in sync with debugAddMissing()
caryclark27c8eb82015-07-06 11:38:33 -0700741/* detects overlaps of different coincident runs on same segment */
742/* does not detect overlaps for pairs without any segments in common */
caryclark55888e42016-07-18 10:01:36 -0700743// returns true if caller should loop again
Cary Clarkab87d7a2016-10-04 10:01:04 -0400744bool SkOpCoincidence::addMissing(bool* added DEBUG_COIN_DECLARE_PARAMS()) {
caryclark27c8eb82015-07-06 11:38:33 -0700745 SkCoincidentSpans* outer = fHead;
caryclark81a478c2016-09-09 09:37:57 -0700746 *added = false;
caryclark54359292015-03-26 07:52:43 -0700747 if (!outer) {
caryclark81a478c2016-09-09 09:37:57 -0700748 return true;
caryclark54359292015-03-26 07:52:43 -0700749 }
caryclark27c8eb82015-07-06 11:38:33 -0700750 fTop = outer;
halcanary96fcdcc2015-08-27 07:41:13 -0700751 fHead = nullptr;
caryclark54359292015-03-26 07:52:43 -0700752 do {
caryclark27c8eb82015-07-06 11:38:33 -0700753 // addifmissing can modify the list that this is walking
caryclark26ad22a2015-10-16 09:03:38 -0700754 // save head so that walker can iterate over old data unperturbed
755 // addifmissing adds to head freely then add saved head in the end
caryclark8016b262016-09-06 05:59:47 -0700756 const SkOpPtT* ocs = outer->coinPtTStart();
757 SkASSERT(!ocs->deleted());
758 const SkOpSegment* outerCoin = ocs->segment();
759 SkASSERT(!outerCoin->done()); // if it's done, should have already been removed from list
760 const SkOpPtT* oos = outer->oppPtTStart();
caryclarkb393a492016-09-07 08:21:09 -0700761 if (oos->deleted()) {
caryclark81a478c2016-09-09 09:37:57 -0700762 return true;
caryclarkb393a492016-09-07 08:21:09 -0700763 }
caryclark8016b262016-09-06 05:59:47 -0700764 const SkOpSegment* outerOpp = oos->segment();
765 SkASSERT(!outerOpp->done());
766 SkOpSegment* outerCoinWritable = const_cast<SkOpSegment*>(outerCoin);
767 SkOpSegment* outerOppWritable = const_cast<SkOpSegment*>(outerOpp);
caryclark54359292015-03-26 07:52:43 -0700768 SkCoincidentSpans* inner = outer;
caryclark55888e42016-07-18 10:01:36 -0700769 while ((inner = inner->next())) {
770 this->debugValidate();
caryclark54359292015-03-26 07:52:43 -0700771 double overS, overE;
caryclark8016b262016-09-06 05:59:47 -0700772 const SkOpPtT* ics = inner->coinPtTStart();
caryclark221a4bb2016-10-07 11:15:15 -0700773 FAIL_IF(ics->deleted());
caryclark8016b262016-09-06 05:59:47 -0700774 const SkOpSegment* innerCoin = ics->segment();
775 SkASSERT(!innerCoin->done());
776 const SkOpPtT* ios = inner->oppPtTStart();
777 SkASSERT(!ios->deleted());
778 const SkOpSegment* innerOpp = ios->segment();
779 SkASSERT(!innerOpp->done());
780 SkOpSegment* innerCoinWritable = const_cast<SkOpSegment*>(innerCoin);
781 SkOpSegment* innerOppWritable = const_cast<SkOpSegment*>(innerOpp);
caryclark55888e42016-07-18 10:01:36 -0700782 if (outerCoin == innerCoin) {
caryclark8016b262016-09-06 05:59:47 -0700783 const SkOpPtT* oce = outer->coinPtTEnd();
caryclarkb393a492016-09-07 08:21:09 -0700784 if (oce->deleted()) {
caryclark81a478c2016-09-09 09:37:57 -0700785 return true;
caryclarkb393a492016-09-07 08:21:09 -0700786 }
caryclark8016b262016-09-06 05:59:47 -0700787 const SkOpPtT* ice = inner->coinPtTEnd();
788 SkASSERT(!ice->deleted());
789 if (outerOpp != innerOpp && this->overlap(ocs, oce, ics, ice, &overS, &overE)) {
caryclark81a478c2016-09-09 09:37:57 -0700790 (void) this->addIfMissing(ocs->starter(oce), ics->starter(ice),
791 overS, overE, outerOppWritable, innerOppWritable, added
caryclark8016b262016-09-06 05:59:47 -0700792 SkDEBUGPARAMS(ocs->debugEnder(oce))
793 SkDEBUGPARAMS(ics->debugEnder(ice)));
caryclark55888e42016-07-18 10:01:36 -0700794 }
795 } else if (outerCoin == innerOpp) {
caryclark8016b262016-09-06 05:59:47 -0700796 const SkOpPtT* oce = outer->coinPtTEnd();
797 SkASSERT(!oce->deleted());
798 const SkOpPtT* ioe = inner->oppPtTEnd();
799 SkASSERT(!ioe->deleted());
800 if (outerOpp != innerCoin && this->overlap(ocs, oce, ios, ioe, &overS, &overE)) {
caryclark81a478c2016-09-09 09:37:57 -0700801 (void) this->addIfMissing(ocs->starter(oce), ios->starter(ioe),
802 overS, overE, outerOppWritable, innerCoinWritable, added
caryclark8016b262016-09-06 05:59:47 -0700803 SkDEBUGPARAMS(ocs->debugEnder(oce))
804 SkDEBUGPARAMS(ios->debugEnder(ioe)));
caryclark55888e42016-07-18 10:01:36 -0700805 }
806 } else if (outerOpp == innerCoin) {
caryclark8016b262016-09-06 05:59:47 -0700807 const SkOpPtT* ooe = outer->oppPtTEnd();
808 SkASSERT(!ooe->deleted());
809 const SkOpPtT* ice = inner->coinPtTEnd();
810 SkASSERT(!ice->deleted());
caryclark55888e42016-07-18 10:01:36 -0700811 SkASSERT(outerCoin != innerOpp);
caryclark8016b262016-09-06 05:59:47 -0700812 if (this->overlap(oos, ooe, ics, ice, &overS, &overE)) {
caryclark81a478c2016-09-09 09:37:57 -0700813 (void) this->addIfMissing(oos->starter(ooe), ics->starter(ice),
814 overS, overE, outerCoinWritable, innerOppWritable, added
caryclark8016b262016-09-06 05:59:47 -0700815 SkDEBUGPARAMS(oos->debugEnder(ooe))
816 SkDEBUGPARAMS(ics->debugEnder(ice)));
caryclark55888e42016-07-18 10:01:36 -0700817 }
818 } else if (outerOpp == innerOpp) {
caryclark8016b262016-09-06 05:59:47 -0700819 const SkOpPtT* ooe = outer->oppPtTEnd();
820 SkASSERT(!ooe->deleted());
821 const SkOpPtT* ioe = inner->oppPtTEnd();
caryclarkb393a492016-09-07 08:21:09 -0700822 if (ioe->deleted()) {
caryclark81a478c2016-09-09 09:37:57 -0700823 return true;
caryclarkb393a492016-09-07 08:21:09 -0700824 }
caryclark55888e42016-07-18 10:01:36 -0700825 SkASSERT(outerCoin != innerCoin);
caryclark8016b262016-09-06 05:59:47 -0700826 if (this->overlap(oos, ooe, ios, ioe, &overS, &overE)) {
caryclark81a478c2016-09-09 09:37:57 -0700827 (void) this->addIfMissing(oos->starter(ooe), ios->starter(ioe),
828 overS, overE, outerCoinWritable, innerCoinWritable, added
caryclark8016b262016-09-06 05:59:47 -0700829 SkDEBUGPARAMS(oos->debugEnder(ooe))
830 SkDEBUGPARAMS(ios->debugEnder(ioe)));
caryclark54359292015-03-26 07:52:43 -0700831 }
832 }
caryclark55888e42016-07-18 10:01:36 -0700833 this->debugValidate();
caryclark54359292015-03-26 07:52:43 -0700834 }
caryclark55888e42016-07-18 10:01:36 -0700835 } while ((outer = outer->next()));
836 this->restoreHead();
caryclark81a478c2016-09-09 09:37:57 -0700837 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700838}
839
caryclark55888e42016-07-18 10:01:36 -0700840bool SkOpCoincidence::addOverlap(const SkOpSegment* seg1, const SkOpSegment* seg1o,
841 const SkOpSegment* seg2, const SkOpSegment* seg2o,
842 const SkOpPtT* overS, const SkOpPtT* overE) {
Cary Clarke47ae292016-10-05 08:51:39 -0400843 const SkOpPtT* s1 = overS->find(seg1);
844 const SkOpPtT* e1 = overE->find(seg1);
caryclark08714012016-10-07 12:57:47 -0700845 FAIL_IF(!s1);
Cary Clark40f23782016-10-06 12:04:16 -0400846 FAIL_IF(!e1);
caryclark27c8eb82015-07-06 11:38:33 -0700847 if (!s1->starter(e1)->span()->upCast()->windValue()) {
Cary Clarke47ae292016-10-05 08:51:39 -0400848 s1 = overS->find(seg1o);
849 e1 = overE->find(seg1o);
caryclark221a4bb2016-10-07 11:15:15 -0700850 FAIL_IF(!s1);
Cary Clark40f23782016-10-06 12:04:16 -0400851 FAIL_IF(!e1);
caryclark27c8eb82015-07-06 11:38:33 -0700852 if (!s1->starter(e1)->span()->upCast()->windValue()) {
caryclark3f0753d2016-06-28 09:23:57 -0700853 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700854 }
855 }
Cary Clarke47ae292016-10-05 08:51:39 -0400856 const SkOpPtT* s2 = overS->find(seg2);
857 const SkOpPtT* e2 = overE->find(seg2);
caryclark27c8eb82015-07-06 11:38:33 -0700858 if (!s2->starter(e2)->span()->upCast()->windValue()) {
Cary Clarke47ae292016-10-05 08:51:39 -0400859 s2 = overS->find(seg2o);
860 e2 = overE->find(seg2o);
caryclark27c8eb82015-07-06 11:38:33 -0700861 if (!s2->starter(e2)->span()->upCast()->windValue()) {
caryclark3f0753d2016-06-28 09:23:57 -0700862 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700863 }
864 }
865 if (s1->segment() == s2->segment()) {
caryclark3f0753d2016-06-28 09:23:57 -0700866 return true;
caryclark27c8eb82015-07-06 11:38:33 -0700867 }
868 if (s1->fT > e1->fT) {
869 SkTSwap(s1, e1);
870 SkTSwap(s2, e2);
871 }
caryclark55888e42016-07-18 10:01:36 -0700872 this->add(s1, e1, s2, e2);
caryclark3f0753d2016-06-28 09:23:57 -0700873 return true;
caryclark54359292015-03-26 07:52:43 -0700874}
875
caryclark55888e42016-07-18 10:01:36 -0700876bool SkOpCoincidence::contains(const SkOpSegment* seg, const SkOpSegment* opp, double oppT) const {
877 if (this->contains(fHead, seg, opp, oppT)) {
878 return true;
879 }
880 if (this->contains(fTop, seg, opp, oppT)) {
881 return true;
882 }
883 return false;
884}
885
886bool SkOpCoincidence::contains(const SkCoincidentSpans* coin, const SkOpSegment* seg,
887 const SkOpSegment* opp, double oppT) const {
888 if (!coin) {
889 return false;
890 }
891 do {
892 if (coin->coinPtTStart()->segment() == seg && coin->oppPtTStart()->segment() == opp
893 && between(coin->oppPtTStart()->fT, oppT, coin->oppPtTEnd()->fT)) {
caryclark54359292015-03-26 07:52:43 -0700894 return true;
895 }
caryclark55888e42016-07-18 10:01:36 -0700896 if (coin->oppPtTStart()->segment() == seg && coin->coinPtTStart()->segment() == opp
897 && between(coin->coinPtTStart()->fT, oppT, coin->coinPtTEnd()->fT)) {
898 return true;
899 }
900 } while ((coin = coin->next()));
caryclark54359292015-03-26 07:52:43 -0700901 return false;
902}
903
caryclark55888e42016-07-18 10:01:36 -0700904bool SkOpCoincidence::contains(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd,
905 const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) const {
906 const SkCoincidentSpans* test = fHead;
907 if (!test) {
908 return false;
909 }
910 const SkOpSegment* coinSeg = coinPtTStart->segment();
911 const SkOpSegment* oppSeg = oppPtTStart->segment();
912 if (!Ordered(coinPtTStart, oppPtTStart)) {
913 SkTSwap(coinSeg, oppSeg);
914 SkTSwap(coinPtTStart, oppPtTStart);
915 SkTSwap(coinPtTEnd, oppPtTEnd);
916 if (coinPtTStart->fT > coinPtTEnd->fT) {
917 SkTSwap(coinPtTStart, coinPtTEnd);
918 SkTSwap(oppPtTStart, oppPtTEnd);
919 }
920 }
921 double oppMinT = SkTMin(oppPtTStart->fT, oppPtTEnd->fT);
922 double oppMaxT = SkTMax(oppPtTStart->fT, oppPtTEnd->fT);
923 do {
924 if (coinSeg != test->coinPtTStart()->segment()) {
925 continue;
926 }
927 if (coinPtTStart->fT < test->coinPtTStart()->fT) {
928 continue;
929 }
930 if (coinPtTEnd->fT > test->coinPtTEnd()->fT) {
931 continue;
932 }
933 if (oppSeg != test->oppPtTStart()->segment()) {
934 continue;
935 }
936 if (oppMinT < SkTMin(test->oppPtTStart()->fT, test->oppPtTEnd()->fT)) {
937 continue;
938 }
939 if (oppMaxT > SkTMax(test->oppPtTStart()->fT, test->oppPtTEnd()->fT)) {
940 continue;
941 }
942 return true;
943 } while ((test = test->next()));
944 return false;
945}
946
Cary Clarkab87d7a2016-10-04 10:01:04 -0400947void SkOpCoincidence::correctEnds(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
948 DEBUG_SET_PHASE();
caryclark55888e42016-07-18 10:01:36 -0700949 SkCoincidentSpans* coin = fHead;
950 if (!coin) {
951 return;
952 }
953 do {
954 coin->correctEnds();
955 } while ((coin = coin->next()));
956}
957
caryclark54359292015-03-26 07:52:43 -0700958// walk span sets in parallel, moving winding from one to the other
Cary Clarke47ae292016-10-05 08:51:39 -0400959void SkOpCoincidence::apply(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
Cary Clarkab87d7a2016-10-04 10:01:04 -0400960 DEBUG_SET_PHASE();
caryclark54359292015-03-26 07:52:43 -0700961 SkCoincidentSpans* coin = fHead;
962 if (!coin) {
Cary Clarke47ae292016-10-05 08:51:39 -0400963 return;
caryclark54359292015-03-26 07:52:43 -0700964 }
965 do {
caryclark55888e42016-07-18 10:01:36 -0700966 SkOpSpan* start = coin->coinPtTStartWritable()->span()->upCast();
caryclark182b4992015-05-14 05:45:54 -0700967 if (start->deleted()) {
968 continue;
969 }
caryclark55888e42016-07-18 10:01:36 -0700970 const SkOpSpanBase* end = coin->coinPtTEnd()->span();
caryclark54359292015-03-26 07:52:43 -0700971 SkASSERT(start == start->starter(end));
caryclark55888e42016-07-18 10:01:36 -0700972 bool flipped = coin->flipped();
973 SkOpSpan* oStart = (flipped ? coin->oppPtTEndWritable()
974 : coin->oppPtTStartWritable())->span()->upCast();
caryclark182b4992015-05-14 05:45:54 -0700975 if (oStart->deleted()) {
976 continue;
977 }
caryclark55888e42016-07-18 10:01:36 -0700978 const SkOpSpanBase* oEnd = (flipped ? coin->oppPtTStart() : coin->oppPtTEnd())->span();
caryclark54359292015-03-26 07:52:43 -0700979 SkASSERT(oStart == oStart->starter(oEnd));
980 SkOpSegment* segment = start->segment();
981 SkOpSegment* oSegment = oStart->segment();
982 bool operandSwap = segment->operand() != oSegment->operand();
983 if (flipped) {
caryclark364a0072015-12-14 08:43:21 -0800984 if (oEnd->deleted()) {
985 continue;
986 }
caryclark54359292015-03-26 07:52:43 -0700987 do {
988 SkOpSpanBase* oNext = oStart->next();
989 if (oNext == oEnd) {
990 break;
991 }
992 oStart = oNext->upCast();
993 } while (true);
994 }
caryclark54359292015-03-26 07:52:43 -0700995 do {
996 int windValue = start->windValue();
caryclark54359292015-03-26 07:52:43 -0700997 int oppValue = start->oppValue();
caryclark1049f122015-04-20 08:31:59 -0700998 int oWindValue = oStart->windValue();
caryclark54359292015-03-26 07:52:43 -0700999 int oOppValue = oStart->oppValue();
1000 // winding values are added or subtracted depending on direction and wind type
1001 // same or opposite values are summed depending on the operand value
caryclark1049f122015-04-20 08:31:59 -07001002 int windDiff = operandSwap ? oOppValue : oWindValue;
1003 int oWindDiff = operandSwap ? oppValue : windValue;
1004 if (!flipped) {
1005 windDiff = -windDiff;
1006 oWindDiff = -oWindDiff;
1007 }
caryclark55888e42016-07-18 10:01:36 -07001008 bool addToStart = windValue && (windValue > windDiff || (windValue == windDiff
1009 && oWindValue <= oWindDiff));
1010 if (addToStart ? start->done() : oStart->done()) {
1011 addToStart ^= true;
1012 }
1013 if (addToStart) {
caryclark54359292015-03-26 07:52:43 -07001014 if (operandSwap) {
1015 SkTSwap(oWindValue, oOppValue);
1016 }
1017 if (flipped) {
1018 windValue -= oWindValue;
1019 oppValue -= oOppValue;
1020 } else {
1021 windValue += oWindValue;
1022 oppValue += oOppValue;
1023 }
caryclark1049f122015-04-20 08:31:59 -07001024 if (segment->isXor()) {
caryclark54359292015-03-26 07:52:43 -07001025 windValue &= 1;
1026 }
caryclark1049f122015-04-20 08:31:59 -07001027 if (segment->oppXor()) {
caryclark54359292015-03-26 07:52:43 -07001028 oppValue &= 1;
1029 }
1030 oWindValue = oOppValue = 0;
1031 } else {
1032 if (operandSwap) {
1033 SkTSwap(windValue, oppValue);
1034 }
1035 if (flipped) {
1036 oWindValue -= windValue;
1037 oOppValue -= oppValue;
1038 } else {
1039 oWindValue += windValue;
1040 oOppValue += oppValue;
1041 }
caryclark1049f122015-04-20 08:31:59 -07001042 if (oSegment->isXor()) {
caryclark54359292015-03-26 07:52:43 -07001043 oWindValue &= 1;
1044 }
caryclark1049f122015-04-20 08:31:59 -07001045 if (oSegment->oppXor()) {
1046 oOppValue &= 1;
1047 }
caryclark54359292015-03-26 07:52:43 -07001048 windValue = oppValue = 0;
1049 }
caryclark6c3b9cd2016-09-26 05:36:58 -07001050#if 0 && DEBUG_COINCIDENCE
caryclark55888e42016-07-18 10:01:36 -07001051 SkDebugf("seg=%d span=%d windValue=%d oppValue=%d\n", segment->debugID(),
1052 start->debugID(), windValue, oppValue);
1053 SkDebugf("seg=%d span=%d windValue=%d oppValue=%d\n", oSegment->debugID(),
1054 oStart->debugID(), oWindValue, oOppValue);
1055#endif
caryclark54359292015-03-26 07:52:43 -07001056 start->setWindValue(windValue);
1057 start->setOppValue(oppValue);
1058 oStart->setWindValue(oWindValue);
1059 oStart->setOppValue(oOppValue);
1060 if (!windValue && !oppValue) {
1061 segment->markDone(start);
1062 }
1063 if (!oWindValue && !oOppValue) {
1064 oSegment->markDone(oStart);
1065 }
1066 SkOpSpanBase* next = start->next();
1067 SkOpSpanBase* oNext = flipped ? oStart->prev() : oStart->next();
1068 if (next == end) {
1069 break;
1070 }
1071 start = next->upCast();
caryclark1049f122015-04-20 08:31:59 -07001072 // if the opposite ran out too soon, just reuse the last span
1073 if (!oNext || !oNext->upCastable()) {
1074 oNext = oStart;
caryclark54359292015-03-26 07:52:43 -07001075 }
1076 oStart = oNext->upCast();
1077 } while (true);
caryclark55888e42016-07-18 10:01:36 -07001078 } while ((coin = coin->next()));
caryclark54359292015-03-26 07:52:43 -07001079}
1080
caryclark55888e42016-07-18 10:01:36 -07001081// Please keep this in sync with debugRelease()
1082bool SkOpCoincidence::release(SkCoincidentSpans* coin, SkCoincidentSpans* remove) {
1083 SkCoincidentSpans* head = coin;
halcanary96fcdcc2015-08-27 07:41:13 -07001084 SkCoincidentSpans* prev = nullptr;
caryclark54359292015-03-26 07:52:43 -07001085 SkCoincidentSpans* next;
1086 do {
caryclark55888e42016-07-18 10:01:36 -07001087 next = coin->next();
caryclark54359292015-03-26 07:52:43 -07001088 if (coin == remove) {
1089 if (prev) {
caryclark55888e42016-07-18 10:01:36 -07001090 prev->setNext(next);
1091 } else if (head == fHead) {
caryclark54359292015-03-26 07:52:43 -07001092 fHead = next;
caryclark55888e42016-07-18 10:01:36 -07001093 } else {
1094 fTop = next;
caryclark54359292015-03-26 07:52:43 -07001095 }
1096 break;
1097 }
1098 prev = coin;
1099 } while ((coin = next));
caryclark55888e42016-07-18 10:01:36 -07001100 return coin != nullptr;
caryclark54359292015-03-26 07:52:43 -07001101}
1102
caryclark30b9fdd2016-08-31 14:36:29 -07001103void SkOpCoincidence::releaseDeleted(SkCoincidentSpans* coin) {
1104 if (!coin) {
1105 return;
1106 }
1107 SkCoincidentSpans* head = coin;
1108 SkCoincidentSpans* prev = nullptr;
1109 SkCoincidentSpans* next;
1110 do {
1111 next = coin->next();
1112 if (coin->coinPtTStart()->deleted()) {
1113 SkOPASSERT(coin->flipped() ? coin->oppPtTEnd()->deleted() :
1114 coin->oppPtTStart()->deleted());
1115 if (prev) {
1116 prev->setNext(next);
1117 } else if (head == fHead) {
1118 fHead = next;
1119 } else {
1120 fTop = next;
1121 }
1122 } else {
1123 SkOPASSERT(coin->flipped() ? !coin->oppPtTEnd()->deleted() :
1124 !coin->oppPtTStart()->deleted());
1125 prev = coin;
1126 }
1127 } while ((coin = next));
1128}
1129
1130void SkOpCoincidence::releaseDeleted() {
1131 this->releaseDeleted(fHead);
1132 this->releaseDeleted(fTop);
1133}
1134
caryclark55888e42016-07-18 10:01:36 -07001135void SkOpCoincidence::restoreHead() {
1136 SkCoincidentSpans** headPtr = &fHead;
1137 while (*headPtr) {
1138 headPtr = (*headPtr)->nextPtr();
1139 }
1140 *headPtr = fTop;
1141 fTop = nullptr;
1142 // segments may have collapsed in the meantime; remove empty referenced segments
1143 headPtr = &fHead;
1144 while (*headPtr) {
1145 SkCoincidentSpans* test = *headPtr;
1146 if (test->coinPtTStart()->segment()->done() || test->oppPtTStart()->segment()->done()) {
1147 *headPtr = test->next();
1148 continue;
1149 }
1150 headPtr = (*headPtr)->nextPtr();
1151 }
1152}
1153
1154// Please keep this in sync with debugExpand()
caryclark30b9fdd2016-08-31 14:36:29 -07001155// expand the range by checking adjacent spans for coincidence
Cary Clarkab87d7a2016-10-04 10:01:04 -04001156bool SkOpCoincidence::expand(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
1157 DEBUG_SET_PHASE();
caryclark54359292015-03-26 07:52:43 -07001158 SkCoincidentSpans* coin = fHead;
1159 if (!coin) {
caryclark27c8eb82015-07-06 11:38:33 -07001160 return false;
caryclark54359292015-03-26 07:52:43 -07001161 }
caryclark27c8eb82015-07-06 11:38:33 -07001162 bool expanded = false;
caryclark54359292015-03-26 07:52:43 -07001163 do {
caryclark55888e42016-07-18 10:01:36 -07001164 if (coin->expand()) {
1165 // check to see if multiple spans expanded so they are now identical
1166 SkCoincidentSpans* test = fHead;
1167 do {
1168 if (coin == test) {
1169 continue;
1170 }
1171 if (coin->coinPtTStart() == test->coinPtTStart()
1172 && coin->oppPtTStart() == test->oppPtTStart()) {
1173 this->release(fHead, test);
1174 break;
1175 }
1176 } while ((test = test->next()));
1177 expanded = true;
caryclark54359292015-03-26 07:52:43 -07001178 }
caryclark55888e42016-07-18 10:01:36 -07001179 } while ((coin = coin->next()));
caryclark27c8eb82015-07-06 11:38:33 -07001180 return expanded;
1181}
1182
Cary Clark40f23782016-10-06 12:04:16 -04001183bool SkOpCoincidence::findOverlaps(SkOpCoincidence* overlaps DEBUG_COIN_DECLARE_PARAMS()) const {
Cary Clarkab87d7a2016-10-04 10:01:04 -04001184 DEBUG_SET_PHASE();
halcanary96fcdcc2015-08-27 07:41:13 -07001185 overlaps->fHead = overlaps->fTop = nullptr;
caryclark27c8eb82015-07-06 11:38:33 -07001186 SkCoincidentSpans* outer = fHead;
1187 while (outer) {
caryclark55888e42016-07-18 10:01:36 -07001188 const SkOpSegment* outerCoin = outer->coinPtTStart()->segment();
1189 const SkOpSegment* outerOpp = outer->oppPtTStart()->segment();
caryclark27c8eb82015-07-06 11:38:33 -07001190 SkCoincidentSpans* inner = outer;
caryclark55888e42016-07-18 10:01:36 -07001191 while ((inner = inner->next())) {
1192 const SkOpSegment* innerCoin = inner->coinPtTStart()->segment();
caryclark27c8eb82015-07-06 11:38:33 -07001193 if (outerCoin == innerCoin) {
1194 continue; // both winners are the same segment, so there's no additional overlap
1195 }
caryclark55888e42016-07-18 10:01:36 -07001196 const SkOpSegment* innerOpp = inner->oppPtTStart()->segment();
1197 const SkOpPtT* overlapS;
1198 const SkOpPtT* overlapE;
1199 if ((outerOpp == innerCoin && SkOpPtT::Overlaps(outer->oppPtTStart(),
1200 outer->oppPtTEnd(),inner->coinPtTStart(), inner->coinPtTEnd(), &overlapS,
1201 &overlapE))
1202 || (outerCoin == innerOpp && SkOpPtT::Overlaps(outer->coinPtTStart(),
1203 outer->coinPtTEnd(), inner->oppPtTStart(), inner->oppPtTEnd(),
caryclark27c8eb82015-07-06 11:38:33 -07001204 &overlapS, &overlapE))
caryclark55888e42016-07-18 10:01:36 -07001205 || (outerOpp == innerOpp && SkOpPtT::Overlaps(outer->oppPtTStart(),
1206 outer->oppPtTEnd(), inner->oppPtTStart(), inner->oppPtTEnd(),
caryclark27c8eb82015-07-06 11:38:33 -07001207 &overlapS, &overlapE))) {
Cary Clark40f23782016-10-06 12:04:16 -04001208 if (!overlaps->addOverlap(outerCoin, outerOpp, innerCoin, innerOpp,
1209 overlapS, overlapE)) {
1210 return false;
1211 }
Cary Clarke47ae292016-10-05 08:51:39 -04001212 }
caryclark27c8eb82015-07-06 11:38:33 -07001213 }
caryclark55888e42016-07-18 10:01:36 -07001214 outer = outer->next();
caryclark27c8eb82015-07-06 11:38:33 -07001215 }
Cary Clark40f23782016-10-06 12:04:16 -04001216 return true;
caryclark27c8eb82015-07-06 11:38:33 -07001217}
1218
caryclark55888e42016-07-18 10:01:36 -07001219void SkOpCoincidence::fixUp(SkOpPtT* deleted, const SkOpPtT* kept) {
caryclarkb393a492016-09-07 08:21:09 -07001220 SkOPASSERT(deleted != kept);
caryclark55888e42016-07-18 10:01:36 -07001221 if (fHead) {
1222 this->fixUp(fHead, deleted, kept);
caryclark54359292015-03-26 07:52:43 -07001223 }
caryclark55888e42016-07-18 10:01:36 -07001224 if (fTop) {
1225 this->fixUp(fTop, deleted, kept);
1226 }
caryclark54359292015-03-26 07:52:43 -07001227}
1228
caryclark55888e42016-07-18 10:01:36 -07001229void SkOpCoincidence::fixUp(SkCoincidentSpans* coin, SkOpPtT* deleted, const SkOpPtT* kept) {
1230 SkCoincidentSpans* head = coin;
1231 do {
1232 if (coin->coinPtTStart() == deleted) {
1233 if (coin->coinPtTEnd()->span() == kept->span()) {
1234 this->release(head, coin);
1235 continue;
1236 }
1237 coin->setCoinPtTStart(kept);
1238 }
1239 if (coin->coinPtTEnd() == deleted) {
1240 if (coin->coinPtTStart()->span() == kept->span()) {
1241 this->release(head, coin);
1242 continue;
1243 }
1244 coin->setCoinPtTEnd(kept);
1245 }
1246 if (coin->oppPtTStart() == deleted) {
1247 if (coin->oppPtTEnd()->span() == kept->span()) {
1248 this->release(head, coin);
1249 continue;
1250 }
1251 coin->setOppPtTStart(kept);
1252 }
1253 if (coin->oppPtTEnd() == deleted) {
1254 if (coin->oppPtTStart()->span() == kept->span()) {
1255 this->release(head, coin);
1256 continue;
1257 }
1258 coin->setOppPtTEnd(kept);
1259 }
1260 } while ((coin = coin->next()));
1261}
1262
1263// Please keep this in sync with debugMark()
caryclark27c8eb82015-07-06 11:38:33 -07001264/* this sets up the coincidence links in the segments when the coincidence crosses multiple spans */
caryclarke6522ea2016-10-17 07:54:33 -07001265bool SkOpCoincidence::mark(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
Cary Clarkab87d7a2016-10-04 10:01:04 -04001266 DEBUG_SET_PHASE();
caryclark54359292015-03-26 07:52:43 -07001267 SkCoincidentSpans* coin = fHead;
1268 if (!coin) {
caryclarke6522ea2016-10-17 07:54:33 -07001269 return true;
caryclark54359292015-03-26 07:52:43 -07001270 }
1271 do {
caryclarke6522ea2016-10-17 07:54:33 -07001272 SkOpSpanBase* startBase = coin->coinPtTStartWritable()->span();
1273 FAIL_IF(!startBase->upCastable());
1274 SkOpSpan* start = startBase->upCast();
caryclark55888e42016-07-18 10:01:36 -07001275 SkASSERT(!start->deleted());
1276 SkOpSpanBase* end = coin->coinPtTEndWritable()->span();
Cary Clark40f23782016-10-06 12:04:16 -04001277 SkOPASSERT(!end->deleted());
caryclark55888e42016-07-18 10:01:36 -07001278 SkOpSpanBase* oStart = coin->oppPtTStartWritable()->span();
Cary Clark40f23782016-10-06 12:04:16 -04001279 SkOPASSERT(!oStart->deleted());
caryclark55888e42016-07-18 10:01:36 -07001280 SkOpSpanBase* oEnd = coin->oppPtTEndWritable()->span();
1281 SkASSERT(!oEnd->deleted());
1282 bool flipped = coin->flipped();
caryclark54359292015-03-26 07:52:43 -07001283 if (flipped) {
1284 SkTSwap(oStart, oEnd);
1285 }
caryclark55888e42016-07-18 10:01:36 -07001286 /* coin and opp spans may not match up. Mark the ends, and then let the interior
1287 get marked as many times as the spans allow */
1288 start->insertCoincidence(oStart->upCast());
1289 end->insertCoinEnd(oEnd);
1290 const SkOpSegment* segment = start->segment();
1291 const SkOpSegment* oSegment = oStart->segment();
caryclark54359292015-03-26 07:52:43 -07001292 SkOpSpanBase* next = start;
1293 SkOpSpanBase* oNext = oStart;
caryclark81a478c2016-09-09 09:37:57 -07001294 bool ordered = coin->ordered();
caryclark55888e42016-07-18 10:01:36 -07001295 while ((next = next->upCast()->next()) != end) {
caryclarke6522ea2016-10-17 07:54:33 -07001296 FAIL_IF(!next->upCastable());
Cary Clarke47ae292016-10-05 08:51:39 -04001297 SkAssertResult(next->upCast()->insertCoincidence(oSegment, flipped, ordered));
caryclark55888e42016-07-18 10:01:36 -07001298 }
1299 while ((oNext = oNext->upCast()->next()) != oEnd) {
caryclarke6522ea2016-10-17 07:54:33 -07001300 FAIL_IF(!oNext->upCast()->insertCoincidence(segment, flipped, ordered));
caryclark55888e42016-07-18 10:01:36 -07001301 }
1302 } while ((coin = coin->next()));
caryclarke6522ea2016-10-17 07:54:33 -07001303 return true;
caryclark54359292015-03-26 07:52:43 -07001304}
1305
caryclark55888e42016-07-18 10:01:36 -07001306// Please keep in sync with debugMarkCollapsed()
1307void SkOpCoincidence::markCollapsed(SkCoincidentSpans* coin, SkOpPtT* test) {
1308 SkCoincidentSpans* head = coin;
1309 while (coin) {
1310 if (coin->collapsed(test)) {
1311 if (zero_or_one(coin->coinPtTStart()->fT) && zero_or_one(coin->coinPtTEnd()->fT)) {
1312 coin->coinPtTStartWritable()->segment()->markAllDone();
1313 }
1314 if (zero_or_one(coin->oppPtTStart()->fT) && zero_or_one(coin->oppPtTEnd()->fT)) {
1315 coin->oppPtTStartWritable()->segment()->markAllDone();
1316 }
1317 this->release(head, coin);
1318 }
1319 coin = coin->next();
1320 }
1321}
1322
1323// Please keep in sync with debugMarkCollapsed()
1324void SkOpCoincidence::markCollapsed(SkOpPtT* test) {
1325 markCollapsed(fHead, test);
1326 markCollapsed(fTop, test);
1327}
1328
1329bool SkOpCoincidence::Ordered(const SkOpSegment* coinSeg, const SkOpSegment* oppSeg) {
1330 if (coinSeg->verb() < oppSeg->verb()) {
1331 return true;
1332 }
1333 if (coinSeg->verb() > oppSeg->verb()) {
1334 return false;
1335 }
1336 int count = (SkPathOpsVerbToPoints(coinSeg->verb()) + 1) * 2;
1337 const SkScalar* cPt = &coinSeg->pts()[0].fX;
1338 const SkScalar* oPt = &oppSeg->pts()[0].fX;
1339 for (int index = 0; index < count; ++index) {
1340 if (*cPt < *oPt) {
1341 return true;
1342 }
1343 if (*cPt > *oPt) {
1344 return false;
1345 }
1346 ++cPt;
1347 ++oPt;
1348 }
1349 return true;
1350}
1351
1352bool SkOpCoincidence::overlap(const SkOpPtT* coin1s, const SkOpPtT* coin1e,
caryclark54359292015-03-26 07:52:43 -07001353 const SkOpPtT* coin2s, const SkOpPtT* coin2e, double* overS, double* overE) const {
caryclark27c8eb82015-07-06 11:38:33 -07001354 SkASSERT(coin1s->segment() == coin2s->segment());
caryclark54359292015-03-26 07:52:43 -07001355 *overS = SkTMax(SkTMin(coin1s->fT, coin1e->fT), SkTMin(coin2s->fT, coin2e->fT));
1356 *overE = SkTMin(SkTMax(coin1s->fT, coin1e->fT), SkTMax(coin2s->fT, coin2e->fT));
1357 return *overS < *overE;
1358}
caryclark27c8eb82015-07-06 11:38:33 -07001359
caryclark55888e42016-07-18 10:01:36 -07001360// Commented-out lines keep this in sync with debugRelease()
1361void SkOpCoincidence::release(const SkOpSegment* deleted) {
1362 SkCoincidentSpans* coin = fHead;
1363 if (!coin) {
1364 return;
1365 }
1366 do {
1367 if (coin->coinPtTStart()->segment() == deleted
1368 || coin->coinPtTEnd()->segment() == deleted
1369 || coin->oppPtTStart()->segment() == deleted
1370 || coin->oppPtTEnd()->segment() == deleted) {
1371 this->release(fHead, coin);
1372 }
1373 } while ((coin = coin->next()));
1374}