blob: 640ba8feb74a0c41dfc5b957edb14295b5b2de30 [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
caryclarkd4349722015-07-23 12:40:22 -070016bool SkOpPtT::collapsed(const SkOpPtT* check) const {
17 if (fPt != check->fPt) {
18 return false;
19 }
20 SkASSERT(this != check);
21 const SkOpSegment* segment = this->segment();
22 SkASSERT(segment == check->segment());
23 return segment->collapsed();
24}
25
caryclark27c8eb82015-07-06 11:38:33 -070026bool SkOpPtT::contains(const SkOpPtT* check) const {
27 SkASSERT(this != check);
28 const SkOpPtT* ptT = this;
29 const SkOpPtT* stopPtT = ptT;
30 while ((ptT = ptT->next()) != stopPtT) {
31 if (ptT == check) {
32 return true;
33 }
34 }
35 return false;
36}
37
caryclark55888e42016-07-18 10:01:36 -070038bool SkOpPtT::contains(const SkOpSegment* segment, const SkPoint& pt) const {
39 SkASSERT(this->segment() != segment);
40 const SkOpPtT* ptT = this;
caryclark27c8eb82015-07-06 11:38:33 -070041 const SkOpPtT* stopPtT = ptT;
42 while ((ptT = ptT->next()) != stopPtT) {
caryclark55888e42016-07-18 10:01:36 -070043 if (ptT->fPt == pt && ptT->segment() == segment) {
44 return true;
45 }
46 }
47 return false;
48}
49
50bool SkOpPtT::contains(const SkOpSegment* segment, double t) const {
51 const SkOpPtT* ptT = this;
52 const SkOpPtT* stopPtT = ptT;
53 while ((ptT = ptT->next()) != stopPtT) {
54 if (ptT->fT == t && ptT->segment() == segment) {
55 return true;
56 }
57 }
58 return false;
59}
60
61const SkOpPtT* SkOpPtT::contains(const SkOpSegment* check) const {
62 SkASSERT(this->segment() != check);
63 const SkOpPtT* ptT = this;
64 const SkOpPtT* stopPtT = ptT;
65 while ((ptT = ptT->next()) != stopPtT) {
66 if (ptT->segment() == check && !ptT->deleted()) {
caryclark27c8eb82015-07-06 11:38:33 -070067 return ptT;
68 }
69 }
halcanary96fcdcc2015-08-27 07:41:13 -070070 return nullptr;
caryclark27c8eb82015-07-06 11:38:33 -070071}
72
caryclark54359292015-03-26 07:52:43 -070073SkOpContour* SkOpPtT::contour() const {
74 return segment()->contour();
75}
76
caryclark55888e42016-07-18 10:01:36 -070077const SkOpPtT* SkOpPtT::find(const SkOpSegment* segment) const {
78 const SkOpPtT* ptT = this;
caryclark27c8eb82015-07-06 11:38:33 -070079 const SkOpPtT* stopPtT = ptT;
80 do {
caryclark55888e42016-07-18 10:01:36 -070081 if (ptT->segment() == segment && !ptT->deleted()) {
caryclark27c8eb82015-07-06 11:38:33 -070082 return ptT;
83 }
84 ptT = ptT->fNext;
85 } while (stopPtT != ptT);
caryclark55888e42016-07-18 10:01:36 -070086// SkASSERT(0);
halcanary96fcdcc2015-08-27 07:41:13 -070087 return nullptr;
caryclark27c8eb82015-07-06 11:38:33 -070088}
89
caryclark54359292015-03-26 07:52:43 -070090SkOpGlobalState* SkOpPtT::globalState() const {
caryclark55888e42016-07-18 10:01:36 -070091 return contour()->globalState();
caryclark54359292015-03-26 07:52:43 -070092}
93
94void SkOpPtT::init(SkOpSpanBase* span, double t, const SkPoint& pt, bool duplicate) {
95 fT = t;
96 fPt = pt;
97 fSpan = span;
98 fNext = this;
99 fDuplicatePt = duplicate;
100 fDeleted = false;
caryclark55888e42016-07-18 10:01:36 -0700101 fCoincident = false;
caryclark1049f122015-04-20 08:31:59 -0700102 SkDEBUGCODE(fID = span->globalState()->nextPtTID());
caryclark54359292015-03-26 07:52:43 -0700103}
104
105bool SkOpPtT::onEnd() const {
106 const SkOpSpanBase* span = this->span();
107 if (span->ptT() != this) {
108 return false;
109 }
110 const SkOpSegment* segment = this->segment();
111 return span == segment->head() || span == segment->tail();
112}
113
caryclark55888e42016-07-18 10:01:36 -0700114bool SkOpPtT::ptAlreadySeen(const SkOpPtT* check) const {
115 while (this != check) {
116 if (this->fPt == check->fPt) {
117 return true;
118 }
119 check = check->fNext;
120 }
121 return false;
122}
123
caryclark54359292015-03-26 07:52:43 -0700124SkOpPtT* SkOpPtT::prev() {
125 SkOpPtT* result = this;
126 SkOpPtT* next = this;
127 while ((next = next->fNext) != this) {
128 result = next;
129 }
130 SkASSERT(result->fNext == this);
131 return result;
132}
133
caryclark55888e42016-07-18 10:01:36 -0700134SkOpPtT* SkOpPtT::remove(const SkOpPtT* kept) {
caryclark54359292015-03-26 07:52:43 -0700135 SkOpPtT* prev = this;
136 do {
137 SkOpPtT* next = prev->fNext;
138 if (next == this) {
caryclark55888e42016-07-18 10:01:36 -0700139 prev->removeNext(kept);
caryclark54359292015-03-26 07:52:43 -0700140 SkASSERT(prev->fNext != prev);
141 fDeleted = true;
142 return prev;
143 }
144 prev = next;
145 } while (prev != this);
146 SkASSERT(0);
halcanary96fcdcc2015-08-27 07:41:13 -0700147 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700148}
149
caryclark55888e42016-07-18 10:01:36 -0700150void SkOpPtT::removeNext(const SkOpPtT* kept) {
caryclark54359292015-03-26 07:52:43 -0700151 SkASSERT(this->fNext);
152 SkOpPtT* next = this->fNext;
153 SkASSERT(this != next->fNext);
154 this->fNext = next->fNext;
155 SkOpSpanBase* span = next->span();
caryclark55888e42016-07-18 10:01:36 -0700156 SkOpCoincidence* coincidence = span->globalState()->coincidence();
157 if (coincidence) {
158 coincidence->fixUp(next, kept);
159 }
caryclark54359292015-03-26 07:52:43 -0700160 next->setDeleted();
161 if (span->ptT() == next) {
mtklein18300a32016-03-16 13:53:35 -0700162 span->upCast()->release(kept);
caryclark54359292015-03-26 07:52:43 -0700163 }
164}
165
166const SkOpSegment* SkOpPtT::segment() const {
167 return span()->segment();
168}
169
170SkOpSegment* SkOpPtT::segment() {
171 return span()->segment();
172}
173
caryclark55888e42016-07-18 10:01:36 -0700174void SkOpPtT::setDeleted() {
175 SkASSERT(this->span()->debugDeleted() || this->span()->ptT() != this);
caryclark15976282016-07-21 05:48:43 -0700176 SkOPASSERT(!fDeleted);
caryclark55888e42016-07-18 10:01:36 -0700177 fDeleted = true;
178}
179
180// please keep this in sync with debugAddOppAndMerge
181// If the added points envelop adjacent spans, merge them in.
182void SkOpSpanBase::addOppAndMerge(SkOpSpanBase* opp) {
183 if (this->ptT()->addOpp(opp->ptT())) {
184 this->checkForCollapsedCoincidence();
185 }
186 // compute bounds of points in span
187 SkPathOpsBounds bounds;
188 bounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMin, SK_ScalarMin);
189 const SkOpPtT* head = this->ptT();
190 const SkOpPtT* nextPt = head;
191 do {
192 bounds.add(nextPt->fPt);
193 } while ((nextPt = nextPt->next()) != head);
194 if (!bounds.width() && !bounds.height()) {
caryclark54359292015-03-26 07:52:43 -0700195 return;
196 }
caryclark55888e42016-07-18 10:01:36 -0700197 this->mergeContained(bounds);
198 opp->mergeContained(bounds);
199}
200
201// Please keep this in sync with debugMergeContained()
202void SkOpSpanBase::mergeContained(const SkPathOpsBounds& bounds) {
203 // while adjacent spans' points are contained by the bounds, merge them
204 SkOpSpanBase* prev = this;
205 SkOpSegment* seg = this->segment();
206 while ((prev = prev->prev()) && bounds.contains(prev->pt()) && !seg->ptsDisjoint(prev, this)) {
207 if (prev->prev()) {
208 this->merge(prev->upCast());
209 prev = this;
210 } else if (this->final()) {
211 seg->clearAll();
212 return;
213 } else {
214 prev->merge(this->upCast());
215 }
216 }
217 SkOpSpanBase* current = this;
218 SkOpSpanBase* next = this;
219 while (next->upCastable() && (next = next->upCast()->next())
220 && bounds.contains(next->pt()) && !seg->ptsDisjoint(this, next)) {
221 if (!current->prev() && next->final()) {
222 seg->clearAll();
caryclark54359292015-03-26 07:52:43 -0700223 return;
224 }
caryclark55888e42016-07-18 10:01:36 -0700225 if (current->prev()) {
226 next->merge(current->upCast());
227 current = next;
228 } else {
229 current->merge(next->upCast());
230 // extra line in debug version
caryclark54359292015-03-26 07:52:43 -0700231 }
caryclark54359292015-03-26 07:52:43 -0700232 }
caryclark55888e42016-07-18 10:01:36 -0700233#if DEBUG_COINCIDENCE
234 this->globalState()->coincidence()->debugValidate();
235#endif
caryclark54359292015-03-26 07:52:43 -0700236}
237
238bool SkOpSpanBase::contains(const SkOpSpanBase* span) const {
239 const SkOpPtT* start = &fPtT;
240 const SkOpPtT* check = &span->fPtT;
caryclarkef4f32a2016-08-24 09:24:18 -0700241 SkOPASSERT(start != check);
caryclark54359292015-03-26 07:52:43 -0700242 const SkOpPtT* walk = start;
243 while ((walk = walk->next()) != start) {
244 if (walk == check) {
245 return true;
246 }
247 }
248 return false;
249}
250
caryclark55888e42016-07-18 10:01:36 -0700251const SkOpPtT* SkOpSpanBase::contains(const SkOpSegment* segment) const {
252 const SkOpPtT* start = &fPtT;
253 const SkOpPtT* walk = start;
caryclark54359292015-03-26 07:52:43 -0700254 while ((walk = walk->next()) != start) {
caryclark55888e42016-07-18 10:01:36 -0700255 if (walk->deleted()) {
256 continue;
257 }
258 if (walk->segment() == segment && walk->span()->ptT() == walk) {
caryclark54359292015-03-26 07:52:43 -0700259 return walk;
260 }
261 }
halcanary96fcdcc2015-08-27 07:41:13 -0700262 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700263}
264
265bool SkOpSpanBase::containsCoinEnd(const SkOpSegment* segment) const {
266 SkASSERT(this->segment() != segment);
267 const SkOpSpanBase* next = this;
268 while ((next = next->fCoinEnd) != this) {
269 if (next->segment() == segment) {
270 return true;
271 }
272 }
273 return false;
274}
275
276SkOpContour* SkOpSpanBase::contour() const {
277 return segment()->contour();
278}
279
280SkOpGlobalState* SkOpSpanBase::globalState() const {
caryclark55888e42016-07-18 10:01:36 -0700281 return contour()->globalState();
caryclark54359292015-03-26 07:52:43 -0700282}
283
284void SkOpSpanBase::initBase(SkOpSegment* segment, SkOpSpan* prev, double t, const SkPoint& pt) {
285 fSegment = segment;
286 fPtT.init(this, t, pt, false);
287 fCoinEnd = this;
halcanary96fcdcc2015-08-27 07:41:13 -0700288 fFromAngle = nullptr;
caryclark54359292015-03-26 07:52:43 -0700289 fPrev = prev;
caryclark08bc8482015-04-24 09:08:57 -0700290 fSpanAdds = 0;
caryclark54359292015-03-26 07:52:43 -0700291 fAligned = true;
292 fChased = false;
caryclark1049f122015-04-20 08:31:59 -0700293 SkDEBUGCODE(fCount = 1);
294 SkDEBUGCODE(fID = globalState()->nextSpanID());
caryclark55888e42016-07-18 10:01:36 -0700295 SkDEBUGCODE(fDeleted = false);
caryclark54359292015-03-26 07:52:43 -0700296}
297
298// this pair of spans share a common t value or point; merge them and eliminate duplicates
299// this does not compute the best t or pt value; this merely moves all data into a single list
300void SkOpSpanBase::merge(SkOpSpan* span) {
301 SkOpPtT* spanPtT = span->ptT();
302 SkASSERT(this->t() != spanPtT->fT);
303 SkASSERT(!zero_or_one(spanPtT->fT));
mtklein18300a32016-03-16 13:53:35 -0700304 span->release(this->ptT());
caryclark55888e42016-07-18 10:01:36 -0700305 if (this->contains(span)) {
306 return; // merge is already in the ptT loop
307 }
caryclark54359292015-03-26 07:52:43 -0700308 SkOpPtT* remainder = spanPtT->next();
caryclark55888e42016-07-18 10:01:36 -0700309 this->ptT()->insert(spanPtT);
caryclark54359292015-03-26 07:52:43 -0700310 while (remainder != spanPtT) {
311 SkOpPtT* next = remainder->next();
312 SkOpPtT* compare = spanPtT->next();
313 while (compare != spanPtT) {
314 SkOpPtT* nextC = compare->next();
315 if (nextC->span() == remainder->span() && nextC->fT == remainder->fT) {
316 goto tryNextRemainder;
317 }
318 compare = nextC;
319 }
320 spanPtT->insert(remainder);
321tryNextRemainder:
322 remainder = next;
323 }
caryclark08bc8482015-04-24 09:08:57 -0700324 fSpanAdds += span->fSpanAdds;
caryclark55888e42016-07-18 10:01:36 -0700325 this->checkForCollapsedCoincidence();
326}
327
328// please keep in sync with debugCheckForCollapsedCoincidence()
329void SkOpSpanBase::checkForCollapsedCoincidence() {
330 SkOpCoincidence* coins = this->globalState()->coincidence();
331 if (coins->isEmpty()) {
332 return;
333 }
334// the insert above may have put both ends of a coincident run in the same span
335// for each coincident ptT in loop; see if its opposite in is also in the loop
336// this implementation is the motivation for marking that a ptT is referenced by a coincident span
337 SkOpPtT* head = this->ptT();
338 SkOpPtT* test = head;
339 do {
340 if (!test->coincident()) {
341 continue;
342 }
343 coins->markCollapsed(test);
344 } while ((test = test->next()) != head);
caryclark54359292015-03-26 07:52:43 -0700345}
346
caryclarkbca19f72015-05-13 08:23:48 -0700347int SkOpSpan::computeWindSum() {
348 SkOpGlobalState* globals = this->globalState();
349 SkOpContour* contourHead = globals->contourHead();
350 int windTry = 0;
351 while (!this->sortableTop(contourHead) && ++windTry < SkOpGlobalState::kMaxWindingTries) {
352 ;
353 }
354 return this->windSum();
355}
356
caryclark54359292015-03-26 07:52:43 -0700357bool SkOpSpan::containsCoincidence(const SkOpSegment* segment) const {
358 SkASSERT(this->segment() != segment);
359 const SkOpSpan* next = fCoincident;
360 do {
361 if (next->segment() == segment) {
362 return true;
363 }
364 } while ((next = next->fCoincident) != this);
365 return false;
366}
367
caryclark55888e42016-07-18 10:01:36 -0700368void SkOpSpan::init(SkOpSegment* segment, SkOpSpan* prev, double t, const SkPoint& pt) {
369 SkASSERT(t != 1);
370 initBase(segment, prev, t, pt);
371 fCoincident = this;
372 fToAngle = nullptr;
373 fWindSum = fOppSum = SK_MinS32;
374 fWindValue = 1;
375 fOppValue = 0;
376 fTopTTry = 0;
377 fChased = fDone = false;
378 segment->bumpCount();
379 fAlreadyAdded = false;
380}
381
382// Please keep this in sync with debugInsertCoincidence()
383bool SkOpSpan::insertCoincidence(const SkOpSegment* segment, bool flipped) {
384 if (this->containsCoincidence(segment)) {
385 return true;
386 }
387 SkOpPtT* next = &fPtT;
388 while ((next = next->next()) != &fPtT) {
389 if (next->segment() == segment) {
caryclark1493b972016-07-19 11:29:14 -0700390 SkOpSpan* span;
391 if (flipped) {
392 span = next->span()->prev();
393 if (!span) {
394 return false;
395 }
396 } else {
397 SkOpSpanBase* base = next->span();
398 if (!base->upCastable()) {
399 return false;
400 }
401 span = base->upCast();
caryclark55888e42016-07-18 10:01:36 -0700402 }
403 this->insertCoincidence(span);
404 return true;
405 }
406 }
407#if DEBUG_COINCIDENCE
408 SkASSERT(0); // FIXME? if we get here, the span is missing its opposite segment...
409#endif
410 return true;
411}
412
413void SkOpSpan::release(const SkOpPtT* kept) {
414 SkDEBUGCODE(fDeleted = true);
415 SkASSERT(kept->span() != this);
caryclark54359292015-03-26 07:52:43 -0700416 SkASSERT(!final());
417 SkOpSpan* prev = this->prev();
418 SkASSERT(prev);
419 SkOpSpanBase* next = this->next();
420 SkASSERT(next);
421 prev->setNext(next);
422 next->setPrev(prev);
mtklein18300a32016-03-16 13:53:35 -0700423 this->segment()->release(this);
caryclark218f21a2015-06-29 11:41:52 -0700424 SkOpCoincidence* coincidence = this->globalState()->coincidence();
425 if (coincidence) {
426 coincidence->fixUp(this->ptT(), kept);
427 }
caryclark54359292015-03-26 07:52:43 -0700428 this->ptT()->setDeleted();
caryclark55888e42016-07-18 10:01:36 -0700429 SkOpPtT* stopPtT = this->ptT();
430 SkOpPtT* testPtT = stopPtT;
431 const SkOpSpanBase* keptSpan = kept->span();
432 do {
433 if (this == testPtT->span()) {
434 testPtT->setSpan(keptSpan);
435 }
436 } while ((testPtT = testPtT->next()) != stopPtT);
caryclark54359292015-03-26 07:52:43 -0700437}
438
439void SkOpSpan::setOppSum(int oppSum) {
440 SkASSERT(!final());
441 if (fOppSum != SK_MinS32 && fOppSum != oppSum) {
442 this->globalState()->setWindingFailed();
443 return;
444 }
bungeman60e0fee2015-08-26 05:15:46 -0700445 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(oppSum) <= DEBUG_LIMIT_WIND_SUM);
caryclark54359292015-03-26 07:52:43 -0700446 fOppSum = oppSum;
447}
caryclark624637c2015-05-11 07:21:27 -0700448
449void SkOpSpan::setWindSum(int windSum) {
450 SkASSERT(!final());
451 if (fWindSum != SK_MinS32 && fWindSum != windSum) {
452 this->globalState()->setWindingFailed();
453 return;
454 }
bungeman60e0fee2015-08-26 05:15:46 -0700455 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(windSum) <= DEBUG_LIMIT_WIND_SUM);
caryclark624637c2015-05-11 07:21:27 -0700456 fWindSum = windSum;
457}