180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/*
280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Copyright 2008 The Android Open Source Project
380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru *
480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Use of this source code is governed by a BSD-style license that can be
580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * found in the LICENSE file.
680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru */
780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkStrokerPriv.h"
980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkGeometry.h"
1080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkPath.h"
1180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
1280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#define kMaxQuadSubdivide   5
137839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger#define kMaxCubicSubdivide  7
1480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
1580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic inline bool degenerate_vector(const SkVector& v) {
1680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return !SkPoint::CanNormalize(v.fX, v.fY);
1780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
1880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
1980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic inline bool normals_too_curvy(const SkVector& norm0, SkVector& norm1) {
2080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    /*  root2/2 is a 45-degree angle
2180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        make this constant bigger for more subdivisions (but not >= 1)
2280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    */
2380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    static const SkScalar kFlatEnoughNormalDotProd =
2480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                            SK_ScalarSqrt2/2 + SK_Scalar1/10;
2580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
2680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkASSERT(kFlatEnoughNormalDotProd > 0 &&
2780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru             kFlatEnoughNormalDotProd < SK_Scalar1);
2880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
2980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return SkPoint::DotProduct(norm0, norm1) <= kFlatEnoughNormalDotProd;
3080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
3180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
3280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic inline bool normals_too_pinchy(const SkVector& norm0, SkVector& norm1) {
3380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    static const SkScalar kTooPinchyNormalDotProd = -SK_Scalar1 * 999 / 1000;
3480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
3580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return SkPoint::DotProduct(norm0, norm1) <= kTooPinchyNormalDotProd;
3680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
3780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
3880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic bool set_normal_unitnormal(const SkPoint& before, const SkPoint& after,
3980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                  SkScalar radius,
4080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                  SkVector* normal, SkVector* unitNormal) {
4180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (!unitNormal->setNormalize(after.fX - before.fX, after.fY - before.fY)) {
4280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        return false;
4380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
4480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    unitNormal->rotateCCW();
4580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    unitNormal->scale(radius, normal);
4680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return true;
4780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
4880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
4980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic bool set_normal_unitnormal(const SkVector& vec,
5080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                  SkScalar radius,
5180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                  SkVector* normal, SkVector* unitNormal) {
5280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (!unitNormal->setNormalize(vec.fX, vec.fY)) {
5380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        return false;
5480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
5580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    unitNormal->rotateCCW();
5680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    unitNormal->scale(radius, normal);
5780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return true;
5880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
5980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
6080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru///////////////////////////////////////////////////////////////////////////////
6180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
6280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruclass SkPathStroker {
6380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querupublic:
6480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkPathStroker(const SkPath& src,
6580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                  SkScalar radius, SkScalar miterLimit, SkPaint::Cap cap,
6680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                  SkPaint::Join join);
6780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
6880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    void moveTo(const SkPoint&);
6980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    void lineTo(const SkPoint&);
7080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    void quadTo(const SkPoint&, const SkPoint&);
7180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    void cubicTo(const SkPoint&, const SkPoint&, const SkPoint&);
7280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    void close(bool isLine) { this->finishContour(true, isLine); }
7380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
7480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    void done(SkPath* dst, bool isLine) {
7580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        this->finishContour(false, isLine);
7680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        fOuter.addPath(fExtra);
7780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        dst->swap(fOuter);
7880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
7980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
8080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruprivate:
8180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkScalar    fRadius;
8280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkScalar    fInvMiterLimit;
8380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
8480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkVector    fFirstNormal, fPrevNormal, fFirstUnitNormal, fPrevUnitNormal;
8580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkPoint     fFirstPt, fPrevPt;  // on original path
8680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkPoint     fFirstOuterPt;
8780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    int         fSegmentCount;
8880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    bool        fPrevIsLine;
8980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
9080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkStrokerPriv::CapProc  fCapper;
9180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkStrokerPriv::JoinProc fJoiner;
9280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
9380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkPath  fInner, fOuter; // outer is our working answer, inner is temp
9480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkPath  fExtra;         // added as extra complete contours
9580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
9680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    void    finishContour(bool close, bool isLine);
9780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    void    preJoinTo(const SkPoint&, SkVector* normal, SkVector* unitNormal,
9880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                      bool isLine);
9980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    void    postJoinTo(const SkPoint&, const SkVector& normal,
10080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                       const SkVector& unitNormal);
10180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
10280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    void    line_to(const SkPoint& currPt, const SkVector& normal);
10380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    void    quad_to(const SkPoint pts[3],
10480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                    const SkVector& normalAB, const SkVector& unitNormalAB,
10580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                    SkVector* normalBC, SkVector* unitNormalBC,
10680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                    int subDivide);
10780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    void    cubic_to(const SkPoint pts[4],
10880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                    const SkVector& normalAB, const SkVector& unitNormalAB,
10980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                    SkVector* normalCD, SkVector* unitNormalCD,
11080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                    int subDivide);
11180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru};
11280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
11380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru///////////////////////////////////////////////////////////////////////////////
11480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
11580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkPathStroker::preJoinTo(const SkPoint& currPt, SkVector* normal,
11680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                              SkVector* unitNormal, bool currIsLine) {
11780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkASSERT(fSegmentCount >= 0);
11880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
11980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkScalar    prevX = fPrevPt.fX;
12080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkScalar    prevY = fPrevPt.fY;
12180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
12280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkAssertResult(set_normal_unitnormal(fPrevPt, currPt, fRadius, normal,
12380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                         unitNormal));
12480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
12580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (fSegmentCount == 0) {
12680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        fFirstNormal = *normal;
12780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        fFirstUnitNormal = *unitNormal;
12880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        fFirstOuterPt.set(prevX + normal->fX, prevY + normal->fY);
12980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
13080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        fOuter.moveTo(fFirstOuterPt.fX, fFirstOuterPt.fY);
13180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        fInner.moveTo(prevX - normal->fX, prevY - normal->fY);
13280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    } else {    // we have a previous segment
13380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        fJoiner(&fOuter, &fInner, fPrevUnitNormal, fPrevPt, *unitNormal,
13480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                fRadius, fInvMiterLimit, fPrevIsLine, currIsLine);
13580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
13680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fPrevIsLine = currIsLine;
13780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
13880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
13980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkPathStroker::postJoinTo(const SkPoint& currPt, const SkVector& normal,
14080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                               const SkVector& unitNormal) {
14180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fPrevPt = currPt;
14280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fPrevUnitNormal = unitNormal;
14380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fPrevNormal = normal;
14480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fSegmentCount += 1;
14580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
14680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
14780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkPathStroker::finishContour(bool close, bool currIsLine) {
14880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (fSegmentCount > 0) {
14980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkPoint pt;
15080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
15180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (close) {
15280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            fJoiner(&fOuter, &fInner, fPrevUnitNormal, fPrevPt,
15380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                    fFirstUnitNormal, fRadius, fInvMiterLimit,
15480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                    fPrevIsLine, currIsLine);
15580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            fOuter.close();
15680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            // now add fInner as its own contour
15780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            fInner.getLastPt(&pt);
15880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            fOuter.moveTo(pt.fX, pt.fY);
15980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            fOuter.reversePathTo(fInner);
16080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            fOuter.close();
16180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        } else {    // add caps to start and end
16280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            // cap the end
16380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            fInner.getLastPt(&pt);
16480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            fCapper(&fOuter, fPrevPt, fPrevNormal, pt,
16580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                    currIsLine ? &fInner : NULL);
16680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            fOuter.reversePathTo(fInner);
16780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            // cap the start
16880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            fCapper(&fOuter, fFirstPt, -fFirstNormal, fFirstOuterPt,
16980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                    fPrevIsLine ? &fInner : NULL);
17080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            fOuter.close();
17180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
17280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
17380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // since we may re-use fInner, we rewind instead of reset, to save on
17480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // reallocating its internal storage.
17580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fInner.rewind();
17680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fSegmentCount = -1;
17780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
17880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
17980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru///////////////////////////////////////////////////////////////////////////////
18080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
18180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruSkPathStroker::SkPathStroker(const SkPath& src,
18280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                             SkScalar radius, SkScalar miterLimit,
18380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                             SkPaint::Cap cap, SkPaint::Join join)
18480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        : fRadius(radius) {
18580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
18680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    /*  This is only used when join is miter_join, but we initialize it here
18780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        so that it is always defined, to fis valgrind warnings.
18880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    */
18980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fInvMiterLimit = 0;
19080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
19180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (join == SkPaint::kMiter_Join) {
19280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (miterLimit <= SK_Scalar1) {
19380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            join = SkPaint::kBevel_Join;
19480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        } else {
19580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            fInvMiterLimit = SkScalarInvert(miterLimit);
19680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
19780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
19880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fCapper = SkStrokerPriv::CapFactory(cap);
19980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fJoiner = SkStrokerPriv::JoinFactory(join);
20080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fSegmentCount = -1;
20180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fPrevIsLine = false;
20280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
20380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // Need some estimate of how large our final result (fOuter)
20480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // and our per-contour temp (fInner) will be, so we don't spend
20580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // extra time repeatedly growing these arrays.
20680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    //
20780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // 3x for result == inner + outer + join (swag)
20880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // 1x for inner == 'wag' (worst contour length would be better guess)
20980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fOuter.incReserve(src.countPoints() * 3);
21080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fInner.incReserve(src.countPoints());
21180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
21280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
21380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkPathStroker::moveTo(const SkPoint& pt) {
21480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (fSegmentCount > 0) {
21580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        this->finishContour(false, false);
21680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
21780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fSegmentCount = 0;
21880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fFirstPt = fPrevPt = pt;
21980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
22080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
22180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkPathStroker::line_to(const SkPoint& currPt, const SkVector& normal) {
22280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fOuter.lineTo(currPt.fX + normal.fX, currPt.fY + normal.fY);
22380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fInner.lineTo(currPt.fX - normal.fX, currPt.fY - normal.fY);
22480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
22580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
22680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkPathStroker::lineTo(const SkPoint& currPt) {
22780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (SkPath::IsLineDegenerate(fPrevPt, currPt)) {
22880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        return;
22980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
23080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkVector    normal, unitNormal;
23180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
23280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    this->preJoinTo(currPt, &normal, &unitNormal, true);
23380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    this->line_to(currPt, normal);
23480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    this->postJoinTo(currPt, normal, unitNormal);
23580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
23680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
23780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkPathStroker::quad_to(const SkPoint pts[3],
23880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                      const SkVector& normalAB, const SkVector& unitNormalAB,
23980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                      SkVector* normalBC, SkVector* unitNormalBC,
24080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                      int subDivide) {
24180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (!set_normal_unitnormal(pts[1], pts[2], fRadius,
24280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                               normalBC, unitNormalBC)) {
24380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        // pts[1] nearly equals pts[2], so just draw a line to pts[2]
24480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        this->line_to(pts[2], normalAB);
24580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        *normalBC = normalAB;
24680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        *unitNormalBC = unitNormalAB;
24780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        return;
24880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
24980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
25080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (--subDivide >= 0 && normals_too_curvy(unitNormalAB, *unitNormalBC)) {
25180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkPoint     tmp[5];
25280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkVector    norm, unit;
25380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
25480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkChopQuadAtHalf(pts, tmp);
25580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        this->quad_to(&tmp[0], normalAB, unitNormalAB, &norm, &unit, subDivide);
25680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        this->quad_to(&tmp[2], norm, unit, normalBC, unitNormalBC, subDivide);
25780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    } else {
258d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger        SkVector    normalB;
259d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger
260d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger        normalB = pts[2] - pts[0];
261d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger        normalB.rotateCCW();
262d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger        SkScalar dot = SkPoint::DotProduct(unitNormalAB, *unitNormalBC);
263d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger        SkAssertResult(normalB.setLength(SkScalarDiv(fRadius,
264d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger                                     SkScalarSqrt((SK_Scalar1 + dot)/2))));
26580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
26680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        fOuter.quadTo(  pts[1].fX + normalB.fX, pts[1].fY + normalB.fY,
26780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                        pts[2].fX + normalBC->fX, pts[2].fY + normalBC->fY);
26880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        fInner.quadTo(  pts[1].fX - normalB.fX, pts[1].fY - normalB.fY,
26980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                        pts[2].fX - normalBC->fX, pts[2].fY - normalBC->fY);
27080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
27180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
27280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
27380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkPathStroker::cubic_to(const SkPoint pts[4],
27480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                      const SkVector& normalAB, const SkVector& unitNormalAB,
27580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                      SkVector* normalCD, SkVector* unitNormalCD,
27680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                      int subDivide) {
27780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkVector    ab = pts[1] - pts[0];
27880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkVector    cd = pts[3] - pts[2];
27980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkVector    normalBC, unitNormalBC;
28080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
28180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    bool    degenerateAB = degenerate_vector(ab);
28280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    bool    degenerateCD = degenerate_vector(cd);
28380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
28480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (degenerateAB && degenerateCD) {
28580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruDRAW_LINE:
28680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        this->line_to(pts[3], normalAB);
28780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        *normalCD = normalAB;
28880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        *unitNormalCD = unitNormalAB;
28980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        return;
29080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
29180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
29280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (degenerateAB) {
29380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        ab = pts[2] - pts[0];
29480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        degenerateAB = degenerate_vector(ab);
29580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
29680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (degenerateCD) {
29780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        cd = pts[3] - pts[1];
29880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        degenerateCD = degenerate_vector(cd);
29980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
30080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (degenerateAB || degenerateCD) {
30180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        goto DRAW_LINE;
30280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
30380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkAssertResult(set_normal_unitnormal(cd, fRadius, normalCD, unitNormalCD));
30480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    bool degenerateBC = !set_normal_unitnormal(pts[1], pts[2], fRadius,
30580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                               &normalBC, &unitNormalBC);
306096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger#ifndef SK_IGNORE_CUBIC_STROKE_FIX
3077839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    if (--subDivide < 0) {
3087839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        goto DRAW_LINE;
309096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    }
310096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger#endif
31180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (degenerateBC || normals_too_curvy(unitNormalAB, unitNormalBC) ||
31280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru             normals_too_curvy(unitNormalBC, *unitNormalCD)) {
313096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger#ifdef SK_IGNORE_CUBIC_STROKE_FIX
31480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        // subdivide if we can
31580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (--subDivide < 0) {
31680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            goto DRAW_LINE;
31780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
318096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger#endif
31980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkPoint     tmp[7];
32080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkVector    norm, unit, dummy, unitDummy;
32180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
32280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkChopCubicAtHalf(pts, tmp);
32380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        this->cubic_to(&tmp[0], normalAB, unitNormalAB, &norm, &unit,
32480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                       subDivide);
32580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        // we use dummys since we already have a valid (and more accurate)
32680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        // normals for CD
32780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        this->cubic_to(&tmp[3], norm, unit, &dummy, &unitDummy, subDivide);
32880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    } else {
32980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkVector    normalB, normalC;
33080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
33180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        // need normals to inset/outset the off-curve pts B and C
33280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
333096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        SkVector    unitBC = pts[2] - pts[1];
334096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        unitBC.normalize();
335096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        unitBC.rotateCCW();
33680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
337096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        normalB = unitNormalAB + unitBC;
338096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        normalC = *unitNormalCD + unitBC;
33980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
340096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        SkScalar dot = SkPoint::DotProduct(unitNormalAB, unitBC);
341096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        SkAssertResult(normalB.setLength(SkScalarDiv(fRadius,
342096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger                                    SkScalarSqrt((SK_Scalar1 + dot)/2))));
343096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        dot = SkPoint::DotProduct(*unitNormalCD, unitBC);
344096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        SkAssertResult(normalC.setLength(SkScalarDiv(fRadius,
345096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger                                    SkScalarSqrt((SK_Scalar1 + dot)/2))));
34680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
34780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        fOuter.cubicTo( pts[1].fX + normalB.fX, pts[1].fY + normalB.fY,
34880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                        pts[2].fX + normalC.fX, pts[2].fY + normalC.fY,
34980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                        pts[3].fX + normalCD->fX, pts[3].fY + normalCD->fY);
35080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
35180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        fInner.cubicTo( pts[1].fX - normalB.fX, pts[1].fY - normalB.fY,
35280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                        pts[2].fX - normalC.fX, pts[2].fY - normalC.fY,
35380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                        pts[3].fX - normalCD->fX, pts[3].fY - normalCD->fY);
35480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
35580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
35680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
35780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkPathStroker::quadTo(const SkPoint& pt1, const SkPoint& pt2) {
35880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    bool    degenerateAB = SkPath::IsLineDegenerate(fPrevPt, pt1);
35980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    bool    degenerateBC = SkPath::IsLineDegenerate(pt1, pt2);
36080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
36180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (degenerateAB | degenerateBC) {
36280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (degenerateAB ^ degenerateBC) {
36380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            this->lineTo(pt2);
36480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
36580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        return;
36680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
36780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
36880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkVector    normalAB, unitAB, normalBC, unitBC;
36980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
37080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    this->preJoinTo(pt1, &normalAB, &unitAB, false);
37180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
37280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    {
37380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkPoint pts[3], tmp[5];
37480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        pts[0] = fPrevPt;
37580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        pts[1] = pt1;
37680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        pts[2] = pt2;
37780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
37880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (SkChopQuadAtMaxCurvature(pts, tmp) == 2) {
37980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            unitBC.setNormalize(pts[2].fX - pts[1].fX, pts[2].fY - pts[1].fY);
38080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            unitBC.rotateCCW();
38180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            if (normals_too_pinchy(unitAB, unitBC)) {
38280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                normalBC = unitBC;
38380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                normalBC.scale(fRadius);
38480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
38580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                fOuter.lineTo(tmp[2].fX + normalAB.fX, tmp[2].fY + normalAB.fY);
38680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                fOuter.lineTo(tmp[2].fX + normalBC.fX, tmp[2].fY + normalBC.fY);
38780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                fOuter.lineTo(tmp[4].fX + normalBC.fX, tmp[4].fY + normalBC.fY);
38880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
38980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                fInner.lineTo(tmp[2].fX - normalAB.fX, tmp[2].fY - normalAB.fY);
39080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                fInner.lineTo(tmp[2].fX - normalBC.fX, tmp[2].fY - normalBC.fY);
39180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                fInner.lineTo(tmp[4].fX - normalBC.fX, tmp[4].fY - normalBC.fY);
39280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
39380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                fExtra.addCircle(tmp[2].fX, tmp[2].fY, fRadius,
39480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                 SkPath::kCW_Direction);
39580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            } else {
39680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                this->quad_to(&tmp[0], normalAB, unitAB, &normalBC, &unitBC,
39780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                              kMaxQuadSubdivide);
39880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                SkVector n = normalBC;
39980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                SkVector u = unitBC;
40080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                this->quad_to(&tmp[2], n, u, &normalBC, &unitBC,
40180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                              kMaxQuadSubdivide);
40280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            }
40380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        } else {
40480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            this->quad_to(pts, normalAB, unitAB, &normalBC, &unitBC,
40580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                          kMaxQuadSubdivide);
40680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
40780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
40880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
40980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    this->postJoinTo(pt2, normalBC, unitBC);
41080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
41180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
41280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkPathStroker::cubicTo(const SkPoint& pt1, const SkPoint& pt2,
41380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                            const SkPoint& pt3) {
41480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    bool    degenerateAB = SkPath::IsLineDegenerate(fPrevPt, pt1);
41580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    bool    degenerateBC = SkPath::IsLineDegenerate(pt1, pt2);
41680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    bool    degenerateCD = SkPath::IsLineDegenerate(pt2, pt3);
41780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
41880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (degenerateAB + degenerateBC + degenerateCD >= 2) {
41980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        this->lineTo(pt3);
42080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        return;
42180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
42280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
42380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkVector    normalAB, unitAB, normalCD, unitCD;
42480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
42580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // find the first tangent (which might be pt1 or pt2
42680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    {
42780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        const SkPoint*  nextPt = &pt1;
42880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (degenerateAB)
42980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            nextPt = &pt2;
43080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        this->preJoinTo(*nextPt, &normalAB, &unitAB, false);
43180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
43280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
43380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    {
43480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkPoint pts[4], tmp[13];
43580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        int         i, count;
43680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkVector    n, u;
43780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkScalar    tValues[3];
43880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
43980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        pts[0] = fPrevPt;
44080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        pts[1] = pt1;
44180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        pts[2] = pt2;
44280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        pts[3] = pt3;
44380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
44480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        count = SkChopCubicAtMaxCurvature(pts, tmp, tValues);
44580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        n = normalAB;
44680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        u = unitAB;
44780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        for (i = 0; i < count; i++) {
44880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            this->cubic_to(&tmp[i * 3], n, u, &normalCD, &unitCD,
44980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                           kMaxCubicSubdivide);
45080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            if (i == count - 1) {
45180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                break;
45280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            }
45380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            n = normalCD;
45480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            u = unitCD;
45580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
45680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
45780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
45880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
45980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    this->postJoinTo(pt3, normalCD, unitCD);
46080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
46180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
46280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru///////////////////////////////////////////////////////////////////////////////
46380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru///////////////////////////////////////////////////////////////////////////////
46480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
46580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkPaintDefaults.h"
46680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
46780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruSkStroke::SkStroke() {
46880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fWidth      = SK_Scalar1;
46980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fMiterLimit = SkPaintDefaults_MiterLimit;
47080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fCap        = SkPaint::kDefault_Cap;
47180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fJoin       = SkPaint::kDefault_Join;
47280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fDoFill     = false;
47380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
47480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
47580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruSkStroke::SkStroke(const SkPaint& p) {
47680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fWidth      = p.getStrokeWidth();
47780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fMiterLimit = p.getStrokeMiter();
47880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fCap        = (uint8_t)p.getStrokeCap();
47980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fJoin       = (uint8_t)p.getStrokeJoin();
48080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fDoFill     = SkToU8(p.getStyle() == SkPaint::kStrokeAndFill_Style);
48180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
48280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
48380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruSkStroke::SkStroke(const SkPaint& p, SkScalar width) {
48480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fWidth      = width;
48580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fMiterLimit = p.getStrokeMiter();
48680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fCap        = (uint8_t)p.getStrokeCap();
48780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fJoin       = (uint8_t)p.getStrokeJoin();
48880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fDoFill     = SkToU8(p.getStyle() == SkPaint::kStrokeAndFill_Style);
48980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
49080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
49180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkStroke::setWidth(SkScalar width) {
49280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkASSERT(width >= 0);
49380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fWidth = width;
49480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
49580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
49680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkStroke::setMiterLimit(SkScalar miterLimit) {
49780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkASSERT(miterLimit >= 0);
49880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fMiterLimit = miterLimit;
49980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
50080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
50180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkStroke::setCap(SkPaint::Cap cap) {
50280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkASSERT((unsigned)cap < SkPaint::kCapCount);
50380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fCap = SkToU8(cap);
50480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
50580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
50680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkStroke::setJoin(SkPaint::Join join) {
50780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkASSERT((unsigned)join < SkPaint::kJoinCount);
50880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fJoin = SkToU8(join);
50980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
51080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
51180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru///////////////////////////////////////////////////////////////////////////////
51280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
51380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru// If src==dst, then we use a tmp path to record the stroke, and then swap
51480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru// its contents with src when we're done.
51580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruclass AutoTmpPath {
51680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querupublic:
51780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    AutoTmpPath(const SkPath& src, SkPath** dst) : fSrc(src) {
51880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (&src == *dst) {
51980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            *dst = &fTmpDst;
52080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            fSwapWithSrc = true;
52180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        } else {
52280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            (*dst)->reset();
52380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            fSwapWithSrc = false;
52480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
52580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
52680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
52780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    ~AutoTmpPath() {
52880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (fSwapWithSrc) {
52980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            fTmpDst.swap(*const_cast<SkPath*>(&fSrc));
53080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
53180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
53280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
53380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruprivate:
53480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkPath          fTmpDst;
53580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    const SkPath&   fSrc;
53680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    bool            fSwapWithSrc;
53780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru};
53880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
53980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkStroke::strokePath(const SkPath& src, SkPath* dst) const {
54080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkASSERT(&src != NULL && dst != NULL);
54180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
54280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkScalar radius = SkScalarHalf(fWidth);
54380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
54480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    AutoTmpPath tmp(src, &dst);
54580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
54680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (radius <= 0) {
54780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        return;
54880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
54980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
550363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    // If src is really a rect, call our specialty strokeRect() method
551363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    {
552363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        bool isClosed;
553363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        SkPath::Direction dir;
554363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        if (src.isRect(&isClosed, &dir) && isClosed) {
555363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            this->strokeRect(src.getBounds(), dst, dir);
556363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            // our answer should preserve the inverseness of the src
557363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            if (src.isInverseFillType()) {
558363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger                SkASSERT(!dst->isInverseFillType());
559363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger                dst->toggleInverseFillType();
560363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            }
561363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            return;
562363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        }
563363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    }
564363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
56558190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    SkAutoConicToQuads converter;
56658190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    const SkScalar conicTol = SK_Scalar1 / 4;
56780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
56880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkPathStroker   stroker(src, radius, fMiterLimit, this->getCap(),
56980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                            this->getJoin());
57080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkPath::Iter    iter(src, false);
57158190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    SkPath::Verb    lastSegment = SkPath::kMove_Verb;
57280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
57358190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    for (;;) {
57458190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger        SkPoint  pts[4];
57558190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger        switch (iter.next(pts, false)) {
57680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            case SkPath::kMove_Verb:
57780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                stroker.moveTo(pts[0]);
57880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                break;
57980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            case SkPath::kLine_Verb:
58080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                stroker.lineTo(pts[1]);
58158190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                lastSegment = SkPath::kLine_Verb;
58280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                break;
58380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            case SkPath::kQuad_Verb:
58480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                stroker.quadTo(pts[1], pts[2]);
58558190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                lastSegment = SkPath::kQuad_Verb;
58680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                break;
58758190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger            case SkPath::kConic_Verb: {
58858190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                // todo: if we had maxcurvature for conics, perhaps we should
58958190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                // natively extrude the conic instead of converting to quads.
59058190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                const SkPoint* quadPts =
59158190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                    converter.computeQuads(pts, iter.conicWeight(), conicTol);
59258190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                for (int i = 0; i < converter.countQuads(); ++i) {
59358190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                    stroker.quadTo(quadPts[1], quadPts[2]);
59458190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                    quadPts += 2;
59558190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                }
59658190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                lastSegment = SkPath::kQuad_Verb;
59758190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger            } break;
59880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            case SkPath::kCubic_Verb:
59980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                stroker.cubicTo(pts[1], pts[2], pts[3]);
60058190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                lastSegment = SkPath::kCubic_Verb;
60180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                break;
60280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            case SkPath::kClose_Verb:
60380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                stroker.close(lastSegment == SkPath::kLine_Verb);
60480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                break;
60558190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger            case SkPath::kDone_Verb:
60658190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                goto DONE;
60780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
60880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
60958190644c30e1c4aa8e527f3503c58f841e0fcf3Derek SollenbergerDONE:
61080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    stroker.done(dst, lastSegment == SkPath::kLine_Verb);
61180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
61280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (fDoFill) {
61380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (src.cheapIsDirection(SkPath::kCCW_Direction)) {
61480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            dst->reverseAddPath(src);
61580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        } else {
61680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            dst->addPath(src);
61780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
61880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    } else {
61980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        //  Seems like we can assume that a 2-point src would always result in
62080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        //  a convex stroke, but testing has proved otherwise.
62180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        //  TODO: fix the stroker to make this assumption true (without making
62280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        //  it slower that the work that will be done in computeConvexity())
62380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#if 0
62480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        // this test results in a non-convex stroke :(
62580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        static void test(SkCanvas* canvas) {
62680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            SkPoint pts[] = { 146.333328,  192.333328, 300.333344, 293.333344 };
62780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            SkPaint paint;
62880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            paint.setStrokeWidth(7);
62980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            paint.setStrokeCap(SkPaint::kRound_Cap);
63080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            canvas->drawLine(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, paint);
63180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
63280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#endif
63380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#if 0
63480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (2 == src.countPoints()) {
63580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            dst->setIsConvex(true);
63680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
63780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#endif
63880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
63980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
64080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // our answer should preserve the inverseness of the src
64180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (src.isInverseFillType()) {
64280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkASSERT(!dst->isInverseFillType());
64380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        dst->toggleInverseFillType();
64480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
64580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
64680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
647363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerstatic SkPath::Direction reverse_direction(SkPath::Direction dir) {
648363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    SkASSERT(SkPath::kUnknown_Direction != dir);
649363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    return SkPath::kCW_Direction == dir ? SkPath::kCCW_Direction : SkPath::kCW_Direction;
650363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger}
651363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
652363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerstatic void addBevel(SkPath* path, const SkRect& r, const SkRect& outer, SkPath::Direction dir) {
653363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    SkPoint pts[8];
654363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
655363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    if (SkPath::kCW_Direction == dir) {
656363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        pts[0].set(r.fLeft, outer.fTop);
657363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        pts[1].set(r.fRight, outer.fTop);
658363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        pts[2].set(outer.fRight, r.fTop);
659363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        pts[3].set(outer.fRight, r.fBottom);
660363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        pts[4].set(r.fRight, outer.fBottom);
661363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        pts[5].set(r.fLeft, outer.fBottom);
662363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        pts[6].set(outer.fLeft, r.fBottom);
663363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        pts[7].set(outer.fLeft, r.fTop);
664363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    } else {
665363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        pts[7].set(r.fLeft, outer.fTop);
666363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        pts[6].set(r.fRight, outer.fTop);
667363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        pts[5].set(outer.fRight, r.fTop);
668363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        pts[4].set(outer.fRight, r.fBottom);
669363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        pts[3].set(r.fRight, outer.fBottom);
670363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        pts[2].set(r.fLeft, outer.fBottom);
671363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        pts[1].set(outer.fLeft, r.fBottom);
672363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        pts[0].set(outer.fLeft, r.fTop);
673363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    }
674363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    path->addPoly(pts, 8, true);
675363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger}
676363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
677363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergervoid SkStroke::strokeRect(const SkRect& origRect, SkPath* dst,
678363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger                          SkPath::Direction dir) const {
679363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    SkASSERT(dst != NULL);
680363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    dst->reset();
681363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
682363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    SkScalar radius = SkScalarHalf(fWidth);
683363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    if (radius <= 0) {
684363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        return;
685363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    }
686363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
687363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    SkScalar rw = origRect.width();
688363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    SkScalar rh = origRect.height();
689363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    if ((rw < 0) ^ (rh < 0)) {
690363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        dir = reverse_direction(dir);
691363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    }
692363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    SkRect rect(origRect);
693363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    rect.sort();
694363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    // reassign these, now that we know they'll be >= 0
695363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    rw = rect.width();
696363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    rh = rect.height();
697363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
698363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    SkRect r(rect);
699363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    r.outset(radius, radius);
700363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
701363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    SkPaint::Join join = (SkPaint::Join)fJoin;
702363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    if (SkPaint::kMiter_Join == join && fMiterLimit < SK_ScalarSqrt2) {
703363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        join = SkPaint::kBevel_Join;
704363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    }
705363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
706363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    switch (join) {
707363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        case SkPaint::kMiter_Join:
708363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            dst->addRect(r, dir);
709363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            break;
710363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        case SkPaint::kBevel_Join:
711363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            addBevel(dst, rect, r, dir);
712363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            break;
713363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        case SkPaint::kRound_Join:
714363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            dst->addRoundRect(r, radius, radius, dir);
715363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            break;
716363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        default:
717363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            break;
718363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    }
719363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
720363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    if (fWidth < SkMinScalar(rw, rh) && !fDoFill) {
721363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        r = rect;
722363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        r.inset(radius, radius);
723363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        dst->addRect(r, reverse_direction(dir));
724363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    }
725363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger}
726