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