xref: /aosp_15_r20/external/skia/src/pathops/SkPathOpsTSect.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2014 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "src/pathops/SkPathOpsTSect.h"
9 
10 #include "include/private/base/SkFloatingPoint.h"
11 #include "include/private/base/SkMacros.h"
12 #include "include/private/base/SkTArray.h"
13 #include "src/base/SkTSort.h"
14 #include "src/pathops/SkIntersections.h"
15 #include "src/pathops/SkPathOpsConic.h"
16 #include "src/pathops/SkPathOpsCubic.h"
17 #include "src/pathops/SkPathOpsLine.h"
18 #include "src/pathops/SkPathOpsQuad.h"
19 
20 #include <cfloat>
21 #include <algorithm>
22 #include <array>
23 #include <cmath>
24 
25 using namespace skia_private;
26 
27 #define COINCIDENT_SPAN_COUNT 9
28 
setPerp(const SkTCurve & c1,double t,const SkDPoint & cPt,const SkTCurve & c2)29 void SkTCoincident::setPerp(const SkTCurve& c1, double t,
30         const SkDPoint& cPt, const SkTCurve& c2) {
31     SkDVector dxdy = c1.dxdyAtT(t);
32     SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }};
33     SkIntersections i  SkDEBUGCODE((c1.globalState()));
34     int used = i.intersectRay(c2, perp);
35     // only keep closest
36     if (used == 0 || used == 3) {
37         this->init();
38         return;
39     }
40     fPerpT = i[0][0];
41     fPerpPt = i.pt(0);
42     SkASSERT(used <= 2);
43     if (used == 2) {
44         double distSq = (fPerpPt - cPt).lengthSquared();
45         double dist2Sq = (i.pt(1) - cPt).lengthSquared();
46         if (dist2Sq < distSq) {
47             fPerpT = i[0][1];
48             fPerpPt = i.pt(1);
49         }
50     }
51 #if DEBUG_T_SECT
52     SkDebugf("setPerp t=%1.9g cPt=(%1.9g,%1.9g) %s oppT=%1.9g fPerpPt=(%1.9g,%1.9g)\n",
53             t, cPt.fX, cPt.fY,
54             cPt.approximatelyEqual(fPerpPt) ? "==" : "!=", fPerpT, fPerpPt.fX, fPerpPt.fY);
55 #endif
56     fMatch = cPt.approximatelyEqual(fPerpPt);
57 #if DEBUG_T_SECT
58     if (fMatch) {
59         SkDebugf("%s", "");  // allow setting breakpoint
60     }
61 #endif
62 }
63 
addBounded(SkTSpan * span,SkArenaAlloc * heap)64 void SkTSpan::addBounded(SkTSpan* span, SkArenaAlloc* heap) {
65     SkTSpanBounded* bounded = heap->make<SkTSpanBounded>();
66     bounded->fBounded = span;
67     bounded->fNext = fBounded;
68     fBounded = bounded;
69 }
70 
addFollowing(SkTSpan * prior)71 SkTSpan* SkTSect::addFollowing(
72         SkTSpan* prior) {
73     SkTSpan* result = this->addOne();
74     SkDEBUGCODE(result->debugSetGlobalState(this->globalState()));
75     result->fStartT = prior ? prior->fEndT : 0;
76     SkTSpan* next = prior ? prior->fNext : fHead;
77     result->fEndT = next ? next->fStartT : 1;
78     result->fPrev = prior;
79     result->fNext = next;
80     if (prior) {
81         prior->fNext = result;
82     } else {
83         fHead = result;
84     }
85     if (next) {
86         next->fPrev = result;
87     }
88     result->resetBounds(fCurve);
89     // world may not be consistent to call validate here
90     result->validate();
91     return result;
92 }
93 
addForPerp(SkTSpan * span,double t)94 void SkTSect::addForPerp(SkTSpan* span, double t) {
95     if (!span->hasOppT(t)) {
96         SkTSpan* priorSpan;
97         SkTSpan* opp = this->spanAtT(t, &priorSpan);
98         if (!opp) {
99             opp = this->addFollowing(priorSpan);
100 #if DEBUG_PERP
101             SkDebugf("%s priorSpan=%d t=%1.9g opp=%d\n", __FUNCTION__, priorSpan ?
102                     priorSpan->debugID() : -1, t, opp->debugID());
103 #endif
104         }
105 #if DEBUG_PERP
106         opp->dump(); SkDebugf("\n");
107         SkDebugf("%s addBounded span=%d opp=%d\n", __FUNCTION__, priorSpan ?
108                 priorSpan->debugID() : -1, opp->debugID());
109 #endif
110         opp->addBounded(span, &fHeap);
111         span->addBounded(opp, &fHeap);
112     }
113     this->validate();
114 #if DEBUG_T_SECT
115     span->validatePerpT(t);
116 #endif
117 }
118 
closestBoundedT(const SkDPoint & pt) const119 double SkTSpan::closestBoundedT(const SkDPoint& pt) const {
120     double result = -1;
121     double closest = DBL_MAX;
122     const SkTSpanBounded* testBounded = fBounded;
123     while (testBounded) {
124         const SkTSpan* test = testBounded->fBounded;
125         double startDist = test->pointFirst().distanceSquared(pt);
126         if (closest > startDist) {
127             closest = startDist;
128             result = test->fStartT;
129         }
130         double endDist = test->pointLast().distanceSquared(pt);
131         if (closest > endDist) {
132             closest = endDist;
133             result = test->fEndT;
134         }
135         testBounded = testBounded->fNext;
136     }
137     SkASSERT(between(0, result, 1));
138     return result;
139 }
140 
141 #ifdef SK_DEBUG
142 
debugIsBefore(const SkTSpan * span) const143 bool SkTSpan::debugIsBefore(const SkTSpan* span) const {
144     const SkTSpan* work = this;
145     do {
146         if (span == work) {
147             return true;
148         }
149     } while ((work = work->fNext));
150     return false;
151 }
152 #endif
153 
contains(double t) const154 bool SkTSpan::contains(double t) const {
155     const SkTSpan* work = this;
156     do {
157         if (between(work->fStartT, t, work->fEndT)) {
158             return true;
159         }
160     } while ((work = work->fNext));
161     return false;
162 }
163 
debugOpp() const164 const SkTSect* SkTSpan::debugOpp() const {
165     return SkDEBUGRELEASE(fDebugSect->debugOpp(), nullptr);
166 }
167 
findOppSpan(const SkTSpan * opp) const168 SkTSpan* SkTSpan::findOppSpan(
169         const SkTSpan* opp) const {
170     SkTSpanBounded* bounded = fBounded;
171     while (bounded) {
172         SkTSpan* test = bounded->fBounded;
173         if (opp == test) {
174             return test;
175         }
176         bounded = bounded->fNext;
177     }
178     return nullptr;
179 }
180 
181 // returns 0 if no hull intersection
182 //         1 if hulls intersect
183 //         2 if hulls only share a common endpoint
184 //        -1 if linear and further checking is required
185 
hullCheck(const SkTSpan * opp,bool * start,bool * oppStart)186 int SkTSpan::hullCheck(const SkTSpan* opp,
187         bool* start, bool* oppStart) {
188     if (fIsLinear) {
189         return -1;
190     }
191     bool ptsInCommon;
192     if (onlyEndPointsInCommon(opp, start, oppStart, &ptsInCommon)) {
193         SkASSERT(ptsInCommon);
194         return 2;
195     }
196     bool linear;
197     if (fPart->hullIntersects(*opp->fPart, &linear)) {
198         if (!linear) {  // check set true if linear
199             return 1;
200         }
201         fIsLinear = true;
202         fIsLine = fPart->controlsInside();
203         return ptsInCommon ? 1 : -1;
204     }
205     // hull is not linear; check set true if intersected at the end points
206     return ((int) ptsInCommon) << 1;  // 0 or 2
207 }
208 
209 // OPTIMIZE ? If at_most_end_pts_in_common detects that one quad is near linear,
210 // use line intersection to guess a better split than 0.5
211 // OPTIMIZE Once at_most_end_pts_in_common detects linear, mark span so all future splits are linear
212 
hullsIntersect(SkTSpan * opp,bool * start,bool * oppStart)213 int SkTSpan::hullsIntersect(SkTSpan* opp,
214         bool* start, bool* oppStart) {
215     if (!fBounds.intersects(opp->fBounds)) {
216         return 0;
217     }
218     int hullSect = this->hullCheck(opp, start, oppStart);
219     if (hullSect >= 0) {
220         return hullSect;
221     }
222     hullSect = opp->hullCheck(this, oppStart, start);
223     if (hullSect >= 0) {
224         return hullSect;
225     }
226     return -1;
227 }
228 
init(const SkTCurve & c)229 void SkTSpan::init(const SkTCurve& c) {
230     fPrev = fNext = nullptr;
231     fStartT = 0;
232     fEndT = 1;
233     fBounded = nullptr;
234     resetBounds(c);
235 }
236 
initBounds(const SkTCurve & c)237 bool SkTSpan::initBounds(const SkTCurve& c) {
238     if (SkIsNaN(fStartT) || SkIsNaN(fEndT)) {
239         return false;
240     }
241     c.subDivide(fStartT, fEndT, fPart);
242     fBounds.setBounds(*fPart);
243     fCoinStart.init();
244     fCoinEnd.init();
245     fBoundsMax = std::max(fBounds.width(), fBounds.height());
246     fCollapsed = fPart->collapsed();
247     fHasPerp = false;
248     fDeleted = false;
249 #if DEBUG_T_SECT
250     if (fCollapsed) {
251         SkDebugf("%s", "");  // for convenient breakpoints
252     }
253 #endif
254     return fBounds.valid();
255 }
256 
linearsIntersect(SkTSpan * span)257 bool SkTSpan::linearsIntersect(SkTSpan* span) {
258     int result = this->linearIntersects(*span->fPart);
259     if (result <= 1) {
260         return SkToBool(result);
261     }
262     SkASSERT(span->fIsLinear);
263     result = span->linearIntersects(*fPart);
264 //    SkASSERT(result <= 1);
265     return SkToBool(result);
266 }
267 
linearT(const SkDPoint & pt) const268 double SkTSpan::linearT(const SkDPoint& pt) const {
269     SkDVector len = this->pointLast() - this->pointFirst();
270     return fabs(len.fX) > fabs(len.fY)
271             ? (pt.fX - this->pointFirst().fX) / len.fX
272             : (pt.fY - this->pointFirst().fY) / len.fY;
273 }
274 
linearIntersects(const SkTCurve & q2) const275 int SkTSpan::linearIntersects(const SkTCurve& q2) const {
276     // looks like q1 is near-linear
277     int start = 0, end = fPart->pointLast();  // the outside points are usually the extremes
278     if (!fPart->controlsInside()) {
279         double dist = 0;  // if there's any question, compute distance to find best outsiders
280         for (int outer = 0; outer < this->pointCount() - 1; ++outer) {
281             for (int inner = outer + 1; inner < this->pointCount(); ++inner) {
282                 double test = ((*fPart)[outer] - (*fPart)[inner]).lengthSquared();
283                 if (dist > test) {
284                     continue;
285                 }
286                 dist = test;
287                 start = outer;
288                 end = inner;
289             }
290         }
291     }
292     // see if q2 is on one side of the line formed by the extreme points
293     double origX = (*fPart)[start].fX;
294     double origY = (*fPart)[start].fY;
295     double adj = (*fPart)[end].fX - origX;
296     double opp = (*fPart)[end].fY - origY;
297     double maxPart = std::max(fabs(adj), fabs(opp));
298     double sign = 0;  // initialization to shut up warning in release build
299     for (int n = 0; n < q2.pointCount(); ++n) {
300         double dx = q2[n].fY - origY;
301         double dy = q2[n].fX - origX;
302         double maxVal = std::max(maxPart, std::max(fabs(dx), fabs(dy)));
303         double test = (q2[n].fY - origY) * adj - (q2[n].fX - origX) * opp;
304         if (precisely_zero_when_compared_to(test, maxVal)) {
305             return 1;
306         }
307         if (approximately_zero_when_compared_to(test, maxVal)) {
308             return 3;
309         }
310         if (n == 0) {
311             sign = test;
312             continue;
313         }
314         if (test * sign < 0) {
315             return 1;
316         }
317     }
318     return 0;
319 }
320 
onlyEndPointsInCommon(const SkTSpan * opp,bool * start,bool * oppStart,bool * ptsInCommon)321 bool SkTSpan::onlyEndPointsInCommon(const SkTSpan* opp,
322         bool* start, bool* oppStart, bool* ptsInCommon) {
323     if (opp->pointFirst() == this->pointFirst()) {
324         *start = *oppStart = true;
325     } else if (opp->pointFirst() == this->pointLast()) {
326         *start = false;
327         *oppStart = true;
328     } else if (opp->pointLast() == this->pointFirst()) {
329         *start = true;
330         *oppStart = false;
331     } else if (opp->pointLast() == this->pointLast()) {
332         *start = *oppStart = false;
333     } else {
334         *ptsInCommon = false;
335         return false;
336     }
337     *ptsInCommon = true;
338     const SkDPoint* otherPts[4], * oppOtherPts[4];
339 //  const SkDPoint* otherPts[this->pointCount() - 1], * oppOtherPts[opp->pointCount() - 1];
340     int baseIndex = *start ? 0 : fPart->pointLast();
341     fPart->otherPts(baseIndex, otherPts);
342     opp->fPart->otherPts(*oppStart ? 0 : opp->fPart->pointLast(), oppOtherPts);
343     const SkDPoint& base = (*fPart)[baseIndex];
344     for (int o1 = 0; o1 < this->pointCount() - 1; ++o1) {
345         SkDVector v1 = *otherPts[o1] - base;
346         for (int o2 = 0; o2 < opp->pointCount() - 1; ++o2) {
347             SkDVector v2 = *oppOtherPts[o2] - base;
348             if (v2.dot(v1) >= 0) {
349                 return false;
350             }
351         }
352     }
353     return true;
354 }
355 
oppT(double t) const356 SkTSpan* SkTSpan::oppT(double t) const {
357     SkTSpanBounded* bounded = fBounded;
358     while (bounded) {
359         SkTSpan* test = bounded->fBounded;
360         if (between(test->fStartT, t, test->fEndT)) {
361             return test;
362         }
363         bounded = bounded->fNext;
364     }
365     return nullptr;
366 }
367 
removeAllBounded()368 bool SkTSpan::removeAllBounded() {
369     bool deleteSpan = false;
370     SkTSpanBounded* bounded = fBounded;
371     while (bounded) {
372         SkTSpan* opp = bounded->fBounded;
373         deleteSpan |= opp->removeBounded(this);
374         bounded = bounded->fNext;
375     }
376     return deleteSpan;
377 }
378 
removeBounded(const SkTSpan * opp)379 bool SkTSpan::removeBounded(const SkTSpan* opp) {
380     if (fHasPerp) {
381         bool foundStart = false;
382         bool foundEnd = false;
383         SkTSpanBounded* bounded = fBounded;
384         while (bounded) {
385             SkTSpan* test = bounded->fBounded;
386             if (opp != test) {
387                 foundStart |= between(test->fStartT, fCoinStart.perpT(), test->fEndT);
388                 foundEnd |= between(test->fStartT, fCoinEnd.perpT(), test->fEndT);
389             }
390             bounded = bounded->fNext;
391         }
392         if (!foundStart || !foundEnd) {
393             fHasPerp = false;
394             fCoinStart.init();
395             fCoinEnd.init();
396         }
397     }
398     SkTSpanBounded* bounded = fBounded;
399     SkTSpanBounded* prev = nullptr;
400     while (bounded) {
401         SkTSpanBounded* boundedNext = bounded->fNext;
402         if (opp == bounded->fBounded) {
403             if (prev) {
404                 prev->fNext = boundedNext;
405                 return false;
406             } else {
407                 fBounded = boundedNext;
408                 return fBounded == nullptr;
409             }
410         }
411         prev = bounded;
412         bounded = boundedNext;
413     }
414     SkOPASSERT(0);
415     return false;
416 }
417 
splitAt(SkTSpan * work,double t,SkArenaAlloc * heap)418 bool SkTSpan::splitAt(SkTSpan* work, double t, SkArenaAlloc* heap) {
419     fStartT = t;
420     fEndT = work->fEndT;
421     if (fStartT == fEndT) {
422         fCollapsed = true;
423         return false;
424     }
425     work->fEndT = t;
426     if (work->fStartT == work->fEndT) {
427         work->fCollapsed = true;
428         return false;
429     }
430     fPrev = work;
431     fNext = work->fNext;
432     fIsLinear = work->fIsLinear;
433     fIsLine = work->fIsLine;
434 
435     work->fNext = this;
436     if (fNext) {
437         fNext->fPrev = this;
438     }
439     this->validate();
440     SkTSpanBounded* bounded = work->fBounded;
441     fBounded = nullptr;
442     while (bounded) {
443         this->addBounded(bounded->fBounded, heap);
444         bounded = bounded->fNext;
445     }
446     bounded = fBounded;
447     while (bounded) {
448         bounded->fBounded->addBounded(this, heap);
449         bounded = bounded->fNext;
450     }
451     return true;
452 }
453 
validate() const454 void SkTSpan::validate() const {
455 #if DEBUG_VALIDATE
456     SkASSERT(this != fPrev);
457     SkASSERT(this != fNext);
458     SkASSERT(fNext == nullptr || fNext != fPrev);
459     SkASSERT(fNext == nullptr || this == fNext->fPrev);
460     SkASSERT(fPrev == nullptr || this == fPrev->fNext);
461     this->validateBounded();
462 #endif
463 #if DEBUG_T_SECT
464     SkASSERT(fBounds.width() || fBounds.height() || fCollapsed);
465     SkASSERT(fBoundsMax == std::max(fBounds.width(), fBounds.height()) || fCollapsed == 0xFF);
466     SkASSERT(0 <= fStartT);
467     SkASSERT(fEndT <= 1);
468     SkASSERT(fStartT <= fEndT);
469     SkASSERT(fBounded || fCollapsed == 0xFF);
470     if (fHasPerp) {
471         if (fCoinStart.isMatch()) {
472             validatePerpT(fCoinStart.perpT());
473             validatePerpPt(fCoinStart.perpT(), fCoinStart.perpPt());
474         }
475         if (fCoinEnd.isMatch()) {
476             validatePerpT(fCoinEnd.perpT());
477             validatePerpPt(fCoinEnd.perpT(), fCoinEnd.perpPt());
478         }
479     }
480 #endif
481 }
482 
validateBounded() const483 void SkTSpan::validateBounded() const {
484 #if DEBUG_VALIDATE
485     const SkTSpanBounded* testBounded = fBounded;
486     while (testBounded) {
487         SkDEBUGCODE(const SkTSpan* overlap = testBounded->fBounded);
488         SkASSERT(!overlap->fDeleted);
489 #if DEBUG_T_SECT
490         SkASSERT(((this->debugID() ^ overlap->debugID()) & 1) == 1);
491         SkASSERT(overlap->findOppSpan(this));
492 #endif
493         testBounded = testBounded->fNext;
494     }
495 #endif
496 }
497 
validatePerpT(double oppT) const498 void SkTSpan::validatePerpT(double oppT) const {
499     const SkTSpanBounded* testBounded = fBounded;
500     while (testBounded) {
501         const SkTSpan* overlap = testBounded->fBounded;
502         if (precisely_between(overlap->fStartT, oppT, overlap->fEndT)) {
503             return;
504         }
505         testBounded = testBounded->fNext;
506     }
507     SkASSERT(0);
508 }
509 
validatePerpPt(double t,const SkDPoint & pt) const510 void SkTSpan::validatePerpPt(double t, const SkDPoint& pt) const {
511     SkASSERT(fDebugSect->fOppSect->fCurve.ptAtT(t) == pt);
512 }
513 
SkTSect(const SkTCurve & c SkDEBUGPARAMS (SkOpGlobalState * debugGlobalState)PATH_OPS_DEBUG_T_SECT_PARAMS (int id))514 SkTSect::SkTSect(const SkTCurve& c
515         SkDEBUGPARAMS(SkOpGlobalState* debugGlobalState)
516         PATH_OPS_DEBUG_T_SECT_PARAMS(int id))
517     : fCurve(c)
518     , fHeap(sizeof(SkTSpan) * 4)
519     , fCoincident(nullptr)
520     , fDeleted(nullptr)
521     , fActiveCount(0)
522     , fHung(false)
523     SkDEBUGPARAMS(fDebugGlobalState(debugGlobalState))
524     PATH_OPS_DEBUG_T_SECT_PARAMS(fID(id))
525     PATH_OPS_DEBUG_T_SECT_PARAMS(fDebugCount(0))
526     PATH_OPS_DEBUG_T_SECT_PARAMS(fDebugAllocatedCount(0))
527 {
528     this->resetRemovedEnds();
529     fHead = this->addOne();
530     SkDEBUGCODE(fHead->debugSetGlobalState(debugGlobalState));
531     fHead->init(c);
532 }
533 
addOne()534 SkTSpan* SkTSect::addOne() {
535     SkTSpan* result;
536     if (fDeleted) {
537         result = fDeleted;
538         fDeleted = result->fNext;
539     } else {
540         result = fHeap.make<SkTSpan>(fCurve, fHeap);
541 #if DEBUG_T_SECT
542         ++fDebugAllocatedCount;
543 #endif
544     }
545     result->reset();
546     result->fHasPerp = false;
547     result->fDeleted = false;
548     ++fActiveCount;
549     PATH_OPS_DEBUG_T_SECT_CODE(result->fID = fDebugCount++ * 2 + fID);
550     SkDEBUGCODE(result->fDebugSect = this);
551 #ifdef SK_DEBUG
552     result->debugInit(fCurve, fHeap);
553     result->fCoinStart.debugInit();
554     result->fCoinEnd.debugInit();
555     result->fPrev = result->fNext = nullptr;
556     result->fBounds.debugInit();
557     result->fStartT = result->fEndT = result->fBoundsMax = SK_ScalarNaN;
558     result->fCollapsed = result->fIsLinear = result->fIsLine = 0xFF;
559 #endif
560     return result;
561 }
562 
binarySearchCoin(SkTSect * sect2,double tStart,double tStep,double * resultT,double * oppT,SkTSpan ** oppFirst)563 bool SkTSect::binarySearchCoin(SkTSect* sect2, double tStart,
564         double tStep, double* resultT, double* oppT, SkTSpan** oppFirst) {
565     SkTSpan work(fCurve, fHeap);
566     double result = work.fStartT = work.fEndT = tStart;
567     SkDEBUGCODE(work.fDebugSect = this);
568     SkDPoint last = fCurve.ptAtT(tStart);
569     SkDPoint oppPt;
570     bool flip = false;
571     bool contained = false;
572     bool down = tStep < 0;
573     const SkTCurve& opp = sect2->fCurve;
574     do {
575         tStep *= 0.5;
576         work.fStartT += tStep;
577         if (flip) {
578             tStep = -tStep;
579             flip = false;
580         }
581         work.initBounds(fCurve);
582         if (work.fCollapsed) {
583             return false;
584         }
585         if (last.approximatelyEqual(work.pointFirst())) {
586             break;
587         }
588         last = work.pointFirst();
589         work.fCoinStart.setPerp(fCurve, work.fStartT, last, opp);
590         if (work.fCoinStart.isMatch()) {
591 #if DEBUG_T_SECT
592             work.validatePerpPt(work.fCoinStart.perpT(), work.fCoinStart.perpPt());
593 #endif
594             double oppTTest = work.fCoinStart.perpT();
595             if (sect2->fHead->contains(oppTTest)) {
596                 *oppT = oppTTest;
597                 oppPt = work.fCoinStart.perpPt();
598                 contained = true;
599                 if (down ? result <= work.fStartT : result >= work.fStartT) {
600                     *oppFirst = nullptr;    // signal caller to fail
601                     return false;
602                 }
603                 result = work.fStartT;
604                 continue;
605             }
606         }
607         tStep = -tStep;
608         flip = true;
609     } while (true);
610     if (!contained) {
611         return false;
612     }
613     if (last.approximatelyEqual(fCurve[0])) {
614         result = 0;
615     } else if (last.approximatelyEqual(this->pointLast())) {
616         result = 1;
617     }
618     if (oppPt.approximatelyEqual(opp[0])) {
619         *oppT = 0;
620     } else if (oppPt.approximatelyEqual(sect2->pointLast())) {
621         *oppT = 1;
622     }
623     *resultT = result;
624     return true;
625 }
626 
627 // OPTIMIZE ? keep a sorted list of sizes in the form of a doubly-linked list in quad span
628 //            so that each quad sect has a pointer to the largest, and can update it as spans
629 //            are split
630 
boundsMax()631 SkTSpan* SkTSect::boundsMax() {
632     SkTSpan* test = fHead;
633     SkTSpan* largest = fHead;
634     bool lCollapsed = largest->fCollapsed;
635     int safetyNet = 10000;
636     while ((test = test->fNext)) {
637         if (!--safetyNet) {
638             fHung = true;
639             return nullptr;
640         }
641         bool tCollapsed = test->fCollapsed;
642         if ((lCollapsed && !tCollapsed) || (lCollapsed == tCollapsed &&
643                 largest->fBoundsMax < test->fBoundsMax)) {
644             largest = test;
645             lCollapsed = test->fCollapsed;
646         }
647     }
648     return largest;
649 }
650 
coincidentCheck(SkTSect * sect2)651 bool SkTSect::coincidentCheck(SkTSect* sect2) {
652     SkTSpan* first = fHead;
653     if (!first) {
654         return false;
655     }
656     SkTSpan* last, * next;
657     do {
658         int consecutive = this->countConsecutiveSpans(first, &last);
659         next = last->fNext;
660         if (consecutive < COINCIDENT_SPAN_COUNT) {
661             continue;
662         }
663         this->validate();
664         sect2->validate();
665         this->computePerpendiculars(sect2, first, last);
666         this->validate();
667         sect2->validate();
668         // check to see if a range of points are on the curve
669         SkTSpan* coinStart = first;
670         do {
671             bool success = this->extractCoincident(sect2, coinStart, last, &coinStart);
672             if (!success) {
673                 return false;
674             }
675         } while (coinStart && !last->fDeleted);
676         if (!fHead || !sect2->fHead) {
677             break;
678         }
679         if (!next || next->fDeleted) {
680             break;
681         }
682     } while ((first = next));
683     return true;
684 }
685 
coincidentForce(SkTSect * sect2,double start1s,double start1e)686 void SkTSect::coincidentForce(SkTSect* sect2,
687         double start1s, double start1e) {
688     SkTSpan* first = fHead;
689     SkTSpan* last = this->tail();
690     SkTSpan* oppFirst = sect2->fHead;
691     SkTSpan* oppLast = sect2->tail();
692     if (!last || !oppLast) {
693         return;
694     }
695     bool deleteEmptySpans = this->updateBounded(first, last, oppFirst);
696     deleteEmptySpans |= sect2->updateBounded(oppFirst, oppLast, first);
697     this->removeSpanRange(first, last);
698     sect2->removeSpanRange(oppFirst, oppLast);
699     first->fStartT = start1s;
700     first->fEndT = start1e;
701     first->resetBounds(fCurve);
702     first->fCoinStart.setPerp(fCurve, start1s, fCurve[0], sect2->fCurve);
703     first->fCoinEnd.setPerp(fCurve, start1e, this->pointLast(), sect2->fCurve);
704     bool oppMatched = first->fCoinStart.perpT() < first->fCoinEnd.perpT();
705     double oppStartT = first->fCoinStart.perpT() == -1 ? 0 : std::max(0., first->fCoinStart.perpT());
706     double oppEndT = first->fCoinEnd.perpT() == -1 ? 1 : std::min(1., first->fCoinEnd.perpT());
707     if (!oppMatched) {
708         using std::swap;
709         swap(oppStartT, oppEndT);
710     }
711     oppFirst->fStartT = oppStartT;
712     oppFirst->fEndT = oppEndT;
713     oppFirst->resetBounds(sect2->fCurve);
714     this->removeCoincident(first, false);
715     sect2->removeCoincident(oppFirst, true);
716     if (deleteEmptySpans) {
717         this->deleteEmptySpans();
718         sect2->deleteEmptySpans();
719     }
720 }
721 
coincidentHasT(double t)722 bool SkTSect::coincidentHasT(double t) {
723     SkTSpan* test = fCoincident;
724     while (test) {
725         if (between(test->fStartT, t, test->fEndT)) {
726             return true;
727         }
728         test = test->fNext;
729     }
730     return false;
731 }
732 
collapsed() const733 int SkTSect::collapsed() const {
734     int result = 0;
735     const SkTSpan* test = fHead;
736     while (test) {
737         if (test->fCollapsed) {
738             ++result;
739         }
740         test = test->next();
741     }
742     return result;
743 }
744 
computePerpendiculars(SkTSect * sect2,SkTSpan * first,SkTSpan * last)745 void SkTSect::computePerpendiculars(SkTSect* sect2,
746         SkTSpan* first, SkTSpan* last) {
747     if (!last) {
748         return;
749     }
750     const SkTCurve& opp = sect2->fCurve;
751     SkTSpan* work = first;
752     SkTSpan* prior = nullptr;
753     do {
754         if (!work->fHasPerp && !work->fCollapsed) {
755             if (prior) {
756                 work->fCoinStart = prior->fCoinEnd;
757             } else {
758                 work->fCoinStart.setPerp(fCurve, work->fStartT, work->pointFirst(), opp);
759             }
760             if (work->fCoinStart.isMatch()) {
761                 double perpT = work->fCoinStart.perpT();
762                 if (sect2->coincidentHasT(perpT)) {
763                     work->fCoinStart.init();
764                 } else {
765                     sect2->addForPerp(work, perpT);
766                 }
767             }
768             work->fCoinEnd.setPerp(fCurve, work->fEndT, work->pointLast(), opp);
769             if (work->fCoinEnd.isMatch()) {
770                 double perpT = work->fCoinEnd.perpT();
771                 if (sect2->coincidentHasT(perpT)) {
772                     work->fCoinEnd.init();
773                 } else {
774                     sect2->addForPerp(work, perpT);
775                 }
776             }
777             work->fHasPerp = true;
778         }
779         if (work == last) {
780             break;
781         }
782         prior = work;
783         work = work->fNext;
784         SkASSERT(work);
785     } while (true);
786 }
787 
countConsecutiveSpans(SkTSpan * first,SkTSpan ** lastPtr) const788 int SkTSect::countConsecutiveSpans(SkTSpan* first,
789         SkTSpan** lastPtr) const {
790     int consecutive = 1;
791     SkTSpan* last = first;
792     do {
793         SkTSpan* next = last->fNext;
794         if (!next) {
795             break;
796         }
797         if (next->fStartT > last->fEndT) {
798             break;
799         }
800         ++consecutive;
801         last = next;
802     } while (true);
803     *lastPtr = last;
804     return consecutive;
805 }
806 
hasBounded(const SkTSpan * span) const807 bool SkTSect::hasBounded(const SkTSpan* span) const {
808     const SkTSpan* test = fHead;
809     if (!test) {
810         return false;
811     }
812     do {
813         if (test->findOppSpan(span)) {
814             return true;
815         }
816     } while ((test = test->next()));
817     return false;
818 }
819 
deleteEmptySpans()820 bool SkTSect::deleteEmptySpans() {
821     SkTSpan* test;
822     SkTSpan* next = fHead;
823     int safetyHatch = 1000;
824     while ((test = next)) {
825         next = test->fNext;
826         if (!test->fBounded) {
827             if (!this->removeSpan(test)) {
828                 return false;
829             }
830         }
831         if (--safetyHatch < 0) {
832             return false;
833         }
834     }
835     return true;
836 }
837 
extractCoincident(SkTSect * sect2,SkTSpan * first,SkTSpan * last,SkTSpan ** result)838 bool SkTSect::extractCoincident(
839         SkTSect* sect2,
840         SkTSpan* first, SkTSpan* last,
841         SkTSpan** result) {
842     first = findCoincidentRun(first, &last);
843     if (!first || !last) {
844         *result = nullptr;
845         return true;
846     }
847     // march outwards to find limit of coincidence from here to previous and next spans
848     double startT = first->fStartT;
849     double oppStartT SK_INIT_TO_AVOID_WARNING;
850     double oppEndT SK_INIT_TO_AVOID_WARNING;
851     SkTSpan* prev = first->fPrev;
852     SkASSERT(first->fCoinStart.isMatch());
853     SkTSpan* oppFirst = first->findOppT(first->fCoinStart.perpT());
854     SkOPASSERT(last->fCoinEnd.isMatch());
855     bool oppMatched = first->fCoinStart.perpT() < first->fCoinEnd.perpT();
856     double coinStart;
857     SkDEBUGCODE(double coinEnd);
858     SkTSpan* cutFirst;
859     if (prev && prev->fEndT == startT
860             && this->binarySearchCoin(sect2, startT, prev->fStartT - startT, &coinStart,
861                                       &oppStartT, &oppFirst)
862             && prev->fStartT < coinStart && coinStart < startT
863             && (cutFirst = prev->oppT(oppStartT))) {
864         oppFirst = cutFirst;
865         first = this->addSplitAt(prev, coinStart);
866         first->markCoincident();
867         prev->fCoinEnd.markCoincident();
868         if (oppFirst->fStartT < oppStartT && oppStartT < oppFirst->fEndT) {
869             SkTSpan* oppHalf = sect2->addSplitAt(oppFirst, oppStartT);
870             if (oppMatched) {
871                 oppFirst->fCoinEnd.markCoincident();
872                 oppHalf->markCoincident();
873                 oppFirst = oppHalf;
874             } else {
875                 oppFirst->markCoincident();
876                 oppHalf->fCoinStart.markCoincident();
877             }
878         }
879     } else {
880         if (!oppFirst) {
881             return false;
882         }
883         SkDEBUGCODE(coinStart = first->fStartT);
884         SkDEBUGCODE(oppStartT = oppMatched ? oppFirst->fStartT : oppFirst->fEndT);
885     }
886     // FIXME: incomplete : if we're not at the end, find end of coin
887     SkTSpan* oppLast;
888     SkOPASSERT(last->fCoinEnd.isMatch());
889     oppLast = last->findOppT(last->fCoinEnd.perpT());
890     SkDEBUGCODE(coinEnd = last->fEndT);
891 #ifdef SK_DEBUG
892     if (!this->globalState() || !this->globalState()->debugSkipAssert()) {
893         oppEndT = oppMatched ? oppLast->fEndT : oppLast->fStartT;
894     }
895 #endif
896     if (!oppMatched) {
897         using std::swap;
898         swap(oppFirst, oppLast);
899         swap(oppStartT, oppEndT);
900     }
901     SkOPASSERT(oppStartT < oppEndT);
902     SkASSERT(coinStart == first->fStartT);
903     SkASSERT(coinEnd == last->fEndT);
904     if (!oppFirst) {
905         *result = nullptr;
906         return true;
907     }
908     SkOPASSERT(oppStartT == oppFirst->fStartT);
909     if (!oppLast) {
910         *result = nullptr;
911         return true;
912     }
913     SkOPASSERT(oppEndT == oppLast->fEndT);
914     // reduce coincident runs to single entries
915     this->validate();
916     sect2->validate();
917     bool deleteEmptySpans = this->updateBounded(first, last, oppFirst);
918     deleteEmptySpans |= sect2->updateBounded(oppFirst, oppLast, first);
919     this->removeSpanRange(first, last);
920     sect2->removeSpanRange(oppFirst, oppLast);
921     first->fEndT = last->fEndT;
922     first->resetBounds(this->fCurve);
923     first->fCoinStart.setPerp(fCurve, first->fStartT, first->pointFirst(), sect2->fCurve);
924     first->fCoinEnd.setPerp(fCurve, first->fEndT, first->pointLast(), sect2->fCurve);
925     oppStartT = first->fCoinStart.perpT();
926     oppEndT = first->fCoinEnd.perpT();
927     if (between(0, oppStartT, 1) && between(0, oppEndT, 1)) {
928         if (!oppMatched) {
929             using std::swap;
930             swap(oppStartT, oppEndT);
931         }
932         oppFirst->fStartT = oppStartT;
933         oppFirst->fEndT = oppEndT;
934         oppFirst->resetBounds(sect2->fCurve);
935     }
936     this->validateBounded();
937     sect2->validateBounded();
938     last = first->fNext;
939     if (!this->removeCoincident(first, false)) {
940         return false;
941     }
942     if (!sect2->removeCoincident(oppFirst, true)) {
943         return false;
944     }
945     if (deleteEmptySpans) {
946         if (!this->deleteEmptySpans() || !sect2->deleteEmptySpans()) {
947             *result = nullptr;
948             return false;
949         }
950     }
951     this->validate();
952     sect2->validate();
953     *result = last && !last->fDeleted && fHead && sect2->fHead ? last : nullptr;
954     return true;
955 }
956 
findCoincidentRun(SkTSpan * first,SkTSpan ** lastPtr)957 SkTSpan* SkTSect::findCoincidentRun(
958         SkTSpan* first, SkTSpan** lastPtr) {
959     SkTSpan* work = first;
960     SkTSpan* lastCandidate = nullptr;
961     first = nullptr;
962     // find the first fully coincident span
963     do {
964         if (work->fCoinStart.isMatch()) {
965 #if DEBUG_T_SECT
966             work->validatePerpT(work->fCoinStart.perpT());
967             work->validatePerpPt(work->fCoinStart.perpT(), work->fCoinStart.perpPt());
968 #endif
969             SkOPASSERT(work->hasOppT(work->fCoinStart.perpT()));
970             if (!work->fCoinEnd.isMatch()) {
971                 break;
972             }
973             lastCandidate = work;
974             if (!first) {
975                 first = work;
976             }
977         } else if (first && work->fCollapsed) {
978             *lastPtr = lastCandidate;
979             return first;
980         } else {
981             lastCandidate = nullptr;
982             SkOPASSERT(!first);
983         }
984         if (work == *lastPtr) {
985             return first;
986         }
987         work = work->fNext;
988         if (!work) {
989             return nullptr;
990         }
991     } while (true);
992     if (lastCandidate) {
993         *lastPtr = lastCandidate;
994     }
995     return first;
996 }
997 
intersects(SkTSpan * span,SkTSect * opp,SkTSpan * oppSpan,int * oppResult)998 int SkTSect::intersects(SkTSpan* span,
999         SkTSect* opp,
1000         SkTSpan* oppSpan, int* oppResult) {
1001     bool spanStart, oppStart;
1002     int hullResult = span->hullsIntersect(oppSpan, &spanStart, &oppStart);
1003     if (hullResult >= 0) {
1004         if (hullResult == 2) {  // hulls have one point in common
1005             if (!span->fBounded || !span->fBounded->fNext) {
1006                 SkASSERT(!span->fBounded || span->fBounded->fBounded == oppSpan);
1007                 if (spanStart) {
1008                     span->fEndT = span->fStartT;
1009                 } else {
1010                     span->fStartT = span->fEndT;
1011                 }
1012             } else {
1013                 hullResult = 1;
1014             }
1015             if (!oppSpan->fBounded || !oppSpan->fBounded->fNext) {
1016                 if (oppSpan->fBounded && oppSpan->fBounded->fBounded != span) {
1017                     return 0;
1018                 }
1019                 if (oppStart) {
1020                     oppSpan->fEndT = oppSpan->fStartT;
1021                 } else {
1022                     oppSpan->fStartT = oppSpan->fEndT;
1023                 }
1024                 *oppResult = 2;
1025             } else {
1026                 *oppResult = 1;
1027             }
1028         } else {
1029             *oppResult = 1;
1030         }
1031         return hullResult;
1032     }
1033     if (span->fIsLine && oppSpan->fIsLine) {
1034         SkIntersections i;
1035         int sects = this->linesIntersect(span, opp, oppSpan, &i);
1036         if (sects == 2) {
1037             return *oppResult = 1;
1038         }
1039         if (!sects) {
1040             return -1;
1041         }
1042         this->removedEndCheck(span);
1043         span->fStartT = span->fEndT = i[0][0];
1044         opp->removedEndCheck(oppSpan);
1045         oppSpan->fStartT = oppSpan->fEndT = i[1][0];
1046         return *oppResult = 2;
1047     }
1048     if (span->fIsLinear || oppSpan->fIsLinear) {
1049         return *oppResult = (int) span->linearsIntersect(oppSpan);
1050     }
1051     return *oppResult = 1;
1052 }
1053 
1054 template<typename SkTCurve>
is_parallel(const SkDLine & thisLine,const SkTCurve & opp)1055 static bool is_parallel(const SkDLine& thisLine, const SkTCurve& opp) {
1056     if (!opp.IsConic()) {
1057         return false; // FIXME : breaks a lot of stuff now
1058     }
1059     int finds = 0;
1060     SkDLine thisPerp;
1061     thisPerp.fPts[0].fX = thisLine.fPts[1].fX + (thisLine.fPts[1].fY - thisLine.fPts[0].fY);
1062     thisPerp.fPts[0].fY = thisLine.fPts[1].fY + (thisLine.fPts[0].fX - thisLine.fPts[1].fX);
1063     thisPerp.fPts[1] = thisLine.fPts[1];
1064     SkIntersections perpRayI;
1065     perpRayI.intersectRay(opp, thisPerp);
1066     for (int pIndex = 0; pIndex < perpRayI.used(); ++pIndex) {
1067         finds += perpRayI.pt(pIndex).approximatelyEqual(thisPerp.fPts[1]);
1068     }
1069     thisPerp.fPts[1].fX = thisLine.fPts[0].fX + (thisLine.fPts[1].fY - thisLine.fPts[0].fY);
1070     thisPerp.fPts[1].fY = thisLine.fPts[0].fY + (thisLine.fPts[0].fX - thisLine.fPts[1].fX);
1071     thisPerp.fPts[0] = thisLine.fPts[0];
1072     perpRayI.intersectRay(opp, thisPerp);
1073     for (int pIndex = 0; pIndex < perpRayI.used(); ++pIndex) {
1074         finds += perpRayI.pt(pIndex).approximatelyEqual(thisPerp.fPts[0]);
1075     }
1076     return finds >= 2;
1077 }
1078 
1079 // while the intersection points are sufficiently far apart:
1080 // construct the tangent lines from the intersections
1081 // find the point where the tangent line intersects the opposite curve
1082 
linesIntersect(SkTSpan * span,SkTSect * opp,SkTSpan * oppSpan,SkIntersections * i)1083 int SkTSect::linesIntersect(SkTSpan* span,
1084         SkTSect* opp,
1085         SkTSpan* oppSpan, SkIntersections* i) {
1086     SkIntersections thisRayI  SkDEBUGCODE((span->fDebugGlobalState));
1087     SkIntersections oppRayI  SkDEBUGCODE((span->fDebugGlobalState));
1088     SkDLine thisLine = {{ span->pointFirst(), span->pointLast() }};
1089     SkDLine oppLine = {{ oppSpan->pointFirst(), oppSpan->pointLast() }};
1090     int loopCount = 0;
1091     double bestDistSq = DBL_MAX;
1092     if (!thisRayI.intersectRay(opp->fCurve, thisLine)) {
1093         return 0;
1094     }
1095     if (!oppRayI.intersectRay(this->fCurve, oppLine)) {
1096         return 0;
1097     }
1098     // if the ends of each line intersect the opposite curve, the lines are coincident
1099     if (thisRayI.used() > 1) {
1100         int ptMatches = 0;
1101         for (int tIndex = 0; tIndex < thisRayI.used(); ++tIndex) {
1102             for (int lIndex = 0; lIndex < (int) std::size(thisLine.fPts); ++lIndex) {
1103                 ptMatches += thisRayI.pt(tIndex).approximatelyEqual(thisLine.fPts[lIndex]);
1104             }
1105         }
1106         if (ptMatches == 2 || is_parallel(thisLine, opp->fCurve)) {
1107             return 2;
1108         }
1109     }
1110     if (oppRayI.used() > 1) {
1111         int ptMatches = 0;
1112         for (int oIndex = 0; oIndex < oppRayI.used(); ++oIndex) {
1113             for (int lIndex = 0; lIndex < (int) std::size(oppLine.fPts); ++lIndex) {
1114                 ptMatches += oppRayI.pt(oIndex).approximatelyEqual(oppLine.fPts[lIndex]);
1115             }
1116         }
1117         if (ptMatches == 2|| is_parallel(oppLine, this->fCurve)) {
1118             return 2;
1119         }
1120     }
1121     do {
1122         // pick the closest pair of points
1123         double closest = DBL_MAX;
1124         int closeIndex SK_INIT_TO_AVOID_WARNING;
1125         int oppCloseIndex SK_INIT_TO_AVOID_WARNING;
1126         for (int index = 0; index < oppRayI.used(); ++index) {
1127             if (!roughly_between(span->fStartT, oppRayI[0][index], span->fEndT)) {
1128                 continue;
1129             }
1130             for (int oIndex = 0; oIndex < thisRayI.used(); ++oIndex) {
1131                 if (!roughly_between(oppSpan->fStartT, thisRayI[0][oIndex], oppSpan->fEndT)) {
1132                     continue;
1133                 }
1134                 double distSq = thisRayI.pt(index).distanceSquared(oppRayI.pt(oIndex));
1135                 if (closest > distSq) {
1136                     closest = distSq;
1137                     closeIndex = index;
1138                     oppCloseIndex = oIndex;
1139                 }
1140             }
1141         }
1142         if (closest == DBL_MAX) {
1143             break;
1144         }
1145         const SkDPoint& oppIPt = thisRayI.pt(oppCloseIndex);
1146         const SkDPoint& iPt = oppRayI.pt(closeIndex);
1147         if (between(span->fStartT, oppRayI[0][closeIndex], span->fEndT)
1148                 && between(oppSpan->fStartT, thisRayI[0][oppCloseIndex], oppSpan->fEndT)
1149                 && oppIPt.approximatelyEqual(iPt)) {
1150             i->merge(oppRayI, closeIndex, thisRayI, oppCloseIndex);
1151             return i->used();
1152         }
1153         double distSq = oppIPt.distanceSquared(iPt);
1154         if (bestDistSq < distSq || ++loopCount > 5) {
1155             return 0;
1156         }
1157         bestDistSq = distSq;
1158         double oppStart = oppRayI[0][closeIndex];
1159         thisLine[0] = fCurve.ptAtT(oppStart);
1160         thisLine[1] = thisLine[0] + fCurve.dxdyAtT(oppStart);
1161         if (!thisRayI.intersectRay(opp->fCurve, thisLine)) {
1162             break;
1163         }
1164         double start = thisRayI[0][oppCloseIndex];
1165         oppLine[0] = opp->fCurve.ptAtT(start);
1166         oppLine[1] = oppLine[0] + opp->fCurve.dxdyAtT(start);
1167         if (!oppRayI.intersectRay(this->fCurve, oppLine)) {
1168             break;
1169         }
1170     } while (true);
1171     // convergence may fail if the curves are nearly coincident
1172     SkTCoincident oCoinS, oCoinE;
1173     oCoinS.setPerp(opp->fCurve, oppSpan->fStartT, oppSpan->pointFirst(), fCurve);
1174     oCoinE.setPerp(opp->fCurve, oppSpan->fEndT, oppSpan->pointLast(), fCurve);
1175     double tStart = oCoinS.perpT();
1176     double tEnd = oCoinE.perpT();
1177     bool swap = tStart > tEnd;
1178     if (swap) {
1179         using std::swap;
1180         swap(tStart, tEnd);
1181     }
1182     tStart = std::max(tStart, span->fStartT);
1183     tEnd = std::min(tEnd, span->fEndT);
1184     if (tStart > tEnd) {
1185         return 0;
1186     }
1187     SkDVector perpS, perpE;
1188     if (tStart == span->fStartT) {
1189         SkTCoincident coinS;
1190         coinS.setPerp(fCurve, span->fStartT, span->pointFirst(), opp->fCurve);
1191         perpS = span->pointFirst() - coinS.perpPt();
1192     } else if (swap) {
1193         perpS = oCoinE.perpPt() - oppSpan->pointLast();
1194     } else {
1195         perpS = oCoinS.perpPt() - oppSpan->pointFirst();
1196     }
1197     if (tEnd == span->fEndT) {
1198         SkTCoincident coinE;
1199         coinE.setPerp(fCurve, span->fEndT, span->pointLast(), opp->fCurve);
1200         perpE = span->pointLast() - coinE.perpPt();
1201     } else if (swap) {
1202         perpE = oCoinS.perpPt() - oppSpan->pointFirst();
1203     } else {
1204         perpE = oCoinE.perpPt() - oppSpan->pointLast();
1205     }
1206     if (perpS.dot(perpE) >= 0) {
1207         return 0;
1208     }
1209     SkTCoincident coinW;
1210     double workT = tStart;
1211     double tStep = tEnd - tStart;
1212     SkDPoint workPt;
1213     do {
1214         tStep *= 0.5;
1215         if (precisely_zero(tStep)) {
1216             return 0;
1217         }
1218         workT += tStep;
1219         workPt = fCurve.ptAtT(workT);
1220         coinW.setPerp(fCurve, workT, workPt, opp->fCurve);
1221         double perpT = coinW.perpT();
1222         if (coinW.isMatch() ? !between(oppSpan->fStartT, perpT, oppSpan->fEndT) : perpT < 0) {
1223             continue;
1224         }
1225         SkDVector perpW = workPt - coinW.perpPt();
1226         if ((perpS.dot(perpW) >= 0) == (tStep < 0)) {
1227             tStep = -tStep;
1228         }
1229         if (workPt.approximatelyEqual(coinW.perpPt())) {
1230             break;
1231         }
1232     } while (true);
1233     double oppTTest = coinW.perpT();
1234     if (!opp->fHead->contains(oppTTest)) {
1235         return 0;
1236     }
1237     i->setMax(1);
1238     i->insert(workT, oppTTest, workPt);
1239     return 1;
1240 }
1241 
markSpanGone(SkTSpan * span)1242 bool SkTSect::markSpanGone(SkTSpan* span) {
1243     if (--fActiveCount < 0) {
1244         return false;
1245     }
1246     span->fNext = fDeleted;
1247     fDeleted = span;
1248     SkOPASSERT(!span->fDeleted);
1249     span->fDeleted = true;
1250     return true;
1251 }
1252 
matchedDirection(double t,const SkTSect * sect2,double t2) const1253 bool SkTSect::matchedDirection(double t, const SkTSect* sect2,
1254         double t2) const {
1255     SkDVector dxdy = this->fCurve.dxdyAtT(t);
1256     SkDVector dxdy2 = sect2->fCurve.dxdyAtT(t2);
1257     return dxdy.dot(dxdy2) >= 0;
1258 }
1259 
matchedDirCheck(double t,const SkTSect * sect2,double t2,bool * calcMatched,bool * oppMatched) const1260 void SkTSect::matchedDirCheck(double t, const SkTSect* sect2,
1261         double t2, bool* calcMatched, bool* oppMatched) const {
1262     if (*calcMatched) {
1263         SkASSERT(*oppMatched == this->matchedDirection(t, sect2, t2));
1264     } else {
1265         *oppMatched = this->matchedDirection(t, sect2, t2);
1266         *calcMatched = true;
1267     }
1268 }
1269 
mergeCoincidence(SkTSect * sect2)1270 void SkTSect::mergeCoincidence(SkTSect* sect2) {
1271     double smallLimit = 0;
1272     do {
1273         // find the smallest unprocessed span
1274         SkTSpan* smaller = nullptr;
1275         SkTSpan* test = fCoincident;
1276         do {
1277             if (!test) {
1278                 return;
1279             }
1280             if (test->fStartT < smallLimit) {
1281                 continue;
1282             }
1283             if (smaller && smaller->fEndT < test->fStartT) {
1284                 continue;
1285             }
1286             smaller = test;
1287         } while ((test = test->fNext));
1288         if (!smaller) {
1289             return;
1290         }
1291         smallLimit = smaller->fEndT;
1292         // find next larger span
1293         SkTSpan* prior = nullptr;
1294         SkTSpan* larger = nullptr;
1295         SkTSpan* largerPrior = nullptr;
1296         test = fCoincident;
1297         do {
1298             if (test->fStartT < smaller->fEndT) {
1299                 continue;
1300             }
1301             SkOPASSERT(test->fStartT != smaller->fEndT);
1302             if (larger && larger->fStartT < test->fStartT) {
1303                 continue;
1304             }
1305             largerPrior = prior;
1306             larger = test;
1307         } while ((void) (prior = test), (test = test->fNext));
1308         if (!larger) {
1309             continue;
1310         }
1311         // check middle t value to see if it is coincident as well
1312         double midT = (smaller->fEndT + larger->fStartT) / 2;
1313         SkDPoint midPt = fCurve.ptAtT(midT);
1314         SkTCoincident coin;
1315         coin.setPerp(fCurve, midT, midPt, sect2->fCurve);
1316         if (coin.isMatch()) {
1317             smaller->fEndT = larger->fEndT;
1318             smaller->fCoinEnd = larger->fCoinEnd;
1319             if (largerPrior) {
1320                 largerPrior->fNext = larger->fNext;
1321                 largerPrior->validate();
1322             } else {
1323                 fCoincident = larger->fNext;
1324             }
1325         }
1326     } while (true);
1327 }
1328 
prev(SkTSpan * span) const1329 SkTSpan* SkTSect::prev(
1330         SkTSpan* span) const {
1331     SkTSpan* result = nullptr;
1332     SkTSpan* test = fHead;
1333     while (span != test) {
1334         result = test;
1335         test = test->fNext;
1336         SkASSERT(test);
1337     }
1338     return result;
1339 }
1340 
recoverCollapsed()1341 void SkTSect::recoverCollapsed() {
1342     SkTSpan* deleted = fDeleted;
1343     while (deleted) {
1344         SkTSpan* delNext = deleted->fNext;
1345         if (deleted->fCollapsed) {
1346             SkTSpan** spanPtr = &fHead;
1347             while (*spanPtr && (*spanPtr)->fEndT <= deleted->fStartT) {
1348                 spanPtr = &(*spanPtr)->fNext;
1349             }
1350             deleted->fNext = *spanPtr;
1351             *spanPtr = deleted;
1352         }
1353         deleted = delNext;
1354     }
1355 }
1356 
removeAllBut(const SkTSpan * keep,SkTSpan * span,SkTSect * opp)1357 void SkTSect::removeAllBut(const SkTSpan* keep,
1358         SkTSpan* span, SkTSect* opp) {
1359     const SkTSpanBounded* testBounded = span->fBounded;
1360     while (testBounded) {
1361         SkTSpan* bounded = testBounded->fBounded;
1362         const SkTSpanBounded* next = testBounded->fNext;
1363         // may have been deleted when opp did 'remove all but'
1364         if (bounded != keep && !bounded->fDeleted) {
1365             SkAssertResult(SkDEBUGCODE(!) span->removeBounded(bounded));
1366             if (bounded->removeBounded(span)) {
1367                 opp->removeSpan(bounded);
1368             }
1369         }
1370         testBounded = next;
1371     }
1372     SkASSERT(!span->fDeleted);
1373     SkASSERT(span->findOppSpan(keep));
1374     SkASSERT(keep->findOppSpan(span));
1375 }
1376 
removeByPerpendicular(SkTSect * opp)1377 bool SkTSect::removeByPerpendicular(SkTSect* opp) {
1378     SkTSpan* test = fHead;
1379     SkTSpan* next;
1380     do {
1381         next = test->fNext;
1382         if (test->fCoinStart.perpT() < 0 || test->fCoinEnd.perpT() < 0) {
1383             continue;
1384         }
1385         SkDVector startV = test->fCoinStart.perpPt() - test->pointFirst();
1386         SkDVector endV = test->fCoinEnd.perpPt() - test->pointLast();
1387 #if DEBUG_T_SECT
1388         SkDebugf("%s startV=(%1.9g,%1.9g) endV=(%1.9g,%1.9g) dot=%1.9g\n", __FUNCTION__,
1389                 startV.fX, startV.fY, endV.fX, endV.fY, startV.dot(endV));
1390 #endif
1391         if (startV.dot(endV) <= 0) {
1392             continue;
1393         }
1394         if (!this->removeSpans(test, opp)) {
1395             return false;
1396         }
1397     } while ((test = next));
1398     return true;
1399 }
1400 
removeCoincident(SkTSpan * span,bool isBetween)1401 bool SkTSect::removeCoincident(SkTSpan* span, bool isBetween) {
1402     if (!this->unlinkSpan(span)) {
1403         return false;
1404     }
1405     if (isBetween || between(0, span->fCoinStart.perpT(), 1)) {
1406         --fActiveCount;
1407         span->fNext = fCoincident;
1408         fCoincident = span;
1409     } else {
1410         this->markSpanGone(span);
1411     }
1412     return true;
1413 }
1414 
removedEndCheck(SkTSpan * span)1415 void SkTSect::removedEndCheck(SkTSpan* span) {
1416     if (!span->fStartT) {
1417         fRemovedStartT = true;
1418     }
1419     if (1 == span->fEndT) {
1420         fRemovedEndT = true;
1421     }
1422 }
1423 
removeSpan(SkTSpan * span)1424 bool SkTSect::removeSpan(SkTSpan* span) {\
1425     this->removedEndCheck(span);
1426     if (!this->unlinkSpan(span)) {
1427         return false;
1428     }
1429     return this->markSpanGone(span);
1430 }
1431 
removeSpanRange(SkTSpan * first,SkTSpan * last)1432 void SkTSect::removeSpanRange(SkTSpan* first,
1433         SkTSpan* last) {
1434     if (first == last) {
1435         return;
1436     }
1437     SkTSpan* span = first;
1438     SkASSERT(span);
1439     SkTSpan* final = last->fNext;
1440     SkTSpan* next = span->fNext;
1441     while ((span = next) && span != final) {
1442         next = span->fNext;
1443         this->markSpanGone(span);
1444     }
1445     if (final) {
1446         final->fPrev = first;
1447     }
1448     first->fNext = final;
1449     // world may not be ready for validation here
1450     first->validate();
1451 }
1452 
removeSpans(SkTSpan * span,SkTSect * opp)1453 bool SkTSect::removeSpans(SkTSpan* span,
1454         SkTSect* opp) {
1455     SkTSpanBounded* bounded = span->fBounded;
1456     while (bounded) {
1457         SkTSpan* spanBounded = bounded->fBounded;
1458         SkTSpanBounded* next = bounded->fNext;
1459         if (span->removeBounded(spanBounded)) {  // shuffles last into position 0
1460             this->removeSpan(span);
1461         }
1462         if (spanBounded->removeBounded(span)) {
1463             opp->removeSpan(spanBounded);
1464         }
1465         if (span->fDeleted && opp->hasBounded(span)) {
1466             return false;
1467         }
1468         bounded = next;
1469     }
1470     return true;
1471 }
1472 
spanAtT(double t,SkTSpan ** priorSpan)1473 SkTSpan* SkTSect::spanAtT(double t,
1474         SkTSpan** priorSpan) {
1475     SkTSpan* test = fHead;
1476     SkTSpan* prev = nullptr;
1477     while (test && test->fEndT < t) {
1478         prev = test;
1479         test = test->fNext;
1480     }
1481     *priorSpan = prev;
1482     return test && test->fStartT <= t ? test : nullptr;
1483 }
1484 
tail()1485 SkTSpan* SkTSect::tail() {
1486     SkTSpan* result = fHead;
1487     SkTSpan* next = fHead;
1488     int safetyNet = 100000;
1489     while ((next = next->fNext)) {
1490         if (!--safetyNet) {
1491             return nullptr;
1492         }
1493         if (next->fEndT > result->fEndT) {
1494             result = next;
1495         }
1496     }
1497     return result;
1498 }
1499 
1500 /* Each span has a range of opposite spans it intersects. After the span is split in two,
1501     adjust the range to its new size */
1502 
trim(SkTSpan * span,SkTSect * opp)1503 bool SkTSect::trim(SkTSpan* span,
1504         SkTSect* opp) {
1505     FAIL_IF(!span->initBounds(fCurve));
1506     const SkTSpanBounded* testBounded = span->fBounded;
1507     while (testBounded) {
1508         SkTSpan* test = testBounded->fBounded;
1509         const SkTSpanBounded* next = testBounded->fNext;
1510         int oppSects, sects = this->intersects(span, opp, test, &oppSects);
1511         if (sects >= 1) {
1512             if (oppSects == 2) {
1513                 test->initBounds(opp->fCurve);
1514                 opp->removeAllBut(span, test, this);
1515             }
1516             if (sects == 2) {
1517                 span->initBounds(fCurve);
1518                 this->removeAllBut(test, span, opp);
1519                 return true;
1520             }
1521         } else {
1522             if (span->removeBounded(test)) {
1523                 this->removeSpan(span);
1524             }
1525             if (test->removeBounded(span)) {
1526                 opp->removeSpan(test);
1527             }
1528         }
1529         testBounded = next;
1530     }
1531     return true;
1532 }
1533 
unlinkSpan(SkTSpan * span)1534 bool SkTSect::unlinkSpan(SkTSpan* span) {
1535     SkTSpan* prev = span->fPrev;
1536     SkTSpan* next = span->fNext;
1537     if (prev) {
1538         prev->fNext = next;
1539         if (next) {
1540             next->fPrev = prev;
1541             if (next->fStartT > next->fEndT) {
1542                 return false;
1543             }
1544             // world may not be ready for validate here
1545             next->validate();
1546         }
1547     } else {
1548         fHead = next;
1549         if (next) {
1550             next->fPrev = nullptr;
1551         }
1552     }
1553     return true;
1554 }
1555 
updateBounded(SkTSpan * first,SkTSpan * last,SkTSpan * oppFirst)1556 bool SkTSect::updateBounded(SkTSpan* first,
1557         SkTSpan* last, SkTSpan* oppFirst) {
1558     SkTSpan* test = first;
1559     const SkTSpan* final = last->next();
1560     bool deleteSpan = false;
1561     do {
1562         deleteSpan |= test->removeAllBounded();
1563     } while ((test = test->fNext) != final && test);
1564     first->fBounded = nullptr;
1565     first->addBounded(oppFirst, &fHeap);
1566     // cannot call validate until remove span range is called
1567     return deleteSpan;
1568 }
1569 
validate() const1570 void SkTSect::validate() const {
1571 #if DEBUG_VALIDATE
1572     int count = 0;
1573     double last = 0;
1574     if (fHead) {
1575         const SkTSpan* span = fHead;
1576         SkASSERT(!span->fPrev);
1577         const SkTSpan* next;
1578         do {
1579             span->validate();
1580             SkASSERT(span->fStartT >= last);
1581             last = span->fEndT;
1582             ++count;
1583             next = span->fNext;
1584             SkASSERT(next != span);
1585         } while ((span = next) != nullptr);
1586     }
1587     SkASSERT(count == fActiveCount);
1588 #endif
1589 #if DEBUG_T_SECT
1590     SkASSERT(fActiveCount <= fDebugAllocatedCount);
1591     int deletedCount = 0;
1592     const SkTSpan* deleted = fDeleted;
1593     while (deleted) {
1594         ++deletedCount;
1595         deleted = deleted->fNext;
1596     }
1597     const SkTSpan* coincident = fCoincident;
1598     while (coincident) {
1599         ++deletedCount;
1600         coincident = coincident->fNext;
1601     }
1602     SkASSERT(fActiveCount + deletedCount == fDebugAllocatedCount);
1603 #endif
1604 }
1605 
validateBounded() const1606 void SkTSect::validateBounded() const {
1607 #if DEBUG_VALIDATE
1608     if (!fHead) {
1609         return;
1610     }
1611     const SkTSpan* span = fHead;
1612     do {
1613         span->validateBounded();
1614     } while ((span = span->fNext) != nullptr);
1615 #endif
1616 }
1617 
EndsEqual(const SkTSect * sect1,const SkTSect * sect2,SkIntersections * intersections)1618 int SkTSect::EndsEqual(const SkTSect* sect1,
1619         const SkTSect* sect2, SkIntersections* intersections) {
1620     int zeroOneSet = 0;
1621     if (sect1->fCurve[0] == sect2->fCurve[0]) {
1622         zeroOneSet |= kZeroS1Set | kZeroS2Set;
1623         intersections->insert(0, 0, sect1->fCurve[0]);
1624     }
1625     if (sect1->fCurve[0] == sect2->pointLast()) {
1626         zeroOneSet |= kZeroS1Set | kOneS2Set;
1627         intersections->insert(0, 1, sect1->fCurve[0]);
1628     }
1629     if (sect1->pointLast() == sect2->fCurve[0]) {
1630         zeroOneSet |= kOneS1Set | kZeroS2Set;
1631         intersections->insert(1, 0, sect1->pointLast());
1632     }
1633     if (sect1->pointLast() == sect2->pointLast()) {
1634         zeroOneSet |= kOneS1Set | kOneS2Set;
1635             intersections->insert(1, 1, sect1->pointLast());
1636     }
1637     // check for zero
1638     if (!(zeroOneSet & (kZeroS1Set | kZeroS2Set))
1639             && sect1->fCurve[0].approximatelyEqual(sect2->fCurve[0])) {
1640         zeroOneSet |= kZeroS1Set | kZeroS2Set;
1641         intersections->insertNear(0, 0, sect1->fCurve[0], sect2->fCurve[0]);
1642     }
1643     if (!(zeroOneSet & (kZeroS1Set | kOneS2Set))
1644             && sect1->fCurve[0].approximatelyEqual(sect2->pointLast())) {
1645         zeroOneSet |= kZeroS1Set | kOneS2Set;
1646         intersections->insertNear(0, 1, sect1->fCurve[0], sect2->pointLast());
1647     }
1648     // check for one
1649     if (!(zeroOneSet & (kOneS1Set | kZeroS2Set))
1650             && sect1->pointLast().approximatelyEqual(sect2->fCurve[0])) {
1651         zeroOneSet |= kOneS1Set | kZeroS2Set;
1652         intersections->insertNear(1, 0, sect1->pointLast(), sect2->fCurve[0]);
1653     }
1654     if (!(zeroOneSet & (kOneS1Set | kOneS2Set))
1655             && sect1->pointLast().approximatelyEqual(sect2->pointLast())) {
1656         zeroOneSet |= kOneS1Set | kOneS2Set;
1657         intersections->insertNear(1, 1, sect1->pointLast(), sect2->pointLast());
1658     }
1659     return zeroOneSet;
1660 }
1661 
1662 struct SkClosestRecord {
operator <SkClosestRecord1663     bool operator<(const SkClosestRecord& rh) const {
1664         return fClosest < rh.fClosest;
1665     }
1666 
addIntersectionSkClosestRecord1667     void addIntersection(SkIntersections* intersections) const {
1668         double r1t = fC1Index ? fC1Span->endT() : fC1Span->startT();
1669         double r2t = fC2Index ? fC2Span->endT() : fC2Span->startT();
1670         intersections->insert(r1t, r2t, fC1Span->part()[fC1Index]);
1671     }
1672 
findEndSkClosestRecord1673     void findEnd(const SkTSpan* span1, const SkTSpan* span2,
1674             int c1Index, int c2Index) {
1675         const SkTCurve& c1 = span1->part();
1676         const SkTCurve& c2 = span2->part();
1677         if (!c1[c1Index].approximatelyEqual(c2[c2Index])) {
1678             return;
1679         }
1680         double dist = c1[c1Index].distanceSquared(c2[c2Index]);
1681         if (fClosest < dist) {
1682             return;
1683         }
1684         fC1Span = span1;
1685         fC2Span = span2;
1686         fC1StartT = span1->startT();
1687         fC1EndT = span1->endT();
1688         fC2StartT = span2->startT();
1689         fC2EndT = span2->endT();
1690         fC1Index = c1Index;
1691         fC2Index = c2Index;
1692         fClosest = dist;
1693     }
1694 
matesWithSkClosestRecord1695     bool matesWith(const SkClosestRecord& mate  SkDEBUGPARAMS(SkIntersections* i)) const {
1696         SkOPOBJASSERT(i, fC1Span == mate.fC1Span || fC1Span->endT() <= mate.fC1Span->startT()
1697                 || mate.fC1Span->endT() <= fC1Span->startT());
1698         SkOPOBJASSERT(i, fC2Span == mate.fC2Span || fC2Span->endT() <= mate.fC2Span->startT()
1699                 || mate.fC2Span->endT() <= fC2Span->startT());
1700         return fC1Span == mate.fC1Span || fC1Span->endT() == mate.fC1Span->startT()
1701                 || fC1Span->startT() == mate.fC1Span->endT()
1702                 || fC2Span == mate.fC2Span
1703                 || fC2Span->endT() == mate.fC2Span->startT()
1704                 || fC2Span->startT() == mate.fC2Span->endT();
1705     }
1706 
mergeSkClosestRecord1707     void merge(const SkClosestRecord& mate) {
1708         fC1Span = mate.fC1Span;
1709         fC2Span = mate.fC2Span;
1710         fClosest = mate.fClosest;
1711         fC1Index = mate.fC1Index;
1712         fC2Index = mate.fC2Index;
1713     }
1714 
resetSkClosestRecord1715     void reset() {
1716         fClosest = FLT_MAX;
1717         SkDEBUGCODE(fC1Span = nullptr);
1718         SkDEBUGCODE(fC2Span = nullptr);
1719         SkDEBUGCODE(fC1Index = fC2Index = -1);
1720     }
1721 
updateSkClosestRecord1722     void update(const SkClosestRecord& mate) {
1723         fC1StartT = std::min(fC1StartT, mate.fC1StartT);
1724         fC1EndT = std::max(fC1EndT, mate.fC1EndT);
1725         fC2StartT = std::min(fC2StartT, mate.fC2StartT);
1726         fC2EndT = std::max(fC2EndT, mate.fC2EndT);
1727     }
1728 
1729     const SkTSpan* fC1Span;
1730     const SkTSpan* fC2Span;
1731     double fC1StartT;
1732     double fC1EndT;
1733     double fC2StartT;
1734     double fC2EndT;
1735     double fClosest;
1736     int fC1Index;
1737     int fC2Index;
1738 };
1739 
1740 struct SkClosestSect {
SkClosestSectSkClosestSect1741     SkClosestSect()
1742         : fUsed(0) {
1743         fClosest.push_back().reset();
1744     }
1745 
findSkClosestSect1746     bool find(const SkTSpan* span1, const SkTSpan* span2
1747             SkDEBUGPARAMS(SkIntersections* i)) {
1748         SkClosestRecord* record = &fClosest[fUsed];
1749         record->findEnd(span1, span2, 0, 0);
1750         record->findEnd(span1, span2, 0, span2->part().pointLast());
1751         record->findEnd(span1, span2, span1->part().pointLast(), 0);
1752         record->findEnd(span1, span2, span1->part().pointLast(), span2->part().pointLast());
1753         if (record->fClosest == FLT_MAX) {
1754             return false;
1755         }
1756         for (int index = 0; index < fUsed; ++index) {
1757             SkClosestRecord* test = &fClosest[index];
1758             if (test->matesWith(*record  SkDEBUGPARAMS(i))) {
1759                 if (test->fClosest > record->fClosest) {
1760                     test->merge(*record);
1761                 }
1762                 test->update(*record);
1763                 record->reset();
1764                 return false;
1765             }
1766         }
1767         ++fUsed;
1768         fClosest.push_back().reset();
1769         return true;
1770     }
1771 
finishSkClosestSect1772     void finish(SkIntersections* intersections) const {
1773         STArray<SkDCubic::kMaxIntersections * 3,
1774                 const SkClosestRecord*, true> closestPtrs;
1775         for (int index = 0; index < fUsed; ++index) {
1776             closestPtrs.push_back(&fClosest[index]);
1777         }
1778         SkTQSort<const SkClosestRecord>(closestPtrs.begin(), closestPtrs.end());
1779         for (int index = 0; index < fUsed; ++index) {
1780             const SkClosestRecord* test = closestPtrs[index];
1781             test->addIntersection(intersections);
1782         }
1783     }
1784 
1785     // this is oversized so that an extra records can merge into final one
1786     STArray<SkDCubic::kMaxIntersections * 2, SkClosestRecord, true> fClosest;
1787     int fUsed;
1788 };
1789 
1790 // returns true if the rect is too small to consider
1791 
BinarySearch(SkTSect * sect1,SkTSect * sect2,SkIntersections * intersections)1792 void SkTSect::BinarySearch(SkTSect* sect1,
1793         SkTSect* sect2, SkIntersections* intersections) {
1794 #if DEBUG_T_SECT_DUMP > 1
1795     gDumpTSectNum = 0;
1796 #endif
1797     SkDEBUGCODE(sect1->fOppSect = sect2);
1798     SkDEBUGCODE(sect2->fOppSect = sect1);
1799     intersections->reset();
1800     intersections->setMax(sect1->fCurve.maxIntersections() + 4);  // give extra for slop
1801     SkTSpan* span1 = sect1->fHead;
1802     SkTSpan* span2 = sect2->fHead;
1803     int oppSect, sect = sect1->intersects(span1, sect2, span2, &oppSect);
1804 //    SkASSERT(between(0, sect, 2));
1805     if (!sect) {
1806         return;
1807     }
1808     if (sect == 2 && oppSect == 2) {
1809         (void) EndsEqual(sect1, sect2, intersections);
1810         return;
1811     }
1812     span1->addBounded(span2, &sect1->fHeap);
1813     span2->addBounded(span1, &sect2->fHeap);
1814     const int kMaxCoinLoopCount = 8;
1815     int coinLoopCount = kMaxCoinLoopCount;
1816     double start1s SK_INIT_TO_AVOID_WARNING;
1817     double start1e SK_INIT_TO_AVOID_WARNING;
1818     do {
1819         // find the largest bounds
1820         SkTSpan* largest1 = sect1->boundsMax();
1821         if (!largest1) {
1822             if (sect1->fHung) {
1823                 return;
1824             }
1825             break;
1826         }
1827         SkTSpan* largest2 = sect2->boundsMax();
1828         // split it
1829         if (!largest2 || (largest1 && (largest1->fBoundsMax > largest2->fBoundsMax
1830                 || (!largest1->fCollapsed && largest2->fCollapsed)))) {
1831             if (sect2->fHung) {
1832                 return;
1833             }
1834             if (largest1->fCollapsed) {
1835                 break;
1836             }
1837             sect1->resetRemovedEnds();
1838             sect2->resetRemovedEnds();
1839             // trim parts that don't intersect the opposite
1840             SkTSpan* half1 = sect1->addOne();
1841             SkDEBUGCODE(half1->debugSetGlobalState(sect1->globalState()));
1842             if (!half1->split(largest1, &sect1->fHeap)) {
1843                 break;
1844             }
1845             if (!sect1->trim(largest1, sect2)) {
1846                 SkOPOBJASSERT(intersections, 0);
1847                 return;
1848             }
1849             if (!sect1->trim(half1, sect2)) {
1850                 SkOPOBJASSERT(intersections, 0);
1851                 return;
1852             }
1853         } else {
1854             if (largest2->fCollapsed) {
1855                 break;
1856             }
1857             sect1->resetRemovedEnds();
1858             sect2->resetRemovedEnds();
1859             // trim parts that don't intersect the opposite
1860             SkTSpan* half2 = sect2->addOne();
1861             SkDEBUGCODE(half2->debugSetGlobalState(sect2->globalState()));
1862             if (!half2->split(largest2, &sect2->fHeap)) {
1863                 break;
1864             }
1865             if (!sect2->trim(largest2, sect1)) {
1866                 SkOPOBJASSERT(intersections, 0);
1867                 return;
1868             }
1869             if (!sect2->trim(half2, sect1)) {
1870                 SkOPOBJASSERT(intersections, 0);
1871                 return;
1872             }
1873         }
1874         sect1->validate();
1875         sect2->validate();
1876 #if DEBUG_T_SECT_LOOP_COUNT
1877         intersections->debugBumpLoopCount(SkIntersections::kIterations_DebugLoop);
1878 #endif
1879         // if there are 9 or more continuous spans on both sects, suspect coincidence
1880         if (sect1->fActiveCount >= COINCIDENT_SPAN_COUNT
1881                 && sect2->fActiveCount >= COINCIDENT_SPAN_COUNT) {
1882             if (coinLoopCount == kMaxCoinLoopCount) {
1883                 start1s = sect1->fHead->fStartT;
1884                 start1e = sect1->tail()->fEndT;
1885             }
1886             if (!sect1->coincidentCheck(sect2)) {
1887                 return;
1888             }
1889             sect1->validate();
1890             sect2->validate();
1891 #if DEBUG_T_SECT_LOOP_COUNT
1892             intersections->debugBumpLoopCount(SkIntersections::kCoinCheck_DebugLoop);
1893 #endif
1894             if (!--coinLoopCount && sect1->fHead && sect2->fHead) {
1895                 /* All known working cases resolve in two tries. Sadly, cubicConicTests[0]
1896                    gets stuck in a loop. It adds an extension to allow a coincident end
1897                    perpendicular to track its intersection in the opposite curve. However,
1898                    the bounding box of the extension does not intersect the original curve,
1899                    so the extension is discarded, only to be added again the next time around. */
1900                 sect1->coincidentForce(sect2, start1s, start1e);
1901                 sect1->validate();
1902                 sect2->validate();
1903             }
1904         }
1905         if (sect1->fActiveCount >= COINCIDENT_SPAN_COUNT
1906                 && sect2->fActiveCount >= COINCIDENT_SPAN_COUNT) {
1907             if (!sect1->fHead) {
1908                 return;
1909             }
1910             sect1->computePerpendiculars(sect2, sect1->fHead, sect1->tail());
1911             if (!sect2->fHead) {
1912                 return;
1913             }
1914             sect2->computePerpendiculars(sect1, sect2->fHead, sect2->tail());
1915             if (!sect1->removeByPerpendicular(sect2)) {
1916                 return;
1917             }
1918             sect1->validate();
1919             sect2->validate();
1920 #if DEBUG_T_SECT_LOOP_COUNT
1921             intersections->debugBumpLoopCount(SkIntersections::kComputePerp_DebugLoop);
1922 #endif
1923             if (sect1->collapsed() > sect1->fCurve.maxIntersections()) {
1924                 break;
1925             }
1926         }
1927 #if DEBUG_T_SECT_DUMP
1928         sect1->dumpBoth(sect2);
1929 #endif
1930         if (!sect1->fHead || !sect2->fHead) {
1931             break;
1932         }
1933     } while (true);
1934     SkTSpan* coincident = sect1->fCoincident;
1935     if (coincident) {
1936         // if there is more than one coincident span, check loosely to see if they should be joined
1937         if (coincident->fNext) {
1938             sect1->mergeCoincidence(sect2);
1939             coincident = sect1->fCoincident;
1940         }
1941         SkASSERT(sect2->fCoincident);  // courtesy check : coincidence only looks at sect 1
1942         do {
1943             if (!coincident) {
1944                 return;
1945             }
1946             if (!coincident->fCoinStart.isMatch()) {
1947                 continue;
1948             }
1949             if (!coincident->fCoinEnd.isMatch()) {
1950                 continue;
1951             }
1952             double perpT = coincident->fCoinStart.perpT();
1953             if (perpT < 0) {
1954                 return;
1955             }
1956             int index = intersections->insertCoincident(coincident->fStartT,
1957                     perpT, coincident->pointFirst());
1958             if ((intersections->insertCoincident(coincident->fEndT,
1959                     coincident->fCoinEnd.perpT(),
1960                     coincident->pointLast()) < 0) && index >= 0) {
1961                 intersections->clearCoincidence(index);
1962             }
1963         } while ((coincident = coincident->fNext));
1964     }
1965     int zeroOneSet = EndsEqual(sect1, sect2, intersections);
1966 //    if (!sect1->fHead || !sect2->fHead) {
1967         // if the final iteration contains an end (0 or 1),
1968         if (sect1->fRemovedStartT && !(zeroOneSet & kZeroS1Set)) {
1969             SkTCoincident perp;   // intersect perpendicular with opposite curve
1970             perp.setPerp(sect1->fCurve, 0, sect1->fCurve[0], sect2->fCurve);
1971             if (perp.isMatch()) {
1972                 intersections->insert(0, perp.perpT(), perp.perpPt());
1973             }
1974         }
1975         if (sect1->fRemovedEndT && !(zeroOneSet & kOneS1Set)) {
1976             SkTCoincident perp;
1977             perp.setPerp(sect1->fCurve, 1, sect1->pointLast(), sect2->fCurve);
1978             if (perp.isMatch()) {
1979                 intersections->insert(1, perp.perpT(), perp.perpPt());
1980             }
1981         }
1982         if (sect2->fRemovedStartT && !(zeroOneSet & kZeroS2Set)) {
1983             SkTCoincident perp;
1984             perp.setPerp(sect2->fCurve, 0, sect2->fCurve[0], sect1->fCurve);
1985             if (perp.isMatch()) {
1986                 intersections->insert(perp.perpT(), 0, perp.perpPt());
1987             }
1988         }
1989         if (sect2->fRemovedEndT && !(zeroOneSet & kOneS2Set)) {
1990             SkTCoincident perp;
1991             perp.setPerp(sect2->fCurve, 1, sect2->pointLast(), sect1->fCurve);
1992             if (perp.isMatch()) {
1993                 intersections->insert(perp.perpT(), 1, perp.perpPt());
1994             }
1995         }
1996 //    }
1997     if (!sect1->fHead || !sect2->fHead) {
1998         return;
1999     }
2000     sect1->recoverCollapsed();
2001     sect2->recoverCollapsed();
2002     SkTSpan* result1 = sect1->fHead;
2003     // check heads and tails for zero and ones and insert them if we haven't already done so
2004     const SkTSpan* head1 = result1;
2005     if (!(zeroOneSet & kZeroS1Set) && approximately_less_than_zero(head1->fStartT)) {
2006         const SkDPoint& start1 = sect1->fCurve[0];
2007         if (head1->isBounded()) {
2008             double t = head1->closestBoundedT(start1);
2009             if (sect2->fCurve.ptAtT(t).approximatelyEqual(start1)) {
2010                 intersections->insert(0, t, start1);
2011             }
2012         }
2013     }
2014     const SkTSpan* head2 = sect2->fHead;
2015     if (!(zeroOneSet & kZeroS2Set) && approximately_less_than_zero(head2->fStartT)) {
2016         const SkDPoint& start2 = sect2->fCurve[0];
2017         if (head2->isBounded()) {
2018             double t = head2->closestBoundedT(start2);
2019             if (sect1->fCurve.ptAtT(t).approximatelyEqual(start2)) {
2020                 intersections->insert(t, 0, start2);
2021             }
2022         }
2023     }
2024     if (!(zeroOneSet & kOneS1Set)) {
2025         const SkTSpan* tail1 = sect1->tail();
2026         if (!tail1) {
2027             return;
2028         }
2029         if (approximately_greater_than_one(tail1->fEndT)) {
2030             const SkDPoint& end1 = sect1->pointLast();
2031             if (tail1->isBounded()) {
2032                 double t = tail1->closestBoundedT(end1);
2033                 if (sect2->fCurve.ptAtT(t).approximatelyEqual(end1)) {
2034                     intersections->insert(1, t, end1);
2035                 }
2036             }
2037         }
2038     }
2039     if (!(zeroOneSet & kOneS2Set)) {
2040         const SkTSpan* tail2 = sect2->tail();
2041         if (!tail2) {
2042             return;
2043         }
2044         if (approximately_greater_than_one(tail2->fEndT)) {
2045             const SkDPoint& end2 = sect2->pointLast();
2046             if (tail2->isBounded()) {
2047                 double t = tail2->closestBoundedT(end2);
2048                 if (sect1->fCurve.ptAtT(t).approximatelyEqual(end2)) {
2049                     intersections->insert(t, 1, end2);
2050                 }
2051             }
2052         }
2053     }
2054     SkClosestSect closest;
2055     do {
2056         while (result1 && result1->fCoinStart.isMatch() && result1->fCoinEnd.isMatch()) {
2057             result1 = result1->fNext;
2058         }
2059         if (!result1) {
2060             break;
2061         }
2062         SkTSpan* result2 = sect2->fHead;
2063         while (result2) {
2064             closest.find(result1, result2  SkDEBUGPARAMS(intersections));
2065             result2 = result2->fNext;
2066         }
2067     } while ((result1 = result1->fNext));
2068     closest.finish(intersections);
2069     // if there is more than one intersection and it isn't already coincident, check
2070     int last = intersections->used() - 1;
2071     for (int index = 0; index < last; ) {
2072         if (intersections->isCoincident(index) && intersections->isCoincident(index + 1)) {
2073             ++index;
2074             continue;
2075         }
2076         double midT = ((*intersections)[0][index] + (*intersections)[0][index + 1]) / 2;
2077         SkDPoint midPt = sect1->fCurve.ptAtT(midT);
2078         // intersect perpendicular with opposite curve
2079         SkTCoincident perp;
2080         perp.setPerp(sect1->fCurve, midT, midPt, sect2->fCurve);
2081         if (!perp.isMatch()) {
2082             ++index;
2083             continue;
2084         }
2085         if (intersections->isCoincident(index)) {
2086             intersections->removeOne(index);
2087             --last;
2088         } else if (intersections->isCoincident(index + 1)) {
2089             intersections->removeOne(index + 1);
2090             --last;
2091         } else {
2092             intersections->setCoincident(index++);
2093         }
2094         intersections->setCoincident(index);
2095     }
2096     SkOPOBJASSERT(intersections, intersections->used() <= sect1->fCurve.maxIntersections());
2097 }
2098 
intersect(const SkDQuad & q1,const SkDQuad & q2)2099 int SkIntersections::intersect(const SkDQuad& q1, const SkDQuad& q2) {
2100     SkTQuad quad1(q1);
2101     SkTQuad quad2(q2);
2102     SkTSect sect1(quad1  SkDEBUGPARAMS(globalState())  PATH_OPS_DEBUG_T_SECT_PARAMS(1));
2103     SkTSect sect2(quad2  SkDEBUGPARAMS(globalState())  PATH_OPS_DEBUG_T_SECT_PARAMS(2));
2104     SkTSect::BinarySearch(&sect1, &sect2, this);
2105     return used();
2106 }
2107 
intersect(const SkDConic & c,const SkDQuad & q)2108 int SkIntersections::intersect(const SkDConic& c, const SkDQuad& q) {
2109     SkTConic conic(c);
2110     SkTQuad quad(q);
2111     SkTSect sect1(conic  SkDEBUGPARAMS(globalState())  PATH_OPS_DEBUG_T_SECT_PARAMS(1));
2112     SkTSect sect2(quad  SkDEBUGPARAMS(globalState())  PATH_OPS_DEBUG_T_SECT_PARAMS(2));
2113     SkTSect::BinarySearch(&sect1, &sect2, this);
2114     return used();
2115 }
2116 
intersect(const SkDConic & c1,const SkDConic & c2)2117 int SkIntersections::intersect(const SkDConic& c1, const SkDConic& c2) {
2118     SkTConic conic1(c1);
2119     SkTConic conic2(c2);
2120     SkTSect sect1(conic1  SkDEBUGPARAMS(globalState())  PATH_OPS_DEBUG_T_SECT_PARAMS(1));
2121     SkTSect sect2(conic2  SkDEBUGPARAMS(globalState())  PATH_OPS_DEBUG_T_SECT_PARAMS(2));
2122     SkTSect::BinarySearch(&sect1, &sect2, this);
2123     return used();
2124 }
2125 
intersect(const SkDCubic & c,const SkDQuad & q)2126 int SkIntersections::intersect(const SkDCubic& c, const SkDQuad& q) {
2127     SkTCubic cubic(c);
2128     SkTQuad quad(q);
2129     SkTSect sect1(cubic  SkDEBUGPARAMS(globalState())  PATH_OPS_DEBUG_T_SECT_PARAMS(1));
2130     SkTSect sect2(quad  SkDEBUGPARAMS(globalState())  PATH_OPS_DEBUG_T_SECT_PARAMS(2));
2131     SkTSect::BinarySearch(&sect1, &sect2, this);
2132     return used();
2133 }
2134 
intersect(const SkDCubic & cu,const SkDConic & co)2135 int SkIntersections::intersect(const SkDCubic& cu, const SkDConic& co) {
2136     SkTCubic cubic(cu);
2137     SkTConic conic(co);
2138     SkTSect sect1(cubic  SkDEBUGPARAMS(globalState())  PATH_OPS_DEBUG_T_SECT_PARAMS(1));
2139     SkTSect sect2(conic  SkDEBUGPARAMS(globalState())  PATH_OPS_DEBUG_T_SECT_PARAMS(2));
2140     SkTSect::BinarySearch(&sect1, &sect2, this);
2141     return used();
2142 
2143 }
2144 
intersect(const SkDCubic & c1,const SkDCubic & c2)2145 int SkIntersections::intersect(const SkDCubic& c1, const SkDCubic& c2) {
2146     SkTCubic cubic1(c1);
2147     SkTCubic cubic2(c2);
2148     SkTSect sect1(cubic1  SkDEBUGPARAMS(globalState())  PATH_OPS_DEBUG_T_SECT_PARAMS(1));
2149     SkTSect sect2(cubic2   SkDEBUGPARAMS(globalState())  PATH_OPS_DEBUG_T_SECT_PARAMS(2));
2150     SkTSect::BinarySearch(&sect1, &sect2, this);
2151     return used();
2152 }
2153