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