• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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