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