1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2018 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/SkContourMeasure.h"
9cb93a386Sopenharmony_ci#include "include/core/SkPath.h"
10cb93a386Sopenharmony_ci#include "src/core/SkGeometry.h"
11cb93a386Sopenharmony_ci#include "src/core/SkPathMeasurePriv.h"
12cb93a386Sopenharmony_ci#include "src/core/SkPathPriv.h"
13cb93a386Sopenharmony_ci#include "src/core/SkTSearch.h"
14cb93a386Sopenharmony_ci
15cb93a386Sopenharmony_ci#define kMaxTValue  0x3FFFFFFF
16cb93a386Sopenharmony_ci
17cb93a386Sopenharmony_ciconstexpr static inline SkScalar tValue2Scalar(int t) {
18cb93a386Sopenharmony_ci    SkASSERT((unsigned)t <= kMaxTValue);
19cb93a386Sopenharmony_ci    // 1/kMaxTValue can't be represented as a float, but it's close and the limits work fine.
20cb93a386Sopenharmony_ci    const SkScalar kMaxTReciprocal = 1.0f / (SkScalar)kMaxTValue;
21cb93a386Sopenharmony_ci    return t * kMaxTReciprocal;
22cb93a386Sopenharmony_ci}
23cb93a386Sopenharmony_ci
24cb93a386Sopenharmony_cistatic_assert(0.0f == tValue2Scalar(         0), "Lower limit should be exact.");
25cb93a386Sopenharmony_cistatic_assert(1.0f == tValue2Scalar(kMaxTValue), "Upper limit should be exact.");
26cb93a386Sopenharmony_ci
27cb93a386Sopenharmony_ciSkScalar SkContourMeasure::Segment::getScalarT() const {
28cb93a386Sopenharmony_ci    return tValue2Scalar(fTValue);
29cb93a386Sopenharmony_ci}
30cb93a386Sopenharmony_ci
31cb93a386Sopenharmony_civoid SkContourMeasure_segTo(const SkPoint pts[], unsigned segType,
32cb93a386Sopenharmony_ci                            SkScalar startT, SkScalar stopT, SkPath* dst) {
33cb93a386Sopenharmony_ci    SkASSERT(startT >= 0 && startT <= SK_Scalar1);
34cb93a386Sopenharmony_ci    SkASSERT(stopT >= 0 && stopT <= SK_Scalar1);
35cb93a386Sopenharmony_ci    SkASSERT(startT <= stopT);
36cb93a386Sopenharmony_ci
37cb93a386Sopenharmony_ci    if (startT == stopT) {
38cb93a386Sopenharmony_ci        if (!dst->isEmpty()) {
39cb93a386Sopenharmony_ci            /* if the dash as a zero-length on segment, add a corresponding zero-length line.
40cb93a386Sopenharmony_ci               The stroke code will add end caps to zero length lines as appropriate */
41cb93a386Sopenharmony_ci            SkPoint lastPt;
42cb93a386Sopenharmony_ci            SkAssertResult(dst->getLastPt(&lastPt));
43cb93a386Sopenharmony_ci            dst->lineTo(lastPt);
44cb93a386Sopenharmony_ci        }
45cb93a386Sopenharmony_ci        return;
46cb93a386Sopenharmony_ci    }
47cb93a386Sopenharmony_ci
48cb93a386Sopenharmony_ci    SkPoint tmp0[7], tmp1[7];
49cb93a386Sopenharmony_ci
50cb93a386Sopenharmony_ci    switch (segType) {
51cb93a386Sopenharmony_ci        case kLine_SegType:
52cb93a386Sopenharmony_ci            if (SK_Scalar1 == stopT) {
53cb93a386Sopenharmony_ci                dst->lineTo(pts[1]);
54cb93a386Sopenharmony_ci            } else {
55cb93a386Sopenharmony_ci                dst->lineTo(SkScalarInterp(pts[0].fX, pts[1].fX, stopT),
56cb93a386Sopenharmony_ci                            SkScalarInterp(pts[0].fY, pts[1].fY, stopT));
57cb93a386Sopenharmony_ci            }
58cb93a386Sopenharmony_ci            break;
59cb93a386Sopenharmony_ci        case kQuad_SegType:
60cb93a386Sopenharmony_ci            if (0 == startT) {
61cb93a386Sopenharmony_ci                if (SK_Scalar1 == stopT) {
62cb93a386Sopenharmony_ci                    dst->quadTo(pts[1], pts[2]);
63cb93a386Sopenharmony_ci                } else {
64cb93a386Sopenharmony_ci                    SkChopQuadAt(pts, tmp0, stopT);
65cb93a386Sopenharmony_ci                    dst->quadTo(tmp0[1], tmp0[2]);
66cb93a386Sopenharmony_ci                }
67cb93a386Sopenharmony_ci            } else {
68cb93a386Sopenharmony_ci                SkChopQuadAt(pts, tmp0, startT);
69cb93a386Sopenharmony_ci                if (SK_Scalar1 == stopT) {
70cb93a386Sopenharmony_ci                    dst->quadTo(tmp0[3], tmp0[4]);
71cb93a386Sopenharmony_ci                } else {
72cb93a386Sopenharmony_ci                    SkChopQuadAt(&tmp0[2], tmp1, (stopT - startT) / (1 - startT));
73cb93a386Sopenharmony_ci                    dst->quadTo(tmp1[1], tmp1[2]);
74cb93a386Sopenharmony_ci                }
75cb93a386Sopenharmony_ci            }
76cb93a386Sopenharmony_ci            break;
77cb93a386Sopenharmony_ci        case kConic_SegType: {
78cb93a386Sopenharmony_ci            SkConic conic(pts[0], pts[2], pts[3], pts[1].fX);
79cb93a386Sopenharmony_ci
80cb93a386Sopenharmony_ci            if (0 == startT) {
81cb93a386Sopenharmony_ci                if (SK_Scalar1 == stopT) {
82cb93a386Sopenharmony_ci                    dst->conicTo(conic.fPts[1], conic.fPts[2], conic.fW);
83cb93a386Sopenharmony_ci                } else {
84cb93a386Sopenharmony_ci                    SkConic tmp[2];
85cb93a386Sopenharmony_ci                    if (conic.chopAt(stopT, tmp)) {
86cb93a386Sopenharmony_ci                        dst->conicTo(tmp[0].fPts[1], tmp[0].fPts[2], tmp[0].fW);
87cb93a386Sopenharmony_ci                    }
88cb93a386Sopenharmony_ci                }
89cb93a386Sopenharmony_ci            } else {
90cb93a386Sopenharmony_ci                if (SK_Scalar1 == stopT) {
91cb93a386Sopenharmony_ci                    SkConic tmp[2];
92cb93a386Sopenharmony_ci                    if (conic.chopAt(startT, tmp)) {
93cb93a386Sopenharmony_ci                        dst->conicTo(tmp[1].fPts[1], tmp[1].fPts[2], tmp[1].fW);
94cb93a386Sopenharmony_ci                    }
95cb93a386Sopenharmony_ci                } else {
96cb93a386Sopenharmony_ci                    SkConic tmp;
97cb93a386Sopenharmony_ci                    conic.chopAt(startT, stopT, &tmp);
98cb93a386Sopenharmony_ci                    dst->conicTo(tmp.fPts[1], tmp.fPts[2], tmp.fW);
99cb93a386Sopenharmony_ci                }
100cb93a386Sopenharmony_ci            }
101cb93a386Sopenharmony_ci        } break;
102cb93a386Sopenharmony_ci        case kCubic_SegType:
103cb93a386Sopenharmony_ci            if (0 == startT) {
104cb93a386Sopenharmony_ci                if (SK_Scalar1 == stopT) {
105cb93a386Sopenharmony_ci                    dst->cubicTo(pts[1], pts[2], pts[3]);
106cb93a386Sopenharmony_ci                } else {
107cb93a386Sopenharmony_ci                    SkChopCubicAt(pts, tmp0, stopT);
108cb93a386Sopenharmony_ci                    dst->cubicTo(tmp0[1], tmp0[2], tmp0[3]);
109cb93a386Sopenharmony_ci                }
110cb93a386Sopenharmony_ci            } else {
111cb93a386Sopenharmony_ci                SkChopCubicAt(pts, tmp0, startT);
112cb93a386Sopenharmony_ci                if (SK_Scalar1 == stopT) {
113cb93a386Sopenharmony_ci                    dst->cubicTo(tmp0[4], tmp0[5], tmp0[6]);
114cb93a386Sopenharmony_ci                } else {
115cb93a386Sopenharmony_ci                    SkChopCubicAt(&tmp0[3], tmp1, (stopT - startT) / (1 - startT));
116cb93a386Sopenharmony_ci                    dst->cubicTo(tmp1[1], tmp1[2], tmp1[3]);
117cb93a386Sopenharmony_ci                }
118cb93a386Sopenharmony_ci            }
119cb93a386Sopenharmony_ci            break;
120cb93a386Sopenharmony_ci        default:
121cb93a386Sopenharmony_ci            SK_ABORT("unknown segType");
122cb93a386Sopenharmony_ci    }
123cb93a386Sopenharmony_ci}
124cb93a386Sopenharmony_ci
125cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////
126cb93a386Sopenharmony_ci
127cb93a386Sopenharmony_cistatic inline int tspan_big_enough(int tspan) {
128cb93a386Sopenharmony_ci    SkASSERT((unsigned)tspan <= kMaxTValue);
129cb93a386Sopenharmony_ci    return tspan >> 10;
130cb93a386Sopenharmony_ci}
131cb93a386Sopenharmony_ci
132cb93a386Sopenharmony_ci// can't use tangents, since we need [0..1..................2] to be seen
133cb93a386Sopenharmony_ci// as definitely not a line (it is when drawn, but not parametrically)
134cb93a386Sopenharmony_ci// so we compare midpoints
135cb93a386Sopenharmony_ci#define CHEAP_DIST_LIMIT    (SK_Scalar1/2)  // just made this value up
136cb93a386Sopenharmony_ci
137cb93a386Sopenharmony_cistatic bool quad_too_curvy(const SkPoint pts[3], SkScalar tolerance) {
138cb93a386Sopenharmony_ci    // diff = (a/4 + b/2 + c/4) - (a/2 + c/2)
139cb93a386Sopenharmony_ci    // diff = -a/4 + b/2 - c/4
140cb93a386Sopenharmony_ci    SkScalar dx = SkScalarHalf(pts[1].fX) -
141cb93a386Sopenharmony_ci                        SkScalarHalf(SkScalarHalf(pts[0].fX + pts[2].fX));
142cb93a386Sopenharmony_ci    SkScalar dy = SkScalarHalf(pts[1].fY) -
143cb93a386Sopenharmony_ci                        SkScalarHalf(SkScalarHalf(pts[0].fY + pts[2].fY));
144cb93a386Sopenharmony_ci
145cb93a386Sopenharmony_ci    SkScalar dist = std::max(SkScalarAbs(dx), SkScalarAbs(dy));
146cb93a386Sopenharmony_ci    return dist > tolerance;
147cb93a386Sopenharmony_ci}
148cb93a386Sopenharmony_ci
149cb93a386Sopenharmony_cistatic bool conic_too_curvy(const SkPoint& firstPt, const SkPoint& midTPt,
150cb93a386Sopenharmony_ci                            const SkPoint& lastPt, SkScalar tolerance) {
151cb93a386Sopenharmony_ci    SkPoint midEnds = firstPt + lastPt;
152cb93a386Sopenharmony_ci    midEnds *= 0.5f;
153cb93a386Sopenharmony_ci    SkVector dxy = midTPt - midEnds;
154cb93a386Sopenharmony_ci    SkScalar dist = std::max(SkScalarAbs(dxy.fX), SkScalarAbs(dxy.fY));
155cb93a386Sopenharmony_ci    return dist > tolerance;
156cb93a386Sopenharmony_ci}
157cb93a386Sopenharmony_ci
158cb93a386Sopenharmony_cistatic bool cheap_dist_exceeds_limit(const SkPoint& pt, SkScalar x, SkScalar y,
159cb93a386Sopenharmony_ci                                     SkScalar tolerance) {
160cb93a386Sopenharmony_ci    SkScalar dist = std::max(SkScalarAbs(x - pt.fX), SkScalarAbs(y - pt.fY));
161cb93a386Sopenharmony_ci    // just made up the 1/2
162cb93a386Sopenharmony_ci    return dist > tolerance;
163cb93a386Sopenharmony_ci}
164cb93a386Sopenharmony_ci
165cb93a386Sopenharmony_cistatic bool cubic_too_curvy(const SkPoint pts[4], SkScalar tolerance) {
166cb93a386Sopenharmony_ci    return  cheap_dist_exceeds_limit(pts[1],
167cb93a386Sopenharmony_ci                         SkScalarInterp(pts[0].fX, pts[3].fX, SK_Scalar1/3),
168cb93a386Sopenharmony_ci                         SkScalarInterp(pts[0].fY, pts[3].fY, SK_Scalar1/3), tolerance)
169cb93a386Sopenharmony_ci                         ||
170cb93a386Sopenharmony_ci            cheap_dist_exceeds_limit(pts[2],
171cb93a386Sopenharmony_ci                         SkScalarInterp(pts[0].fX, pts[3].fX, SK_Scalar1*2/3),
172cb93a386Sopenharmony_ci                         SkScalarInterp(pts[0].fY, pts[3].fY, SK_Scalar1*2/3), tolerance);
173cb93a386Sopenharmony_ci}
174cb93a386Sopenharmony_ci
175cb93a386Sopenharmony_ciclass SkContourMeasureIter::Impl {
176cb93a386Sopenharmony_cipublic:
177cb93a386Sopenharmony_ci    Impl(const SkPath& path, bool forceClosed, SkScalar resScale)
178cb93a386Sopenharmony_ci        : fPath(path)
179cb93a386Sopenharmony_ci        , fIter(SkPathPriv::Iterate(fPath).begin())
180cb93a386Sopenharmony_ci        , fTolerance(CHEAP_DIST_LIMIT * SkScalarInvert(resScale))
181cb93a386Sopenharmony_ci        , fForceClosed(forceClosed) {}
182cb93a386Sopenharmony_ci
183cb93a386Sopenharmony_ci    bool hasNextSegments() const { return fIter != SkPathPriv::Iterate(fPath).end(); }
184cb93a386Sopenharmony_ci    SkContourMeasure* buildSegments();
185cb93a386Sopenharmony_ci
186cb93a386Sopenharmony_ciprivate:
187cb93a386Sopenharmony_ci    SkPath                fPath;
188cb93a386Sopenharmony_ci    SkPathPriv::RangeIter fIter;
189cb93a386Sopenharmony_ci    SkScalar              fTolerance;
190cb93a386Sopenharmony_ci    bool                  fForceClosed;
191cb93a386Sopenharmony_ci
192cb93a386Sopenharmony_ci    // temporary
193cb93a386Sopenharmony_ci    SkTDArray<SkContourMeasure::Segment>  fSegments;
194cb93a386Sopenharmony_ci    SkTDArray<SkPoint>  fPts; // Points used to define the segments
195cb93a386Sopenharmony_ci
196cb93a386Sopenharmony_ci    SkDEBUGCODE(void validate() const;)
197cb93a386Sopenharmony_ci    SkScalar compute_line_seg(SkPoint p0, SkPoint p1, SkScalar distance, unsigned ptIndex);
198cb93a386Sopenharmony_ci    SkScalar compute_quad_segs(const SkPoint pts[3], SkScalar distance,
199cb93a386Sopenharmony_ci                               int mint, int maxt, unsigned ptIndex);
200cb93a386Sopenharmony_ci    SkScalar compute_conic_segs(const SkConic& conic, SkScalar distance,
201cb93a386Sopenharmony_ci                                                         int mint, const SkPoint& minPt,
202cb93a386Sopenharmony_ci                                                         int maxt, const SkPoint& maxPt,
203cb93a386Sopenharmony_ci                                unsigned ptIndex);
204cb93a386Sopenharmony_ci    SkScalar compute_cubic_segs(const SkPoint pts[4], SkScalar distance,
205cb93a386Sopenharmony_ci                                int mint, int maxt, unsigned ptIndex);
206cb93a386Sopenharmony_ci};
207cb93a386Sopenharmony_ci
208cb93a386Sopenharmony_ciSkScalar SkContourMeasureIter::Impl::compute_quad_segs(const SkPoint pts[3], SkScalar distance,
209cb93a386Sopenharmony_ci                                                       int mint, int maxt, unsigned ptIndex) {
210cb93a386Sopenharmony_ci    if (tspan_big_enough(maxt - mint) && quad_too_curvy(pts, fTolerance)) {
211cb93a386Sopenharmony_ci        SkPoint tmp[5];
212cb93a386Sopenharmony_ci        int     halft = (mint + maxt) >> 1;
213cb93a386Sopenharmony_ci
214cb93a386Sopenharmony_ci        SkChopQuadAtHalf(pts, tmp);
215cb93a386Sopenharmony_ci        distance = this->compute_quad_segs(tmp, distance, mint, halft, ptIndex);
216cb93a386Sopenharmony_ci        distance = this->compute_quad_segs(&tmp[2], distance, halft, maxt, ptIndex);
217cb93a386Sopenharmony_ci    } else {
218cb93a386Sopenharmony_ci        SkScalar d = SkPoint::Distance(pts[0], pts[2]);
219cb93a386Sopenharmony_ci        SkScalar prevD = distance;
220cb93a386Sopenharmony_ci        distance += d;
221cb93a386Sopenharmony_ci        if (distance > prevD) {
222cb93a386Sopenharmony_ci            SkASSERT(ptIndex < (unsigned)fPts.count());
223cb93a386Sopenharmony_ci            SkContourMeasure::Segment* seg = fSegments.append();
224cb93a386Sopenharmony_ci            seg->fDistance = distance;
225cb93a386Sopenharmony_ci            seg->fPtIndex = ptIndex;
226cb93a386Sopenharmony_ci            seg->fType = kQuad_SegType;
227cb93a386Sopenharmony_ci            seg->fTValue = maxt;
228cb93a386Sopenharmony_ci        }
229cb93a386Sopenharmony_ci    }
230cb93a386Sopenharmony_ci    return distance;
231cb93a386Sopenharmony_ci}
232cb93a386Sopenharmony_ci
233cb93a386Sopenharmony_ciSkScalar SkContourMeasureIter::Impl::compute_conic_segs(const SkConic& conic, SkScalar distance,
234cb93a386Sopenharmony_ci                                                        int mint, const SkPoint& minPt,
235cb93a386Sopenharmony_ci                                                        int maxt, const SkPoint& maxPt,
236cb93a386Sopenharmony_ci                                                        unsigned ptIndex) {
237cb93a386Sopenharmony_ci    int halft = (mint + maxt) >> 1;
238cb93a386Sopenharmony_ci    SkPoint halfPt = conic.evalAt(tValue2Scalar(halft));
239cb93a386Sopenharmony_ci    if (!halfPt.isFinite()) {
240cb93a386Sopenharmony_ci        return distance;
241cb93a386Sopenharmony_ci    }
242cb93a386Sopenharmony_ci    if (tspan_big_enough(maxt - mint) && conic_too_curvy(minPt, halfPt, maxPt, fTolerance)) {
243cb93a386Sopenharmony_ci        distance = this->compute_conic_segs(conic, distance, mint, minPt, halft, halfPt, ptIndex);
244cb93a386Sopenharmony_ci        distance = this->compute_conic_segs(conic, distance, halft, halfPt, maxt, maxPt, ptIndex);
245cb93a386Sopenharmony_ci    } else {
246cb93a386Sopenharmony_ci        SkScalar d = SkPoint::Distance(minPt, maxPt);
247cb93a386Sopenharmony_ci        SkScalar prevD = distance;
248cb93a386Sopenharmony_ci        distance += d;
249cb93a386Sopenharmony_ci        if (distance > prevD) {
250cb93a386Sopenharmony_ci            SkASSERT(ptIndex < (unsigned)fPts.count());
251cb93a386Sopenharmony_ci            SkContourMeasure::Segment* seg = fSegments.append();
252cb93a386Sopenharmony_ci            seg->fDistance = distance;
253cb93a386Sopenharmony_ci            seg->fPtIndex = ptIndex;
254cb93a386Sopenharmony_ci            seg->fType = kConic_SegType;
255cb93a386Sopenharmony_ci            seg->fTValue = maxt;
256cb93a386Sopenharmony_ci        }
257cb93a386Sopenharmony_ci    }
258cb93a386Sopenharmony_ci    return distance;
259cb93a386Sopenharmony_ci}
260cb93a386Sopenharmony_ci
261cb93a386Sopenharmony_ciSkScalar SkContourMeasureIter::Impl::compute_cubic_segs(const SkPoint pts[4], SkScalar distance,
262cb93a386Sopenharmony_ci                                                        int mint, int maxt, unsigned ptIndex) {
263cb93a386Sopenharmony_ci    if (tspan_big_enough(maxt - mint) && cubic_too_curvy(pts, fTolerance)) {
264cb93a386Sopenharmony_ci        SkPoint tmp[7];
265cb93a386Sopenharmony_ci        int     halft = (mint + maxt) >> 1;
266cb93a386Sopenharmony_ci
267cb93a386Sopenharmony_ci        SkChopCubicAtHalf(pts, tmp);
268cb93a386Sopenharmony_ci        distance = this->compute_cubic_segs(tmp, distance, mint, halft, ptIndex);
269cb93a386Sopenharmony_ci        distance = this->compute_cubic_segs(&tmp[3], distance, halft, maxt, ptIndex);
270cb93a386Sopenharmony_ci    } else {
271cb93a386Sopenharmony_ci        SkScalar d = SkPoint::Distance(pts[0], pts[3]);
272cb93a386Sopenharmony_ci        SkScalar prevD = distance;
273cb93a386Sopenharmony_ci        distance += d;
274cb93a386Sopenharmony_ci        if (distance > prevD) {
275cb93a386Sopenharmony_ci            SkASSERT(ptIndex < (unsigned)fPts.count());
276cb93a386Sopenharmony_ci            SkContourMeasure::Segment* seg = fSegments.append();
277cb93a386Sopenharmony_ci            seg->fDistance = distance;
278cb93a386Sopenharmony_ci            seg->fPtIndex = ptIndex;
279cb93a386Sopenharmony_ci            seg->fType = kCubic_SegType;
280cb93a386Sopenharmony_ci            seg->fTValue = maxt;
281cb93a386Sopenharmony_ci        }
282cb93a386Sopenharmony_ci    }
283cb93a386Sopenharmony_ci    return distance;
284cb93a386Sopenharmony_ci}
285cb93a386Sopenharmony_ci
286cb93a386Sopenharmony_ciSkScalar SkContourMeasureIter::Impl::compute_line_seg(SkPoint p0, SkPoint p1, SkScalar distance,
287cb93a386Sopenharmony_ci                                                      unsigned ptIndex) {
288cb93a386Sopenharmony_ci    SkScalar d = SkPoint::Distance(p0, p1);
289cb93a386Sopenharmony_ci    SkASSERT(d >= 0);
290cb93a386Sopenharmony_ci    SkScalar prevD = distance;
291cb93a386Sopenharmony_ci    distance += d;
292cb93a386Sopenharmony_ci    if (distance > prevD) {
293cb93a386Sopenharmony_ci        SkASSERT((unsigned)ptIndex < (unsigned)fPts.count());
294cb93a386Sopenharmony_ci        SkContourMeasure::Segment* seg = fSegments.append();
295cb93a386Sopenharmony_ci        seg->fDistance = distance;
296cb93a386Sopenharmony_ci        seg->fPtIndex = ptIndex;
297cb93a386Sopenharmony_ci        seg->fType = kLine_SegType;
298cb93a386Sopenharmony_ci        seg->fTValue = kMaxTValue;
299cb93a386Sopenharmony_ci    }
300cb93a386Sopenharmony_ci    return distance;
301cb93a386Sopenharmony_ci}
302cb93a386Sopenharmony_ci
303cb93a386Sopenharmony_ci#ifdef SK_DEBUG
304cb93a386Sopenharmony_civoid SkContourMeasureIter::Impl::validate() const {
305cb93a386Sopenharmony_ci    const SkContourMeasure::Segment* seg = fSegments.begin();
306cb93a386Sopenharmony_ci    const SkContourMeasure::Segment* stop = fSegments.end();
307cb93a386Sopenharmony_ci    unsigned ptIndex = 0;
308cb93a386Sopenharmony_ci    SkScalar distance = 0;
309cb93a386Sopenharmony_ci    // limit the loop to a reasonable number; pathological cases can run for minutes
310cb93a386Sopenharmony_ci    int maxChecks = 10000000;  // set to INT_MAX to defeat the check
311cb93a386Sopenharmony_ci    while (seg < stop) {
312cb93a386Sopenharmony_ci        SkASSERT(seg->fDistance > distance);
313cb93a386Sopenharmony_ci        SkASSERT(seg->fPtIndex >= ptIndex);
314cb93a386Sopenharmony_ci        SkASSERT(seg->fTValue > 0);
315cb93a386Sopenharmony_ci
316cb93a386Sopenharmony_ci        const SkContourMeasure::Segment* s = seg;
317cb93a386Sopenharmony_ci        while (s < stop - 1 && s[0].fPtIndex == s[1].fPtIndex && --maxChecks > 0) {
318cb93a386Sopenharmony_ci            SkASSERT(s[0].fType == s[1].fType);
319cb93a386Sopenharmony_ci            SkASSERT(s[0].fTValue < s[1].fTValue);
320cb93a386Sopenharmony_ci            s += 1;
321cb93a386Sopenharmony_ci        }
322cb93a386Sopenharmony_ci
323cb93a386Sopenharmony_ci        distance = seg->fDistance;
324cb93a386Sopenharmony_ci        ptIndex = seg->fPtIndex;
325cb93a386Sopenharmony_ci        seg += 1;
326cb93a386Sopenharmony_ci    }
327cb93a386Sopenharmony_ci}
328cb93a386Sopenharmony_ci#endif
329cb93a386Sopenharmony_ci
330cb93a386Sopenharmony_ciSkContourMeasure* SkContourMeasureIter::Impl::buildSegments() {
331cb93a386Sopenharmony_ci    int         ptIndex = -1;
332cb93a386Sopenharmony_ci    SkScalar    distance = 0;
333cb93a386Sopenharmony_ci    bool        haveSeenClose = fForceClosed;
334cb93a386Sopenharmony_ci    bool        haveSeenMoveTo = false;
335cb93a386Sopenharmony_ci
336cb93a386Sopenharmony_ci    /*  Note:
337cb93a386Sopenharmony_ci     *  as we accumulate distance, we have to check that the result of +=
338cb93a386Sopenharmony_ci     *  actually made it larger, since a very small delta might be > 0, but
339cb93a386Sopenharmony_ci     *  still have no effect on distance (if distance >>> delta).
340cb93a386Sopenharmony_ci     *
341cb93a386Sopenharmony_ci     *  We do this check below, and in compute_quad_segs and compute_cubic_segs
342cb93a386Sopenharmony_ci     */
343cb93a386Sopenharmony_ci
344cb93a386Sopenharmony_ci    fSegments.reset();
345cb93a386Sopenharmony_ci    fPts.reset();
346cb93a386Sopenharmony_ci
347cb93a386Sopenharmony_ci    auto end = SkPathPriv::Iterate(fPath).end();
348cb93a386Sopenharmony_ci    for (; fIter != end; ++fIter) {
349cb93a386Sopenharmony_ci        auto [verb, pts, w] = *fIter;
350cb93a386Sopenharmony_ci        if (haveSeenMoveTo && verb == SkPathVerb::kMove) {
351cb93a386Sopenharmony_ci            break;
352cb93a386Sopenharmony_ci        }
353cb93a386Sopenharmony_ci        switch (verb) {
354cb93a386Sopenharmony_ci            case SkPathVerb::kMove:
355cb93a386Sopenharmony_ci                ptIndex += 1;
356cb93a386Sopenharmony_ci                fPts.append(1, pts);
357cb93a386Sopenharmony_ci                SkASSERT(!haveSeenMoveTo);
358cb93a386Sopenharmony_ci                haveSeenMoveTo = true;
359cb93a386Sopenharmony_ci                break;
360cb93a386Sopenharmony_ci
361cb93a386Sopenharmony_ci            case SkPathVerb::kLine: {
362cb93a386Sopenharmony_ci                SkASSERT(haveSeenMoveTo);
363cb93a386Sopenharmony_ci                SkScalar prevD = distance;
364cb93a386Sopenharmony_ci                distance = this->compute_line_seg(pts[0], pts[1], distance, ptIndex);
365cb93a386Sopenharmony_ci                if (distance > prevD) {
366cb93a386Sopenharmony_ci                    fPts.append(1, pts + 1);
367cb93a386Sopenharmony_ci                    ptIndex++;
368cb93a386Sopenharmony_ci                }
369cb93a386Sopenharmony_ci            } break;
370cb93a386Sopenharmony_ci
371cb93a386Sopenharmony_ci            case SkPathVerb::kQuad: {
372cb93a386Sopenharmony_ci                SkASSERT(haveSeenMoveTo);
373cb93a386Sopenharmony_ci                SkScalar prevD = distance;
374cb93a386Sopenharmony_ci                distance = this->compute_quad_segs(pts, distance, 0, kMaxTValue, ptIndex);
375cb93a386Sopenharmony_ci                if (distance > prevD) {
376cb93a386Sopenharmony_ci                    fPts.append(2, pts + 1);
377cb93a386Sopenharmony_ci                    ptIndex += 2;
378cb93a386Sopenharmony_ci                }
379cb93a386Sopenharmony_ci            } break;
380cb93a386Sopenharmony_ci
381cb93a386Sopenharmony_ci            case SkPathVerb::kConic: {
382cb93a386Sopenharmony_ci                SkASSERT(haveSeenMoveTo);
383cb93a386Sopenharmony_ci                const SkConic conic(pts, *w);
384cb93a386Sopenharmony_ci                SkScalar prevD = distance;
385cb93a386Sopenharmony_ci                distance = this->compute_conic_segs(conic, distance, 0, conic.fPts[0],
386cb93a386Sopenharmony_ci                                                    kMaxTValue, conic.fPts[2], ptIndex);
387cb93a386Sopenharmony_ci                if (distance > prevD) {
388cb93a386Sopenharmony_ci                    // we store the conic weight in our next point, followed by the last 2 pts
389cb93a386Sopenharmony_ci                    // thus to reconstitue a conic, you'd need to say
390cb93a386Sopenharmony_ci                    // SkConic(pts[0], pts[2], pts[3], weight = pts[1].fX)
391cb93a386Sopenharmony_ci                    fPts.append()->set(conic.fW, 0);
392cb93a386Sopenharmony_ci                    fPts.append(2, pts + 1);
393cb93a386Sopenharmony_ci                    ptIndex += 3;
394cb93a386Sopenharmony_ci                }
395cb93a386Sopenharmony_ci            } break;
396cb93a386Sopenharmony_ci
397cb93a386Sopenharmony_ci            case SkPathVerb::kCubic: {
398cb93a386Sopenharmony_ci                SkASSERT(haveSeenMoveTo);
399cb93a386Sopenharmony_ci                SkScalar prevD = distance;
400cb93a386Sopenharmony_ci                distance = this->compute_cubic_segs(pts, distance, 0, kMaxTValue, ptIndex);
401cb93a386Sopenharmony_ci                if (distance > prevD) {
402cb93a386Sopenharmony_ci                    fPts.append(3, pts + 1);
403cb93a386Sopenharmony_ci                    ptIndex += 3;
404cb93a386Sopenharmony_ci                }
405cb93a386Sopenharmony_ci            } break;
406cb93a386Sopenharmony_ci
407cb93a386Sopenharmony_ci            case SkPathVerb::kClose:
408cb93a386Sopenharmony_ci                haveSeenClose = true;
409cb93a386Sopenharmony_ci                break;
410cb93a386Sopenharmony_ci        }
411cb93a386Sopenharmony_ci
412cb93a386Sopenharmony_ci    }
413cb93a386Sopenharmony_ci
414cb93a386Sopenharmony_ci    if (!SkScalarIsFinite(distance)) {
415cb93a386Sopenharmony_ci        return nullptr;
416cb93a386Sopenharmony_ci    }
417cb93a386Sopenharmony_ci    if (fSegments.count() == 0) {
418cb93a386Sopenharmony_ci        return nullptr;
419cb93a386Sopenharmony_ci    }
420cb93a386Sopenharmony_ci
421cb93a386Sopenharmony_ci    if (haveSeenClose) {
422cb93a386Sopenharmony_ci        SkScalar prevD = distance;
423cb93a386Sopenharmony_ci        SkPoint firstPt = fPts[0];
424cb93a386Sopenharmony_ci        distance = this->compute_line_seg(fPts[ptIndex], firstPt, distance, ptIndex);
425cb93a386Sopenharmony_ci        if (distance > prevD) {
426cb93a386Sopenharmony_ci            *fPts.append() = firstPt;
427cb93a386Sopenharmony_ci        }
428cb93a386Sopenharmony_ci    }
429cb93a386Sopenharmony_ci
430cb93a386Sopenharmony_ci    SkDEBUGCODE(this->validate();)
431cb93a386Sopenharmony_ci
432cb93a386Sopenharmony_ci    return new SkContourMeasure(std::move(fSegments), std::move(fPts), distance, haveSeenClose);
433cb93a386Sopenharmony_ci}
434cb93a386Sopenharmony_ci
435cb93a386Sopenharmony_cistatic void compute_pos_tan(const SkPoint pts[], unsigned segType,
436cb93a386Sopenharmony_ci                            SkScalar t, SkPoint* pos, SkVector* tangent) {
437cb93a386Sopenharmony_ci    switch (segType) {
438cb93a386Sopenharmony_ci        case kLine_SegType:
439cb93a386Sopenharmony_ci            if (pos) {
440cb93a386Sopenharmony_ci                pos->set(SkScalarInterp(pts[0].fX, pts[1].fX, t),
441cb93a386Sopenharmony_ci                         SkScalarInterp(pts[0].fY, pts[1].fY, t));
442cb93a386Sopenharmony_ci            }
443cb93a386Sopenharmony_ci            if (tangent) {
444cb93a386Sopenharmony_ci                tangent->setNormalize(pts[1].fX - pts[0].fX, pts[1].fY - pts[0].fY);
445cb93a386Sopenharmony_ci            }
446cb93a386Sopenharmony_ci            break;
447cb93a386Sopenharmony_ci        case kQuad_SegType:
448cb93a386Sopenharmony_ci            SkEvalQuadAt(pts, t, pos, tangent);
449cb93a386Sopenharmony_ci            if (tangent) {
450cb93a386Sopenharmony_ci                tangent->normalize();
451cb93a386Sopenharmony_ci            }
452cb93a386Sopenharmony_ci            break;
453cb93a386Sopenharmony_ci        case kConic_SegType: {
454cb93a386Sopenharmony_ci            SkConic(pts[0], pts[2], pts[3], pts[1].fX).evalAt(t, pos, tangent);
455cb93a386Sopenharmony_ci            if (tangent) {
456cb93a386Sopenharmony_ci                tangent->normalize();
457cb93a386Sopenharmony_ci            }
458cb93a386Sopenharmony_ci        } break;
459cb93a386Sopenharmony_ci        case kCubic_SegType:
460cb93a386Sopenharmony_ci            SkEvalCubicAt(pts, t, pos, tangent, nullptr);
461cb93a386Sopenharmony_ci            if (tangent) {
462cb93a386Sopenharmony_ci                tangent->normalize();
463cb93a386Sopenharmony_ci            }
464cb93a386Sopenharmony_ci            break;
465cb93a386Sopenharmony_ci        default:
466cb93a386Sopenharmony_ci            SkDEBUGFAIL("unknown segType");
467cb93a386Sopenharmony_ci    }
468cb93a386Sopenharmony_ci}
469cb93a386Sopenharmony_ci
470cb93a386Sopenharmony_ci
471cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////////
472cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////////
473cb93a386Sopenharmony_ci
474cb93a386Sopenharmony_ciSkContourMeasureIter::SkContourMeasureIter() {
475cb93a386Sopenharmony_ci}
476cb93a386Sopenharmony_ci
477cb93a386Sopenharmony_ciSkContourMeasureIter::SkContourMeasureIter(const SkPath& path, bool forceClosed,
478cb93a386Sopenharmony_ci                                           SkScalar resScale) {
479cb93a386Sopenharmony_ci    this->reset(path, forceClosed, resScale);
480cb93a386Sopenharmony_ci}
481cb93a386Sopenharmony_ci
482cb93a386Sopenharmony_ciSkContourMeasureIter::~SkContourMeasureIter() {}
483cb93a386Sopenharmony_ci
484cb93a386Sopenharmony_ci/** Assign a new path, or null to have none.
485cb93a386Sopenharmony_ci*/
486cb93a386Sopenharmony_civoid SkContourMeasureIter::reset(const SkPath& path, bool forceClosed, SkScalar resScale) {
487cb93a386Sopenharmony_ci    if (path.isFinite()) {
488cb93a386Sopenharmony_ci        fImpl = std::make_unique<Impl>(path, forceClosed, resScale);
489cb93a386Sopenharmony_ci    } else {
490cb93a386Sopenharmony_ci        fImpl.reset();
491cb93a386Sopenharmony_ci    }
492cb93a386Sopenharmony_ci}
493cb93a386Sopenharmony_ci
494cb93a386Sopenharmony_cisk_sp<SkContourMeasure> SkContourMeasureIter::next() {
495cb93a386Sopenharmony_ci    if (!fImpl) {
496cb93a386Sopenharmony_ci        return nullptr;
497cb93a386Sopenharmony_ci    }
498cb93a386Sopenharmony_ci    while (fImpl->hasNextSegments()) {
499cb93a386Sopenharmony_ci        auto cm = fImpl->buildSegments();
500cb93a386Sopenharmony_ci        if (cm) {
501cb93a386Sopenharmony_ci            return sk_sp<SkContourMeasure>(cm);
502cb93a386Sopenharmony_ci        }
503cb93a386Sopenharmony_ci    }
504cb93a386Sopenharmony_ci    return nullptr;
505cb93a386Sopenharmony_ci}
506cb93a386Sopenharmony_ci
507cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
508cb93a386Sopenharmony_ci
509cb93a386Sopenharmony_ciSkContourMeasure::SkContourMeasure(SkTDArray<Segment>&& segs, SkTDArray<SkPoint>&& pts, SkScalar length, bool isClosed)
510cb93a386Sopenharmony_ci    : fSegments(std::move(segs))
511cb93a386Sopenharmony_ci    , fPts(std::move(pts))
512cb93a386Sopenharmony_ci    , fLength(length)
513cb93a386Sopenharmony_ci    , fIsClosed(isClosed)
514cb93a386Sopenharmony_ci    {}
515cb93a386Sopenharmony_ci
516cb93a386Sopenharmony_citemplate <typename T, typename K>
517cb93a386Sopenharmony_ciint SkTKSearch(const T base[], int count, const K& key) {
518cb93a386Sopenharmony_ci    SkASSERT(count >= 0);
519cb93a386Sopenharmony_ci    if (count <= 0) {
520cb93a386Sopenharmony_ci        return ~0;
521cb93a386Sopenharmony_ci    }
522cb93a386Sopenharmony_ci
523cb93a386Sopenharmony_ci    SkASSERT(base != nullptr); // base may be nullptr if count is zero
524cb93a386Sopenharmony_ci
525cb93a386Sopenharmony_ci    unsigned lo = 0;
526cb93a386Sopenharmony_ci    unsigned hi = count - 1;
527cb93a386Sopenharmony_ci
528cb93a386Sopenharmony_ci    while (lo < hi) {
529cb93a386Sopenharmony_ci        unsigned mid = (hi + lo) >> 1;
530cb93a386Sopenharmony_ci        if (base[mid].fDistance < key) {
531cb93a386Sopenharmony_ci            lo = mid + 1;
532cb93a386Sopenharmony_ci        } else {
533cb93a386Sopenharmony_ci            hi = mid;
534cb93a386Sopenharmony_ci        }
535cb93a386Sopenharmony_ci    }
536cb93a386Sopenharmony_ci
537cb93a386Sopenharmony_ci    if (base[hi].fDistance < key) {
538cb93a386Sopenharmony_ci        hi += 1;
539cb93a386Sopenharmony_ci        hi = ~hi;
540cb93a386Sopenharmony_ci    } else if (key < base[hi].fDistance) {
541cb93a386Sopenharmony_ci        hi = ~hi;
542cb93a386Sopenharmony_ci    }
543cb93a386Sopenharmony_ci    return hi;
544cb93a386Sopenharmony_ci}
545cb93a386Sopenharmony_ci
546cb93a386Sopenharmony_ciconst SkContourMeasure::Segment* SkContourMeasure::distanceToSegment( SkScalar distance,
547cb93a386Sopenharmony_ci                                                                     SkScalar* t) const {
548cb93a386Sopenharmony_ci    SkDEBUGCODE(SkScalar length = ) this->length();
549cb93a386Sopenharmony_ci    SkASSERT(distance >= 0 && distance <= length);
550cb93a386Sopenharmony_ci
551cb93a386Sopenharmony_ci    const Segment*  seg = fSegments.begin();
552cb93a386Sopenharmony_ci    int             count = fSegments.count();
553cb93a386Sopenharmony_ci
554cb93a386Sopenharmony_ci    int index = SkTKSearch<Segment, SkScalar>(seg, count, distance);
555cb93a386Sopenharmony_ci    // don't care if we hit an exact match or not, so we xor index if it is negative
556cb93a386Sopenharmony_ci    index ^= (index >> 31);
557cb93a386Sopenharmony_ci    seg = &seg[index];
558cb93a386Sopenharmony_ci
559cb93a386Sopenharmony_ci    // now interpolate t-values with the prev segment (if possible)
560cb93a386Sopenharmony_ci    SkScalar    startT = 0, startD = 0;
561cb93a386Sopenharmony_ci    // check if the prev segment is legal, and references the same set of points
562cb93a386Sopenharmony_ci    if (index > 0) {
563cb93a386Sopenharmony_ci        startD = seg[-1].fDistance;
564cb93a386Sopenharmony_ci        if (seg[-1].fPtIndex == seg->fPtIndex) {
565cb93a386Sopenharmony_ci            SkASSERT(seg[-1].fType == seg->fType);
566cb93a386Sopenharmony_ci            startT = seg[-1].getScalarT();
567cb93a386Sopenharmony_ci        }
568cb93a386Sopenharmony_ci    }
569cb93a386Sopenharmony_ci
570cb93a386Sopenharmony_ci    SkASSERT(seg->getScalarT() > startT);
571cb93a386Sopenharmony_ci    SkASSERT(distance >= startD);
572cb93a386Sopenharmony_ci    SkASSERT(seg->fDistance > startD);
573cb93a386Sopenharmony_ci
574cb93a386Sopenharmony_ci    *t = startT + (seg->getScalarT() - startT) * (distance - startD) / (seg->fDistance - startD);
575cb93a386Sopenharmony_ci    return seg;
576cb93a386Sopenharmony_ci}
577cb93a386Sopenharmony_ci
578cb93a386Sopenharmony_cibool SkContourMeasure::getPosTan(SkScalar distance, SkPoint* pos, SkVector* tangent) const {
579cb93a386Sopenharmony_ci    if (SkScalarIsNaN(distance)) {
580cb93a386Sopenharmony_ci        return false;
581cb93a386Sopenharmony_ci    }
582cb93a386Sopenharmony_ci
583cb93a386Sopenharmony_ci    const SkScalar length = this->length();
584cb93a386Sopenharmony_ci    SkASSERT(length > 0 && fSegments.count() > 0);
585cb93a386Sopenharmony_ci
586cb93a386Sopenharmony_ci    // pin the distance to a legal range
587cb93a386Sopenharmony_ci    if (distance < 0) {
588cb93a386Sopenharmony_ci        distance = 0;
589cb93a386Sopenharmony_ci    } else if (distance > length) {
590cb93a386Sopenharmony_ci        distance = length;
591cb93a386Sopenharmony_ci    }
592cb93a386Sopenharmony_ci
593cb93a386Sopenharmony_ci    SkScalar        t;
594cb93a386Sopenharmony_ci    const Segment*  seg = this->distanceToSegment(distance, &t);
595cb93a386Sopenharmony_ci    if (SkScalarIsNaN(t)) {
596cb93a386Sopenharmony_ci        return false;
597cb93a386Sopenharmony_ci    }
598cb93a386Sopenharmony_ci
599cb93a386Sopenharmony_ci    SkASSERT((unsigned)seg->fPtIndex < (unsigned)fPts.count());
600cb93a386Sopenharmony_ci    compute_pos_tan(&fPts[seg->fPtIndex], seg->fType, t, pos, tangent);
601cb93a386Sopenharmony_ci    return true;
602cb93a386Sopenharmony_ci}
603cb93a386Sopenharmony_ci
604cb93a386Sopenharmony_cibool SkContourMeasure::getMatrix(SkScalar distance, SkMatrix* matrix, MatrixFlags flags) const {
605cb93a386Sopenharmony_ci    SkPoint     position;
606cb93a386Sopenharmony_ci    SkVector    tangent;
607cb93a386Sopenharmony_ci
608cb93a386Sopenharmony_ci    if (this->getPosTan(distance, &position, &tangent)) {
609cb93a386Sopenharmony_ci        if (matrix) {
610cb93a386Sopenharmony_ci            if (flags & kGetTangent_MatrixFlag) {
611cb93a386Sopenharmony_ci                matrix->setSinCos(tangent.fY, tangent.fX, 0, 0);
612cb93a386Sopenharmony_ci            } else {
613cb93a386Sopenharmony_ci                matrix->reset();
614cb93a386Sopenharmony_ci            }
615cb93a386Sopenharmony_ci            if (flags & kGetPosition_MatrixFlag) {
616cb93a386Sopenharmony_ci                matrix->postTranslate(position.fX, position.fY);
617cb93a386Sopenharmony_ci            }
618cb93a386Sopenharmony_ci        }
619cb93a386Sopenharmony_ci        return true;
620cb93a386Sopenharmony_ci    }
621cb93a386Sopenharmony_ci    return false;
622cb93a386Sopenharmony_ci}
623cb93a386Sopenharmony_ci
624cb93a386Sopenharmony_cibool SkContourMeasure::getSegment(SkScalar startD, SkScalar stopD, SkPath* dst,
625cb93a386Sopenharmony_ci                                  bool startWithMoveTo) const {
626cb93a386Sopenharmony_ci    SkASSERT(dst);
627cb93a386Sopenharmony_ci
628cb93a386Sopenharmony_ci    SkScalar length = this->length();    // ensure we have built our segments
629cb93a386Sopenharmony_ci
630cb93a386Sopenharmony_ci    if (startD < 0) {
631cb93a386Sopenharmony_ci        startD = 0;
632cb93a386Sopenharmony_ci    }
633cb93a386Sopenharmony_ci    if (stopD > length) {
634cb93a386Sopenharmony_ci        stopD = length;
635cb93a386Sopenharmony_ci    }
636cb93a386Sopenharmony_ci    if (!(startD <= stopD)) {   // catch NaN values as well
637cb93a386Sopenharmony_ci        return false;
638cb93a386Sopenharmony_ci    }
639cb93a386Sopenharmony_ci    if (!fSegments.count()) {
640cb93a386Sopenharmony_ci        return false;
641cb93a386Sopenharmony_ci    }
642cb93a386Sopenharmony_ci
643cb93a386Sopenharmony_ci    SkPoint  p;
644cb93a386Sopenharmony_ci    SkScalar startT, stopT;
645cb93a386Sopenharmony_ci    const Segment* seg = this->distanceToSegment(startD, &startT);
646cb93a386Sopenharmony_ci    if (!SkScalarIsFinite(startT)) {
647cb93a386Sopenharmony_ci        return false;
648cb93a386Sopenharmony_ci    }
649cb93a386Sopenharmony_ci    const Segment* stopSeg = this->distanceToSegment(stopD, &stopT);
650cb93a386Sopenharmony_ci    if (!SkScalarIsFinite(stopT)) {
651cb93a386Sopenharmony_ci        return false;
652cb93a386Sopenharmony_ci    }
653cb93a386Sopenharmony_ci    SkASSERT(seg <= stopSeg);
654cb93a386Sopenharmony_ci    if (startWithMoveTo) {
655cb93a386Sopenharmony_ci        compute_pos_tan(&fPts[seg->fPtIndex], seg->fType, startT, &p, nullptr);
656cb93a386Sopenharmony_ci        dst->moveTo(p);
657cb93a386Sopenharmony_ci    }
658cb93a386Sopenharmony_ci
659cb93a386Sopenharmony_ci    if (seg->fPtIndex == stopSeg->fPtIndex) {
660cb93a386Sopenharmony_ci        SkContourMeasure_segTo(&fPts[seg->fPtIndex], seg->fType, startT, stopT, dst);
661cb93a386Sopenharmony_ci    } else {
662cb93a386Sopenharmony_ci        do {
663cb93a386Sopenharmony_ci            SkContourMeasure_segTo(&fPts[seg->fPtIndex], seg->fType, startT, SK_Scalar1, dst);
664cb93a386Sopenharmony_ci            seg = SkContourMeasure::Segment::Next(seg);
665cb93a386Sopenharmony_ci            startT = 0;
666cb93a386Sopenharmony_ci        } while (seg->fPtIndex < stopSeg->fPtIndex);
667cb93a386Sopenharmony_ci        SkContourMeasure_segTo(&fPts[seg->fPtIndex], seg->fType, 0, stopT, dst);
668cb93a386Sopenharmony_ci    }
669cb93a386Sopenharmony_ci
670cb93a386Sopenharmony_ci    return true;
671cb93a386Sopenharmony_ci}
672