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