11cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
21cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger/*
31cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger * Copyright 2006 The Android Open Source Project
41cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger *
51cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger * Use of this source code is governed by a BSD-style license that can be
61cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger * found in the LICENSE file.
71cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger */
81cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
90910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkPath.h"
1135e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger#include "SkReader32.h"
1235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger#include "SkWriter32.h"
130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkMath.h"
140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project////////////////////////////////////////////////////////////////////////////
160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
171cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger/**
181cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger *  Path.bounds is defined to be the bounds of all the control points.
191cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger *  If we called bounds.join(r) we would skip r if r was empty, which breaks
201cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger *  our promise. Hence we have a custom joiner that doesn't look at emptiness
211cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger */
221cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergerstatic void joinNoEmptyChecks(SkRect* dst, const SkRect& src) {
231cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    dst->fLeft = SkMinScalar(dst->fLeft, src.fLeft);
241cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    dst->fTop = SkMinScalar(dst->fTop, src.fTop);
251cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    dst->fRight = SkMaxScalar(dst->fRight, src.fRight);
261cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    dst->fBottom = SkMaxScalar(dst->fBottom, src.fBottom);
271cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
281cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
294f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenbergerstatic bool is_degenerate(const SkPath& path) {
304f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    SkPath::Iter iter(path, false);
314f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    SkPoint pts[4];
324f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    return SkPath::kDone_Verb == iter.next(pts);
334f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger}
344f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger
350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project/*  This guy's constructor/destructor bracket a path editing operation. It is
360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    used when we know the bounds of the amount we are going to add to the path
370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    (usually a new contour, but not required).
3840528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    It captures some state about the path up front (i.e. if it already has a
400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    cached bounds), and the if it can, it updates the cache bounds explicitly,
410e747d6d0a794242bd214fa44a6a179baeadfdf9Mike Reed    avoiding the need to revisit all of the points in getBounds().
4240528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
434f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    It also notes if the path was originally degenerate, and if so, sets
444f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    isConvex to true. Thus it can only be used if the contour being added is
454f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    convex.
460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project */
470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectclass SkAutoPathBoundsUpdate {
480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectpublic:
490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkAutoPathBoundsUpdate(SkPath* path, const SkRect& r) : fRect(r) {
500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->init(path);
510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkAutoPathBoundsUpdate(SkPath* path, SkScalar left, SkScalar top,
540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                           SkScalar right, SkScalar bottom) {
550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fRect.set(left, top, right, bottom);
560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->init(path);
570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
5840528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    ~SkAutoPathBoundsUpdate() {
604f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        fPath->setIsConvex(fDegenerate);
610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (fEmpty) {
620e747d6d0a794242bd214fa44a6a179baeadfdf9Mike Reed            fPath->fBounds = fRect;
630e747d6d0a794242bd214fa44a6a179baeadfdf9Mike Reed            fPath->fBoundsIsDirty = false;
640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        } else if (!fDirty) {
651cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            joinNoEmptyChecks(&fPath->fBounds, fRect);
660e747d6d0a794242bd214fa44a6a179baeadfdf9Mike Reed            fPath->fBoundsIsDirty = false;
670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
6940528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectprivate:
7179377cbceeea970b663e7934d7cb1f27bb223d98Mike Reed    SkPath* fPath;
7279377cbceeea970b663e7934d7cb1f27bb223d98Mike Reed    SkRect  fRect;
7379377cbceeea970b663e7934d7cb1f27bb223d98Mike Reed    bool    fDirty;
744f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    bool    fDegenerate;
7579377cbceeea970b663e7934d7cb1f27bb223d98Mike Reed    bool    fEmpty;
7640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // returns true if we should proceed
7879377cbceeea970b663e7934d7cb1f27bb223d98Mike Reed    void init(SkPath* path) {
790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fPath = path;
802c497e64d20a73267eb92ae88fdc51ba2a356b55Mike Reed        fDirty = SkToBool(path->fBoundsIsDirty);
814f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        fDegenerate = is_degenerate(*path);
820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fEmpty = path->isEmpty();
83aa4832adcc7eba085987357591bcfeb530ba7b0dMike Reed        // Cannot use fRect for our bounds unless we know it is sorted
84aa4832adcc7eba085987357591bcfeb530ba7b0dMike Reed        fRect.sort();
850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project};
870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
880e747d6d0a794242bd214fa44a6a179baeadfdf9Mike Reedstatic void compute_pt_bounds(SkRect* bounds, const SkTDArray<SkPoint>& pts) {
890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (pts.count() <= 1) {  // we ignore just 1 point (moveto)
900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        bounds->set(0, 0, 0, 0);
910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    } else {
920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        bounds->set(pts.begin(), pts.count());
930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project//        SkDebugf("------- compute bounds %p %d", &pts, pts.count());
940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project////////////////////////////////////////////////////////////////////////////
980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project/*
1000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    Stores the verbs and points as they are given to us, with exceptions:
1011cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    - we only record "Close" if it was immediately preceeded by Move | Line | Quad | Cubic
1020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    - we insert a Move(0,0) if Line | Quad | Cubic is our first command
1030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    The iterator does more cleanup, especially if forceClose == true
1051cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    1. If we encounter degenerate segments, remove them
1061cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    2. if we encounter Close, return a cons'd up Line() first (if the curr-pt != start-pt)
1071cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    3. if we encounter Move without a preceeding Close, and forceClose is true, goto #2
1081cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    4. if we encounter Line | Quad | Cubic after Close, cons up a Move
1090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project*/
1100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project////////////////////////////////////////////////////////////////////////////
1120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1134f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger// flag to require a moveTo if we begin with something else, like lineTo etc.
1144f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger#define INITIAL_LASTMOVETOINDEX_VALUE   ~0
1154f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger
1161cab2921ab279367f8206cdadc9259d12e603548Derek SollenbergerSkPath::SkPath()
1171cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    : fFillType(kWinding_FillType)
1181cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    , fBoundsIsDirty(true) {
11935e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    fConvexity = kUnknown_Convexity;
1201cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    fSegmentMask = 0;
1214f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    fLastMoveToIndex = INITIAL_LASTMOVETOINDEX_VALUE;
1221cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger#ifdef SK_BUILD_FOR_ANDROID
123fad89e5c108c0cf674a206cd133da011465ccd09Romain Guy    fGenerationID = 0;
1244f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    fSourcePath = NULL;
12587b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenberger#endif
12679377cbceeea970b663e7934d7cb1f27bb223d98Mike Reed}
1270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectSkPath::SkPath(const SkPath& src) {
1290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkDEBUGCODE(src.validate();)
1300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    *this = src;
1311cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger#ifdef SK_BUILD_FOR_ANDROID
13287b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenberger    // the assignment operator above increments the ID so correct for that here
1334f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    fGenerationID = src.fGenerationID;
1344f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    fSourcePath = NULL;
13587b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenberger#endif
1360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectSkPath::~SkPath() {
1390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkDEBUGCODE(this->validate();)
1400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectSkPath& SkPath::operator=(const SkPath& src) {
1430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkDEBUGCODE(src.validate();)
1440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (this != &src) {
1460e747d6d0a794242bd214fa44a6a179baeadfdf9Mike Reed        fBounds         = src.fBounds;
1470e747d6d0a794242bd214fa44a6a179baeadfdf9Mike Reed        fPts            = src.fPts;
1480e747d6d0a794242bd214fa44a6a179baeadfdf9Mike Reed        fVerbs          = src.fVerbs;
1490e747d6d0a794242bd214fa44a6a179baeadfdf9Mike Reed        fFillType       = src.fFillType;
1500e747d6d0a794242bd214fa44a6a179baeadfdf9Mike Reed        fBoundsIsDirty  = src.fBoundsIsDirty;
15135e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        fConvexity      = src.fConvexity;
1521cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        fSegmentMask    = src.fSegmentMask;
1534f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        fLastMoveToIndex = src.fLastMoveToIndex;
15487b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenberger        GEN_ID_INC;
1550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkDEBUGCODE(this->validate();)
1570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return *this;
1580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1603298d565d8a70b84f28b455f6289293883c85494The Android Open Source Projectbool operator==(const SkPath& a, const SkPath& b) {
16179377cbceeea970b663e7934d7cb1f27bb223d98Mike Reed    // note: don't need to look at isConvex or bounds, since just comparing the
16279377cbceeea970b663e7934d7cb1f27bb223d98Mike Reed    // raw data is sufficient.
1631cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
1641cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    // We explicitly check fSegmentMask as a quick-reject. We could skip it,
1651cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    // since it is only a cache of info in the fVerbs, but its a fast way to
1661cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    // notice a difference
1671cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
1683298d565d8a70b84f28b455f6289293883c85494The Android Open Source Project    return &a == &b ||
1691cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        (a.fFillType == b.fFillType && a.fSegmentMask == b.fSegmentMask &&
1701cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger         a.fVerbs == b.fVerbs && a.fPts == b.fPts);
1713298d565d8a70b84f28b455f6289293883c85494The Android Open Source Project}
1723298d565d8a70b84f28b455f6289293883c85494The Android Open Source Project
1730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPath::swap(SkPath& other) {
1740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(&other != NULL);
1750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (this != &other) {
1770e747d6d0a794242bd214fa44a6a179baeadfdf9Mike Reed        SkTSwap<SkRect>(fBounds, other.fBounds);
1780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fPts.swap(other.fPts);
1790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fVerbs.swap(other.fVerbs);
1800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkTSwap<uint8_t>(fFillType, other.fFillType);
1810e747d6d0a794242bd214fa44a6a179baeadfdf9Mike Reed        SkTSwap<uint8_t>(fBoundsIsDirty, other.fBoundsIsDirty);
18235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        SkTSwap<uint8_t>(fConvexity, other.fConvexity);
1831cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkTSwap<uint8_t>(fSegmentMask, other.fSegmentMask);
1844f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        SkTSwap<int>(fLastMoveToIndex, other.fLastMoveToIndex);
18587b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenberger        GEN_ID_INC;
1860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1891cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger#ifdef SK_BUILD_FOR_ANDROID
190fad89e5c108c0cf674a206cd133da011465ccd09Romain Guyuint32_t SkPath::getGenerationID() const {
191fad89e5c108c0cf674a206cd133da011465ccd09Romain Guy    return fGenerationID;
192fad89e5c108c0cf674a206cd133da011465ccd09Romain Guy}
1934f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger
1944f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenbergerconst SkPath* SkPath::getSourcePath() const {
1954f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    return fSourcePath;
1964f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger}
1974f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger
1984f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenbergervoid SkPath::setSourcePath(const SkPath* path) {
1994f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    fSourcePath = path;
2004f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger}
20187b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenberger#endif
202fad89e5c108c0cf674a206cd133da011465ccd09Romain Guy
2030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPath::reset() {
2040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkDEBUGCODE(this->validate();)
2050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fPts.reset();
2070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fVerbs.reset();
20887b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenberger    GEN_ID_INC;
2090e747d6d0a794242bd214fa44a6a179baeadfdf9Mike Reed    fBoundsIsDirty = true;
21035e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    fConvexity = kUnknown_Convexity;
2111cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    fSegmentMask = 0;
2124f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    fLastMoveToIndex = INITIAL_LASTMOVETOINDEX_VALUE;
2130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
2140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPath::rewind() {
2160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkDEBUGCODE(this->validate();)
2170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fPts.rewind();
2190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fVerbs.rewind();
22087b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenberger    GEN_ID_INC;
22135e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    fConvexity = kUnknown_Convexity;
2221cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    fBoundsIsDirty = true;
2231cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    fSegmentMask = 0;
2244f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    fLastMoveToIndex = INITIAL_LASTMOVETOINDEX_VALUE;
2250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
2260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectbool SkPath::isEmpty() const {
2280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkDEBUGCODE(this->validate();)
2291cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    return 0 == fVerbs.count();
2300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
2310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2321cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger/*
2331cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger Determines if path is a rect by keeping track of changes in direction
2341cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger and looking for a loop either clockwise or counterclockwise.
2351cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
2361cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger The direction is computed such that:
2371cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger  0: vertical up
2381cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger  1: horizontal right
2391cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger  2: vertical down
2401cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger  3: horizontal left
2411cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
2421cab2921ab279367f8206cdadc9259d12e603548Derek SollenbergerA rectangle cycles up/right/down/left or up/left/down/right.
2431cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
2441cab2921ab279367f8206cdadc9259d12e603548Derek SollenbergerThe test fails if:
2451cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger  The path is closed, and followed by a line.
2461cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger  A second move creates a new endpoint.
2471cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger  A diagonal line is parsed.
2481cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger  There's more than four changes of direction.
2491cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger  There's a discontinuity on the line (e.g., a move in the middle)
2501cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger  The line reverses direction.
2511cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger  The rectangle doesn't complete a cycle.
2521cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger  The path contains a quadratic or cubic.
2531cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger  The path contains fewer than four points.
2541cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger  The final point isn't equal to the first point.
2551cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
2561cab2921ab279367f8206cdadc9259d12e603548Derek SollenbergerIt's OK if the path has:
2571cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger  Several colinear line segments composing a rectangle side.
2581cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger  Single points on the rectangle side.
2591cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
2601cab2921ab279367f8206cdadc9259d12e603548Derek SollenbergerThe direction takes advantage of the corners found since opposite sides
2611cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergermust travel in opposite directions.
2621cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
2631cab2921ab279367f8206cdadc9259d12e603548Derek SollenbergerFIXME: Allow colinear quads and cubics to be treated like lines.
2641cab2921ab279367f8206cdadc9259d12e603548Derek SollenbergerFIXME: If the API passes fill-only, return true if the filled stroke
2651cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger       is a rectangle, though the caller failed to close the path.
2661cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger */
2671cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergerbool SkPath::isRect(SkRect* rect) const {
2680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkDEBUGCODE(this->validate();)
26940528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
2701cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    int corners = 0;
2711cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    SkPoint first, last;
2721cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    first.set(0, 0);
2731cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    last.set(0, 0);
2741cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    int firstDirection = 0;
2751cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    int lastDirection = 0;
2761cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    int nextDirection = 0;
2771cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    bool closedOrMoved = false;
2781cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    bool autoClose = false;
2791cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    const uint8_t* verbs = fVerbs.begin();
2801cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    const uint8_t* verbStop = fVerbs.end();
2811cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    const SkPoint* pts = fPts.begin();
2821cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    while (verbs != verbStop) {
2831cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        switch (*verbs++) {
2841cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            case kClose_Verb:
2851cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                pts = fPts.begin();
2861cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                autoClose = true;
2871cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            case kLine_Verb: {
2881cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                SkScalar left = last.fX;
2891cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                SkScalar top = last.fY;
2901cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                SkScalar right = pts->fX;
2911cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                SkScalar bottom = pts->fY;
2921cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                ++pts;
2931cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                if (left != right && top != bottom) {
2941cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                    return false; // diagonal
2951cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                }
2961cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                if (left == right && top == bottom) {
2971cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                    break; // single point on side OK
2981cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                }
2991cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                nextDirection = (left != right) << 0 |
3001cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                    (left < right || top < bottom) << 1;
3011cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                if (0 == corners) {
3021cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                    firstDirection = nextDirection;
3031cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                    first = last;
3041cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                    last = pts[-1];
3051cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                    corners = 1;
3061cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                    closedOrMoved = false;
3071cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                    break;
3081cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                }
3091cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                if (closedOrMoved) {
3101cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                    return false; // closed followed by a line
3111cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                }
3121cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                closedOrMoved = autoClose;
3131cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                if (lastDirection != nextDirection) {
3141cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                    if (++corners > 4) {
3151cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                        return false; // too many direction changes
3161cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                    }
3171cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                }
3181cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                last = pts[-1];
3191cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                if (lastDirection == nextDirection) {
3201cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                    break; // colinear segment
3211cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                }
3221cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                // Possible values for corners are 2, 3, and 4.
3231cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                // When corners == 3, nextDirection opposes firstDirection.
3241cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                // Otherwise, nextDirection at corner 2 opposes corner 4.
3251cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                int turn = firstDirection ^ (corners - 1);
3261cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                int directionCycle = 3 == corners ? 0 : nextDirection ^ turn;
3271cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                if ((directionCycle ^ turn) != nextDirection) {
3281cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                    return false; // direction didn't follow cycle
3291cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                }
3301cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                break;
3311cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            }
3321cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            case kQuad_Verb:
3331cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            case kCubic_Verb:
3341cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                return false; // quadratic, cubic not allowed
3351cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            case kMove_Verb:
3361cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                last = *pts++;
3371cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                closedOrMoved = true;
3381cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                break;
3391cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        }
3401cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        lastDirection = nextDirection;
3411cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    }
3421cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    // Success if 4 corners and first point equals last
3431cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    bool result = 4 == corners && first == last;
3441cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    if (result && rect) {
3451cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        *rect = getBounds();
3461cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    }
3471cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    return result;
3480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
3490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectint SkPath::getPoints(SkPoint copy[], int max) const {
3510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkDEBUGCODE(this->validate();)
3520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(max >= 0);
3540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int count = fPts.count();
3550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (copy && max > 0 && count > 0) {
3560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        memcpy(copy, fPts.begin(), sizeof(SkPoint) * SkMin32(max, count));
3570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
3580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return count;
3590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
3600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3611c980e0d7772f05f570ae0227d91635f017c2227Mike ReedSkPoint SkPath::getPoint(int index) const {
3621c980e0d7772f05f570ae0227d91635f017c2227Mike Reed    if ((unsigned)index < (unsigned)fPts.count()) {
3631c980e0d7772f05f570ae0227d91635f017c2227Mike Reed        return fPts[index];
3641c980e0d7772f05f570ae0227d91635f017c2227Mike Reed    }
3651c980e0d7772f05f570ae0227d91635f017c2227Mike Reed    return SkPoint::Make(0, 0);
3661c980e0d7772f05f570ae0227d91635f017c2227Mike Reed}
3671c980e0d7772f05f570ae0227d91635f017c2227Mike Reed
3681cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergerbool SkPath::getLastPt(SkPoint* lastPt) const {
3690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkDEBUGCODE(this->validate();)
3700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3711cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    int count = fPts.count();
3721cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    if (count > 0) {
3731cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        if (lastPt) {
3740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            *lastPt = fPts[count - 1];
3750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
3761cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        return true;
3771cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    }
3781cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    if (lastPt) {
3791cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        lastPt->set(0, 0);
3800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
3811cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    return false;
3820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
3830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPath::setLastPt(SkScalar x, SkScalar y) {
3850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkDEBUGCODE(this->validate();)
3860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int count = fPts.count();
3880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (count == 0) {
3890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->moveTo(x, y);
3900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    } else {
3910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fPts[count - 1].set(x, y);
39287b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenberger        GEN_ID_INC;
3930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
3940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
3950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3960e747d6d0a794242bd214fa44a6a179baeadfdf9Mike Reedvoid SkPath::computeBounds() const {
3970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkDEBUGCODE(this->validate();)
3980e747d6d0a794242bd214fa44a6a179baeadfdf9Mike Reed    SkASSERT(fBoundsIsDirty);
3990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4000e747d6d0a794242bd214fa44a6a179baeadfdf9Mike Reed    fBoundsIsDirty = false;
4010e747d6d0a794242bd214fa44a6a179baeadfdf9Mike Reed    compute_pt_bounds(&fBounds, fPts);
4020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
4030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
40435e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenbergervoid SkPath::setConvexity(Convexity c) {
40535e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    if (fConvexity != c) {
40635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        fConvexity = c;
40735e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        GEN_ID_INC;
40835e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    }
40935e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger}
41035e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger
4110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project//////////////////////////////////////////////////////////////////////////////
4120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project//  Construction methods
4130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4141cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger#define DIRTY_AFTER_EDIT                 \
4151cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    do {                                 \
4161cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        fBoundsIsDirty = true;           \
4171cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        fConvexity = kUnknown_Convexity; \
4180b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    } while (0)
4190b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
4204f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger#define DIRTY_AFTER_EDIT_NO_CONVEXITY_CHANGE    \
4214f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    do {                                        \
4224f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        fBoundsIsDirty = true;                  \
4234f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    } while (0)
4244f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger
4250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPath::incReserve(U16CPU inc) {
4260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkDEBUGCODE(this->validate();)
4270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fVerbs.setReserve(fVerbs.count() + inc);
4290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fPts.setReserve(fPts.count() + inc);
4300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkDEBUGCODE(this->validate();)
4320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
4330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPath::moveTo(SkScalar x, SkScalar y) {
4350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkDEBUGCODE(this->validate();)
4360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int      vc = fVerbs.count();
4380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPoint* pt;
4390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4404f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    // remember our index
4414f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    fLastMoveToIndex = fPts.count();
4424f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger
4431cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    pt = fPts.append();
4441cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    *fVerbs.append() = kMove_Verb;
4450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    pt->set(x, y);
4460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
44787b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenberger    GEN_ID_INC;
4484f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    DIRTY_AFTER_EDIT_NO_CONVEXITY_CHANGE;
4490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
4500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPath::rMoveTo(SkScalar x, SkScalar y) {
4520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPoint pt;
4530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->getLastPt(&pt);
4540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->moveTo(pt.fX + x, pt.fY + y);
4550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
4560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4574f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenbergervoid SkPath::injectMoveToIfNeeded() {
4584f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    if (fLastMoveToIndex < 0) {
4594f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        SkScalar x, y;
4604f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        if (fVerbs.count() == 0) {
4614f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            x = y = 0;
4624f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        } else {
4634f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            const SkPoint& pt = fPts[~fLastMoveToIndex];
4644f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            x = pt.fX;
4654f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            y = pt.fY;
4664f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        }
4674f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        this->moveTo(x, y);
4684f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    }
4694f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger}
4704f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger
4710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPath::lineTo(SkScalar x, SkScalar y) {
4720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkDEBUGCODE(this->validate();)
4730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4744f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    this->injectMoveToIfNeeded();
4754f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger
4760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fPts.append()->set(x, y);
4770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    *fVerbs.append() = kLine_Verb;
4781cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    fSegmentMask |= kLine_SegmentMask;
4790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
48087b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenberger    GEN_ID_INC;
4810b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    DIRTY_AFTER_EDIT;
4820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
4830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPath::rLineTo(SkScalar x, SkScalar y) {
4850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPoint pt;
4860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->getLastPt(&pt);
4870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->lineTo(pt.fX + x, pt.fY + y);
4880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
4890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPath::quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
4910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkDEBUGCODE(this->validate();)
4920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4934f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    this->injectMoveToIfNeeded();
4940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPoint* pts = fPts.append(2);
4960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    pts[0].set(x1, y1);
4970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    pts[1].set(x2, y2);
4980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    *fVerbs.append() = kQuad_Verb;
4991cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    fSegmentMask |= kQuad_SegmentMask;
5000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
50187b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenberger    GEN_ID_INC;
5020b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    DIRTY_AFTER_EDIT;
5030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
5040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPath::rQuadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
5060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPoint pt;
5070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->getLastPt(&pt);
5080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->quadTo(pt.fX + x1, pt.fY + y1, pt.fX + x2, pt.fY + y2);
5090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
5100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPath::cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
5120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                     SkScalar x3, SkScalar y3) {
5130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkDEBUGCODE(this->validate();)
5140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5154f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    this->injectMoveToIfNeeded();
5164f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger
5170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPoint* pts = fPts.append(3);
5180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    pts[0].set(x1, y1);
5190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    pts[1].set(x2, y2);
5200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    pts[2].set(x3, y3);
5210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    *fVerbs.append() = kCubic_Verb;
5221cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    fSegmentMask |= kCubic_SegmentMask;
5230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
52487b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenberger    GEN_ID_INC;
5250b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    DIRTY_AFTER_EDIT;
5260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
5270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPath::rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
5290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                      SkScalar x3, SkScalar y3) {
5300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPoint pt;
5310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->getLastPt(&pt);
5320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->cubicTo(pt.fX + x1, pt.fY + y1, pt.fX + x2, pt.fY + y2,
5330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                  pt.fX + x3, pt.fY + y3);
5340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
5350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPath::close() {
5370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkDEBUGCODE(this->validate();)
5380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int count = fVerbs.count();
5400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (count > 0) {
5410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        switch (fVerbs[count - 1]) {
5420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            case kLine_Verb:
5430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            case kQuad_Verb:
5440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            case kCubic_Verb:
5451cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            case kMove_Verb:
5460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                *fVerbs.append() = kClose_Verb;
54787b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenberger                GEN_ID_INC;
5480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                break;
5490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            default:
5501cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                // don't add a close if it's the first verb or a repeat
5510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                break;
5520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
5530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
5544f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger
5554f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    // signal that we need a moveTo to follow us (unless we're done)
5564f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger#if 0
5574f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    if (fLastMoveToIndex >= 0) {
5584f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        fLastMoveToIndex = ~fLastMoveToIndex;
5594f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    }
5604f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger#else
5614f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    fLastMoveToIndex ^= ~fLastMoveToIndex >> (8 * sizeof(fLastMoveToIndex) - 1);
5624f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger#endif
5630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
5640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
56640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
5670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPath::addRect(const SkRect& rect, Direction dir) {
5680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->addRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, dir);
5690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
5700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPath::addRect(SkScalar left, SkScalar top, SkScalar right,
5720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                     SkScalar bottom, Direction dir) {
5730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkAutoPathBoundsUpdate apbu(this, left, top, right, bottom);
5740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->incReserve(5);
5760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->moveTo(left, top);
5780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (dir == kCCW_Direction) {
5790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->lineTo(left, bottom);
5800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->lineTo(right, bottom);
5810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->lineTo(right, top);
5820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    } else {
5830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->lineTo(right, top);
5840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->lineTo(right, bottom);
5850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->lineTo(left, bottom);
5860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
5870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->close();
5880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
5890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#define CUBIC_ARC_FACTOR    ((SK_ScalarSqrt2 - SK_Scalar1) * 4 / 3)
5910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPath::addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry,
5930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                          Direction dir) {
5940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar    w = rect.width();
5950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar    halfW = SkScalarHalf(w);
5960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar    h = rect.height();
5970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar    halfH = SkScalarHalf(h);
5980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (halfW <= 0 || halfH <= 0) {
6000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return;
6010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
6020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
60340528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    bool skip_hori = rx >= halfW;
60440528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    bool skip_vert = ry >= halfH;
6050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
6060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (skip_hori && skip_vert) {
6070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->addOval(rect, dir);
6080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return;
6090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
61040528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
61140528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    SkAutoPathBoundsUpdate apbu(this, rect);
61240528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
6130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (skip_hori) {
6140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        rx = halfW;
6150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    } else if (skip_vert) {
6160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        ry = halfH;
6170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
6180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
6190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar    sx = SkScalarMul(rx, CUBIC_ARC_FACTOR);
6200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar    sy = SkScalarMul(ry, CUBIC_ARC_FACTOR);
6210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
6220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->incReserve(17);
6230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->moveTo(rect.fRight - rx, rect.fTop);
6240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (dir == kCCW_Direction) {
6250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (!skip_hori) {
6260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            this->lineTo(rect.fLeft + rx, rect.fTop);       // top
6270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
6280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->cubicTo(rect.fLeft + rx - sx, rect.fTop,
6290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                      rect.fLeft, rect.fTop + ry - sy,
6300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                      rect.fLeft, rect.fTop + ry);          // top-left
6310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (!skip_vert) {
6320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            this->lineTo(rect.fLeft, rect.fBottom - ry);        // left
6330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
6340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->cubicTo(rect.fLeft, rect.fBottom - ry + sy,
6350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                      rect.fLeft + rx - sx, rect.fBottom,
6360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                      rect.fLeft + rx, rect.fBottom);       // bot-left
6370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (!skip_hori) {
6380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            this->lineTo(rect.fRight - rx, rect.fBottom);   // bottom
6390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
6400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->cubicTo(rect.fRight - rx + sx, rect.fBottom,
6410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                      rect.fRight, rect.fBottom - ry + sy,
6420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                      rect.fRight, rect.fBottom - ry);      // bot-right
6430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (!skip_vert) {
6440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            this->lineTo(rect.fRight, rect.fTop + ry);
6450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
6460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->cubicTo(rect.fRight, rect.fTop + ry - sy,
6470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                      rect.fRight - rx + sx, rect.fTop,
6480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                      rect.fRight - rx, rect.fTop);         // top-right
6490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    } else {
6500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->cubicTo(rect.fRight - rx + sx, rect.fTop,
6510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                      rect.fRight, rect.fTop + ry - sy,
6520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                      rect.fRight, rect.fTop + ry);         // top-right
6530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (!skip_vert) {
6540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            this->lineTo(rect.fRight, rect.fBottom - ry);
6550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
6560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->cubicTo(rect.fRight, rect.fBottom - ry + sy,
6570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                      rect.fRight - rx + sx, rect.fBottom,
6580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                      rect.fRight - rx, rect.fBottom);      // bot-right
6590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (!skip_hori) {
6600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            this->lineTo(rect.fLeft + rx, rect.fBottom);    // bottom
6610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
6620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->cubicTo(rect.fLeft + rx - sx, rect.fBottom,
6630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                      rect.fLeft, rect.fBottom - ry + sy,
6640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                      rect.fLeft, rect.fBottom - ry);       // bot-left
6650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (!skip_vert) {
6660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            this->lineTo(rect.fLeft, rect.fTop + ry);       // left
6670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
6680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->cubicTo(rect.fLeft, rect.fTop + ry - sy,
6690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                      rect.fLeft + rx - sx, rect.fTop,
6700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                      rect.fLeft + rx, rect.fTop);          // top-left
6710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (!skip_hori) {
6720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            this->lineTo(rect.fRight - rx, rect.fTop);      // top
6730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
6740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
6750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->close();
6760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
6770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
6780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void add_corner_arc(SkPath* path, const SkRect& rect,
6790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                           SkScalar rx, SkScalar ry, int startAngle,
6800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                           SkPath::Direction dir, bool forceMoveTo) {
6810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    rx = SkMinScalar(SkScalarHalf(rect.width()), rx);
6820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    ry = SkMinScalar(SkScalarHalf(rect.height()), ry);
68340528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
6840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkRect   r;
6850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    r.set(-rx, -ry, rx, ry);
6860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
6870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    switch (startAngle) {
6880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case   0:
6890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            r.offset(rect.fRight - r.fRight, rect.fBottom - r.fBottom);
6900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            break;
6910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case  90:
6920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            r.offset(rect.fLeft - r.fLeft,   rect.fBottom - r.fBottom);
6930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            break;
6940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case 180: r.offset(rect.fLeft - r.fLeft,   rect.fTop - r.fTop); break;
6950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case 270: r.offset(rect.fRight - r.fRight, rect.fTop - r.fTop); break;
6961cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        default: SkDEBUGFAIL("unexpected startAngle in add_corner_arc");
6970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
69840528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
6990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar start = SkIntToScalar(startAngle);
7000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar sweep = SkIntToScalar(90);
7010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (SkPath::kCCW_Direction == dir) {
7020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        start += sweep;
7030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        sweep = -sweep;
7040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
70540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
7060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    path->arcTo(r, start, sweep, forceMoveTo);
7070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
7080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
7090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPath::addRoundRect(const SkRect& rect, const SkScalar rad[],
7100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                          Direction dir) {
71140528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    // abort before we invoke SkAutoPathBoundsUpdate()
71240528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    if (rect.isEmpty()) {
71340528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        return;
71440528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    }
71540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
7160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkAutoPathBoundsUpdate apbu(this, rect);
7170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
7180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (kCW_Direction == dir) {
7190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        add_corner_arc(this, rect, rad[0], rad[1], 180, dir, true);
7200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        add_corner_arc(this, rect, rad[2], rad[3], 270, dir, false);
7210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        add_corner_arc(this, rect, rad[4], rad[5],   0, dir, false);
7220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        add_corner_arc(this, rect, rad[6], rad[7],  90, dir, false);
7230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    } else {
7240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        add_corner_arc(this, rect, rad[0], rad[1], 180, dir, true);
7250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        add_corner_arc(this, rect, rad[6], rad[7],  90, dir, false);
7260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        add_corner_arc(this, rect, rad[4], rad[5],   0, dir, false);
7270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        add_corner_arc(this, rect, rad[2], rad[3], 270, dir, false);
7280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
7290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->close();
7300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
7310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
7320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPath::addOval(const SkRect& oval, Direction dir) {
7330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkAutoPathBoundsUpdate apbu(this, oval);
7340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
7350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar    cx = oval.centerX();
7360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar    cy = oval.centerY();
7370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar    rx = SkScalarHalf(oval.width());
7380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar    ry = SkScalarHalf(oval.height());
7390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#if 0   // these seem faster than using quads (1/2 the number of edges)
7400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar    sx = SkScalarMul(rx, CUBIC_ARC_FACTOR);
7410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar    sy = SkScalarMul(ry, CUBIC_ARC_FACTOR);
7420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
7430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->incReserve(13);
7440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->moveTo(cx + rx, cy);
7450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (dir == kCCW_Direction) {
7460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->cubicTo(cx + rx, cy - sy, cx + sx, cy - ry, cx, cy - ry);
7470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->cubicTo(cx - sx, cy - ry, cx - rx, cy - sy, cx - rx, cy);
7480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->cubicTo(cx - rx, cy + sy, cx - sx, cy + ry, cx, cy + ry);
7490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->cubicTo(cx + sx, cy + ry, cx + rx, cy + sy, cx + rx, cy);
7500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    } else {
7510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->cubicTo(cx + rx, cy + sy, cx + sx, cy + ry, cx, cy + ry);
7520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->cubicTo(cx - sx, cy + ry, cx - rx, cy + sy, cx - rx, cy);
7530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->cubicTo(cx - rx, cy - sy, cx - sx, cy - ry, cx, cy - ry);
7540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->cubicTo(cx + sx, cy - ry, cx + rx, cy - sy, cx + rx, cy);
7550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
7560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#else
7570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar    sx = SkScalarMul(rx, SK_ScalarTanPIOver8);
7580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar    sy = SkScalarMul(ry, SK_ScalarTanPIOver8);
7590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar    mx = SkScalarMul(rx, SK_ScalarRoot2Over2);
7600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar    my = SkScalarMul(ry, SK_ScalarRoot2Over2);
7610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
7620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    /*
7630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        To handle imprecision in computing the center and radii, we revert to
7640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        the provided bounds when we can (i.e. use oval.fLeft instead of cx-rx)
7650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        to ensure that we don't exceed the oval's bounds *ever*, since we want
7660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        to use oval for our fast-bounds, rather than have to recompute it.
7670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    */
7680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const SkScalar L = oval.fLeft;      // cx - rx
7690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const SkScalar T = oval.fTop;       // cy - ry
7700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const SkScalar R = oval.fRight;     // cx + rx
7710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const SkScalar B = oval.fBottom;    // cy + ry
7720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
7730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->incReserve(17);   // 8 quads + close
7740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->moveTo(R, cy);
7750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (dir == kCCW_Direction) {
7760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->quadTo(      R, cy - sy, cx + mx, cy - my);
7770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->quadTo(cx + sx,       T, cx     ,       T);
7780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->quadTo(cx - sx,       T, cx - mx, cy - my);
7790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->quadTo(      L, cy - sy,       L, cy     );
7800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->quadTo(      L, cy + sy, cx - mx, cy + my);
7810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->quadTo(cx - sx,       B, cx     ,       B);
7820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->quadTo(cx + sx,       B, cx + mx, cy + my);
7830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->quadTo(      R, cy + sy,       R, cy     );
7840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    } else {
7850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->quadTo(      R, cy + sy, cx + mx, cy + my);
7860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->quadTo(cx + sx,       B, cx     ,       B);
7870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->quadTo(cx - sx,       B, cx - mx, cy + my);
7880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->quadTo(      L, cy + sy,       L, cy     );
7890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->quadTo(      L, cy - sy, cx - mx, cy - my);
7900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->quadTo(cx - sx,       T, cx     ,       T);
7910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->quadTo(cx + sx,       T, cx + mx, cy - my);
7920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->quadTo(      R, cy - sy,       R, cy     );
7930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
7940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
7950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->close();
7960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
7970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
7980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPath::addCircle(SkScalar x, SkScalar y, SkScalar r, Direction dir) {
7990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (r > 0) {
8000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkRect  rect;
8010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        rect.set(x - r, y - r, x + r, y + r);
8020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->addOval(rect, dir);
8030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
8040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
8050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
8060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkGeometry.h"
8070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
8080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic int build_arc_points(const SkRect& oval, SkScalar startAngle,
8090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                            SkScalar sweepAngle,
8100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                            SkPoint pts[kSkBuildQuadArcStorage]) {
8110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkVector start, stop;
8120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
8130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    start.fY = SkScalarSinCos(SkDegreesToRadians(startAngle), &start.fX);
8140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    stop.fY = SkScalarSinCos(SkDegreesToRadians(startAngle + sweepAngle),
8150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                             &stop.fX);
8161c980e0d7772f05f570ae0227d91635f017c2227Mike Reed
8171c980e0d7772f05f570ae0227d91635f017c2227Mike Reed    /*  If the sweep angle is nearly (but less than) 360, then due to precision
8181c980e0d7772f05f570ae0227d91635f017c2227Mike Reed        loss in radians-conversion and/or sin/cos, we may end up with coincident
8191c980e0d7772f05f570ae0227d91635f017c2227Mike Reed        vectors, which will fool SkBuildQuadArc into doing nothing (bad) instead
8201c980e0d7772f05f570ae0227d91635f017c2227Mike Reed        of drawing a nearly complete circle (good).
8211c980e0d7772f05f570ae0227d91635f017c2227Mike Reed             e.g. canvas.drawArc(0, 359.99, ...)
8221c980e0d7772f05f570ae0227d91635f017c2227Mike Reed             -vs- canvas.drawArc(0, 359.9, ...)
8231c980e0d7772f05f570ae0227d91635f017c2227Mike Reed        We try to detect this edge case, and tweak the stop vector
8241c980e0d7772f05f570ae0227d91635f017c2227Mike Reed     */
8251c980e0d7772f05f570ae0227d91635f017c2227Mike Reed    if (start == stop) {
8261c980e0d7772f05f570ae0227d91635f017c2227Mike Reed        SkScalar sw = SkScalarAbs(sweepAngle);
8271c980e0d7772f05f570ae0227d91635f017c2227Mike Reed        if (sw < SkIntToScalar(360) && sw > SkIntToScalar(359)) {
8281c980e0d7772f05f570ae0227d91635f017c2227Mike Reed            SkScalar stopRad = SkDegreesToRadians(startAngle + sweepAngle);
8291c980e0d7772f05f570ae0227d91635f017c2227Mike Reed            // make a guess at a tiny angle (in radians) to tweak by
8301c980e0d7772f05f570ae0227d91635f017c2227Mike Reed            SkScalar deltaRad = SkScalarCopySign(SK_Scalar1/512, sweepAngle);
8311c980e0d7772f05f570ae0227d91635f017c2227Mike Reed            // not sure how much will be enough, so we use a loop
8321c980e0d7772f05f570ae0227d91635f017c2227Mike Reed            do {
8331c980e0d7772f05f570ae0227d91635f017c2227Mike Reed                stopRad -= deltaRad;
8341c980e0d7772f05f570ae0227d91635f017c2227Mike Reed                stop.fY = SkScalarSinCos(stopRad, &stop.fX);
8351c980e0d7772f05f570ae0227d91635f017c2227Mike Reed            } while (start == stop);
8361c980e0d7772f05f570ae0227d91635f017c2227Mike Reed        }
8371c980e0d7772f05f570ae0227d91635f017c2227Mike Reed    }
8381c980e0d7772f05f570ae0227d91635f017c2227Mike Reed
8390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkMatrix    matrix;
84040528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
8410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    matrix.setScale(SkScalarHalf(oval.width()), SkScalarHalf(oval.height()));
8420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    matrix.postTranslate(oval.centerX(), oval.centerY());
84340528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
8440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return SkBuildQuadArc(start, stop,
8450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project          sweepAngle > 0 ? kCW_SkRotationDirection : kCCW_SkRotationDirection,
8460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                          &matrix, pts);
8470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
8480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
8490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPath::arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
8500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                   bool forceMoveTo) {
8510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (oval.width() < 0 || oval.height() < 0) {
8520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return;
8530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
8540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
8550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPoint pts[kSkBuildQuadArcStorage];
8560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int count = build_arc_points(oval, startAngle, sweepAngle, pts);
8570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT((count & 1) == 1);
8580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
8590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (fVerbs.count() == 0) {
8600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        forceMoveTo = true;
8610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
8620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->incReserve(count);
8630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    forceMoveTo ? this->moveTo(pts[0]) : this->lineTo(pts[0]);
8640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    for (int i = 1; i < count; i += 2) {
8650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->quadTo(pts[i], pts[i+1]);
8660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
8670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
8680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
8690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPath::addArc(const SkRect& oval, SkScalar startAngle,
8700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    SkScalar sweepAngle) {
8710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (oval.isEmpty() || 0 == sweepAngle) {
8720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return;
8730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
8740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
8750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const SkScalar kFullCircleAngle = SkIntToScalar(360);
8760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
8770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (sweepAngle >= kFullCircleAngle || sweepAngle <= -kFullCircleAngle) {
8780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->addOval(oval, sweepAngle > 0 ? kCW_Direction : kCCW_Direction);
8790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return;
8800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
8810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
8820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPoint pts[kSkBuildQuadArcStorage];
8830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int count = build_arc_points(oval, startAngle, sweepAngle, pts);
8840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
8850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->incReserve(count);
8860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->moveTo(pts[0]);
8870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    for (int i = 1; i < count; i += 2) {
8880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->quadTo(pts[i], pts[i+1]);
8890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
8900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
8910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
8920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project/*
8930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    Need to handle the case when the angle is sharp, and our computed end-points
8940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    for the arc go behind pt1 and/or p2...
8950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project*/
8960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPath::arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
8970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                   SkScalar radius) {
8980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkVector    before, after;
89940528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
9000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // need to know our prev pt so we can construct tangent vectors
9010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    {
9020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkPoint start;
9030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->getLastPt(&start);
90440528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        // Handle degenerate cases by adding a line to the first point and
90540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        // bailing out.
90640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        if ((x1 == start.fX && y1 == start.fY) ||
90740528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger            (x1 == x2 && y1 == y2) ||
90840528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger            radius == 0) {
90940528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger            this->lineTo(x1, y1);
91040528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger            return;
91140528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        }
9120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        before.setNormalize(x1 - start.fX, y1 - start.fY);
9130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        after.setNormalize(x2 - x1, y2 - y1);
9140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
91540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
9160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar cosh = SkPoint::DotProduct(before, after);
9170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar sinh = SkPoint::CrossProduct(before, after);
9180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
9190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (SkScalarNearlyZero(sinh)) {   // angle is too tight
92040528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        this->lineTo(x1, y1);
9210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return;
9220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
92340528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
9240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar dist = SkScalarMulDiv(radius, SK_Scalar1 - cosh, sinh);
9250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (dist < 0) {
9260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        dist = -dist;
9270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
9280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
9290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar xx = x1 - SkScalarMul(dist, before.fX);
9300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar yy = y1 - SkScalarMul(dist, before.fY);
9310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkRotationDirection arcDir;
9320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
9330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // now turn before/after into normals
9340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (sinh > 0) {
9350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        before.rotateCCW();
9360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        after.rotateCCW();
9370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        arcDir = kCW_SkRotationDirection;
9380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    } else {
9390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        before.rotateCW();
9400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        after.rotateCW();
9410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        arcDir = kCCW_SkRotationDirection;
9420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
9430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
9440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkMatrix    matrix;
9450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPoint     pts[kSkBuildQuadArcStorage];
94640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
9470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    matrix.setScale(radius, radius);
9480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    matrix.postTranslate(xx - SkScalarMul(radius, before.fX),
9490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                         yy - SkScalarMul(radius, before.fY));
95040528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
9510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int count = SkBuildQuadArc(before, after, arcDir, &matrix, pts);
95240528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
9530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->incReserve(count);
9540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // [xx,yy] == pts[0]
9550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->lineTo(xx, yy);
9560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    for (int i = 1; i < count; i += 2) {
9570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->quadTo(pts[i], pts[i+1]);
9580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
9590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
9600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
9610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
9620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
9630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPath::addPath(const SkPath& path, SkScalar dx, SkScalar dy) {
9640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkMatrix matrix;
9650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
9660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    matrix.setTranslate(dx, dy);
9670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->addPath(path, matrix);
9680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
9690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
9700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPath::addPath(const SkPath& path, const SkMatrix& matrix) {
9710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->incReserve(path.fPts.count());
9720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
9731cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    RawIter iter(path);
9740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPoint pts[4];
9750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    Verb    verb;
9760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
9770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkMatrix::MapPtsProc proc = matrix.getMapPtsProc();
9780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
9790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    while ((verb = iter.next(pts)) != kDone_Verb) {
9800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        switch (verb) {
9810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            case kMove_Verb:
9820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                proc(matrix, &pts[0], &pts[0], 1);
9830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                this->moveTo(pts[0]);
9840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                break;
9850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            case kLine_Verb:
9860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                proc(matrix, &pts[1], &pts[1], 1);
9870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                this->lineTo(pts[1]);
9880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                break;
9890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            case kQuad_Verb:
9900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                proc(matrix, &pts[1], &pts[1], 2);
9910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                this->quadTo(pts[1], pts[2]);
9920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                break;
9930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            case kCubic_Verb:
9940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                proc(matrix, &pts[1], &pts[1], 3);
9950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                this->cubicTo(pts[1], pts[2], pts[3]);
9960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                break;
9970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            case kClose_Verb:
9980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                this->close();
9990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                break;
10000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            default:
10011cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                SkDEBUGFAIL("unknown verb");
10020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
10030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
10040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
10050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
10060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
10070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
10080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic const uint8_t gPtsInVerb[] = {
10090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    1,  // kMove
10100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    1,  // kLine
10110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    2,  // kQuad
10120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    3,  // kCubic
10130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    0,  // kClose
10140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    0   // kDone
10150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project};
10160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
10170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project// ignore the initial moveto, and stop when the 1st contour ends
10180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPath::pathTo(const SkPath& path) {
10190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int i, vcount = path.fVerbs.count();
10200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (vcount == 0) {
10210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return;
10220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
10230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
10240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->incReserve(vcount);
10250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
10260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const uint8_t*  verbs = path.fVerbs.begin();
10270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const SkPoint*  pts = path.fPts.begin() + 1;    // 1 for the initial moveTo
10280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
10290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(verbs[0] == kMove_Verb);
10300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    for (i = 1; i < vcount; i++) {
10310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        switch (verbs[i]) {
10320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            case kLine_Verb:
10330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                this->lineTo(pts[0].fX, pts[0].fY);
10340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                break;
10350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            case kQuad_Verb:
10360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                this->quadTo(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY);
10370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                break;
10380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            case kCubic_Verb:
10390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                this->cubicTo(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY,
10400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                              pts[2].fX, pts[2].fY);
10410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                break;
10420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            case kClose_Verb:
10430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                return;
10440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
10450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        pts += gPtsInVerb[verbs[i]];
10460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
10470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
10480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
10490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project// ignore the last point of the 1st contour
10500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPath::reversePathTo(const SkPath& path) {
10510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int i, vcount = path.fVerbs.count();
10520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (vcount == 0) {
10530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return;
10540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
10550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
10560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->incReserve(vcount);
10570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
10580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const uint8_t*  verbs = path.fVerbs.begin();
10590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const SkPoint*  pts = path.fPts.begin();
10600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
10610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(verbs[0] == kMove_Verb);
10620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    for (i = 1; i < vcount; i++) {
10630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        int n = gPtsInVerb[verbs[i]];
10640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (n == 0) {
10650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            break;
10660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
10670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        pts += n;
10680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
10690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
10700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    while (--i > 0) {
10710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        switch (verbs[i]) {
10720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            case kLine_Verb:
10730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                this->lineTo(pts[-1].fX, pts[-1].fY);
10740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                break;
10750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            case kQuad_Verb:
10760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                this->quadTo(pts[-1].fX, pts[-1].fY, pts[-2].fX, pts[-2].fY);
10770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                break;
10780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            case kCubic_Verb:
10790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                this->cubicTo(pts[-1].fX, pts[-1].fY, pts[-2].fX, pts[-2].fY,
10800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                              pts[-3].fX, pts[-3].fY);
10810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                break;
10820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            default:
10831cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                SkDEBUGFAIL("bad verb");
10840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                break;
10850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
10860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        pts -= gPtsInVerb[verbs[i]];
10870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
10880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
10890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
10901cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergervoid SkPath::reverseAddPath(const SkPath& src) {
10911cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    this->incReserve(src.fPts.count());
10921cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
10931cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    const SkPoint* startPts = src.fPts.begin();
10941cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    const SkPoint* pts = src.fPts.end();
10951cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    const uint8_t* startVerbs = src.fVerbs.begin();
10961cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    const uint8_t* verbs = src.fVerbs.end();
10971cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
10981cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    bool needMove = true;
10991cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    bool needClose = false;
11001cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    while (verbs > startVerbs) {
11011cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        uint8_t v = *--verbs;
11021cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        int n = gPtsInVerb[v];
11031cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
11041cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        if (needMove) {
11051cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            --pts;
11061cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            this->moveTo(pts->fX, pts->fY);
11071cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            needMove = false;
11081cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        }
11091cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        pts -= n;
11101cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        switch (v) {
11111cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            case kMove_Verb:
11121cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                if (needClose) {
11131cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                    this->close();
11141cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                    needClose = false;
11151cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                }
11161cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                needMove = true;
11171cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                pts += 1;   // so we see the point in "if (needMove)" above
11181cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                break;
11191cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            case kLine_Verb:
11201cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                this->lineTo(pts[0]);
11211cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                break;
11221cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            case kQuad_Verb:
11231cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                this->quadTo(pts[1], pts[0]);
11241cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                break;
11251cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            case kCubic_Verb:
11261cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                this->cubicTo(pts[2], pts[1], pts[0]);
11271cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                break;
11281cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            case kClose_Verb:
11291cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                needClose = true;
11301cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                break;
11311cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            default:
11321cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                SkASSERT(!"unexpected verb");
11331cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        }
11341cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    }
11351cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
11361cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
11370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
11380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
11390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPath::offset(SkScalar dx, SkScalar dy, SkPath* dst) const {
11400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkMatrix    matrix;
11410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
11420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    matrix.setTranslate(dx, dy);
11430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->transform(matrix, dst);
11440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
11450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
11460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkGeometry.h"
11470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
11480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void subdivide_quad_to(SkPath* path, const SkPoint pts[3],
11490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                              int level = 2) {
11500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (--level >= 0) {
11510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkPoint tmp[5];
11520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
11530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkChopQuadAtHalf(pts, tmp);
11540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        subdivide_quad_to(path, &tmp[0], level);
11550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        subdivide_quad_to(path, &tmp[2], level);
11560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    } else {
11570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        path->quadTo(pts[1], pts[2]);
11580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
11590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
11600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
11610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void subdivide_cubic_to(SkPath* path, const SkPoint pts[4],
11620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                               int level = 2) {
11630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (--level >= 0) {
11640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkPoint tmp[7];
11650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
11660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkChopCubicAtHalf(pts, tmp);
11670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        subdivide_cubic_to(path, &tmp[0], level);
11680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        subdivide_cubic_to(path, &tmp[3], level);
11690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    } else {
11700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        path->cubicTo(pts[1], pts[2], pts[3]);
11710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
11720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
11730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
11740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPath::transform(const SkMatrix& matrix, SkPath* dst) const {
11750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkDEBUGCODE(this->validate();)
11760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (dst == NULL) {
11770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        dst = (SkPath*)this;
11780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
11790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
11800199fa7423f89a129da2b22a488f2c18e2e4727fDerek Sollenberger    if (matrix.hasPerspective()) {
11810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkPath  tmp;
11820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        tmp.fFillType = fFillType;
11830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
11840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkPath::Iter    iter(*this, false);
11850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkPoint         pts[4];
11860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkPath::Verb    verb;
11870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
11880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        while ((verb = iter.next(pts)) != kDone_Verb) {
11890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            switch (verb) {
11900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                case kMove_Verb:
11910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    tmp.moveTo(pts[0]);
11920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    break;
11930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                case kLine_Verb:
11940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    tmp.lineTo(pts[1]);
11950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    break;
11960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                case kQuad_Verb:
11970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    subdivide_quad_to(&tmp, pts);
11980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    break;
11990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                case kCubic_Verb:
12000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    subdivide_cubic_to(&tmp, pts);
12010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    break;
12020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                case kClose_Verb:
12030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    tmp.close();
12040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    break;
12050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                default:
12061cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                    SkDEBUGFAIL("unknown verb");
12070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    break;
12080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
12090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
12100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1211ebb0af8e21433525397cefdec3a8903e3da966b0Romain Guy        // swap() will increment the gen id if needed
12120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        dst->swap(tmp);
12130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        matrix.mapPoints(dst->fPts.begin(), dst->fPts.count());
12140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    } else {
12150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        // remember that dst might == this, so be sure to check
12160e747d6d0a794242bd214fa44a6a179baeadfdf9Mike Reed        // fBoundsIsDirty before we set it
12170e747d6d0a794242bd214fa44a6a179baeadfdf9Mike Reed        if (!fBoundsIsDirty && matrix.rectStaysRect() && fPts.count() > 1) {
12180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            // if we're empty, fastbounds should not be mapped
12190e747d6d0a794242bd214fa44a6a179baeadfdf9Mike Reed            matrix.mapRect(&dst->fBounds, fBounds);
12200e747d6d0a794242bd214fa44a6a179baeadfdf9Mike Reed            dst->fBoundsIsDirty = false;
12210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        } else {
12220e747d6d0a794242bd214fa44a6a179baeadfdf9Mike Reed            dst->fBoundsIsDirty = true;
12230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
12240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
12250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (this != dst) {
12260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            dst->fVerbs = fVerbs;
12270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            dst->fPts.setCount(fPts.count());
12280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            dst->fFillType = fFillType;
12291cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            dst->fSegmentMask = fSegmentMask;
12301cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            dst->fConvexity = fConvexity;
12310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
1232ebb0af8e21433525397cefdec3a8903e3da966b0Romain Guy
1233ebb0af8e21433525397cefdec3a8903e3da966b0Romain Guy        if (!matrix.isIdentity()) {
1234ebb0af8e21433525397cefdec3a8903e3da966b0Romain Guy            GEN_ID_PTR_INC(dst);
1235ebb0af8e21433525397cefdec3a8903e3da966b0Romain Guy        }
12360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        matrix.mapPoints(dst->fPts.begin(), fPts.begin(), fPts.count());
1237ebb0af8e21433525397cefdec3a8903e3da966b0Romain Guy
12380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkDEBUGCODE(dst->validate();)
12390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
12400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
12410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
12420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
12430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
12440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
12451cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergerenum SegmentState {
12464f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    kEmptyContour_SegmentState,   // The current contour is empty. We may be
12474f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                                  // starting processing or we may have just
12484f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                                  // closed a contour.
12491cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    kAfterMove_SegmentState,      // We have seen a move, but nothing else.
12501cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    kAfterPrimitive_SegmentState  // We have seen a primitive but not yet
12511cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                                  // closed the path. Also the initial state.
12520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project};
12530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
12540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectSkPath::Iter::Iter() {
12550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#ifdef SK_DEBUG
12560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fPts = NULL;
12570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fMoveTo.fX = fMoveTo.fY = fLastPt.fX = fLastPt.fY = 0;
12581cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    fForceClose = fCloseLine = false;
12594f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    fSegmentState = kEmptyContour_SegmentState;
12600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
12610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // need to init enough to make next() harmlessly return kDone_Verb
12620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fVerbs = NULL;
12630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fVerbStop = NULL;
12640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fNeedClose = false;
12650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
12660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
12670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectSkPath::Iter::Iter(const SkPath& path, bool forceClose) {
12680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->setPath(path, forceClose);
12690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
12700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
12710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPath::Iter::setPath(const SkPath& path, bool forceClose) {
12720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fPts = path.fPts.begin();
12730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fVerbs = path.fVerbs.begin();
12740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fVerbStop = path.fVerbs.end();
12751cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    fLastPt.fX = fLastPt.fY = 0;
12761cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    fMoveTo.fX = fMoveTo.fY = 0;
12770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fForceClose = SkToU8(forceClose);
12780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fNeedClose = false;
12794f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    fSegmentState = kEmptyContour_SegmentState;
12800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
12810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
12820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectbool SkPath::Iter::isClosedContour() const {
12830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (fVerbs == NULL || fVerbs == fVerbStop) {
12840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return false;
12850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
12860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (fForceClose) {
12870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return true;
12880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
12890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
12900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const uint8_t* verbs = fVerbs;
12910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const uint8_t* stop = fVerbStop;
129240528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
12930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (kMove_Verb == *verbs) {
12940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        verbs += 1; // skip the initial moveto
12950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
12960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
12970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    while (verbs < stop) {
129840528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        unsigned v = *verbs++;
12990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (kMove_Verb == v) {
13000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            break;
13010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
13020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (kClose_Verb == v) {
13030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            return true;
13040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
13050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
13060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return false;
13070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
13080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
13090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectSkPath::Verb SkPath::Iter::autoClose(SkPoint pts[2]) {
13100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (fLastPt != fMoveTo) {
13117ecd8eaf1681919d6be87612a374739541b31996Feng Qian        // A special case: if both points are NaN, SkPoint::operation== returns
13127ecd8eaf1681919d6be87612a374739541b31996Feng Qian        // false, but the iterator expects that they are treated as the same.
13137ecd8eaf1681919d6be87612a374739541b31996Feng Qian        // (consider SkPoint is a 2-dimension float point).
1314cac9f6a367de0788a55059ca6b34ed5b3f741390Mike Reed        if (SkScalarIsNaN(fLastPt.fX) || SkScalarIsNaN(fLastPt.fY) ||
1315cac9f6a367de0788a55059ca6b34ed5b3f741390Mike Reed            SkScalarIsNaN(fMoveTo.fX) || SkScalarIsNaN(fMoveTo.fY)) {
13167ecd8eaf1681919d6be87612a374739541b31996Feng Qian            return kClose_Verb;
13177ecd8eaf1681919d6be87612a374739541b31996Feng Qian        }
1318aa4832adcc7eba085987357591bcfeb530ba7b0dMike Reed
13190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (pts) {
13200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            pts[0] = fLastPt;
13210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            pts[1] = fMoveTo;
13220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
13230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fLastPt = fMoveTo;
13240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fCloseLine = true;
13250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return kLine_Verb;
13261cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    } else {
13271cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        pts[0] = fMoveTo;
13281cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        return kClose_Verb;
13290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
13300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
13310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
13320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectbool SkPath::Iter::cons_moveTo(SkPoint pts[1]) {
13331cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    if (fSegmentState == kAfterMove_SegmentState) {
13341cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        // Set the first return pt to the move pt
13350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (pts) {
13360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            *pts = fMoveTo;
13370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
13381cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        fSegmentState = kAfterPrimitive_SegmentState;
13390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    } else {
13401cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkASSERT(fSegmentState == kAfterPrimitive_SegmentState);
13411cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger         // Set the first return pt to the last pt of the previous primitive.
13420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (pts) {
13430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            *pts = fPts[-1];
13440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
13450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
13460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return false;
13470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
13480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
13491cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergervoid SkPath::Iter::consumeDegenerateSegments() {
13501cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    // We need to step over anything that will not move the current draw point
13511cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    // forward before the next move is seen
13521cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    const uint8_t* lastMoveVerb = 0;
13531cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    const SkPoint* lastMovePt = 0;
13541cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    SkPoint lastPt = fLastPt;
13551cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    while (fVerbs != fVerbStop) {
13561cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        unsigned verb = *fVerbs;
13571cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        switch (verb) {
13581cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            case kMove_Verb:
13591cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                // Keep a record of this most recent move
13601cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                lastMoveVerb = fVerbs;
13611cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                lastMovePt = fPts;
13621cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                lastPt = fPts[0];
13631cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                fVerbs++;
13641cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                fPts++;
13651cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                break;
13661cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
13671cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            case kClose_Verb:
13681cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                // A close when we are in a segment is always valid
13691cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                if (fSegmentState == kAfterPrimitive_SegmentState) {
13701cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                    return;
13711cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                }
13721cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                // A close at any other time must be ignored
13731cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                fVerbs++;
13741cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                break;
13751cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
13761cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            case kLine_Verb:
13771cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                if (!IsLineDegenerate(lastPt, fPts[0])) {
13781cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                    if (lastMoveVerb) {
13791cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                        fVerbs = lastMoveVerb;
13801cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                        fPts = lastMovePt;
13811cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                        return;
13821cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                    }
13831cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                    return;
13841cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                }
13851cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                // Ignore this line and continue
13861cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                fVerbs++;
13871cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                fPts++;
13881cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                break;
13891cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
13901cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            case kQuad_Verb:
13911cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                if (!IsQuadDegenerate(lastPt, fPts[0], fPts[1])) {
13921cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                    if (lastMoveVerb) {
13931cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                        fVerbs = lastMoveVerb;
13941cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                        fPts = lastMovePt;
13951cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                        return;
13961cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                    }
13971cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                    return;
13981cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                }
13991cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                // Ignore this line and continue
14001cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                fVerbs++;
14011cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                fPts += 2;
14021cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                break;
14031cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
14041cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            case kCubic_Verb:
14051cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                if (!IsCubicDegenerate(lastPt, fPts[0], fPts[1], fPts[2])) {
14061cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                    if (lastMoveVerb) {
14071cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                        fVerbs = lastMoveVerb;
14081cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                        fPts = lastMovePt;
14091cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                        return;
14101cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                    }
14111cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                    return;
14121cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                }
14131cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                // Ignore this line and continue
14141cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                fVerbs++;
14151cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                fPts += 3;
14161cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                break;
14171cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
14181cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            default:
14191cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                SkDEBUGFAIL("Should never see kDone_Verb");
14201cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        }
14211cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    }
14221cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
14231cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
14240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectSkPath::Verb SkPath::Iter::next(SkPoint pts[4]) {
14251cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    this->consumeDegenerateSegments();
14261cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
14270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (fVerbs == fVerbStop) {
14281cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        // Close the curve if requested and if there is some curve to close
14291cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        if (fNeedClose && fSegmentState == kAfterPrimitive_SegmentState) {
14300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (kLine_Verb == this->autoClose(pts)) {
14310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                return kLine_Verb;
14320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
14330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            fNeedClose = false;
14340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            return kClose_Verb;
14350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
14360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return kDone_Verb;
14370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
14380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
14390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    unsigned        verb = *fVerbs++;
14400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const SkPoint*  srcPts = fPts;
14410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
14420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    switch (verb) {
14430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case kMove_Verb:
14440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (fNeedClose) {
14450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                fVerbs -= 1;
14460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                verb = this->autoClose(pts);
14470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                if (verb == kClose_Verb) {
14480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    fNeedClose = false;
14490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                }
14500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                return (Verb)verb;
14510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
14520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (fVerbs == fVerbStop) {    // might be a trailing moveto
14530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                return kDone_Verb;
14540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
14550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            fMoveTo = *srcPts;
14560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (pts) {
14570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                pts[0] = *srcPts;
14580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
14590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            srcPts += 1;
14601cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            fSegmentState = kAfterMove_SegmentState;
14611cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            fLastPt = fMoveTo;
14620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            fNeedClose = fForceClose;
14630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            break;
14640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case kLine_Verb:
14650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (this->cons_moveTo(pts)) {
14660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                return kMove_Verb;
14670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
14680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (pts) {
14690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                pts[1] = srcPts[0];
14700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
14710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            fLastPt = srcPts[0];
14720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            fCloseLine = false;
14730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            srcPts += 1;
14740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            break;
14750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case kQuad_Verb:
14760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (this->cons_moveTo(pts)) {
14770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                return kMove_Verb;
14780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
14790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (pts) {
14800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                memcpy(&pts[1], srcPts, 2 * sizeof(SkPoint));
14810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
14820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            fLastPt = srcPts[1];
14830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            srcPts += 2;
14840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            break;
14850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case kCubic_Verb:
14860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (this->cons_moveTo(pts)) {
14870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                return kMove_Verb;
14880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
14890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (pts) {
14900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                memcpy(&pts[1], srcPts, 3 * sizeof(SkPoint));
14910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
14920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            fLastPt = srcPts[2];
14930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            srcPts += 3;
14940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            break;
14950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case kClose_Verb:
14960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            verb = this->autoClose(pts);
14970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (verb == kLine_Verb) {
14980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                fVerbs -= 1;
14990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            } else {
15000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                fNeedClose = false;
15014f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                fSegmentState = kEmptyContour_SegmentState;
15020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
15031cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            fLastPt = fMoveTo;
15040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            break;
15050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
15060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fPts = srcPts;
15070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return (Verb)verb;
15080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
15090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
15100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
15110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
15121cab2921ab279367f8206cdadc9259d12e603548Derek SollenbergerSkPath::RawIter::RawIter() {
15131cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger#ifdef SK_DEBUG
15141cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    fPts = NULL;
15151cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    fMoveTo.fX = fMoveTo.fY = fLastPt.fX = fLastPt.fY = 0;
15161cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger#endif
15171cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    // need to init enough to make next() harmlessly return kDone_Verb
15181cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    fVerbs = NULL;
15191cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    fVerbStop = NULL;
15200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
15210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
15221cab2921ab279367f8206cdadc9259d12e603548Derek SollenbergerSkPath::RawIter::RawIter(const SkPath& path) {
15231cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    this->setPath(path);
15240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
15250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
15261cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergervoid SkPath::RawIter::setPath(const SkPath& path) {
15271cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    fPts = path.fPts.begin();
15281cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    fVerbs = path.fVerbs.begin();
15291cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    fVerbStop = path.fVerbs.end();
15301cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    fMoveTo.fX = fMoveTo.fY = 0;
15311cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    fLastPt.fX = fLastPt.fY = 0;
15320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
15330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
15341cab2921ab279367f8206cdadc9259d12e603548Derek SollenbergerSkPath::Verb SkPath::RawIter::next(SkPoint pts[4]) {
15351cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    if (fVerbs == fVerbStop) {
15361cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        return kDone_Verb;
15370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
15380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
15391cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    unsigned        verb = *fVerbs++;
15401cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    const SkPoint*  srcPts = fPts;
15410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
15421cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    switch (verb) {
15431cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        case kMove_Verb:
15441cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            if (pts) {
15451cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                pts[0] = *srcPts;
15461cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            }
15471cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            fMoveTo = srcPts[0];
15481cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            fLastPt = fMoveTo;
15491cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            srcPts += 1;
15501cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            break;
15511cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        case kLine_Verb:
15521cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            if (pts) {
15531cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                pts[0] = fLastPt;
15541cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                pts[1] = srcPts[0];
15551cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            }
15561cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            fLastPt = srcPts[0];
15571cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            srcPts += 1;
15581cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            break;
15591cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        case kQuad_Verb:
15601cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            if (pts) {
15611cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                pts[0] = fLastPt;
15621cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                memcpy(&pts[1], srcPts, 2 * sizeof(SkPoint));
15631cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            }
15641cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            fLastPt = srcPts[1];
15651cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            srcPts += 2;
15661cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            break;
15671cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        case kCubic_Verb:
15681cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            if (pts) {
15691cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                pts[0] = fLastPt;
15701cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                memcpy(&pts[1], srcPts, 3 * sizeof(SkPoint));
15711cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            }
15721cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            fLastPt = srcPts[2];
15731cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            srcPts += 3;
15741cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            break;
15751cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        case kClose_Verb:
15761cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            fLastPt = fMoveTo;
15771cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            if (pts) {
15781cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                pts[0] = fMoveTo;
15791cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            }
15801cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            break;
15810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
15821cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    fPts = srcPts;
15831cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    return (Verb)verb;
15840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
15850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
15861cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger///////////////////////////////////////////////////////////////////////////////
15871cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
15880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project/*
15890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    Format in flattened buffer: [ptCount, verbCount, pts[], verbs[]]
15900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project*/
15910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
159235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenbergervoid SkPath::flatten(SkWriter32& buffer) const {
15930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkDEBUGCODE(this->validate();)
15940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
15950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    buffer.write32(fPts.count());
15960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    buffer.write32(fVerbs.count());
15971cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    buffer.write32((fFillType << 8) | fSegmentMask);
15980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    buffer.writeMul4(fPts.begin(), sizeof(SkPoint) * fPts.count());
15990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    buffer.writePad(fVerbs.begin(), fVerbs.count());
16000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
16010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
160235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenbergervoid SkPath::unflatten(SkReader32& buffer) {
16030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fPts.setCount(buffer.readS32());
16040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fVerbs.setCount(buffer.readS32());
16051cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    uint32_t packed = buffer.readS32();
16061cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    fFillType = packed >> 8;
16071cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    fSegmentMask = packed & 0xFF;
16080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    buffer.read(fPts.begin(), sizeof(SkPoint) * fPts.count());
16090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    buffer.read(fVerbs.begin(), fVerbs.count());
161087b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenberger
161187b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenberger    GEN_ID_INC;
16120b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    DIRTY_AFTER_EDIT;
16130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
16140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkDEBUGCODE(this->validate();)
16150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
16160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
16170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
16180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
16190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPath::dump(bool forceClose, const char title[]) const {
16200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    Iter    iter(*this, forceClose);
16210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPoint pts[4];
16220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    Verb    verb;
16230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
16240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkDebugf("path: forceClose=%s %s\n", forceClose ? "true" : "false",
16250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project             title ? title : "");
16260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
16270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    while ((verb = iter.next(pts)) != kDone_Verb) {
16280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        switch (verb) {
16290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            case kMove_Verb:
16300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#ifdef SK_CAN_USE_FLOAT
16310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                SkDebugf("  path: moveTo [%g %g]\n",
16320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                        SkScalarToFloat(pts[0].fX), SkScalarToFloat(pts[0].fY));
16330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#else
16340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                SkDebugf("  path: moveTo [%x %x]\n", pts[0].fX, pts[0].fY);
16350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
16360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                break;
16370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            case kLine_Verb:
16380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#ifdef SK_CAN_USE_FLOAT
16390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                SkDebugf("  path: lineTo [%g %g]\n",
16400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                        SkScalarToFloat(pts[1].fX), SkScalarToFloat(pts[1].fY));
16410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#else
16420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                SkDebugf("  path: lineTo [%x %x]\n", pts[1].fX, pts[1].fY);
16430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
16440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                break;
16450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            case kQuad_Verb:
16460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#ifdef SK_CAN_USE_FLOAT
16470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                SkDebugf("  path: quadTo [%g %g] [%g %g]\n",
16480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                        SkScalarToFloat(pts[1].fX), SkScalarToFloat(pts[1].fY),
16490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                        SkScalarToFloat(pts[2].fX), SkScalarToFloat(pts[2].fY));
16500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#else
16510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                SkDebugf("  path: quadTo [%x %x] [%x %x]\n",
16520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                         pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY);
16530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
16540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                break;
16550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            case kCubic_Verb:
16560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#ifdef SK_CAN_USE_FLOAT
16570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                SkDebugf("  path: cubeTo [%g %g] [%g %g] [%g %g]\n",
16580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                        SkScalarToFloat(pts[1].fX), SkScalarToFloat(pts[1].fY),
16590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                        SkScalarToFloat(pts[2].fX), SkScalarToFloat(pts[2].fY),
16600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                        SkScalarToFloat(pts[3].fX), SkScalarToFloat(pts[3].fY));
16610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#else
16620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                SkDebugf("  path: cubeTo [%x %x] [%x %x] [%x %x]\n",
16630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                         pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY,
16640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                         pts[3].fX, pts[3].fY);
16650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
16660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                break;
16670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            case kClose_Verb:
16680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                SkDebugf("  path: close\n");
16690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                break;
16700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            default:
16710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                SkDebugf("  path: UNKNOWN VERB %d, aborting dump...\n", verb);
16720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                verb = kDone_Verb;  // stop the loop
16730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                break;
16740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
16750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
16760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkDebugf("path: done %s\n", title ? title : "");
16770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
16780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1679a8b45f65acb9d306cb57edd886728933f13d4424Mike Reedvoid SkPath::dump() const {
1680a8b45f65acb9d306cb57edd886728933f13d4424Mike Reed    this->dump(false);
1681a8b45f65acb9d306cb57edd886728933f13d4424Mike Reed}
1682a8b45f65acb9d306cb57edd886728933f13d4424Mike Reed
1683a8b45f65acb9d306cb57edd886728933f13d4424Mike Reed#ifdef SK_DEBUG
1684a8b45f65acb9d306cb57edd886728933f13d4424Mike Reedvoid SkPath::validate() const {
1685a8b45f65acb9d306cb57edd886728933f13d4424Mike Reed    SkASSERT(this != NULL);
1686a8b45f65acb9d306cb57edd886728933f13d4424Mike Reed    SkASSERT((fFillType & ~3) == 0);
1687a8b45f65acb9d306cb57edd886728933f13d4424Mike Reed    fPts.validate();
1688a8b45f65acb9d306cb57edd886728933f13d4424Mike Reed    fVerbs.validate();
168940528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
1690a8b45f65acb9d306cb57edd886728933f13d4424Mike Reed    if (!fBoundsIsDirty) {
1691a8b45f65acb9d306cb57edd886728933f13d4424Mike Reed        SkRect bounds;
1692a8b45f65acb9d306cb57edd886728933f13d4424Mike Reed        compute_pt_bounds(&bounds, fPts);
1693a8b45f65acb9d306cb57edd886728933f13d4424Mike Reed        if (fPts.count() <= 1) {
1694a8b45f65acb9d306cb57edd886728933f13d4424Mike Reed            // if we're empty, fBounds may be empty but translated, so we can't
1695a8b45f65acb9d306cb57edd886728933f13d4424Mike Reed            // necessarily compare to bounds directly
1696a8b45f65acb9d306cb57edd886728933f13d4424Mike Reed            // try path.addOval(2, 2, 2, 2) which is empty, but the bounds will
1697a8b45f65acb9d306cb57edd886728933f13d4424Mike Reed            // be [2, 2, 2, 2]
1698a8b45f65acb9d306cb57edd886728933f13d4424Mike Reed            SkASSERT(bounds.isEmpty());
1699a8b45f65acb9d306cb57edd886728933f13d4424Mike Reed            SkASSERT(fBounds.isEmpty());
1700a8b45f65acb9d306cb57edd886728933f13d4424Mike Reed        } else {
17011cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            if (bounds.isEmpty()) {
17021cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                SkASSERT(fBounds.isEmpty());
17031cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            } else {
17041cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                if (!fBounds.isEmpty()) {
17051cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                    SkASSERT(fBounds.contains(bounds));
17061cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                }
17071cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            }
17081cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        }
17091cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    }
17101cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
17111cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    uint32_t mask = 0;
17121cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    for (int i = 0; i < fVerbs.count(); i++) {
17131cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        switch (fVerbs[i]) {
17141cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            case kLine_Verb:
17151cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                mask |= kLine_SegmentMask;
17161cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                break;
17171cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            case kQuad_Verb:
17181cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                mask |= kQuad_SegmentMask;
17191cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                break;
17201cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            case kCubic_Verb:
17211cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                mask |= kCubic_SegmentMask;
1722a8b45f65acb9d306cb57edd886728933f13d4424Mike Reed        }
1723a8b45f65acb9d306cb57edd886728933f13d4424Mike Reed    }
17241cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    SkASSERT(mask == fSegmentMask);
1725a8b45f65acb9d306cb57edd886728933f13d4424Mike Reed}
17260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
1727a8b45f65acb9d306cb57edd886728933f13d4424Mike Reed
172835e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger///////////////////////////////////////////////////////////////////////////////
172935e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger
173035e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenbergerstatic int sign(SkScalar x) { return x < 0; }
173135e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger#define kValueNeverReturnedBySign   2
173235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger
173335e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenbergerstatic int CrossProductSign(const SkVector& a, const SkVector& b) {
17341cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    return SkScalarSignAsInt(SkPoint::CrossProduct(a, b));
173535e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger}
173635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger
173735e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger// only valid for a single contour
173835e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenbergerstruct Convexicator {
17390b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    Convexicator() : fPtCount(0), fConvexity(SkPath::kConvex_Convexity) {
174035e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        fSign = 0;
174135e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        // warnings
174235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        fCurrPt.set(0, 0);
174335e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        fVec0.set(0, 0);
174435e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        fVec1.set(0, 0);
174535e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        fFirstVec.set(0, 0);
174635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger
174735e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        fDx = fDy = 0;
174835e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        fSx = fSy = kValueNeverReturnedBySign;
174935e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    }
175035e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger
175135e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    SkPath::Convexity getConvexity() const { return fConvexity; }
175235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger
175335e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    void addPt(const SkPoint& pt) {
175435e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        if (SkPath::kConcave_Convexity == fConvexity) {
175535e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            return;
175635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        }
175735e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger
175835e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        if (0 == fPtCount) {
175935e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            fCurrPt = pt;
176035e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            ++fPtCount;
176135e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        } else {
176235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            SkVector vec = pt - fCurrPt;
176335e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            if (vec.fX || vec.fY) {
176435e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                fCurrPt = pt;
176535e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                if (++fPtCount == 2) {
176635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                    fFirstVec = fVec1 = vec;
176735e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                } else {
176835e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                    SkASSERT(fPtCount > 2);
176935e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                    this->addVec(vec);
177035e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                }
177135e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger
177235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                int sx = sign(vec.fX);
177335e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                int sy = sign(vec.fY);
177435e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                fDx += (sx != fSx);
177535e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                fDy += (sy != fSy);
177635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                fSx = sx;
177735e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                fSy = sy;
177835e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger
177935e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                if (fDx > 3 || fDy > 3) {
178035e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                    fConvexity = SkPath::kConcave_Convexity;
178135e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                }
178235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            }
178335e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        }
178435e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    }
178535e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger
178635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    void close() {
178735e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        if (fPtCount > 2) {
178835e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            this->addVec(fFirstVec);
178935e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        }
179035e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    }
179135e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger
179235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenbergerprivate:
179335e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    void addVec(const SkVector& vec) {
179435e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        SkASSERT(vec.fX || vec.fY);
179535e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        fVec0 = fVec1;
179635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        fVec1 = vec;
179735e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        int sign = CrossProductSign(fVec0, fVec1);
179835e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        if (0 == fSign) {
179935e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            fSign = sign;
180035e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        } else if (sign) {
18010b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger            if (fSign != sign) {
180235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                fConvexity = SkPath::kConcave_Convexity;
180335e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            }
180435e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        }
180535e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    }
180635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger
180735e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    SkPoint             fCurrPt;
180835e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    SkVector            fVec0, fVec1, fFirstVec;
180935e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    int                 fPtCount;   // non-degenerate points
181035e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    int                 fSign;
181135e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    SkPath::Convexity   fConvexity;
181235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    int                 fDx, fDy, fSx, fSy;
181335e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger};
181435e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger
181535e2e62b55598210f6999fc2ea26ff8f41446ffeDerek SollenbergerSkPath::Convexity SkPath::ComputeConvexity(const SkPath& path) {
181635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    SkPoint         pts[4];
181735e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    SkPath::Verb    verb;
181835e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    SkPath::Iter    iter(path, true);
181935e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger
182035e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    int             contourCount = 0;
182135e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    int             count;
182235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    Convexicator    state;
182335e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger
182435e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
182535e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        switch (verb) {
182635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            case kMove_Verb:
182735e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                if (++contourCount > 1) {
182835e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                    return kConcave_Convexity;
182935e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                }
183035e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                pts[1] = pts[0];
183135e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                count = 1;
183235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                break;
183335e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            case kLine_Verb: count = 1; break;
183435e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            case kQuad_Verb: count = 2; break;
183535e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            case kCubic_Verb: count = 3; break;
183635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            case kClose_Verb:
183735e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                state.close();
183835e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                count = 0;
183935e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                break;
184035e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            default:
18411cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                SkDEBUGFAIL("bad verb");
184235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                return kConcave_Convexity;
184335e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        }
184435e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger
184535e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        for (int i = 1; i <= count; i++) {
184635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            state.addPt(pts[i]);
184735e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        }
184835e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        // early exit
184935e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        if (kConcave_Convexity == state.getConvexity()) {
185035e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            return kConcave_Convexity;
185135e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        }
185235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    }
185335e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    return state.getConvexity();
185435e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger}
18551cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
18561cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger///////////////////////////////////////////////////////////////////////////////
18571cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
18581cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergerclass ContourIter {
18591cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergerpublic:
18601cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    ContourIter(const SkTDArray<uint8_t>& verbs, const SkTDArray<SkPoint>& pts);
18611cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
18621cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    bool done() const { return fDone; }
18631cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    // if !done() then these may be called
18641cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    int count() const { return fCurrPtCount; }
18651cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    const SkPoint* pts() const { return fCurrPt; }
18661cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    void next();
18671cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
18681cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergerprivate:
18691cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    int fCurrPtCount;
18701cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    const SkPoint* fCurrPt;
18711cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    const uint8_t* fCurrVerb;
18721cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    const uint8_t* fStopVerbs;
18731cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    bool fDone;
18741cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    SkDEBUGCODE(int fContourCounter;)
18751cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger};
18761cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
18771cab2921ab279367f8206cdadc9259d12e603548Derek SollenbergerContourIter::ContourIter(const SkTDArray<uint8_t>& verbs,
18781cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                         const SkTDArray<SkPoint>& pts) {
18791cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    fStopVerbs = verbs.begin() + verbs.count();
18801cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
18811cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    fDone = false;
18821cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    fCurrPt = pts.begin();
18831cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    fCurrVerb = verbs.begin();
18841cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    fCurrPtCount = 0;
18851cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    SkDEBUGCODE(fContourCounter = 0;)
18861cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    this->next();
18871cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
18881cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
18891cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergervoid ContourIter::next() {
18901cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    if (fCurrVerb >= fStopVerbs) {
18911cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        fDone = true;
18921cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    }
18931cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    if (fDone) {
18941cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        return;
18951cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    }
18961cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
18971cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    // skip pts of prev contour
18981cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    fCurrPt += fCurrPtCount;
18991cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
19001cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    SkASSERT(SkPath::kMove_Verb == fCurrVerb[0]);
19011cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    int ptCount = 1;    // moveTo
19021cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    const uint8_t* verbs = fCurrVerb;
19031cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
19041cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    for (++verbs; verbs < fStopVerbs; ++verbs) {
19051cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        switch (*verbs) {
19061cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            case SkPath::kMove_Verb:
19071cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                goto CONTOUR_END;
19081cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            case SkPath::kLine_Verb:
19091cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                ptCount += 1;
19101cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                break;
19111cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            case SkPath::kQuad_Verb:
19121cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                ptCount += 2;
19131cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                break;
19141cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            case SkPath::kCubic_Verb:
19151cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                ptCount += 3;
19161cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                break;
19171cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            default:    // kClose_Verb, just keep going
19181cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                break;
19191cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        }
19201cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    }
19211cab2921ab279367f8206cdadc9259d12e603548Derek SollenbergerCONTOUR_END:
19221cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    fCurrPtCount = ptCount;
19231cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    fCurrVerb = verbs;
19241cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    SkDEBUGCODE(++fContourCounter;)
19251cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
19261cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
19274f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger// returns cross product of (p1 - p0) and (p2 - p0)
19281cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergerstatic SkScalar cross_prod(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2) {
19294f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    SkScalar cross = SkPoint::CrossProduct(p1 - p0, p2 - p0);
19304f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    // We may get 0 when the above subtracts underflow. We expect this to be
19314f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    // very rare and lazily promote to double.
19324f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    if (0 == cross) {
19334f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        double p0x = SkScalarToDouble(p0.fX);
19344f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        double p0y = SkScalarToDouble(p0.fY);
19354f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger
19364f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        double p1x = SkScalarToDouble(p1.fX);
19374f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        double p1y = SkScalarToDouble(p1.fY);
19384f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger
19394f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        double p2x = SkScalarToDouble(p2.fX);
19404f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        double p2y = SkScalarToDouble(p2.fY);
19414f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger
19424f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        cross = SkDoubleToScalar((p1x - p0x) * (p2y - p0y) -
19434f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                                 (p1y - p0y) * (p2x - p0x));
19444f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger
19454f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    }
19464f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    return cross;
19471cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
19481cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
19494f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger// Returns the first pt with the maximum Y coordinate
19501cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergerstatic int find_max_y(const SkPoint pts[], int count) {
19511cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    SkASSERT(count > 0);
19521cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    SkScalar max = pts[0].fY;
19534f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    int firstIndex = 0;
19541cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    for (int i = 1; i < count; ++i) {
19554f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        SkScalar y = pts[i].fY;
19564f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        if (y > max) {
19574f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            max = y;
19584f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            firstIndex = i;
19591cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        }
19601cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    }
19614f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    return firstIndex;
19621cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
19631cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
19641cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergerstatic int find_diff_pt(const SkPoint pts[], int index, int n, int inc) {
19651cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    int i = index;
19661cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    for (;;) {
19671cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        i = (i + inc) % n;
19681cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        if (i == index) {   // we wrapped around, so abort
19691cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            break;
19701cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        }
19711cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        if (pts[index] != pts[i]) { // found a different point, success!
19721cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            break;
19731cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        }
19741cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    }
19751cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    return i;
19761cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
19771cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
19784f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger/**
19794f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger *  Starting at index, and moving forward (incrementing), find the xmin and
19804f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger *  xmax of the contiguous points that have the same Y.
19814f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger */
19824f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenbergerstatic int find_min_max_x_at_y(const SkPoint pts[], int index, int n,
19834f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                               int* maxIndexPtr) {
19844f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    const SkScalar y = pts[index].fY;
19854f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    SkScalar min = pts[index].fX;
19864f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    SkScalar max = min;
19874f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    int minIndex = index;
19884f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    int maxIndex = index;
19894f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    for (int i = index + 1; i < n; ++i) {
19904f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        if (pts[i].fY != y) {
19914f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            break;
19924f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        }
19934f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        SkScalar x = pts[i].fX;
19944f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        if (x < min) {
19954f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            min = x;
19964f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            minIndex = i;
19974f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        } else if (x > max) {
19984f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            max = x;
19994f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            maxIndex = i;
20004f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        }
20014f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    }
20024f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    *maxIndexPtr = maxIndex;
20034f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    return minIndex;
20044f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger}
20054f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger
20064f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenbergerstatic bool crossToDir(SkScalar cross, SkPath::Direction* dir) {
20074f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    if (dir) {
20084f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        *dir = cross > 0 ? SkPath::kCW_Direction : SkPath::kCCW_Direction;
20094f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    }
20104f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    return true;
20114f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger}
20124f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger
20134f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger#if 0
20144f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger#include "SkString.h"
20154f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger#include "../utils/SkParsePath.h"
20164f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenbergerstatic void dumpPath(const SkPath& path) {
20174f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    SkString str;
20184f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    SkParsePath::ToSVGString(path, &str);
20194f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    SkDebugf("%s\n", str.c_str());
20204f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger}
20214f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger#endif
20224f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger
20234f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger/*
20244f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger *  We loop through all contours, and keep the computed cross-product of the
20254f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger *  contour that contained the global y-max. If we just look at the first
20264f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger *  contour, we may find one that is wound the opposite way (correctly) since
20274f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger *  it is the interior of a hole (e.g. 'o'). Thus we must find the contour
20284f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger *  that is outer most (or at least has the global y-max) before we can consider
20294f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger *  its cross product.
20304f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger */
20311cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergerbool SkPath::cheapComputeDirection(Direction* dir) const {
20324f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger//    dumpPath(*this);
20331cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    // don't want to pay the cost for computing this if it
20341cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    // is unknown, so we don't call isConvex()
20351cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    const Convexity conv = this->getConvexityOrUnknown();
20361cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
20371cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    ContourIter iter(fVerbs, fPts);
20381cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
20394f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    // initialize with our logical y-min
20404f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    SkScalar ymax = this->getBounds().fTop;
20414f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    SkScalar ymaxCross = 0;
20424f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger
20431cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    for (; !iter.done(); iter.next()) {
20441cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        int n = iter.count();
20451cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        if (n < 3) {
20461cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            continue;
20471cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        }
20481cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
20491cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        const SkPoint* pts = iter.pts();
20501cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkScalar cross = 0;
20511cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        if (kConvex_Convexity == conv) {
20521cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            // we loop, skipping over degenerate or flat segments that will
20531cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            // return 0 for the cross-product
20541cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            for (int i = 0; i < n - 2; ++i) {
20551cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                cross = cross_prod(pts[i], pts[i + 1], pts[i + 2]);
20561cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                if (cross) {
20574f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                    // early-exit, as kConvex is assumed to have only 1
20584f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                    // non-degenerate contour
20594f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                    return crossToDir(cross, dir);
20601cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                }
20611cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            }
20621cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        } else {
20631cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            int index = find_max_y(pts, n);
20644f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            if (pts[index].fY < ymax) {
20651cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                continue;
20661cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            }
20674f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger
20684f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            // If there is more than 1 distinct point at the y-max, we take the
20694f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            // x-min and x-max of them and just subtract to compute the dir.
20704f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            if (pts[(index + 1) % n].fY == pts[index].fY) {
20714f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                int maxIndex;
20724f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                int minIndex = find_min_max_x_at_y(pts, index, n, &maxIndex);
20734f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                if (minIndex == maxIndex) {
20744f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                    goto TRY_CROSSPROD;
20754f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                }
20764f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                SkASSERT(pts[minIndex].fY == pts[index].fY);
20774f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                SkASSERT(pts[maxIndex].fY == pts[index].fY);
20784f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                SkASSERT(pts[minIndex].fX <= pts[maxIndex].fX);
20794f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                // we just subtract the indices, and let that auto-convert to
20804f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                // SkScalar, since we just want - or + to signal the direction.
20814f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                cross = minIndex - maxIndex;
20824f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            } else {
20834f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                TRY_CROSSPROD:
20844f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                // Find a next and prev index to use for the cross-product test,
20854f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                // but we try to find pts that form non-zero vectors from pts[index]
20864f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                //
20874f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                // Its possible that we can't find two non-degenerate vectors, so
20884f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                // we have to guard our search (e.g. all the pts could be in the
20894f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                // same place).
20904f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger
20914f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                // we pass n - 1 instead of -1 so we don't foul up % operator by
20924f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                // passing it a negative LH argument.
20934f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                int prev = find_diff_pt(pts, index, n, n - 1);
20944f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                if (prev == index) {
20954f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                    // completely degenerate, skip to next contour
20964f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                    continue;
20974f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                }
20984f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                int next = find_diff_pt(pts, index, n, 1);
20994f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                SkASSERT(next != index);
21004f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                cross = cross_prod(pts[prev], pts[index], pts[next]);
21014f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                // if we get a zero, but the pts aren't on top of each other, then
21024f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                // we can just look at the direction
21034f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                if (0 == cross) {
21044f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                    // construct the subtract so we get the correct Direction below
21054f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                    cross = pts[index].fX - pts[next].fX;
21064f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                }
21074f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            }
21084f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger
21094f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            if (cross) {
21104f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                // record our best guess so far
21114f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                ymax = pts[index].fY;
21124f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                ymaxCross = cross;
21131cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            }
21141cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        }
21151cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    }
21161cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
21174f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    return ymaxCross ? crossToDir(ymaxCross, dir) : false;
21184f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger}
2119