1 /*
2 * Copyright 2012 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 "src/core/SkPointPriv.h"
8 #include "src/pathops/SkOpCoincidence.h"
9 #include "src/pathops/SkOpContour.h"
10 #include "src/pathops/SkOpSegment.h"
11 #include "src/pathops/SkPathWriter.h"
12
13 #include <utility>
14
15 /*
16 After computing raw intersections, post process all segments to:
17 - find small collections of points that can be collapsed to a single point
18 - find missing intersections to resolve differences caused by different algorithms
19
20 Consider segments containing tiny or small intervals. Consider coincident segments
21 because coincidence finds intersections through distance measurement that non-coincident
22 intersection tests cannot.
23 */
24
25 #define F (false) // discard the edge
26 #define T (true) // keep the edge
27
28 static const bool gUnaryActiveEdge[2][2] = {
29 // from=0 from=1
30 // to=0,1 to=0,1
31 {F, T}, {T, F},
32 };
33
34 static const bool gActiveEdge[kXOR_SkPathOp + 1][2][2][2][2] = {
35 // miFrom=0 miFrom=1
36 // miTo=0 miTo=1 miTo=0 miTo=1
37 // suFrom=0 1 suFrom=0 1 suFrom=0 1 suFrom=0 1
38 // suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1
39 {{{{F, F}, {F, F}}, {{T, F}, {T, F}}}, {{{T, T}, {F, F}}, {{F, T}, {T, F}}}}, // mi - su
40 {{{{F, F}, {F, F}}, {{F, T}, {F, T}}}, {{{F, F}, {T, T}}, {{F, T}, {T, F}}}}, // mi & su
41 {{{{F, T}, {T, F}}, {{T, T}, {F, F}}}, {{{T, F}, {T, F}}, {{F, F}, {F, F}}}}, // mi | su
42 {{{{F, T}, {T, F}}, {{T, F}, {F, T}}}, {{{T, F}, {F, T}}, {{F, T}, {T, F}}}}, // mi ^ su
43 };
44
45 #undef F
46 #undef T
47
activeAngle(SkOpSpanBase * start,SkOpSpanBase ** startPtr,SkOpSpanBase ** endPtr,bool * done)48 SkOpAngle* SkOpSegment::activeAngle(SkOpSpanBase* start, SkOpSpanBase** startPtr,
49 SkOpSpanBase** endPtr, bool* done) {
50 if (SkOpAngle* result = activeAngleInner(start, startPtr, endPtr, done)) {
51 return result;
52 }
53 if (SkOpAngle* result = activeAngleOther(start, startPtr, endPtr, done)) {
54 return result;
55 }
56 return nullptr;
57 }
58
activeAngleInner(SkOpSpanBase * start,SkOpSpanBase ** startPtr,SkOpSpanBase ** endPtr,bool * done)59 SkOpAngle* SkOpSegment::activeAngleInner(SkOpSpanBase* start, SkOpSpanBase** startPtr,
60 SkOpSpanBase** endPtr, bool* done) {
61 SkOpSpan* upSpan = start->upCastable();
62 if (upSpan) {
63 if (upSpan->windValue() || upSpan->oppValue()) {
64 SkOpSpanBase* next = upSpan->next();
65 if (!*endPtr) {
66 *startPtr = start;
67 *endPtr = next;
68 }
69 if (!upSpan->done()) {
70 if (upSpan->windSum() != SK_MinS32) {
71 return spanToAngle(start, next);
72 }
73 *done = false;
74 }
75 } else {
76 SkASSERT(upSpan->done());
77 }
78 }
79 SkOpSpan* downSpan = start->prev();
80 // edge leading into junction
81 if (downSpan) {
82 if (downSpan->windValue() || downSpan->oppValue()) {
83 if (!*endPtr) {
84 *startPtr = start;
85 *endPtr = downSpan;
86 }
87 if (!downSpan->done()) {
88 if (downSpan->windSum() != SK_MinS32) {
89 return spanToAngle(start, downSpan);
90 }
91 *done = false;
92 }
93 } else {
94 SkASSERT(downSpan->done());
95 }
96 }
97 return nullptr;
98 }
99
activeAngleOther(SkOpSpanBase * start,SkOpSpanBase ** startPtr,SkOpSpanBase ** endPtr,bool * done)100 SkOpAngle* SkOpSegment::activeAngleOther(SkOpSpanBase* start, SkOpSpanBase** startPtr,
101 SkOpSpanBase** endPtr, bool* done) {
102 SkOpPtT* oPtT = start->ptT()->next();
103 SkOpSegment* other = oPtT->segment();
104 SkOpSpanBase* oSpan = oPtT->span();
105 return other->activeAngleInner(oSpan, startPtr, endPtr, done);
106 }
107
activeOp(SkOpSpanBase * start,SkOpSpanBase * end,int xorMiMask,int xorSuMask,SkPathOp op)108 bool SkOpSegment::activeOp(SkOpSpanBase* start, SkOpSpanBase* end, int xorMiMask, int xorSuMask,
109 SkPathOp op) {
110 int sumMiWinding = this->updateWinding(end, start);
111 int sumSuWinding = this->updateOppWinding(end, start);
112 #if DEBUG_LIMIT_WIND_SUM
113 SkASSERT(abs(sumMiWinding) <= DEBUG_LIMIT_WIND_SUM);
114 SkASSERT(abs(sumSuWinding) <= DEBUG_LIMIT_WIND_SUM);
115 #endif
116 if (this->operand()) {
117 using std::swap;
118 swap(sumMiWinding, sumSuWinding);
119 }
120 return this->activeOp(xorMiMask, xorSuMask, start, end, op, &sumMiWinding, &sumSuWinding);
121 }
122
activeOp(int xorMiMask,int xorSuMask,SkOpSpanBase * start,SkOpSpanBase * end,SkPathOp op,int * sumMiWinding,int * sumSuWinding)123 bool SkOpSegment::activeOp(int xorMiMask, int xorSuMask, SkOpSpanBase* start, SkOpSpanBase* end,
124 SkPathOp op, int* sumMiWinding, int* sumSuWinding) {
125 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
126 this->setUpWindings(start, end, sumMiWinding, sumSuWinding,
127 &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
128 bool miFrom;
129 bool miTo;
130 bool suFrom;
131 bool suTo;
132 if (operand()) {
133 miFrom = (oppMaxWinding & xorMiMask) != 0;
134 miTo = (oppSumWinding & xorMiMask) != 0;
135 suFrom = (maxWinding & xorSuMask) != 0;
136 suTo = (sumWinding & xorSuMask) != 0;
137 } else {
138 miFrom = (maxWinding & xorMiMask) != 0;
139 miTo = (sumWinding & xorMiMask) != 0;
140 suFrom = (oppMaxWinding & xorSuMask) != 0;
141 suTo = (oppSumWinding & xorSuMask) != 0;
142 }
143 bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo];
144 #if DEBUG_ACTIVE_OP
145 SkDebugf("%s id=%d t=%1.9g tEnd=%1.9g op=%s miFrom=%d miTo=%d suFrom=%d suTo=%d result=%d\n",
146 __FUNCTION__, debugID(), start->t(), end->t(),
147 SkPathOpsDebug::kPathOpStr[op], miFrom, miTo, suFrom, suTo, result);
148 #endif
149 return result;
150 }
151
activeWinding(SkOpSpanBase * start,SkOpSpanBase * end)152 bool SkOpSegment::activeWinding(SkOpSpanBase* start, SkOpSpanBase* end) {
153 int sumWinding = updateWinding(end, start);
154 return activeWinding(start, end, &sumWinding);
155 }
156
activeWinding(SkOpSpanBase * start,SkOpSpanBase * end,int * sumWinding)157 bool SkOpSegment::activeWinding(SkOpSpanBase* start, SkOpSpanBase* end, int* sumWinding) {
158 int maxWinding;
159 setUpWinding(start, end, &maxWinding, sumWinding);
160 bool from = maxWinding != 0;
161 bool to = *sumWinding != 0;
162 bool result = gUnaryActiveEdge[from][to];
163 return result;
164 }
165
addCurveTo(const SkOpSpanBase * start,const SkOpSpanBase * end,SkPathWriter * path) const166 bool SkOpSegment::addCurveTo(const SkOpSpanBase* start, const SkOpSpanBase* end,
167 SkPathWriter* path) const {
168 const SkOpSpan* spanStart = start->starter(end);
169 FAIL_IF(spanStart->alreadyAdded());
170 const_cast<SkOpSpan*>(spanStart)->markAdded();
171 SkDCurveSweep curvePart;
172 start->segment()->subDivide(start, end, &curvePart.fCurve);
173 curvePart.setCurveHullSweep(fVerb);
174 SkPath::Verb verb = curvePart.isCurve() ? fVerb : SkPath::kLine_Verb;
175 path->deferredMove(start->ptT());
176 switch (verb) {
177 case SkPath::kLine_Verb:
178 FAIL_IF(!path->deferredLine(end->ptT()));
179 break;
180 case SkPath::kQuad_Verb:
181 path->quadTo(curvePart.fCurve.fQuad[1].asSkPoint(), end->ptT());
182 break;
183 case SkPath::kConic_Verb:
184 path->conicTo(curvePart.fCurve.fConic[1].asSkPoint(), end->ptT(),
185 curvePart.fCurve.fConic.fWeight);
186 break;
187 case SkPath::kCubic_Verb:
188 path->cubicTo(curvePart.fCurve.fCubic[1].asSkPoint(),
189 curvePart.fCurve.fCubic[2].asSkPoint(), end->ptT());
190 break;
191 default:
192 SkASSERT(0);
193 }
194 return true;
195 }
196
existing(double t,const SkOpSegment * opp) const197 const SkOpPtT* SkOpSegment::existing(double t, const SkOpSegment* opp) const {
198 const SkOpSpanBase* test = &fHead;
199 const SkOpPtT* testPtT;
200 SkPoint pt = this->ptAtT(t);
201 do {
202 testPtT = test->ptT();
203 if (testPtT->fT == t) {
204 break;
205 }
206 if (!this->match(testPtT, this, t, pt)) {
207 if (t < testPtT->fT) {
208 return nullptr;
209 }
210 continue;
211 }
212 if (!opp) {
213 return testPtT;
214 }
215 const SkOpPtT* loop = testPtT->next();
216 while (loop != testPtT) {
217 if (loop->segment() == this && loop->fT == t && loop->fPt == pt) {
218 goto foundMatch;
219 }
220 loop = loop->next();
221 }
222 return nullptr;
223 } while ((test = test->upCast()->next()));
224 foundMatch:
225 return opp && !test->contains(opp) ? nullptr : testPtT;
226 }
227
228 // break the span so that the coincident part does not change the angle of the remainder
addExpanded(double newT,const SkOpSpanBase * test,bool * startOver)229 bool SkOpSegment::addExpanded(double newT, const SkOpSpanBase* test, bool* startOver) {
230 if (this->contains(newT)) {
231 return true;
232 }
233 this->globalState()->resetAllocatedOpSpan();
234 FAIL_IF(!between(0, newT, 1));
235 SkOpPtT* newPtT = this->addT(newT);
236 *startOver |= this->globalState()->allocatedOpSpan();
237 if (!newPtT) {
238 return false;
239 }
240 newPtT->fPt = this->ptAtT(newT);
241 SkOpPtT* oppPrev = test->ptT()->oppPrev(newPtT);
242 if (oppPrev) {
243 // const cast away to change linked list; pt/t values stays unchanged
244 SkOpSpanBase* writableTest = const_cast<SkOpSpanBase*>(test);
245 writableTest->mergeMatches(newPtT->span());
246 writableTest->ptT()->addOpp(newPtT, oppPrev);
247 writableTest->checkForCollapsedCoincidence();
248 }
249 return true;
250 }
251
252 // Please keep this in sync with debugAddT()
addT(double t,const SkPoint & pt)253 SkOpPtT* SkOpSegment::addT(double t, const SkPoint& pt) {
254 debugValidate();
255 SkOpSpanBase* spanBase = &fHead;
256 do {
257 SkOpPtT* result = spanBase->ptT();
258 if (t == result->fT || (!zero_or_one(t) && this->match(result, this, t, pt))) {
259 spanBase->bumpSpanAdds();
260 return result;
261 }
262 if (t < result->fT) {
263 SkOpSpan* prev = result->span()->prev();
264 FAIL_WITH_NULL_IF(!prev);
265 // marks in global state that new op span has been allocated
266 SkOpSpan* span = this->insert(prev);
267 span->init(this, prev, t, pt);
268 this->debugValidate();
269 #if DEBUG_ADD_T
270 SkDebugf("%s insert t=%1.9g segID=%d spanID=%d\n", __FUNCTION__, t,
271 span->segment()->debugID(), span->debugID());
272 #endif
273 span->bumpSpanAdds();
274 return span->ptT();
275 }
276 FAIL_WITH_NULL_IF(spanBase == &fTail);
277 } while ((spanBase = spanBase->upCast()->next()));
278 SkASSERT(0);
279 return nullptr; // we never get here, but need this to satisfy compiler
280 }
281
addT(double t)282 SkOpPtT* SkOpSegment::addT(double t) {
283 return addT(t, this->ptAtT(t));
284 }
285
calcAngles()286 void SkOpSegment::calcAngles() {
287 bool activePrior = !fHead.isCanceled();
288 if (activePrior && !fHead.simple()) {
289 addStartSpan();
290 }
291 SkOpSpan* prior = &fHead;
292 SkOpSpanBase* spanBase = fHead.next();
293 while (spanBase != &fTail) {
294 if (activePrior) {
295 SkOpAngle* priorAngle = this->globalState()->allocator()->make<SkOpAngle>();
296 priorAngle->set(spanBase, prior);
297 spanBase->setFromAngle(priorAngle);
298 }
299 SkOpSpan* span = spanBase->upCast();
300 bool active = !span->isCanceled();
301 SkOpSpanBase* next = span->next();
302 if (active) {
303 SkOpAngle* angle = this->globalState()->allocator()->make<SkOpAngle>();
304 angle->set(span, next);
305 span->setToAngle(angle);
306 }
307 activePrior = active;
308 prior = span;
309 spanBase = next;
310 }
311 if (activePrior && !fTail.simple()) {
312 addEndSpan();
313 }
314 }
315
316 // Please keep this in sync with debugClearAll()
clearAll()317 void SkOpSegment::clearAll() {
318 SkOpSpan* span = &fHead;
319 do {
320 this->clearOne(span);
321 } while ((span = span->next()->upCastable()));
322 this->globalState()->coincidence()->release(this);
323 }
324
325 // Please keep this in sync with debugClearOne()
clearOne(SkOpSpan * span)326 void SkOpSegment::clearOne(SkOpSpan* span) {
327 span->setWindValue(0);
328 span->setOppValue(0);
329 this->markDone(span);
330 }
331
collapsed(double s,double e) const332 SkOpSpanBase::Collapsed SkOpSegment::collapsed(double s, double e) const {
333 const SkOpSpanBase* span = &fHead;
334 do {
335 SkOpSpanBase::Collapsed result = span->collapsed(s, e);
336 if (SkOpSpanBase::Collapsed::kNo != result) {
337 return result;
338 }
339 } while (span->upCastable() && (span = span->upCast()->next()));
340 return SkOpSpanBase::Collapsed::kNo;
341 }
342
ComputeOneSum(const SkOpAngle * baseAngle,SkOpAngle * nextAngle,SkOpAngle::IncludeType includeType)343 bool SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
344 SkOpAngle::IncludeType includeType) {
345 SkOpSegment* baseSegment = baseAngle->segment();
346 int sumMiWinding = baseSegment->updateWindingReverse(baseAngle);
347 int sumSuWinding;
348 bool binary = includeType >= SkOpAngle::kBinarySingle;
349 if (binary) {
350 sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle);
351 if (baseSegment->operand()) {
352 using std::swap;
353 swap(sumMiWinding, sumSuWinding);
354 }
355 }
356 SkOpSegment* nextSegment = nextAngle->segment();
357 int maxWinding, sumWinding;
358 SkOpSpanBase* last = nullptr;
359 if (binary) {
360 int oppMaxWinding, oppSumWinding;
361 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
362 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
363 if (!nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
364 nextAngle, &last)) {
365 return false;
366 }
367 } else {
368 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
369 &maxWinding, &sumWinding);
370 if (!nextSegment->markAngle(maxWinding, sumWinding, nextAngle, &last)) {
371 return false;
372 }
373 }
374 nextAngle->setLastMarked(last);
375 return true;
376 }
377
ComputeOneSumReverse(SkOpAngle * baseAngle,SkOpAngle * nextAngle,SkOpAngle::IncludeType includeType)378 bool SkOpSegment::ComputeOneSumReverse(SkOpAngle* baseAngle, SkOpAngle* nextAngle,
379 SkOpAngle::IncludeType includeType) {
380 SkOpSegment* baseSegment = baseAngle->segment();
381 int sumMiWinding = baseSegment->updateWinding(baseAngle);
382 int sumSuWinding;
383 bool binary = includeType >= SkOpAngle::kBinarySingle;
384 if (binary) {
385 sumSuWinding = baseSegment->updateOppWinding(baseAngle);
386 if (baseSegment->operand()) {
387 using std::swap;
388 swap(sumMiWinding, sumSuWinding);
389 }
390 }
391 SkOpSegment* nextSegment = nextAngle->segment();
392 int maxWinding, sumWinding;
393 SkOpSpanBase* last = nullptr;
394 if (binary) {
395 int oppMaxWinding, oppSumWinding;
396 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
397 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
398 if (!nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
399 nextAngle, &last)) {
400 return false;
401 }
402 } else {
403 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
404 &maxWinding, &sumWinding);
405 if (!nextSegment->markAngle(maxWinding, sumWinding, nextAngle, &last)) {
406 return false;
407 }
408 }
409 nextAngle->setLastMarked(last);
410 return true;
411 }
412
413 // at this point, the span is already ordered, or unorderable
computeSum(SkOpSpanBase * start,SkOpSpanBase * end,SkOpAngle::IncludeType includeType)414 int SkOpSegment::computeSum(SkOpSpanBase* start, SkOpSpanBase* end,
415 SkOpAngle::IncludeType includeType) {
416 SkASSERT(includeType != SkOpAngle::kUnaryXor);
417 SkOpAngle* firstAngle = this->spanToAngle(end, start);
418 if (nullptr == firstAngle || nullptr == firstAngle->next()) {
419 return SK_NaN32;
420 }
421 // if all angles have a computed winding,
422 // or if no adjacent angles are orderable,
423 // or if adjacent orderable angles have no computed winding,
424 // there's nothing to do
425 // if two orderable angles are adjacent, and both are next to orderable angles,
426 // and one has winding computed, transfer to the other
427 SkOpAngle* baseAngle = nullptr;
428 bool tryReverse = false;
429 // look for counterclockwise transfers
430 SkOpAngle* angle = firstAngle->previous();
431 SkOpAngle* next = angle->next();
432 firstAngle = next;
433 do {
434 SkOpAngle* prior = angle;
435 angle = next;
436 next = angle->next();
437 SkASSERT(prior->next() == angle);
438 SkASSERT(angle->next() == next);
439 if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
440 baseAngle = nullptr;
441 continue;
442 }
443 int testWinding = angle->starter()->windSum();
444 if (SK_MinS32 != testWinding) {
445 baseAngle = angle;
446 tryReverse = true;
447 continue;
448 }
449 if (baseAngle) {
450 ComputeOneSum(baseAngle, angle, includeType);
451 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : nullptr;
452 }
453 } while (next != firstAngle);
454 if (baseAngle && SK_MinS32 == firstAngle->starter()->windSum()) {
455 firstAngle = baseAngle;
456 tryReverse = true;
457 }
458 if (tryReverse) {
459 baseAngle = nullptr;
460 SkOpAngle* prior = firstAngle;
461 do {
462 angle = prior;
463 prior = angle->previous();
464 SkASSERT(prior->next() == angle);
465 next = angle->next();
466 if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
467 baseAngle = nullptr;
468 continue;
469 }
470 int testWinding = angle->starter()->windSum();
471 if (SK_MinS32 != testWinding) {
472 baseAngle = angle;
473 continue;
474 }
475 if (baseAngle) {
476 ComputeOneSumReverse(baseAngle, angle, includeType);
477 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : nullptr;
478 }
479 } while (prior != firstAngle);
480 }
481 return start->starter(end)->windSum();
482 }
483
contains(double newT) const484 bool SkOpSegment::contains(double newT) const {
485 const SkOpSpanBase* spanBase = &fHead;
486 do {
487 if (spanBase->ptT()->contains(this, newT)) {
488 return true;
489 }
490 if (spanBase == &fTail) {
491 break;
492 }
493 spanBase = spanBase->upCast()->next();
494 } while (true);
495 return false;
496 }
497
release(const SkOpSpan * span)498 void SkOpSegment::release(const SkOpSpan* span) {
499 if (span->done()) {
500 --fDoneCount;
501 }
502 --fCount;
503 SkOPASSERT(fCount >= fDoneCount);
504 }
505
506 #if DEBUG_ANGLE
507 // called only by debugCheckNearCoincidence
distSq(double t,const SkOpAngle * oppAngle) const508 double SkOpSegment::distSq(double t, const SkOpAngle* oppAngle) const {
509 SkDPoint testPt = this->dPtAtT(t);
510 SkDLine testPerp = {{ testPt, testPt }};
511 SkDVector slope = this->dSlopeAtT(t);
512 testPerp[1].fX += slope.fY;
513 testPerp[1].fY -= slope.fX;
514 SkIntersections i;
515 const SkOpSegment* oppSegment = oppAngle->segment();
516 (*CurveIntersectRay[oppSegment->verb()])(oppSegment->pts(), oppSegment->weight(), testPerp, &i);
517 double closestDistSq = SK_ScalarInfinity;
518 for (int index = 0; index < i.used(); ++index) {
519 if (!between(oppAngle->start()->t(), i[0][index], oppAngle->end()->t())) {
520 continue;
521 }
522 double testDistSq = testPt.distanceSquared(i.pt(index));
523 if (closestDistSq > testDistSq) {
524 closestDistSq = testDistSq;
525 }
526 }
527 return closestDistSq;
528 }
529 #endif
530
531 /*
532 The M and S variable name parts stand for the operators.
533 Mi stands for Minuend (see wiki subtraction, analogous to difference)
534 Su stands for Subtrahend
535 The Opp variable name part designates that the value is for the Opposite operator.
536 Opposite values result from combining coincident spans.
537 */
findNextOp(SkTDArray<SkOpSpanBase * > * chase,SkOpSpanBase ** nextStart,SkOpSpanBase ** nextEnd,bool * unsortable,bool * simple,SkPathOp op,int xorMiMask,int xorSuMask)538 SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBase** nextStart,
539 SkOpSpanBase** nextEnd, bool* unsortable, bool* simple,
540 SkPathOp op, int xorMiMask, int xorSuMask) {
541 SkOpSpanBase* start = *nextStart;
542 SkOpSpanBase* end = *nextEnd;
543 SkASSERT(start != end);
544 int step = start->step(end);
545 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
546 if ((*simple = other)) {
547 // mark the smaller of startIndex, endIndex done, and all adjacent
548 // spans with the same T value (but not 'other' spans)
549 #if DEBUG_WINDING
550 SkDebugf("%s simple\n", __FUNCTION__);
551 #endif
552 SkOpSpan* startSpan = start->starter(end);
553 if (startSpan->done()) {
554 return nullptr;
555 }
556 markDone(startSpan);
557 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
558 return other;
559 }
560 SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
561 SkASSERT(endNear == end); // is this ever not end?
562 SkASSERT(endNear);
563 SkASSERT(start != endNear);
564 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
565 // more than one viable candidate -- measure angles to find best
566 int calcWinding = computeSum(start, endNear, SkOpAngle::kBinaryOpp);
567 bool sortable = calcWinding != SK_NaN32;
568 if (!sortable) {
569 *unsortable = true;
570 markDone(start->starter(end));
571 return nullptr;
572 }
573 SkOpAngle* angle = this->spanToAngle(end, start);
574 if (angle->unorderable()) {
575 *unsortable = true;
576 markDone(start->starter(end));
577 return nullptr;
578 }
579 #if DEBUG_SORT
580 SkDebugf("%s\n", __FUNCTION__);
581 angle->debugLoop();
582 #endif
583 int sumMiWinding = updateWinding(end, start);
584 if (sumMiWinding == SK_MinS32) {
585 *unsortable = true;
586 markDone(start->starter(end));
587 return nullptr;
588 }
589 int sumSuWinding = updateOppWinding(end, start);
590 if (operand()) {
591 using std::swap;
592 swap(sumMiWinding, sumSuWinding);
593 }
594 SkOpAngle* nextAngle = angle->next();
595 const SkOpAngle* foundAngle = nullptr;
596 bool foundDone = false;
597 // iterate through the angle, and compute everyone's winding
598 SkOpSegment* nextSegment;
599 int activeCount = 0;
600 do {
601 nextSegment = nextAngle->segment();
602 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
603 nextAngle->end(), op, &sumMiWinding, &sumSuWinding);
604 if (activeAngle) {
605 ++activeCount;
606 if (!foundAngle || (foundDone && activeCount & 1)) {
607 foundAngle = nextAngle;
608 foundDone = nextSegment->done(nextAngle);
609 }
610 }
611 if (nextSegment->done()) {
612 continue;
613 }
614 if (!activeAngle) {
615 (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end(), nullptr);
616 }
617 SkOpSpanBase* last = nextAngle->lastMarked();
618 if (last) {
619 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
620 *chase->append() = last;
621 #if DEBUG_WINDING
622 SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__,
623 last->segment()->debugID(), last->debugID());
624 if (!last->final()) {
625 SkDebugf(" windSum=%d", last->upCast()->windSum());
626 }
627 SkDebugf("\n");
628 #endif
629 }
630 } while ((nextAngle = nextAngle->next()) != angle);
631 start->segment()->markDone(start->starter(end));
632 if (!foundAngle) {
633 return nullptr;
634 }
635 *nextStart = foundAngle->start();
636 *nextEnd = foundAngle->end();
637 nextSegment = foundAngle->segment();
638 #if DEBUG_WINDING
639 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
640 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
641 #endif
642 return nextSegment;
643 }
644
findNextWinding(SkTDArray<SkOpSpanBase * > * chase,SkOpSpanBase ** nextStart,SkOpSpanBase ** nextEnd,bool * unsortable)645 SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpanBase*>* chase,
646 SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd, bool* unsortable) {
647 SkOpSpanBase* start = *nextStart;
648 SkOpSpanBase* end = *nextEnd;
649 SkASSERT(start != end);
650 int step = start->step(end);
651 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
652 if (other) {
653 // mark the smaller of startIndex, endIndex done, and all adjacent
654 // spans with the same T value (but not 'other' spans)
655 #if DEBUG_WINDING
656 SkDebugf("%s simple\n", __FUNCTION__);
657 #endif
658 SkOpSpan* startSpan = start->starter(end);
659 if (startSpan->done()) {
660 return nullptr;
661 }
662 markDone(startSpan);
663 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
664 return other;
665 }
666 SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
667 SkASSERT(endNear == end); // is this ever not end?
668 SkASSERT(endNear);
669 SkASSERT(start != endNear);
670 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
671 // more than one viable candidate -- measure angles to find best
672 int calcWinding = computeSum(start, endNear, SkOpAngle::kUnaryWinding);
673 bool sortable = calcWinding != SK_NaN32;
674 if (!sortable) {
675 *unsortable = true;
676 markDone(start->starter(end));
677 return nullptr;
678 }
679 SkOpAngle* angle = this->spanToAngle(end, start);
680 if (angle->unorderable()) {
681 *unsortable = true;
682 markDone(start->starter(end));
683 return nullptr;
684 }
685 #if DEBUG_SORT
686 SkDebugf("%s\n", __FUNCTION__);
687 angle->debugLoop();
688 #endif
689 int sumWinding = updateWinding(end, start);
690 SkOpAngle* nextAngle = angle->next();
691 const SkOpAngle* foundAngle = nullptr;
692 bool foundDone = false;
693 // iterate through the angle, and compute everyone's winding
694 SkOpSegment* nextSegment;
695 int activeCount = 0;
696 do {
697 nextSegment = nextAngle->segment();
698 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
699 &sumWinding);
700 if (activeAngle) {
701 ++activeCount;
702 if (!foundAngle || (foundDone && activeCount & 1)) {
703 foundAngle = nextAngle;
704 foundDone = nextSegment->done(nextAngle);
705 }
706 }
707 if (nextSegment->done()) {
708 continue;
709 }
710 if (!activeAngle) {
711 (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end(), nullptr);
712 }
713 SkOpSpanBase* last = nextAngle->lastMarked();
714 if (last) {
715 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
716 *chase->append() = last;
717 #if DEBUG_WINDING
718 SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__,
719 last->segment()->debugID(), last->debugID());
720 if (!last->final()) {
721 SkDebugf(" windSum=%d", last->upCast()->windSum());
722 }
723 SkDebugf("\n");
724 #endif
725 }
726 } while ((nextAngle = nextAngle->next()) != angle);
727 start->segment()->markDone(start->starter(end));
728 if (!foundAngle) {
729 return nullptr;
730 }
731 *nextStart = foundAngle->start();
732 *nextEnd = foundAngle->end();
733 nextSegment = foundAngle->segment();
734 #if DEBUG_WINDING
735 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
736 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
737 #endif
738 return nextSegment;
739 }
740
findNextXor(SkOpSpanBase ** nextStart,SkOpSpanBase ** nextEnd,bool * unsortable)741 SkOpSegment* SkOpSegment::findNextXor(SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd,
742 bool* unsortable) {
743 SkOpSpanBase* start = *nextStart;
744 SkOpSpanBase* end = *nextEnd;
745 SkASSERT(start != end);
746 int step = start->step(end);
747 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStart
748 if (other) {
749 // mark the smaller of startIndex, endIndex done, and all adjacent
750 // spans with the same T value (but not 'other' spans)
751 #if DEBUG_WINDING
752 SkDebugf("%s simple\n", __FUNCTION__);
753 #endif
754 SkOpSpan* startSpan = start->starter(end);
755 if (startSpan->done()) {
756 return nullptr;
757 }
758 markDone(startSpan);
759 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
760 return other;
761 }
762 SkDEBUGCODE(SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() \
763 : (*nextStart)->prev());
764 SkASSERT(endNear == end); // is this ever not end?
765 SkASSERT(endNear);
766 SkASSERT(start != endNear);
767 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
768 SkOpAngle* angle = this->spanToAngle(end, start);
769 if (!angle || angle->unorderable()) {
770 *unsortable = true;
771 markDone(start->starter(end));
772 return nullptr;
773 }
774 #if DEBUG_SORT
775 SkDebugf("%s\n", __FUNCTION__);
776 angle->debugLoop();
777 #endif
778 SkOpAngle* nextAngle = angle->next();
779 const SkOpAngle* foundAngle = nullptr;
780 bool foundDone = false;
781 // iterate through the angle, and compute everyone's winding
782 SkOpSegment* nextSegment;
783 int activeCount = 0;
784 do {
785 if (!nextAngle) {
786 return nullptr;
787 }
788 nextSegment = nextAngle->segment();
789 ++activeCount;
790 if (!foundAngle || (foundDone && activeCount & 1)) {
791 foundAngle = nextAngle;
792 if (!(foundDone = nextSegment->done(nextAngle))) {
793 break;
794 }
795 }
796 nextAngle = nextAngle->next();
797 } while (nextAngle != angle);
798 start->segment()->markDone(start->starter(end));
799 if (!foundAngle) {
800 return nullptr;
801 }
802 *nextStart = foundAngle->start();
803 *nextEnd = foundAngle->end();
804 nextSegment = foundAngle->segment();
805 #if DEBUG_WINDING
806 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
807 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
808 #endif
809 return nextSegment;
810 }
811
globalState() const812 SkOpGlobalState* SkOpSegment::globalState() const {
813 return contour()->globalState();
814 }
815
init(SkPoint pts[],SkScalar weight,SkOpContour * contour,SkPath::Verb verb)816 void SkOpSegment::init(SkPoint pts[], SkScalar weight, SkOpContour* contour, SkPath::Verb verb) {
817 fContour = contour;
818 fNext = nullptr;
819 fPts = pts;
820 fWeight = weight;
821 fVerb = verb;
822 fCount = 0;
823 fDoneCount = 0;
824 fVisited = false;
825 SkOpSpan* zeroSpan = &fHead;
826 zeroSpan->init(this, nullptr, 0, fPts[0]);
827 SkOpSpanBase* oneSpan = &fTail;
828 zeroSpan->setNext(oneSpan);
829 oneSpan->initBase(this, zeroSpan, 1, fPts[SkPathOpsVerbToPoints(fVerb)]);
830 SkDEBUGCODE(fID = globalState()->nextSegmentID());
831 }
832
isClose(double t,const SkOpSegment * opp) const833 bool SkOpSegment::isClose(double t, const SkOpSegment* opp) const {
834 SkDPoint cPt = this->dPtAtT(t);
835 SkDVector dxdy = (*CurveDSlopeAtT[this->verb()])(this->pts(), this->weight(), t);
836 SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }};
837 SkIntersections i;
838 (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(), perp, &i);
839 int used = i.used();
840 for (int index = 0; index < used; ++index) {
841 if (cPt.roughlyEqual(i.pt(index))) {
842 return true;
843 }
844 }
845 return false;
846 }
847
isXor() const848 bool SkOpSegment::isXor() const {
849 return fContour->isXor();
850 }
851
markAllDone()852 void SkOpSegment::markAllDone() {
853 SkOpSpan* span = this->head();
854 do {
855 this->markDone(span);
856 } while ((span = span->next()->upCastable()));
857 }
858
markAndChaseDone(SkOpSpanBase * start,SkOpSpanBase * end,SkOpSpanBase ** found)859 bool SkOpSegment::markAndChaseDone(SkOpSpanBase* start, SkOpSpanBase* end, SkOpSpanBase** found) {
860 int step = start->step(end);
861 SkOpSpan* minSpan = start->starter(end);
862 markDone(minSpan);
863 SkOpSpanBase* last = nullptr;
864 SkOpSegment* other = this;
865 SkOpSpan* priorDone = nullptr;
866 SkOpSpan* lastDone = nullptr;
867 int safetyNet = 100000;
868 while ((other = other->nextChase(&start, &step, &minSpan, &last))) {
869 if (!--safetyNet) {
870 return false;
871 }
872 if (other->done()) {
873 SkASSERT(!last);
874 break;
875 }
876 if (lastDone == minSpan || priorDone == minSpan) {
877 if (found) {
878 *found = nullptr;
879 }
880 return true;
881 }
882 other->markDone(minSpan);
883 priorDone = lastDone;
884 lastDone = minSpan;
885 }
886 if (found) {
887 *found = last;
888 }
889 return true;
890 }
891
markAndChaseWinding(SkOpSpanBase * start,SkOpSpanBase * end,int winding,SkOpSpanBase ** lastPtr)892 bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end, int winding,
893 SkOpSpanBase** lastPtr) {
894 SkOpSpan* spanStart = start->starter(end);
895 int step = start->step(end);
896 bool success = markWinding(spanStart, winding);
897 SkOpSpanBase* last = nullptr;
898 SkOpSegment* other = this;
899 int safetyNet = 100000;
900 while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
901 if (!--safetyNet) {
902 return false;
903 }
904 if (spanStart->windSum() != SK_MinS32) {
905 // SkASSERT(spanStart->windSum() == winding); // FIXME: is this assert too aggressive?
906 SkASSERT(!last);
907 break;
908 }
909 (void) other->markWinding(spanStart, winding);
910 }
911 if (lastPtr) {
912 *lastPtr = last;
913 }
914 return success;
915 }
916
markAndChaseWinding(SkOpSpanBase * start,SkOpSpanBase * end,int winding,int oppWinding,SkOpSpanBase ** lastPtr)917 bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end,
918 int winding, int oppWinding, SkOpSpanBase** lastPtr) {
919 SkOpSpan* spanStart = start->starter(end);
920 int step = start->step(end);
921 bool success = markWinding(spanStart, winding, oppWinding);
922 SkOpSpanBase* last = nullptr;
923 SkOpSegment* other = this;
924 int safetyNet = 100000;
925 while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
926 if (!--safetyNet) {
927 return false;
928 }
929 if (spanStart->windSum() != SK_MinS32) {
930 if (this->operand() == other->operand()) {
931 if (spanStart->windSum() != winding || spanStart->oppSum() != oppWinding) {
932 this->globalState()->setWindingFailed();
933 return true; // ... but let it succeed anyway
934 }
935 } else {
936 FAIL_IF(spanStart->windSum() != oppWinding);
937 FAIL_IF(spanStart->oppSum() != winding);
938 }
939 SkASSERT(!last);
940 break;
941 }
942 if (this->operand() == other->operand()) {
943 (void) other->markWinding(spanStart, winding, oppWinding);
944 } else {
945 (void) other->markWinding(spanStart, oppWinding, winding);
946 }
947 }
948 if (lastPtr) {
949 *lastPtr = last;
950 }
951 return success;
952 }
953
markAngle(int maxWinding,int sumWinding,const SkOpAngle * angle,SkOpSpanBase ** result)954 bool SkOpSegment::markAngle(int maxWinding, int sumWinding, const SkOpAngle* angle,
955 SkOpSpanBase** result) {
956 SkASSERT(angle->segment() == this);
957 if (UseInnerWinding(maxWinding, sumWinding)) {
958 maxWinding = sumWinding;
959 }
960 if (!markAndChaseWinding(angle->start(), angle->end(), maxWinding, result)) {
961 return false;
962 }
963 #if DEBUG_WINDING
964 SkOpSpanBase* last = *result;
965 if (last) {
966 SkDebugf("%s last seg=%d span=%d", __FUNCTION__,
967 last->segment()->debugID(), last->debugID());
968 if (!last->final()) {
969 SkDebugf(" windSum=");
970 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
971 }
972 SkDebugf("\n");
973 }
974 #endif
975 return true;
976 }
977
markAngle(int maxWinding,int sumWinding,int oppMaxWinding,int oppSumWinding,const SkOpAngle * angle,SkOpSpanBase ** result)978 bool SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWinding,
979 int oppSumWinding, const SkOpAngle* angle, SkOpSpanBase** result) {
980 SkASSERT(angle->segment() == this);
981 if (UseInnerWinding(maxWinding, sumWinding)) {
982 maxWinding = sumWinding;
983 }
984 if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumWinding)) {
985 oppMaxWinding = oppSumWinding;
986 }
987 // caller doesn't require that this marks anything
988 if (!markAndChaseWinding(angle->start(), angle->end(), maxWinding, oppMaxWinding, result)) {
989 return false;
990 }
991 #if DEBUG_WINDING
992 if (result) {
993 SkOpSpanBase* last = *result;
994 if (last) {
995 SkDebugf("%s last segment=%d span=%d", __FUNCTION__,
996 last->segment()->debugID(), last->debugID());
997 if (!last->final()) {
998 SkDebugf(" windSum=");
999 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
1000 }
1001 SkDebugf(" \n");
1002 }
1003 }
1004 #endif
1005 return true;
1006 }
1007
markDone(SkOpSpan * span)1008 void SkOpSegment::markDone(SkOpSpan* span) {
1009 SkASSERT(this == span->segment());
1010 if (span->done()) {
1011 return;
1012 }
1013 #if DEBUG_MARK_DONE
1014 debugShowNewWinding(__FUNCTION__, span, span->windSum(), span->oppSum());
1015 #endif
1016 span->setDone(true);
1017 ++fDoneCount;
1018 debugValidate();
1019 }
1020
markWinding(SkOpSpan * span,int winding)1021 bool SkOpSegment::markWinding(SkOpSpan* span, int winding) {
1022 SkASSERT(this == span->segment());
1023 SkASSERT(winding);
1024 if (span->done()) {
1025 return false;
1026 }
1027 #if DEBUG_MARK_DONE
1028 debugShowNewWinding(__FUNCTION__, span, winding);
1029 #endif
1030 span->setWindSum(winding);
1031 debugValidate();
1032 return true;
1033 }
1034
markWinding(SkOpSpan * span,int winding,int oppWinding)1035 bool SkOpSegment::markWinding(SkOpSpan* span, int winding, int oppWinding) {
1036 SkASSERT(this == span->segment());
1037 SkASSERT(winding || oppWinding);
1038 if (span->done()) {
1039 return false;
1040 }
1041 #if DEBUG_MARK_DONE
1042 debugShowNewWinding(__FUNCTION__, span, winding, oppWinding);
1043 #endif
1044 span->setWindSum(winding);
1045 span->setOppSum(oppWinding);
1046 debugValidate();
1047 return true;
1048 }
1049
match(const SkOpPtT * base,const SkOpSegment * testParent,double testT,const SkPoint & testPt) const1050 bool SkOpSegment::match(const SkOpPtT* base, const SkOpSegment* testParent, double testT,
1051 const SkPoint& testPt) const {
1052 SkASSERT(this == base->segment());
1053 if (this == testParent) {
1054 if (precisely_equal(base->fT, testT)) {
1055 return true;
1056 }
1057 }
1058 if (!SkDPoint::ApproximatelyEqual(testPt, base->fPt)) {
1059 return false;
1060 }
1061 return this != testParent || !this->ptsDisjoint(base->fT, base->fPt, testT, testPt);
1062 }
1063
set_last(SkOpSpanBase ** last,SkOpSpanBase * endSpan)1064 static SkOpSegment* set_last(SkOpSpanBase** last, SkOpSpanBase* endSpan) {
1065 if (last) {
1066 *last = endSpan;
1067 }
1068 return nullptr;
1069 }
1070
nextChase(SkOpSpanBase ** startPtr,int * stepPtr,SkOpSpan ** minPtr,SkOpSpanBase ** last) const1071 SkOpSegment* SkOpSegment::nextChase(SkOpSpanBase** startPtr, int* stepPtr, SkOpSpan** minPtr,
1072 SkOpSpanBase** last) const {
1073 SkOpSpanBase* origStart = *startPtr;
1074 int step = *stepPtr;
1075 SkOpSpanBase* endSpan = step > 0 ? origStart->upCast()->next() : origStart->prev();
1076 SkASSERT(endSpan);
1077 SkOpAngle* angle = step > 0 ? endSpan->fromAngle() : endSpan->upCast()->toAngle();
1078 SkOpSpanBase* foundSpan;
1079 SkOpSpanBase* otherEnd;
1080 SkOpSegment* other;
1081 if (angle == nullptr) {
1082 if (endSpan->t() != 0 && endSpan->t() != 1) {
1083 return nullptr;
1084 }
1085 SkOpPtT* otherPtT = endSpan->ptT()->next();
1086 other = otherPtT->segment();
1087 foundSpan = otherPtT->span();
1088 otherEnd = step > 0
1089 ? foundSpan->upCastable() ? foundSpan->upCast()->next() : nullptr
1090 : foundSpan->prev();
1091 } else {
1092 int loopCount = angle->loopCount();
1093 if (loopCount > 2) {
1094 return set_last(last, endSpan);
1095 }
1096 const SkOpAngle* next = angle->next();
1097 if (nullptr == next) {
1098 return nullptr;
1099 }
1100 #if DEBUG_WINDING
1101 if (angle->debugSign() != next->debugSign() && !angle->segment()->contour()->isXor()
1102 && !next->segment()->contour()->isXor()) {
1103 SkDebugf("%s mismatched signs\n", __FUNCTION__);
1104 }
1105 #endif
1106 other = next->segment();
1107 foundSpan = endSpan = next->start();
1108 otherEnd = next->end();
1109 }
1110 if (!otherEnd) {
1111 return nullptr;
1112 }
1113 int foundStep = foundSpan->step(otherEnd);
1114 if (*stepPtr != foundStep) {
1115 return set_last(last, endSpan);
1116 }
1117 SkASSERT(*startPtr);
1118 // SkASSERT(otherEnd >= 0);
1119 SkOpSpan* origMin = step < 0 ? origStart->prev() : origStart->upCast();
1120 SkOpSpan* foundMin = foundSpan->starter(otherEnd);
1121 if (foundMin->windValue() != origMin->windValue()
1122 || foundMin->oppValue() != origMin->oppValue()) {
1123 return set_last(last, endSpan);
1124 }
1125 *startPtr = foundSpan;
1126 *stepPtr = foundStep;
1127 if (minPtr) {
1128 *minPtr = foundMin;
1129 }
1130 return other;
1131 }
1132
1133 // Please keep this in sync with DebugClearVisited()
ClearVisited(SkOpSpanBase * span)1134 void SkOpSegment::ClearVisited(SkOpSpanBase* span) {
1135 // reset visited flag back to false
1136 do {
1137 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
1138 while ((ptT = ptT->next()) != stopPtT) {
1139 SkOpSegment* opp = ptT->segment();
1140 opp->resetVisited();
1141 }
1142 } while (!span->final() && (span = span->upCast()->next()));
1143 }
1144
1145 // Please keep this in sync with debugMissingCoincidence()
1146 // look for pairs of undetected coincident curves
1147 // assumes that segments going in have visited flag clear
1148 // Even though pairs of curves correct detect coincident runs, a run may be missed
1149 // if the coincidence is a product of multiple intersections. For instance, given
1150 // curves A, B, and C:
1151 // A-B intersect at a point 1; A-C and B-C intersect at point 2, so near
1152 // the end of C that the intersection is replaced with the end of C.
1153 // Even though A-B correctly do not detect an intersection at point 2,
1154 // the resulting run from point 1 to point 2 is coincident on A and B.
missingCoincidence()1155 bool SkOpSegment::missingCoincidence() {
1156 if (this->done()) {
1157 return false;
1158 }
1159 SkOpSpan* prior = nullptr;
1160 SkOpSpanBase* spanBase = &fHead;
1161 bool result = false;
1162 int safetyNet = 100000;
1163 do {
1164 SkOpPtT* ptT = spanBase->ptT(), * spanStopPtT = ptT;
1165 SkOPASSERT(ptT->span() == spanBase);
1166 while ((ptT = ptT->next()) != spanStopPtT) {
1167 if (!--safetyNet) {
1168 return false;
1169 }
1170 if (ptT->deleted()) {
1171 continue;
1172 }
1173 SkOpSegment* opp = ptT->span()->segment();
1174 if (opp->done()) {
1175 continue;
1176 }
1177 // when opp is encounted the 1st time, continue; on 2nd encounter, look for coincidence
1178 if (!opp->visited()) {
1179 continue;
1180 }
1181 if (spanBase == &fHead) {
1182 continue;
1183 }
1184 if (ptT->segment() == this) {
1185 continue;
1186 }
1187 SkOpSpan* span = spanBase->upCastable();
1188 // FIXME?: this assumes that if the opposite segment is coincident then no more
1189 // coincidence needs to be detected. This may not be true.
1190 if (span && span->containsCoincidence(opp)) {
1191 continue;
1192 }
1193 if (spanBase->containsCoinEnd(opp)) {
1194 continue;
1195 }
1196 SkOpPtT* priorPtT = nullptr, * priorStopPtT;
1197 // find prior span containing opp segment
1198 SkOpSegment* priorOpp = nullptr;
1199 SkOpSpan* priorTest = spanBase->prev();
1200 while (!priorOpp && priorTest) {
1201 priorStopPtT = priorPtT = priorTest->ptT();
1202 while ((priorPtT = priorPtT->next()) != priorStopPtT) {
1203 if (priorPtT->deleted()) {
1204 continue;
1205 }
1206 SkOpSegment* segment = priorPtT->span()->segment();
1207 if (segment == opp) {
1208 prior = priorTest;
1209 priorOpp = opp;
1210 break;
1211 }
1212 }
1213 priorTest = priorTest->prev();
1214 }
1215 if (!priorOpp) {
1216 continue;
1217 }
1218 if (priorPtT == ptT) {
1219 continue;
1220 }
1221 SkOpPtT* oppStart = prior->ptT();
1222 SkOpPtT* oppEnd = spanBase->ptT();
1223 bool swapped = priorPtT->fT > ptT->fT;
1224 if (swapped) {
1225 using std::swap;
1226 swap(priorPtT, ptT);
1227 swap(oppStart, oppEnd);
1228 }
1229 SkOpCoincidence* coincidences = this->globalState()->coincidence();
1230 SkOpPtT* rootPriorPtT = priorPtT->span()->ptT();
1231 SkOpPtT* rootPtT = ptT->span()->ptT();
1232 SkOpPtT* rootOppStart = oppStart->span()->ptT();
1233 SkOpPtT* rootOppEnd = oppEnd->span()->ptT();
1234 if (coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) {
1235 goto swapBack;
1236 }
1237 if (this->testForCoincidence(rootPriorPtT, rootPtT, prior, spanBase, opp)) {
1238 // mark coincidence
1239 #if DEBUG_COINCIDENCE_VERBOSE
1240 SkDebugf("%s coinSpan=%d endSpan=%d oppSpan=%d oppEndSpan=%d\n", __FUNCTION__,
1241 rootPriorPtT->debugID(), rootPtT->debugID(), rootOppStart->debugID(),
1242 rootOppEnd->debugID());
1243 #endif
1244 if (!coincidences->extend(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) {
1245 coincidences->add(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd);
1246 }
1247 #if DEBUG_COINCIDENCE
1248 SkASSERT(coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd));
1249 #endif
1250 result = true;
1251 }
1252 swapBack:
1253 if (swapped) {
1254 using std::swap;
1255 swap(priorPtT, ptT);
1256 }
1257 }
1258 } while ((spanBase = spanBase->final() ? nullptr : spanBase->upCast()->next()));
1259 ClearVisited(&fHead);
1260 return result;
1261 }
1262
1263 // please keep this in sync with debugMoveMultiples()
1264 // if a span has more than one intersection, merge the other segments' span as needed
moveMultiples()1265 bool SkOpSegment::moveMultiples() {
1266 debugValidate();
1267 SkOpSpanBase* test = &fHead;
1268 do {
1269 int addCount = test->spanAddsCount();
1270 // FAIL_IF(addCount < 1);
1271 if (addCount <= 1) {
1272 continue;
1273 }
1274 SkOpPtT* startPtT = test->ptT();
1275 SkOpPtT* testPtT = startPtT;
1276 int safetyHatch = 1000000;
1277 do { // iterate through all spans associated with start
1278 if (!--safetyHatch) {
1279 return false;
1280 }
1281 SkOpSpanBase* oppSpan = testPtT->span();
1282 if (oppSpan->spanAddsCount() == addCount) {
1283 continue;
1284 }
1285 if (oppSpan->deleted()) {
1286 continue;
1287 }
1288 SkOpSegment* oppSegment = oppSpan->segment();
1289 if (oppSegment == this) {
1290 continue;
1291 }
1292 // find range of spans to consider merging
1293 SkOpSpanBase* oppPrev = oppSpan;
1294 SkOpSpanBase* oppFirst = oppSpan;
1295 while ((oppPrev = oppPrev->prev())) {
1296 if (!roughly_equal(oppPrev->t(), oppSpan->t())) {
1297 break;
1298 }
1299 if (oppPrev->spanAddsCount() == addCount) {
1300 continue;
1301 }
1302 if (oppPrev->deleted()) {
1303 continue;
1304 }
1305 oppFirst = oppPrev;
1306 }
1307 SkOpSpanBase* oppNext = oppSpan;
1308 SkOpSpanBase* oppLast = oppSpan;
1309 while ((oppNext = oppNext->final() ? nullptr : oppNext->upCast()->next())) {
1310 if (!roughly_equal(oppNext->t(), oppSpan->t())) {
1311 break;
1312 }
1313 if (oppNext->spanAddsCount() == addCount) {
1314 continue;
1315 }
1316 if (oppNext->deleted()) {
1317 continue;
1318 }
1319 oppLast = oppNext;
1320 }
1321 if (oppFirst == oppLast) {
1322 continue;
1323 }
1324 SkOpSpanBase* oppTest = oppFirst;
1325 do {
1326 if (oppTest == oppSpan) {
1327 continue;
1328 }
1329 // check to see if the candidate meets specific criteria:
1330 // it contains spans of segments in test's loop but not including 'this'
1331 SkOpPtT* oppStartPtT = oppTest->ptT();
1332 SkOpPtT* oppPtT = oppStartPtT;
1333 while ((oppPtT = oppPtT->next()) != oppStartPtT) {
1334 SkOpSegment* oppPtTSegment = oppPtT->segment();
1335 if (oppPtTSegment == this) {
1336 goto tryNextSpan;
1337 }
1338 SkOpPtT* matchPtT = startPtT;
1339 do {
1340 if (matchPtT->segment() == oppPtTSegment) {
1341 goto foundMatch;
1342 }
1343 } while ((matchPtT = matchPtT->next()) != startPtT);
1344 goto tryNextSpan;
1345 foundMatch: // merge oppTest and oppSpan
1346 oppSegment->debugValidate();
1347 oppTest->mergeMatches(oppSpan);
1348 oppTest->addOpp(oppSpan);
1349 oppSegment->debugValidate();
1350 goto checkNextSpan;
1351 }
1352 tryNextSpan:
1353 ;
1354 } while (oppTest != oppLast && (oppTest = oppTest->upCast()->next()));
1355 } while ((testPtT = testPtT->next()) != startPtT);
1356 checkNextSpan:
1357 ;
1358 } while ((test = test->final() ? nullptr : test->upCast()->next()));
1359 debugValidate();
1360 return true;
1361 }
1362
1363 // adjacent spans may have points close by
spansNearby(const SkOpSpanBase * refSpan,const SkOpSpanBase * checkSpan,bool * found) const1364 bool SkOpSegment::spansNearby(const SkOpSpanBase* refSpan, const SkOpSpanBase* checkSpan,
1365 bool* found) const {
1366 const SkOpPtT* refHead = refSpan->ptT();
1367 const SkOpPtT* checkHead = checkSpan->ptT();
1368 // if the first pt pair from adjacent spans are far apart, assume that all are far enough apart
1369 if (!SkDPoint::WayRoughlyEqual(refHead->fPt, checkHead->fPt)) {
1370 #if DEBUG_COINCIDENCE
1371 // verify that no combination of points are close
1372 const SkOpPtT* dBugRef = refHead;
1373 do {
1374 const SkOpPtT* dBugCheck = checkHead;
1375 do {
1376 SkOPASSERT(!SkDPoint::ApproximatelyEqual(dBugRef->fPt, dBugCheck->fPt));
1377 dBugCheck = dBugCheck->next();
1378 } while (dBugCheck != checkHead);
1379 dBugRef = dBugRef->next();
1380 } while (dBugRef != refHead);
1381 #endif
1382 *found = false;
1383 return true;
1384 }
1385 // check only unique points
1386 SkScalar distSqBest = SK_ScalarMax;
1387 const SkOpPtT* refBest = nullptr;
1388 const SkOpPtT* checkBest = nullptr;
1389 const SkOpPtT* ref = refHead;
1390 do {
1391 if (ref->deleted()) {
1392 continue;
1393 }
1394 while (ref->ptAlreadySeen(refHead)) {
1395 ref = ref->next();
1396 if (ref == refHead) {
1397 goto doneCheckingDistance;
1398 }
1399 }
1400 const SkOpPtT* check = checkHead;
1401 const SkOpSegment* refSeg = ref->segment();
1402 int escapeHatch = 100000; // defend against infinite loops
1403 do {
1404 if (check->deleted()) {
1405 continue;
1406 }
1407 while (check->ptAlreadySeen(checkHead)) {
1408 check = check->next();
1409 if (check == checkHead) {
1410 goto nextRef;
1411 }
1412 }
1413 SkScalar distSq = SkPointPriv::DistanceToSqd(ref->fPt, check->fPt);
1414 if (distSqBest > distSq && (refSeg != check->segment()
1415 || !refSeg->ptsDisjoint(*ref, *check))) {
1416 distSqBest = distSq;
1417 refBest = ref;
1418 checkBest = check;
1419 }
1420 if (--escapeHatch <= 0) {
1421 return false;
1422 }
1423 } while ((check = check->next()) != checkHead);
1424 nextRef:
1425 ;
1426 } while ((ref = ref->next()) != refHead);
1427 doneCheckingDistance:
1428 *found = checkBest && refBest->segment()->match(refBest, checkBest->segment(), checkBest->fT,
1429 checkBest->fPt);
1430 return true;
1431 }
1432
1433 // Please keep this function in sync with debugMoveNearby()
1434 // Move nearby t values and pts so they all hang off the same span. Alignment happens later.
moveNearby()1435 bool SkOpSegment::moveNearby() {
1436 debugValidate();
1437 // release undeleted spans pointing to this seg that are linked to the primary span
1438 SkOpSpanBase* spanBase = &fHead;
1439 int escapeHatch = 9999; // the largest count for a regular test is 50; for a fuzzer, 500
1440 do {
1441 SkOpPtT* ptT = spanBase->ptT();
1442 const SkOpPtT* headPtT = ptT;
1443 while ((ptT = ptT->next()) != headPtT) {
1444 if (!--escapeHatch) {
1445 return false;
1446 }
1447 SkOpSpanBase* test = ptT->span();
1448 if (ptT->segment() == this && !ptT->deleted() && test != spanBase
1449 && test->ptT() == ptT) {
1450 if (test->final()) {
1451 if (spanBase == &fHead) {
1452 this->clearAll();
1453 return true;
1454 }
1455 spanBase->upCast()->release(ptT);
1456 } else if (test->prev()) {
1457 test->upCast()->release(headPtT);
1458 }
1459 break;
1460 }
1461 }
1462 spanBase = spanBase->upCast()->next();
1463 } while (!spanBase->final());
1464 // This loop looks for adjacent spans which are near by
1465 spanBase = &fHead;
1466 do { // iterate through all spans associated with start
1467 SkOpSpanBase* test = spanBase->upCast()->next();
1468 bool found;
1469 if (!this->spansNearby(spanBase, test, &found)) {
1470 return false;
1471 }
1472 if (found) {
1473 if (test->final()) {
1474 if (spanBase->prev()) {
1475 test->merge(spanBase->upCast());
1476 } else {
1477 this->clearAll();
1478 return true;
1479 }
1480 } else {
1481 spanBase->merge(test->upCast());
1482 }
1483 }
1484 spanBase = test;
1485 } while (!spanBase->final());
1486 debugValidate();
1487 return true;
1488 }
1489
operand() const1490 bool SkOpSegment::operand() const {
1491 return fContour->operand();
1492 }
1493
oppXor() const1494 bool SkOpSegment::oppXor() const {
1495 return fContour->oppXor();
1496 }
1497
ptsDisjoint(double t1,const SkPoint & pt1,double t2,const SkPoint & pt2) const1498 bool SkOpSegment::ptsDisjoint(double t1, const SkPoint& pt1, double t2, const SkPoint& pt2) const {
1499 if (fVerb == SkPath::kLine_Verb) {
1500 return false;
1501 }
1502 // quads (and cubics) can loop back to nearly a line so that an opposite curve
1503 // hits in two places with very different t values.
1504 // OPTIMIZATION: curves could be preflighted so that, for example, something like
1505 // 'controls contained by ends' could avoid this check for common curves
1506 // 'ends are extremes in x or y' is cheaper to compute and real-world common
1507 // on the other hand, the below check is relatively inexpensive
1508 double midT = (t1 + t2) / 2;
1509 SkPoint midPt = this->ptAtT(midT);
1510 double seDistSq = std::max(SkPointPriv::DistanceToSqd(pt1, pt2) * 2, FLT_EPSILON * 2);
1511 return SkPointPriv::DistanceToSqd(midPt, pt1) > seDistSq ||
1512 SkPointPriv::DistanceToSqd(midPt, pt2) > seDistSq;
1513 }
1514
setUpWindings(SkOpSpanBase * start,SkOpSpanBase * end,int * sumMiWinding,int * maxWinding,int * sumWinding)1515 void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1516 int* maxWinding, int* sumWinding) {
1517 int deltaSum = SpanSign(start, end);
1518 *maxWinding = *sumMiWinding;
1519 *sumWinding = *sumMiWinding -= deltaSum;
1520 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
1521 }
1522
setUpWindings(SkOpSpanBase * start,SkOpSpanBase * end,int * sumMiWinding,int * sumSuWinding,int * maxWinding,int * sumWinding,int * oppMaxWinding,int * oppSumWinding)1523 void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1524 int* sumSuWinding, int* maxWinding, int* sumWinding, int* oppMaxWinding,
1525 int* oppSumWinding) {
1526 int deltaSum = SpanSign(start, end);
1527 int oppDeltaSum = OppSign(start, end);
1528 if (operand()) {
1529 *maxWinding = *sumSuWinding;
1530 *sumWinding = *sumSuWinding -= deltaSum;
1531 *oppMaxWinding = *sumMiWinding;
1532 *oppSumWinding = *sumMiWinding -= oppDeltaSum;
1533 } else {
1534 *maxWinding = *sumMiWinding;
1535 *sumWinding = *sumMiWinding -= deltaSum;
1536 *oppMaxWinding = *sumSuWinding;
1537 *oppSumWinding = *sumSuWinding -= oppDeltaSum;
1538 }
1539 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
1540 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*oppSumWinding) <= DEBUG_LIMIT_WIND_SUM);
1541 }
1542
sortAngles()1543 bool SkOpSegment::sortAngles() {
1544 SkOpSpanBase* span = &this->fHead;
1545 do {
1546 SkOpAngle* fromAngle = span->fromAngle();
1547 SkOpAngle* toAngle = span->final() ? nullptr : span->upCast()->toAngle();
1548 if (!fromAngle && !toAngle) {
1549 continue;
1550 }
1551 #if DEBUG_ANGLE
1552 bool wroteAfterHeader = false;
1553 #endif
1554 SkOpAngle* baseAngle = fromAngle;
1555 if (fromAngle && toAngle) {
1556 #if DEBUG_ANGLE
1557 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), span->t(),
1558 span->debugID());
1559 wroteAfterHeader = true;
1560 #endif
1561 FAIL_IF(!fromAngle->insert(toAngle));
1562 } else if (!fromAngle) {
1563 baseAngle = toAngle;
1564 }
1565 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
1566 int safetyNet = 1000000;
1567 do {
1568 if (!--safetyNet) {
1569 return false;
1570 }
1571 SkOpSpanBase* oSpan = ptT->span();
1572 if (oSpan == span) {
1573 continue;
1574 }
1575 SkOpAngle* oAngle = oSpan->fromAngle();
1576 if (oAngle) {
1577 #if DEBUG_ANGLE
1578 if (!wroteAfterHeader) {
1579 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1580 span->t(), span->debugID());
1581 wroteAfterHeader = true;
1582 }
1583 #endif
1584 if (!oAngle->loopContains(baseAngle)) {
1585 baseAngle->insert(oAngle);
1586 }
1587 }
1588 if (!oSpan->final()) {
1589 oAngle = oSpan->upCast()->toAngle();
1590 if (oAngle) {
1591 #if DEBUG_ANGLE
1592 if (!wroteAfterHeader) {
1593 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1594 span->t(), span->debugID());
1595 wroteAfterHeader = true;
1596 }
1597 #endif
1598 if (!oAngle->loopContains(baseAngle)) {
1599 baseAngle->insert(oAngle);
1600 }
1601 }
1602 }
1603 } while ((ptT = ptT->next()) != stopPtT);
1604 if (baseAngle->loopCount() == 1) {
1605 span->setFromAngle(nullptr);
1606 if (toAngle) {
1607 span->upCast()->setToAngle(nullptr);
1608 }
1609 baseAngle = nullptr;
1610 }
1611 #if DEBUG_SORT
1612 SkASSERT(!baseAngle || baseAngle->loopCount() > 1);
1613 #endif
1614 } while (!span->final() && (span = span->upCast()->next()));
1615 return true;
1616 }
1617
subDivide(const SkOpSpanBase * start,const SkOpSpanBase * end,SkDCurve * edge) const1618 bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
1619 SkDCurve* edge) const {
1620 SkASSERT(start != end);
1621 const SkOpPtT& startPtT = *start->ptT();
1622 const SkOpPtT& endPtT = *end->ptT();
1623 SkDEBUGCODE(edge->fVerb = fVerb);
1624 edge->fCubic[0].set(startPtT.fPt);
1625 int points = SkPathOpsVerbToPoints(fVerb);
1626 edge->fCubic[points].set(endPtT.fPt);
1627 if (fVerb == SkPath::kLine_Verb) {
1628 return false;
1629 }
1630 double startT = startPtT.fT;
1631 double endT = endPtT.fT;
1632 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
1633 // don't compute midpoints if we already have them
1634 if (fVerb == SkPath::kQuad_Verb) {
1635 edge->fLine[1].set(fPts[1]);
1636 return false;
1637 }
1638 if (fVerb == SkPath::kConic_Verb) {
1639 edge->fConic[1].set(fPts[1]);
1640 edge->fConic.fWeight = fWeight;
1641 return false;
1642 }
1643 SkASSERT(fVerb == SkPath::kCubic_Verb);
1644 if (startT == 0) {
1645 edge->fCubic[1].set(fPts[1]);
1646 edge->fCubic[2].set(fPts[2]);
1647 return false;
1648 }
1649 edge->fCubic[1].set(fPts[2]);
1650 edge->fCubic[2].set(fPts[1]);
1651 return false;
1652 }
1653 if (fVerb == SkPath::kQuad_Verb) {
1654 edge->fQuad[1] = SkDQuad::SubDivide(fPts, edge->fQuad[0], edge->fQuad[2], startT, endT);
1655 } else if (fVerb == SkPath::kConic_Verb) {
1656 edge->fConic[1] = SkDConic::SubDivide(fPts, fWeight, edge->fQuad[0], edge->fQuad[2],
1657 startT, endT, &edge->fConic.fWeight);
1658 } else {
1659 SkASSERT(fVerb == SkPath::kCubic_Verb);
1660 SkDCubic::SubDivide(fPts, edge->fCubic[0], edge->fCubic[3], startT, endT, &edge->fCubic[1]);
1661 }
1662 return true;
1663 }
1664
testForCoincidence(const SkOpPtT * priorPtT,const SkOpPtT * ptT,const SkOpSpanBase * prior,const SkOpSpanBase * spanBase,const SkOpSegment * opp) const1665 bool SkOpSegment::testForCoincidence(const SkOpPtT* priorPtT, const SkOpPtT* ptT,
1666 const SkOpSpanBase* prior, const SkOpSpanBase* spanBase, const SkOpSegment* opp) const {
1667 // average t, find mid pt
1668 double midT = (prior->t() + spanBase->t()) / 2;
1669 SkPoint midPt = this->ptAtT(midT);
1670 bool coincident = true;
1671 // if the mid pt is not near either end pt, project perpendicular through opp seg
1672 if (!SkDPoint::ApproximatelyEqual(priorPtT->fPt, midPt)
1673 && !SkDPoint::ApproximatelyEqual(ptT->fPt, midPt)) {
1674 if (priorPtT->span() == ptT->span()) {
1675 return false;
1676 }
1677 coincident = false;
1678 SkIntersections i;
1679 SkDCurve curvePart;
1680 this->subDivide(prior, spanBase, &curvePart);
1681 SkDVector dxdy = (*CurveDDSlopeAtT[fVerb])(curvePart, 0.5f);
1682 SkDPoint partMidPt = (*CurveDDPointAtT[fVerb])(curvePart, 0.5f);
1683 SkDLine ray = {{{midPt.fX, midPt.fY}, {partMidPt.fX + dxdy.fY, partMidPt.fY - dxdy.fX}}};
1684 SkDCurve oppPart;
1685 opp->subDivide(priorPtT->span(), ptT->span(), &oppPart);
1686 (*CurveDIntersectRay[opp->verb()])(oppPart, ray, &i);
1687 // measure distance and see if it's small enough to denote coincidence
1688 for (int index = 0; index < i.used(); ++index) {
1689 if (!between(0, i[0][index], 1)) {
1690 continue;
1691 }
1692 SkDPoint oppPt = i.pt(index);
1693 if (oppPt.approximatelyDEqual(midPt)) {
1694 // the coincidence can occur at almost any angle
1695 coincident = true;
1696 }
1697 }
1698 }
1699 return coincident;
1700 }
1701
undoneSpan()1702 SkOpSpan* SkOpSegment::undoneSpan() {
1703 SkOpSpan* span = &fHead;
1704 SkOpSpanBase* next;
1705 do {
1706 next = span->next();
1707 if (!span->done()) {
1708 return span;
1709 }
1710 } while (!next->final() && (span = next->upCast()));
1711 return nullptr;
1712 }
1713
updateOppWinding(const SkOpSpanBase * start,const SkOpSpanBase * end) const1714 int SkOpSegment::updateOppWinding(const SkOpSpanBase* start, const SkOpSpanBase* end) const {
1715 const SkOpSpan* lesser = start->starter(end);
1716 int oppWinding = lesser->oppSum();
1717 int oppSpanWinding = SkOpSegment::OppSign(start, end);
1718 if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWinding)
1719 && oppWinding != SK_MaxS32) {
1720 oppWinding -= oppSpanWinding;
1721 }
1722 return oppWinding;
1723 }
1724
updateOppWinding(const SkOpAngle * angle) const1725 int SkOpSegment::updateOppWinding(const SkOpAngle* angle) const {
1726 const SkOpSpanBase* startSpan = angle->start();
1727 const SkOpSpanBase* endSpan = angle->end();
1728 return updateOppWinding(endSpan, startSpan);
1729 }
1730
updateOppWindingReverse(const SkOpAngle * angle) const1731 int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const {
1732 const SkOpSpanBase* startSpan = angle->start();
1733 const SkOpSpanBase* endSpan = angle->end();
1734 return updateOppWinding(startSpan, endSpan);
1735 }
1736
updateWinding(SkOpSpanBase * start,SkOpSpanBase * end)1737 int SkOpSegment::updateWinding(SkOpSpanBase* start, SkOpSpanBase* end) {
1738 SkOpSpan* lesser = start->starter(end);
1739 int winding = lesser->windSum();
1740 if (winding == SK_MinS32) {
1741 winding = lesser->computeWindSum();
1742 }
1743 if (winding == SK_MinS32) {
1744 return winding;
1745 }
1746 int spanWinding = SkOpSegment::SpanSign(start, end);
1747 if (winding && UseInnerWinding(winding - spanWinding, winding)
1748 && winding != SK_MaxS32) {
1749 winding -= spanWinding;
1750 }
1751 return winding;
1752 }
1753
updateWinding(SkOpAngle * angle)1754 int SkOpSegment::updateWinding(SkOpAngle* angle) {
1755 SkOpSpanBase* startSpan = angle->start();
1756 SkOpSpanBase* endSpan = angle->end();
1757 return updateWinding(endSpan, startSpan);
1758 }
1759
updateWindingReverse(const SkOpAngle * angle)1760 int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) {
1761 SkOpSpanBase* startSpan = angle->start();
1762 SkOpSpanBase* endSpan = angle->end();
1763 return updateWinding(startSpan, endSpan);
1764 }
1765
1766 // OPTIMIZATION: does the following also work, and is it any faster?
1767 // return outerWinding * innerWinding > 0
1768 // || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
UseInnerWinding(int outerWinding,int innerWinding)1769 bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) {
1770 SkASSERT(outerWinding != SK_MaxS32);
1771 SkASSERT(innerWinding != SK_MaxS32);
1772 int absOut = SkTAbs(outerWinding);
1773 int absIn = SkTAbs(innerWinding);
1774 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
1775 return result;
1776 }
1777
windSum(const SkOpAngle * angle) const1778 int SkOpSegment::windSum(const SkOpAngle* angle) const {
1779 const SkOpSpan* minSpan = angle->start()->starter(angle->end());
1780 return minSpan->windSum();
1781 }
1782