11cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
20910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project/*
31cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger * Copyright 2008 The Android Open Source Project
40910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *
51cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger * Use of this source code is governed by a BSD-style license that can be
61cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger * found in the LICENSE file.
70910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project */
80910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
91cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkStrokerPriv.h"
110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkGeometry.h"
120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkPath.h"
130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#define kMaxQuadSubdivide   5
150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#define kMaxCubicSubdivide  4
160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic inline bool degenerate_vector(const SkVector& v) {
181cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    return !SkPoint::CanNormalize(v.fX, v.fY);
190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic inline bool normals_too_curvy(const SkVector& norm0, SkVector& norm1) {
220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    /*  root2/2 is a 45-degree angle
230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        make this constant bigger for more subdivisions (but not >= 1)
240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    */
250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    static const SkScalar kFlatEnoughNormalDotProd =
260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                            SK_ScalarSqrt2/2 + SK_Scalar1/10;
270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(kFlatEnoughNormalDotProd > 0 &&
290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project             kFlatEnoughNormalDotProd < SK_Scalar1);
300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return SkPoint::DotProduct(norm0, norm1) <= kFlatEnoughNormalDotProd;
320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic inline bool normals_too_pinchy(const SkVector& norm0, SkVector& norm1) {
350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    static const SkScalar kTooPinchyNormalDotProd = -SK_Scalar1 * 999 / 1000;
360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return SkPoint::DotProduct(norm0, norm1) <= kTooPinchyNormalDotProd;
380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic bool set_normal_unitnormal(const SkPoint& before, const SkPoint& after,
410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                  SkScalar radius,
420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                  SkVector* normal, SkVector* unitNormal) {
430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (!unitNormal->setNormalize(after.fX - before.fX, after.fY - before.fY)) {
440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return false;
450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    unitNormal->rotateCCW();
470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    unitNormal->scale(radius, normal);
480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return true;
490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic bool set_normal_unitnormal(const SkVector& vec,
520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                  SkScalar radius,
530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                  SkVector* normal, SkVector* unitNormal) {
540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (!unitNormal->setNormalize(vec.fX, vec.fY)) {
550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return false;
560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    unitNormal->rotateCCW();
580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    unitNormal->scale(radius, normal);
590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return true;
600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectclass SkPathStroker {
650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectpublic:
660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPathStroker(SkScalar radius, SkScalar miterLimit, SkPaint::Cap cap,
670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                  SkPaint::Join join);
680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    void moveTo(const SkPoint&);
700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    void lineTo(const SkPoint&);
710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    void quadTo(const SkPoint&, const SkPoint&);
720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    void cubicTo(const SkPoint&, const SkPoint&, const SkPoint&);
730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    void close(bool isLine) { this->finishContour(true, isLine); }
740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    void done(SkPath* dst, bool isLine) {
760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->finishContour(false, isLine);
770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fOuter.addPath(fExtra);
780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        dst->swap(fOuter);
790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectprivate:
820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar    fRadius;
830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar    fInvMiterLimit;
840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkVector    fFirstNormal, fPrevNormal, fFirstUnitNormal, fPrevUnitNormal;
860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPoint     fFirstPt, fPrevPt;  // on original path
870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPoint     fFirstOuterPt;
880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int         fSegmentCount;
890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    bool        fPrevIsLine;
900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkStrokerPriv::CapProc  fCapper;
920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkStrokerPriv::JoinProc fJoiner;
930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPath  fInner, fOuter; // outer is our working answer, inner is temp
950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPath  fExtra;         // added as extra complete contours
960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    void    finishContour(bool close, bool isLine);
980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    void    preJoinTo(const SkPoint&, SkVector* normal, SkVector* unitNormal,
990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                      bool isLine);
1000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    void    postJoinTo(const SkPoint&, const SkVector& normal,
1010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                       const SkVector& unitNormal);
1020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    void    line_to(const SkPoint& currPt, const SkVector& normal);
1040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    void    quad_to(const SkPoint pts[3],
1050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    const SkVector& normalAB, const SkVector& unitNormalAB,
1060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    SkVector* normalBC, SkVector* unitNormalBC,
1070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    int subDivide);
1080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    void    cubic_to(const SkPoint pts[4],
1090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    const SkVector& normalAB, const SkVector& unitNormalAB,
1100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    SkVector* normalCD, SkVector* unitNormalCD,
1110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    int subDivide);
1120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project};
1130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
1150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPathStroker::preJoinTo(const SkPoint& currPt, SkVector* normal,
1170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                              SkVector* unitNormal, bool currIsLine) {
1180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(fSegmentCount >= 0);
1190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar    prevX = fPrevPt.fX;
1210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar    prevY = fPrevPt.fY;
1220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkAssertResult(set_normal_unitnormal(fPrevPt, currPt, fRadius, normal,
1240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                         unitNormal));
1250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (fSegmentCount == 0) {
1270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fFirstNormal = *normal;
1280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fFirstUnitNormal = *unitNormal;
1290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fFirstOuterPt.set(prevX + normal->fX, prevY + normal->fY);
1300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fOuter.moveTo(fFirstOuterPt.fX, fFirstOuterPt.fY);
1320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fInner.moveTo(prevX - normal->fX, prevY - normal->fY);
1330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    } else {    // we have a previous segment
1340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fJoiner(&fOuter, &fInner, fPrevUnitNormal, fPrevPt, *unitNormal,
1350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                fRadius, fInvMiterLimit, fPrevIsLine, currIsLine);
1360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fPrevIsLine = currIsLine;
1380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPathStroker::postJoinTo(const SkPoint& currPt, const SkVector& normal,
1410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                               const SkVector& unitNormal) {
1420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fPrevPt = currPt;
1430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fPrevUnitNormal = unitNormal;
1440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fPrevNormal = normal;
1450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fSegmentCount += 1;
1460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPathStroker::finishContour(bool close, bool currIsLine) {
1490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (fSegmentCount > 0) {
1500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkPoint pt;
1510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (close) {
1530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            fJoiner(&fOuter, &fInner, fPrevUnitNormal, fPrevPt,
1540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    fFirstUnitNormal, fRadius, fInvMiterLimit,
1550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    fPrevIsLine, currIsLine);
1560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            fOuter.close();
1570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            // now add fInner as its own contour
1580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            fInner.getLastPt(&pt);
1590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            fOuter.moveTo(pt.fX, pt.fY);
1600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            fOuter.reversePathTo(fInner);
1610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            fOuter.close();
1620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        } else {    // add caps to start and end
1630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            // cap the end
1640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            fInner.getLastPt(&pt);
1650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            fCapper(&fOuter, fPrevPt, fPrevNormal, pt,
1660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    currIsLine ? &fInner : NULL);
1670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            fOuter.reversePathTo(fInner);
1680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            // cap the start
1690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            fCapper(&fOuter, fFirstPt, -fFirstNormal, fFirstOuterPt,
1700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    fPrevIsLine ? &fInner : NULL);
1710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            fOuter.close();
1720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
1730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fInner.reset();
1750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fSegmentCount = -1;
1760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
1790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectSkPathStroker::SkPathStroker(SkScalar radius, SkScalar miterLimit,
1810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                             SkPaint::Cap cap, SkPaint::Join join)
1820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        : fRadius(radius) {
1830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    /*  This is only used when join is miter_join, but we initialize it here
1850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        so that it is always defined, to fis valgrind warnings.
1860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    */
1870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fInvMiterLimit = 0;
1880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (join == SkPaint::kMiter_Join) {
1900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (miterLimit <= SK_Scalar1) {
1910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            join = SkPaint::kBevel_Join;
1920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        } else {
1930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            fInvMiterLimit = SkScalarInvert(miterLimit);
1940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
1950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fCapper = SkStrokerPriv::CapFactory(cap);
1970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fJoiner = SkStrokerPriv::JoinFactory(join);
1980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fSegmentCount = -1;
1990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fPrevIsLine = false;
2000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
2010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPathStroker::moveTo(const SkPoint& pt) {
2030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (fSegmentCount > 0) {
2040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->finishContour(false, false);
2050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
2060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fSegmentCount = 0;
2070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fFirstPt = fPrevPt = pt;
2080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
2090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPathStroker::line_to(const SkPoint& currPt, const SkVector& normal) {
2110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fOuter.lineTo(currPt.fX + normal.fX, currPt.fY + normal.fY);
2120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fInner.lineTo(currPt.fX - normal.fX, currPt.fY - normal.fY);
2130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
2140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPathStroker::lineTo(const SkPoint& currPt) {
2161cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    if (SkPath::IsLineDegenerate(fPrevPt, currPt)) {
2170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return;
2180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
2190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkVector    normal, unitNormal;
2200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->preJoinTo(currPt, &normal, &unitNormal, true);
2220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->line_to(currPt, normal);
2230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->postJoinTo(currPt, normal, unitNormal);
2240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
2250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPathStroker::quad_to(const SkPoint pts[3],
2270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                      const SkVector& normalAB, const SkVector& unitNormalAB,
2280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                      SkVector* normalBC, SkVector* unitNormalBC,
2290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                      int subDivide) {
2300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (!set_normal_unitnormal(pts[1], pts[2], fRadius,
2310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                               normalBC, unitNormalBC)) {
2320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        // pts[1] nearly equals pts[2], so just draw a line to pts[2]
2330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->line_to(pts[2], normalAB);
2340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        *normalBC = normalAB;
2350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        *unitNormalBC = unitNormalAB;
2360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return;
2370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
2380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (--subDivide >= 0 && normals_too_curvy(unitNormalAB, *unitNormalBC)) {
2400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkPoint     tmp[5];
2410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkVector    norm, unit;
2420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkChopQuadAtHalf(pts, tmp);
2440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->quad_to(&tmp[0], normalAB, unitNormalAB, &norm, &unit, subDivide);
2450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->quad_to(&tmp[2], norm, unit, normalBC, unitNormalBC, subDivide);
2460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    } else {
2470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkVector    normalB, unitB;
2480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkAssertResult(set_normal_unitnormal(pts[0], pts[2], fRadius,
2490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                             &normalB, &unitB));
2500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fOuter.quadTo(  pts[1].fX + normalB.fX, pts[1].fY + normalB.fY,
2520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                        pts[2].fX + normalBC->fX, pts[2].fY + normalBC->fY);
2530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fInner.quadTo(  pts[1].fX - normalB.fX, pts[1].fY - normalB.fY,
2540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                        pts[2].fX - normalBC->fX, pts[2].fY - normalBC->fY);
2550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
2560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
2570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPathStroker::cubic_to(const SkPoint pts[4],
2590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                      const SkVector& normalAB, const SkVector& unitNormalAB,
2600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                      SkVector* normalCD, SkVector* unitNormalCD,
2610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                      int subDivide) {
2620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkVector    ab = pts[1] - pts[0];
2630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkVector    cd = pts[3] - pts[2];
2640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkVector    normalBC, unitNormalBC;
2650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    bool    degenerateAB = degenerate_vector(ab);
2670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    bool    degenerateCD = degenerate_vector(cd);
2680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (degenerateAB && degenerateCD) {
2700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectDRAW_LINE:
2710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->line_to(pts[3], normalAB);
2720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        *normalCD = normalAB;
2730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        *unitNormalCD = unitNormalAB;
2740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return;
2750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
2760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (degenerateAB) {
2780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        ab = pts[2] - pts[0];
2790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        degenerateAB = degenerate_vector(ab);
2800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
2810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (degenerateCD) {
2820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        cd = pts[3] - pts[1];
2830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        degenerateCD = degenerate_vector(cd);
2840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
2850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (degenerateAB || degenerateCD) {
2860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        goto DRAW_LINE;
2870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
2880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkAssertResult(set_normal_unitnormal(cd, fRadius, normalCD, unitNormalCD));
2890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    bool degenerateBC = !set_normal_unitnormal(pts[1], pts[2], fRadius,
2900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                               &normalBC, &unitNormalBC);
2910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2929f0b433bdd1680cd1d371c19d7e0ffde8fb2c484Mike Reed    if (degenerateBC || normals_too_curvy(unitNormalAB, unitNormalBC) ||
2939f0b433bdd1680cd1d371c19d7e0ffde8fb2c484Mike Reed             normals_too_curvy(unitNormalBC, *unitNormalCD)) {
2949f0b433bdd1680cd1d371c19d7e0ffde8fb2c484Mike Reed        // subdivide if we can
2959f0b433bdd1680cd1d371c19d7e0ffde8fb2c484Mike Reed        if (--subDivide < 0) {
2969f0b433bdd1680cd1d371c19d7e0ffde8fb2c484Mike Reed            goto DRAW_LINE;
2979f0b433bdd1680cd1d371c19d7e0ffde8fb2c484Mike Reed        }
2980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkPoint     tmp[7];
2990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkVector    norm, unit, dummy, unitDummy;
3000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkChopCubicAtHalf(pts, tmp);
3020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->cubic_to(&tmp[0], normalAB, unitNormalAB, &norm, &unit,
3030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                       subDivide);
3040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        // we use dummys since we already have a valid (and more accurate)
3050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        // normals for CD
3060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->cubic_to(&tmp[3], norm, unit, &dummy, &unitDummy, subDivide);
3070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    } else {
3080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkVector    normalB, normalC;
3090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        // need normals to inset/outset the off-curve pts B and C
3110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (0) {    // this is normal to the line between our adjacent pts
3130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            normalB = pts[2] - pts[0];
3140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            normalB.rotateCCW();
3150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkAssertResult(normalB.setLength(fRadius));
3160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            normalC = pts[3] - pts[1];
3180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            normalC.rotateCCW();
3190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkAssertResult(normalC.setLength(fRadius));
3200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        } else {    // miter-join
3210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkVector    unitBC = pts[2] - pts[1];
3220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            unitBC.normalize();
3230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            unitBC.rotateCCW();
3240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            normalB = unitNormalAB + unitBC;
3260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            normalC = *unitNormalCD + unitBC;
3270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkScalar dot = SkPoint::DotProduct(unitNormalAB, unitBC);
3290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkAssertResult(normalB.setLength(SkScalarDiv(fRadius,
3300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                        SkScalarSqrt((SK_Scalar1 + dot)/2))));
3310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            dot = SkPoint::DotProduct(*unitNormalCD, unitBC);
3320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkAssertResult(normalC.setLength(SkScalarDiv(fRadius,
3330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                        SkScalarSqrt((SK_Scalar1 + dot)/2))));
3340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
3350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fOuter.cubicTo( pts[1].fX + normalB.fX, pts[1].fY + normalB.fY,
3370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                        pts[2].fX + normalC.fX, pts[2].fY + normalC.fY,
3380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                        pts[3].fX + normalCD->fX, pts[3].fY + normalCD->fY);
3390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fInner.cubicTo( pts[1].fX - normalB.fX, pts[1].fY - normalB.fY,
3410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                        pts[2].fX - normalC.fX, pts[2].fY - normalC.fY,
3420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                        pts[3].fX - normalCD->fX, pts[3].fY - normalCD->fY);
3430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
3440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
3450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPathStroker::quadTo(const SkPoint& pt1, const SkPoint& pt2) {
3471cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    bool    degenerateAB = SkPath::IsLineDegenerate(fPrevPt, pt1);
3481cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    bool    degenerateBC = SkPath::IsLineDegenerate(pt1, pt2);
3490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (degenerateAB | degenerateBC) {
3510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (degenerateAB ^ degenerateBC) {
3520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            this->lineTo(pt2);
3530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
3540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return;
3550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
3560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkVector    normalAB, unitAB, normalBC, unitBC;
3580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->preJoinTo(pt1, &normalAB, &unitAB, false);
3600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    {
3620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkPoint pts[3], tmp[5];
3630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        pts[0] = fPrevPt;
3640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        pts[1] = pt1;
3650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        pts[2] = pt2;
3660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (SkChopQuadAtMaxCurvature(pts, tmp) == 2) {
3680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            unitBC.setNormalize(pts[2].fX - pts[1].fX, pts[2].fY - pts[1].fY);
3690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            unitBC.rotateCCW();
3700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (normals_too_pinchy(unitAB, unitBC)) {
3710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                normalBC = unitBC;
3720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                normalBC.scale(fRadius);
3730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                fOuter.lineTo(tmp[2].fX + normalAB.fX, tmp[2].fY + normalAB.fY);
3750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                fOuter.lineTo(tmp[2].fX + normalBC.fX, tmp[2].fY + normalBC.fY);
3760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                fOuter.lineTo(tmp[4].fX + normalBC.fX, tmp[4].fY + normalBC.fY);
3770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                fInner.lineTo(tmp[2].fX - normalAB.fX, tmp[2].fY - normalAB.fY);
3790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                fInner.lineTo(tmp[2].fX - normalBC.fX, tmp[2].fY - normalBC.fY);
3800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                fInner.lineTo(tmp[4].fX - normalBC.fX, tmp[4].fY - normalBC.fY);
3810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                fExtra.addCircle(tmp[2].fX, tmp[2].fY, fRadius,
3830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                 SkPath::kCW_Direction);
3840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            } else {
3850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                this->quad_to(&tmp[0], normalAB, unitAB, &normalBC, &unitBC,
3860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                              kMaxQuadSubdivide);
3870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                SkVector n = normalBC;
3880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                SkVector u = unitBC;
3890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                this->quad_to(&tmp[2], n, u, &normalBC, &unitBC,
3900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                              kMaxQuadSubdivide);
3910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
3920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        } else {
3930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            this->quad_to(pts, normalAB, unitAB, &normalBC, &unitBC,
3940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                          kMaxQuadSubdivide);
3950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
3960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
3970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->postJoinTo(pt2, normalBC, unitBC);
3990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
4000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPathStroker::cubicTo(const SkPoint& pt1, const SkPoint& pt2,
4020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                            const SkPoint& pt3) {
4031cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    bool    degenerateAB = SkPath::IsLineDegenerate(fPrevPt, pt1);
4041cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    bool    degenerateBC = SkPath::IsLineDegenerate(pt1, pt2);
4051cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    bool    degenerateCD = SkPath::IsLineDegenerate(pt2, pt3);
4060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (degenerateAB + degenerateBC + degenerateCD >= 2) {
4080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->lineTo(pt3);
4090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return;
4100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
4110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkVector    normalAB, unitAB, normalCD, unitCD;
4130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // find the first tangent (which might be pt1 or pt2
4150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    {
4160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        const SkPoint*  nextPt = &pt1;
4170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (degenerateAB)
4180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            nextPt = &pt2;
4190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->preJoinTo(*nextPt, &normalAB, &unitAB, false);
4200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
4210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    {
4230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkPoint pts[4], tmp[13];
4240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        int         i, count;
4250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkVector    n, u;
4260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkScalar    tValues[3];
4270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        pts[0] = fPrevPt;
4290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        pts[1] = pt1;
4300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        pts[2] = pt2;
4310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        pts[3] = pt3;
4320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#if 1
4340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        count = SkChopCubicAtMaxCurvature(pts, tmp, tValues);
4350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#else
4360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        count = 1;
4370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        memcpy(tmp, pts, 4 * sizeof(SkPoint));
4380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
4390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        n = normalAB;
4400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        u = unitAB;
4410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        for (i = 0; i < count; i++) {
4420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            this->cubic_to(&tmp[i * 3], n, u, &normalCD, &unitCD,
4430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                           kMaxCubicSubdivide);
4440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (i == count - 1) {
4450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                break;
4460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
4470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            n = normalCD;
4480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            u = unitCD;
4490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
4510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        // check for too pinchy
4530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        for (i = 1; i < count; i++) {
4540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkPoint p;
4550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkVector    v, c;
4560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkEvalCubicAt(pts, tValues[i - 1], &p, &v, &c);
4580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkScalar    dot = SkPoint::DotProduct(c, c);
4600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            v.scale(SkScalarInvert(dot));
4610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (SkScalarNearlyZero(v.fX) && SkScalarNearlyZero(v.fY)) {
4630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                fExtra.addCircle(p.fX, p.fY, fRadius, SkPath::kCW_Direction);
4640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
4650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
4660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
4680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->postJoinTo(pt3, normalCD, unitCD);
4700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
4710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
4730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
4740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4754f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger#include "SkPaintDefaults.h"
4760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectSkStroke::SkStroke() {
4784f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    fWidth      = SK_Scalar1;
4794f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    fMiterLimit = SkPaintDefaults_MiterLimit;
4800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fCap        = SkPaint::kDefault_Cap;
4810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fJoin       = SkPaint::kDefault_Join;
4820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fDoFill     = false;
4830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
4840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectSkStroke::SkStroke(const SkPaint& p) {
4860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fWidth      = p.getStrokeWidth();
4870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fMiterLimit = p.getStrokeMiter();
4880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fCap        = (uint8_t)p.getStrokeCap();
4890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fJoin       = (uint8_t)p.getStrokeJoin();
4900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fDoFill     = SkToU8(p.getStyle() == SkPaint::kStrokeAndFill_Style);
4910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
4920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectSkStroke::SkStroke(const SkPaint& p, SkScalar width) {
4940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fWidth      = width;
4950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fMiterLimit = p.getStrokeMiter();
4960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fCap        = (uint8_t)p.getStrokeCap();
4970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fJoin       = (uint8_t)p.getStrokeJoin();
4980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fDoFill     = SkToU8(p.getStyle() == SkPaint::kStrokeAndFill_Style);
4990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
5000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkStroke::setWidth(SkScalar width) {
5020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(width >= 0);
5030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fWidth = width;
5040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
5050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkStroke::setMiterLimit(SkScalar miterLimit) {
5070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(miterLimit >= 0);
5080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fMiterLimit = miterLimit;
5090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
5100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkStroke::setCap(SkPaint::Cap cap) {
5120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT((unsigned)cap < SkPaint::kCapCount);
5130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fCap = SkToU8(cap);
5140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
5150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkStroke::setJoin(SkPaint::Join join) {
5170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT((unsigned)join < SkPaint::kJoinCount);
5180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fJoin = SkToU8(join);
5190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
5200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
5220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#ifdef SK_SCALAR_IS_FIXED
5240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    /*  return non-zero if the path is too big, and should be shrunk to avoid
5250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        overflows during intermediate calculations. Note that we compute the
5260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        bounds for this. If we had a custom callback/walker for paths, we could
5270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        perhaps go faster by using that, and just perform the abs | in that
5280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        routine
5290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    */
5300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    static int needs_to_shrink(const SkPath& path) {
5310e747d6d0a794242bd214fa44a6a179baeadfdf9Mike Reed        const SkRect& r = path.getBounds();
5320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkFixed mask = SkAbs32(r.fLeft);
5330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        mask |= SkAbs32(r.fTop);
5340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        mask |= SkAbs32(r.fRight);
5350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        mask |= SkAbs32(r.fBottom);
5360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        // we need the top 3 bits clear (after abs) to avoid overflow
5370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return mask >> 29;
5380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
5390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    static void identity_proc(SkPoint pts[], int count) {}
5410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    static void shift_down_2_proc(SkPoint pts[], int count) {
5420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        for (int i = 0; i < count; i++) {
5430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            pts->fX >>= 2;
5440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            pts->fY >>= 2;
5450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            pts += 1;
5460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
5470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
5480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    #define APPLY_PROC(proc, pts, count)    proc(pts, count)
5490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#else   // float does need any of this
5500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    #define APPLY_PROC(proc, pts, count)
5510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
5520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkStroke::strokePath(const SkPath& src, SkPath* dst) const {
5540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(&src != NULL && dst != NULL);
5550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar radius = SkScalarHalf(fWidth);
5570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    dst->reset();
5590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (radius <= 0) {
5600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return;
5610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
5620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#ifdef SK_SCALAR_IS_FIXED
5640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    void (*proc)(SkPoint pts[], int count) = identity_proc;
5650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (needs_to_shrink(src)) {
5660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        proc = shift_down_2_proc;
5670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        radius >>= 2;
5680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (radius == 0) {
5690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            return;
5700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
5710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
5720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
5730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPathStroker   stroker(radius, fMiterLimit, this->getCap(),
5750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                            this->getJoin());
5760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPath::Iter    iter(src, false);
5780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPoint         pts[4];
5790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPath::Verb    verb, lastSegment = SkPath::kMove_Verb;
5800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
5820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        switch (verb) {
5830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            case SkPath::kMove_Verb:
5840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                APPLY_PROC(proc, &pts[0], 1);
5850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                stroker.moveTo(pts[0]);
5860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                break;
5870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            case SkPath::kLine_Verb:
5880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                APPLY_PROC(proc, &pts[1], 1);
5890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                stroker.lineTo(pts[1]);
5900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                lastSegment = verb;
5910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                break;
5920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            case SkPath::kQuad_Verb:
5930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                APPLY_PROC(proc, &pts[1], 2);
5940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                stroker.quadTo(pts[1], pts[2]);
5950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                lastSegment = verb;
5960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                break;
5970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            case SkPath::kCubic_Verb:
5980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                APPLY_PROC(proc, &pts[1], 3);
5990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                stroker.cubicTo(pts[1], pts[2], pts[3]);
6000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                lastSegment = verb;
6010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                break;
6020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            case SkPath::kClose_Verb:
6030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                stroker.close(lastSegment == SkPath::kLine_Verb);
6040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                break;
6050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            default:
6060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                break;
6070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
6080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
6090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    stroker.done(dst, lastSegment == SkPath::kLine_Verb);
6100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
6110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#ifdef SK_SCALAR_IS_FIXED
6120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // undo our previous down_shift
6130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (shift_down_2_proc == proc) {
6140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        // need a real shift methid on path. antialias paths could use this too
6150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkMatrix matrix;
6160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        matrix.setScale(SkIntToScalar(4), SkIntToScalar(4));
6170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        dst->transform(matrix);
6180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
6190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
6200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
6210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (fDoFill) {
6221cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        if (src.cheapIsDirection(SkPath::kCCW_Direction)) {
6231cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            dst->reverseAddPath(src);
6241cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        } else {
6251cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            dst->addPath(src);
6261cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        }
62740528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    } else {
6281cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        //  Seems like we can assume that a 2-point src would always result in
6291cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        //  a convex stroke, but testing has proved otherwise.
6301cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        //  TODO: fix the stroker to make this assumption true (without making
6311cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        //  it slower that the work that will be done in computeConvexity())
6321cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger#if 0
6331cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        // this test results in a non-convex stroke :(
6341cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        static void test(SkCanvas* canvas) {
6351cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            SkPoint pts[] = { 146.333328,  192.333328, 300.333344, 293.333344 };
6361cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            SkPaint paint;
6371cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            paint.setStrokeWidth(7);
6381cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            paint.setStrokeCap(SkPaint::kRound_Cap);
6391cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            canvas->drawLine(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, paint);
6401cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        }
6411cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger#endif
6421cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger#if 0
6431cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        if (2 == src.countPoints()) {
64440528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger            dst->setIsConvex(true);
64540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        }
6461cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger#endif
6471cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    }
6481cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
6491cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    // our answer should preserve the inverseness of the src
6501cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    if (src.isInverseFillType()) {
6511cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkASSERT(!dst->isInverseFillType());
6521cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        dst->toggleInverseFillType();
6530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
6540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
6550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
6560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkStroke::strokeLine(const SkPoint& p0, const SkPoint& p1,
6570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                          SkPath* dst) const {
6580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPath  tmp;
6590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
6600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    tmp.moveTo(p0);
6610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    tmp.lineTo(p1);
6620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->strokePath(tmp, dst);
6630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
6640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
665