Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2008 The Android Open Source Project
      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 
      9 #include "SkPathMeasure.h"
     10 #include "SkPathMeasurePriv.h"
     11 #include "SkGeometry.h"
     12 #include "SkPath.h"
     13 #include "SkTSearch.h"
     14 
     15 #define kMaxTValue  0x3FFFFFFF
     16 
     17 static inline SkScalar tValue2Scalar(int t) {
     18     SkASSERT((unsigned)t <= kMaxTValue);
     19     const SkScalar kMaxTReciprocal = 1.0f / kMaxTValue;
     20     return t * kMaxTReciprocal;
     21 }
     22 
     23 SkScalar SkPathMeasure::Segment::getScalarT() const {
     24     return tValue2Scalar(fTValue);
     25 }
     26 
     27 const SkPathMeasure::Segment* SkPathMeasure::NextSegment(const Segment* seg) {
     28     unsigned ptIndex = seg->fPtIndex;
     29 
     30     do {
     31         ++seg;
     32     } while (seg->fPtIndex == ptIndex);
     33     return seg;
     34 }
     35 
     36 void SkPathMeasure_segTo(const SkPoint pts[], unsigned segType,
     37                    SkScalar startT, SkScalar stopT, SkPath* dst) {
     38     SkASSERT(startT >= 0 && startT <= SK_Scalar1);
     39     SkASSERT(stopT >= 0 && stopT <= SK_Scalar1);
     40     SkASSERT(startT <= stopT);
     41 
     42     if (startT == stopT) {
     43         /* if the dash as a zero-length on segment, add a corresponding zero-length line.
     44            The stroke code will add end caps to zero length lines as appropriate */
     45         SkPoint lastPt;
     46         SkAssertResult(dst->getLastPt(&lastPt));
     47         dst->lineTo(lastPt);
     48         return;
     49     }
     50 
     51     SkPoint tmp0[7], tmp1[7];
     52 
     53     switch (segType) {
     54         case kLine_SegType:
     55             if (SK_Scalar1 == stopT) {
     56                 dst->lineTo(pts[1]);
     57             } else {
     58                 dst->lineTo(SkScalarInterp(pts[0].fX, pts[1].fX, stopT),
     59                             SkScalarInterp(pts[0].fY, pts[1].fY, stopT));
     60             }
     61             break;
     62         case kQuad_SegType:
     63             if (0 == startT) {
     64                 if (SK_Scalar1 == stopT) {
     65                     dst->quadTo(pts[1], pts[2]);
     66                 } else {
     67                     SkChopQuadAt(pts, tmp0, stopT);
     68                     dst->quadTo(tmp0[1], tmp0[2]);
     69                 }
     70             } else {
     71                 SkChopQuadAt(pts, tmp0, startT);
     72                 if (SK_Scalar1 == stopT) {
     73                     dst->quadTo(tmp0[3], tmp0[4]);
     74                 } else {
     75                     SkChopQuadAt(&tmp0[2], tmp1, (stopT - startT) / (1 - startT));
     76                     dst->quadTo(tmp1[1], tmp1[2]);
     77                 }
     78             }
     79             break;
     80         case kConic_SegType: {
     81             SkConic conic(pts[0], pts[2], pts[3], pts[1].fX);
     82 
     83             if (0 == startT) {
     84                 if (SK_Scalar1 == stopT) {
     85                     dst->conicTo(conic.fPts[1], conic.fPts[2], conic.fW);
     86                 } else {
     87                     SkConic tmp[2];
     88                     if (conic.chopAt(stopT, tmp)) {
     89                         dst->conicTo(tmp[0].fPts[1], tmp[0].fPts[2], tmp[0].fW);
     90                     }
     91                 }
     92             } else {
     93                 if (SK_Scalar1 == stopT) {
     94                     SkConic tmp1[2];
     95                     if (conic.chopAt(startT, tmp1)) {
     96                         dst->conicTo(tmp1[1].fPts[1], tmp1[1].fPts[2], tmp1[1].fW);
     97                     }
     98                 } else {
     99                     SkConic tmp;
    100                     conic.chopAt(startT, stopT, &tmp);
    101                     dst->conicTo(tmp.fPts[1], tmp.fPts[2], tmp.fW);
    102                 }
    103             }
    104         } break;
    105         case kCubic_SegType:
    106             if (0 == startT) {
    107                 if (SK_Scalar1 == stopT) {
    108                     dst->cubicTo(pts[1], pts[2], pts[3]);
    109                 } else {
    110                     SkChopCubicAt(pts, tmp0, stopT);
    111                     dst->cubicTo(tmp0[1], tmp0[2], tmp0[3]);
    112                 }
    113             } else {
    114                 SkChopCubicAt(pts, tmp0, startT);
    115                 if (SK_Scalar1 == stopT) {
    116                     dst->cubicTo(tmp0[4], tmp0[5], tmp0[6]);
    117                 } else {
    118                     SkChopCubicAt(&tmp0[3], tmp1, (stopT - startT) / (1 - startT));
    119                     dst->cubicTo(tmp1[1], tmp1[2], tmp1[3]);
    120                 }
    121             }
    122             break;
    123         default:
    124             SkDEBUGFAIL("unknown segType");
    125             sk_throw();
    126     }
    127 }
    128 
    129 ///////////////////////////////////////////////////////////////////////////////
    130 
    131 static inline int tspan_big_enough(int tspan) {
    132     SkASSERT((unsigned)tspan <= kMaxTValue);
    133     return tspan >> 10;
    134 }
    135 
    136 // can't use tangents, since we need [0..1..................2] to be seen
    137 // as definitely not a line (it is when drawn, but not parametrically)
    138 // so we compare midpoints
    139 #define CHEAP_DIST_LIMIT    (SK_Scalar1/2)  // just made this value up
    140 
    141 bool SkPathMeasure::quad_too_curvy(const SkPoint pts[3]) {
    142     // diff = (a/4 + b/2 + c/4) - (a/2 + c/2)
    143     // diff = -a/4 + b/2 - c/4
    144     SkScalar dx = SkScalarHalf(pts[1].fX) -
    145                         SkScalarHalf(SkScalarHalf(pts[0].fX + pts[2].fX));
    146     SkScalar dy = SkScalarHalf(pts[1].fY) -
    147                         SkScalarHalf(SkScalarHalf(pts[0].fY + pts[2].fY));
    148 
    149     SkScalar dist = SkMaxScalar(SkScalarAbs(dx), SkScalarAbs(dy));
    150     return dist > fTolerance;
    151 }
    152 
    153 bool SkPathMeasure::conic_too_curvy(const SkPoint& firstPt, const SkPoint& midTPt,
    154                             const SkPoint& lastPt) {
    155     SkPoint midEnds = firstPt + lastPt;
    156     midEnds *= 0.5f;
    157     SkVector dxy = midTPt - midEnds;
    158     SkScalar dist = SkMaxScalar(SkScalarAbs(dxy.fX), SkScalarAbs(dxy.fY));
    159     return dist > fTolerance;
    160 }
    161 
    162 bool SkPathMeasure::cheap_dist_exceeds_limit(const SkPoint& pt,
    163                                      SkScalar x, SkScalar y) {
    164     SkScalar dist = SkMaxScalar(SkScalarAbs(x - pt.fX), SkScalarAbs(y - pt.fY));
    165     // just made up the 1/2
    166     return dist > fTolerance;
    167 }
    168 
    169 bool SkPathMeasure::cubic_too_curvy(const SkPoint pts[4]) {
    170     return  cheap_dist_exceeds_limit(pts[1],
    171                          SkScalarInterp(pts[0].fX, pts[3].fX, SK_Scalar1/3),
    172                          SkScalarInterp(pts[0].fY, pts[3].fY, SK_Scalar1/3))
    173                          ||
    174             cheap_dist_exceeds_limit(pts[2],
    175                          SkScalarInterp(pts[0].fX, pts[3].fX, SK_Scalar1*2/3),
    176                          SkScalarInterp(pts[0].fY, pts[3].fY, SK_Scalar1*2/3));
    177 }
    178 
    179 static SkScalar quad_folded_len(const SkPoint pts[3]) {
    180     SkScalar t = SkFindQuadMaxCurvature(pts);
    181     SkPoint pt = SkEvalQuadAt(pts, t);
    182     SkVector a = pts[2] - pt;
    183     SkScalar result = a.length();
    184     if (0 != t) {
    185         SkVector b = pts[0] - pt;
    186         result += b.length();
    187     }
    188     SkASSERT(SkScalarIsFinite(result));
    189     return result;
    190 }
    191 
    192 /* from http://www.malczak.linuxpl.com/blog/quadratic-bezier-curve-length/ */
    193 /* This works -- more needs to be done to see if it is performant on all platforms.
    194    To use this to measure parts of quads requires recomputing everything -- perhaps
    195    a chop-like interface can start from a larger measurement and get two new measurements
    196    with one call here.
    197  */
    198 static SkScalar compute_quad_len(const SkPoint pts[3]) {
    199     SkPoint a,b;
    200     a.fX = pts[0].fX - 2 * pts[1].fX + pts[2].fX;
    201     a.fY = pts[0].fY - 2 * pts[1].fY + pts[2].fY;
    202     SkScalar A = 4 * (a.fX * a.fX + a.fY * a.fY);
    203     if (0 == A) {
    204         a = pts[2] - pts[0];
    205         return a.length();
    206     }
    207     b.fX = 2 * (pts[1].fX - pts[0].fX);
    208     b.fY = 2 * (pts[1].fY - pts[0].fY);
    209     SkScalar B = 4 * (a.fX * b.fX + a.fY * b.fY);
    210     SkScalar C =      b.fX * b.fX + b.fY * b.fY;
    211     SkScalar Sabc = 2 * SkScalarSqrt(A + B + C);
    212     SkScalar A_2  = SkScalarSqrt(A);
    213     SkScalar A_32 = 2 * A * A_2;
    214     SkScalar C_2  = 2 * SkScalarSqrt(C);
    215     SkScalar BA   = B / A_2;
    216     if (0 == BA + C_2) {
    217         return quad_folded_len(pts);
    218     }
    219     SkScalar J = A_32 * Sabc + A_2 * B * (Sabc - C_2);
    220     SkScalar K = 4 * C * A - B * B;
    221     SkScalar L = (2 * A_2 + BA + Sabc) / (BA + C_2);
    222     if (L <= 0) {
    223         return quad_folded_len(pts);
    224     }
    225     SkScalar M = SkScalarLog(L);
    226     SkScalar result = (J + K * M) / (4 * A_32);
    227     SkASSERT(SkScalarIsFinite(result));
    228     return result;
    229 }
    230 
    231 SkScalar SkPathMeasure::compute_quad_segs(const SkPoint pts[3],
    232                           SkScalar distance, int mint, int maxt, int ptIndex) {
    233     if (tspan_big_enough(maxt - mint) && quad_too_curvy(pts)) {
    234         SkPoint tmp[5];
    235         int     halft = (mint + maxt) >> 1;
    236 
    237         SkChopQuadAtHalf(pts, tmp);
    238         distance = this->compute_quad_segs(tmp, distance, mint, halft, ptIndex);
    239         distance = this->compute_quad_segs(&tmp[2], distance, halft, maxt, ptIndex);
    240     } else {
    241         SkScalar d = SkPoint::Distance(pts[0], pts[2]);
    242         SkScalar prevD = distance;
    243         distance += d;
    244         if (distance > prevD) {
    245             Segment* seg = fSegments.append();
    246             seg->fDistance = distance;
    247             seg->fPtIndex = ptIndex;
    248             seg->fType = kQuad_SegType;
    249             seg->fTValue = maxt;
    250         }
    251     }
    252     return distance;
    253 }
    254 
    255 SkScalar SkPathMeasure::compute_conic_segs(const SkConic& conic, SkScalar distance,
    256                                            int mint, const SkPoint& minPt,
    257                                            int maxt, const SkPoint& maxPt, int ptIndex) {
    258     int halft = (mint + maxt) >> 1;
    259     SkPoint halfPt = conic.evalAt(tValue2Scalar(halft));
    260     if (tspan_big_enough(maxt - mint) && conic_too_curvy(minPt, halfPt, maxPt)) {
    261         distance = this->compute_conic_segs(conic, distance, mint, minPt, halft, halfPt, ptIndex);
    262         distance = this->compute_conic_segs(conic, distance, halft, halfPt, maxt, maxPt, ptIndex);
    263     } else {
    264         SkScalar d = SkPoint::Distance(minPt, maxPt);
    265         SkScalar prevD = distance;
    266         distance += d;
    267         if (distance > prevD) {
    268             Segment* seg = fSegments.append();
    269             seg->fDistance = distance;
    270             seg->fPtIndex = ptIndex;
    271             seg->fType = kConic_SegType;
    272             seg->fTValue = maxt;
    273         }
    274     }
    275     return distance;
    276 }
    277 
    278 SkScalar SkPathMeasure::compute_cubic_segs(const SkPoint pts[4],
    279                            SkScalar distance, int mint, int maxt, int ptIndex) {
    280     if (tspan_big_enough(maxt - mint) && cubic_too_curvy(pts)) {
    281         SkPoint tmp[7];
    282         int     halft = (mint + maxt) >> 1;
    283 
    284         SkChopCubicAtHalf(pts, tmp);
    285         distance = this->compute_cubic_segs(tmp, distance, mint, halft, ptIndex);
    286         distance = this->compute_cubic_segs(&tmp[3], distance, halft, maxt, ptIndex);
    287     } else {
    288         SkScalar d = SkPoint::Distance(pts[0], pts[3]);
    289         SkScalar prevD = distance;
    290         distance += d;
    291         if (distance > prevD) {
    292             Segment* seg = fSegments.append();
    293             seg->fDistance = distance;
    294             seg->fPtIndex = ptIndex;
    295             seg->fType = kCubic_SegType;
    296             seg->fTValue = maxt;
    297         }
    298     }
    299     return distance;
    300 }
    301 
    302 void SkPathMeasure::buildSegments() {
    303     SkPoint         pts[4];
    304     int             ptIndex = fFirstPtIndex;
    305     SkScalar        distance = 0;
    306     bool            isClosed = fForceClosed;
    307     bool            firstMoveTo = ptIndex < 0;
    308     Segment*        seg;
    309 
    310     /*  Note:
    311      *  as we accumulate distance, we have to check that the result of +=
    312      *  actually made it larger, since a very small delta might be > 0, but
    313      *  still have no effect on distance (if distance >>> delta).
    314      *
    315      *  We do this check below, and in compute_quad_segs and compute_cubic_segs
    316      */
    317     fSegments.reset();
    318     bool done = false;
    319     do {
    320         switch (fIter.next(pts)) {
    321             case SkPath::kMove_Verb:
    322                 ptIndex += 1;
    323                 fPts.append(1, pts);
    324                 if (!firstMoveTo) {
    325                     done = true;
    326                     break;
    327                 }
    328                 firstMoveTo = false;
    329                 break;
    330 
    331             case SkPath::kLine_Verb: {
    332                 SkScalar d = SkPoint::Distance(pts[0], pts[1]);
    333                 SkASSERT(d >= 0);
    334                 SkScalar prevD = distance;
    335                 distance += d;
    336                 if (distance > prevD) {
    337                     seg = fSegments.append();
    338                     seg->fDistance = distance;
    339                     seg->fPtIndex = ptIndex;
    340                     seg->fType = kLine_SegType;
    341                     seg->fTValue = kMaxTValue;
    342                     fPts.append(1, pts + 1);
    343                     ptIndex++;
    344                 }
    345             } break;
    346 
    347             case SkPath::kQuad_Verb: {
    348                 SkScalar prevD = distance;
    349                 if (false) {
    350                     SkScalar length = compute_quad_len(pts);
    351                     if (length) {
    352                         distance += length;
    353                         Segment* seg = fSegments.append();
    354                         seg->fDistance = distance;
    355                         seg->fPtIndex = ptIndex;
    356                         seg->fType = kQuad_SegType;
    357                         seg->fTValue = kMaxTValue;
    358                     }
    359                 } else {
    360                     distance = this->compute_quad_segs(pts, distance, 0, kMaxTValue, ptIndex);
    361                 }
    362                 if (distance > prevD) {
    363                     fPts.append(2, pts + 1);
    364                     ptIndex += 2;
    365                 }
    366             } break;
    367 
    368             case SkPath::kConic_Verb: {
    369                 const SkConic conic(pts, fIter.conicWeight());
    370                 SkScalar prevD = distance;
    371                 distance = this->compute_conic_segs(conic, distance, 0, conic.fPts[0],
    372                                                     kMaxTValue, conic.fPts[2], ptIndex);
    373                 if (distance > prevD) {
    374                     // we store the conic weight in our next point, followed by the last 2 pts
    375                     // thus to reconstitue a conic, you'd need to say
    376                     // SkConic(pts[0], pts[2], pts[3], weight = pts[1].fX)
    377                     fPts.append()->set(conic.fW, 0);
    378                     fPts.append(2, pts + 1);
    379                     ptIndex += 3;
    380                 }
    381             } break;
    382 
    383             case SkPath::kCubic_Verb: {
    384                 SkScalar prevD = distance;
    385                 distance = this->compute_cubic_segs(pts, distance, 0, kMaxTValue, ptIndex);
    386                 if (distance > prevD) {
    387                     fPts.append(3, pts + 1);
    388                     ptIndex += 3;
    389                 }
    390             } break;
    391 
    392             case SkPath::kClose_Verb:
    393                 isClosed = true;
    394                 break;
    395 
    396             case SkPath::kDone_Verb:
    397                 done = true;
    398                 break;
    399         }
    400     } while (!done);
    401 
    402     fLength = distance;
    403     fIsClosed = isClosed;
    404     fFirstPtIndex = ptIndex;
    405 
    406 #ifdef SK_DEBUG
    407     {
    408         const Segment* seg = fSegments.begin();
    409         const Segment* stop = fSegments.end();
    410         unsigned        ptIndex = 0;
    411         SkScalar        distance = 0;
    412         // limit the loop to a reasonable number; pathological cases can run for minutes
    413         int             maxChecks = 10000000;  // set to INT_MAX to defeat the check
    414         while (seg < stop) {
    415             SkASSERT(seg->fDistance > distance);
    416             SkASSERT(seg->fPtIndex >= ptIndex);
    417             SkASSERT(seg->fTValue > 0);
    418 
    419             const Segment* s = seg;
    420             while (s < stop - 1 && s[0].fPtIndex == s[1].fPtIndex && --maxChecks > 0) {
    421                 SkASSERT(s[0].fType == s[1].fType);
    422                 SkASSERT(s[0].fTValue < s[1].fTValue);
    423                 s += 1;
    424             }
    425 
    426             distance = seg->fDistance;
    427             ptIndex = seg->fPtIndex;
    428             seg += 1;
    429         }
    430     //  SkDebugf("\n");
    431     }
    432 #endif
    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 SkPathMeasure::SkPathMeasure() {
    475     fPath = nullptr;
    476     fTolerance = CHEAP_DIST_LIMIT;
    477     fLength = -1;   // signal we need to compute it
    478     fForceClosed = false;
    479     fFirstPtIndex = -1;
    480 }
    481 
    482 SkPathMeasure::SkPathMeasure(const SkPath& path, bool forceClosed, SkScalar resScale) {
    483     fPath = &path;
    484     fTolerance = CHEAP_DIST_LIMIT * SkScalarInvert(resScale);
    485     fLength = -1;   // signal we need to compute it
    486     fForceClosed = forceClosed;
    487     fFirstPtIndex = -1;
    488 
    489     fIter.setPath(path, forceClosed);
    490 }
    491 
    492 SkPathMeasure::~SkPathMeasure() {}
    493 
    494 /** Assign a new path, or null to have none.
    495 */
    496 void SkPathMeasure::setPath(const SkPath* path, bool forceClosed) {
    497     fPath = path;
    498     fLength = -1;   // signal we need to compute it
    499     fForceClosed = forceClosed;
    500     fFirstPtIndex = -1;
    501 
    502     if (path) {
    503         fIter.setPath(*path, forceClosed);
    504     }
    505     fSegments.reset();
    506     fPts.reset();
    507 }
    508 
    509 SkScalar SkPathMeasure::getLength() {
    510     if (fPath == nullptr) {
    511         return 0;
    512     }
    513     if (fLength < 0) {
    514         this->buildSegments();
    515     }
    516     if (SkScalarIsNaN(fLength)) {
    517         fLength = 0;
    518     }
    519     SkASSERT(fLength >= 0);
    520     return fLength;
    521 }
    522 
    523 template <typename T, typename K>
    524 int SkTKSearch(const T base[], int count, const K& key) {
    525     SkASSERT(count >= 0);
    526     if (count <= 0) {
    527         return ~0;
    528     }
    529 
    530     SkASSERT(base != nullptr); // base may be nullptr if count is zero
    531 
    532     int lo = 0;
    533     int hi = count - 1;
    534 
    535     while (lo < hi) {
    536         int mid = (hi + lo) >> 1;
    537         if (base[mid].fDistance < key) {
    538             lo = mid + 1;
    539         } else {
    540             hi = mid;
    541         }
    542     }
    543 
    544     if (base[hi].fDistance < key) {
    545         hi += 1;
    546         hi = ~hi;
    547     } else if (key < base[hi].fDistance) {
    548         hi = ~hi;
    549     }
    550     return hi;
    551 }
    552 
    553 const SkPathMeasure::Segment* SkPathMeasure::distanceToSegment(
    554                                             SkScalar distance, SkScalar* t) {
    555     SkDEBUGCODE(SkScalar length = ) this->getLength();
    556     SkASSERT(distance >= 0 && distance <= length);
    557 
    558     const Segment*  seg = fSegments.begin();
    559     int             count = fSegments.count();
    560 
    561     int index = SkTKSearch<Segment, SkScalar>(seg, count, distance);
    562     // don't care if we hit an exact match or not, so we xor index if it is negative
    563     index ^= (index >> 31);
    564     seg = &seg[index];
    565 
    566     // now interpolate t-values with the prev segment (if possible)
    567     SkScalar    startT = 0, startD = 0;
    568     // check if the prev segment is legal, and references the same set of points
    569     if (index > 0) {
    570         startD = seg[-1].fDistance;
    571         if (seg[-1].fPtIndex == seg->fPtIndex) {
    572             SkASSERT(seg[-1].fType == seg->fType);
    573             startT = seg[-1].getScalarT();
    574         }
    575     }
    576 
    577     SkASSERT(seg->getScalarT() > startT);
    578     SkASSERT(distance >= startD);
    579     SkASSERT(seg->fDistance > startD);
    580 
    581     *t = startT + (seg->getScalarT() - startT) * (distance - startD) / (seg->fDistance - startD);
    582     return seg;
    583 }
    584 
    585 bool SkPathMeasure::getPosTan(SkScalar distance, SkPoint* pos, SkVector* tangent) {
    586     if (nullptr == fPath) {
    587         return false;
    588     }
    589 
    590     SkScalar    length = this->getLength(); // call this to force computing it
    591     int         count = fSegments.count();
    592 
    593     if (count == 0 || length == 0) {
    594         return false;
    595     }
    596 
    597     // pin the distance to a legal range
    598     if (distance < 0) {
    599         distance = 0;
    600     } else if (distance > length) {
    601         distance = length;
    602     }
    603 
    604     SkScalar        t;
    605     const Segment*  seg = this->distanceToSegment(distance, &t);
    606 
    607     compute_pos_tan(&fPts[seg->fPtIndex], seg->fType, t, pos, tangent);
    608     return true;
    609 }
    610 
    611 bool SkPathMeasure::getMatrix(SkScalar distance, SkMatrix* matrix,
    612                               MatrixFlags flags) {
    613     if (nullptr == fPath) {
    614         return false;
    615     }
    616 
    617     SkPoint     position;
    618     SkVector    tangent;
    619 
    620     if (this->getPosTan(distance, &position, &tangent)) {
    621         if (matrix) {
    622             if (flags & kGetTangent_MatrixFlag) {
    623                 matrix->setSinCos(tangent.fY, tangent.fX, 0, 0);
    624             } else {
    625                 matrix->reset();
    626             }
    627             if (flags & kGetPosition_MatrixFlag) {
    628                 matrix->postTranslate(position.fX, position.fY);
    629             }
    630         }
    631         return true;
    632     }
    633     return false;
    634 }
    635 
    636 bool SkPathMeasure::getSegment(SkScalar startD, SkScalar stopD, SkPath* dst,
    637                                bool startWithMoveTo) {
    638     SkASSERT(dst);
    639 
    640     SkScalar length = this->getLength();    // ensure we have built our segments
    641 
    642     if (startD < 0) {
    643         startD = 0;
    644     }
    645     if (stopD > length) {
    646         stopD = length;
    647     }
    648     if (startD > stopD) {
    649         return false;
    650     }
    651     if (!fSegments.count()) {
    652         return false;
    653     }
    654 
    655     SkPoint  p;
    656     SkScalar startT, stopT;
    657     const Segment* seg = this->distanceToSegment(startD, &startT);
    658     const Segment* stopSeg = this->distanceToSegment(stopD, &stopT);
    659     SkASSERT(seg <= stopSeg);
    660 
    661     if (startWithMoveTo) {
    662         compute_pos_tan(&fPts[seg->fPtIndex], seg->fType, startT, &p, nullptr);
    663         dst->moveTo(p);
    664     }
    665 
    666     if (seg->fPtIndex == stopSeg->fPtIndex) {
    667         SkPathMeasure_segTo(&fPts[seg->fPtIndex], seg->fType, startT, stopT, dst);
    668     } else {
    669         do {
    670             SkPathMeasure_segTo(&fPts[seg->fPtIndex], seg->fType, startT, SK_Scalar1, dst);
    671             seg = SkPathMeasure::NextSegment(seg);
    672             startT = 0;
    673         } while (seg->fPtIndex < stopSeg->fPtIndex);
    674         SkPathMeasure_segTo(&fPts[seg->fPtIndex], seg->fType, 0, stopT, dst);
    675     }
    676     return true;
    677 }
    678 
    679 bool SkPathMeasure::isClosed() {
    680     (void)this->getLength();
    681     return fIsClosed;
    682 }
    683 
    684 /** Move to the next contour in the path. Return true if one exists, or false if
    685     we're done with the path.
    686 */
    687 bool SkPathMeasure::nextContour() {
    688     fLength = -1;
    689     return this->getLength() > 0;
    690 }
    691 
    692 ///////////////////////////////////////////////////////////////////////////////
    693 ///////////////////////////////////////////////////////////////////////////////
    694 
    695 #ifdef SK_DEBUG
    696 
    697 void SkPathMeasure::dump() {
    698     SkDebugf("pathmeas: length=%g, segs=%d\n", fLength, fSegments.count());
    699 
    700     for (int i = 0; i < fSegments.count(); i++) {
    701         const Segment* seg = &fSegments[i];
    702         SkDebugf("pathmeas: seg[%d] distance=%g, point=%d, t=%g, type=%d\n",
    703                 i, seg->fDistance, seg->fPtIndex, seg->getScalarT(),
    704                  seg->fType);
    705     }
    706 }
    707 
    708 #endif
    709