1fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/* 2fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Copyright 2006 The Android Open Source Project 3fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * 4fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Use of this source code is governed by a BSD-style license that can be 5fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * found in the LICENSE file. 6fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */ 7fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 8fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkStrokerPriv.h" 9fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkGeometry.h" 10fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkPath.h" 11fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkPointPriv.h" 12fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 13fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void ButtCapper(SkPath* path, const SkPoint& pivot, const SkVector& normal, 14fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const SkPoint& stop, SkPath*) { 15fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot path->lineTo(stop.fX, stop.fY); 16fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 17fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 18fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void RoundCapper(SkPath* path, const SkPoint& pivot, const SkVector& normal, 19fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const SkPoint& stop, SkPath*) { 20fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkVector parallel; 21fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkPointPriv::RotateCW(normal, ¶llel); 22fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 23fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkPoint projectedCenter = pivot + parallel; 24fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 25fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot path->conicTo(projectedCenter + normal, projectedCenter, SK_ScalarRoot2Over2); 26fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot path->conicTo(projectedCenter - normal, stop, SK_ScalarRoot2Over2); 27fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 28fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 29fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void SquareCapper(SkPath* path, const SkPoint& pivot, const SkVector& normal, 30fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const SkPoint& stop, SkPath* otherPath) { 31fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkVector parallel; 32fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkPointPriv::RotateCW(normal, ¶llel); 33fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 34fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (otherPath) { 35fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot path->setLastPt(pivot.fX + normal.fX + parallel.fX, pivot.fY + normal.fY + parallel.fY); 36fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot path->lineTo(pivot.fX - normal.fX + parallel.fX, pivot.fY - normal.fY + parallel.fY); 37fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } else { 38fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot path->lineTo(pivot.fX + normal.fX + parallel.fX, pivot.fY + normal.fY + parallel.fY); 39fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot path->lineTo(pivot.fX - normal.fX + parallel.fX, pivot.fY - normal.fY + parallel.fY); 40fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot path->lineTo(stop.fX, stop.fY); 41fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 42fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 43fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 44fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot///////////////////////////////////////////////////////////////////////////// 45fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 46fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic bool is_clockwise(const SkVector& before, const SkVector& after) { 47fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return before.fX * after.fY > before.fY * after.fX; 48fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 49fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 50fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotenum AngleType { 51fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot kNearly180_AngleType, 52fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot kSharp_AngleType, 53fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot kShallow_AngleType, 54fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot kNearlyLine_AngleType 55fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}; 56fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 57fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic AngleType Dot2AngleType(SkScalar dot) { 58fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// need more precise fixed normalization 59fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// SkASSERT(SkScalarAbs(dot) <= SK_Scalar1 + SK_ScalarNearlyZero); 60fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 61fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (dot >= 0) { // shallow or line 62fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return SkScalarNearlyZero(SK_Scalar1 - dot) ? kNearlyLine_AngleType : kShallow_AngleType; 63fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } else { // sharp or 180 64fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return SkScalarNearlyZero(SK_Scalar1 + dot) ? kNearly180_AngleType : kSharp_AngleType; 65fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 66fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 67fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 68fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void HandleInnerJoin(SkPath* inner, const SkPoint& pivot, const SkVector& after) { 69fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if 1 70fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot /* In the degenerate case that the stroke radius is larger than our segments 71fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot just connecting the two inner segments may "show through" as a funny 72fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot diagonal. To pseudo-fix this, we go through the pivot point. This adds 73fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot an extra point/edge, but I can't see a cheap way to know when this is 74fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot not needed :( 75fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */ 76fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot inner->lineTo(pivot.fX, pivot.fY); 77fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif 78fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 79fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot inner->lineTo(pivot.fX - after.fX, pivot.fY - after.fY); 80fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 81fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 82fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void BluntJoiner(SkPath* outer, SkPath* inner, const SkVector& beforeUnitNormal, 83fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const SkPoint& pivot, const SkVector& afterUnitNormal, 84fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkScalar radius, SkScalar invMiterLimit, bool, bool) { 85fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkVector after; 86fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot afterUnitNormal.scale(radius, &after); 87fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 88fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (!is_clockwise(beforeUnitNormal, afterUnitNormal)) { 89fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkTSwap<SkPath*>(outer, inner); 90fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot after.negate(); 91fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 92fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 93fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot outer->lineTo(pivot.fX + after.fX, pivot.fY + after.fY); 94fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot HandleInnerJoin(inner, pivot, after); 95fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 96fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 97fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void RoundJoiner(SkPath* outer, SkPath* inner, const SkVector& beforeUnitNormal, 98fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const SkPoint& pivot, const SkVector& afterUnitNormal, 99fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkScalar radius, SkScalar invMiterLimit, bool, bool) { 100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkScalar dotProd = SkPoint::DotProduct(beforeUnitNormal, afterUnitNormal); 101fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot AngleType angleType = Dot2AngleType(dotProd); 102fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 103fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (angleType == kNearlyLine_AngleType) 104fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return; 105fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 106fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkVector before = beforeUnitNormal; 107fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkVector after = afterUnitNormal; 108fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkRotationDirection dir = kCW_SkRotationDirection; 109fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 110fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (!is_clockwise(before, after)) { 111fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkTSwap<SkPath*>(outer, inner); 112fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot before.negate(); 113fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot after.negate(); 114fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot dir = kCCW_SkRotationDirection; 115fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 116fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 117fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkMatrix matrix; 118fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot matrix.setScale(radius, radius); 119fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot matrix.postTranslate(pivot.fX, pivot.fY); 120fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkConic conics[SkConic::kMaxConicsForArc]; 121fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot int count = SkConic::BuildUnitArc(before, after, dir, &matrix, conics); 122fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (count > 0) { 123fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot for (int i = 0; i < count; ++i) { 124fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot outer->conicTo(conics[i].fPts[1], conics[i].fPts[2], conics[i].fW); 125fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 126fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot after.scale(radius); 127fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot HandleInnerJoin(inner, pivot, after); 128fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 129fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 130fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 131fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#define kOneOverSqrt2 (0.707106781f) 132fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 133fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void MiterJoiner(SkPath* outer, SkPath* inner, const SkVector& beforeUnitNormal, 134fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const SkPoint& pivot, const SkVector& afterUnitNormal, 135fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkScalar radius, SkScalar invMiterLimit, 136fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot bool prevIsLine, bool currIsLine) { 137fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // negate the dot since we're using normals instead of tangents 138fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkScalar dotProd = SkPoint::DotProduct(beforeUnitNormal, afterUnitNormal); 139fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot AngleType angleType = Dot2AngleType(dotProd); 140fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkVector before = beforeUnitNormal; 141fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkVector after = afterUnitNormal; 142fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkVector mid; 143fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkScalar sinHalfAngle; 144fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot bool ccw; 145fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 146fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (angleType == kNearlyLine_AngleType) { 147fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return; 148fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 149fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (angleType == kNearly180_AngleType) { 150fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot currIsLine = false; 151fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot goto DO_BLUNT; 152fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 153fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 154fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot ccw = !is_clockwise(before, after); 155fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (ccw) { 156fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkTSwap<SkPath*>(outer, inner); 157fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot before.negate(); 158fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot after.negate(); 159fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 160fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 161fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot /* Before we enter the world of square-roots and divides, 162fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot check if we're trying to join an upright right angle 163fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot (common case for stroking rectangles). If so, special case 164fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot that (for speed an accuracy). 165fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot Note: we only need to check one normal if dot==0 166fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */ 167fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (0 == dotProd && invMiterLimit <= kOneOverSqrt2) { 168fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot mid = (before + after) * radius; 169fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot goto DO_MITER; 170fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 171fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 172fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot /* midLength = radius / sinHalfAngle 173fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (midLength > miterLimit * radius) abort 174fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (radius / sinHalf > miterLimit * radius) abort 175fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (1 / sinHalf > miterLimit) abort 176fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (1 / miterLimit > sinHalf) abort 177fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot My dotProd is opposite sign, since it is built from normals and not tangents 178fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot hence 1 + dot instead of 1 - dot in the formula 179fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */ 180fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot sinHalfAngle = SkScalarSqrt(SkScalarHalf(SK_Scalar1 + dotProd)); 181fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (sinHalfAngle < invMiterLimit) { 182fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot currIsLine = false; 183fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot goto DO_BLUNT; 184fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 185fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 186fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // choose the most accurate way to form the initial mid-vector 187fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (angleType == kSharp_AngleType) { 188fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot mid.set(after.fY - before.fY, before.fX - after.fX); 189fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (ccw) { 190fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot mid.negate(); 191fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 192fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } else { 193fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot mid.set(before.fX + after.fX, before.fY + after.fY); 194fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 195fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 196fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot mid.setLength(radius / sinHalfAngle); 197fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotDO_MITER: 198fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (prevIsLine) { 199fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot outer->setLastPt(pivot.fX + mid.fX, pivot.fY + mid.fY); 200fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } else { 201fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot outer->lineTo(pivot.fX + mid.fX, pivot.fY + mid.fY); 202fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 203fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 204fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotDO_BLUNT: 205fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot after.scale(radius); 206fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (!currIsLine) { 207fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot outer->lineTo(pivot.fX + after.fX, pivot.fY + after.fY); 208fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 209fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot HandleInnerJoin(inner, pivot, after); 210fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 211fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 212fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot///////////////////////////////////////////////////////////////////////////// 213fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 214fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkStrokerPriv::CapProc SkStrokerPriv::CapFactory(SkPaint::Cap cap) { 215fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const SkStrokerPriv::CapProc gCappers[] = { 216fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot ButtCapper, RoundCapper, SquareCapper 217fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot }; 218fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 219fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT((unsigned)cap < SkPaint::kCapCount); 220fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return gCappers[cap]; 221fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 222fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 223fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkStrokerPriv::JoinProc SkStrokerPriv::JoinFactory(SkPaint::Join join) { 224fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const SkStrokerPriv::JoinProc gJoiners[] = { 225fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot MiterJoiner, RoundJoiner, BluntJoiner 226fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot }; 227fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 228fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT((unsigned)join < SkPaint::kJoinCount); 229fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return gJoiners[join]; 230fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 231