blob: b75a692f7440cb5dea5bdd30879522d389d356ae [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
16SkOpContour* SkOpPtT::contour() const {
17 return segment()->contour();
18}
19
20SkOpGlobalState* SkOpPtT::globalState() const {
21 return contour()->globalState();
22}
23
24void SkOpPtT::init(SkOpSpanBase* span, double t, const SkPoint& pt, bool duplicate) {
25 fT = t;
26 fPt = pt;
27 fSpan = span;
28 fNext = this;
29 fDuplicatePt = duplicate;
30 fDeleted = false;
caryclark1049f122015-04-20 08:31:59 -070031 SkDEBUGCODE(fID = span->globalState()->nextPtTID());
caryclark54359292015-03-26 07:52:43 -070032}
33
34bool SkOpPtT::onEnd() const {
35 const SkOpSpanBase* span = this->span();
36 if (span->ptT() != this) {
37 return false;
38 }
39 const SkOpSegment* segment = this->segment();
40 return span == segment->head() || span == segment->tail();
41}
42
43SkOpPtT* SkOpPtT::prev() {
44 SkOpPtT* result = this;
45 SkOpPtT* next = this;
46 while ((next = next->fNext) != this) {
47 result = next;
48 }
49 SkASSERT(result->fNext == this);
50 return result;
51}
52
53SkOpPtT* SkOpPtT::remove() {
54 SkOpPtT* prev = this;
55 do {
56 SkOpPtT* next = prev->fNext;
57 if (next == this) {
58 prev->removeNext(this);
59 SkASSERT(prev->fNext != prev);
60 fDeleted = true;
61 return prev;
62 }
63 prev = next;
64 } while (prev != this);
65 SkASSERT(0);
66 return NULL;
67}
68
69void SkOpPtT::removeNext(SkOpPtT* kept) {
70 SkASSERT(this->fNext);
71 SkOpPtT* next = this->fNext;
72 SkASSERT(this != next->fNext);
73 this->fNext = next->fNext;
74 SkOpSpanBase* span = next->span();
75 next->setDeleted();
76 if (span->ptT() == next) {
77 span->upCast()->detach(kept);
78 }
79}
80
81const SkOpSegment* SkOpPtT::segment() const {
82 return span()->segment();
83}
84
85SkOpSegment* SkOpPtT::segment() {
86 return span()->segment();
87}
88
89// find the starting or ending span with an existing loop of angles
90// OPTIMIZE? remove the spans pointing to windValue==0 here or earlier?
91// FIXME? assert that only one other span has a valid windValue or oppValue
caryclark1049f122015-04-20 08:31:59 -070092bool SkOpSpanBase::addSimpleAngle(bool checkFrom, SkChunkAlloc* allocator) {
caryclark54359292015-03-26 07:52:43 -070093 SkOpAngle* angle;
94 if (checkFrom) {
caryclark1049f122015-04-20 08:31:59 -070095 if (!this->final()) {
96 return false;
97 }
caryclark54359292015-03-26 07:52:43 -070098 if (this->fromAngle()) {
99 SkASSERT(this->fromAngle()->loopCount() == 2);
caryclark1049f122015-04-20 08:31:59 -0700100 return true;
caryclark54359292015-03-26 07:52:43 -0700101 }
102 angle = this->segment()->addEndSpan(allocator);
103 } else {
104 SkASSERT(this->t() == 0);
105 SkOpSpan* span = this->upCast();
106 if (span->toAngle()) {
107 SkASSERT(span->toAngle()->loopCount() == 2);
108 SkASSERT(!span->fromAngle());
109 span->setFromAngle(span->toAngle()->next());
caryclark1049f122015-04-20 08:31:59 -0700110 return true;
caryclark54359292015-03-26 07:52:43 -0700111 }
112 angle = this->segment()->addStartSpan(allocator);
113 }
114 SkOpPtT* ptT = this->ptT();
115 SkOpSpanBase* oSpanBase;
116 SkOpSpan* oSpan;
117 SkOpSegment* other;
118 do {
119 ptT = ptT->next();
120 oSpanBase = ptT->span();
121 oSpan = oSpanBase->upCastable();
122 other = oSpanBase->segment();
123 if (oSpan && oSpan->windValue()) {
124 break;
125 }
126 if (oSpanBase->t() == 0) {
127 continue;
128 }
129 SkOpSpan* oFromSpan = oSpanBase->prev();
130 SkASSERT(oFromSpan->t() < 1);
131 if (oFromSpan->windValue()) {
132 break;
133 }
134 } while (ptT != this->ptT());
135 SkOpAngle* oAngle;
136 if (checkFrom) {
137 oAngle = other->addStartSpan(allocator);
138 SkASSERT(oSpan && !oSpan->final());
139 SkASSERT(oAngle == oSpan->toAngle());
140 } else {
141 oAngle = other->addEndSpan(allocator);
142 SkASSERT(oAngle == oSpanBase->fromAngle());
143 }
144 angle->insert(oAngle);
caryclark1049f122015-04-20 08:31:59 -0700145 return true;
caryclark54359292015-03-26 07:52:43 -0700146}
147
148void SkOpSpanBase::align() {
149 if (this->fAligned) {
150 return;
151 }
152 SkASSERT(!zero_or_one(this->fPtT.fT));
153 SkASSERT(this->fPtT.next());
154 // if a linked pt/t pair has a t of zero or one, use it as the base for alignment
155 SkOpPtT* ptT = &this->fPtT, * stopPtT = ptT;
156 while ((ptT = ptT->next()) != stopPtT) {
157 if (zero_or_one(ptT->fT)) {
158 SkOpSegment* segment = ptT->segment();
159 SkASSERT(this->segment() != segment);
160 SkASSERT(segment->head()->ptT() == ptT || segment->tail()->ptT() == ptT);
161 if (ptT->fT) {
162 segment->tail()->alignEnd(1, segment->lastPt());
163 } else {
164 segment->head()->alignEnd(0, segment->pts()[0]);
165 }
166 return;
167 }
168 }
169 alignInner();
170 this->fAligned = true;
171}
172
173
174// FIXME: delete spans that collapse
175// delete segments that collapse
176// delete contours that collapse
177void SkOpSpanBase::alignEnd(double t, const SkPoint& pt) {
178 SkASSERT(zero_or_one(t));
179 SkOpSegment* segment = this->segment();
180 SkASSERT(t ? segment->lastPt() == pt : segment->pts()[0] == pt);
181 alignInner();
182 *segment->writablePt(!!t) = pt;
183 SkOpPtT* ptT = &this->fPtT;
184 SkASSERT(t == ptT->fT);
185 SkASSERT(pt == ptT->fPt);
186 SkOpPtT* test = ptT, * stopPtT = ptT;
187 while ((test = test->next()) != stopPtT) {
188 SkOpSegment* other = test->segment();
189 if (other == this->segment()) {
190 continue;
191 }
192 if (!zero_or_one(test->fT)) {
193 continue;
194 }
195 *other->writablePt(!!test->fT) = pt;
196 }
197 this->fAligned = true;
198}
199
200void SkOpSpanBase::alignInner() {
201 // force the spans to share points and t values
202 SkOpPtT* ptT = &this->fPtT, * stopPtT = ptT;
203 const SkPoint& pt = ptT->fPt;
204 do {
205 ptT->fPt = pt;
206 const SkOpSpanBase* span = ptT->span();
207 SkOpPtT* test = ptT;
208 do {
209 SkOpPtT* prev = test;
210 if ((test = test->next()) == stopPtT) {
211 break;
212 }
213 if (span == test->span() && !span->segment()->ptsDisjoint(*ptT, *test)) {
214 // omit aliases that alignment makes redundant
215 if ((!ptT->alias() || test->alias()) && (ptT->onEnd() || !test->onEnd())) {
216 SkASSERT(test->alias());
217 prev->removeNext(ptT);
218 test = prev;
219 } else {
220 SkASSERT(ptT->alias());
221 stopPtT = ptT = ptT->remove();
222 break;
223 }
224 }
225 } while (true);
226 } while ((ptT = ptT->next()) != stopPtT);
227}
228
229bool SkOpSpanBase::contains(const SkOpSpanBase* span) const {
230 const SkOpPtT* start = &fPtT;
231 const SkOpPtT* check = &span->fPtT;
232 SkASSERT(start != check);
233 const SkOpPtT* walk = start;
234 while ((walk = walk->next()) != start) {
235 if (walk == check) {
236 return true;
237 }
238 }
239 return false;
240}
241
242SkOpPtT* SkOpSpanBase::contains(const SkOpSegment* segment) {
243 SkOpPtT* start = &fPtT;
244 SkOpPtT* walk = start;
245 while ((walk = walk->next()) != start) {
246 if (walk->segment() == segment) {
247 return walk;
248 }
249 }
250 return NULL;
251}
252
253bool SkOpSpanBase::containsCoinEnd(const SkOpSegment* segment) const {
254 SkASSERT(this->segment() != segment);
255 const SkOpSpanBase* next = this;
256 while ((next = next->fCoinEnd) != this) {
257 if (next->segment() == segment) {
258 return true;
259 }
260 }
261 return false;
262}
263
264SkOpContour* SkOpSpanBase::contour() const {
265 return segment()->contour();
266}
267
268SkOpGlobalState* SkOpSpanBase::globalState() const {
269 return contour()->globalState();
270}
271
272void SkOpSpanBase::initBase(SkOpSegment* segment, SkOpSpan* prev, double t, const SkPoint& pt) {
273 fSegment = segment;
274 fPtT.init(this, t, pt, false);
275 fCoinEnd = this;
276 fFromAngle = NULL;
277 fPrev = prev;
caryclark08bc8482015-04-24 09:08:57 -0700278 fSpanAdds = 0;
caryclark54359292015-03-26 07:52:43 -0700279 fAligned = true;
280 fChased = false;
caryclark1049f122015-04-20 08:31:59 -0700281 SkDEBUGCODE(fCount = 1);
282 SkDEBUGCODE(fID = globalState()->nextSpanID());
caryclark54359292015-03-26 07:52:43 -0700283}
284
285// this pair of spans share a common t value or point; merge them and eliminate duplicates
286// this does not compute the best t or pt value; this merely moves all data into a single list
287void SkOpSpanBase::merge(SkOpSpan* span) {
288 SkOpPtT* spanPtT = span->ptT();
289 SkASSERT(this->t() != spanPtT->fT);
290 SkASSERT(!zero_or_one(spanPtT->fT));
291 span->detach(this->ptT());
292 SkOpPtT* remainder = spanPtT->next();
293 ptT()->insert(spanPtT);
294 while (remainder != spanPtT) {
295 SkOpPtT* next = remainder->next();
296 SkOpPtT* compare = spanPtT->next();
297 while (compare != spanPtT) {
298 SkOpPtT* nextC = compare->next();
299 if (nextC->span() == remainder->span() && nextC->fT == remainder->fT) {
300 goto tryNextRemainder;
301 }
302 compare = nextC;
303 }
304 spanPtT->insert(remainder);
305tryNextRemainder:
306 remainder = next;
307 }
caryclark08bc8482015-04-24 09:08:57 -0700308 fSpanAdds += span->fSpanAdds;
caryclark54359292015-03-26 07:52:43 -0700309}
310
311void SkOpSpan::applyCoincidence(SkOpSpan* opp) {
312 SkASSERT(!final());
313 SkASSERT(0); // incomplete
314}
315
316bool SkOpSpan::containsCoincidence(const SkOpSegment* segment) const {
317 SkASSERT(this->segment() != segment);
318 const SkOpSpan* next = fCoincident;
319 do {
320 if (next->segment() == segment) {
321 return true;
322 }
323 } while ((next = next->fCoincident) != this);
324 return false;
325}
326
327void SkOpSpan::detach(SkOpPtT* kept) {
328 SkASSERT(!final());
329 SkOpSpan* prev = this->prev();
330 SkASSERT(prev);
331 SkOpSpanBase* next = this->next();
332 SkASSERT(next);
333 prev->setNext(next);
334 next->setPrev(prev);
335 this->segment()->detach(this);
336 this->globalState()->coincidence()->fixUp(this->ptT(), kept);
337 this->ptT()->setDeleted();
338}
339
340void SkOpSpan::init(SkOpSegment* segment, SkOpSpan* prev, double t, const SkPoint& pt) {
341 SkASSERT(t != 1);
342 initBase(segment, prev, t, pt);
343 fCoincident = this;
344 fToAngle = NULL;
345 fWindSum = fOppSum = SK_MinS32;
346 fWindValue = 1;
347 fOppValue = 0;
348 fChased = fDone = false;
349 segment->bumpCount();
350}
351
352void SkOpSpan::setOppSum(int oppSum) {
353 SkASSERT(!final());
354 if (fOppSum != SK_MinS32 && fOppSum != oppSum) {
355 this->globalState()->setWindingFailed();
356 return;
357 }
358 SkASSERT(!DEBUG_LIMIT_WIND_SUM || abs(oppSum) <= DEBUG_LIMIT_WIND_SUM);
359 fOppSum = oppSum;
360}