blob: 98165fcfc53c08458d942dfddff78c9a58e468d2 [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) {
caryclark29b25632016-08-25 11:27:17 -0700183 SkOpPtT* oppPrev = this->ptT()->oppPrev(opp->ptT());
184 if (oppPrev) {
185 this->ptT()->addOpp(opp->ptT(), oppPrev);
caryclark55888e42016-07-18 10:01:36 -0700186 this->checkForCollapsedCoincidence();
187 }
188 // compute bounds of points in span
189 SkPathOpsBounds bounds;
190 bounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMin, SK_ScalarMin);
191 const SkOpPtT* head = this->ptT();
192 const SkOpPtT* nextPt = head;
193 do {
194 bounds.add(nextPt->fPt);
195 } while ((nextPt = nextPt->next()) != head);
196 if (!bounds.width() && !bounds.height()) {
caryclark54359292015-03-26 07:52:43 -0700197 return;
198 }
caryclark55888e42016-07-18 10:01:36 -0700199 this->mergeContained(bounds);
200 opp->mergeContained(bounds);
201}
202
203// Please keep this in sync with debugMergeContained()
204void SkOpSpanBase::mergeContained(const SkPathOpsBounds& bounds) {
205 // while adjacent spans' points are contained by the bounds, merge them
206 SkOpSpanBase* prev = this;
207 SkOpSegment* seg = this->segment();
208 while ((prev = prev->prev()) && bounds.contains(prev->pt()) && !seg->ptsDisjoint(prev, this)) {
209 if (prev->prev()) {
210 this->merge(prev->upCast());
211 prev = this;
212 } else if (this->final()) {
213 seg->clearAll();
214 return;
215 } else {
216 prev->merge(this->upCast());
217 }
218 }
219 SkOpSpanBase* current = this;
220 SkOpSpanBase* next = this;
221 while (next->upCastable() && (next = next->upCast()->next())
222 && bounds.contains(next->pt()) && !seg->ptsDisjoint(this, next)) {
223 if (!current->prev() && next->final()) {
224 seg->clearAll();
caryclark54359292015-03-26 07:52:43 -0700225 return;
226 }
caryclark55888e42016-07-18 10:01:36 -0700227 if (current->prev()) {
228 next->merge(current->upCast());
229 current = next;
230 } else {
231 current->merge(next->upCast());
232 // extra line in debug version
caryclark54359292015-03-26 07:52:43 -0700233 }
caryclark54359292015-03-26 07:52:43 -0700234 }
caryclark55888e42016-07-18 10:01:36 -0700235#if DEBUG_COINCIDENCE
236 this->globalState()->coincidence()->debugValidate();
237#endif
caryclark54359292015-03-26 07:52:43 -0700238}
239
240bool SkOpSpanBase::contains(const SkOpSpanBase* span) const {
241 const SkOpPtT* start = &fPtT;
242 const SkOpPtT* check = &span->fPtT;
caryclarkef4f32a2016-08-24 09:24:18 -0700243 SkOPASSERT(start != check);
caryclark54359292015-03-26 07:52:43 -0700244 const SkOpPtT* walk = start;
245 while ((walk = walk->next()) != start) {
246 if (walk == check) {
247 return true;
248 }
249 }
250 return false;
251}
252
caryclark55888e42016-07-18 10:01:36 -0700253const SkOpPtT* SkOpSpanBase::contains(const SkOpSegment* segment) const {
254 const SkOpPtT* start = &fPtT;
255 const SkOpPtT* walk = start;
caryclark54359292015-03-26 07:52:43 -0700256 while ((walk = walk->next()) != start) {
caryclark55888e42016-07-18 10:01:36 -0700257 if (walk->deleted()) {
258 continue;
259 }
260 if (walk->segment() == segment && walk->span()->ptT() == walk) {
caryclark54359292015-03-26 07:52:43 -0700261 return walk;
262 }
263 }
halcanary96fcdcc2015-08-27 07:41:13 -0700264 return nullptr;
caryclark54359292015-03-26 07:52:43 -0700265}
266
267bool SkOpSpanBase::containsCoinEnd(const SkOpSegment* segment) const {
268 SkASSERT(this->segment() != segment);
269 const SkOpSpanBase* next = this;
270 while ((next = next->fCoinEnd) != this) {
271 if (next->segment() == segment) {
272 return true;
273 }
274 }
275 return false;
276}
277
278SkOpContour* SkOpSpanBase::contour() const {
279 return segment()->contour();
280}
281
282SkOpGlobalState* SkOpSpanBase::globalState() const {
caryclark55888e42016-07-18 10:01:36 -0700283 return contour()->globalState();
caryclark54359292015-03-26 07:52:43 -0700284}
285
286void SkOpSpanBase::initBase(SkOpSegment* segment, SkOpSpan* prev, double t, const SkPoint& pt) {
287 fSegment = segment;
288 fPtT.init(this, t, pt, false);
289 fCoinEnd = this;
halcanary96fcdcc2015-08-27 07:41:13 -0700290 fFromAngle = nullptr;
caryclark54359292015-03-26 07:52:43 -0700291 fPrev = prev;
caryclark08bc8482015-04-24 09:08:57 -0700292 fSpanAdds = 0;
caryclark54359292015-03-26 07:52:43 -0700293 fAligned = true;
294 fChased = false;
caryclark1049f122015-04-20 08:31:59 -0700295 SkDEBUGCODE(fCount = 1);
296 SkDEBUGCODE(fID = globalState()->nextSpanID());
caryclark55888e42016-07-18 10:01:36 -0700297 SkDEBUGCODE(fDeleted = false);
caryclark54359292015-03-26 07:52:43 -0700298}
299
300// this pair of spans share a common t value or point; merge them and eliminate duplicates
301// this does not compute the best t or pt value; this merely moves all data into a single list
302void SkOpSpanBase::merge(SkOpSpan* span) {
303 SkOpPtT* spanPtT = span->ptT();
304 SkASSERT(this->t() != spanPtT->fT);
305 SkASSERT(!zero_or_one(spanPtT->fT));
mtklein18300a32016-03-16 13:53:35 -0700306 span->release(this->ptT());
caryclark55888e42016-07-18 10:01:36 -0700307 if (this->contains(span)) {
308 return; // merge is already in the ptT loop
309 }
caryclark54359292015-03-26 07:52:43 -0700310 SkOpPtT* remainder = spanPtT->next();
caryclark55888e42016-07-18 10:01:36 -0700311 this->ptT()->insert(spanPtT);
caryclark54359292015-03-26 07:52:43 -0700312 while (remainder != spanPtT) {
313 SkOpPtT* next = remainder->next();
314 SkOpPtT* compare = spanPtT->next();
315 while (compare != spanPtT) {
316 SkOpPtT* nextC = compare->next();
317 if (nextC->span() == remainder->span() && nextC->fT == remainder->fT) {
318 goto tryNextRemainder;
319 }
320 compare = nextC;
321 }
322 spanPtT->insert(remainder);
323tryNextRemainder:
324 remainder = next;
325 }
caryclark08bc8482015-04-24 09:08:57 -0700326 fSpanAdds += span->fSpanAdds;
caryclark55888e42016-07-18 10:01:36 -0700327 this->checkForCollapsedCoincidence();
328}
329
330// please keep in sync with debugCheckForCollapsedCoincidence()
331void SkOpSpanBase::checkForCollapsedCoincidence() {
332 SkOpCoincidence* coins = this->globalState()->coincidence();
333 if (coins->isEmpty()) {
334 return;
335 }
336// the insert above may have put both ends of a coincident run in the same span
337// for each coincident ptT in loop; see if its opposite in is also in the loop
338// this implementation is the motivation for marking that a ptT is referenced by a coincident span
339 SkOpPtT* head = this->ptT();
340 SkOpPtT* test = head;
341 do {
342 if (!test->coincident()) {
343 continue;
344 }
345 coins->markCollapsed(test);
346 } while ((test = test->next()) != head);
caryclark54359292015-03-26 07:52:43 -0700347}
348
caryclarkbca19f72015-05-13 08:23:48 -0700349int SkOpSpan::computeWindSum() {
350 SkOpGlobalState* globals = this->globalState();
351 SkOpContour* contourHead = globals->contourHead();
352 int windTry = 0;
353 while (!this->sortableTop(contourHead) && ++windTry < SkOpGlobalState::kMaxWindingTries) {
354 ;
355 }
356 return this->windSum();
357}
358
caryclark54359292015-03-26 07:52:43 -0700359bool SkOpSpan::containsCoincidence(const SkOpSegment* segment) const {
360 SkASSERT(this->segment() != segment);
361 const SkOpSpan* next = fCoincident;
362 do {
363 if (next->segment() == segment) {
364 return true;
365 }
366 } while ((next = next->fCoincident) != this);
367 return false;
368}
369
caryclark55888e42016-07-18 10:01:36 -0700370void SkOpSpan::init(SkOpSegment* segment, SkOpSpan* prev, double t, const SkPoint& pt) {
371 SkASSERT(t != 1);
372 initBase(segment, prev, t, pt);
373 fCoincident = this;
374 fToAngle = nullptr;
375 fWindSum = fOppSum = SK_MinS32;
376 fWindValue = 1;
377 fOppValue = 0;
378 fTopTTry = 0;
379 fChased = fDone = false;
380 segment->bumpCount();
381 fAlreadyAdded = false;
382}
383
384// Please keep this in sync with debugInsertCoincidence()
385bool SkOpSpan::insertCoincidence(const SkOpSegment* segment, bool flipped) {
386 if (this->containsCoincidence(segment)) {
387 return true;
388 }
389 SkOpPtT* next = &fPtT;
390 while ((next = next->next()) != &fPtT) {
391 if (next->segment() == segment) {
caryclark1493b972016-07-19 11:29:14 -0700392 SkOpSpan* span;
393 if (flipped) {
394 span = next->span()->prev();
395 if (!span) {
396 return false;
397 }
398 } else {
399 SkOpSpanBase* base = next->span();
400 if (!base->upCastable()) {
401 return false;
402 }
403 span = base->upCast();
caryclark55888e42016-07-18 10:01:36 -0700404 }
405 this->insertCoincidence(span);
406 return true;
407 }
408 }
409#if DEBUG_COINCIDENCE
410 SkASSERT(0); // FIXME? if we get here, the span is missing its opposite segment...
411#endif
412 return true;
413}
414
415void SkOpSpan::release(const SkOpPtT* kept) {
416 SkDEBUGCODE(fDeleted = true);
417 SkASSERT(kept->span() != this);
caryclark54359292015-03-26 07:52:43 -0700418 SkASSERT(!final());
419 SkOpSpan* prev = this->prev();
420 SkASSERT(prev);
421 SkOpSpanBase* next = this->next();
422 SkASSERT(next);
423 prev->setNext(next);
424 next->setPrev(prev);
mtklein18300a32016-03-16 13:53:35 -0700425 this->segment()->release(this);
caryclark218f21a2015-06-29 11:41:52 -0700426 SkOpCoincidence* coincidence = this->globalState()->coincidence();
427 if (coincidence) {
428 coincidence->fixUp(this->ptT(), kept);
429 }
caryclark54359292015-03-26 07:52:43 -0700430 this->ptT()->setDeleted();
caryclark55888e42016-07-18 10:01:36 -0700431 SkOpPtT* stopPtT = this->ptT();
432 SkOpPtT* testPtT = stopPtT;
433 const SkOpSpanBase* keptSpan = kept->span();
434 do {
435 if (this == testPtT->span()) {
436 testPtT->setSpan(keptSpan);
437 }
438 } while ((testPtT = testPtT->next()) != stopPtT);
caryclark54359292015-03-26 07:52:43 -0700439}
440
441void SkOpSpan::setOppSum(int oppSum) {
442 SkASSERT(!final());
443 if (fOppSum != SK_MinS32 && fOppSum != oppSum) {
444 this->globalState()->setWindingFailed();
445 return;
446 }
bungeman60e0fee2015-08-26 05:15:46 -0700447 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(oppSum) <= DEBUG_LIMIT_WIND_SUM);
caryclark54359292015-03-26 07:52:43 -0700448 fOppSum = oppSum;
449}
caryclark624637c2015-05-11 07:21:27 -0700450
451void SkOpSpan::setWindSum(int windSum) {
452 SkASSERT(!final());
453 if (fWindSum != SK_MinS32 && fWindSum != windSum) {
454 this->globalState()->setWindingFailed();
455 return;
456 }
bungeman60e0fee2015-08-26 05:15:46 -0700457 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(windSum) <= DEBUG_LIMIT_WIND_SUM);
caryclark624637c2015-05-11 07:21:27 -0700458 fWindSum = windSum;
459}