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