1685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com
2bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com/*
3685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * Copyright 2008 The Android Open Source Project
4bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com *
5685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * Use of this source code is governed by a BSD-style license that can be
6685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * found in the LICENSE file.
7bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com */
8bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
9685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com
10bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkPathMeasure.h"
11bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkGeometry.h"
12bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkPath.h"
13bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkTSearch.h"
14bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
15bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com// these must be 0,1,2 since they are in our 2-bit field
16bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comenum {
17bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    kLine_SegType,
18bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    kQuad_SegType,
19bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    kCubic_SegType
20bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com};
21bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
22bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#define kMaxTValue  32767
23bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
24bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comstatic inline SkScalar tValue2Scalar(int t) {
25bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT((unsigned)t <= kMaxTValue);
26bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
27bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#ifdef SK_SCALAR_IS_FLOAT
28bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return t * 3.05185e-5f; // t / 32767
29bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#else
30bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return (t + (t >> 14)) << 1;
31bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#endif
32bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
33bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
34bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comSkScalar SkPathMeasure::Segment::getScalarT() const {
35bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return tValue2Scalar(fTValue);
36bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
37bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
38bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comconst SkPathMeasure::Segment* SkPathMeasure::NextSegment(const Segment* seg) {
39bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    unsigned ptIndex = seg->fPtIndex;
40bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
41bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    do {
42bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        ++seg;
43bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    } while (seg->fPtIndex == ptIndex);
44bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return seg;
45bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
46bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
47bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com///////////////////////////////////////////////////////////////////////////////
48bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
49bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comstatic inline int tspan_big_enough(int tspan) {
50bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT((unsigned)tspan <= kMaxTValue);
51bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return tspan >> 10;
52bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
53bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
54bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com// can't use tangents, since we need [0..1..................2] to be seen
55bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com// as definitely not a line (it is when drawn, but not parametrically)
56bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com// so we compare midpoints
57bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#define CHEAP_DIST_LIMIT    (SK_Scalar1/2)  // just made this value up
58bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
59bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comstatic bool quad_too_curvy(const SkPoint pts[3]) {
60bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // diff = (a/4 + b/2 + c/4) - (a/2 + c/2)
61bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // diff = -a/4 + b/2 - c/4
62bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkScalar dx = SkScalarHalf(pts[1].fX) -
63bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                        SkScalarHalf(SkScalarHalf(pts[0].fX + pts[2].fX));
64bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkScalar dy = SkScalarHalf(pts[1].fY) -
65bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                        SkScalarHalf(SkScalarHalf(pts[0].fY + pts[2].fY));
66bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
67bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkScalar dist = SkMaxScalar(SkScalarAbs(dx), SkScalarAbs(dy));
68bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return dist > CHEAP_DIST_LIMIT;
69bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
70bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
71bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comstatic bool cheap_dist_exceeds_limit(const SkPoint& pt,
72bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                                     SkScalar x, SkScalar y) {
73bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkScalar dist = SkMaxScalar(SkScalarAbs(x - pt.fX), SkScalarAbs(y - pt.fY));
74bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // just made up the 1/2
75bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return dist > CHEAP_DIST_LIMIT;
76bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
77bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
78bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comstatic bool cubic_too_curvy(const SkPoint pts[4]) {
79bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return  cheap_dist_exceeds_limit(pts[1],
80bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                         SkScalarInterp(pts[0].fX, pts[3].fX, SK_Scalar1/3),
81bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                         SkScalarInterp(pts[0].fY, pts[3].fY, SK_Scalar1/3))
82bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                         ||
83bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            cheap_dist_exceeds_limit(pts[2],
84bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                         SkScalarInterp(pts[0].fX, pts[3].fX, SK_Scalar1*2/3),
85bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                         SkScalarInterp(pts[0].fY, pts[3].fY, SK_Scalar1*2/3));
86bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
87bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
88bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comSkScalar SkPathMeasure::compute_quad_segs(const SkPoint pts[3],
89bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                          SkScalar distance, int mint, int maxt, int ptIndex) {
90bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (tspan_big_enough(maxt - mint) && quad_too_curvy(pts)) {
91bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkPoint tmp[5];
92bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        int     halft = (mint + maxt) >> 1;
93bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
94bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkChopQuadAtHalf(pts, tmp);
95bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        distance = this->compute_quad_segs(tmp, distance, mint, halft, ptIndex);
96bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        distance = this->compute_quad_segs(&tmp[2], distance, halft, maxt, ptIndex);
97bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    } else {
98bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkScalar d = SkPoint::Distance(pts[0], pts[2]);
99839341811ba8026eca7f6e39eeb654eca7971461reed@google.com        SkScalar prevD = distance;
100839341811ba8026eca7f6e39eeb654eca7971461reed@google.com        distance += d;
101839341811ba8026eca7f6e39eeb654eca7971461reed@google.com        if (distance > prevD) {
102bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            Segment* seg = fSegments.append();
103bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            seg->fDistance = distance;
104bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            seg->fPtIndex = ptIndex;
105bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            seg->fType = kQuad_SegType;
106bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            seg->fTValue = maxt;
107bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
108bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
109bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return distance;
110bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
111bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
112bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comSkScalar SkPathMeasure::compute_cubic_segs(const SkPoint pts[4],
113bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                           SkScalar distance, int mint, int maxt, int ptIndex) {
114bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (tspan_big_enough(maxt - mint) && cubic_too_curvy(pts)) {
115bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkPoint tmp[7];
116bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        int     halft = (mint + maxt) >> 1;
117bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
118bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkChopCubicAtHalf(pts, tmp);
119bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        distance = this->compute_cubic_segs(tmp, distance, mint, halft, ptIndex);
120bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        distance = this->compute_cubic_segs(&tmp[3], distance, halft, maxt, ptIndex);
121bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    } else {
122bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkScalar d = SkPoint::Distance(pts[0], pts[3]);
123839341811ba8026eca7f6e39eeb654eca7971461reed@google.com        SkScalar prevD = distance;
124839341811ba8026eca7f6e39eeb654eca7971461reed@google.com        distance += d;
125839341811ba8026eca7f6e39eeb654eca7971461reed@google.com        if (distance > prevD) {
126bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            Segment* seg = fSegments.append();
127bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            seg->fDistance = distance;
128bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            seg->fPtIndex = ptIndex;
129bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            seg->fType = kCubic_SegType;
130bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            seg->fTValue = maxt;
131bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
132bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
133bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return distance;
134bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
135bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
136bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comvoid SkPathMeasure::buildSegments() {
137bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkPoint         pts[4];
138bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    int             ptIndex = fFirstPtIndex;
13967b63a2f8aa3d3e6053c75e9de7f63887f5d496freed@google.com    SkScalar        distance = 0;
140bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    bool            isClosed = fForceClosed;
141bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    bool            firstMoveTo = ptIndex < 0;
142bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    Segment*        seg;
143bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
14467b63a2f8aa3d3e6053c75e9de7f63887f5d496freed@google.com    /*  Note:
14567b63a2f8aa3d3e6053c75e9de7f63887f5d496freed@google.com     *  as we accumulate distance, we have to check that the result of +=
14667b63a2f8aa3d3e6053c75e9de7f63887f5d496freed@google.com     *  actually made it larger, since a very small delta might be > 0, but
14767b63a2f8aa3d3e6053c75e9de7f63887f5d496freed@google.com     *  still have no effect on distance (if distance >>> delta).
148839341811ba8026eca7f6e39eeb654eca7971461reed@google.com     *
149839341811ba8026eca7f6e39eeb654eca7971461reed@google.com     *  We do this check below, and in compute_quad_segs and compute_cubic_segs
15067b63a2f8aa3d3e6053c75e9de7f63887f5d496freed@google.com     */
151bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fSegments.reset();
152ef7f0ecebfaa39e8a3b8a3011448e3e35eb71134schenney@chromium.org    bool done = false;
153ef7f0ecebfaa39e8a3b8a3011448e3e35eb71134schenney@chromium.org    do {
154bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        switch (fIter.next(pts)) {
1556cae19e7539368fe697eb353d7e6197f027bc8dareed@google.com            case SkPath::kConic_Verb:
1566cae19e7539368fe697eb353d7e6197f027bc8dareed@google.com                SkASSERT(0);
1576cae19e7539368fe697eb353d7e6197f027bc8dareed@google.com                break;
158bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            case SkPath::kMove_Verb:
159ef7f0ecebfaa39e8a3b8a3011448e3e35eb71134schenney@chromium.org                ptIndex += 1;
160ef7f0ecebfaa39e8a3b8a3011448e3e35eb71134schenney@chromium.org                fPts.append(1, pts);
161bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                if (!firstMoveTo) {
162ef7f0ecebfaa39e8a3b8a3011448e3e35eb71134schenney@chromium.org                    done = true;
163ef7f0ecebfaa39e8a3b8a3011448e3e35eb71134schenney@chromium.org                    break;
164bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                }
165ef7f0ecebfaa39e8a3b8a3011448e3e35eb71134schenney@chromium.org                firstMoveTo = false;
166ef7f0ecebfaa39e8a3b8a3011448e3e35eb71134schenney@chromium.org                break;
167bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
16867b63a2f8aa3d3e6053c75e9de7f63887f5d496freed@google.com            case SkPath::kLine_Verb: {
16967b63a2f8aa3d3e6053c75e9de7f63887f5d496freed@google.com                SkScalar d = SkPoint::Distance(pts[0], pts[1]);
170bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                SkASSERT(d >= 0);
17167b63a2f8aa3d3e6053c75e9de7f63887f5d496freed@google.com                SkScalar prevD = distance;
172ef7f0ecebfaa39e8a3b8a3011448e3e35eb71134schenney@chromium.org                distance += d;
17367b63a2f8aa3d3e6053c75e9de7f63887f5d496freed@google.com                if (distance > prevD) {
17467b63a2f8aa3d3e6053c75e9de7f63887f5d496freed@google.com                    seg = fSegments.append();
17567b63a2f8aa3d3e6053c75e9de7f63887f5d496freed@google.com                    seg->fDistance = distance;
17667b63a2f8aa3d3e6053c75e9de7f63887f5d496freed@google.com                    seg->fPtIndex = ptIndex;
17767b63a2f8aa3d3e6053c75e9de7f63887f5d496freed@google.com                    seg->fType = kLine_SegType;
17867b63a2f8aa3d3e6053c75e9de7f63887f5d496freed@google.com                    seg->fTValue = kMaxTValue;
17967b63a2f8aa3d3e6053c75e9de7f63887f5d496freed@google.com                    fPts.append(1, pts + 1);
18067b63a2f8aa3d3e6053c75e9de7f63887f5d496freed@google.com                    ptIndex++;
18167b63a2f8aa3d3e6053c75e9de7f63887f5d496freed@google.com                }
18267b63a2f8aa3d3e6053c75e9de7f63887f5d496freed@google.com            } break;
183bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
18467b63a2f8aa3d3e6053c75e9de7f63887f5d496freed@google.com            case SkPath::kQuad_Verb: {
18567b63a2f8aa3d3e6053c75e9de7f63887f5d496freed@google.com                SkScalar prevD = distance;
186bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                distance = this->compute_quad_segs(pts, distance, 0,
187bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                                                   kMaxTValue, ptIndex);
18867b63a2f8aa3d3e6053c75e9de7f63887f5d496freed@google.com                if (distance > prevD) {
18967b63a2f8aa3d3e6053c75e9de7f63887f5d496freed@google.com                    fPts.append(2, pts + 1);
19067b63a2f8aa3d3e6053c75e9de7f63887f5d496freed@google.com                    ptIndex += 2;
19167b63a2f8aa3d3e6053c75e9de7f63887f5d496freed@google.com                }
19267b63a2f8aa3d3e6053c75e9de7f63887f5d496freed@google.com            } break;
193bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
19467b63a2f8aa3d3e6053c75e9de7f63887f5d496freed@google.com            case SkPath::kCubic_Verb: {
19567b63a2f8aa3d3e6053c75e9de7f63887f5d496freed@google.com                SkScalar prevD = distance;
196bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                distance = this->compute_cubic_segs(pts, distance, 0,
197bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                                                    kMaxTValue, ptIndex);
19867b63a2f8aa3d3e6053c75e9de7f63887f5d496freed@google.com                if (distance > prevD) {
19967b63a2f8aa3d3e6053c75e9de7f63887f5d496freed@google.com                    fPts.append(3, pts + 1);
20067b63a2f8aa3d3e6053c75e9de7f63887f5d496freed@google.com                    ptIndex += 3;
20167b63a2f8aa3d3e6053c75e9de7f63887f5d496freed@google.com                }
20267b63a2f8aa3d3e6053c75e9de7f63887f5d496freed@google.com            } break;
203bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
204bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            case SkPath::kClose_Verb:
205bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                isClosed = true;
206bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                break;
207935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
208bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            case SkPath::kDone_Verb:
209ef7f0ecebfaa39e8a3b8a3011448e3e35eb71134schenney@chromium.org                done = true;
210ef7f0ecebfaa39e8a3b8a3011448e3e35eb71134schenney@chromium.org                break;
211bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
212ef7f0ecebfaa39e8a3b8a3011448e3e35eb71134schenney@chromium.org    } while (!done);
213ef7f0ecebfaa39e8a3b8a3011448e3e35eb71134schenney@chromium.org
214bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fLength = distance;
215bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fIsClosed = isClosed;
216ef7f0ecebfaa39e8a3b8a3011448e3e35eb71134schenney@chromium.org    fFirstPtIndex = ptIndex;
217bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
218bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#ifdef SK_DEBUG
219bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    {
220bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        const Segment* seg = fSegments.begin();
221bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        const Segment* stop = fSegments.end();
222bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        unsigned        ptIndex = 0;
223bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkScalar        distance = 0;
224bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
225bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        while (seg < stop) {
226bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            SkASSERT(seg->fDistance > distance);
227bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            SkASSERT(seg->fPtIndex >= ptIndex);
228bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            SkASSERT(seg->fTValue > 0);
229bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
230bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            const Segment* s = seg;
231bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            while (s < stop - 1 && s[0].fPtIndex == s[1].fPtIndex) {
232bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                SkASSERT(s[0].fType == s[1].fType);
233bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                SkASSERT(s[0].fTValue < s[1].fTValue);
234bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                s += 1;
235bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            }
236bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
237bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            distance = seg->fDistance;
238bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            ptIndex = seg->fPtIndex;
239bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            seg += 1;
240bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
241bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    //  SkDebugf("\n");
242bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
243bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#endif
244bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
245bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
2466c9435ca6bbfa1cd040133867767d4bc4cfb1f1breed@google.comstatic void compute_pos_tan(const SkPoint pts[], int segType,
2476c9435ca6bbfa1cd040133867767d4bc4cfb1f1breed@google.com                            SkScalar t, SkPoint* pos, SkVector* tangent) {
248bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    switch (segType) {
249bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        case kLine_SegType:
250bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            if (pos) {
251ef7f0ecebfaa39e8a3b8a3011448e3e35eb71134schenney@chromium.org                pos->set(SkScalarInterp(pts[0].fX, pts[1].fX, t),
2526c9435ca6bbfa1cd040133867767d4bc4cfb1f1breed@google.com                         SkScalarInterp(pts[0].fY, pts[1].fY, t));
253bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            }
254bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            if (tangent) {
255ef7f0ecebfaa39e8a3b8a3011448e3e35eb71134schenney@chromium.org                tangent->setNormalize(pts[1].fX - pts[0].fX, pts[1].fY - pts[0].fY);
256bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            }
257bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            break;
258bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        case kQuad_SegType:
259bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            SkEvalQuadAt(pts, t, pos, tangent);
260bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            if (tangent) {
261bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                tangent->normalize();
262bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            }
263bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            break;
264bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        case kCubic_SegType:
265bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            SkEvalCubicAt(pts, t, pos, tangent, NULL);
266bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            if (tangent) {
267bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                tangent->normalize();
268bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            }
269bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            break;
270bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        default:
2712d7de2d243beab591671dfaf535a637b5d305735tomhudson@google.com            SkDEBUGFAIL("unknown segType");
272bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
273bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
274bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
2756c9435ca6bbfa1cd040133867767d4bc4cfb1f1breed@google.comstatic void seg_to(const SkPoint pts[], int segType,
2766c9435ca6bbfa1cd040133867767d4bc4cfb1f1breed@google.com                   SkScalar startT, SkScalar stopT, SkPath* dst) {
277bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(startT >= 0 && startT <= SK_Scalar1);
278bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(stopT >= 0 && stopT <= SK_Scalar1);
279bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(startT <= stopT);
280bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
28182d0b008b242b56745403e86bf33b459745bbb4dreed@google.com    if (startT == stopT) {
28282d0b008b242b56745403e86bf33b459745bbb4dreed@google.com        return; // should we report this, to undo a moveTo?
283bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
284bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
285bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkPoint         tmp0[7], tmp1[7];
286bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
287bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    switch (segType) {
288bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        case kLine_SegType:
28951651bf077c6f79e0d5a8cdd43468147fe5cd649reed@google.com            if (SK_Scalar1 == stopT) {
290ef7f0ecebfaa39e8a3b8a3011448e3e35eb71134schenney@chromium.org                dst->lineTo(pts[1]);
291bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            } else {
292ef7f0ecebfaa39e8a3b8a3011448e3e35eb71134schenney@chromium.org                dst->lineTo(SkScalarInterp(pts[0].fX, pts[1].fX, stopT),
293ef7f0ecebfaa39e8a3b8a3011448e3e35eb71134schenney@chromium.org                            SkScalarInterp(pts[0].fY, pts[1].fY, stopT));
294bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            }
295bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            break;
296bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        case kQuad_SegType:
29751651bf077c6f79e0d5a8cdd43468147fe5cd649reed@google.com            if (0 == startT) {
29851651bf077c6f79e0d5a8cdd43468147fe5cd649reed@google.com                if (SK_Scalar1 == stopT) {
299bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                    dst->quadTo(pts[1], pts[2]);
300bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                } else {
301bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                    SkChopQuadAt(pts, tmp0, stopT);
302bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                    dst->quadTo(tmp0[1], tmp0[2]);
303bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                }
304bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            } else {
305bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                SkChopQuadAt(pts, tmp0, startT);
30651651bf077c6f79e0d5a8cdd43468147fe5cd649reed@google.com                if (SK_Scalar1 == stopT) {
307bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                    dst->quadTo(tmp0[3], tmp0[4]);
308bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                } else {
309bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                    SkChopQuadAt(&tmp0[2], tmp1, SkScalarDiv(stopT - startT,
310bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                                                         SK_Scalar1 - startT));
311bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                    dst->quadTo(tmp1[1], tmp1[2]);
312bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                }
313bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            }
314bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            break;
315bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        case kCubic_SegType:
31651651bf077c6f79e0d5a8cdd43468147fe5cd649reed@google.com            if (0 == startT) {
31751651bf077c6f79e0d5a8cdd43468147fe5cd649reed@google.com                if (SK_Scalar1 == stopT) {
318bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                    dst->cubicTo(pts[1], pts[2], pts[3]);
319bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                } else {
320bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                    SkChopCubicAt(pts, tmp0, stopT);
321bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                    dst->cubicTo(tmp0[1], tmp0[2], tmp0[3]);
322bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                }
323bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            } else {
324bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                SkChopCubicAt(pts, tmp0, startT);
32551651bf077c6f79e0d5a8cdd43468147fe5cd649reed@google.com                if (SK_Scalar1 == stopT) {
326bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                    dst->cubicTo(tmp0[4], tmp0[5], tmp0[6]);
327bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                } else {
328bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                    SkChopCubicAt(&tmp0[3], tmp1, SkScalarDiv(stopT - startT,
329bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                                                        SK_Scalar1 - startT));
330bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                    dst->cubicTo(tmp1[1], tmp1[2], tmp1[3]);
331bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                }
332bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            }
333bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            break;
334bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        default:
3352d7de2d243beab591671dfaf535a637b5d305735tomhudson@google.com            SkDEBUGFAIL("unknown segType");
336bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            sk_throw();
337bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
338bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
339bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
340bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com////////////////////////////////////////////////////////////////////////////////
341bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com////////////////////////////////////////////////////////////////////////////////
342bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
343bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comSkPathMeasure::SkPathMeasure() {
344bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fPath = NULL;
345bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fLength = -1;   // signal we need to compute it
346bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fForceClosed = false;
347bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fFirstPtIndex = -1;
348bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
349bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
350bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comSkPathMeasure::SkPathMeasure(const SkPath& path, bool forceClosed) {
351bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fPath = &path;
352bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fLength = -1;   // signal we need to compute it
353bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fForceClosed = forceClosed;
354bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fFirstPtIndex = -1;
355bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
356bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fIter.setPath(path, forceClosed);
357bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
358bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
359bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comSkPathMeasure::~SkPathMeasure() {}
360bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
361bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com/** Assign a new path, or null to have none.
362bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com*/
363bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comvoid SkPathMeasure::setPath(const SkPath* path, bool forceClosed) {
364bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fPath = path;
365bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fLength = -1;   // signal we need to compute it
366bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fForceClosed = forceClosed;
367bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fFirstPtIndex = -1;
368bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
369bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (path) {
370bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        fIter.setPath(*path, forceClosed);
371bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
372bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fSegments.reset();
373ef7f0ecebfaa39e8a3b8a3011448e3e35eb71134schenney@chromium.org    fPts.reset();
374bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
375bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
376bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comSkScalar SkPathMeasure::getLength() {
377bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (fPath == NULL) {
378bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        return 0;
379bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
380bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (fLength < 0) {
381bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        this->buildSegments();
382bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
383bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(fLength >= 0);
384bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return fLength;
385bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
386bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
387bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comconst SkPathMeasure::Segment* SkPathMeasure::distanceToSegment(
388bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                                            SkScalar distance, SkScalar* t) {
389bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkDEBUGCODE(SkScalar length = ) this->getLength();
390bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(distance >= 0 && distance <= length);
391bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
392bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    const Segment*  seg = fSegments.begin();
393bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    int             count = fSegments.count();
394bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
395caf8693aa69b3afc94fd73059bc15417255046d0bsalomon@google.com    int index = SkTSearch<SkScalar>(&seg->fDistance, count, distance, sizeof(Segment));
396bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // don't care if we hit an exact match or not, so we xor index if it is negative
397bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    index ^= (index >> 31);
398bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    seg = &seg[index];
399bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
400bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // now interpolate t-values with the prev segment (if possible)
401bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkScalar    startT = 0, startD = 0;
402bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // check if the prev segment is legal, and references the same set of points
403bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (index > 0) {
404bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        startD = seg[-1].fDistance;
405bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if (seg[-1].fPtIndex == seg->fPtIndex) {
406bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            SkASSERT(seg[-1].fType == seg->fType);
407bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            startT = seg[-1].getScalarT();
408bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
409bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
410bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
411bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(seg->getScalarT() > startT);
412bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(distance >= startD);
413bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(seg->fDistance > startD);
414bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
415bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    *t = startT + SkScalarMulDiv(seg->getScalarT() - startT,
416bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                                 distance - startD,
417bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                                 seg->fDistance - startD);
418bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return seg;
419bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
420bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
421bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.combool SkPathMeasure::getPosTan(SkScalar distance, SkPoint* pos,
422bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                              SkVector* tangent) {
423cba822f0c18ef67566ce11f5bf1183192c29aa70djsollen@google.com    if (NULL == fPath) {
424bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        return false;
425bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
426bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
427bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkScalar    length = this->getLength(); // call this to force computing it
428bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    int         count = fSegments.count();
429bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
430bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (count == 0 || length == 0) {
431ef7f0ecebfaa39e8a3b8a3011448e3e35eb71134schenney@chromium.org        return false;
432bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
433bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
434bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // pin the distance to a legal range
435bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (distance < 0) {
436bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        distance = 0;
437bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    } else if (distance > length) {
438bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        distance = length;
439bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
440935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
441bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkScalar        t;
442bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    const Segment*  seg = this->distanceToSegment(distance, &t);
443bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
4446c9435ca6bbfa1cd040133867767d4bc4cfb1f1breed@google.com    compute_pos_tan(&fPts[seg->fPtIndex], seg->fType, t, pos, tangent);
445bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return true;
446bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
447bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
448bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.combool SkPathMeasure::getMatrix(SkScalar distance, SkMatrix* matrix,
449bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                              MatrixFlags flags) {
450cba822f0c18ef67566ce11f5bf1183192c29aa70djsollen@google.com    if (NULL == fPath) {
451cba822f0c18ef67566ce11f5bf1183192c29aa70djsollen@google.com        return false;
452cba822f0c18ef67566ce11f5bf1183192c29aa70djsollen@google.com    }
453cba822f0c18ef67566ce11f5bf1183192c29aa70djsollen@google.com
454bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkPoint     position;
455bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkVector    tangent;
456bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
457bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (this->getPosTan(distance, &position, &tangent)) {
458bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if (matrix) {
459bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            if (flags & kGetTangent_MatrixFlag) {
460bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                matrix->setSinCos(tangent.fY, tangent.fX, 0, 0);
461bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            } else {
462bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                matrix->reset();
463bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            }
464bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            if (flags & kGetPosition_MatrixFlag) {
465bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                matrix->postTranslate(position.fX, position.fY);
466bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            }
467bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
468bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        return true;
469bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
470bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return false;
471bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
472bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
473bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.combool SkPathMeasure::getSegment(SkScalar startD, SkScalar stopD, SkPath* dst,
474bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                               bool startWithMoveTo) {
475bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(dst);
476bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
477bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkScalar length = this->getLength();    // ensure we have built our segments
478bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
479bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (startD < 0) {
480bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        startD = 0;
481bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
482bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (stopD > length) {
483bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        stopD = length;
484bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
485bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (startD >= stopD) {
486bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        return false;
487bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
488bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
489bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkPoint  p;
490bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkScalar startT, stopT;
491bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    const Segment* seg = this->distanceToSegment(startD, &startT);
492bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    const Segment* stopSeg = this->distanceToSegment(stopD, &stopT);
493bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(seg <= stopSeg);
494bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
495bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (startWithMoveTo) {
4966c9435ca6bbfa1cd040133867767d4bc4cfb1f1breed@google.com        compute_pos_tan(&fPts[seg->fPtIndex], seg->fType, startT, &p, NULL);
497bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        dst->moveTo(p);
498bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
499bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
500bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (seg->fPtIndex == stopSeg->fPtIndex) {
5016c9435ca6bbfa1cd040133867767d4bc4cfb1f1breed@google.com        seg_to(&fPts[seg->fPtIndex], seg->fType, startT, stopT, dst);
502bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    } else {
503bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        do {
5046c9435ca6bbfa1cd040133867767d4bc4cfb1f1breed@google.com            seg_to(&fPts[seg->fPtIndex], seg->fType, startT, SK_Scalar1, dst);
505bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            seg = SkPathMeasure::NextSegment(seg);
506bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            startT = 0;
507bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        } while (seg->fPtIndex < stopSeg->fPtIndex);
5086c9435ca6bbfa1cd040133867767d4bc4cfb1f1breed@google.com        seg_to(&fPts[seg->fPtIndex], seg->fType, 0, stopT, dst);
509bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
510bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return true;
511bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
512bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
513bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.combool SkPathMeasure::isClosed() {
514bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    (void)this->getLength();
515bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return fIsClosed;
516bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
517bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
518bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com/** Move to the next contour in the path. Return true if one exists, or false if
519bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    we're done with the path.
520bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com*/
521bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.combool SkPathMeasure::nextContour() {
522bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fLength = -1;
523bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return this->getLength() > 0;
524bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
525bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
526bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com///////////////////////////////////////////////////////////////////////////////
527bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com///////////////////////////////////////////////////////////////////////////////
528bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
529bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#ifdef SK_DEBUG
530bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
531bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comvoid SkPathMeasure::dump() {
532bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkDebugf("pathmeas: length=%g, segs=%d\n", fLength, fSegments.count());
533bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
534bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    for (int i = 0; i < fSegments.count(); i++) {
535bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        const Segment* seg = &fSegments[i];
536bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkDebugf("pathmeas: seg[%d] distance=%g, point=%d, t=%g, type=%d\n",
537bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                i, seg->fDistance, seg->fPtIndex, seg->getScalarT(),
538bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                 seg->fType);
539bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
540bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
541bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
542bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#endif
543