18a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/*
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2008 The Android Open Source Project
38a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
68a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com */
78a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkPathMeasure.h"
1023d97760248300b7aec213a36f8b0485857240b5hstern#include "SkPathMeasurePriv.h"
118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkGeometry.h"
128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkPath.h"
138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkTSearch.h"
148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
15f97aa74fea0133378e64700e30a7c2962212fcb5caryclark#define kMaxTValue  0x3FFFFFFF
168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic inline SkScalar tValue2Scalar(int t) {
188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT((unsigned)t <= kMaxTValue);
19f97aa74fea0133378e64700e30a7c2962212fcb5caryclark    const SkScalar kMaxTReciprocal = 1.0f / kMaxTValue;
20f97aa74fea0133378e64700e30a7c2962212fcb5caryclark    return t * kMaxTReciprocal;
218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkScalar SkPathMeasure::Segment::getScalarT() const {
248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return tValue2Scalar(fTValue);
258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comconst SkPathMeasure::Segment* SkPathMeasure::NextSegment(const Segment* seg) {
288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned ptIndex = seg->fPtIndex;
298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    do {
318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        ++seg;
328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } while (seg->fPtIndex == ptIndex);
338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return seg;
348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3623d97760248300b7aec213a36f8b0485857240b5hsternvoid SkPathMeasure_segTo(const SkPoint pts[], unsigned segType,
3723d97760248300b7aec213a36f8b0485857240b5hstern                   SkScalar startT, SkScalar stopT, SkPath* dst) {
3823d97760248300b7aec213a36f8b0485857240b5hstern    SkASSERT(startT >= 0 && startT <= SK_Scalar1);
3923d97760248300b7aec213a36f8b0485857240b5hstern    SkASSERT(stopT >= 0 && stopT <= SK_Scalar1);
4023d97760248300b7aec213a36f8b0485857240b5hstern    SkASSERT(startT <= stopT);
4123d97760248300b7aec213a36f8b0485857240b5hstern
4223d97760248300b7aec213a36f8b0485857240b5hstern    if (startT == stopT) {
4323d97760248300b7aec213a36f8b0485857240b5hstern        /* if the dash as a zero-length on segment, add a corresponding zero-length line.
4423d97760248300b7aec213a36f8b0485857240b5hstern           The stroke code will add end caps to zero length lines as appropriate */
4523d97760248300b7aec213a36f8b0485857240b5hstern        SkPoint lastPt;
4623d97760248300b7aec213a36f8b0485857240b5hstern        SkAssertResult(dst->getLastPt(&lastPt));
4723d97760248300b7aec213a36f8b0485857240b5hstern        dst->lineTo(lastPt);
4823d97760248300b7aec213a36f8b0485857240b5hstern        return;
4923d97760248300b7aec213a36f8b0485857240b5hstern    }
5023d97760248300b7aec213a36f8b0485857240b5hstern
5123d97760248300b7aec213a36f8b0485857240b5hstern    SkPoint tmp0[7], tmp1[7];
5223d97760248300b7aec213a36f8b0485857240b5hstern
5323d97760248300b7aec213a36f8b0485857240b5hstern    switch (segType) {
5423d97760248300b7aec213a36f8b0485857240b5hstern        case kLine_SegType:
5523d97760248300b7aec213a36f8b0485857240b5hstern            if (SK_Scalar1 == stopT) {
5623d97760248300b7aec213a36f8b0485857240b5hstern                dst->lineTo(pts[1]);
5723d97760248300b7aec213a36f8b0485857240b5hstern            } else {
5823d97760248300b7aec213a36f8b0485857240b5hstern                dst->lineTo(SkScalarInterp(pts[0].fX, pts[1].fX, stopT),
5923d97760248300b7aec213a36f8b0485857240b5hstern                            SkScalarInterp(pts[0].fY, pts[1].fY, stopT));
6023d97760248300b7aec213a36f8b0485857240b5hstern            }
6123d97760248300b7aec213a36f8b0485857240b5hstern            break;
6223d97760248300b7aec213a36f8b0485857240b5hstern        case kQuad_SegType:
6323d97760248300b7aec213a36f8b0485857240b5hstern            if (0 == startT) {
6423d97760248300b7aec213a36f8b0485857240b5hstern                if (SK_Scalar1 == stopT) {
6523d97760248300b7aec213a36f8b0485857240b5hstern                    dst->quadTo(pts[1], pts[2]);
6623d97760248300b7aec213a36f8b0485857240b5hstern                } else {
6723d97760248300b7aec213a36f8b0485857240b5hstern                    SkChopQuadAt(pts, tmp0, stopT);
6823d97760248300b7aec213a36f8b0485857240b5hstern                    dst->quadTo(tmp0[1], tmp0[2]);
6923d97760248300b7aec213a36f8b0485857240b5hstern                }
7023d97760248300b7aec213a36f8b0485857240b5hstern            } else {
7123d97760248300b7aec213a36f8b0485857240b5hstern                SkChopQuadAt(pts, tmp0, startT);
7223d97760248300b7aec213a36f8b0485857240b5hstern                if (SK_Scalar1 == stopT) {
7323d97760248300b7aec213a36f8b0485857240b5hstern                    dst->quadTo(tmp0[3], tmp0[4]);
7423d97760248300b7aec213a36f8b0485857240b5hstern                } else {
7523d97760248300b7aec213a36f8b0485857240b5hstern                    SkChopQuadAt(&tmp0[2], tmp1, (stopT - startT) / (1 - startT));
7623d97760248300b7aec213a36f8b0485857240b5hstern                    dst->quadTo(tmp1[1], tmp1[2]);
7723d97760248300b7aec213a36f8b0485857240b5hstern                }
7823d97760248300b7aec213a36f8b0485857240b5hstern            }
7923d97760248300b7aec213a36f8b0485857240b5hstern            break;
8023d97760248300b7aec213a36f8b0485857240b5hstern        case kConic_SegType: {
8123d97760248300b7aec213a36f8b0485857240b5hstern            SkConic conic(pts[0], pts[2], pts[3], pts[1].fX);
8223d97760248300b7aec213a36f8b0485857240b5hstern
8323d97760248300b7aec213a36f8b0485857240b5hstern            if (0 == startT) {
8423d97760248300b7aec213a36f8b0485857240b5hstern                if (SK_Scalar1 == stopT) {
8523d97760248300b7aec213a36f8b0485857240b5hstern                    dst->conicTo(conic.fPts[1], conic.fPts[2], conic.fW);
8623d97760248300b7aec213a36f8b0485857240b5hstern                } else {
8723d97760248300b7aec213a36f8b0485857240b5hstern                    SkConic tmp[2];
88414c4295f951d43068666b6294df15b2fd2ba85ccaryclark                    if (conic.chopAt(stopT, tmp)) {
89414c4295f951d43068666b6294df15b2fd2ba85ccaryclark                        dst->conicTo(tmp[0].fPts[1], tmp[0].fPts[2], tmp[0].fW);
90414c4295f951d43068666b6294df15b2fd2ba85ccaryclark                    }
9123d97760248300b7aec213a36f8b0485857240b5hstern                }
9223d97760248300b7aec213a36f8b0485857240b5hstern            } else {
9323d97760248300b7aec213a36f8b0485857240b5hstern                if (SK_Scalar1 == stopT) {
9423d97760248300b7aec213a36f8b0485857240b5hstern                    SkConic tmp1[2];
95414c4295f951d43068666b6294df15b2fd2ba85ccaryclark                    if (conic.chopAt(startT, tmp1)) {
96414c4295f951d43068666b6294df15b2fd2ba85ccaryclark                        dst->conicTo(tmp1[1].fPts[1], tmp1[1].fPts[2], tmp1[1].fW);
97414c4295f951d43068666b6294df15b2fd2ba85ccaryclark                    }
9823d97760248300b7aec213a36f8b0485857240b5hstern                } else {
9923d97760248300b7aec213a36f8b0485857240b5hstern                    SkConic tmp;
10023d97760248300b7aec213a36f8b0485857240b5hstern                    conic.chopAt(startT, stopT, &tmp);
10123d97760248300b7aec213a36f8b0485857240b5hstern                    dst->conicTo(tmp.fPts[1], tmp.fPts[2], tmp.fW);
10223d97760248300b7aec213a36f8b0485857240b5hstern                }
10323d97760248300b7aec213a36f8b0485857240b5hstern            }
10423d97760248300b7aec213a36f8b0485857240b5hstern        } break;
10523d97760248300b7aec213a36f8b0485857240b5hstern        case kCubic_SegType:
10623d97760248300b7aec213a36f8b0485857240b5hstern            if (0 == startT) {
10723d97760248300b7aec213a36f8b0485857240b5hstern                if (SK_Scalar1 == stopT) {
10823d97760248300b7aec213a36f8b0485857240b5hstern                    dst->cubicTo(pts[1], pts[2], pts[3]);
10923d97760248300b7aec213a36f8b0485857240b5hstern                } else {
11023d97760248300b7aec213a36f8b0485857240b5hstern                    SkChopCubicAt(pts, tmp0, stopT);
11123d97760248300b7aec213a36f8b0485857240b5hstern                    dst->cubicTo(tmp0[1], tmp0[2], tmp0[3]);
11223d97760248300b7aec213a36f8b0485857240b5hstern                }
11323d97760248300b7aec213a36f8b0485857240b5hstern            } else {
11423d97760248300b7aec213a36f8b0485857240b5hstern                SkChopCubicAt(pts, tmp0, startT);
11523d97760248300b7aec213a36f8b0485857240b5hstern                if (SK_Scalar1 == stopT) {
11623d97760248300b7aec213a36f8b0485857240b5hstern                    dst->cubicTo(tmp0[4], tmp0[5], tmp0[6]);
11723d97760248300b7aec213a36f8b0485857240b5hstern                } else {
11823d97760248300b7aec213a36f8b0485857240b5hstern                    SkChopCubicAt(&tmp0[3], tmp1, (stopT - startT) / (1 - startT));
11923d97760248300b7aec213a36f8b0485857240b5hstern                    dst->cubicTo(tmp1[1], tmp1[2], tmp1[3]);
12023d97760248300b7aec213a36f8b0485857240b5hstern                }
12123d97760248300b7aec213a36f8b0485857240b5hstern            }
12223d97760248300b7aec213a36f8b0485857240b5hstern            break;
12323d97760248300b7aec213a36f8b0485857240b5hstern        default:
1247ca9a74fef3296cdf1385785b5e817e963bb4c35Ben Wagner            SK_ABORT("unknown segType");
12523d97760248300b7aec213a36f8b0485857240b5hstern    }
12623d97760248300b7aec213a36f8b0485857240b5hstern}
12723d97760248300b7aec213a36f8b0485857240b5hstern
1288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
1298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic inline int tspan_big_enough(int tspan) {
1318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT((unsigned)tspan <= kMaxTValue);
1328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return tspan >> 10;
1338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// can't use tangents, since we need [0..1..................2] to be seen
1368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// as definitely not a line (it is when drawn, but not parametrically)
1378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// so we compare midpoints
1388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define CHEAP_DIST_LIMIT    (SK_Scalar1/2)  // just made this value up
1398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1401a7eb266644d2e1b0968dbca606ca0a91903419dcaryclarkbool SkPathMeasure::quad_too_curvy(const SkPoint pts[3]) {
1418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // diff = (a/4 + b/2 + c/4) - (a/2 + c/2)
1428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // diff = -a/4 + b/2 - c/4
1438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScalar dx = SkScalarHalf(pts[1].fX) -
1448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                        SkScalarHalf(SkScalarHalf(pts[0].fX + pts[2].fX));
1458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScalar dy = SkScalarHalf(pts[1].fY) -
1468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                        SkScalarHalf(SkScalarHalf(pts[0].fY + pts[2].fY));
1478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScalar dist = SkMaxScalar(SkScalarAbs(dx), SkScalarAbs(dy));
1491a7eb266644d2e1b0968dbca606ca0a91903419dcaryclark    return dist > fTolerance;
1508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1521a7eb266644d2e1b0968dbca606ca0a91903419dcaryclarkbool SkPathMeasure::conic_too_curvy(const SkPoint& firstPt, const SkPoint& midTPt,
153b6474dd1a530a543ae799c3822e8bc60180761c0caryclark                            const SkPoint& lastPt) {
154b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    SkPoint midEnds = firstPt + lastPt;
155b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    midEnds *= 0.5f;
156b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    SkVector dxy = midTPt - midEnds;
157b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    SkScalar dist = SkMaxScalar(SkScalarAbs(dxy.fX), SkScalarAbs(dxy.fY));
1581a7eb266644d2e1b0968dbca606ca0a91903419dcaryclark    return dist > fTolerance;
159b6474dd1a530a543ae799c3822e8bc60180761c0caryclark}
160b6474dd1a530a543ae799c3822e8bc60180761c0caryclark
1611a7eb266644d2e1b0968dbca606ca0a91903419dcaryclarkbool SkPathMeasure::cheap_dist_exceeds_limit(const SkPoint& pt,
1628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                     SkScalar x, SkScalar y) {
1638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScalar dist = SkMaxScalar(SkScalarAbs(x - pt.fX), SkScalarAbs(y - pt.fY));
1648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // just made up the 1/2
1651a7eb266644d2e1b0968dbca606ca0a91903419dcaryclark    return dist > fTolerance;
1668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1681a7eb266644d2e1b0968dbca606ca0a91903419dcaryclarkbool SkPathMeasure::cubic_too_curvy(const SkPoint pts[4]) {
1698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return  cheap_dist_exceeds_limit(pts[1],
1708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                         SkScalarInterp(pts[0].fX, pts[3].fX, SK_Scalar1/3),
1718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                         SkScalarInterp(pts[0].fY, pts[3].fY, SK_Scalar1/3))
1728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                         ||
1738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            cheap_dist_exceeds_limit(pts[2],
1748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                         SkScalarInterp(pts[0].fX, pts[3].fX, SK_Scalar1*2/3),
1758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                         SkScalarInterp(pts[0].fY, pts[3].fY, SK_Scalar1*2/3));
1768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
178b6474dd1a530a543ae799c3822e8bc60180761c0caryclarkstatic SkScalar quad_folded_len(const SkPoint pts[3]) {
179b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    SkScalar t = SkFindQuadMaxCurvature(pts);
180b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    SkPoint pt = SkEvalQuadAt(pts, t);
181b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    SkVector a = pts[2] - pt;
182b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    SkScalar result = a.length();
183b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    if (0 != t) {
184b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        SkVector b = pts[0] - pt;
185b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        result += b.length();
186b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    }
187b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    SkASSERT(SkScalarIsFinite(result));
188b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    return result;
189b6474dd1a530a543ae799c3822e8bc60180761c0caryclark}
190b6474dd1a530a543ae799c3822e8bc60180761c0caryclark
19117bc0851d34afe8c89d7455c061a1d419f76af8acaryclark/* from http://www.malczak.linuxpl.com/blog/quadratic-bezier-curve-length/ */
192b6474dd1a530a543ae799c3822e8bc60180761c0caryclark/* This works -- more needs to be done to see if it is performant on all platforms.
193b6474dd1a530a543ae799c3822e8bc60180761c0caryclark   To use this to measure parts of quads requires recomputing everything -- perhaps
194b6474dd1a530a543ae799c3822e8bc60180761c0caryclark   a chop-like interface can start from a larger measurement and get two new measurements
195b6474dd1a530a543ae799c3822e8bc60180761c0caryclark   with one call here.
196b6474dd1a530a543ae799c3822e8bc60180761c0caryclark */
19717bc0851d34afe8c89d7455c061a1d419f76af8acaryclarkstatic SkScalar compute_quad_len(const SkPoint pts[3]) {
198b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    SkPoint a,b;
199b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    a.fX = pts[0].fX - 2 * pts[1].fX + pts[2].fX;
200b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    a.fY = pts[0].fY - 2 * pts[1].fY + pts[2].fY;
201b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    SkScalar A = 4 * (a.fX * a.fX + a.fY * a.fY);
202b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    if (0 == A) {
203b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        a = pts[2] - pts[0];
204b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        return a.length();
205b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    }
206b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    b.fX = 2 * (pts[1].fX - pts[0].fX);
207b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    b.fY = 2 * (pts[1].fY - pts[0].fY);
208b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    SkScalar B = 4 * (a.fX * b.fX + a.fY * b.fY);
209b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    SkScalar C =      b.fX * b.fX + b.fY * b.fY;
210b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    SkScalar Sabc = 2 * SkScalarSqrt(A + B + C);
211b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    SkScalar A_2  = SkScalarSqrt(A);
212b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    SkScalar A_32 = 2 * A * A_2;
213b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    SkScalar C_2  = 2 * SkScalarSqrt(C);
214b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    SkScalar BA   = B / A_2;
215b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    if (0 == BA + C_2) {
216b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        return quad_folded_len(pts);
217b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    }
218b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    SkScalar J = A_32 * Sabc + A_2 * B * (Sabc - C_2);
219b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    SkScalar K = 4 * C * A - B * B;
220b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    SkScalar L = (2 * A_2 + BA + Sabc) / (BA + C_2);
221b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    if (L <= 0) {
222b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        return quad_folded_len(pts);
223b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    }
224b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    SkScalar M = SkScalarLog(L);
225b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    SkScalar result = (J + K * M) / (4 * A_32);
226b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    SkASSERT(SkScalarIsFinite(result));
227b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    return result;
22817bc0851d34afe8c89d7455c061a1d419f76af8acaryclark}
22917bc0851d34afe8c89d7455c061a1d419f76af8acaryclark
2308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkScalar SkPathMeasure::compute_quad_segs(const SkPoint pts[3],
2318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                          SkScalar distance, int mint, int maxt, int ptIndex) {
2328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (tspan_big_enough(maxt - mint) && quad_too_curvy(pts)) {
2338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkPoint tmp[5];
2348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int     halft = (mint + maxt) >> 1;
2358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkChopQuadAtHalf(pts, tmp);
2378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        distance = this->compute_quad_segs(tmp, distance, mint, halft, ptIndex);
2388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        distance = this->compute_quad_segs(&tmp[2], distance, halft, maxt, ptIndex);
2398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {
2408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkScalar d = SkPoint::Distance(pts[0], pts[2]);
241ded44149856373072a8c6d2b2eacb213a1273a6ereed@google.com        SkScalar prevD = distance;
242ded44149856373072a8c6d2b2eacb213a1273a6ereed@google.com        distance += d;
243ded44149856373072a8c6d2b2eacb213a1273a6ereed@google.com        if (distance > prevD) {
2448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            Segment* seg = fSegments.append();
2458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            seg->fDistance = distance;
2468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            seg->fPtIndex = ptIndex;
2478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            seg->fType = kQuad_SegType;
2488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            seg->fTValue = maxt;
2498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
2508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return distance;
2528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
2538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
254b6474dd1a530a543ae799c3822e8bc60180761c0caryclarkSkScalar SkPathMeasure::compute_conic_segs(const SkConic& conic, SkScalar distance,
255b6474dd1a530a543ae799c3822e8bc60180761c0caryclark                                           int mint, const SkPoint& minPt,
256b6474dd1a530a543ae799c3822e8bc60180761c0caryclark                                           int maxt, const SkPoint& maxPt, int ptIndex) {
257b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    int halft = (mint + maxt) >> 1;
258b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    SkPoint halfPt = conic.evalAt(tValue2Scalar(halft));
259b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    if (tspan_big_enough(maxt - mint) && conic_too_curvy(minPt, halfPt, maxPt)) {
260b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        distance = this->compute_conic_segs(conic, distance, mint, minPt, halft, halfPt, ptIndex);
261b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        distance = this->compute_conic_segs(conic, distance, halft, halfPt, maxt, maxPt, ptIndex);
262b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    } else {
263b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        SkScalar d = SkPoint::Distance(minPt, maxPt);
264b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        SkScalar prevD = distance;
265b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        distance += d;
266b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        if (distance > prevD) {
267b6474dd1a530a543ae799c3822e8bc60180761c0caryclark            Segment* seg = fSegments.append();
268b6474dd1a530a543ae799c3822e8bc60180761c0caryclark            seg->fDistance = distance;
269b6474dd1a530a543ae799c3822e8bc60180761c0caryclark            seg->fPtIndex = ptIndex;
270b6474dd1a530a543ae799c3822e8bc60180761c0caryclark            seg->fType = kConic_SegType;
271b6474dd1a530a543ae799c3822e8bc60180761c0caryclark            seg->fTValue = maxt;
272b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        }
273b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    }
274b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    return distance;
275b6474dd1a530a543ae799c3822e8bc60180761c0caryclark}
276220f926d9d4b38a9018c922c095847bbd261f583reed
2778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkScalar SkPathMeasure::compute_cubic_segs(const SkPoint pts[4],
2788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                           SkScalar distance, int mint, int maxt, int ptIndex) {
2798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (tspan_big_enough(maxt - mint) && cubic_too_curvy(pts)) {
2808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkPoint tmp[7];
2818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int     halft = (mint + maxt) >> 1;
2828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkChopCubicAtHalf(pts, tmp);
2848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        distance = this->compute_cubic_segs(tmp, distance, mint, halft, ptIndex);
2858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        distance = this->compute_cubic_segs(&tmp[3], distance, halft, maxt, ptIndex);
2868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {
2878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkScalar d = SkPoint::Distance(pts[0], pts[3]);
288ded44149856373072a8c6d2b2eacb213a1273a6ereed@google.com        SkScalar prevD = distance;
289ded44149856373072a8c6d2b2eacb213a1273a6ereed@google.com        distance += d;
290ded44149856373072a8c6d2b2eacb213a1273a6ereed@google.com        if (distance > prevD) {
2918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            Segment* seg = fSegments.append();
2928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            seg->fDistance = distance;
2938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            seg->fPtIndex = ptIndex;
2948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            seg->fType = kCubic_SegType;
2958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            seg->fTValue = maxt;
2968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
2978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return distance;
2998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
3008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkPathMeasure::buildSegments() {
3028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPoint         pts[4];
3038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int             ptIndex = fFirstPtIndex;
304fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com    SkScalar        distance = 0;
3058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool            isClosed = fForceClosed;
3068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool            firstMoveTo = ptIndex < 0;
3078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    Segment*        seg;
3088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
309fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com    /*  Note:
310fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com     *  as we accumulate distance, we have to check that the result of +=
311fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com     *  actually made it larger, since a very small delta might be > 0, but
312fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com     *  still have no effect on distance (if distance >>> delta).
313ded44149856373072a8c6d2b2eacb213a1273a6ereed@google.com     *
314ded44149856373072a8c6d2b2eacb213a1273a6ereed@google.com     *  We do this check below, and in compute_quad_segs and compute_cubic_segs
315fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com     */
3168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fSegments.reset();
317a6d04d90e2f0a35698a7380cef8d622a8ee0b33fschenney@chromium.org    bool done = false;
318a6d04d90e2f0a35698a7380cef8d622a8ee0b33fschenney@chromium.org    do {
3198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        switch (fIter.next(pts)) {
3208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            case SkPath::kMove_Verb:
321a6d04d90e2f0a35698a7380cef8d622a8ee0b33fschenney@chromium.org                ptIndex += 1;
322a6d04d90e2f0a35698a7380cef8d622a8ee0b33fschenney@chromium.org                fPts.append(1, pts);
3238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                if (!firstMoveTo) {
324a6d04d90e2f0a35698a7380cef8d622a8ee0b33fschenney@chromium.org                    done = true;
325a6d04d90e2f0a35698a7380cef8d622a8ee0b33fschenney@chromium.org                    break;
3268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                }
327a6d04d90e2f0a35698a7380cef8d622a8ee0b33fschenney@chromium.org                firstMoveTo = false;
328a6d04d90e2f0a35698a7380cef8d622a8ee0b33fschenney@chromium.org                break;
3298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
330fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com            case SkPath::kLine_Verb: {
331fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com                SkScalar d = SkPoint::Distance(pts[0], pts[1]);
3328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkASSERT(d >= 0);
333fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com                SkScalar prevD = distance;
334a6d04d90e2f0a35698a7380cef8d622a8ee0b33fschenney@chromium.org                distance += d;
335fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com                if (distance > prevD) {
336fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com                    seg = fSegments.append();
337fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com                    seg->fDistance = distance;
338fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com                    seg->fPtIndex = ptIndex;
339fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com                    seg->fType = kLine_SegType;
340fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com                    seg->fTValue = kMaxTValue;
341fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com                    fPts.append(1, pts + 1);
342fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com                    ptIndex++;
343fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com                }
344fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com            } break;
3458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
346fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com            case SkPath::kQuad_Verb: {
347fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com                SkScalar prevD = distance;
34817bc0851d34afe8c89d7455c061a1d419f76af8acaryclark                if (false) {
34917bc0851d34afe8c89d7455c061a1d419f76af8acaryclark                    SkScalar length = compute_quad_len(pts);
35017bc0851d34afe8c89d7455c061a1d419f76af8acaryclark                    if (length) {
35117bc0851d34afe8c89d7455c061a1d419f76af8acaryclark                        distance += length;
35217bc0851d34afe8c89d7455c061a1d419f76af8acaryclark                        Segment* seg = fSegments.append();
35317bc0851d34afe8c89d7455c061a1d419f76af8acaryclark                        seg->fDistance = distance;
35417bc0851d34afe8c89d7455c061a1d419f76af8acaryclark                        seg->fPtIndex = ptIndex;
35517bc0851d34afe8c89d7455c061a1d419f76af8acaryclark                        seg->fType = kQuad_SegType;
35617bc0851d34afe8c89d7455c061a1d419f76af8acaryclark                        seg->fTValue = kMaxTValue;
35717bc0851d34afe8c89d7455c061a1d419f76af8acaryclark                    }
35817bc0851d34afe8c89d7455c061a1d419f76af8acaryclark                } else {
35917bc0851d34afe8c89d7455c061a1d419f76af8acaryclark                    distance = this->compute_quad_segs(pts, distance, 0, kMaxTValue, ptIndex);
36017bc0851d34afe8c89d7455c061a1d419f76af8acaryclark                }
361fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com                if (distance > prevD) {
362fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com                    fPts.append(2, pts + 1);
363fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com                    ptIndex += 2;
364fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com                }
365fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com            } break;
3668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
367220f926d9d4b38a9018c922c095847bbd261f583reed            case SkPath::kConic_Verb: {
368220f926d9d4b38a9018c922c095847bbd261f583reed                const SkConic conic(pts, fIter.conicWeight());
369220f926d9d4b38a9018c922c095847bbd261f583reed                SkScalar prevD = distance;
370b6474dd1a530a543ae799c3822e8bc60180761c0caryclark                distance = this->compute_conic_segs(conic, distance, 0, conic.fPts[0],
371b6474dd1a530a543ae799c3822e8bc60180761c0caryclark                                                    kMaxTValue, conic.fPts[2], ptIndex);
372220f926d9d4b38a9018c922c095847bbd261f583reed                if (distance > prevD) {
373220f926d9d4b38a9018c922c095847bbd261f583reed                    // we store the conic weight in our next point, followed by the last 2 pts
374220f926d9d4b38a9018c922c095847bbd261f583reed                    // thus to reconstitue a conic, you'd need to say
375220f926d9d4b38a9018c922c095847bbd261f583reed                    // SkConic(pts[0], pts[2], pts[3], weight = pts[1].fX)
376220f926d9d4b38a9018c922c095847bbd261f583reed                    fPts.append()->set(conic.fW, 0);
377220f926d9d4b38a9018c922c095847bbd261f583reed                    fPts.append(2, pts + 1);
378220f926d9d4b38a9018c922c095847bbd261f583reed                    ptIndex += 3;
379220f926d9d4b38a9018c922c095847bbd261f583reed                }
380220f926d9d4b38a9018c922c095847bbd261f583reed            } break;
381220f926d9d4b38a9018c922c095847bbd261f583reed
382fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com            case SkPath::kCubic_Verb: {
383fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com                SkScalar prevD = distance;
384220f926d9d4b38a9018c922c095847bbd261f583reed                distance = this->compute_cubic_segs(pts, distance, 0, kMaxTValue, ptIndex);
385fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com                if (distance > prevD) {
386fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com                    fPts.append(3, pts + 1);
387fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com                    ptIndex += 3;
388fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com                }
389fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com            } break;
3908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            case SkPath::kClose_Verb:
3928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                isClosed = true;
3938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                break;
394fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
3958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            case SkPath::kDone_Verb:
396a6d04d90e2f0a35698a7380cef8d622a8ee0b33fschenney@chromium.org                done = true;
397a6d04d90e2f0a35698a7380cef8d622a8ee0b33fschenney@chromium.org                break;
3988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
399a6d04d90e2f0a35698a7380cef8d622a8ee0b33fschenney@chromium.org    } while (!done);
400a6d04d90e2f0a35698a7380cef8d622a8ee0b33fschenney@chromium.org
4018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fLength = distance;
4028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fIsClosed = isClosed;
403a6d04d90e2f0a35698a7380cef8d622a8ee0b33fschenney@chromium.org    fFirstPtIndex = ptIndex;
4048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG
4068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    {
4078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        const Segment* seg = fSegments.begin();
4088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        const Segment* stop = fSegments.end();
4098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        unsigned        ptIndex = 0;
4108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkScalar        distance = 0;
411d1d628120af11c022e88265e9bdd27eb7d5d1eb8caryclark        // limit the loop to a reasonable number; pathological cases can run for minutes
412d1d628120af11c022e88265e9bdd27eb7d5d1eb8caryclark        int             maxChecks = 10000000;  // set to INT_MAX to defeat the check
4138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        while (seg < stop) {
4148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(seg->fDistance > distance);
4158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(seg->fPtIndex >= ptIndex);
4168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(seg->fTValue > 0);
4178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            const Segment* s = seg;
419d1d628120af11c022e88265e9bdd27eb7d5d1eb8caryclark            while (s < stop - 1 && s[0].fPtIndex == s[1].fPtIndex && --maxChecks > 0) {
4208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkASSERT(s[0].fType == s[1].fType);
4218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkASSERT(s[0].fTValue < s[1].fTValue);
4228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                s += 1;
4238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
4248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            distance = seg->fDistance;
4268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            ptIndex = seg->fPtIndex;
4278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            seg += 1;
4288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
4298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    //  SkDebugf("\n");
4308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
4318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
4328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
43423d97760248300b7aec213a36f8b0485857240b5hsternstatic void compute_pos_tan(const SkPoint pts[], unsigned segType,
4355b94153a7b039a9269a8aabbe8f0da0e878e3978reed@google.com                            SkScalar t, SkPoint* pos, SkVector* tangent) {
4368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    switch (segType) {
4378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case kLine_SegType:
4388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (pos) {
439a6d04d90e2f0a35698a7380cef8d622a8ee0b33fschenney@chromium.org                pos->set(SkScalarInterp(pts[0].fX, pts[1].fX, t),
4405b94153a7b039a9269a8aabbe8f0da0e878e3978reed@google.com                         SkScalarInterp(pts[0].fY, pts[1].fY, t));
4418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
4428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (tangent) {
443a6d04d90e2f0a35698a7380cef8d622a8ee0b33fschenney@chromium.org                tangent->setNormalize(pts[1].fX - pts[0].fX, pts[1].fY - pts[0].fY);
4448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
4458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
4468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case kQuad_SegType:
4478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkEvalQuadAt(pts, t, pos, tangent);
4488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (tangent) {
4498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                tangent->normalize();
4508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
4518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
452220f926d9d4b38a9018c922c095847bbd261f583reed        case kConic_SegType: {
453220f926d9d4b38a9018c922c095847bbd261f583reed            SkConic(pts[0], pts[2], pts[3], pts[1].fX).evalAt(t, pos, tangent);
454220f926d9d4b38a9018c922c095847bbd261f583reed            if (tangent) {
455220f926d9d4b38a9018c922c095847bbd261f583reed                tangent->normalize();
456220f926d9d4b38a9018c922c095847bbd261f583reed            }
457220f926d9d4b38a9018c922c095847bbd261f583reed        } break;
4588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case kCubic_SegType:
45996fcdcc219d2a0d3579719b84b28bede76efba64halcanary            SkEvalCubicAt(pts, t, pos, tangent, nullptr);
4608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (tangent) {
4618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                tangent->normalize();
4628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
4638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
4648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        default:
4650c00f21fee3f5cfa3aa7e5d46ff94cb8cf340451tomhudson@google.com            SkDEBUGFAIL("unknown segType");
4668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
4678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com////////////////////////////////////////////////////////////////////////////////
4718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com////////////////////////////////////////////////////////////////////////////////
4728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkPathMeasure::SkPathMeasure() {
47496fcdcc219d2a0d3579719b84b28bede76efba64halcanary    fPath = nullptr;
4751a7eb266644d2e1b0968dbca606ca0a91903419dcaryclark    fTolerance = CHEAP_DIST_LIMIT;
4768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fLength = -1;   // signal we need to compute it
4778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fForceClosed = false;
4788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fFirstPtIndex = -1;
4798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4811a7eb266644d2e1b0968dbca606ca0a91903419dcaryclarkSkPathMeasure::SkPathMeasure(const SkPath& path, bool forceClosed, SkScalar resScale) {
4828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fPath = &path;
4831a7eb266644d2e1b0968dbca606ca0a91903419dcaryclark    fTolerance = CHEAP_DIST_LIMIT * SkScalarInvert(resScale);
4848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fLength = -1;   // signal we need to compute it
4858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fForceClosed = forceClosed;
4868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fFirstPtIndex = -1;
4878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fIter.setPath(path, forceClosed);
4898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkPathMeasure::~SkPathMeasure() {}
4928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/** Assign a new path, or null to have none.
4948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com*/
4958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkPathMeasure::setPath(const SkPath* path, bool forceClosed) {
4968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fPath = path;
4978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fLength = -1;   // signal we need to compute it
4988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fForceClosed = forceClosed;
4998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fFirstPtIndex = -1;
5008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (path) {
5028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fIter.setPath(*path, forceClosed);
5038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
5048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fSegments.reset();
505a6d04d90e2f0a35698a7380cef8d622a8ee0b33fschenney@chromium.org    fPts.reset();
5068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
5078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkScalar SkPathMeasure::getLength() {
50996fcdcc219d2a0d3579719b84b28bede76efba64halcanary    if (fPath == nullptr) {
5108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return 0;
5118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
5128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (fLength < 0) {
5138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->buildSegments();
5148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
515ae68a399cdf3d94aff28e497d5360bc288f2131dCary Clark    if (SkScalarIsNaN(fLength)) {
516ae68a399cdf3d94aff28e497d5360bc288f2131dCary Clark        fLength = 0;
517ae68a399cdf3d94aff28e497d5360bc288f2131dCary Clark    }
5188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(fLength >= 0);
5198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return fLength;
5208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
5218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
52283e22e407e48acc4e23774edb2241c6a111e1db9reedtemplate <typename T, typename K>
52383e22e407e48acc4e23774edb2241c6a111e1db9reedint SkTKSearch(const T base[], int count, const K& key) {
52483e22e407e48acc4e23774edb2241c6a111e1db9reed    SkASSERT(count >= 0);
52583e22e407e48acc4e23774edb2241c6a111e1db9reed    if (count <= 0) {
52683e22e407e48acc4e23774edb2241c6a111e1db9reed        return ~0;
52783e22e407e48acc4e23774edb2241c6a111e1db9reed    }
5289d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary
52996fcdcc219d2a0d3579719b84b28bede76efba64halcanary    SkASSERT(base != nullptr); // base may be nullptr if count is zero
5309d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary
53183e22e407e48acc4e23774edb2241c6a111e1db9reed    int lo = 0;
53283e22e407e48acc4e23774edb2241c6a111e1db9reed    int hi = count - 1;
5339d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary
53483e22e407e48acc4e23774edb2241c6a111e1db9reed    while (lo < hi) {
53583e22e407e48acc4e23774edb2241c6a111e1db9reed        int mid = (hi + lo) >> 1;
53683e22e407e48acc4e23774edb2241c6a111e1db9reed        if (base[mid].fDistance < key) {
53783e22e407e48acc4e23774edb2241c6a111e1db9reed            lo = mid + 1;
53883e22e407e48acc4e23774edb2241c6a111e1db9reed        } else {
53983e22e407e48acc4e23774edb2241c6a111e1db9reed            hi = mid;
54083e22e407e48acc4e23774edb2241c6a111e1db9reed        }
54183e22e407e48acc4e23774edb2241c6a111e1db9reed    }
5429d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary
54383e22e407e48acc4e23774edb2241c6a111e1db9reed    if (base[hi].fDistance < key) {
54483e22e407e48acc4e23774edb2241c6a111e1db9reed        hi += 1;
54583e22e407e48acc4e23774edb2241c6a111e1db9reed        hi = ~hi;
54683e22e407e48acc4e23774edb2241c6a111e1db9reed    } else if (key < base[hi].fDistance) {
54783e22e407e48acc4e23774edb2241c6a111e1db9reed        hi = ~hi;
54883e22e407e48acc4e23774edb2241c6a111e1db9reed    }
54983e22e407e48acc4e23774edb2241c6a111e1db9reed    return hi;
55083e22e407e48acc4e23774edb2241c6a111e1db9reed}
55183e22e407e48acc4e23774edb2241c6a111e1db9reed
5528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comconst SkPathMeasure::Segment* SkPathMeasure::distanceToSegment(
5538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                            SkScalar distance, SkScalar* t) {
5548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDEBUGCODE(SkScalar length = ) this->getLength();
5558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(distance >= 0 && distance <= length);
5568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const Segment*  seg = fSegments.begin();
5588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int             count = fSegments.count();
5598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
56083e22e407e48acc4e23774edb2241c6a111e1db9reed    int index = SkTKSearch<Segment, SkScalar>(seg, count, distance);
5618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // don't care if we hit an exact match or not, so we xor index if it is negative
5628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    index ^= (index >> 31);
5638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    seg = &seg[index];
5648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // now interpolate t-values with the prev segment (if possible)
5668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScalar    startT = 0, startD = 0;
5678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // check if the prev segment is legal, and references the same set of points
5688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (index > 0) {
5698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        startD = seg[-1].fDistance;
5708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (seg[-1].fPtIndex == seg->fPtIndex) {
5718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(seg[-1].fType == seg->fType);
5728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            startT = seg[-1].getScalarT();
5738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
5748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
5758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(seg->getScalarT() > startT);
5778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(distance >= startD);
5788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(seg->fDistance > startD);
5798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
580a99b6ceff92183b424634f2e7276b9ea1d59e69dMike Reed    *t = startT + (seg->getScalarT() - startT) * (distance - startD) / (seg->fDistance - startD);
5818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return seg;
5828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
5838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
584a99b6ceff92183b424634f2e7276b9ea1d59e69dMike Reedbool SkPathMeasure::getPosTan(SkScalar distance, SkPoint* pos, SkVector* tangent) {
58596fcdcc219d2a0d3579719b84b28bede76efba64halcanary    if (nullptr == fPath) {
5868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
5878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
5888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScalar    length = this->getLength(); // call this to force computing it
5908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int         count = fSegments.count();
5918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (count == 0 || length == 0) {
593a6d04d90e2f0a35698a7380cef8d622a8ee0b33fschenney@chromium.org        return false;
5948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
5958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // pin the distance to a legal range
5978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (distance < 0) {
5988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        distance = 0;
5998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else if (distance > length) {
6008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        distance = length;
6018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
602fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
6038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScalar        t;
6048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const Segment*  seg = this->distanceToSegment(distance, &t);
6058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6065b94153a7b039a9269a8aabbe8f0da0e878e3978reed@google.com    compute_pos_tan(&fPts[seg->fPtIndex], seg->fType, t, pos, tangent);
6078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return true;
6088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
6098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkPathMeasure::getMatrix(SkScalar distance, SkMatrix* matrix,
6118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                              MatrixFlags flags) {
61296fcdcc219d2a0d3579719b84b28bede76efba64halcanary    if (nullptr == fPath) {
613dfef456f183713da8c05fe5f3d252736a7776c8cdjsollen@google.com        return false;
614dfef456f183713da8c05fe5f3d252736a7776c8cdjsollen@google.com    }
615dfef456f183713da8c05fe5f3d252736a7776c8cdjsollen@google.com
6168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPoint     position;
6178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkVector    tangent;
6188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (this->getPosTan(distance, &position, &tangent)) {
6208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (matrix) {
6218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (flags & kGetTangent_MatrixFlag) {
6228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                matrix->setSinCos(tangent.fY, tangent.fX, 0, 0);
6238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            } else {
6248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                matrix->reset();
6258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
6268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (flags & kGetPosition_MatrixFlag) {
6278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                matrix->postTranslate(position.fX, position.fY);
6288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
6298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
6308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return true;
6318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
6328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return false;
6338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
6348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkPathMeasure::getSegment(SkScalar startD, SkScalar stopD, SkPath* dst,
6368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                               bool startWithMoveTo) {
6378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(dst);
6388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScalar length = this->getLength();    // ensure we have built our segments
6408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (startD < 0) {
6428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        startD = 0;
6438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
6448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (stopD > length) {
6458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        stopD = length;
6468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
6475cb00a95734143ca068960ead1ae94d0440c61dacaryclark    if (startD > stopD) {
6488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
6498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
650703348f5fac69dbedf22cda2ce264d2c9683bcf3caryclark    if (!fSegments.count()) {
651703348f5fac69dbedf22cda2ce264d2c9683bcf3caryclark        return false;
652703348f5fac69dbedf22cda2ce264d2c9683bcf3caryclark    }
6538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPoint  p;
6558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScalar startT, stopT;
6568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const Segment* seg = this->distanceToSegment(startD, &startT);
6578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const Segment* stopSeg = this->distanceToSegment(stopD, &stopT);
6588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(seg <= stopSeg);
6598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (startWithMoveTo) {
66196fcdcc219d2a0d3579719b84b28bede76efba64halcanary        compute_pos_tan(&fPts[seg->fPtIndex], seg->fType, startT, &p, nullptr);
6628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        dst->moveTo(p);
6638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
6648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (seg->fPtIndex == stopSeg->fPtIndex) {
66623d97760248300b7aec213a36f8b0485857240b5hstern        SkPathMeasure_segTo(&fPts[seg->fPtIndex], seg->fType, startT, stopT, dst);
6678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {
6688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        do {
66923d97760248300b7aec213a36f8b0485857240b5hstern            SkPathMeasure_segTo(&fPts[seg->fPtIndex], seg->fType, startT, SK_Scalar1, dst);
6708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            seg = SkPathMeasure::NextSegment(seg);
6718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            startT = 0;
6728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        } while (seg->fPtIndex < stopSeg->fPtIndex);
67323d97760248300b7aec213a36f8b0485857240b5hstern        SkPathMeasure_segTo(&fPts[seg->fPtIndex], seg->fType, 0, stopT, dst);
6748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
6758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return true;
6768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
6778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkPathMeasure::isClosed() {
6794727ba84944fbb1e674257d938e2d0a5f2b79a56Mike Reed    (void)this->getLength();    // make sure we measure the current contour
6808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return fIsClosed;
6818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
6828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/** Move to the next contour in the path. Return true if one exists, or false if
6848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    we're done with the path.
6858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com*/
6868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkPathMeasure::nextContour() {
6874727ba84944fbb1e674257d938e2d0a5f2b79a56Mike Reed    (void)this->getLength();    // make sure we measure the current contour
6884727ba84944fbb1e674257d938e2d0a5f2b79a56Mike Reed    fLength = -1;               // now signal that we should build the next set of segments
6898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return this->getLength() > 0;
6908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
6918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
6938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
6948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG
6968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkPathMeasure::dump() {
6988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDebugf("pathmeas: length=%g, segs=%d\n", fLength, fSegments.count());
6998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    for (int i = 0; i < fSegments.count(); i++) {
7018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        const Segment* seg = &fSegments[i];
7028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkDebugf("pathmeas: seg[%d] distance=%g, point=%d, t=%g, type=%d\n",
7038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                i, seg->fDistance, seg->fPtIndex, seg->getScalarT(),
7048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                 seg->fType);
7058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
7068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
7078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
709