1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2012 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#include "src/core/SkGeometry.h"
8cb93a386Sopenharmony_ci#include "src/core/SkPathPriv.h"
9cb93a386Sopenharmony_ci#include "src/core/SkTSort.h"
10cb93a386Sopenharmony_ci#include "src/pathops/SkOpEdgeBuilder.h"
11cb93a386Sopenharmony_ci#include "src/pathops/SkReduceOrder.h"
12cb93a386Sopenharmony_ci
13cb93a386Sopenharmony_civoid SkOpEdgeBuilder::init() {
14cb93a386Sopenharmony_ci    fOperand = false;
15cb93a386Sopenharmony_ci    fXorMask[0] = fXorMask[1] = ((int)fPath->getFillType() & 1) ? kEvenOdd_PathOpsMask
16cb93a386Sopenharmony_ci            : kWinding_PathOpsMask;
17cb93a386Sopenharmony_ci    fUnparseable = false;
18cb93a386Sopenharmony_ci    fSecondHalf = preFetch();
19cb93a386Sopenharmony_ci}
20cb93a386Sopenharmony_ci
21cb93a386Sopenharmony_ci// very tiny points cause numerical instability : don't allow them
22cb93a386Sopenharmony_cistatic SkPoint force_small_to_zero(const SkPoint& pt) {
23cb93a386Sopenharmony_ci    SkPoint ret = pt;
24cb93a386Sopenharmony_ci    if (SkScalarAbs(ret.fX) < FLT_EPSILON_ORDERABLE_ERR) {
25cb93a386Sopenharmony_ci        ret.fX = 0;
26cb93a386Sopenharmony_ci    }
27cb93a386Sopenharmony_ci    if (SkScalarAbs(ret.fY) < FLT_EPSILON_ORDERABLE_ERR) {
28cb93a386Sopenharmony_ci        ret.fY = 0;
29cb93a386Sopenharmony_ci    }
30cb93a386Sopenharmony_ci    return ret;
31cb93a386Sopenharmony_ci}
32cb93a386Sopenharmony_ci
33cb93a386Sopenharmony_cistatic bool can_add_curve(SkPath::Verb verb, SkPoint* curve) {
34cb93a386Sopenharmony_ci    if (SkPath::kMove_Verb == verb) {
35cb93a386Sopenharmony_ci        return false;
36cb93a386Sopenharmony_ci    }
37cb93a386Sopenharmony_ci    for (int index = 0; index <= SkPathOpsVerbToPoints(verb); ++index) {
38cb93a386Sopenharmony_ci        curve[index] = force_small_to_zero(curve[index]);
39cb93a386Sopenharmony_ci    }
40cb93a386Sopenharmony_ci    return SkPath::kLine_Verb != verb || !SkDPoint::ApproximatelyEqual(curve[0], curve[1]);
41cb93a386Sopenharmony_ci}
42cb93a386Sopenharmony_ci
43cb93a386Sopenharmony_civoid SkOpEdgeBuilder::addOperand(const SkPath& path) {
44cb93a386Sopenharmony_ci    SkASSERT(fPathVerbs.count() > 0 && fPathVerbs.end()[-1] == SkPath::kDone_Verb);
45cb93a386Sopenharmony_ci    fPathVerbs.pop();
46cb93a386Sopenharmony_ci    fPath = &path;
47cb93a386Sopenharmony_ci    fXorMask[1] = ((int)fPath->getFillType() & 1) ? kEvenOdd_PathOpsMask
48cb93a386Sopenharmony_ci            : kWinding_PathOpsMask;
49cb93a386Sopenharmony_ci    preFetch();
50cb93a386Sopenharmony_ci}
51cb93a386Sopenharmony_ci
52cb93a386Sopenharmony_cibool SkOpEdgeBuilder::finish() {
53cb93a386Sopenharmony_ci    fOperand = false;
54cb93a386Sopenharmony_ci    if (fUnparseable || !walk()) {
55cb93a386Sopenharmony_ci        return false;
56cb93a386Sopenharmony_ci    }
57cb93a386Sopenharmony_ci    complete();
58cb93a386Sopenharmony_ci    SkOpContour* contour = fContourBuilder.contour();
59cb93a386Sopenharmony_ci    if (contour && !contour->count()) {
60cb93a386Sopenharmony_ci        fContoursHead->remove(contour);
61cb93a386Sopenharmony_ci    }
62cb93a386Sopenharmony_ci    return true;
63cb93a386Sopenharmony_ci}
64cb93a386Sopenharmony_ci
65cb93a386Sopenharmony_civoid SkOpEdgeBuilder::closeContour(const SkPoint& curveEnd, const SkPoint& curveStart) {
66cb93a386Sopenharmony_ci    if (!SkDPoint::ApproximatelyEqual(curveEnd, curveStart)) {
67cb93a386Sopenharmony_ci        *fPathVerbs.append() = SkPath::kLine_Verb;
68cb93a386Sopenharmony_ci        *fPathPts.append() = curveStart;
69cb93a386Sopenharmony_ci    } else {
70cb93a386Sopenharmony_ci        int verbCount = fPathVerbs.count();
71cb93a386Sopenharmony_ci        int ptsCount = fPathPts.count();
72cb93a386Sopenharmony_ci        if (SkPath::kLine_Verb == fPathVerbs[verbCount - 1]
73cb93a386Sopenharmony_ci                && fPathPts[ptsCount - 2] == curveStart) {
74cb93a386Sopenharmony_ci            fPathVerbs.pop();
75cb93a386Sopenharmony_ci            fPathPts.pop();
76cb93a386Sopenharmony_ci        } else {
77cb93a386Sopenharmony_ci            fPathPts[ptsCount - 1] = curveStart;
78cb93a386Sopenharmony_ci        }
79cb93a386Sopenharmony_ci    }
80cb93a386Sopenharmony_ci    *fPathVerbs.append() = SkPath::kClose_Verb;
81cb93a386Sopenharmony_ci}
82cb93a386Sopenharmony_ci
83cb93a386Sopenharmony_ciint SkOpEdgeBuilder::preFetch() {
84cb93a386Sopenharmony_ci    if (!fPath->isFinite()) {
85cb93a386Sopenharmony_ci        fUnparseable = true;
86cb93a386Sopenharmony_ci        return 0;
87cb93a386Sopenharmony_ci    }
88cb93a386Sopenharmony_ci    SkPoint curveStart;
89cb93a386Sopenharmony_ci    SkPoint curve[4];
90cb93a386Sopenharmony_ci    bool lastCurve = false;
91cb93a386Sopenharmony_ci    for (auto [pathVerb, pts, w] : SkPathPriv::Iterate(*fPath)) {
92cb93a386Sopenharmony_ci        auto verb = static_cast<SkPath::Verb>(pathVerb);
93cb93a386Sopenharmony_ci        switch (verb) {
94cb93a386Sopenharmony_ci            case SkPath::kMove_Verb:
95cb93a386Sopenharmony_ci                if (!fAllowOpenContours && lastCurve) {
96cb93a386Sopenharmony_ci                    closeContour(curve[0], curveStart);
97cb93a386Sopenharmony_ci                }
98cb93a386Sopenharmony_ci                *fPathVerbs.append() = verb;
99cb93a386Sopenharmony_ci                curve[0] = force_small_to_zero(pts[0]);
100cb93a386Sopenharmony_ci                *fPathPts.append() = curve[0];
101cb93a386Sopenharmony_ci                curveStart = curve[0];
102cb93a386Sopenharmony_ci                lastCurve = false;
103cb93a386Sopenharmony_ci                continue;
104cb93a386Sopenharmony_ci            case SkPath::kLine_Verb:
105cb93a386Sopenharmony_ci                curve[1] = force_small_to_zero(pts[1]);
106cb93a386Sopenharmony_ci                if (SkDPoint::ApproximatelyEqual(curve[0], curve[1])) {
107cb93a386Sopenharmony_ci                    uint8_t lastVerb = fPathVerbs.top();
108cb93a386Sopenharmony_ci                    if (lastVerb != SkPath::kLine_Verb && lastVerb != SkPath::kMove_Verb) {
109cb93a386Sopenharmony_ci                        fPathPts.top() = curve[0] = curve[1];
110cb93a386Sopenharmony_ci                    }
111cb93a386Sopenharmony_ci                    continue;  // skip degenerate points
112cb93a386Sopenharmony_ci                }
113cb93a386Sopenharmony_ci                break;
114cb93a386Sopenharmony_ci            case SkPath::kQuad_Verb:
115cb93a386Sopenharmony_ci                curve[1] = force_small_to_zero(pts[1]);
116cb93a386Sopenharmony_ci                curve[2] = force_small_to_zero(pts[2]);
117cb93a386Sopenharmony_ci                verb = SkReduceOrder::Quad(curve, curve);
118cb93a386Sopenharmony_ci                if (verb == SkPath::kMove_Verb) {
119cb93a386Sopenharmony_ci                    continue;  // skip degenerate points
120cb93a386Sopenharmony_ci                }
121cb93a386Sopenharmony_ci                break;
122cb93a386Sopenharmony_ci            case SkPath::kConic_Verb:
123cb93a386Sopenharmony_ci                curve[1] = force_small_to_zero(pts[1]);
124cb93a386Sopenharmony_ci                curve[2] = force_small_to_zero(pts[2]);
125cb93a386Sopenharmony_ci                verb = SkReduceOrder::Quad(curve, curve);
126cb93a386Sopenharmony_ci                if (SkPath::kQuad_Verb == verb && 1 != *w) {
127cb93a386Sopenharmony_ci                  verb = SkPath::kConic_Verb;
128cb93a386Sopenharmony_ci                } else if (verb == SkPath::kMove_Verb) {
129cb93a386Sopenharmony_ci                    continue;  // skip degenerate points
130cb93a386Sopenharmony_ci                }
131cb93a386Sopenharmony_ci                break;
132cb93a386Sopenharmony_ci            case SkPath::kCubic_Verb:
133cb93a386Sopenharmony_ci                curve[1] = force_small_to_zero(pts[1]);
134cb93a386Sopenharmony_ci                curve[2] = force_small_to_zero(pts[2]);
135cb93a386Sopenharmony_ci                curve[3] = force_small_to_zero(pts[3]);
136cb93a386Sopenharmony_ci                verb = SkReduceOrder::Cubic(curve, curve);
137cb93a386Sopenharmony_ci                if (verb == SkPath::kMove_Verb) {
138cb93a386Sopenharmony_ci                    continue;  // skip degenerate points
139cb93a386Sopenharmony_ci                }
140cb93a386Sopenharmony_ci                break;
141cb93a386Sopenharmony_ci            case SkPath::kClose_Verb:
142cb93a386Sopenharmony_ci                closeContour(curve[0], curveStart);
143cb93a386Sopenharmony_ci                lastCurve = false;
144cb93a386Sopenharmony_ci                continue;
145cb93a386Sopenharmony_ci            case SkPath::kDone_Verb:
146cb93a386Sopenharmony_ci                continue;
147cb93a386Sopenharmony_ci        }
148cb93a386Sopenharmony_ci        *fPathVerbs.append() = verb;
149cb93a386Sopenharmony_ci        int ptCount = SkPathOpsVerbToPoints(verb);
150cb93a386Sopenharmony_ci        fPathPts.append(ptCount, &curve[1]);
151cb93a386Sopenharmony_ci        if (verb == SkPath::kConic_Verb) {
152cb93a386Sopenharmony_ci            *fWeights.append() = *w;
153cb93a386Sopenharmony_ci        }
154cb93a386Sopenharmony_ci        curve[0] = curve[ptCount];
155cb93a386Sopenharmony_ci        lastCurve = true;
156cb93a386Sopenharmony_ci    }
157cb93a386Sopenharmony_ci    if (!fAllowOpenContours && lastCurve) {
158cb93a386Sopenharmony_ci        closeContour(curve[0], curveStart);
159cb93a386Sopenharmony_ci    }
160cb93a386Sopenharmony_ci    *fPathVerbs.append() = SkPath::kDone_Verb;
161cb93a386Sopenharmony_ci    return fPathVerbs.count() - 1;
162cb93a386Sopenharmony_ci}
163cb93a386Sopenharmony_ci
164cb93a386Sopenharmony_cibool SkOpEdgeBuilder::close() {
165cb93a386Sopenharmony_ci    complete();
166cb93a386Sopenharmony_ci    return true;
167cb93a386Sopenharmony_ci}
168cb93a386Sopenharmony_ci
169cb93a386Sopenharmony_cibool SkOpEdgeBuilder::walk() {
170cb93a386Sopenharmony_ci    uint8_t* verbPtr = fPathVerbs.begin();
171cb93a386Sopenharmony_ci    uint8_t* endOfFirstHalf = &verbPtr[fSecondHalf];
172cb93a386Sopenharmony_ci    SkPoint* pointsPtr = fPathPts.begin();
173cb93a386Sopenharmony_ci    SkScalar* weightPtr = fWeights.begin();
174cb93a386Sopenharmony_ci    SkPath::Verb verb;
175cb93a386Sopenharmony_ci    SkOpContour* contour = fContourBuilder.contour();
176cb93a386Sopenharmony_ci    int moveToPtrBump = 0;
177cb93a386Sopenharmony_ci    while ((verb = (SkPath::Verb) *verbPtr) != SkPath::kDone_Verb) {
178cb93a386Sopenharmony_ci        if (verbPtr == endOfFirstHalf) {
179cb93a386Sopenharmony_ci            fOperand = true;
180cb93a386Sopenharmony_ci        }
181cb93a386Sopenharmony_ci        verbPtr++;
182cb93a386Sopenharmony_ci        switch (verb) {
183cb93a386Sopenharmony_ci            case SkPath::kMove_Verb:
184cb93a386Sopenharmony_ci                if (contour && contour->count()) {
185cb93a386Sopenharmony_ci                    if (fAllowOpenContours) {
186cb93a386Sopenharmony_ci                        complete();
187cb93a386Sopenharmony_ci                    } else if (!close()) {
188cb93a386Sopenharmony_ci                        return false;
189cb93a386Sopenharmony_ci                    }
190cb93a386Sopenharmony_ci                }
191cb93a386Sopenharmony_ci                if (!contour) {
192cb93a386Sopenharmony_ci                    fContourBuilder.setContour(contour = fContoursHead->appendContour());
193cb93a386Sopenharmony_ci                }
194cb93a386Sopenharmony_ci                contour->init(fGlobalState, fOperand,
195cb93a386Sopenharmony_ci                    fXorMask[fOperand] == kEvenOdd_PathOpsMask);
196cb93a386Sopenharmony_ci                pointsPtr += moveToPtrBump;
197cb93a386Sopenharmony_ci                moveToPtrBump = 1;
198cb93a386Sopenharmony_ci                continue;
199cb93a386Sopenharmony_ci            case SkPath::kLine_Verb:
200cb93a386Sopenharmony_ci                fContourBuilder.addLine(pointsPtr);
201cb93a386Sopenharmony_ci                break;
202cb93a386Sopenharmony_ci            case SkPath::kQuad_Verb:
203cb93a386Sopenharmony_ci                {
204cb93a386Sopenharmony_ci                    SkVector vec1 = pointsPtr[1] - pointsPtr[0];
205cb93a386Sopenharmony_ci                    SkVector vec2 = pointsPtr[2] - pointsPtr[1];
206cb93a386Sopenharmony_ci                    if (vec1.dot(vec2) < 0) {
207cb93a386Sopenharmony_ci                        SkPoint pair[5];
208cb93a386Sopenharmony_ci                        if (SkChopQuadAtMaxCurvature(pointsPtr, pair) == 1) {
209cb93a386Sopenharmony_ci                            goto addOneQuad;
210cb93a386Sopenharmony_ci                        }
211cb93a386Sopenharmony_ci                        if (!SkScalarsAreFinite(&pair[0].fX, SK_ARRAY_COUNT(pair) * 2)) {
212cb93a386Sopenharmony_ci                            return false;
213cb93a386Sopenharmony_ci                        }
214cb93a386Sopenharmony_ci                        for (unsigned index = 0; index < SK_ARRAY_COUNT(pair); ++index) {
215cb93a386Sopenharmony_ci                            pair[index] = force_small_to_zero(pair[index]);
216cb93a386Sopenharmony_ci                        }
217cb93a386Sopenharmony_ci                        SkPoint cStorage[2][2];
218cb93a386Sopenharmony_ci                        SkPath::Verb v1 = SkReduceOrder::Quad(&pair[0], cStorage[0]);
219cb93a386Sopenharmony_ci                        SkPath::Verb v2 = SkReduceOrder::Quad(&pair[2], cStorage[1]);
220cb93a386Sopenharmony_ci                        SkPoint* curve1 = v1 != SkPath::kLine_Verb ? &pair[0] : cStorage[0];
221cb93a386Sopenharmony_ci                        SkPoint* curve2 = v2 != SkPath::kLine_Verb ? &pair[2] : cStorage[1];
222cb93a386Sopenharmony_ci                        if (can_add_curve(v1, curve1) && can_add_curve(v2, curve2)) {
223cb93a386Sopenharmony_ci                            fContourBuilder.addCurve(v1, curve1);
224cb93a386Sopenharmony_ci                            fContourBuilder.addCurve(v2, curve2);
225cb93a386Sopenharmony_ci                            break;
226cb93a386Sopenharmony_ci                        }
227cb93a386Sopenharmony_ci                    }
228cb93a386Sopenharmony_ci                }
229cb93a386Sopenharmony_ci            addOneQuad:
230cb93a386Sopenharmony_ci                fContourBuilder.addQuad(pointsPtr);
231cb93a386Sopenharmony_ci                break;
232cb93a386Sopenharmony_ci            case SkPath::kConic_Verb: {
233cb93a386Sopenharmony_ci                SkVector vec1 = pointsPtr[1] - pointsPtr[0];
234cb93a386Sopenharmony_ci                SkVector vec2 = pointsPtr[2] - pointsPtr[1];
235cb93a386Sopenharmony_ci                SkScalar weight = *weightPtr++;
236cb93a386Sopenharmony_ci                if (vec1.dot(vec2) < 0) {
237cb93a386Sopenharmony_ci                    // FIXME: max curvature for conics hasn't been implemented; use placeholder
238cb93a386Sopenharmony_ci                    SkScalar maxCurvature = SkFindQuadMaxCurvature(pointsPtr);
239cb93a386Sopenharmony_ci                    if (0 < maxCurvature && maxCurvature < 1) {
240cb93a386Sopenharmony_ci                        SkConic conic(pointsPtr, weight);
241cb93a386Sopenharmony_ci                        SkConic pair[2];
242cb93a386Sopenharmony_ci                        if (!conic.chopAt(maxCurvature, pair)) {
243cb93a386Sopenharmony_ci                            // if result can't be computed, use original
244cb93a386Sopenharmony_ci                            fContourBuilder.addConic(pointsPtr, weight);
245cb93a386Sopenharmony_ci                            break;
246cb93a386Sopenharmony_ci                        }
247cb93a386Sopenharmony_ci                        SkPoint cStorage[2][3];
248cb93a386Sopenharmony_ci                        SkPath::Verb v1 = SkReduceOrder::Conic(pair[0], cStorage[0]);
249cb93a386Sopenharmony_ci                        SkPath::Verb v2 = SkReduceOrder::Conic(pair[1], cStorage[1]);
250cb93a386Sopenharmony_ci                        SkPoint* curve1 = v1 != SkPath::kLine_Verb ? pair[0].fPts : cStorage[0];
251cb93a386Sopenharmony_ci                        SkPoint* curve2 = v2 != SkPath::kLine_Verb ? pair[1].fPts : cStorage[1];
252cb93a386Sopenharmony_ci                        if (can_add_curve(v1, curve1) && can_add_curve(v2, curve2)) {
253cb93a386Sopenharmony_ci                            fContourBuilder.addCurve(v1, curve1, pair[0].fW);
254cb93a386Sopenharmony_ci                            fContourBuilder.addCurve(v2, curve2, pair[1].fW);
255cb93a386Sopenharmony_ci                            break;
256cb93a386Sopenharmony_ci                        }
257cb93a386Sopenharmony_ci                    }
258cb93a386Sopenharmony_ci                }
259cb93a386Sopenharmony_ci                fContourBuilder.addConic(pointsPtr, weight);
260cb93a386Sopenharmony_ci                } break;
261cb93a386Sopenharmony_ci            case SkPath::kCubic_Verb:
262cb93a386Sopenharmony_ci                {
263cb93a386Sopenharmony_ci                    // Split complex cubics (such as self-intersecting curves or
264cb93a386Sopenharmony_ci                    // ones with difficult curvature) in two before proceeding.
265cb93a386Sopenharmony_ci                    // This can be required for intersection to succeed.
266cb93a386Sopenharmony_ci                    SkScalar splitT[3];
267cb93a386Sopenharmony_ci                    int breaks = SkDCubic::ComplexBreak(pointsPtr, splitT);
268cb93a386Sopenharmony_ci                    if (!breaks) {
269cb93a386Sopenharmony_ci                        fContourBuilder.addCubic(pointsPtr);
270cb93a386Sopenharmony_ci                        break;
271cb93a386Sopenharmony_ci                    }
272cb93a386Sopenharmony_ci                    SkASSERT(breaks <= (int) SK_ARRAY_COUNT(splitT));
273cb93a386Sopenharmony_ci                    struct Splitsville {
274cb93a386Sopenharmony_ci                        double fT[2];
275cb93a386Sopenharmony_ci                        SkPoint fPts[4];
276cb93a386Sopenharmony_ci                        SkPoint fReduced[4];
277cb93a386Sopenharmony_ci                        SkPath::Verb fVerb;
278cb93a386Sopenharmony_ci                        bool fCanAdd;
279cb93a386Sopenharmony_ci                    } splits[4];
280cb93a386Sopenharmony_ci                    SkASSERT(SK_ARRAY_COUNT(splits) == SK_ARRAY_COUNT(splitT) + 1);
281cb93a386Sopenharmony_ci                    SkTQSort(splitT, splitT + breaks);
282cb93a386Sopenharmony_ci                    for (int index = 0; index <= breaks; ++index) {
283cb93a386Sopenharmony_ci                        Splitsville* split = &splits[index];
284cb93a386Sopenharmony_ci                        split->fT[0] = index ? splitT[index - 1] : 0;
285cb93a386Sopenharmony_ci                        split->fT[1] = index < breaks ? splitT[index] : 1;
286cb93a386Sopenharmony_ci                        SkDCubic part = SkDCubic::SubDivide(pointsPtr, split->fT[0], split->fT[1]);
287cb93a386Sopenharmony_ci                        if (!part.toFloatPoints(split->fPts)) {
288cb93a386Sopenharmony_ci                            return false;
289cb93a386Sopenharmony_ci                        }
290cb93a386Sopenharmony_ci                        split->fVerb = SkReduceOrder::Cubic(split->fPts, split->fReduced);
291cb93a386Sopenharmony_ci                        SkPoint* curve = SkPath::kCubic_Verb == split->fVerb
292cb93a386Sopenharmony_ci                                ? split->fPts : split->fReduced;
293cb93a386Sopenharmony_ci                        split->fCanAdd = can_add_curve(split->fVerb, curve);
294cb93a386Sopenharmony_ci                    }
295cb93a386Sopenharmony_ci                    for (int index = 0; index <= breaks; ++index) {
296cb93a386Sopenharmony_ci                        Splitsville* split = &splits[index];
297cb93a386Sopenharmony_ci                        if (!split->fCanAdd) {
298cb93a386Sopenharmony_ci                            continue;
299cb93a386Sopenharmony_ci                        }
300cb93a386Sopenharmony_ci                        int prior = index;
301cb93a386Sopenharmony_ci                        while (prior > 0 && !splits[prior - 1].fCanAdd) {
302cb93a386Sopenharmony_ci                            --prior;
303cb93a386Sopenharmony_ci                        }
304cb93a386Sopenharmony_ci                        if (prior < index) {
305cb93a386Sopenharmony_ci                            split->fT[0] = splits[prior].fT[0];
306cb93a386Sopenharmony_ci                            split->fPts[0] = splits[prior].fPts[0];
307cb93a386Sopenharmony_ci                        }
308cb93a386Sopenharmony_ci                        int next = index;
309cb93a386Sopenharmony_ci                        int breakLimit = std::min(breaks, (int) SK_ARRAY_COUNT(splits) - 1);
310cb93a386Sopenharmony_ci                        while (next < breakLimit && !splits[next + 1].fCanAdd) {
311cb93a386Sopenharmony_ci                            ++next;
312cb93a386Sopenharmony_ci                        }
313cb93a386Sopenharmony_ci                        if (next > index) {
314cb93a386Sopenharmony_ci                            split->fT[1] = splits[next].fT[1];
315cb93a386Sopenharmony_ci                            split->fPts[3] = splits[next].fPts[3];
316cb93a386Sopenharmony_ci                        }
317cb93a386Sopenharmony_ci                        if (prior < index || next > index) {
318cb93a386Sopenharmony_ci                            split->fVerb = SkReduceOrder::Cubic(split->fPts, split->fReduced);
319cb93a386Sopenharmony_ci                        }
320cb93a386Sopenharmony_ci                        SkPoint* curve = SkPath::kCubic_Verb == split->fVerb
321cb93a386Sopenharmony_ci                                ? split->fPts : split->fReduced;
322cb93a386Sopenharmony_ci                        if (!can_add_curve(split->fVerb, curve)) {
323cb93a386Sopenharmony_ci                            return false;
324cb93a386Sopenharmony_ci                        }
325cb93a386Sopenharmony_ci                        fContourBuilder.addCurve(split->fVerb, curve);
326cb93a386Sopenharmony_ci                    }
327cb93a386Sopenharmony_ci                }
328cb93a386Sopenharmony_ci                break;
329cb93a386Sopenharmony_ci            case SkPath::kClose_Verb:
330cb93a386Sopenharmony_ci                SkASSERT(contour);
331cb93a386Sopenharmony_ci                if (!close()) {
332cb93a386Sopenharmony_ci                    return false;
333cb93a386Sopenharmony_ci                }
334cb93a386Sopenharmony_ci                contour = nullptr;
335cb93a386Sopenharmony_ci                continue;
336cb93a386Sopenharmony_ci            default:
337cb93a386Sopenharmony_ci                SkDEBUGFAIL("bad verb");
338cb93a386Sopenharmony_ci                return false;
339cb93a386Sopenharmony_ci        }
340cb93a386Sopenharmony_ci        SkASSERT(contour);
341cb93a386Sopenharmony_ci        if (contour->count()) {
342cb93a386Sopenharmony_ci            contour->debugValidate();
343cb93a386Sopenharmony_ci        }
344cb93a386Sopenharmony_ci        pointsPtr += SkPathOpsVerbToPoints(verb);
345cb93a386Sopenharmony_ci    }
346cb93a386Sopenharmony_ci    fContourBuilder.flush();
347cb93a386Sopenharmony_ci    if (contour && contour->count() &&!fAllowOpenContours && !close()) {
348cb93a386Sopenharmony_ci        return false;
349cb93a386Sopenharmony_ci    }
350cb93a386Sopenharmony_ci    return true;
351cb93a386Sopenharmony_ci}
352