1e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com/*
2e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com * Copyright 2012 Google Inc.
3e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com *
4e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com * Use of this source code is governed by a BSD-style license that can be
5e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com * found in the LICENSE file.
6e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com */
7e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com
8e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com#include "GrStrokePathRenderer.h"
9e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com
10e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com#include "GrDrawTarget.h"
11e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com#include "SkPath.h"
12e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com#include "SkStrokeRec.h"
13e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com
145a064e3af8e30d8160e9e67dbe263baf9762c9b6tfarina@chromium.orgstatic bool is_clockwise(const SkVector& before, const SkVector& after) {
15e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    return before.cross(after) > 0;
16e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com}
17e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com
18e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.comenum IntersectionType {
19e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    kNone_IntersectionType,
20e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    kIn_IntersectionType,
21e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    kOut_IntersectionType
22e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com};
23e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com
245a064e3af8e30d8160e9e67dbe263baf9762c9b6tfarina@chromium.orgstatic IntersectionType intersection(const SkPoint& p1, const SkPoint& p2,
255a064e3af8e30d8160e9e67dbe263baf9762c9b6tfarina@chromium.org                                     const SkPoint& p3, const SkPoint& p4,
265a064e3af8e30d8160e9e67dbe263baf9762c9b6tfarina@chromium.org                                     SkPoint& res) {
27e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    // Store the values for fast access and easy
28e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    // equations-to-code conversion
29e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    SkScalar x1 = p1.x(), x2 = p2.x(), x3 = p3.x(), x4 = p4.x();
30e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    SkScalar y1 = p1.y(), y2 = p2.y(), y3 = p3.y(), y4 = p4.y();
314e8ef337bc2343a7ed422558106dccfc0d073bdeskia.committer@gmail.com
32e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    SkScalar d = SkScalarMul(x1 - x2, y3 - y4) - SkScalarMul(y1 - y2, x3 - x4);
33e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    // If d is zero, there is no intersection
34e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    if (SkScalarNearlyZero(d)) {
35e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com        return kNone_IntersectionType;
36e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    }
374e8ef337bc2343a7ed422558106dccfc0d073bdeskia.committer@gmail.com
38e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    // Get the x and y
39e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    SkScalar pre  = SkScalarMul(x1, y2) - SkScalarMul(y1, x2),
40e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com             post = SkScalarMul(x3, y4) - SkScalarMul(y3, x4);
41e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    // Compute the point of intersection
42e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    res.set(SkScalarDiv(SkScalarMul(pre, x3 - x4) - SkScalarMul(x1 - x2, post), d),
43e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com            SkScalarDiv(SkScalarMul(pre, y3 - y4) - SkScalarMul(y1 - y2, post), d));
44e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com
45e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    // Check if the x and y coordinates are within both lines
46e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    return (res.x() < GrMin(x1, x2) || res.x() > GrMax(x1, x2) ||
47e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com            res.x() < GrMin(x3, x4) || res.x() > GrMax(x3, x4) ||
48e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com            res.y() < GrMin(y1, y2) || res.y() > GrMax(y1, y2) ||
49e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com            res.y() < GrMin(y3, y4) || res.y() > GrMax(y3, y4)) ?
50e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com            kOut_IntersectionType : kIn_IntersectionType;
51e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com}
52e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com
53e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.comGrStrokePathRenderer::GrStrokePathRenderer() {
54e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com}
55e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com
56e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.combool GrStrokePathRenderer::canDrawPath(const SkPath& path,
57e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                       const SkStrokeRec& stroke,
58e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                       const GrDrawTarget* target,
59e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                       bool antiAlias) const {
60e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    // FIXME : put the proper condition once GrDrawTarget::isOpaque is implemented
61e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    const bool isOpaque = true; // target->isOpaque();
62e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com
63e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    // FIXME : remove this requirement once we have AA circles and implement the
64e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    //         circle joins/caps appropriately in the ::onDrawPath() function.
65e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    const bool requiresAACircle = (stroke.getCap()  == SkPaint::kRound_Cap) ||
66e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                  (stroke.getJoin() == SkPaint::kRound_Join);
67e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com
68e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    // Indices being stored in uint16, we don't want to overflow the indices capacity
69e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    static const int maxVBSize = 1 << 16;
70e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    const int maxNbVerts = (path.countPoints() + 1) * 5;
714e8ef337bc2343a7ed422558106dccfc0d073bdeskia.committer@gmail.com
72e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    // Check that the path contains no curved lines, only straight lines
73e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    static const uint32_t unsupportedMask = SkPath::kQuad_SegmentMask | SkPath::kCubic_SegmentMask;
74e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com
75e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    // Must not be filled nor hairline nor semi-transparent
76e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    // Note : May require a check to path.isConvex() if AA is supported
77e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    return ((stroke.getStyle() == SkStrokeRec::kStroke_Style) && (maxNbVerts < maxVBSize) &&
78e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com            !path.isInverseFillType() && isOpaque && !requiresAACircle && !antiAlias &&
79e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com            ((path.getSegmentMasks() & unsupportedMask) == 0));
80e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com}
81e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com
82e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.combool GrStrokePathRenderer::onDrawPath(const SkPath& origPath,
83e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                      const SkStrokeRec& stroke,
84e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                      GrDrawTarget* target,
85e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                      bool antiAlias) {
86e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    if (origPath.isEmpty()) {
87e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com        return true;
88e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    }
89e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com
90e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    SkScalar width = stroke.getWidth();
91e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    if (width <= 0) {
92e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com        return false;
93e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    }
94e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com
95e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    // Get the join type
96e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    SkPaint::Join join = stroke.getJoin();
97e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    SkScalar miterLimit = stroke.getMiter();
98e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    SkScalar sqMiterLimit = SkScalarMul(miterLimit, miterLimit);
99e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    if ((join == SkPaint::kMiter_Join) && (miterLimit <= SK_Scalar1)) {
100e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com        // If the miter limit is small, treat it as a bevel join
101e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com        join = SkPaint::kBevel_Join;
102e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    }
103e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    const bool isMiter       = (join == SkPaint::kMiter_Join);
104e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    const bool isBevel       = (join == SkPaint::kBevel_Join);
105e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    SkScalar invMiterLimit   = isMiter ? SK_Scalar1 / miterLimit : 0;
106e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    SkScalar invMiterLimitSq = SkScalarMul(invMiterLimit, invMiterLimit);
107e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com
108e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    // Allocate vertices
109e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    const int nbQuads     = origPath.countPoints() + 1; // Could be "-1" if path is not closed
110e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    const int extraVerts  = isMiter || isBevel ? 1 : 0;
111e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    const int maxVertexCount = nbQuads * (4 + extraVerts);
112e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    const int maxIndexCount  = nbQuads * (6 + extraVerts * 3); // Each extra vert adds a triangle
1139b855c7c95ce9fff7a447e4a6bdf8a469c1f3097jvanverth@google.com    target->drawState()->setDefaultVertexAttribs();
1149b855c7c95ce9fff7a447e4a6bdf8a469c1f3097jvanverth@google.com    GrDrawTarget::AutoReleaseGeometry arg(target, maxVertexCount, maxIndexCount);
115e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    if (!arg.succeeded()) {
116e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com        return false;
117e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    }
118e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    SkPoint* verts = reinterpret_cast<SkPoint*>(arg.vertices());
119e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    uint16_t* idxs = reinterpret_cast<uint16_t*>(arg.indices());
120e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    int vCount = 0, iCount = 0;
121e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com
122e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    // Transform the path into a list of triangles
123e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    SkPath::Iter iter(origPath, false);
124e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    SkPoint pts[4];
1259b855c7c95ce9fff7a447e4a6bdf8a469c1f3097jvanverth@google.com    const SkScalar radius = SkScalarMul(width, 0.5f);
126e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    SkPoint *firstPt = verts, *lastPt = NULL;
127e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    SkVector firstDir, dir;
128e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    firstDir.set(0, 0);
129e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    dir.set(0, 0);
130e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    bool isOpen = true;
131e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    for(SkPath::Verb v = iter.next(pts); v != SkPath::kDone_Verb; v = iter.next(pts)) {
132e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com        switch(v) {
133e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com            case SkPath::kMove_Verb:
134e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                // This will already be handled as pts[0] of the 1st line
135e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                break;
136e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com            case SkPath::kClose_Verb:
137e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                isOpen = (lastPt == NULL);
138e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                break;
139e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com            case SkPath::kLine_Verb:
140e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com            {
141e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                SkVector v0 = dir;
142e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                dir = pts[1] - pts[0];
143e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                if (dir.setLength(radius)) {
144e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                    SkVector dirT;
145e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                    dirT.set(dir.fY, -dir.fX); // Get perpendicular direction
146e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                    SkPoint l1a = pts[0]+dirT, l1b = pts[1]+dirT,
147e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                            l2a = pts[0]-dirT, l2b = pts[1]-dirT;
148e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                    SkPoint miterPt[2];
149e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                    bool useMiterPoint = false;
150e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                    int idx0(-1), idx1(-1);
151e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                    if (NULL == lastPt) {
152e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                        firstDir = dir;
153e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                    } else {
154e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                        SkVector v1 = dir;
155e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                        if (v0.normalize() && v1.normalize()) {
156e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                            SkScalar dotProd = v0.dot(v1);
157e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                            // No need for bevel or miter join if the angle
158e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                            // is either 0 or 180 degrees
159e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                            if (!SkScalarNearlyZero(dotProd + SK_Scalar1) &&
160e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                !SkScalarNearlyZero(dotProd - SK_Scalar1)) {
161e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                bool ccw = !is_clockwise(v0, v1);
162e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                int offset = ccw ? 1 : 0;
163e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                idx0 = vCount-2+offset;
164e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                idx1 = vCount+offset;
165e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                const SkPoint* pt0 = &(lastPt[offset]);
166e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                const SkPoint* pt1 = ccw ? &l2a : &l1a;
167e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                switch(join) {
168e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                    case SkPaint::kMiter_Join:
169e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                    {
170e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                        // *Note : Logic is from MiterJoiner
171e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com
172e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                        // FIXME : Special case if we have a right angle ?
173e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                        // if (SkScalarNearlyZero(dotProd)) {...}
174e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com
175e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                        SkScalar sinHalfAngleSq =
176e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                                SkScalarHalf(SK_Scalar1 + dotProd);
177e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                        if (sinHalfAngleSq >= invMiterLimitSq) {
178e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                            // Find the miter point (or points if it is further
179e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                            // than the miter limit)
180e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                            const SkPoint pt2 = *pt0+v0, pt3 = *pt1+v1;
181e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                            if (intersection(*pt0, pt2, *pt1, pt3, miterPt[0]) !=
182e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                                kNone_IntersectionType) {
183e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                                SkPoint miterPt0 = miterPt[0] - *pt0;
184e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                                SkPoint miterPt1 = miterPt[0] - *pt1;
185e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                                SkScalar sqDist0 = miterPt0.dot(miterPt0);
186e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                                SkScalar sqDist1 = miterPt1.dot(miterPt1);
187e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                                const SkScalar rSq =
188e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                                        SkScalarDiv(SkScalarMul(radius, radius),
189e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                                                    sinHalfAngleSq);
190e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                                const SkScalar sqRLimit =
191e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                                        SkScalarMul(sqMiterLimit, rSq);
192e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                                if (sqDist0 > sqRLimit || sqDist1 > sqRLimit) {
193e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                                    if (sqDist1 > sqRLimit) {
194e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                                        v1.setLength(SkScalarSqrt(sqRLimit));
195e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                                        miterPt[1] = *pt1+v1;
196e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                                    } else {
197e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                                        miterPt[1] = miterPt[0];
198e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                                    }
199e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                                    if (sqDist0 > sqRLimit) {
200e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                                        v0.setLength(SkScalarSqrt(sqRLimit));
201e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                                        miterPt[0] = *pt0+v0;
202e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                                    }
203e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                                } else {
204e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                                    miterPt[1] = miterPt[0];
205e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                                }
206e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                                useMiterPoint = true;
207e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                            }
208e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                        }
209e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                        if (useMiterPoint && (miterPt[1] == miterPt[0])) {
210e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                            break;
211e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                        }
212e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                    }
213e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                    default:
214e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                    case SkPaint::kBevel_Join:
215e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                    {
216e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                        // Note : This currently causes some overdraw where both
217e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                        //        lines initially intersect. We'd need to add
218e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                        //        another line intersection check here if the
219e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                        //        overdraw becomes an issue instead of using the
220e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                        //        current point directly.
221e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com
222e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                        // Add center point
223e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                        *verts++ = pts[0]; // Use current point directly
224e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                        // This idx is passed the current point so increment it
225e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                        ++idx1;
226e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                        // Add center triangle
227e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                        *idxs++ = idx0;
228e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                        *idxs++ = vCount;
229e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                        *idxs++ = idx1;
230e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                        vCount++;
231e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                        iCount += 3;
232e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                    }
233e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                    break;
234e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                                }
235e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                            }
236e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                        }
237e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                    }
238e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                    *verts++ = l1a;
239e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                    *verts++ = l2a;
240e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                    lastPt   = verts;
241e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                    *verts++ = l1b;
242e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                    *verts++ = l2b;
243e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com
244e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                    if (useMiterPoint && (idx0 >= 0) && (idx1 >= 0)) {
245e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                        firstPt[idx0] = miterPt[0];
246e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                        firstPt[idx1] = miterPt[1];
247e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                    }
248e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com
249e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                    // 1st triangle
250e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                    *idxs++  = vCount+0;
251e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                    *idxs++  = vCount+2;
252e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                    *idxs++  = vCount+1;
253e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                    // 2nd triangle
254e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                    *idxs++  = vCount+1;
255e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                    *idxs++  = vCount+2;
256e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                    *idxs++  = vCount+3;
257e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com
258e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                    vCount += 4;
259e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                    iCount += 6;
260e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                }
261e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com            }
262e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                break;
263e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com            case SkPath::kQuad_Verb:
264e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com            case SkPath::kCubic_Verb:
265330313a8a8343876ee596da39da06a5d69badd9cmtklein@google.com                SkDEBUGFAIL("Curves not supported!");
266e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com            default:
267e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                // Unhandled cases
268f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org                SkASSERT(false);
269e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com        }
270e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    }
271e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com
272e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    if (isOpen) {
273e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com        // Add caps
274e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com        switch (stroke.getCap()) {
275e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com            case SkPaint::kSquare_Cap:
276e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                firstPt[0] -= firstDir;
277e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                firstPt[1] -= firstDir;
278e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                lastPt [0] += dir;
279e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                lastPt [1] += dir;
280e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                break;
281e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com            case SkPaint::kRound_Cap:
282330313a8a8343876ee596da39da06a5d69badd9cmtklein@google.com                SkDEBUGFAIL("Round caps not supported!");
283e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com            default: // No cap
284e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                break;
285e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com        }
286e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    }
287e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com
288f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(vCount <= maxVertexCount);
289f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(iCount <= maxIndexCount);
290e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com
291e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    if (vCount > 0) {
292e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com        target->drawIndexed(kTriangles_GrPrimitiveType,
293e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                            0,        // start vertex
294e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                            0,        // start index
295e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                            vCount,
296e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com                            iCount);
297e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    }
298e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com
299e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com    return true;
300e3453cbd20d00d685131a09d9141b1c70f0c5710sugoi@google.com}
301