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