1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2015 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// given a prospective edge, compute its initial winding by projecting a ray
9cb93a386Sopenharmony_ci// if the ray hits another edge
10cb93a386Sopenharmony_ci    // if the edge doesn't have a winding yet, hop up to that edge and start over
11cb93a386Sopenharmony_ci        // concern : check for hops forming a loop
12cb93a386Sopenharmony_ci    // if the edge is unsortable, or
13cb93a386Sopenharmony_ci    // the intersection is nearly at the ends, or
14cb93a386Sopenharmony_ci    // the tangent at the intersection is nearly coincident to the ray,
15cb93a386Sopenharmony_ci        // choose a different ray and try again
16cb93a386Sopenharmony_ci            // concern : if it is unable to succeed after N tries, try another edge? direction?
17cb93a386Sopenharmony_ci// if no edge is hit, compute the winding directly
18cb93a386Sopenharmony_ci
19cb93a386Sopenharmony_ci// given the top span, project the most perpendicular ray and look for intersections
20cb93a386Sopenharmony_ci    // let's try up and then down. What the hey
21cb93a386Sopenharmony_ci
22cb93a386Sopenharmony_ci// bestXY is initialized by caller with basePt
23cb93a386Sopenharmony_ci
24cb93a386Sopenharmony_ci#include "src/core/SkTSort.h"
25cb93a386Sopenharmony_ci#include "src/pathops/SkOpContour.h"
26cb93a386Sopenharmony_ci#include "src/pathops/SkOpSegment.h"
27cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsCurve.h"
28cb93a386Sopenharmony_ci
29cb93a386Sopenharmony_ci#include <utility>
30cb93a386Sopenharmony_ci
31cb93a386Sopenharmony_cienum class SkOpRayDir {
32cb93a386Sopenharmony_ci    kLeft,
33cb93a386Sopenharmony_ci    kTop,
34cb93a386Sopenharmony_ci    kRight,
35cb93a386Sopenharmony_ci    kBottom,
36cb93a386Sopenharmony_ci};
37cb93a386Sopenharmony_ci
38cb93a386Sopenharmony_ci#if DEBUG_WINDING
39cb93a386Sopenharmony_ciconst char* gDebugRayDirName[] = {
40cb93a386Sopenharmony_ci    "kLeft",
41cb93a386Sopenharmony_ci    "kTop",
42cb93a386Sopenharmony_ci    "kRight",
43cb93a386Sopenharmony_ci    "kBottom"
44cb93a386Sopenharmony_ci};
45cb93a386Sopenharmony_ci#endif
46cb93a386Sopenharmony_ci
47cb93a386Sopenharmony_cistatic int xy_index(SkOpRayDir dir) {
48cb93a386Sopenharmony_ci    return static_cast<int>(dir) & 1;
49cb93a386Sopenharmony_ci}
50cb93a386Sopenharmony_ci
51cb93a386Sopenharmony_cistatic SkScalar pt_xy(const SkPoint& pt, SkOpRayDir dir) {
52cb93a386Sopenharmony_ci    return (&pt.fX)[xy_index(dir)];
53cb93a386Sopenharmony_ci}
54cb93a386Sopenharmony_ci
55cb93a386Sopenharmony_cistatic SkScalar pt_yx(const SkPoint& pt, SkOpRayDir dir) {
56cb93a386Sopenharmony_ci    return (&pt.fX)[!xy_index(dir)];
57cb93a386Sopenharmony_ci}
58cb93a386Sopenharmony_ci
59cb93a386Sopenharmony_cistatic double pt_dxdy(const SkDVector& v, SkOpRayDir dir) {
60cb93a386Sopenharmony_ci    return (&v.fX)[xy_index(dir)];
61cb93a386Sopenharmony_ci}
62cb93a386Sopenharmony_ci
63cb93a386Sopenharmony_cistatic double pt_dydx(const SkDVector& v, SkOpRayDir dir) {
64cb93a386Sopenharmony_ci    return (&v.fX)[!xy_index(dir)];
65cb93a386Sopenharmony_ci}
66cb93a386Sopenharmony_ci
67cb93a386Sopenharmony_cistatic SkScalar rect_side(const SkRect& r, SkOpRayDir dir) {
68cb93a386Sopenharmony_ci    return (&r.fLeft)[static_cast<int>(dir)];
69cb93a386Sopenharmony_ci}
70cb93a386Sopenharmony_ci
71cb93a386Sopenharmony_cistatic bool sideways_overlap(const SkRect& rect, const SkPoint& pt, SkOpRayDir dir) {
72cb93a386Sopenharmony_ci    int i = !xy_index(dir);
73cb93a386Sopenharmony_ci    return approximately_between((&rect.fLeft)[i], (&pt.fX)[i], (&rect.fRight)[i]);
74cb93a386Sopenharmony_ci}
75cb93a386Sopenharmony_ci
76cb93a386Sopenharmony_cistatic bool less_than(SkOpRayDir dir) {
77cb93a386Sopenharmony_ci    return static_cast<bool>((static_cast<int>(dir) & 2) == 0);
78cb93a386Sopenharmony_ci}
79cb93a386Sopenharmony_ci
80cb93a386Sopenharmony_cistatic bool ccw_dxdy(const SkDVector& v, SkOpRayDir dir) {
81cb93a386Sopenharmony_ci    bool vPartPos = pt_dydx(v, dir) > 0;
82cb93a386Sopenharmony_ci    bool leftBottom = ((static_cast<int>(dir) + 1) & 2) != 0;
83cb93a386Sopenharmony_ci    return vPartPos == leftBottom;
84cb93a386Sopenharmony_ci}
85cb93a386Sopenharmony_ci
86cb93a386Sopenharmony_cistruct SkOpRayHit {
87cb93a386Sopenharmony_ci    SkOpRayDir makeTestBase(SkOpSpan* span, double t) {
88cb93a386Sopenharmony_ci        fNext = nullptr;
89cb93a386Sopenharmony_ci        fSpan = span;
90cb93a386Sopenharmony_ci        fT = span->t() * (1 - t) + span->next()->t() * t;
91cb93a386Sopenharmony_ci        SkOpSegment* segment = span->segment();
92cb93a386Sopenharmony_ci        fSlope = segment->dSlopeAtT(fT);
93cb93a386Sopenharmony_ci        fPt = segment->ptAtT(fT);
94cb93a386Sopenharmony_ci        fValid = true;
95cb93a386Sopenharmony_ci        return fabs(fSlope.fX) < fabs(fSlope.fY) ? SkOpRayDir::kLeft : SkOpRayDir::kTop;
96cb93a386Sopenharmony_ci    }
97cb93a386Sopenharmony_ci
98cb93a386Sopenharmony_ci    SkOpRayHit* fNext;
99cb93a386Sopenharmony_ci    SkOpSpan* fSpan;
100cb93a386Sopenharmony_ci    SkPoint fPt;
101cb93a386Sopenharmony_ci    double fT;
102cb93a386Sopenharmony_ci    SkDVector fSlope;
103cb93a386Sopenharmony_ci    bool fValid;
104cb93a386Sopenharmony_ci};
105cb93a386Sopenharmony_ci
106cb93a386Sopenharmony_civoid SkOpContour::rayCheck(const SkOpRayHit& base, SkOpRayDir dir, SkOpRayHit** hits,
107cb93a386Sopenharmony_ci                           SkArenaAlloc* allocator) {
108cb93a386Sopenharmony_ci    // if the bounds extreme is outside the best, we're done
109cb93a386Sopenharmony_ci    SkScalar baseXY = pt_xy(base.fPt, dir);
110cb93a386Sopenharmony_ci    SkScalar boundsXY = rect_side(fBounds, dir);
111cb93a386Sopenharmony_ci    bool checkLessThan = less_than(dir);
112cb93a386Sopenharmony_ci    if (!approximately_equal(baseXY, boundsXY) && (baseXY < boundsXY) == checkLessThan) {
113cb93a386Sopenharmony_ci        return;
114cb93a386Sopenharmony_ci    }
115cb93a386Sopenharmony_ci    SkOpSegment* testSegment = &fHead;
116cb93a386Sopenharmony_ci    do {
117cb93a386Sopenharmony_ci        testSegment->rayCheck(base, dir, hits, allocator);
118cb93a386Sopenharmony_ci    } while ((testSegment = testSegment->next()));
119cb93a386Sopenharmony_ci}
120cb93a386Sopenharmony_ci
121cb93a386Sopenharmony_civoid SkOpSegment::rayCheck(const SkOpRayHit& base, SkOpRayDir dir, SkOpRayHit** hits,
122cb93a386Sopenharmony_ci                           SkArenaAlloc* allocator) {
123cb93a386Sopenharmony_ci    if (!sideways_overlap(fBounds, base.fPt, dir)) {
124cb93a386Sopenharmony_ci        return;
125cb93a386Sopenharmony_ci    }
126cb93a386Sopenharmony_ci    SkScalar baseXY = pt_xy(base.fPt, dir);
127cb93a386Sopenharmony_ci    SkScalar boundsXY = rect_side(fBounds, dir);
128cb93a386Sopenharmony_ci    bool checkLessThan = less_than(dir);
129cb93a386Sopenharmony_ci    if (!approximately_equal(baseXY, boundsXY) && (baseXY < boundsXY) == checkLessThan) {
130cb93a386Sopenharmony_ci        return;
131cb93a386Sopenharmony_ci    }
132cb93a386Sopenharmony_ci    double tVals[3];
133cb93a386Sopenharmony_ci    SkScalar baseYX = pt_yx(base.fPt, dir);
134cb93a386Sopenharmony_ci    int roots = (*CurveIntercept[fVerb * 2 + xy_index(dir)])(fPts, fWeight, baseYX, tVals);
135cb93a386Sopenharmony_ci    for (int index = 0; index < roots; ++index) {
136cb93a386Sopenharmony_ci        double t = tVals[index];
137cb93a386Sopenharmony_ci        if (base.fSpan->segment() == this && approximately_equal(base.fT, t)) {
138cb93a386Sopenharmony_ci            continue;
139cb93a386Sopenharmony_ci        }
140cb93a386Sopenharmony_ci        SkDVector slope;
141cb93a386Sopenharmony_ci        SkPoint pt;
142cb93a386Sopenharmony_ci        SkDEBUGCODE(sk_bzero(&slope, sizeof(slope)));
143cb93a386Sopenharmony_ci        bool valid = false;
144cb93a386Sopenharmony_ci        if (approximately_zero(t)) {
145cb93a386Sopenharmony_ci            pt = fPts[0];
146cb93a386Sopenharmony_ci        } else if (approximately_equal(t, 1)) {
147cb93a386Sopenharmony_ci            pt = fPts[SkPathOpsVerbToPoints(fVerb)];
148cb93a386Sopenharmony_ci        } else {
149cb93a386Sopenharmony_ci            SkASSERT(between(0, t, 1));
150cb93a386Sopenharmony_ci            pt = this->ptAtT(t);
151cb93a386Sopenharmony_ci            if (SkDPoint::ApproximatelyEqual(pt, base.fPt)) {
152cb93a386Sopenharmony_ci                if (base.fSpan->segment() == this) {
153cb93a386Sopenharmony_ci                    continue;
154cb93a386Sopenharmony_ci                }
155cb93a386Sopenharmony_ci            } else {
156cb93a386Sopenharmony_ci                SkScalar ptXY = pt_xy(pt, dir);
157cb93a386Sopenharmony_ci                if (!approximately_equal(baseXY, ptXY) && (baseXY < ptXY) == checkLessThan) {
158cb93a386Sopenharmony_ci                    continue;
159cb93a386Sopenharmony_ci                }
160cb93a386Sopenharmony_ci                slope = this->dSlopeAtT(t);
161cb93a386Sopenharmony_ci                if (fVerb == SkPath::kCubic_Verb && base.fSpan->segment() == this
162cb93a386Sopenharmony_ci                        && roughly_equal(base.fT, t)
163cb93a386Sopenharmony_ci                        && SkDPoint::RoughlyEqual(pt, base.fPt)) {
164cb93a386Sopenharmony_ci    #if DEBUG_WINDING
165cb93a386Sopenharmony_ci                    SkDebugf("%s (rarely expect this)\n", __FUNCTION__);
166cb93a386Sopenharmony_ci    #endif
167cb93a386Sopenharmony_ci                    continue;
168cb93a386Sopenharmony_ci                }
169cb93a386Sopenharmony_ci                if (fabs(pt_dydx(slope, dir) * 10000) > fabs(pt_dxdy(slope, dir))) {
170cb93a386Sopenharmony_ci                    valid = true;
171cb93a386Sopenharmony_ci                }
172cb93a386Sopenharmony_ci            }
173cb93a386Sopenharmony_ci        }
174cb93a386Sopenharmony_ci        SkOpSpan* span = this->windingSpanAtT(t);
175cb93a386Sopenharmony_ci        if (!span) {
176cb93a386Sopenharmony_ci            valid = false;
177cb93a386Sopenharmony_ci        } else if (!span->windValue() && !span->oppValue()) {
178cb93a386Sopenharmony_ci            continue;
179cb93a386Sopenharmony_ci        }
180cb93a386Sopenharmony_ci        SkOpRayHit* newHit = allocator->make<SkOpRayHit>();
181cb93a386Sopenharmony_ci        newHit->fNext = *hits;
182cb93a386Sopenharmony_ci        newHit->fPt = pt;
183cb93a386Sopenharmony_ci        newHit->fSlope = slope;
184cb93a386Sopenharmony_ci        newHit->fSpan = span;
185cb93a386Sopenharmony_ci        newHit->fT = t;
186cb93a386Sopenharmony_ci        newHit->fValid = valid;
187cb93a386Sopenharmony_ci        *hits = newHit;
188cb93a386Sopenharmony_ci    }
189cb93a386Sopenharmony_ci}
190cb93a386Sopenharmony_ci
191cb93a386Sopenharmony_ciSkOpSpan* SkOpSegment::windingSpanAtT(double tHit) {
192cb93a386Sopenharmony_ci    SkOpSpan* span = &fHead;
193cb93a386Sopenharmony_ci    SkOpSpanBase* next;
194cb93a386Sopenharmony_ci    do {
195cb93a386Sopenharmony_ci        next = span->next();
196cb93a386Sopenharmony_ci        if (approximately_equal(tHit, next->t())) {
197cb93a386Sopenharmony_ci            return nullptr;
198cb93a386Sopenharmony_ci        }
199cb93a386Sopenharmony_ci        if (tHit < next->t()) {
200cb93a386Sopenharmony_ci            return span;
201cb93a386Sopenharmony_ci        }
202cb93a386Sopenharmony_ci    } while (!next->final() && (span = next->upCast()));
203cb93a386Sopenharmony_ci    return nullptr;
204cb93a386Sopenharmony_ci}
205cb93a386Sopenharmony_ci
206cb93a386Sopenharmony_cistatic bool hit_compare_x(const SkOpRayHit* a, const SkOpRayHit* b) {
207cb93a386Sopenharmony_ci    return a->fPt.fX < b->fPt.fX;
208cb93a386Sopenharmony_ci}
209cb93a386Sopenharmony_ci
210cb93a386Sopenharmony_cistatic bool reverse_hit_compare_x(const SkOpRayHit* a, const SkOpRayHit* b) {
211cb93a386Sopenharmony_ci    return b->fPt.fX  < a->fPt.fX;
212cb93a386Sopenharmony_ci}
213cb93a386Sopenharmony_ci
214cb93a386Sopenharmony_cistatic bool hit_compare_y(const SkOpRayHit* a, const SkOpRayHit* b) {
215cb93a386Sopenharmony_ci    return a->fPt.fY < b->fPt.fY;
216cb93a386Sopenharmony_ci}
217cb93a386Sopenharmony_ci
218cb93a386Sopenharmony_cistatic bool reverse_hit_compare_y(const SkOpRayHit* a, const SkOpRayHit* b) {
219cb93a386Sopenharmony_ci    return b->fPt.fY  < a->fPt.fY;
220cb93a386Sopenharmony_ci}
221cb93a386Sopenharmony_ci
222cb93a386Sopenharmony_cistatic double get_t_guess(int tTry, int* dirOffset) {
223cb93a386Sopenharmony_ci    double t = 0.5;
224cb93a386Sopenharmony_ci    *dirOffset = tTry & 1;
225cb93a386Sopenharmony_ci    int tBase = tTry >> 1;
226cb93a386Sopenharmony_ci    int tBits = 0;
227cb93a386Sopenharmony_ci    while (tTry >>= 1) {
228cb93a386Sopenharmony_ci        t /= 2;
229cb93a386Sopenharmony_ci        ++tBits;
230cb93a386Sopenharmony_ci    }
231cb93a386Sopenharmony_ci    if (tBits) {
232cb93a386Sopenharmony_ci        int tIndex = (tBase - 1) & ((1 << tBits) - 1);
233cb93a386Sopenharmony_ci        t += t * 2 * tIndex;
234cb93a386Sopenharmony_ci    }
235cb93a386Sopenharmony_ci    return t;
236cb93a386Sopenharmony_ci}
237cb93a386Sopenharmony_ci
238cb93a386Sopenharmony_cibool SkOpSpan::sortableTop(SkOpContour* contourHead) {
239cb93a386Sopenharmony_ci    SkSTArenaAlloc<1024> allocator;
240cb93a386Sopenharmony_ci    int dirOffset;
241cb93a386Sopenharmony_ci    double t = get_t_guess(fTopTTry++, &dirOffset);
242cb93a386Sopenharmony_ci    SkOpRayHit hitBase;
243cb93a386Sopenharmony_ci    SkOpRayDir dir = hitBase.makeTestBase(this, t);
244cb93a386Sopenharmony_ci    if (hitBase.fSlope.fX == 0 && hitBase.fSlope.fY == 0) {
245cb93a386Sopenharmony_ci        return false;
246cb93a386Sopenharmony_ci    }
247cb93a386Sopenharmony_ci    SkOpRayHit* hitHead = &hitBase;
248cb93a386Sopenharmony_ci    dir = static_cast<SkOpRayDir>(static_cast<int>(dir) + dirOffset);
249cb93a386Sopenharmony_ci    if (hitBase.fSpan && hitBase.fSpan->segment()->verb() > SkPath::kLine_Verb
250cb93a386Sopenharmony_ci            && !pt_dydx(hitBase.fSlope, dir)) {
251cb93a386Sopenharmony_ci        return false;
252cb93a386Sopenharmony_ci    }
253cb93a386Sopenharmony_ci    SkOpContour* contour = contourHead;
254cb93a386Sopenharmony_ci    do {
255cb93a386Sopenharmony_ci        if (!contour->count()) {
256cb93a386Sopenharmony_ci            continue;
257cb93a386Sopenharmony_ci        }
258cb93a386Sopenharmony_ci        contour->rayCheck(hitBase, dir, &hitHead, &allocator);
259cb93a386Sopenharmony_ci    } while ((contour = contour->next()));
260cb93a386Sopenharmony_ci    // sort hits
261cb93a386Sopenharmony_ci    SkSTArray<1, SkOpRayHit*> sorted;
262cb93a386Sopenharmony_ci    SkOpRayHit* hit = hitHead;
263cb93a386Sopenharmony_ci    while (hit) {
264cb93a386Sopenharmony_ci        sorted.push_back(hit);
265cb93a386Sopenharmony_ci        hit = hit->fNext;
266cb93a386Sopenharmony_ci    }
267cb93a386Sopenharmony_ci    int count = sorted.count();
268cb93a386Sopenharmony_ci    SkTQSort(sorted.begin(), sorted.end(),
269cb93a386Sopenharmony_ci             xy_index(dir) ? less_than(dir) ? hit_compare_y : reverse_hit_compare_y
270cb93a386Sopenharmony_ci                           : less_than(dir) ? hit_compare_x : reverse_hit_compare_x);
271cb93a386Sopenharmony_ci    // verify windings
272cb93a386Sopenharmony_ci#if DEBUG_WINDING
273cb93a386Sopenharmony_ci    SkDebugf("%s dir=%s seg=%d t=%1.9g pt=(%1.9g,%1.9g)\n", __FUNCTION__,
274cb93a386Sopenharmony_ci            gDebugRayDirName[static_cast<int>(dir)], hitBase.fSpan->segment()->debugID(),
275cb93a386Sopenharmony_ci            hitBase.fT, hitBase.fPt.fX, hitBase.fPt.fY);
276cb93a386Sopenharmony_ci    for (int index = 0; index < count; ++index) {
277cb93a386Sopenharmony_ci        hit = sorted[index];
278cb93a386Sopenharmony_ci        SkOpSpan* span = hit->fSpan;
279cb93a386Sopenharmony_ci        SkOpSegment* hitSegment = span ? span->segment() : nullptr;
280cb93a386Sopenharmony_ci        bool operand = span ? hitSegment->operand() : false;
281cb93a386Sopenharmony_ci        bool ccw = ccw_dxdy(hit->fSlope, dir);
282cb93a386Sopenharmony_ci        SkDebugf("%s [%d] valid=%d operand=%d span=%d ccw=%d ", __FUNCTION__, index,
283cb93a386Sopenharmony_ci                hit->fValid, operand, span ? span->debugID() : -1, ccw);
284cb93a386Sopenharmony_ci        if (span) {
285cb93a386Sopenharmony_ci            hitSegment->dumpPtsInner();
286cb93a386Sopenharmony_ci        }
287cb93a386Sopenharmony_ci        SkDebugf(" t=%1.9g pt=(%1.9g,%1.9g) slope=(%1.9g,%1.9g)\n", hit->fT,
288cb93a386Sopenharmony_ci                hit->fPt.fX, hit->fPt.fY, hit->fSlope.fX, hit->fSlope.fY);
289cb93a386Sopenharmony_ci    }
290cb93a386Sopenharmony_ci#endif
291cb93a386Sopenharmony_ci    const SkPoint* last = nullptr;
292cb93a386Sopenharmony_ci    int wind = 0;
293cb93a386Sopenharmony_ci    int oppWind = 0;
294cb93a386Sopenharmony_ci    for (int index = 0; index < count; ++index) {
295cb93a386Sopenharmony_ci        hit = sorted[index];
296cb93a386Sopenharmony_ci        if (!hit->fValid) {
297cb93a386Sopenharmony_ci            return false;
298cb93a386Sopenharmony_ci        }
299cb93a386Sopenharmony_ci        bool ccw = ccw_dxdy(hit->fSlope, dir);
300cb93a386Sopenharmony_ci//        SkASSERT(!approximately_zero(hit->fT) || !hit->fValid);
301cb93a386Sopenharmony_ci        SkOpSpan* span = hit->fSpan;
302cb93a386Sopenharmony_ci        if (!span) {
303cb93a386Sopenharmony_ci            return false;
304cb93a386Sopenharmony_ci        }
305cb93a386Sopenharmony_ci        SkOpSegment* hitSegment = span->segment();
306cb93a386Sopenharmony_ci        if (span->windValue() == 0 && span->oppValue() == 0) {
307cb93a386Sopenharmony_ci            continue;
308cb93a386Sopenharmony_ci        }
309cb93a386Sopenharmony_ci        if (last && SkDPoint::ApproximatelyEqual(*last, hit->fPt)) {
310cb93a386Sopenharmony_ci            return false;
311cb93a386Sopenharmony_ci        }
312cb93a386Sopenharmony_ci        if (index < count - 1) {
313cb93a386Sopenharmony_ci            const SkPoint& next = sorted[index + 1]->fPt;
314cb93a386Sopenharmony_ci            if (SkDPoint::ApproximatelyEqual(next, hit->fPt)) {
315cb93a386Sopenharmony_ci                return false;
316cb93a386Sopenharmony_ci            }
317cb93a386Sopenharmony_ci        }
318cb93a386Sopenharmony_ci        bool operand = hitSegment->operand();
319cb93a386Sopenharmony_ci        if (operand) {
320cb93a386Sopenharmony_ci            using std::swap;
321cb93a386Sopenharmony_ci            swap(wind, oppWind);
322cb93a386Sopenharmony_ci        }
323cb93a386Sopenharmony_ci        int lastWind = wind;
324cb93a386Sopenharmony_ci        int lastOpp = oppWind;
325cb93a386Sopenharmony_ci        int windValue = ccw ? -span->windValue() : span->windValue();
326cb93a386Sopenharmony_ci        int oppValue = ccw ? -span->oppValue() : span->oppValue();
327cb93a386Sopenharmony_ci        wind += windValue;
328cb93a386Sopenharmony_ci        oppWind += oppValue;
329cb93a386Sopenharmony_ci        bool sumSet = false;
330cb93a386Sopenharmony_ci        int spanSum = span->windSum();
331cb93a386Sopenharmony_ci        int windSum = SkOpSegment::UseInnerWinding(lastWind, wind) ? wind : lastWind;
332cb93a386Sopenharmony_ci        if (spanSum == SK_MinS32) {
333cb93a386Sopenharmony_ci            span->setWindSum(windSum);
334cb93a386Sopenharmony_ci            sumSet = true;
335cb93a386Sopenharmony_ci        } else {
336cb93a386Sopenharmony_ci            // the need for this condition suggests that UseInnerWinding is flawed
337cb93a386Sopenharmony_ci            // happened when last = 1 wind = -1
338cb93a386Sopenharmony_ci#if 0
339cb93a386Sopenharmony_ci            SkASSERT((hitSegment->isXor() ? (windSum & 1) == (spanSum & 1) : windSum == spanSum)
340cb93a386Sopenharmony_ci                    || (abs(wind) == abs(lastWind)
341cb93a386Sopenharmony_ci                    && (windSum ^ wind ^ lastWind) == spanSum));
342cb93a386Sopenharmony_ci#endif
343cb93a386Sopenharmony_ci        }
344cb93a386Sopenharmony_ci        int oSpanSum = span->oppSum();
345cb93a386Sopenharmony_ci        int oppSum = SkOpSegment::UseInnerWinding(lastOpp, oppWind) ? oppWind : lastOpp;
346cb93a386Sopenharmony_ci        if (oSpanSum == SK_MinS32) {
347cb93a386Sopenharmony_ci            span->setOppSum(oppSum);
348cb93a386Sopenharmony_ci        } else {
349cb93a386Sopenharmony_ci#if 0
350cb93a386Sopenharmony_ci            SkASSERT(hitSegment->oppXor() ? (oppSum & 1) == (oSpanSum & 1) : oppSum == oSpanSum
351cb93a386Sopenharmony_ci                    || (abs(oppWind) == abs(lastOpp)
352cb93a386Sopenharmony_ci                    && (oppSum ^ oppWind ^ lastOpp) == oSpanSum));
353cb93a386Sopenharmony_ci#endif
354cb93a386Sopenharmony_ci        }
355cb93a386Sopenharmony_ci        if (sumSet) {
356cb93a386Sopenharmony_ci            if (this->globalState()->phase() == SkOpPhase::kFixWinding) {
357cb93a386Sopenharmony_ci                hitSegment->contour()->setCcw(ccw);
358cb93a386Sopenharmony_ci            } else {
359cb93a386Sopenharmony_ci                (void) hitSegment->markAndChaseWinding(span, span->next(), windSum, oppSum, nullptr);
360cb93a386Sopenharmony_ci                (void) hitSegment->markAndChaseWinding(span->next(), span, windSum, oppSum, nullptr);
361cb93a386Sopenharmony_ci            }
362cb93a386Sopenharmony_ci        }
363cb93a386Sopenharmony_ci        if (operand) {
364cb93a386Sopenharmony_ci            using std::swap;
365cb93a386Sopenharmony_ci            swap(wind, oppWind);
366cb93a386Sopenharmony_ci        }
367cb93a386Sopenharmony_ci        last = &hit->fPt;
368cb93a386Sopenharmony_ci        this->globalState()->bumpNested();
369cb93a386Sopenharmony_ci    }
370cb93a386Sopenharmony_ci    return true;
371cb93a386Sopenharmony_ci}
372cb93a386Sopenharmony_ci
373cb93a386Sopenharmony_ciSkOpSpan* SkOpSegment::findSortableTop(SkOpContour* contourHead) {
374cb93a386Sopenharmony_ci    SkOpSpan* span = &fHead;
375cb93a386Sopenharmony_ci    SkOpSpanBase* next;
376cb93a386Sopenharmony_ci    do {
377cb93a386Sopenharmony_ci        next = span->next();
378cb93a386Sopenharmony_ci        if (span->done()) {
379cb93a386Sopenharmony_ci            continue;
380cb93a386Sopenharmony_ci        }
381cb93a386Sopenharmony_ci        if (span->windSum() != SK_MinS32) {
382cb93a386Sopenharmony_ci            return span;
383cb93a386Sopenharmony_ci        }
384cb93a386Sopenharmony_ci        if (span->sortableTop(contourHead)) {
385cb93a386Sopenharmony_ci            return span;
386cb93a386Sopenharmony_ci        }
387cb93a386Sopenharmony_ci    } while (!next->final() && (span = next->upCast()));
388cb93a386Sopenharmony_ci    return nullptr;
389cb93a386Sopenharmony_ci}
390cb93a386Sopenharmony_ci
391cb93a386Sopenharmony_ciSkOpSpan* SkOpContour::findSortableTop(SkOpContour* contourHead) {
392cb93a386Sopenharmony_ci    bool allDone = true;
393cb93a386Sopenharmony_ci    if (fCount) {
394cb93a386Sopenharmony_ci        SkOpSegment* testSegment = &fHead;
395cb93a386Sopenharmony_ci        do {
396cb93a386Sopenharmony_ci            if (testSegment->done()) {
397cb93a386Sopenharmony_ci                continue;
398cb93a386Sopenharmony_ci            }
399cb93a386Sopenharmony_ci            allDone = false;
400cb93a386Sopenharmony_ci            SkOpSpan* result = testSegment->findSortableTop(contourHead);
401cb93a386Sopenharmony_ci            if (result) {
402cb93a386Sopenharmony_ci                return result;
403cb93a386Sopenharmony_ci            }
404cb93a386Sopenharmony_ci        } while ((testSegment = testSegment->next()));
405cb93a386Sopenharmony_ci    }
406cb93a386Sopenharmony_ci    if (allDone) {
407cb93a386Sopenharmony_ci      fDone = true;
408cb93a386Sopenharmony_ci    }
409cb93a386Sopenharmony_ci    return nullptr;
410cb93a386Sopenharmony_ci}
411cb93a386Sopenharmony_ci
412cb93a386Sopenharmony_ciSkOpSpan* FindSortableTop(SkOpContourHead* contourHead) {
413cb93a386Sopenharmony_ci    for (int index = 0; index < SkOpGlobalState::kMaxWindingTries; ++index) {
414cb93a386Sopenharmony_ci        SkOpContour* contour = contourHead;
415cb93a386Sopenharmony_ci        do {
416cb93a386Sopenharmony_ci            if (contour->done()) {
417cb93a386Sopenharmony_ci                continue;
418cb93a386Sopenharmony_ci            }
419cb93a386Sopenharmony_ci            SkOpSpan* result = contour->findSortableTop(contourHead);
420cb93a386Sopenharmony_ci            if (result) {
421cb93a386Sopenharmony_ci                return result;
422cb93a386Sopenharmony_ci            }
423cb93a386Sopenharmony_ci        } while ((contour = contour->next()));
424cb93a386Sopenharmony_ci    }
425cb93a386Sopenharmony_ci    return nullptr;
426cb93a386Sopenharmony_ci}
427