blob: 9fa05f1655be22daa4471cb632819a9307bcf677 [file] [log] [blame]
caryclark54359292015-03-26 07:52:43 -07001/*
2 * Copyright 2014 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 "SkOpContour.h"
9#include "SkOpSegment.h"
10#include "SkPathWriter.h"
11
12bool SkOpPtT::alias() const {
13 return this->span()->ptT() != this;
14}
15
caryclark30b9fdd2016-08-31 14:36:29 -070016const SkOpPtT* SkOpPtT::active() const {
17 if (!fDeleted) {
18 return this;
19 }
20 const SkOpPtT* ptT = this;
21 const SkOpPtT* stopPtT = ptT;
22 while ((ptT = ptT->next()) != stopPtT) {
23 if (ptT->fSpan == fSpan && !ptT->fDeleted) {
24 return ptT;
25 }
26 }
Cary Clark74b42902018-03-09 07:38:47 -050027 return nullptr; // should never return deleted; caller must abort
caryclark30b9fdd2016-08-31 14:36:29 -070028}
29
caryclark27c8eb82015-07-06 11:38:33 -070030bool SkOpPtT::contains(const SkOpPtT* check) const {
caryclarke7bb5b22016-09-22 05:20:07 -070031 SkOPASSERT(this != check);
caryclark27c8eb82015-07-06 11:38:33 -070032 const SkOpPtT* ptT = this;
33 const SkOpPtT* stopPtT = ptT;
34 while ((ptT = ptT->next()) != stopPtT) {
35 if (ptT == check) {
36 return true;
37 }
38 }
39 return false;
40}
41
caryclark55888e42016-07-18 10:01:36 -070042bool SkOpPtT::contains(const SkOpSegment* segment, const SkPoint& pt) const {
43 SkASSERT(this->segment() != segment);
44 const SkOpPtT* ptT = this;
caryclark27c8eb82015-07-06 11:38:33 -070045 const SkOpPtT* stopPtT = ptT;
46 while ((ptT = ptT->next()) != stopPtT) {
caryclark55888e42016-07-18 10:01:36 -070047 if (ptT->fPt == pt && ptT->segment() == segment) {
48 return true;
49 }
50 }
51 return false;
52}
53
54bool SkOpPtT::contains(const SkOpSegment* segment, double t) const {
55 const SkOpPtT* ptT = this;
56 const SkOpPtT* stopPtT = ptT;
57 while ((ptT = ptT->next()) != stopPtT) {
58 if (ptT->fT == t && ptT->segment() == segment) {
59 return true;
60 }
61 }
62 return false;
63}
64
65const SkOpPtT* SkOpPtT::contains(const SkOpSegment* check) const {
66 SkASSERT(this->segment() != check);
67 const SkOpPtT* ptT = this;
68 const SkOpPtT* stopPtT = ptT;
69 while ((ptT = ptT->next()) != stopPtT) {
70 if (ptT->segment() == check && !ptT->deleted()) {
caryclark27c8eb82015-07-06 11:38:33 -070071 return ptT;
72 }
73 }
halcanary96fcdcc2015-08-27 07:41:13 -070074 return nullptr;
caryclark27c8eb82015-07-06 11:38:33 -070075}
76
caryclark54359292015-03-26 07:52:43 -070077SkOpContour* SkOpPtT::contour() const {
78 return segment()->contour();
79}
80
caryclark55888e42016-07-18 10:01:36 -070081const SkOpPtT* SkOpPtT::find(const SkOpSegment* segment) const {
82 const SkOpPtT* ptT = this;
caryclark27c8eb82015-07-06 11:38:33 -070083 const SkOpPtT* stopPtT = ptT;
84 do {
caryclark55888e42016-07-18 10:01:36 -070085 if (ptT->segment() == segment && !ptT->deleted()) {
caryclark27c8eb82015-07-06 11:38:33 -070086 return ptT;
87 }
88 ptT = ptT->fNext;
89 } while (stopPtT != ptT);
caryclark55888e42016-07-18 10:01:36 -070090// SkASSERT(0);
halcanary96fcdcc2015-08-27 07:41:13 -070091 return nullptr;
caryclark27c8eb82015-07-06 11:38:33 -070092}
93
caryclark54359292015-03-26 07:52:43 -070094SkOpGlobalState* SkOpPtT::globalState() const {
caryclark55888e42016-07-18 10:01:36 -070095 return contour()->globalState();
caryclark54359292015-03-26 07:52:43 -070096}
97
98void SkOpPtT::init(SkOpSpanBase* span, double t, const SkPoint& pt, bool duplicate) {
99 fT = t;
100 fPt = pt;
101 fSpan = span;
102 fNext = this;
103 fDuplicatePt = duplicate;
104 fDeleted = false;
caryclark55888e42016-07-18 10:01:36 -0700105 fCoincident = false;
caryclark1049f122015-04-20 08:31:59 -0700106 SkDEBUGCODE(fID = span->globalState()->nextPtTID());
caryclark54359292015-03-26 07:52:43 -0700107}
108
109bool SkOpPtT::onEnd() const {
110 const SkOpSpanBase* span = this->span();
111 if (span->ptT() != this) {
112 return false;
113 }
114 const SkOpSegment* segment = this->segment();
115 return span == segment->head() || span == segment->tail();
116}
117
caryclark55888e42016-07-18 10:01:36 -0700118bool SkOpPtT::ptAlreadySeen(const SkOpPtT* check) const {
119 while (this != check) {
120 if (this->fPt == check->fPt) {
121 return true;
122 }
123 check = check->fNext;
124 }
125 return false;
126}
127
caryclark54359292015-03-26 07:52:43 -0700128SkOpPtT* SkOpPtT::prev() {
129 SkOpPtT* result = this;
130 SkOpPtT* next = this;
131 while ((next = next->fNext) != this) {
132 result = next;
133 }
134 SkASSERT(result->fNext == this);
135 return result;
136}
137
caryclark54359292015-03-26 07:52:43 -0700138const SkOpSegment* SkOpPtT::segment() const {
139 return span()->segment();
140}
141
142SkOpSegment* SkOpPtT::segment() {
143 return span()->segment();
144}
145
caryclark55888e42016-07-18 10:01:36 -0700146void SkOpPtT::setDeleted() {
147 SkASSERT(this->span()->debugDeleted() || this->span()->ptT() != this);
caryclark15976282016-07-21 05:48:43 -0700148 SkOPASSERT(!fDeleted);
caryclark55888e42016-07-18 10:01:36 -0700149 fDeleted = true;
150}
151
caryclark30b9fdd2016-08-31 14:36:29 -0700152void SkOpSpanBase::addOpp(SkOpSpanBase* opp) {
caryclark29b25632016-08-25 11:27:17 -0700153 SkOpPtT* oppPrev = this->ptT()->oppPrev(opp->ptT());
caryclark30b9fdd2016-08-31 14:36:29 -0700154 if (!oppPrev) {
caryclark54359292015-03-26 07:52:43 -0700155 return;
156 }
caryclark30b9fdd2016-08-31 14:36:29 -0700157 this->mergeMatches(opp);
158 this->ptT()->addOpp(opp->ptT(), oppPrev);
159 this->checkForCollapsedCoincidence();
caryclark55888e42016-07-18 10:01:36 -0700160}
161
Cary Clarkba610292018-06-19 09:47:15 -0400162SkOpSpanBase::Collapsed SkOpSpanBase::collapsed(double s, double e) const {
caryclark30b9fdd2016-08-31 14:36:29 -0700163 const SkOpPtT* start = &fPtT;
Cary Clarkba610292018-06-19 09:47:15 -0400164 const SkOpPtT* startNext = nullptr;
caryclark30b9fdd2016-08-31 14:36:29 -0700165 const SkOpPtT* walk = start;
166 double min = walk->fT;
167 double max = min;
168 const SkOpSegment* segment = this->segment();
Cary Clark4929a4a2018-10-17 14:12:41 -0400169 int safetyNet = 100000;
caryclark30b9fdd2016-08-31 14:36:29 -0700170 while ((walk = walk->next()) != start) {
Cary Clark4929a4a2018-10-17 14:12:41 -0400171 if (!--safetyNet) {
172 return Collapsed::kError;
173 }
Cary Clarkba610292018-06-19 09:47:15 -0400174 if (walk == startNext) {
175 return Collapsed::kError;
176 }
caryclark30b9fdd2016-08-31 14:36:29 -0700177 if (walk->segment() != segment) {
178 continue;
179 }
180 min = SkTMin(min, walk->fT);
181 max = SkTMax(max, walk->fT);
182 if (between(min, s, max) && between(min, e, max)) {
Cary Clarkba610292018-06-19 09:47:15 -0400183 return Collapsed::kYes;
caryclark30b9fdd2016-08-31 14:36:29 -0700184 }
Cary Clarkba610292018-06-19 09:47:15 -0400185 startNext = start->next();
caryclark30b9fdd2016-08-31 14:36:29 -0700186 }
Cary Clarkba610292018-06-19 09:47:15 -0400187 return Collapsed::kNo;
caryclark30b9fdd2016-08-31 14:36:29 -0700188}
189
caryclark54359292015-03-26 07:52:43 -0700190bool SkOpSpanBase::contains(const SkOpSpanBase* span) const {
191 const SkOpPtT* start = &fPtT;
192 const SkOpPtT* check = &span->fPtT;
caryclarkef4f32a2016-08-24 09:24:18 -0700193 SkOPASSERT(start != check);
caryclark54359292015-03-26 07:52:43 -0700194 const SkOpPtT* walk = start;
195 while ((walk = walk->next()) != start) {
196 if (walk == check) {
197 return true;
198 }
199 }
200 return false;
201}
202
caryclark55888e42016-07-18 10:01:36 -0700203const SkOpPtT* SkOpSpanBase::contains(const SkOpSegment* segment) const {
204 const SkOpPtT* start = &fPtT;
205 const SkOpPtT* walk = start;
caryclark54359292015-03-26 07:52:43 -0700206 while ((walk = walk->next()) != start) {
caryclark55888e42016-07-18 10:01:36 -0700207 if (walk->deleted()) {
208 continue;
209 }
210 if (walk->segment() == segment && walk->span()->ptT() == walk) {
caryclark54359292015-03-26 07:52:43 -0700211 return walk;
212 }
213 }
halcanary96fcdcc2015-08-27 07:41:13 -0700214 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700215}
216
217bool SkOpSpanBase::containsCoinEnd(const SkOpSegment* segment) const {
218 SkASSERT(this->segment() != segment);
219 const SkOpSpanBase* next = this;
220 while ((next = next->fCoinEnd) != this) {
221 if (next->segment() == segment) {
222 return true;
223 }
224 }
225 return false;
226}
227
228SkOpContour* SkOpSpanBase::contour() const {
229 return segment()->contour();
230}
231
232SkOpGlobalState* SkOpSpanBase::globalState() const {
caryclark55888e42016-07-18 10:01:36 -0700233 return contour()->globalState();
caryclark54359292015-03-26 07:52:43 -0700234}
235
236void SkOpSpanBase::initBase(SkOpSegment* segment, SkOpSpan* prev, double t, const SkPoint& pt) {
237 fSegment = segment;
238 fPtT.init(this, t, pt, false);
239 fCoinEnd = this;
halcanary96fcdcc2015-08-27 07:41:13 -0700240 fFromAngle = nullptr;
caryclark54359292015-03-26 07:52:43 -0700241 fPrev = prev;
caryclark08bc8482015-04-24 09:08:57 -0700242 fSpanAdds = 0;
caryclark54359292015-03-26 07:52:43 -0700243 fAligned = true;
244 fChased = false;
caryclark1049f122015-04-20 08:31:59 -0700245 SkDEBUGCODE(fCount = 1);
246 SkDEBUGCODE(fID = globalState()->nextSpanID());
caryclark30b9fdd2016-08-31 14:36:29 -0700247 SkDEBUGCODE(fDebugDeleted = false);
caryclark54359292015-03-26 07:52:43 -0700248}
249
250// this pair of spans share a common t value or point; merge them and eliminate duplicates
251// this does not compute the best t or pt value; this merely moves all data into a single list
252void SkOpSpanBase::merge(SkOpSpan* span) {
253 SkOpPtT* spanPtT = span->ptT();
254 SkASSERT(this->t() != spanPtT->fT);
255 SkASSERT(!zero_or_one(spanPtT->fT));
mtklein18300a32016-03-16 13:53:35 -0700256 span->release(this->ptT());
caryclark55888e42016-07-18 10:01:36 -0700257 if (this->contains(span)) {
caryclark30b9fdd2016-08-31 14:36:29 -0700258 SkOPASSERT(0); // check to see if this ever happens -- should have been found earlier
caryclark55888e42016-07-18 10:01:36 -0700259 return; // merge is already in the ptT loop
260 }
caryclark54359292015-03-26 07:52:43 -0700261 SkOpPtT* remainder = spanPtT->next();
caryclark55888e42016-07-18 10:01:36 -0700262 this->ptT()->insert(spanPtT);
caryclark54359292015-03-26 07:52:43 -0700263 while (remainder != spanPtT) {
264 SkOpPtT* next = remainder->next();
265 SkOpPtT* compare = spanPtT->next();
266 while (compare != spanPtT) {
267 SkOpPtT* nextC = compare->next();
268 if (nextC->span() == remainder->span() && nextC->fT == remainder->fT) {
269 goto tryNextRemainder;
270 }
271 compare = nextC;
272 }
273 spanPtT->insert(remainder);
274tryNextRemainder:
275 remainder = next;
276 }
caryclark08bc8482015-04-24 09:08:57 -0700277 fSpanAdds += span->fSpanAdds;
caryclark30b9fdd2016-08-31 14:36:29 -0700278}
279
caryclark55888e42016-07-18 10:01:36 -0700280// please keep in sync with debugCheckForCollapsedCoincidence()
281void SkOpSpanBase::checkForCollapsedCoincidence() {
282 SkOpCoincidence* coins = this->globalState()->coincidence();
283 if (coins->isEmpty()) {
284 return;
285 }
286// the insert above may have put both ends of a coincident run in the same span
287// for each coincident ptT in loop; see if its opposite in is also in the loop
288// this implementation is the motivation for marking that a ptT is referenced by a coincident span
289 SkOpPtT* head = this->ptT();
290 SkOpPtT* test = head;
291 do {
292 if (!test->coincident()) {
293 continue;
294 }
295 coins->markCollapsed(test);
296 } while ((test = test->next()) != head);
caryclark30b9fdd2016-08-31 14:36:29 -0700297 coins->releaseDeleted();
298}
299
300// please keep in sync with debugMergeMatches()
301// Look to see if pt-t linked list contains same segment more than once
302// if so, and if each pt-t is directly pointed to by spans in that segment,
303// merge them
304// keep the points, but remove spans so that the segment doesn't have 2 or more
305// spans pointing to the same pt-t loop at different loop elements
306void SkOpSpanBase::mergeMatches(SkOpSpanBase* opp) {
307 SkOpPtT* test = &fPtT;
308 SkOpPtT* testNext;
309 const SkOpPtT* stop = test;
310 do {
311 testNext = test->next();
312 if (test->deleted()) {
313 continue;
314 }
315 SkOpSpanBase* testBase = test->span();
316 SkASSERT(testBase->ptT() == test);
317 SkOpSegment* segment = test->segment();
318 if (segment->done()) {
319 continue;
320 }
321 SkOpPtT* inner = opp->ptT();
322 const SkOpPtT* innerStop = inner;
323 do {
324 if (inner->segment() != segment) {
325 continue;
326 }
327 if (inner->deleted()) {
328 continue;
329 }
330 SkOpSpanBase* innerBase = inner->span();
331 SkASSERT(innerBase->ptT() == inner);
Ben Wagner63fd7602017-10-09 15:45:33 -0400332 // when the intersection is first detected, the span base is marked if there are
caryclark30b9fdd2016-08-31 14:36:29 -0700333 // more than one point in the intersection.
334 if (!zero_or_one(inner->fT)) {
335 innerBase->upCast()->release(test);
336 } else {
caryclarkb393a492016-09-07 08:21:09 -0700337 SkOPASSERT(inner->fT != test->fT);
caryclark30b9fdd2016-08-31 14:36:29 -0700338 if (!zero_or_one(test->fT)) {
339 testBase->upCast()->release(inner);
340 } else {
341 segment->markAllDone(); // mark segment as collapsed
342 SkDEBUGCODE(testBase->debugSetDeleted());
343 test->setDeleted();
344 SkDEBUGCODE(innerBase->debugSetDeleted());
345 inner->setDeleted();
346 }
347 }
348#ifdef SK_DEBUG // assert if another undeleted entry points to segment
349 const SkOpPtT* debugInner = inner;
350 while ((debugInner = debugInner->next()) != innerStop) {
351 if (debugInner->segment() != segment) {
352 continue;
353 }
354 if (debugInner->deleted()) {
355 continue;
356 }
357 SkOPASSERT(0);
358 }
359#endif
360 break;
361 } while ((inner = inner->next()) != innerStop);
362 } while ((test = testNext) != stop);
363 this->checkForCollapsedCoincidence();
caryclark54359292015-03-26 07:52:43 -0700364}
365
caryclarkbca19f72015-05-13 08:23:48 -0700366int SkOpSpan::computeWindSum() {
367 SkOpGlobalState* globals = this->globalState();
368 SkOpContour* contourHead = globals->contourHead();
369 int windTry = 0;
370 while (!this->sortableTop(contourHead) && ++windTry < SkOpGlobalState::kMaxWindingTries) {
371 ;
372 }
373 return this->windSum();
374}
375
caryclark54359292015-03-26 07:52:43 -0700376bool SkOpSpan::containsCoincidence(const SkOpSegment* segment) const {
377 SkASSERT(this->segment() != segment);
378 const SkOpSpan* next = fCoincident;
379 do {
380 if (next->segment() == segment) {
381 return true;
382 }
383 } while ((next = next->fCoincident) != this);
384 return false;
385}
386
caryclark55888e42016-07-18 10:01:36 -0700387void SkOpSpan::init(SkOpSegment* segment, SkOpSpan* prev, double t, const SkPoint& pt) {
388 SkASSERT(t != 1);
389 initBase(segment, prev, t, pt);
390 fCoincident = this;
391 fToAngle = nullptr;
392 fWindSum = fOppSum = SK_MinS32;
393 fWindValue = 1;
394 fOppValue = 0;
395 fTopTTry = 0;
396 fChased = fDone = false;
397 segment->bumpCount();
398 fAlreadyAdded = false;
399}
400
401// Please keep this in sync with debugInsertCoincidence()
caryclark81a478c2016-09-09 09:37:57 -0700402bool SkOpSpan::insertCoincidence(const SkOpSegment* segment, bool flipped, bool ordered) {
caryclark55888e42016-07-18 10:01:36 -0700403 if (this->containsCoincidence(segment)) {
404 return true;
405 }
406 SkOpPtT* next = &fPtT;
407 while ((next = next->next()) != &fPtT) {
408 if (next->segment() == segment) {
caryclark1493b972016-07-19 11:29:14 -0700409 SkOpSpan* span;
caryclark81a478c2016-09-09 09:37:57 -0700410 SkOpSpanBase* base = next->span();
411 if (!ordered) {
caryclarke6522ea2016-10-17 07:54:33 -0700412 const SkOpPtT* spanEndPtT = fNext->contains(segment);
413 FAIL_IF(!spanEndPtT);
414 const SkOpSpanBase* spanEnd = spanEndPtT->span();
caryclark81a478c2016-09-09 09:37:57 -0700415 const SkOpPtT* start = base->ptT()->starter(spanEnd->ptT());
caryclark45f04b82016-09-21 08:46:56 -0700416 FAIL_IF(!start->span()->upCastable());
caryclark81a478c2016-09-09 09:37:57 -0700417 span = const_cast<SkOpSpan*>(start->span()->upCast());
418 } else if (flipped) {
419 span = base->prev();
420 FAIL_IF(!span);
caryclark1493b972016-07-19 11:29:14 -0700421 } else {
caryclark81a478c2016-09-09 09:37:57 -0700422 FAIL_IF(!base->upCastable());
caryclark1493b972016-07-19 11:29:14 -0700423 span = base->upCast();
caryclark55888e42016-07-18 10:01:36 -0700424 }
425 this->insertCoincidence(span);
426 return true;
427 }
428 }
429#if DEBUG_COINCIDENCE
430 SkASSERT(0); // FIXME? if we get here, the span is missing its opposite segment...
431#endif
432 return true;
433}
434
435void SkOpSpan::release(const SkOpPtT* kept) {
caryclark30b9fdd2016-08-31 14:36:29 -0700436 SkDEBUGCODE(fDebugDeleted = true);
caryclarkb393a492016-09-07 08:21:09 -0700437 SkOPASSERT(kept->span() != this);
caryclark54359292015-03-26 07:52:43 -0700438 SkASSERT(!final());
439 SkOpSpan* prev = this->prev();
440 SkASSERT(prev);
441 SkOpSpanBase* next = this->next();
442 SkASSERT(next);
443 prev->setNext(next);
444 next->setPrev(prev);
mtklein18300a32016-03-16 13:53:35 -0700445 this->segment()->release(this);
caryclark218f21a2015-06-29 11:41:52 -0700446 SkOpCoincidence* coincidence = this->globalState()->coincidence();
447 if (coincidence) {
448 coincidence->fixUp(this->ptT(), kept);
449 }
caryclark54359292015-03-26 07:52:43 -0700450 this->ptT()->setDeleted();
caryclark55888e42016-07-18 10:01:36 -0700451 SkOpPtT* stopPtT = this->ptT();
452 SkOpPtT* testPtT = stopPtT;
453 const SkOpSpanBase* keptSpan = kept->span();
454 do {
455 if (this == testPtT->span()) {
456 testPtT->setSpan(keptSpan);
457 }
458 } while ((testPtT = testPtT->next()) != stopPtT);
caryclark54359292015-03-26 07:52:43 -0700459}
460
461void SkOpSpan::setOppSum(int oppSum) {
462 SkASSERT(!final());
463 if (fOppSum != SK_MinS32 && fOppSum != oppSum) {
464 this->globalState()->setWindingFailed();
465 return;
466 }
bungeman60e0fee2015-08-26 05:15:46 -0700467 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(oppSum) <= DEBUG_LIMIT_WIND_SUM);
caryclark54359292015-03-26 07:52:43 -0700468 fOppSum = oppSum;
469}
caryclark624637c2015-05-11 07:21:27 -0700470
471void SkOpSpan::setWindSum(int windSum) {
472 SkASSERT(!final());
473 if (fWindSum != SK_MinS32 && fWindSum != windSum) {
474 this->globalState()->setWindingFailed();
475 return;
476 }
bungeman60e0fee2015-08-26 05:15:46 -0700477 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(windSum) <= DEBUG_LIMIT_WIND_SUM);
caryclark624637c2015-05-11 07:21:27 -0700478 fWindSum = windSum;
479}