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