Flutter Engine
The Flutter Engine
SkOpSpan.cpp
Go to the documentation of this file.
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 */
15
16#include <algorithm>
17
18bool SkOpPtT::alias() const {
19 return this->span()->ptT() != this;
20}
21
22const SkOpPtT* SkOpPtT::active() const {
23 if (!fDeleted) {
24 return this;
25 }
26 const SkOpPtT* ptT = this;
27 const SkOpPtT* stopPtT = ptT;
28 while ((ptT = ptT->next()) != stopPtT) {
29 if (ptT->fSpan == fSpan && !ptT->fDeleted) {
30 return ptT;
31 }
32 }
33 return nullptr; // should never return deleted; caller must abort
34}
35
36bool SkOpPtT::contains(const SkOpPtT* check) const {
37 SkOPASSERT(this != check);
38 const SkOpPtT* ptT = this;
39 const SkOpPtT* stopPtT = ptT;
40 while ((ptT = ptT->next()) != stopPtT) {
41 if (ptT == check) {
42 return true;
43 }
44 }
45 return false;
46}
47
48bool SkOpPtT::contains(const SkOpSegment* segment, const SkPoint& pt) const {
49 SkASSERT(this->segment() != segment);
50 const SkOpPtT* ptT = this;
51 const SkOpPtT* stopPtT = ptT;
52 while ((ptT = ptT->next()) != stopPtT) {
53 if (ptT->fPt == pt && ptT->segment() == segment) {
54 return true;
55 }
56 }
57 return false;
58}
59
60bool SkOpPtT::contains(const SkOpSegment* segment, double t) const {
61 const SkOpPtT* ptT = this;
62 const SkOpPtT* stopPtT = ptT;
63 while ((ptT = ptT->next()) != stopPtT) {
64 if (ptT->fT == t && ptT->segment() == segment) {
65 return true;
66 }
67 }
68 return false;
69}
70
72 SkASSERT(this->segment() != check);
73 const SkOpPtT* ptT = this;
74 const SkOpPtT* stopPtT = ptT;
75 while ((ptT = ptT->next()) != stopPtT) {
76 if (ptT->segment() == check && !ptT->deleted()) {
77 return ptT;
78 }
79 }
80 return nullptr;
81}
82
84 return segment()->contour();
85}
86
87const SkOpPtT* SkOpPtT::find(const SkOpSegment* segment) const {
88 const SkOpPtT* ptT = this;
89 const SkOpPtT* stopPtT = ptT;
90 do {
91 if (ptT->segment() == segment && !ptT->deleted()) {
92 return ptT;
93 }
94 ptT = ptT->fNext;
95 } while (stopPtT != ptT);
96// SkASSERT(0);
97 return nullptr;
98}
99
101 return contour()->globalState();
102}
103
104void SkOpPtT::init(SkOpSpanBase* span, double t, const SkPoint& pt, bool duplicate) {
105 fT = t;
106 fPt = pt;
107 fSpan = span;
108 fNext = this;
110 fDeleted = false;
111 fCoincident = false;
112 SkDEBUGCODE(fID = span->globalState()->nextPtTID());
113}
114
115bool SkOpPtT::onEnd() const {
116 const SkOpSpanBase* span = this->span();
117 if (span->ptT() != this) {
118 return false;
119 }
120 const SkOpSegment* segment = this->segment();
121 return span == segment->head() || span == segment->tail();
122}
123
125 while (this != check) {
126 if (this->fPt == check->fPt) {
127 return true;
128 }
129 check = check->fNext;
130 }
131 return false;
132}
133
135 SkOpPtT* result = this;
136 SkOpPtT* next = this;
137 while ((next = next->fNext) != this) {
138 result = next;
139 }
140 SkASSERT(result->fNext == this);
141 return result;
142}
143
145 return span()->segment();
146}
147
149 return span()->segment();
150}
151
153 SkASSERT(this->span()->debugDeleted() || this->span()->ptT() != this);
155 fDeleted = true;
156}
157
159 SkOpPtT* oppPrev = this->ptT()->oppPrev(opp->ptT());
160 if (!oppPrev) {
161 return true;
162 }
163 FAIL_IF(!this->mergeMatches(opp));
164 this->ptT()->addOpp(opp->ptT(), oppPrev);
166 return true;
167}
168
170 const SkOpPtT* start = &fPtT;
171 const SkOpPtT* startNext = nullptr;
172 const SkOpPtT* walk = start;
173 double min = walk->fT;
174 double max = min;
175 const SkOpSegment* segment = this->segment();
176 int safetyNet = 100000;
177 while ((walk = walk->next()) != start) {
178 if (!--safetyNet) {
179 return Collapsed::kError;
180 }
181 if (walk == startNext) {
182 return Collapsed::kError;
183 }
184 if (walk->segment() != segment) {
185 continue;
186 }
187 min = std::min(min, walk->fT);
188 max = std::max(max, walk->fT);
189 if (between(min, s, max) && between(min, e, max)) {
190 return Collapsed::kYes;
191 }
192 startNext = start->next();
193 }
194 return Collapsed::kNo;
195}
196
197bool SkOpSpanBase::contains(const SkOpSpanBase* span) const {
198 const SkOpPtT* start = &fPtT;
199 const SkOpPtT* check = &span->fPtT;
201 const SkOpPtT* walk = start;
202 while ((walk = walk->next()) != start) {
203 if (walk == check) {
204 return true;
205 }
206 }
207 return false;
208}
209
210const SkOpPtT* SkOpSpanBase::contains(const SkOpSegment* segment) const {
211 const SkOpPtT* start = &fPtT;
212 const SkOpPtT* walk = start;
213 while ((walk = walk->next()) != start) {
214 if (walk->deleted()) {
215 continue;
216 }
217 if (walk->segment() == segment && walk->span()->ptT() == walk) {
218 return walk;
219 }
220 }
221 return nullptr;
222}
223
224bool SkOpSpanBase::containsCoinEnd(const SkOpSegment* segment) const {
225 SkASSERT(this->segment() != segment);
226 const SkOpSpanBase* next = this;
227 while ((next = next->fCoinEnd) != this) {
228 if (next->segment() == segment) {
229 return true;
230 }
231 }
232 return false;
233}
234
236 return segment()->contour();
237}
238
240 return contour()->globalState();
241}
242
243void SkOpSpanBase::initBase(SkOpSegment* segment, SkOpSpan* prev, double t, const SkPoint& pt) {
245 fPtT.init(this, t, pt, false);
246 fCoinEnd = this;
247 fFromAngle = nullptr;
248 fPrev = prev;
249 fSpanAdds = 0;
250 fAligned = true;
251 fChased = false;
252 SkDEBUGCODE(fCount = 1);
253 SkDEBUGCODE(fID = globalState()->nextSpanID());
254 SkDEBUGCODE(fDebugDeleted = false);
255}
256
257// this pair of spans share a common t value or point; merge them and eliminate duplicates
258// this does not compute the best t or pt value; this merely moves all data into a single list
260 SkOpPtT* spanPtT = span->ptT();
261 SkASSERT(this->t() != spanPtT->fT);
262 SkASSERT(!zero_or_one(spanPtT->fT));
263 span->release(this->ptT());
264 if (this->contains(span)) {
265 SkOPASSERT(0); // check to see if this ever happens -- should have been found earlier
266 return; // merge is already in the ptT loop
267 }
268 SkOpPtT* remainder = spanPtT->next();
269 this->ptT()->insert(spanPtT);
270 while (remainder != spanPtT) {
271 SkOpPtT* next = remainder->next();
272 SkOpPtT* compare = spanPtT->next();
273 while (compare != spanPtT) {
274 SkOpPtT* nextC = compare->next();
275 if (nextC->span() == remainder->span() && nextC->fT == remainder->fT) {
276 goto tryNextRemainder;
277 }
278 compare = nextC;
279 }
280 spanPtT->insert(remainder);
281tryNextRemainder:
282 remainder = next;
283 }
284 fSpanAdds += span->fSpanAdds;
285}
286
287// please keep in sync with debugCheckForCollapsedCoincidence()
289 SkOpCoincidence* coins = this->globalState()->coincidence();
290 if (coins->isEmpty()) {
291 return;
292 }
293// the insert above may have put both ends of a coincident run in the same span
294// for each coincident ptT in loop; see if its opposite in is also in the loop
295// this implementation is the motivation for marking that a ptT is referenced by a coincident span
296 SkOpPtT* head = this->ptT();
297 SkOpPtT* test = head;
298 do {
299 if (!test->coincident()) {
300 continue;
301 }
302 coins->markCollapsed(test);
303 } while ((test = test->next()) != head);
304 coins->releaseDeleted();
305}
306
307// please keep in sync with debugMergeMatches()
308// Look to see if pt-t linked list contains same segment more than once
309// if so, and if each pt-t is directly pointed to by spans in that segment,
310// merge them
311// keep the points, but remove spans so that the segment doesn't have 2 or more
312// spans pointing to the same pt-t loop at different loop elements
314 SkOpPtT* test = &fPtT;
315 SkOpPtT* testNext;
316 const SkOpPtT* stop = test;
317 int safetyHatch = 1000000;
318 do {
319 if (!--safetyHatch) {
320 return false;
321 }
322 testNext = test->next();
323 if (test->deleted()) {
324 continue;
325 }
326 SkOpSpanBase* testBase = test->span();
327 SkASSERT(testBase->ptT() == test);
328 SkOpSegment* segment = test->segment();
329 if (segment->done()) {
330 continue;
331 }
332 SkOpPtT* inner = opp->ptT();
333 const SkOpPtT* innerStop = inner;
334 do {
335 if (inner->segment() != segment) {
336 continue;
337 }
338 if (inner->deleted()) {
339 continue;
340 }
341 SkOpSpanBase* innerBase = inner->span();
342 SkASSERT(innerBase->ptT() == inner);
343 // when the intersection is first detected, the span base is marked if there are
344 // more than one point in the intersection.
345 if (!zero_or_one(inner->fT)) {
346 innerBase->upCast()->release(test);
347 } else {
348 SkOPASSERT(inner->fT != test->fT);
349 if (!zero_or_one(test->fT)) {
350 testBase->upCast()->release(inner);
351 } else {
352 segment->markAllDone(); // mark segment as collapsed
353 SkDEBUGCODE(testBase->debugSetDeleted());
354 test->setDeleted();
355 SkDEBUGCODE(innerBase->debugSetDeleted());
356 inner->setDeleted();
357 }
358 }
359#ifdef SK_DEBUG // assert if another undeleted entry points to segment
360 const SkOpPtT* debugInner = inner;
361 while ((debugInner = debugInner->next()) != innerStop) {
362 if (debugInner->segment() != segment) {
363 continue;
364 }
365 if (debugInner->deleted()) {
366 continue;
367 }
368 SkOPASSERT(0);
369 }
370#endif
371 break;
372 } while ((inner = inner->next()) != innerStop);
373 } while ((test = testNext) != stop);
375 return true;
376}
377
379 SkOpGlobalState* globals = this->globalState();
380 SkOpContour* contourHead = globals->contourHead();
381 int windTry = 0;
382 while (!this->sortableTop(contourHead) && ++windTry < SkOpGlobalState::kMaxWindingTries) {
383 }
384 return this->windSum();
385}
386
387bool SkOpSpan::containsCoincidence(const SkOpSegment* segment) const {
388 SkASSERT(this->segment() != segment);
389 const SkOpSpan* next = fCoincident;
390 do {
391 if (next->segment() == segment) {
392 return true;
393 }
394 } while ((next = next->fCoincident) != this);
395 return false;
396}
397
398void SkOpSpan::init(SkOpSegment* segment, SkOpSpan* prev, double t, const SkPoint& pt) {
399 SkASSERT(t != 1);
401 fCoincident = this;
402 fToAngle = nullptr;
403 fWindSum = fOppSum = SK_MinS32;
404 fWindValue = 1;
405 fOppValue = 0;
406 fTopTTry = 0;
407 fChased = fDone = false;
409 fAlreadyAdded = false;
410}
411
412// Please keep this in sync with debugInsertCoincidence()
413bool SkOpSpan::insertCoincidence(const SkOpSegment* segment, bool flipped, bool ordered) {
414 if (this->containsCoincidence(segment)) {
415 return true;
416 }
417 SkOpPtT* next = &fPtT;
418 while ((next = next->next()) != &fPtT) {
419 if (next->segment() == segment) {
420 SkOpSpan* span;
421 SkOpSpanBase* base = next->span();
422 if (!ordered) {
423 const SkOpPtT* spanEndPtT = fNext->contains(segment);
424 FAIL_IF(!spanEndPtT);
425 const SkOpSpanBase* spanEnd = spanEndPtT->span();
426 const SkOpPtT* start = base->ptT()->starter(spanEnd->ptT());
427 FAIL_IF(!start->span()->upCastable());
428 span = const_cast<SkOpSpan*>(start->span()->upCast());
429 } else if (flipped) {
430 span = base->prev();
431 FAIL_IF(!span);
432 } else {
433 FAIL_IF(!base->upCastable());
434 span = base->upCast();
435 }
436 this->insertCoincidence(span);
437 return true;
438 }
439 }
440#if DEBUG_COINCIDENCE
441 SkASSERT(0); // FIXME? if we get here, the span is missing its opposite segment...
442#endif
443 return true;
444}
445
446void SkOpSpan::release(const SkOpPtT* kept) {
447 SkDEBUGCODE(fDebugDeleted = true);
448 SkOPASSERT(kept->span() != this);
449 SkASSERT(!final());
450 SkOpSpan* prev = this->prev();
451 SkASSERT(prev);
452 SkOpSpanBase* next = this->next();
453 SkASSERT(next);
454 prev->setNext(next);
455 next->setPrev(prev);
456 this->segment()->release(this);
457 SkOpCoincidence* coincidence = this->globalState()->coincidence();
458 if (coincidence) {
459 coincidence->fixUp(this->ptT(), kept);
460 }
461 this->ptT()->setDeleted();
462 SkOpPtT* stopPtT = this->ptT();
463 SkOpPtT* testPtT = stopPtT;
464 const SkOpSpanBase* keptSpan = kept->span();
465 do {
466 if (this == testPtT->span()) {
467 testPtT->setSpan(keptSpan);
468 }
469 } while ((testPtT = testPtT->next()) != stopPtT);
470}
471
472void SkOpSpan::setOppSum(int oppSum) {
473 SkASSERT(!final());
474 if (fOppSum != SK_MinS32 && fOppSum != oppSum) {
475 this->globalState()->setWindingFailed();
476 return;
477 }
479 fOppSum = oppSum;
480}
481
482void SkOpSpan::setWindSum(int windSum) {
483 SkASSERT(!final());
484 if (fWindSum != SK_MinS32 && fWindSum != windSum) {
485 this->globalState()->setWindingFailed();
486 return;
487 }
489 fWindSum = windSum;
490}
#define test(name)
static float next(float f)
static float prev(float f)
#define check(reporter, ref, unref, make, kill)
Definition: RefCntTest.cpp:85
#define SkASSERT(cond)
Definition: SkAssert.h:116
static constexpr int32_t SK_MinS32
Definition: SkMath.h:22
#define DEBUG_LIMIT_WIND_SUM
#define FAIL_IF(cond)
bool between(double a, double b, double c)
#define SkOPASSERT(cond)
bool zero_or_one(double x)
static T SkTAbs(T value)
Definition: SkTemplates.h:43
SkDEBUGCODE(SK_SPI) SkThreadID SkGetThreadID()
void markCollapsed(SkOpPtT *)
void fixUp(SkOpPtT *deleted, const SkOpPtT *kept)
bool isEmpty() const
SkOpGlobalState * globalState() const
Definition: SkOpContour.h:139
SkOpContourHead * contourHead()
SkOpCoincidence * coincidence()
const SkOpSpanBase * span() const
Definition: SkOpSpan.h:154
SkPoint fPt
Definition: SkOpSpan.h:167
bool fDeleted
Definition: SkOpSpan.h:171
const SkOpPtT * next() const
Definition: SkOpSpan.h:93
double fT
Definition: SkOpSpan.h:166
bool deleted() const
Definition: SkOpSpan.h:71
SkOpGlobalState * globalState() const
Definition: SkOpSpan.cpp:100
SkOpPtT * oppPrev(const SkOpPtT *opp) const
Definition: SkOpSpan.h:104
void addOpp(SkOpPtT *opp, SkOpPtT *oppPrev)
Definition: SkOpSpan.h:34
void setSpan(const SkOpSpanBase *span)
Definition: SkOpSpan.h:150
bool ptAlreadySeen(const SkOpPtT *head) const
Definition: SkOpSpan.cpp:124
const SkOpSegment * segment() const
Definition: SkOpSpan.cpp:144
bool fDuplicatePt
Definition: SkOpSpan.h:172
const SkOpPtT * active() const
Definition: SkOpSpan.cpp:22
bool alias() const
Definition: SkOpSpan.cpp:18
bool fCoincident
Definition: SkOpSpan.h:174
void insert(SkOpPtT *span)
Definition: SkOpSpan.h:87
SkOpContour * contour() const
Definition: SkOpSpan.cpp:83
SkOpSpanBase * fSpan
Definition: SkOpSpan.h:169
void init(SkOpSpanBase *, double t, const SkPoint &, bool dup)
Definition: SkOpSpan.cpp:104
bool onEnd() const
Definition: SkOpSpan.cpp:115
SkOpPtT * prev()
Definition: SkOpSpan.cpp:134
void setDeleted()
Definition: SkOpSpan.cpp:152
SkOpPtT * fNext
Definition: SkOpSpan.h:170
const SkOpPtT * find(const SkOpSegment *) const
Definition: SkOpSpan.cpp:87
bool contains(const SkOpPtT *) const
Definition: SkOpSpan.cpp:36
bool duplicate() const
Definition: SkOpSpan.h:75
bool done() const
Definition: SkOpSegment.h:200
const SkOpSpanBase * tail() const
Definition: SkOpSegment.h:398
void markAllDone()
void release(const SkOpSpan *)
const SkOpSpan * head() const
Definition: SkOpSegment.h:234
SkOpContour * contour() const
Definition: SkOpSegment.h:130
void bumpCount()
Definition: SkOpSegment.h:113
const SkPoint & pt() const
Definition: SkOpSpan.h:306
Collapsed collapsed(double s, double e) const
Definition: SkOpSpan.cpp:169
SkOpAngle * fFromAngle
Definition: SkOpSpan.h:408
const SkOpSpan * prev() const
Definition: SkOpSpan.h:298
bool fAligned
Definition: SkOpSpan.h:411
bool containsCoinEnd(const SkOpSpanBase *coin) const
Definition: SkOpSpan.h:206
SkOpSpanBase * fCoinEnd
Definition: SkOpSpan.h:407
void merge(SkOpSpan *span)
Definition: SkOpSpan.cpp:259
bool mergeMatches(SkOpSpanBase *opp)
Definition: SkOpSpan.cpp:313
SkOpPtT fPtT
Definition: SkOpSpan.h:405
SkOpContour * contour() const
Definition: SkOpSpan.cpp:235
SkOpGlobalState * globalState() const
Definition: SkOpSpan.cpp:239
void initBase(SkOpSegment *parent, SkOpSpan *prev, double t, const SkPoint &pt)
Definition: SkOpSpan.cpp:243
bool addOpp(SkOpSpanBase *opp)
Definition: SkOpSpan.cpp:158
bool fChased
Definition: SkOpSpan.h:412
SkOpSpan * fPrev
Definition: SkOpSpan.h:409
bool contains(const SkOpSpanBase *) const
Definition: SkOpSpan.cpp:197
SkDEBUGCODE(int fCount;) SkDEBUGCODE(int fID
void setPrev(SkOpSpan *prev)
Definition: SkOpSpan.h:334
SkOpSegment * fSegment
Definition: SkOpSpan.h:406
double t() const
Definition: SkOpSpan.h:375
void checkForCollapsedCoincidence()
Definition: SkOpSpan.cpp:288
SkOpSpan * upCast()
Definition: SkOpSpan.h:383
int fSpanAdds
Definition: SkOpSpan.h:410
SkOpSegment * segment() const
Definition: SkOpSpan.h:318
const SkOpPtT * ptT() const
Definition: SkOpSpan.h:310
bool sortableTop(SkOpContour *)
int windSum() const
Definition: SkOpSpan.h:555
int computeWindSum()
Definition: SkOpSpan.cpp:378
bool insertCoincidence(const SkOpSegment *, bool flipped, bool ordered)
Definition: SkOpSpan.cpp:413
SkOpSpanBase * next() const
Definition: SkOpSpan.h:495
void setNext(SkOpSpanBase *nextT)
Definition: SkOpSpan.h:519
void setWindSum(int windSum)
Definition: SkOpSpan.cpp:482
int oppSum() const
Definition: SkOpSpan.h:500
bool containsCoincidence(const SkOpSegment *) const
Definition: SkOpSpan.cpp:387
void setOppSum(int oppSum)
Definition: SkOpSpan.cpp:472
void release(const SkOpPtT *)
Definition: SkOpSpan.cpp:446
void init(SkOpSegment *parent, SkOpSpan *prev, double t, const SkPoint &pt)
Definition: SkOpSpan.cpp:398
struct MyStruct s
GAsyncResult * result
static float max(float r, float g, float b)
Definition: hsl.cpp:49
static float min(float r, float g, float b)
Definition: hsl.cpp:48
int compare(const void *untyped_lhs, const void *untyped_rhs)
Definition: skdiff.h:161