SkPathMeasure.cpp revision 0910916c0f7b951ee55c4b7c6358295b9bca0565
10910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project/*
20910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * Copyright (C) 2006-2008 The Android Open Source Project
30910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *
40910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
50910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * you may not use this file except in compliance with the License.
60910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * You may obtain a copy of the License at
70910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *
80910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
90910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *
100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * See the License for the specific language governing permissions and
140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * limitations under the License.
150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project */
160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkPathMeasure.h"
180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkGeometry.h"
190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkPath.h"
200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkTSearch.h"
210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project// these must be 0,1,2 since they are in our 2-bit field
230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectenum {
240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    kLine_SegType,
250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    kCloseLine_SegType,
260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    kQuad_SegType,
270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    kCubic_SegType
280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project};
290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#define kMaxTValue  32767
310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic inline SkScalar tValue2Scalar(int t) {
330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT((unsigned)t <= kMaxTValue);
340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#ifdef SK_SCALAR_IS_FLOAT
360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return t * 3.05185e-5f; // t / 32767
370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#else
380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return (t + (t >> 14)) << 1;
390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectSkScalar SkPathMeasure::Segment::getScalarT() const {
430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return tValue2Scalar(fTValue);
440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectconst SkPathMeasure::Segment* SkPathMeasure::NextSegment(const Segment* seg) {
470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    unsigned ptIndex = seg->fPtIndex;
480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    do {
500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        ++seg;
510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    } while (seg->fPtIndex == ptIndex);
520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return seg;
530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic inline int tspan_big_enough(int tspan) {
580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT((unsigned)tspan <= kMaxTValue);
590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return tspan >> 10;
600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#if 0
630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic inline bool tangents_too_curvy(const SkVector& tan0, SkVector& tan1) {
640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    static const SkScalar kFlatEnoughTangentDotProd = SK_Scalar1 * 99 / 100;
650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(kFlatEnoughTangentDotProd > 0 &&
670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project             kFlatEnoughTangentDotProd < SK_Scalar1);
680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return SkPoint::DotProduct(tan0, tan1) < kFlatEnoughTangentDotProd;
700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project// can't use tangents, since we need [0..1..................2] to be seen
740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project// as definitely not a line (it is when drawn, but not parametrically)
750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project// so we compare midpoints
760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#define CHEAP_DIST_LIMIT    (SK_Scalar1/2)  // just made this value up
770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic bool quad_too_curvy(const SkPoint pts[3]) {
790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // diff = (a/4 + b/2 + c/4) - (a/2 + c/2)
800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // diff = -a/4 + b/2 - c/4
810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar dx = SkScalarHalf(pts[1].fX) -
820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                        SkScalarHalf(SkScalarHalf(pts[0].fX + pts[2].fX));
830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar dy = SkScalarHalf(pts[1].fY) -
840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                        SkScalarHalf(SkScalarHalf(pts[0].fY + pts[2].fY));
850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar dist = SkMaxScalar(SkScalarAbs(dx), SkScalarAbs(dy));
870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return dist > CHEAP_DIST_LIMIT;
880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic bool cheap_dist_exceeds_limit(const SkPoint& pt,
910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                     SkScalar x, SkScalar y) {
920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar dist = SkMaxScalar(SkScalarAbs(x - pt.fX), SkScalarAbs(y - pt.fY));
930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // just made up the 1/2
940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return dist > CHEAP_DIST_LIMIT;
950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic bool cubic_too_curvy(const SkPoint pts[4]) {
980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return  cheap_dist_exceeds_limit(pts[1],
990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                         SkScalarInterp(pts[0].fX, pts[3].fX, SK_Scalar1/3),
1000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                         SkScalarInterp(pts[0].fY, pts[3].fY, SK_Scalar1/3))
1010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                         ||
1020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            cheap_dist_exceeds_limit(pts[2],
1030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                         SkScalarInterp(pts[0].fX, pts[3].fX, SK_Scalar1*2/3),
1040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                         SkScalarInterp(pts[0].fY, pts[3].fY, SK_Scalar1*2/3));
1050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectSkScalar SkPathMeasure::compute_quad_segs(const SkPoint pts[3],
1080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                          SkScalar distance, int mint, int maxt, int ptIndex) {
1090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (tspan_big_enough(maxt - mint) && quad_too_curvy(pts)) {
1100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkPoint tmp[5];
1110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        int     halft = (mint + maxt) >> 1;
1120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkChopQuadAtHalf(pts, tmp);
1140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        distance = this->compute_quad_segs(tmp, distance, mint, halft, ptIndex);
1150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        distance = this->compute_quad_segs(&tmp[2], distance, halft, maxt, ptIndex);
1160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    } else {
1170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkScalar d = SkPoint::Distance(pts[0], pts[2]);
1180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkASSERT(d >= 0);
1190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (!SkScalarNearlyZero(d)) {
1200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            distance += d;
1210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            Segment* seg = fSegments.append();
1220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            seg->fDistance = distance;
1230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            seg->fPtIndex = ptIndex;
1240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            seg->fType = kQuad_SegType;
1250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            seg->fTValue = maxt;
1260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
1270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return distance;
1290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectSkScalar SkPathMeasure::compute_cubic_segs(const SkPoint pts[4],
1320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                           SkScalar distance, int mint, int maxt, int ptIndex) {
1330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (tspan_big_enough(maxt - mint) && cubic_too_curvy(pts)) {
1340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkPoint tmp[7];
1350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        int     halft = (mint + maxt) >> 1;
1360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkChopCubicAtHalf(pts, tmp);
1380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        distance = this->compute_cubic_segs(tmp, distance, mint, halft, ptIndex);
1390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        distance = this->compute_cubic_segs(&tmp[3], distance, halft, maxt, ptIndex);
1400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    } else {
1410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkScalar d = SkPoint::Distance(pts[0], pts[3]);
1420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkASSERT(d >= 0);
1430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (!SkScalarNearlyZero(d)) {
1440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            distance += d;
1450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            Segment* seg = fSegments.append();
1460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            seg->fDistance = distance;
1470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            seg->fPtIndex = ptIndex;
1480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            seg->fType = kCubic_SegType;
1490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            seg->fTValue = maxt;
1500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
1510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return distance;
1530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPathMeasure::buildSegments() {
1560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPoint         pts[4];
1570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int             ptIndex = fFirstPtIndex;
1580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar        d, distance = 0;
1590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    bool            isClosed = fForceClosed;
1600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    bool            firstMoveTo = ptIndex < 0;
1610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    Segment*        seg;
1620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fSegments.reset();
1640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    for (;;) {
1650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        switch (fIter.next(pts)) {
1660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            case SkPath::kMove_Verb:
1670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                if (!firstMoveTo) {
1680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    goto DONE;
1690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                }
1700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            ptIndex += 1;
1710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            firstMoveTo = false;
1720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            break;
1730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            case SkPath::kLine_Verb:
1750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                d = SkPoint::Distance(pts[0], pts[1]);
1760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                SkASSERT(d >= 0);
1770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                if (!SkScalarNearlyZero(d)) {
1780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    distance += d;
1790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    seg = fSegments.append();
1800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    seg->fDistance = distance;
1810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    seg->fPtIndex = ptIndex;
1820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    seg->fType = fIter.isCloseLine() ?
1830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                    kCloseLine_SegType : kLine_SegType;
1840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    seg->fTValue = kMaxTValue;
1850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                }
1860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                ptIndex += !fIter.isCloseLine();
1870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                break;
1880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            case SkPath::kQuad_Verb:
1900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                distance = this->compute_quad_segs(pts, distance, 0,
1910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                                   kMaxTValue, ptIndex);
1920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                ptIndex += 2;
1930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                break;
1940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            case SkPath::kCubic_Verb:
1960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                distance = this->compute_cubic_segs(pts, distance, 0,
1970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                                    kMaxTValue, ptIndex);
1980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                ptIndex += 3;
1990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                break;
2000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            case SkPath::kClose_Verb:
2020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                isClosed = true;
2030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                break;
2040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            case SkPath::kDone_Verb:
2060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                goto DONE;
2070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
2080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
2090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectDONE:
2100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fLength = distance;
2110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fIsClosed = isClosed;
2120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fFirstPtIndex = ptIndex + 1;
2130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#ifdef SK_DEBUG
2150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    {
2160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        const Segment* seg = fSegments.begin();
2170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        const Segment* stop = fSegments.end();
2180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        unsigned        ptIndex = 0;
2190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkScalar        distance = 0;
2200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        while (seg < stop) {
2220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkASSERT(seg->fDistance > distance);
2230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkASSERT(seg->fPtIndex >= ptIndex);
2240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkASSERT(seg->fTValue > 0);
2250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            const Segment* s = seg;
2270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            while (s < stop - 1 && s[0].fPtIndex == s[1].fPtIndex) {
2280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                SkASSERT(s[0].fType == s[1].fType);
2290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                SkASSERT(s[0].fTValue < s[1].fTValue);
2300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                s += 1;
2310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
2320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            distance = seg->fDistance;
2340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            ptIndex = seg->fPtIndex;
2350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            seg += 1;
2360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
2370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //  SkDebugf("\n");
2380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
2390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
2400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
2410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project// marked as a friend in SkPath.h
2430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectconst SkPoint* sk_get_path_points(const SkPath& path, int index) {
2440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return &path.fPts[index];
2450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
2460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void compute_pos_tan(const SkPath& path, int firstPtIndex, int ptIndex,
2480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    int segType, SkScalar t, SkPoint* pos, SkVector* tangent) {
2490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const SkPoint*  pts = sk_get_path_points(path, ptIndex);
2500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    switch (segType) {
2520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case kLine_SegType:
2530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case kCloseLine_SegType: {
2540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            const SkPoint* endp = (segType == kLine_SegType) ?
2550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                    &pts[1] :
2560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                    sk_get_path_points(path, firstPtIndex);
2570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (pos) {
2590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                pos->set(SkScalarInterp(pts[0].fX, endp->fX, t),
2600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                        SkScalarInterp(pts[0].fY, endp->fY, t));
2610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
2620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (tangent) {
2630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                tangent->setNormalize(endp->fX - pts[0].fX, endp->fY - pts[0].fY);
2640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
2650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            break;
2660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
2670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case kQuad_SegType:
2680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkEvalQuadAt(pts, t, pos, tangent);
2690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (tangent) {
2700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                tangent->normalize();
2710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
2720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            break;
2730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case kCubic_SegType:
2740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkEvalCubicAt(pts, t, pos, tangent, NULL);
2750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (tangent) {
2760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                tangent->normalize();
2770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
2780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            break;
2790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        default:
2800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkASSERT(!"unknown segType");
2810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
2820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
2830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void seg_to(const SkPath& src, int firstPtIndex, int ptIndex,
2850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                   int segType, SkScalar startT, SkScalar stopT, SkPath* dst) {
2860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(startT >= 0 && startT <= SK_Scalar1);
2870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(stopT >= 0 && stopT <= SK_Scalar1);
2880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(startT <= stopT);
2890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (SkScalarNearlyZero(stopT - startT)) {
2910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return;
2920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
2930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const SkPoint*  pts = sk_get_path_points(src, ptIndex);
2950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPoint         tmp0[7], tmp1[7];
2960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    switch (segType) {
2980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case kLine_SegType:
2990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case kCloseLine_SegType: {
3000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            const SkPoint* endp = (segType == kLine_SegType) ?
3010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                    &pts[1] :
3020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                    sk_get_path_points(src, firstPtIndex);
3030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (stopT == kMaxTValue) {
3050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                dst->lineTo(*endp);
3060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            } else {
3070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                dst->lineTo(SkScalarInterp(pts[0].fX, endp->fX, stopT),
3080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                            SkScalarInterp(pts[0].fY, endp->fY, stopT));
3090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
3100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            break;
3110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
3120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case kQuad_SegType:
3130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (startT == 0) {
3140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                if (stopT == SK_Scalar1) {
3150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    dst->quadTo(pts[1], pts[2]);
3160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                } else {
3170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    SkChopQuadAt(pts, tmp0, stopT);
3180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    dst->quadTo(tmp0[1], tmp0[2]);
3190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                }
3200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            } else {
3210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                SkChopQuadAt(pts, tmp0, startT);
3220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                if (stopT == SK_Scalar1) {
3230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    dst->quadTo(tmp0[3], tmp0[4]);
3240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                } else {
3250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    SkChopQuadAt(&tmp0[2], tmp1, SkScalarDiv(stopT - startT,
3260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                                         SK_Scalar1 - startT));
3270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    dst->quadTo(tmp1[1], tmp1[2]);
3280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                }
3290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
3300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            break;
3310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case kCubic_SegType:
3320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (startT == 0) {
3330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                if (stopT == SK_Scalar1) {
3340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    dst->cubicTo(pts[1], pts[2], pts[3]);
3350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                } else {
3360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    SkChopCubicAt(pts, tmp0, stopT);
3370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    dst->cubicTo(tmp0[1], tmp0[2], tmp0[3]);
3380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                }
3390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            } else {
3400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                SkChopCubicAt(pts, tmp0, startT);
3410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                if (stopT == SK_Scalar1) {
3420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    dst->cubicTo(tmp0[4], tmp0[5], tmp0[6]);
3430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                } else {
3440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    SkChopCubicAt(&tmp0[3], tmp1, SkScalarDiv(stopT - startT,
3450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                                        SK_Scalar1 - startT));
3460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    dst->cubicTo(tmp1[1], tmp1[2], tmp1[3]);
3470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                }
3480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
3490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            break;
3500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        default:
3510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkASSERT(!"unknown segType");
3520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            sk_throw();
3530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
3540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
3550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project////////////////////////////////////////////////////////////////////////////////
3570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project////////////////////////////////////////////////////////////////////////////////
3580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectSkPathMeasure::SkPathMeasure() {
3600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fPath = NULL;
3610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fLength = -1;   // signal we need to compute it
3620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fForceClosed = false;
3630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fFirstPtIndex = -1;
3640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
3650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectSkPathMeasure::SkPathMeasure(const SkPath& path, bool forceClosed) {
3670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fPath = &path;
3680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fLength = -1;   // signal we need to compute it
3690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fForceClosed = forceClosed;
3700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fFirstPtIndex = -1;
3710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fIter.setPath(path, forceClosed);
3730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
3740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectSkPathMeasure::~SkPathMeasure() {}
3760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project/** Assign a new path, or null to have none.
3780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project*/
3790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPathMeasure::setPath(const SkPath* path, bool forceClosed) {
3800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fPath = path;
3810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fLength = -1;   // signal we need to compute it
3820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fForceClosed = forceClosed;
3830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fFirstPtIndex = -1;
3840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (path) {
3860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fIter.setPath(*path, forceClosed);
3870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
3880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fSegments.reset();
3890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
3900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectSkScalar SkPathMeasure::getLength() {
3920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (fPath == NULL) {
3930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return 0;
3940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
3950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (fLength < 0) {
3960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->buildSegments();
3970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
3980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(fLength >= 0);
3990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return fLength;
4000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
4010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectconst SkPathMeasure::Segment* SkPathMeasure::distanceToSegment(
4030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                            SkScalar distance, SkScalar* t) {
4040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkDEBUGCODE(SkScalar length = ) this->getLength();
4050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(distance >= 0 && distance <= length);
4060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const Segment*  seg = fSegments.begin();
4080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int             count = fSegments.count();
4090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int index = SkTSearch<SkScalar>(&seg->fDistance, count, distance,
4110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                    sizeof(Segment));
4120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // don't care if we hit an exact match or not, so we xor index if it is negative
4130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    index ^= (index >> 31);
4140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    seg = &seg[index];
4150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // now interpolate t-values with the prev segment (if possible)
4170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar    startT = 0, startD = 0;
4180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // check if the prev segment is legal, and references the same set of points
4190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (index > 0) {
4200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        startD = seg[-1].fDistance;
4210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (seg[-1].fPtIndex == seg->fPtIndex) {
4220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkASSERT(seg[-1].fType == seg->fType);
4230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            startT = seg[-1].getScalarT();
4240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
4250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
4260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(seg->getScalarT() > startT);
4280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(distance >= startD);
4290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(seg->fDistance > startD);
4300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    *t = startT + SkScalarMulDiv(seg->getScalarT() - startT,
4320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                 distance - startD,
4330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                 seg->fDistance - startD);
4340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return seg;
4350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
4360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectbool SkPathMeasure::getPosTan(SkScalar distance, SkPoint* pos,
4380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                              SkVector* tangent) {
4390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(fPath);
4400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (fPath == NULL) {
4410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    EMPTY:
4420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return false;
4430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
4440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar    length = this->getLength(); // call this to force computing it
4460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int         count = fSegments.count();
4470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (count == 0 || length == 0) {
4490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        goto EMPTY;
4500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
4510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // pin the distance to a legal range
4530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (distance < 0) {
4540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        distance = 0;
4550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    } else if (distance > length) {
4560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        distance = length;
4570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
4580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar        t;
4600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const Segment*  seg = this->distanceToSegment(distance, &t);
4610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    compute_pos_tan(*fPath, fSegments[0].fPtIndex, seg->fPtIndex, seg->fType,
4630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    t, pos, tangent);
4640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return true;
4650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
4660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectbool SkPathMeasure::getMatrix(SkScalar distance, SkMatrix* matrix,
4680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                              MatrixFlags flags) {
4690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPoint     position;
4700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkVector    tangent;
4710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (this->getPosTan(distance, &position, &tangent)) {
4730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (matrix) {
4740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (flags & kGetTangent_MatrixFlag) {
4750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                matrix->setSinCos(tangent.fY, tangent.fX, 0, 0);
4760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            } else {
4770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                matrix->reset();
4780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
4790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (flags & kGetPosition_MatrixFlag) {
4800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                matrix->postTranslate(position.fX, position.fY);
4810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
4820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
4830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return true;
4840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
4850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return false;
4860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
4870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectbool SkPathMeasure::getSegment(SkScalar startD, SkScalar stopD, SkPath* dst,
4890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                               bool startWithMoveTo) {
4900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(dst);
4910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar length = this->getLength();    // ensure we have built our segments
4930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (startD < 0) {
4950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        startD = 0;
4960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
4970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (stopD > length) {
4980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        stopD = length;
4990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
5000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (startD >= stopD) {
5010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return false;
5020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
5030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPoint  p;
5050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar startT, stopT;
5060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const Segment* seg = this->distanceToSegment(startD, &startT);
5070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const Segment* stopSeg = this->distanceToSegment(stopD, &stopT);
5080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(seg <= stopSeg);
5090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (startWithMoveTo) {
5110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        compute_pos_tan(*fPath, fSegments[0].fPtIndex, seg->fPtIndex,
5120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                        seg->fType, startT, &p, NULL);
5130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        dst->moveTo(p);
5140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
5150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (seg->fPtIndex == stopSeg->fPtIndex) {
5170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        seg_to(*fPath, fSegments[0].fPtIndex, seg->fPtIndex, seg->fType,
5180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project               startT, stopT, dst);
5190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    } else {
5200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        do {
5210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            seg_to(*fPath, fSegments[0].fPtIndex, seg->fPtIndex, seg->fType,
5220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                   startT, SK_Scalar1, dst);
5230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            seg = SkPathMeasure::NextSegment(seg);
5240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            startT = 0;
5250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        } while (seg->fPtIndex < stopSeg->fPtIndex);
5260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        seg_to(*fPath, fSegments[0].fPtIndex, seg->fPtIndex, seg->fType,
5270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project               0, stopT, dst);
5280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
5290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return true;
5300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
5310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectbool SkPathMeasure::isClosed() {
5330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    (void)this->getLength();
5340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return fIsClosed;
5350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
5360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project/** Move to the next contour in the path. Return true if one exists, or false if
5380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    we're done with the path.
5390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project*/
5400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectbool SkPathMeasure::nextContour() {
5410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fLength = -1;
5420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return this->getLength() > 0;
5430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
5440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
5460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
5470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#ifdef SK_DEBUG
5490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPathMeasure::dump() {
5510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkDebugf("pathmeas: length=%g, segs=%d\n", fLength, fSegments.count());
5520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    for (int i = 0; i < fSegments.count(); i++) {
5540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        const Segment* seg = &fSegments[i];
5550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkDebugf("pathmeas: seg[%d] distance=%g, point=%d, t=%g, type=%d\n",
5560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                i, seg->fDistance, seg->fPtIndex, seg->getScalarT(),
5570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                 seg->fType);
5580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
5590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
5600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPathMeasure::UnitTest() {
5620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#ifdef SK_SUPPORT_UNITTEST
5630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPath  path;
5640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    path.moveTo(0, 0);
5660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    path.lineTo(SK_Scalar1, 0);
5670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    path.lineTo(SK_Scalar1, SK_Scalar1);
5680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    path.lineTo(0, SK_Scalar1);
5690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPathMeasure   meas(path, true);
5710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar        length = meas.getLength();
5720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(length == SK_Scalar1*4);
5730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    path.reset();
5750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    path.moveTo(0, 0);
5760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    path.lineTo(SK_Scalar1*3, SK_Scalar1*4);
5770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    meas.setPath(&path, false);
5780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    length = meas.getLength();
5790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(length == SK_Scalar1*5);
5800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    path.reset();
5820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    path.addCircle(0, 0, SK_Scalar1);
5830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    meas.setPath(&path, true);
5840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    length = meas.getLength();
5850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkDebugf("circle arc-length = %g\n", length);
5860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    for (int i = 0; i < 8; i++) {
5880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkScalar    d = length * i / 8;
5890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkPoint     p;
5900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkVector    v;
5910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        meas.getPosTan(d, &p, &v);
5920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkDebugf("circle arc-length=%g, pos[%g %g] tan[%g %g]\n",
5930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                 d, p.fX, p.fY, v.fX, v.fY);
5940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
5950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
5960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
5970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
599