blob: 162bcad2937b74aa5e62b0999a499acf6fbee588 [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 }
27 SkASSERT(0); // should never return deleted
28 return this;
29}
30
caryclarkd4349722015-07-23 12:40:22 -070031bool SkOpPtT::collapsed(const SkOpPtT* check) const {
32 if (fPt != check->fPt) {
33 return false;
34 }
35 SkASSERT(this != check);
36 const SkOpSegment* segment = this->segment();
37 SkASSERT(segment == check->segment());
38 return segment->collapsed();
39}
40
caryclark27c8eb82015-07-06 11:38:33 -070041bool SkOpPtT::contains(const SkOpPtT* check) const {
42 SkASSERT(this != check);
43 const SkOpPtT* ptT = this;
44 const SkOpPtT* stopPtT = ptT;
45 while ((ptT = ptT->next()) != stopPtT) {
46 if (ptT == check) {
47 return true;
48 }
49 }
50 return false;
51}
52
caryclark55888e42016-07-18 10:01:36 -070053bool SkOpPtT::contains(const SkOpSegment* segment, const SkPoint& pt) const {
54 SkASSERT(this->segment() != segment);
55 const SkOpPtT* ptT = this;
caryclark27c8eb82015-07-06 11:38:33 -070056 const SkOpPtT* stopPtT = ptT;
57 while ((ptT = ptT->next()) != stopPtT) {
caryclark55888e42016-07-18 10:01:36 -070058 if (ptT->fPt == pt && ptT->segment() == segment) {
59 return true;
60 }
61 }
62 return false;
63}
64
65bool SkOpPtT::contains(const SkOpSegment* segment, double t) const {
66 const SkOpPtT* ptT = this;
67 const SkOpPtT* stopPtT = ptT;
68 while ((ptT = ptT->next()) != stopPtT) {
69 if (ptT->fT == t && ptT->segment() == segment) {
70 return true;
71 }
72 }
73 return false;
74}
75
76const SkOpPtT* SkOpPtT::contains(const SkOpSegment* check) const {
77 SkASSERT(this->segment() != check);
78 const SkOpPtT* ptT = this;
79 const SkOpPtT* stopPtT = ptT;
80 while ((ptT = ptT->next()) != stopPtT) {
81 if (ptT->segment() == check && !ptT->deleted()) {
caryclark27c8eb82015-07-06 11:38:33 -070082 return ptT;
83 }
84 }
halcanary96fcdcc2015-08-27 07:41:13 -070085 return nullptr;
caryclark27c8eb82015-07-06 11:38:33 -070086}
87
caryclark54359292015-03-26 07:52:43 -070088SkOpContour* SkOpPtT::contour() const {
89 return segment()->contour();
90}
91
caryclark55888e42016-07-18 10:01:36 -070092const SkOpPtT* SkOpPtT::find(const SkOpSegment* segment) const {
93 const SkOpPtT* ptT = this;
caryclark27c8eb82015-07-06 11:38:33 -070094 const SkOpPtT* stopPtT = ptT;
95 do {
caryclark55888e42016-07-18 10:01:36 -070096 if (ptT->segment() == segment && !ptT->deleted()) {
caryclark27c8eb82015-07-06 11:38:33 -070097 return ptT;
98 }
99 ptT = ptT->fNext;
100 } while (stopPtT != ptT);
caryclark55888e42016-07-18 10:01:36 -0700101// SkASSERT(0);
halcanary96fcdcc2015-08-27 07:41:13 -0700102 return nullptr;
caryclark27c8eb82015-07-06 11:38:33 -0700103}
104
caryclark54359292015-03-26 07:52:43 -0700105SkOpGlobalState* SkOpPtT::globalState() const {
caryclark55888e42016-07-18 10:01:36 -0700106 return contour()->globalState();
caryclark54359292015-03-26 07:52:43 -0700107}
108
109void SkOpPtT::init(SkOpSpanBase* span, double t, const SkPoint& pt, bool duplicate) {
110 fT = t;
111 fPt = pt;
112 fSpan = span;
113 fNext = this;
114 fDuplicatePt = duplicate;
115 fDeleted = false;
caryclark55888e42016-07-18 10:01:36 -0700116 fCoincident = false;
caryclark1049f122015-04-20 08:31:59 -0700117 SkDEBUGCODE(fID = span->globalState()->nextPtTID());
caryclark54359292015-03-26 07:52:43 -0700118}
119
120bool SkOpPtT::onEnd() const {
121 const SkOpSpanBase* span = this->span();
122 if (span->ptT() != this) {
123 return false;
124 }
125 const SkOpSegment* segment = this->segment();
126 return span == segment->head() || span == segment->tail();
127}
128
caryclark55888e42016-07-18 10:01:36 -0700129bool SkOpPtT::ptAlreadySeen(const SkOpPtT* check) const {
130 while (this != check) {
131 if (this->fPt == check->fPt) {
132 return true;
133 }
134 check = check->fNext;
135 }
136 return false;
137}
138
caryclark54359292015-03-26 07:52:43 -0700139SkOpPtT* SkOpPtT::prev() {
140 SkOpPtT* result = this;
141 SkOpPtT* next = this;
142 while ((next = next->fNext) != this) {
143 result = next;
144 }
145 SkASSERT(result->fNext == this);
146 return result;
147}
148
caryclark55888e42016-07-18 10:01:36 -0700149SkOpPtT* SkOpPtT::remove(const SkOpPtT* kept) {
caryclark54359292015-03-26 07:52:43 -0700150 SkOpPtT* prev = this;
151 do {
152 SkOpPtT* next = prev->fNext;
153 if (next == this) {
caryclark55888e42016-07-18 10:01:36 -0700154 prev->removeNext(kept);
caryclark54359292015-03-26 07:52:43 -0700155 SkASSERT(prev->fNext != prev);
156 fDeleted = true;
157 return prev;
158 }
159 prev = next;
160 } while (prev != this);
161 SkASSERT(0);
halcanary96fcdcc2015-08-27 07:41:13 -0700162 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700163}
164
caryclark55888e42016-07-18 10:01:36 -0700165void SkOpPtT::removeNext(const SkOpPtT* kept) {
caryclark54359292015-03-26 07:52:43 -0700166 SkASSERT(this->fNext);
167 SkOpPtT* next = this->fNext;
168 SkASSERT(this != next->fNext);
169 this->fNext = next->fNext;
170 SkOpSpanBase* span = next->span();
caryclark55888e42016-07-18 10:01:36 -0700171 SkOpCoincidence* coincidence = span->globalState()->coincidence();
172 if (coincidence) {
173 coincidence->fixUp(next, kept);
174 }
caryclark54359292015-03-26 07:52:43 -0700175 next->setDeleted();
176 if (span->ptT() == next) {
mtklein18300a32016-03-16 13:53:35 -0700177 span->upCast()->release(kept);
caryclark54359292015-03-26 07:52:43 -0700178 }
179}
180
181const SkOpSegment* SkOpPtT::segment() const {
182 return span()->segment();
183}
184
185SkOpSegment* SkOpPtT::segment() {
186 return span()->segment();
187}
188
caryclark55888e42016-07-18 10:01:36 -0700189void SkOpPtT::setDeleted() {
190 SkASSERT(this->span()->debugDeleted() || this->span()->ptT() != this);
caryclark15976282016-07-21 05:48:43 -0700191 SkOPASSERT(!fDeleted);
caryclark55888e42016-07-18 10:01:36 -0700192 fDeleted = true;
193}
194
caryclark30b9fdd2016-08-31 14:36:29 -0700195void SkOpSpanBase::addOpp(SkOpSpanBase* opp) {
caryclark29b25632016-08-25 11:27:17 -0700196 SkOpPtT* oppPrev = this->ptT()->oppPrev(opp->ptT());
caryclark30b9fdd2016-08-31 14:36:29 -0700197 if (!oppPrev) {
caryclark54359292015-03-26 07:52:43 -0700198 return;
199 }
caryclark30b9fdd2016-08-31 14:36:29 -0700200 this->mergeMatches(opp);
201 this->ptT()->addOpp(opp->ptT(), oppPrev);
202 this->checkForCollapsedCoincidence();
caryclark55888e42016-07-18 10:01:36 -0700203}
204
205// Please keep this in sync with debugMergeContained()
206void SkOpSpanBase::mergeContained(const SkPathOpsBounds& bounds) {
207 // while adjacent spans' points are contained by the bounds, merge them
208 SkOpSpanBase* prev = this;
209 SkOpSegment* seg = this->segment();
210 while ((prev = prev->prev()) && bounds.contains(prev->pt()) && !seg->ptsDisjoint(prev, this)) {
caryclark30b9fdd2016-08-31 14:36:29 -0700211 this->mergeMatches(prev);
212 this->addOpp(prev);
caryclark55888e42016-07-18 10:01:36 -0700213 }
caryclark55888e42016-07-18 10:01:36 -0700214 SkOpSpanBase* next = this;
215 while (next->upCastable() && (next = next->upCast()->next())
216 && bounds.contains(next->pt()) && !seg->ptsDisjoint(this, next)) {
caryclark30b9fdd2016-08-31 14:36:29 -0700217 this->mergeMatches(next);
218 this->addOpp(next);
caryclark54359292015-03-26 07:52:43 -0700219 }
caryclark55888e42016-07-18 10:01:36 -0700220#if DEBUG_COINCIDENCE
221 this->globalState()->coincidence()->debugValidate();
222#endif
caryclark54359292015-03-26 07:52:43 -0700223}
224
caryclark30b9fdd2016-08-31 14:36:29 -0700225bool SkOpSpanBase::collapsed(double s, double e) const {
226 const SkOpPtT* start = &fPtT;
227 const SkOpPtT* walk = start;
228 double min = walk->fT;
229 double max = min;
230 const SkOpSegment* segment = this->segment();
231 while ((walk = walk->next()) != start) {
232 if (walk->segment() != segment) {
233 continue;
234 }
235 min = SkTMin(min, walk->fT);
236 max = SkTMax(max, walk->fT);
237 if (between(min, s, max) && between(min, e, max)) {
238 return true;
239 }
240 }
241 return false;
242}
243
caryclark54359292015-03-26 07:52:43 -0700244bool SkOpSpanBase::contains(const SkOpSpanBase* span) const {
245 const SkOpPtT* start = &fPtT;
246 const SkOpPtT* check = &span->fPtT;
caryclarkef4f32a2016-08-24 09:24:18 -0700247 SkOPASSERT(start != check);
caryclark54359292015-03-26 07:52:43 -0700248 const SkOpPtT* walk = start;
249 while ((walk = walk->next()) != start) {
250 if (walk == check) {
251 return true;
252 }
253 }
254 return false;
255}
256
caryclark55888e42016-07-18 10:01:36 -0700257const SkOpPtT* SkOpSpanBase::contains(const SkOpSegment* segment) const {
258 const SkOpPtT* start = &fPtT;
259 const SkOpPtT* walk = start;
caryclark54359292015-03-26 07:52:43 -0700260 while ((walk = walk->next()) != start) {
caryclark55888e42016-07-18 10:01:36 -0700261 if (walk->deleted()) {
262 continue;
263 }
264 if (walk->segment() == segment && walk->span()->ptT() == walk) {
caryclark54359292015-03-26 07:52:43 -0700265 return walk;
266 }
267 }
halcanary96fcdcc2015-08-27 07:41:13 -0700268 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700269}
270
271bool SkOpSpanBase::containsCoinEnd(const SkOpSegment* segment) const {
272 SkASSERT(this->segment() != segment);
273 const SkOpSpanBase* next = this;
274 while ((next = next->fCoinEnd) != this) {
275 if (next->segment() == segment) {
276 return true;
277 }
278 }
279 return false;
280}
281
282SkOpContour* SkOpSpanBase::contour() const {
283 return segment()->contour();
284}
285
286SkOpGlobalState* SkOpSpanBase::globalState() const {
caryclark55888e42016-07-18 10:01:36 -0700287 return contour()->globalState();
caryclark54359292015-03-26 07:52:43 -0700288}
289
290void SkOpSpanBase::initBase(SkOpSegment* segment, SkOpSpan* prev, double t, const SkPoint& pt) {
291 fSegment = segment;
292 fPtT.init(this, t, pt, false);
293 fCoinEnd = this;
halcanary96fcdcc2015-08-27 07:41:13 -0700294 fFromAngle = nullptr;
caryclark54359292015-03-26 07:52:43 -0700295 fPrev = prev;
caryclark08bc8482015-04-24 09:08:57 -0700296 fSpanAdds = 0;
caryclark54359292015-03-26 07:52:43 -0700297 fAligned = true;
298 fChased = false;
caryclark1049f122015-04-20 08:31:59 -0700299 SkDEBUGCODE(fCount = 1);
300 SkDEBUGCODE(fID = globalState()->nextSpanID());
caryclark30b9fdd2016-08-31 14:36:29 -0700301 SkDEBUGCODE(fDebugDeleted = false);
caryclark54359292015-03-26 07:52:43 -0700302}
303
304// this pair of spans share a common t value or point; merge them and eliminate duplicates
305// this does not compute the best t or pt value; this merely moves all data into a single list
306void SkOpSpanBase::merge(SkOpSpan* span) {
307 SkOpPtT* spanPtT = span->ptT();
308 SkASSERT(this->t() != spanPtT->fT);
309 SkASSERT(!zero_or_one(spanPtT->fT));
mtklein18300a32016-03-16 13:53:35 -0700310 span->release(this->ptT());
caryclark55888e42016-07-18 10:01:36 -0700311 if (this->contains(span)) {
caryclark30b9fdd2016-08-31 14:36:29 -0700312 SkOPASSERT(0); // check to see if this ever happens -- should have been found earlier
caryclark55888e42016-07-18 10:01:36 -0700313 return; // merge is already in the ptT loop
314 }
caryclark54359292015-03-26 07:52:43 -0700315 SkOpPtT* remainder = spanPtT->next();
caryclark55888e42016-07-18 10:01:36 -0700316 this->ptT()->insert(spanPtT);
caryclark54359292015-03-26 07:52:43 -0700317 while (remainder != spanPtT) {
318 SkOpPtT* next = remainder->next();
319 SkOpPtT* compare = spanPtT->next();
320 while (compare != spanPtT) {
321 SkOpPtT* nextC = compare->next();
322 if (nextC->span() == remainder->span() && nextC->fT == remainder->fT) {
323 goto tryNextRemainder;
324 }
325 compare = nextC;
326 }
327 spanPtT->insert(remainder);
328tryNextRemainder:
329 remainder = next;
330 }
caryclark08bc8482015-04-24 09:08:57 -0700331 fSpanAdds += span->fSpanAdds;
caryclark30b9fdd2016-08-31 14:36:29 -0700332}
333
334SkOpSpanBase* SkOpSpanBase::active() {
335 SkOpSpanBase* result = fPrev ? fPrev->next() : upCast()->next()->prev();
336 SkASSERT(this == result || fDebugDeleted);
337 return result;
caryclark55888e42016-07-18 10:01:36 -0700338}
339
340// please keep in sync with debugCheckForCollapsedCoincidence()
341void SkOpSpanBase::checkForCollapsedCoincidence() {
342 SkOpCoincidence* coins = this->globalState()->coincidence();
343 if (coins->isEmpty()) {
344 return;
345 }
346// the insert above may have put both ends of a coincident run in the same span
347// for each coincident ptT in loop; see if its opposite in is also in the loop
348// this implementation is the motivation for marking that a ptT is referenced by a coincident span
349 SkOpPtT* head = this->ptT();
350 SkOpPtT* test = head;
351 do {
352 if (!test->coincident()) {
353 continue;
354 }
355 coins->markCollapsed(test);
356 } while ((test = test->next()) != head);
caryclark30b9fdd2016-08-31 14:36:29 -0700357 coins->releaseDeleted();
358}
359
360// please keep in sync with debugMergeMatches()
361// Look to see if pt-t linked list contains same segment more than once
362// if so, and if each pt-t is directly pointed to by spans in that segment,
363// merge them
364// keep the points, but remove spans so that the segment doesn't have 2 or more
365// spans pointing to the same pt-t loop at different loop elements
366void SkOpSpanBase::mergeMatches(SkOpSpanBase* opp) {
367 SkOpPtT* test = &fPtT;
368 SkOpPtT* testNext;
369 const SkOpPtT* stop = test;
370 do {
371 testNext = test->next();
372 if (test->deleted()) {
373 continue;
374 }
375 SkOpSpanBase* testBase = test->span();
376 SkASSERT(testBase->ptT() == test);
377 SkOpSegment* segment = test->segment();
378 if (segment->done()) {
379 continue;
380 }
381 SkOpPtT* inner = opp->ptT();
382 const SkOpPtT* innerStop = inner;
383 do {
384 if (inner->segment() != segment) {
385 continue;
386 }
387 if (inner->deleted()) {
388 continue;
389 }
390 SkOpSpanBase* innerBase = inner->span();
391 SkASSERT(innerBase->ptT() == inner);
392 // when the intersection is first detected, the span base is marked if there are
393 // more than one point in the intersection.
394 if (!zero_or_one(inner->fT)) {
395 innerBase->upCast()->release(test);
396 } else {
397 SkASSERT(inner->fT != test->fT);
398 if (!zero_or_one(test->fT)) {
399 testBase->upCast()->release(inner);
400 } else {
401 segment->markAllDone(); // mark segment as collapsed
402 SkDEBUGCODE(testBase->debugSetDeleted());
403 test->setDeleted();
404 SkDEBUGCODE(innerBase->debugSetDeleted());
405 inner->setDeleted();
406 }
407 }
408#ifdef SK_DEBUG // assert if another undeleted entry points to segment
409 const SkOpPtT* debugInner = inner;
410 while ((debugInner = debugInner->next()) != innerStop) {
411 if (debugInner->segment() != segment) {
412 continue;
413 }
414 if (debugInner->deleted()) {
415 continue;
416 }
417 SkOPASSERT(0);
418 }
419#endif
420 break;
421 } while ((inner = inner->next()) != innerStop);
422 } while ((test = testNext) != stop);
423 this->checkForCollapsedCoincidence();
caryclark54359292015-03-26 07:52:43 -0700424}
425
caryclarkbca19f72015-05-13 08:23:48 -0700426int SkOpSpan::computeWindSum() {
427 SkOpGlobalState* globals = this->globalState();
428 SkOpContour* contourHead = globals->contourHead();
429 int windTry = 0;
430 while (!this->sortableTop(contourHead) && ++windTry < SkOpGlobalState::kMaxWindingTries) {
431 ;
432 }
433 return this->windSum();
434}
435
caryclark54359292015-03-26 07:52:43 -0700436bool SkOpSpan::containsCoincidence(const SkOpSegment* segment) const {
437 SkASSERT(this->segment() != segment);
438 const SkOpSpan* next = fCoincident;
439 do {
440 if (next->segment() == segment) {
441 return true;
442 }
443 } while ((next = next->fCoincident) != this);
444 return false;
445}
446
caryclark55888e42016-07-18 10:01:36 -0700447void SkOpSpan::init(SkOpSegment* segment, SkOpSpan* prev, double t, const SkPoint& pt) {
448 SkASSERT(t != 1);
449 initBase(segment, prev, t, pt);
450 fCoincident = this;
451 fToAngle = nullptr;
452 fWindSum = fOppSum = SK_MinS32;
453 fWindValue = 1;
454 fOppValue = 0;
455 fTopTTry = 0;
456 fChased = fDone = false;
457 segment->bumpCount();
458 fAlreadyAdded = false;
459}
460
461// Please keep this in sync with debugInsertCoincidence()
462bool SkOpSpan::insertCoincidence(const SkOpSegment* segment, bool flipped) {
463 if (this->containsCoincidence(segment)) {
464 return true;
465 }
466 SkOpPtT* next = &fPtT;
467 while ((next = next->next()) != &fPtT) {
468 if (next->segment() == segment) {
caryclark1493b972016-07-19 11:29:14 -0700469 SkOpSpan* span;
470 if (flipped) {
471 span = next->span()->prev();
472 if (!span) {
473 return false;
474 }
475 } else {
476 SkOpSpanBase* base = next->span();
477 if (!base->upCastable()) {
478 return false;
479 }
480 span = base->upCast();
caryclark55888e42016-07-18 10:01:36 -0700481 }
482 this->insertCoincidence(span);
483 return true;
484 }
485 }
486#if DEBUG_COINCIDENCE
487 SkASSERT(0); // FIXME? if we get here, the span is missing its opposite segment...
488#endif
489 return true;
490}
491
492void SkOpSpan::release(const SkOpPtT* kept) {
caryclark30b9fdd2016-08-31 14:36:29 -0700493 SkDEBUGCODE(fDebugDeleted = true);
caryclark55888e42016-07-18 10:01:36 -0700494 SkASSERT(kept->span() != this);
caryclark54359292015-03-26 07:52:43 -0700495 SkASSERT(!final());
496 SkOpSpan* prev = this->prev();
497 SkASSERT(prev);
498 SkOpSpanBase* next = this->next();
499 SkASSERT(next);
500 prev->setNext(next);
501 next->setPrev(prev);
mtklein18300a32016-03-16 13:53:35 -0700502 this->segment()->release(this);
caryclark218f21a2015-06-29 11:41:52 -0700503 SkOpCoincidence* coincidence = this->globalState()->coincidence();
504 if (coincidence) {
505 coincidence->fixUp(this->ptT(), kept);
506 }
caryclark54359292015-03-26 07:52:43 -0700507 this->ptT()->setDeleted();
caryclark55888e42016-07-18 10:01:36 -0700508 SkOpPtT* stopPtT = this->ptT();
509 SkOpPtT* testPtT = stopPtT;
510 const SkOpSpanBase* keptSpan = kept->span();
511 do {
512 if (this == testPtT->span()) {
513 testPtT->setSpan(keptSpan);
514 }
515 } while ((testPtT = testPtT->next()) != stopPtT);
caryclark54359292015-03-26 07:52:43 -0700516}
517
518void SkOpSpan::setOppSum(int oppSum) {
519 SkASSERT(!final());
520 if (fOppSum != SK_MinS32 && fOppSum != oppSum) {
521 this->globalState()->setWindingFailed();
522 return;
523 }
bungeman60e0fee2015-08-26 05:15:46 -0700524 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(oppSum) <= DEBUG_LIMIT_WIND_SUM);
caryclark54359292015-03-26 07:52:43 -0700525 fOppSum = oppSum;
526}
caryclark624637c2015-05-11 07:21:27 -0700527
528void SkOpSpan::setWindSum(int windSum) {
529 SkASSERT(!final());
530 if (fWindSum != SK_MinS32 && fWindSum != windSum) {
531 this->globalState()->setWindingFailed();
532 return;
533 }
bungeman60e0fee2015-08-26 05:15:46 -0700534 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(windSum) <= DEBUG_LIMIT_WIND_SUM);
caryclark624637c2015-05-11 07:21:27 -0700535 fWindSum = windSum;
536}