1 /*
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
alias() const12 bool SkOpPtT::alias() const {
13 return this->span()->ptT() != this;
14 }
15
collapsed(const SkOpPtT * check) const16 bool 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
contains(const SkOpPtT * check) const26 bool 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
contains(const SkOpSegment * check)38 SkOpPtT* 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 nullptr;
48 }
49
contour() const50 SkOpContour* SkOpPtT::contour() const {
51 return segment()->contour();
52 }
53
doppelganger()54 SkOpPtT* 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 nullptr;
69 }
70
find(SkOpSegment * segment)71 SkOpPtT* 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 nullptr;
82 }
83
globalState() const84 SkOpGlobalState* SkOpPtT::globalState() const {
85 return contour()->globalState();
86 }
87
init(SkOpSpanBase * span,double t,const SkPoint & pt,bool duplicate)88 void 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;
95 SkDEBUGCODE(fID = span->globalState()->nextPtTID());
96 }
97
onEnd() const98 bool 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
prev()107 SkOpPtT* 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
remove()117 SkOpPtT* 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 nullptr;
131 }
132
removeNext(SkOpPtT * kept)133 void 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
segment() const145 const SkOpSegment* SkOpPtT::segment() const {
146 return span()->segment();
147 }
148
segment()149 SkOpSegment* SkOpPtT::segment() {
150 return span()->segment();
151 }
152
align()153 void 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
alignEnd(double t,const SkPoint & pt)182 void 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
alignInner()205 void 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
contains(const SkOpSpanBase * span) const234 bool 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
contains(const SkOpSegment * segment)247 SkOpPtT* 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 nullptr;
256 }
257
containsCoinEnd(const SkOpSegment * segment) const258 bool 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
contour() const269 SkOpContour* SkOpSpanBase::contour() const {
270 return segment()->contour();
271 }
272
globalState() const273 SkOpGlobalState* SkOpSpanBase::globalState() const {
274 return contour()->globalState();
275 }
276
initBase(SkOpSegment * segment,SkOpSpan * prev,double t,const SkPoint & pt)277 void 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 = nullptr;
282 fPrev = prev;
283 fSpanAdds = 0;
284 fAligned = true;
285 fChased = false;
286 SkDEBUGCODE(fCount = 1);
287 SkDEBUGCODE(fID = globalState()->nextSpanID());
288 }
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
merge(SkOpSpan * span)292 void 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);
310 tryNextRemainder:
311 remainder = next;
312 }
313 fSpanAdds += span->fSpanAdds;
314 }
315
computeWindSum()316 int 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
containsCoincidence(const SkOpSegment * segment) const326 bool 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
detach(SkOpPtT * kept)337 void 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);
346 SkOpCoincidence* coincidence = this->globalState()->coincidence();
347 if (coincidence) {
348 coincidence->fixUp(this->ptT(), kept);
349 }
350 this->ptT()->setDeleted();
351 }
352
init(SkOpSegment * segment,SkOpSpan * prev,double t,const SkPoint & pt)353 void 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 = nullptr;
358 fWindSum = fOppSum = SK_MinS32;
359 fWindValue = 1;
360 fOppValue = 0;
361 fTopTTry = 0;
362 fChased = fDone = false;
363 segment->bumpCount();
364 fAlreadyAdded = false;
365 }
366
setOppSum(int oppSum)367 void SkOpSpan::setOppSum(int oppSum) {
368 SkASSERT(!final());
369 if (fOppSum != SK_MinS32 && fOppSum != oppSum) {
370 this->globalState()->setWindingFailed();
371 return;
372 }
373 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(oppSum) <= DEBUG_LIMIT_WIND_SUM);
374 fOppSum = oppSum;
375 }
376
setWindSum(int windSum)377 void SkOpSpan::setWindSum(int windSum) {
378 SkASSERT(!final());
379 if (fWindSum != SK_MinS32 && fWindSum != windSum) {
380 this->globalState()->setWindingFailed();
381 return;
382 }
383 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(windSum) <= DEBUG_LIMIT_WIND_SUM);
384 fWindSum = windSum;
385 }
386