1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2011 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 "include/core/SkPath.h"
9cb93a386Sopenharmony_ci#include "include/private/SkTo.h"
10cb93a386Sopenharmony_ci#include "src/core/SkAnalyticEdge.h"
11cb93a386Sopenharmony_ci#include "src/core/SkEdge.h"
12cb93a386Sopenharmony_ci#include "src/core/SkEdgeBuilder.h"
13cb93a386Sopenharmony_ci#include "src/core/SkEdgeClipper.h"
14cb93a386Sopenharmony_ci#include "src/core/SkGeometry.h"
15cb93a386Sopenharmony_ci#include "src/core/SkLineClipper.h"
16cb93a386Sopenharmony_ci#include "src/core/SkPathPriv.h"
17cb93a386Sopenharmony_ci#include "src/core/SkSafeMath.h"
18cb93a386Sopenharmony_ci
19cb93a386Sopenharmony_ciSkEdgeBuilder::Combine SkBasicEdgeBuilder::combineVertical(const SkEdge* edge, SkEdge* last) {
20cb93a386Sopenharmony_ci    if (last->fCurveCount || last->fDX || edge->fX != last->fX) {
21cb93a386Sopenharmony_ci        return kNo_Combine;
22cb93a386Sopenharmony_ci    }
23cb93a386Sopenharmony_ci    if (edge->fWinding == last->fWinding) {
24cb93a386Sopenharmony_ci        if (edge->fLastY + 1 == last->fFirstY) {
25cb93a386Sopenharmony_ci            last->fFirstY = edge->fFirstY;
26cb93a386Sopenharmony_ci            return kPartial_Combine;
27cb93a386Sopenharmony_ci        }
28cb93a386Sopenharmony_ci        if (edge->fFirstY == last->fLastY + 1) {
29cb93a386Sopenharmony_ci            last->fLastY = edge->fLastY;
30cb93a386Sopenharmony_ci            return kPartial_Combine;
31cb93a386Sopenharmony_ci        }
32cb93a386Sopenharmony_ci        return kNo_Combine;
33cb93a386Sopenharmony_ci    }
34cb93a386Sopenharmony_ci    if (edge->fFirstY == last->fFirstY) {
35cb93a386Sopenharmony_ci        if (edge->fLastY == last->fLastY) {
36cb93a386Sopenharmony_ci            return kTotal_Combine;
37cb93a386Sopenharmony_ci        }
38cb93a386Sopenharmony_ci        if (edge->fLastY < last->fLastY) {
39cb93a386Sopenharmony_ci            last->fFirstY = edge->fLastY + 1;
40cb93a386Sopenharmony_ci            return kPartial_Combine;
41cb93a386Sopenharmony_ci        }
42cb93a386Sopenharmony_ci        last->fFirstY = last->fLastY + 1;
43cb93a386Sopenharmony_ci        last->fLastY = edge->fLastY;
44cb93a386Sopenharmony_ci        last->fWinding = edge->fWinding;
45cb93a386Sopenharmony_ci        return kPartial_Combine;
46cb93a386Sopenharmony_ci    }
47cb93a386Sopenharmony_ci    if (edge->fLastY == last->fLastY) {
48cb93a386Sopenharmony_ci        if (edge->fFirstY > last->fFirstY) {
49cb93a386Sopenharmony_ci            last->fLastY = edge->fFirstY - 1;
50cb93a386Sopenharmony_ci            return kPartial_Combine;
51cb93a386Sopenharmony_ci        }
52cb93a386Sopenharmony_ci        last->fLastY = last->fFirstY - 1;
53cb93a386Sopenharmony_ci        last->fFirstY = edge->fFirstY;
54cb93a386Sopenharmony_ci        last->fWinding = edge->fWinding;
55cb93a386Sopenharmony_ci        return kPartial_Combine;
56cb93a386Sopenharmony_ci    }
57cb93a386Sopenharmony_ci    return kNo_Combine;
58cb93a386Sopenharmony_ci}
59cb93a386Sopenharmony_ci
60cb93a386Sopenharmony_ciSkEdgeBuilder::Combine SkAnalyticEdgeBuilder::combineVertical(const SkAnalyticEdge* edge,
61cb93a386Sopenharmony_ci                                                              SkAnalyticEdge* last) {
62cb93a386Sopenharmony_ci    auto approximately_equal = [](SkFixed a, SkFixed b) {
63cb93a386Sopenharmony_ci        return SkAbs32(a - b) < 0x100;
64cb93a386Sopenharmony_ci    };
65cb93a386Sopenharmony_ci
66cb93a386Sopenharmony_ci    if (last->fCurveCount || last->fDX || edge->fX != last->fX) {
67cb93a386Sopenharmony_ci        return kNo_Combine;
68cb93a386Sopenharmony_ci    }
69cb93a386Sopenharmony_ci    if (edge->fWinding == last->fWinding) {
70cb93a386Sopenharmony_ci        if (edge->fLowerY == last->fUpperY) {
71cb93a386Sopenharmony_ci            last->fUpperY = edge->fUpperY;
72cb93a386Sopenharmony_ci            last->fY = last->fUpperY;
73cb93a386Sopenharmony_ci            return kPartial_Combine;
74cb93a386Sopenharmony_ci        }
75cb93a386Sopenharmony_ci        if (approximately_equal(edge->fUpperY, last->fLowerY)) {
76cb93a386Sopenharmony_ci            last->fLowerY = edge->fLowerY;
77cb93a386Sopenharmony_ci            return kPartial_Combine;
78cb93a386Sopenharmony_ci        }
79cb93a386Sopenharmony_ci        return kNo_Combine;
80cb93a386Sopenharmony_ci    }
81cb93a386Sopenharmony_ci    if (approximately_equal(edge->fUpperY, last->fUpperY)) {
82cb93a386Sopenharmony_ci        if (approximately_equal(edge->fLowerY, last->fLowerY)) {
83cb93a386Sopenharmony_ci            return kTotal_Combine;
84cb93a386Sopenharmony_ci        }
85cb93a386Sopenharmony_ci        if (edge->fLowerY < last->fLowerY) {
86cb93a386Sopenharmony_ci            last->fUpperY = edge->fLowerY;
87cb93a386Sopenharmony_ci            last->fY = last->fUpperY;
88cb93a386Sopenharmony_ci            return kPartial_Combine;
89cb93a386Sopenharmony_ci        }
90cb93a386Sopenharmony_ci        last->fUpperY = last->fLowerY;
91cb93a386Sopenharmony_ci        last->fY = last->fUpperY;
92cb93a386Sopenharmony_ci        last->fLowerY = edge->fLowerY;
93cb93a386Sopenharmony_ci        last->fWinding = edge->fWinding;
94cb93a386Sopenharmony_ci        return kPartial_Combine;
95cb93a386Sopenharmony_ci    }
96cb93a386Sopenharmony_ci    if (approximately_equal(edge->fLowerY, last->fLowerY)) {
97cb93a386Sopenharmony_ci        if (edge->fUpperY > last->fUpperY) {
98cb93a386Sopenharmony_ci            last->fLowerY = edge->fUpperY;
99cb93a386Sopenharmony_ci            return kPartial_Combine;
100cb93a386Sopenharmony_ci        }
101cb93a386Sopenharmony_ci        last->fLowerY = last->fUpperY;
102cb93a386Sopenharmony_ci        last->fUpperY = edge->fUpperY;
103cb93a386Sopenharmony_ci        last->fY = last->fUpperY;
104cb93a386Sopenharmony_ci        last->fWinding = edge->fWinding;
105cb93a386Sopenharmony_ci        return kPartial_Combine;
106cb93a386Sopenharmony_ci    }
107cb93a386Sopenharmony_ci    return kNo_Combine;
108cb93a386Sopenharmony_ci}
109cb93a386Sopenharmony_ci
110cb93a386Sopenharmony_citemplate <typename Edge>
111cb93a386Sopenharmony_cistatic bool is_vertical(const Edge* edge) {
112cb93a386Sopenharmony_ci    return edge->fDX         == 0
113cb93a386Sopenharmony_ci        && edge->fCurveCount == 0;
114cb93a386Sopenharmony_ci}
115cb93a386Sopenharmony_ci
116cb93a386Sopenharmony_ci// TODO: we can deallocate the edge if edge->setFoo() fails
117cb93a386Sopenharmony_ci// or when we don't use it (kPartial_Combine or kTotal_Combine).
118cb93a386Sopenharmony_ci
119cb93a386Sopenharmony_civoid SkBasicEdgeBuilder::addLine(const SkPoint pts[]) {
120cb93a386Sopenharmony_ci    SkEdge* edge = fAlloc.make<SkEdge>();
121cb93a386Sopenharmony_ci    if (edge->setLine(pts[0], pts[1], fClipShift)) {
122cb93a386Sopenharmony_ci        Combine combine = is_vertical(edge) && !fList.empty()
123cb93a386Sopenharmony_ci            ? this->combineVertical(edge, (SkEdge*)fList.top())
124cb93a386Sopenharmony_ci            : kNo_Combine;
125cb93a386Sopenharmony_ci
126cb93a386Sopenharmony_ci        switch (combine) {
127cb93a386Sopenharmony_ci            case kTotal_Combine:    fList.pop();           break;
128cb93a386Sopenharmony_ci            case kPartial_Combine:                         break;
129cb93a386Sopenharmony_ci            case kNo_Combine:       fList.push_back(edge); break;
130cb93a386Sopenharmony_ci        }
131cb93a386Sopenharmony_ci    }
132cb93a386Sopenharmony_ci}
133cb93a386Sopenharmony_civoid SkAnalyticEdgeBuilder::addLine(const SkPoint pts[]) {
134cb93a386Sopenharmony_ci    SkAnalyticEdge* edge = fAlloc.make<SkAnalyticEdge>();
135cb93a386Sopenharmony_ci    if (edge->setLine(pts[0], pts[1])) {
136cb93a386Sopenharmony_ci
137cb93a386Sopenharmony_ci        Combine combine = is_vertical(edge) && !fList.empty()
138cb93a386Sopenharmony_ci            ? this->combineVertical(edge, (SkAnalyticEdge*)fList.top())
139cb93a386Sopenharmony_ci            : kNo_Combine;
140cb93a386Sopenharmony_ci
141cb93a386Sopenharmony_ci        switch (combine) {
142cb93a386Sopenharmony_ci            case kTotal_Combine:    fList.pop();           break;
143cb93a386Sopenharmony_ci            case kPartial_Combine:                         break;
144cb93a386Sopenharmony_ci            case kNo_Combine:       fList.push_back(edge); break;
145cb93a386Sopenharmony_ci        }
146cb93a386Sopenharmony_ci    }
147cb93a386Sopenharmony_ci}
148cb93a386Sopenharmony_civoid SkBasicEdgeBuilder::addQuad(const SkPoint pts[]) {
149cb93a386Sopenharmony_ci    SkQuadraticEdge* edge = fAlloc.make<SkQuadraticEdge>();
150cb93a386Sopenharmony_ci    if (edge->setQuadratic(pts, fClipShift)) {
151cb93a386Sopenharmony_ci        fList.push_back(edge);
152cb93a386Sopenharmony_ci    }
153cb93a386Sopenharmony_ci}
154cb93a386Sopenharmony_civoid SkAnalyticEdgeBuilder::addQuad(const SkPoint pts[]) {
155cb93a386Sopenharmony_ci    SkAnalyticQuadraticEdge* edge = fAlloc.make<SkAnalyticQuadraticEdge>();
156cb93a386Sopenharmony_ci    if (edge->setQuadratic(pts)) {
157cb93a386Sopenharmony_ci        fList.push_back(edge);
158cb93a386Sopenharmony_ci    }
159cb93a386Sopenharmony_ci}
160cb93a386Sopenharmony_ci
161cb93a386Sopenharmony_civoid SkBasicEdgeBuilder::addCubic(const SkPoint pts[]) {
162cb93a386Sopenharmony_ci    SkCubicEdge* edge = fAlloc.make<SkCubicEdge>();
163cb93a386Sopenharmony_ci    if (edge->setCubic(pts, fClipShift)) {
164cb93a386Sopenharmony_ci        fList.push_back(edge);
165cb93a386Sopenharmony_ci    }
166cb93a386Sopenharmony_ci}
167cb93a386Sopenharmony_civoid SkAnalyticEdgeBuilder::addCubic(const SkPoint pts[]) {
168cb93a386Sopenharmony_ci    SkAnalyticCubicEdge* edge = fAlloc.make<SkAnalyticCubicEdge>();
169cb93a386Sopenharmony_ci    if (edge->setCubic(pts)) {
170cb93a386Sopenharmony_ci        fList.push_back(edge);
171cb93a386Sopenharmony_ci    }
172cb93a386Sopenharmony_ci}
173cb93a386Sopenharmony_ci
174cb93a386Sopenharmony_ci// TODO: merge addLine() and addPolyLine()?
175cb93a386Sopenharmony_ci
176cb93a386Sopenharmony_ciSkEdgeBuilder::Combine SkBasicEdgeBuilder::addPolyLine(const SkPoint pts[],
177cb93a386Sopenharmony_ci                                                       char* arg_edge, char** arg_edgePtr) {
178cb93a386Sopenharmony_ci    auto edge    = (SkEdge*) arg_edge;
179cb93a386Sopenharmony_ci    auto edgePtr = (SkEdge**)arg_edgePtr;
180cb93a386Sopenharmony_ci
181cb93a386Sopenharmony_ci    if (edge->setLine(pts[0], pts[1], fClipShift)) {
182cb93a386Sopenharmony_ci        return is_vertical(edge) && edgePtr > (SkEdge**)fEdgeList
183cb93a386Sopenharmony_ci            ? this->combineVertical(edge, edgePtr[-1])
184cb93a386Sopenharmony_ci            : kNo_Combine;
185cb93a386Sopenharmony_ci    }
186cb93a386Sopenharmony_ci    return SkEdgeBuilder::kPartial_Combine;  // A convenient lie.  Same do-nothing behavior.
187cb93a386Sopenharmony_ci}
188cb93a386Sopenharmony_ciSkEdgeBuilder::Combine SkAnalyticEdgeBuilder::addPolyLine(const SkPoint pts[],
189cb93a386Sopenharmony_ci                                                          char* arg_edge, char** arg_edgePtr) {
190cb93a386Sopenharmony_ci    auto edge    = (SkAnalyticEdge*) arg_edge;
191cb93a386Sopenharmony_ci    auto edgePtr = (SkAnalyticEdge**)arg_edgePtr;
192cb93a386Sopenharmony_ci
193cb93a386Sopenharmony_ci    if (edge->setLine(pts[0], pts[1])) {
194cb93a386Sopenharmony_ci        return is_vertical(edge) && edgePtr > (SkAnalyticEdge**)fEdgeList
195cb93a386Sopenharmony_ci            ? this->combineVertical(edge, edgePtr[-1])
196cb93a386Sopenharmony_ci            : kNo_Combine;
197cb93a386Sopenharmony_ci    }
198cb93a386Sopenharmony_ci    return SkEdgeBuilder::kPartial_Combine;  // As above.
199cb93a386Sopenharmony_ci}
200cb93a386Sopenharmony_ci
201cb93a386Sopenharmony_ciSkRect SkBasicEdgeBuilder::recoverClip(const SkIRect& src) const {
202cb93a386Sopenharmony_ci    return { SkIntToScalar(src.fLeft   >> fClipShift),
203cb93a386Sopenharmony_ci             SkIntToScalar(src.fTop    >> fClipShift),
204cb93a386Sopenharmony_ci             SkIntToScalar(src.fRight  >> fClipShift),
205cb93a386Sopenharmony_ci             SkIntToScalar(src.fBottom >> fClipShift), };
206cb93a386Sopenharmony_ci}
207cb93a386Sopenharmony_ciSkRect SkAnalyticEdgeBuilder::recoverClip(const SkIRect& src) const {
208cb93a386Sopenharmony_ci    return SkRect::Make(src);
209cb93a386Sopenharmony_ci}
210cb93a386Sopenharmony_ci
211cb93a386Sopenharmony_cichar* SkBasicEdgeBuilder::allocEdges(size_t n, size_t* size) {
212cb93a386Sopenharmony_ci    *size = sizeof(SkEdge);
213cb93a386Sopenharmony_ci    return (char*)fAlloc.makeArrayDefault<SkEdge>(n);
214cb93a386Sopenharmony_ci}
215cb93a386Sopenharmony_cichar* SkAnalyticEdgeBuilder::allocEdges(size_t n, size_t* size) {
216cb93a386Sopenharmony_ci    *size = sizeof(SkAnalyticEdge);
217cb93a386Sopenharmony_ci    return (char*)fAlloc.makeArrayDefault<SkAnalyticEdge>(n);
218cb93a386Sopenharmony_ci}
219cb93a386Sopenharmony_ci
220cb93a386Sopenharmony_ci// TODO: maybe get rid of buildPoly() entirely?
221cb93a386Sopenharmony_ciint SkEdgeBuilder::buildPoly(const SkPath& path, const SkIRect* iclip, bool canCullToTheRight) {
222cb93a386Sopenharmony_ci    size_t maxEdgeCount = path.countPoints();
223cb93a386Sopenharmony_ci    if (iclip) {
224cb93a386Sopenharmony_ci        // clipping can turn 1 line into (up to) kMaxClippedLineSegments, since
225cb93a386Sopenharmony_ci        // we turn portions that are clipped out on the left/right into vertical
226cb93a386Sopenharmony_ci        // segments.
227cb93a386Sopenharmony_ci        SkSafeMath safe;
228cb93a386Sopenharmony_ci        maxEdgeCount = safe.mul(maxEdgeCount, SkLineClipper::kMaxClippedLineSegments);
229cb93a386Sopenharmony_ci        if (!safe) {
230cb93a386Sopenharmony_ci            return 0;
231cb93a386Sopenharmony_ci        }
232cb93a386Sopenharmony_ci    }
233cb93a386Sopenharmony_ci
234cb93a386Sopenharmony_ci    size_t edgeSize;
235cb93a386Sopenharmony_ci    char* edge = this->allocEdges(maxEdgeCount, &edgeSize);
236cb93a386Sopenharmony_ci
237cb93a386Sopenharmony_ci    SkDEBUGCODE(char* edgeStart = edge);
238cb93a386Sopenharmony_ci    char** edgePtr = fAlloc.makeArrayDefault<char*>(maxEdgeCount);
239cb93a386Sopenharmony_ci    fEdgeList = (void**)edgePtr;
240cb93a386Sopenharmony_ci
241cb93a386Sopenharmony_ci    SkPathEdgeIter iter(path);
242cb93a386Sopenharmony_ci    if (iclip) {
243cb93a386Sopenharmony_ci        SkRect clip = this->recoverClip(*iclip);
244cb93a386Sopenharmony_ci
245cb93a386Sopenharmony_ci        while (auto e = iter.next()) {
246cb93a386Sopenharmony_ci            switch (e.fEdge) {
247cb93a386Sopenharmony_ci                case SkPathEdgeIter::Edge::kLine: {
248cb93a386Sopenharmony_ci                    SkPoint lines[SkLineClipper::kMaxPoints];
249cb93a386Sopenharmony_ci                    int lineCount = SkLineClipper::ClipLine(e.fPts, clip, lines, canCullToTheRight);
250cb93a386Sopenharmony_ci                    SkASSERT(lineCount <= SkLineClipper::kMaxClippedLineSegments);
251cb93a386Sopenharmony_ci                    for (int i = 0; i < lineCount; i++) {
252cb93a386Sopenharmony_ci                        switch( this->addPolyLine(lines + i, edge, edgePtr) ) {
253cb93a386Sopenharmony_ci                            case kTotal_Combine:   edgePtr--; break;
254cb93a386Sopenharmony_ci                            case kPartial_Combine:            break;
255cb93a386Sopenharmony_ci                            case kNo_Combine: *edgePtr++ = edge;
256cb93a386Sopenharmony_ci                                               edge += edgeSize;
257cb93a386Sopenharmony_ci                        }
258cb93a386Sopenharmony_ci                    }
259cb93a386Sopenharmony_ci                    break;
260cb93a386Sopenharmony_ci                }
261cb93a386Sopenharmony_ci                default:
262cb93a386Sopenharmony_ci                    SkDEBUGFAIL("unexpected verb");
263cb93a386Sopenharmony_ci                    break;
264cb93a386Sopenharmony_ci            }
265cb93a386Sopenharmony_ci        }
266cb93a386Sopenharmony_ci    } else {
267cb93a386Sopenharmony_ci        while (auto e = iter.next()) {
268cb93a386Sopenharmony_ci            switch (e.fEdge) {
269cb93a386Sopenharmony_ci                case SkPathEdgeIter::Edge::kLine: {
270cb93a386Sopenharmony_ci                    switch( this->addPolyLine(e.fPts, edge, edgePtr) ) {
271cb93a386Sopenharmony_ci                        case kTotal_Combine:   edgePtr--; break;
272cb93a386Sopenharmony_ci                        case kPartial_Combine:            break;
273cb93a386Sopenharmony_ci                        case kNo_Combine: *edgePtr++ = edge;
274cb93a386Sopenharmony_ci                                           edge += edgeSize;
275cb93a386Sopenharmony_ci                    }
276cb93a386Sopenharmony_ci                    break;
277cb93a386Sopenharmony_ci                }
278cb93a386Sopenharmony_ci                default:
279cb93a386Sopenharmony_ci                    SkDEBUGFAIL("unexpected verb");
280cb93a386Sopenharmony_ci                    break;
281cb93a386Sopenharmony_ci            }
282cb93a386Sopenharmony_ci        }
283cb93a386Sopenharmony_ci    }
284cb93a386Sopenharmony_ci    SkASSERT((size_t)(edge - edgeStart) <= maxEdgeCount * edgeSize);
285cb93a386Sopenharmony_ci    SkASSERT((size_t)(edgePtr - (char**)fEdgeList) <= maxEdgeCount);
286cb93a386Sopenharmony_ci    return SkToInt(edgePtr - (char**)fEdgeList);
287cb93a386Sopenharmony_ci}
288cb93a386Sopenharmony_ci
289cb93a386Sopenharmony_ciint SkEdgeBuilder::build(const SkPath& path, const SkIRect* iclip, bool canCullToTheRight) {
290cb93a386Sopenharmony_ci    SkAutoConicToQuads quadder;
291cb93a386Sopenharmony_ci    const SkScalar conicTol = SK_Scalar1 / 4;
292cb93a386Sopenharmony_ci    bool is_finite = true;
293cb93a386Sopenharmony_ci
294cb93a386Sopenharmony_ci    SkPathEdgeIter iter(path);
295cb93a386Sopenharmony_ci    if (iclip) {
296cb93a386Sopenharmony_ci        SkRect clip = this->recoverClip(*iclip);
297cb93a386Sopenharmony_ci        struct Rec {
298cb93a386Sopenharmony_ci            SkEdgeBuilder* fBuilder;
299cb93a386Sopenharmony_ci            bool           fIsFinite;
300cb93a386Sopenharmony_ci        } rec = { this, true };
301cb93a386Sopenharmony_ci
302cb93a386Sopenharmony_ci        SkEdgeClipper::ClipPath(path, clip, canCullToTheRight,
303cb93a386Sopenharmony_ci                                [](SkEdgeClipper* clipper, bool, void* ctx) {
304cb93a386Sopenharmony_ci            Rec* rec = (Rec*)ctx;
305cb93a386Sopenharmony_ci            SkPoint      pts[4];
306cb93a386Sopenharmony_ci            SkPath::Verb verb;
307cb93a386Sopenharmony_ci
308cb93a386Sopenharmony_ci            while ((verb = clipper->next(pts)) != SkPath::kDone_Verb) {
309cb93a386Sopenharmony_ci                const int count = SkPathPriv::PtsInIter(verb);
310cb93a386Sopenharmony_ci                if (!SkScalarsAreFinite(&pts[0].fX, count*2)) {
311cb93a386Sopenharmony_ci                    rec->fIsFinite = false;
312cb93a386Sopenharmony_ci                    return;
313cb93a386Sopenharmony_ci                }
314cb93a386Sopenharmony_ci                switch (verb) {
315cb93a386Sopenharmony_ci                    case SkPath::kLine_Verb:  rec->fBuilder->addLine (pts); break;
316cb93a386Sopenharmony_ci                    case SkPath::kQuad_Verb:  rec->fBuilder->addQuad (pts); break;
317cb93a386Sopenharmony_ci                    case SkPath::kCubic_Verb: rec->fBuilder->addCubic(pts); break;
318cb93a386Sopenharmony_ci                    default: break;
319cb93a386Sopenharmony_ci                }
320cb93a386Sopenharmony_ci            }
321cb93a386Sopenharmony_ci        }, &rec);
322cb93a386Sopenharmony_ci        is_finite = rec.fIsFinite;
323cb93a386Sopenharmony_ci    } else {
324cb93a386Sopenharmony_ci        auto handle_quad = [this](const SkPoint pts[3]) {
325cb93a386Sopenharmony_ci            SkPoint monoX[5];
326cb93a386Sopenharmony_ci            int n = SkChopQuadAtYExtrema(pts, monoX);
327cb93a386Sopenharmony_ci            for (int i = 0; i <= n; i++) {
328cb93a386Sopenharmony_ci                this->addQuad(&monoX[i * 2]);
329cb93a386Sopenharmony_ci            }
330cb93a386Sopenharmony_ci        };
331cb93a386Sopenharmony_ci        while (auto e = iter.next()) {
332cb93a386Sopenharmony_ci            switch (e.fEdge) {
333cb93a386Sopenharmony_ci                case SkPathEdgeIter::Edge::kLine:
334cb93a386Sopenharmony_ci                    this->addLine(e.fPts);
335cb93a386Sopenharmony_ci                    break;
336cb93a386Sopenharmony_ci                case SkPathEdgeIter::Edge::kQuad: {
337cb93a386Sopenharmony_ci                    handle_quad(e.fPts);
338cb93a386Sopenharmony_ci                    break;
339cb93a386Sopenharmony_ci                }
340cb93a386Sopenharmony_ci                case SkPathEdgeIter::Edge::kConic: {
341cb93a386Sopenharmony_ci                    const SkPoint* quadPts = quadder.computeQuads(
342cb93a386Sopenharmony_ci                                          e.fPts, iter.conicWeight(), conicTol);
343cb93a386Sopenharmony_ci                    for (int i = 0; i < quadder.countQuads(); ++i) {
344cb93a386Sopenharmony_ci                        handle_quad(quadPts);
345cb93a386Sopenharmony_ci                        quadPts += 2;
346cb93a386Sopenharmony_ci                    }
347cb93a386Sopenharmony_ci                } break;
348cb93a386Sopenharmony_ci                case SkPathEdgeIter::Edge::kCubic: {
349cb93a386Sopenharmony_ci                    SkPoint monoY[10];
350cb93a386Sopenharmony_ci                    int n = SkChopCubicAtYExtrema(e.fPts, monoY);
351cb93a386Sopenharmony_ci                    for (int i = 0; i <= n; i++) {
352cb93a386Sopenharmony_ci                        this->addCubic(&monoY[i * 3]);
353cb93a386Sopenharmony_ci                    }
354cb93a386Sopenharmony_ci                    break;
355cb93a386Sopenharmony_ci                }
356cb93a386Sopenharmony_ci            }
357cb93a386Sopenharmony_ci        }
358cb93a386Sopenharmony_ci    }
359cb93a386Sopenharmony_ci    fEdgeList = fList.begin();
360cb93a386Sopenharmony_ci    return is_finite ? fList.count() : 0;
361cb93a386Sopenharmony_ci}
362cb93a386Sopenharmony_ci
363cb93a386Sopenharmony_ciint SkEdgeBuilder::buildEdges(const SkPath& path,
364cb93a386Sopenharmony_ci                              const SkIRect* shiftedClip) {
365cb93a386Sopenharmony_ci    // If we're convex, then we need both edges, even if the right edge is past the clip.
366cb93a386Sopenharmony_ci    const bool canCullToTheRight = !path.isConvex();
367cb93a386Sopenharmony_ci
368cb93a386Sopenharmony_ci    // We can use our buildPoly() optimization if all the segments are lines.
369cb93a386Sopenharmony_ci    // (Edges are homogeneous and stored contiguously in memory, no need for indirection.)
370cb93a386Sopenharmony_ci    const int count = SkPath::kLine_SegmentMask == path.getSegmentMasks()
371cb93a386Sopenharmony_ci        ? this->buildPoly(path, shiftedClip, canCullToTheRight)
372cb93a386Sopenharmony_ci        : this->build    (path, shiftedClip, canCullToTheRight);
373cb93a386Sopenharmony_ci
374cb93a386Sopenharmony_ci    SkASSERT(count >= 0);
375cb93a386Sopenharmony_ci
376cb93a386Sopenharmony_ci    // If we can't cull to the right, we should have count > 1 (or 0).
377cb93a386Sopenharmony_ci    if (!canCullToTheRight) {
378cb93a386Sopenharmony_ci        SkASSERT(count != 1);
379cb93a386Sopenharmony_ci    }
380cb93a386Sopenharmony_ci    return count;
381cb93a386Sopenharmony_ci}
382