blob: 5c89c736fb82966b586aa3ee09f759d348b4e91c [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
38SkOpPtT* SkOpPtT::contains(const SkOpSegment* check) {
39 SkASSERT(this->segment() != check);
40 SkOpPtT* ptT = this;
41 const SkOpPtT* stopPtT = ptT;
42 while ((ptT = ptT->next()) != stopPtT) {
43 if (ptT->segment() == check) {
44 return ptT;
45 }
46 }
47 return NULL;
48}
49
caryclark54359292015-03-26 07:52:43 -070050SkOpContour* SkOpPtT::contour() const {
51 return segment()->contour();
52}
53
caryclark27c8eb82015-07-06 11:38:33 -070054SkOpPtT* SkOpPtT::doppelganger() {
55 SkASSERT(fDeleted);
56 SkOpPtT* ptT = fNext;
57 while (ptT->fDeleted) {
58 ptT = ptT->fNext;
59 }
60 const SkOpPtT* stopPtT = ptT;
61 do {
62 if (ptT->fSpan == fSpan) {
63 return ptT;
64 }
65 ptT = ptT->fNext;
66 } while (stopPtT != ptT);
67 SkASSERT(0);
68 return NULL;
69}
70
71SkOpPtT* SkOpPtT::find(SkOpSegment* segment) {
72 SkOpPtT* ptT = this;
73 const SkOpPtT* stopPtT = ptT;
74 do {
75 if (ptT->segment() == segment) {
76 return ptT;
77 }
78 ptT = ptT->fNext;
79 } while (stopPtT != ptT);
80 SkASSERT(0);
81 return NULL;
82}
83
caryclark54359292015-03-26 07:52:43 -070084SkOpGlobalState* SkOpPtT::globalState() const {
85 return contour()->globalState();
86}
87
88void SkOpPtT::init(SkOpSpanBase* span, double t, const SkPoint& pt, bool duplicate) {
89 fT = t;
90 fPt = pt;
91 fSpan = span;
92 fNext = this;
93 fDuplicatePt = duplicate;
94 fDeleted = false;
caryclark1049f122015-04-20 08:31:59 -070095 SkDEBUGCODE(fID = span->globalState()->nextPtTID());
caryclark54359292015-03-26 07:52:43 -070096}
97
98bool SkOpPtT::onEnd() const {
99 const SkOpSpanBase* span = this->span();
100 if (span->ptT() != this) {
101 return false;
102 }
103 const SkOpSegment* segment = this->segment();
104 return span == segment->head() || span == segment->tail();
105}
106
107SkOpPtT* SkOpPtT::prev() {
108 SkOpPtT* result = this;
109 SkOpPtT* next = this;
110 while ((next = next->fNext) != this) {
111 result = next;
112 }
113 SkASSERT(result->fNext == this);
114 return result;
115}
116
117SkOpPtT* SkOpPtT::remove() {
118 SkOpPtT* prev = this;
119 do {
120 SkOpPtT* next = prev->fNext;
121 if (next == this) {
122 prev->removeNext(this);
123 SkASSERT(prev->fNext != prev);
124 fDeleted = true;
125 return prev;
126 }
127 prev = next;
128 } while (prev != this);
129 SkASSERT(0);
130 return NULL;
131}
132
133void SkOpPtT::removeNext(SkOpPtT* kept) {
134 SkASSERT(this->fNext);
135 SkOpPtT* next = this->fNext;
136 SkASSERT(this != next->fNext);
137 this->fNext = next->fNext;
138 SkOpSpanBase* span = next->span();
139 next->setDeleted();
140 if (span->ptT() == next) {
141 span->upCast()->detach(kept);
142 }
143}
144
145const SkOpSegment* SkOpPtT::segment() const {
146 return span()->segment();
147}
148
149SkOpSegment* SkOpPtT::segment() {
150 return span()->segment();
151}
152
caryclark54359292015-03-26 07:52:43 -0700153void SkOpSpanBase::align() {
154 if (this->fAligned) {
155 return;
156 }
157 SkASSERT(!zero_or_one(this->fPtT.fT));
158 SkASSERT(this->fPtT.next());
159 // if a linked pt/t pair has a t of zero or one, use it as the base for alignment
160 SkOpPtT* ptT = &this->fPtT, * stopPtT = ptT;
161 while ((ptT = ptT->next()) != stopPtT) {
162 if (zero_or_one(ptT->fT)) {
163 SkOpSegment* segment = ptT->segment();
164 SkASSERT(this->segment() != segment);
165 SkASSERT(segment->head()->ptT() == ptT || segment->tail()->ptT() == ptT);
166 if (ptT->fT) {
167 segment->tail()->alignEnd(1, segment->lastPt());
168 } else {
169 segment->head()->alignEnd(0, segment->pts()[0]);
170 }
171 return;
172 }
173 }
174 alignInner();
175 this->fAligned = true;
176}
177
178
179// FIXME: delete spans that collapse
180// delete segments that collapse
181// delete contours that collapse
182void SkOpSpanBase::alignEnd(double t, const SkPoint& pt) {
183 SkASSERT(zero_or_one(t));
184 SkOpSegment* segment = this->segment();
185 SkASSERT(t ? segment->lastPt() == pt : segment->pts()[0] == pt);
186 alignInner();
187 *segment->writablePt(!!t) = pt;
188 SkOpPtT* ptT = &this->fPtT;
189 SkASSERT(t == ptT->fT);
190 SkASSERT(pt == ptT->fPt);
191 SkOpPtT* test = ptT, * stopPtT = ptT;
192 while ((test = test->next()) != stopPtT) {
193 SkOpSegment* other = test->segment();
194 if (other == this->segment()) {
195 continue;
196 }
197 if (!zero_or_one(test->fT)) {
198 continue;
199 }
200 *other->writablePt(!!test->fT) = pt;
201 }
202 this->fAligned = true;
203}
204
205void SkOpSpanBase::alignInner() {
206 // force the spans to share points and t values
207 SkOpPtT* ptT = &this->fPtT, * stopPtT = ptT;
208 const SkPoint& pt = ptT->fPt;
209 do {
210 ptT->fPt = pt;
211 const SkOpSpanBase* span = ptT->span();
212 SkOpPtT* test = ptT;
213 do {
214 SkOpPtT* prev = test;
215 if ((test = test->next()) == stopPtT) {
216 break;
217 }
218 if (span == test->span() && !span->segment()->ptsDisjoint(*ptT, *test)) {
219 // omit aliases that alignment makes redundant
220 if ((!ptT->alias() || test->alias()) && (ptT->onEnd() || !test->onEnd())) {
221 SkASSERT(test->alias());
222 prev->removeNext(ptT);
223 test = prev;
224 } else {
225 SkASSERT(ptT->alias());
226 stopPtT = ptT = ptT->remove();
227 break;
228 }
229 }
230 } while (true);
231 } while ((ptT = ptT->next()) != stopPtT);
232}
233
234bool SkOpSpanBase::contains(const SkOpSpanBase* span) const {
235 const SkOpPtT* start = &fPtT;
236 const SkOpPtT* check = &span->fPtT;
237 SkASSERT(start != check);
238 const SkOpPtT* walk = start;
239 while ((walk = walk->next()) != start) {
240 if (walk == check) {
241 return true;
242 }
243 }
244 return false;
245}
246
247SkOpPtT* SkOpSpanBase::contains(const SkOpSegment* segment) {
248 SkOpPtT* start = &fPtT;
249 SkOpPtT* walk = start;
250 while ((walk = walk->next()) != start) {
251 if (walk->segment() == segment) {
252 return walk;
253 }
254 }
255 return NULL;
256}
257
258bool SkOpSpanBase::containsCoinEnd(const SkOpSegment* segment) const {
259 SkASSERT(this->segment() != segment);
260 const SkOpSpanBase* next = this;
261 while ((next = next->fCoinEnd) != this) {
262 if (next->segment() == segment) {
263 return true;
264 }
265 }
266 return false;
267}
268
269SkOpContour* SkOpSpanBase::contour() const {
270 return segment()->contour();
271}
272
273SkOpGlobalState* SkOpSpanBase::globalState() const {
274 return contour()->globalState();
275}
276
277void SkOpSpanBase::initBase(SkOpSegment* segment, SkOpSpan* prev, double t, const SkPoint& pt) {
278 fSegment = segment;
279 fPtT.init(this, t, pt, false);
280 fCoinEnd = this;
281 fFromAngle = NULL;
282 fPrev = prev;
caryclark08bc8482015-04-24 09:08:57 -0700283 fSpanAdds = 0;
caryclark54359292015-03-26 07:52:43 -0700284 fAligned = true;
285 fChased = false;
caryclark1049f122015-04-20 08:31:59 -0700286 SkDEBUGCODE(fCount = 1);
287 SkDEBUGCODE(fID = globalState()->nextSpanID());
caryclark54359292015-03-26 07:52:43 -0700288}
289
290// this pair of spans share a common t value or point; merge them and eliminate duplicates
291// this does not compute the best t or pt value; this merely moves all data into a single list
292void SkOpSpanBase::merge(SkOpSpan* span) {
293 SkOpPtT* spanPtT = span->ptT();
294 SkASSERT(this->t() != spanPtT->fT);
295 SkASSERT(!zero_or_one(spanPtT->fT));
296 span->detach(this->ptT());
297 SkOpPtT* remainder = spanPtT->next();
298 ptT()->insert(spanPtT);
299 while (remainder != spanPtT) {
300 SkOpPtT* next = remainder->next();
301 SkOpPtT* compare = spanPtT->next();
302 while (compare != spanPtT) {
303 SkOpPtT* nextC = compare->next();
304 if (nextC->span() == remainder->span() && nextC->fT == remainder->fT) {
305 goto tryNextRemainder;
306 }
307 compare = nextC;
308 }
309 spanPtT->insert(remainder);
310tryNextRemainder:
311 remainder = next;
312 }
caryclark08bc8482015-04-24 09:08:57 -0700313 fSpanAdds += span->fSpanAdds;
caryclark54359292015-03-26 07:52:43 -0700314}
315
caryclarkbca19f72015-05-13 08:23:48 -0700316int SkOpSpan::computeWindSum() {
317 SkOpGlobalState* globals = this->globalState();
318 SkOpContour* contourHead = globals->contourHead();
319 int windTry = 0;
320 while (!this->sortableTop(contourHead) && ++windTry < SkOpGlobalState::kMaxWindingTries) {
321 ;
322 }
323 return this->windSum();
324}
325
caryclark54359292015-03-26 07:52:43 -0700326bool SkOpSpan::containsCoincidence(const SkOpSegment* segment) const {
327 SkASSERT(this->segment() != segment);
328 const SkOpSpan* next = fCoincident;
329 do {
330 if (next->segment() == segment) {
331 return true;
332 }
333 } while ((next = next->fCoincident) != this);
334 return false;
335}
336
337void SkOpSpan::detach(SkOpPtT* kept) {
338 SkASSERT(!final());
339 SkOpSpan* prev = this->prev();
340 SkASSERT(prev);
341 SkOpSpanBase* next = this->next();
342 SkASSERT(next);
343 prev->setNext(next);
344 next->setPrev(prev);
345 this->segment()->detach(this);
caryclark218f21a2015-06-29 11:41:52 -0700346 SkOpCoincidence* coincidence = this->globalState()->coincidence();
347 if (coincidence) {
348 coincidence->fixUp(this->ptT(), kept);
349 }
caryclark54359292015-03-26 07:52:43 -0700350 this->ptT()->setDeleted();
351}
352
353void SkOpSpan::init(SkOpSegment* segment, SkOpSpan* prev, double t, const SkPoint& pt) {
354 SkASSERT(t != 1);
355 initBase(segment, prev, t, pt);
356 fCoincident = this;
357 fToAngle = NULL;
358 fWindSum = fOppSum = SK_MinS32;
359 fWindValue = 1;
360 fOppValue = 0;
caryclark624637c2015-05-11 07:21:27 -0700361 fTopTTry = 0;
caryclark54359292015-03-26 07:52:43 -0700362 fChased = fDone = false;
363 segment->bumpCount();
364}
365
366void SkOpSpan::setOppSum(int oppSum) {
367 SkASSERT(!final());
368 if (fOppSum != SK_MinS32 && fOppSum != oppSum) {
369 this->globalState()->setWindingFailed();
370 return;
371 }
372 SkASSERT(!DEBUG_LIMIT_WIND_SUM || abs(oppSum) <= DEBUG_LIMIT_WIND_SUM);
373 fOppSum = oppSum;
374}
caryclark624637c2015-05-11 07:21:27 -0700375
376void SkOpSpan::setWindSum(int windSum) {
377 SkASSERT(!final());
378 if (fWindSum != SK_MinS32 && fWindSum != windSum) {
379 this->globalState()->setWindingFailed();
380 return;
381 }
382 SkASSERT(!DEBUG_LIMIT_WIND_SUM || abs(windSum) <= DEBUG_LIMIT_WIND_SUM);
383 fWindSum = windSum;
384}