| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2008 The Android Open Source Project | 2 * Copyright 2008 The Android Open Source Project |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "SkStrokerPriv.h" | 8 #include "SkStrokerPriv.h" |
| 9 #include "SkGeometry.h" | 9 #include "SkGeometry.h" |
| 10 #include "SkPath.h" | 10 #include "SkPath.h" |
| 11 | 11 |
| 12 #ifndef SK_LEGACY_STROKE_CURVES | 12 enum { |
| 13 kTangent_RecursiveLimit, |
| 14 kCubic_RecursiveLimit, |
| 15 kConic_RecursiveLimit, |
| 16 kQuad_RecursiveLimit |
| 17 }; |
| 13 | 18 |
| 14 enum { | 19 // quads with extreme widths (e.g. (0,1) (1,6) (0,3) width=5e7) recurse to point
of failure |
| 15 kTangent_RecursiveLimit, | 20 // largest seen for normal cubics : 5, 26 |
| 16 kCubic_RecursiveLimit, | 21 // largest seen for normal quads : 11 |
| 17 kConic_RecursiveLimit, | 22 static const int kRecursiveLimits[] = { 5*3, 26*3, 11*3, 11*3 }; // 3x limits se
en in practice |
| 18 kQuad_RecursiveLimit | |
| 19 }; | |
| 20 | 23 |
| 21 // quads with extreme widths (e.g. (0,1) (1,6) (0,3) width=5e7) recurse to p
oint of failure | 24 SK_COMPILE_ASSERT(0 == kTangent_RecursiveLimit, cubic_stroke_relies_on_tangent_e
qualling_zero); |
| 22 // largest seen for normal cubics : 5, 26 | 25 SK_COMPILE_ASSERT(1 == kCubic_RecursiveLimit, cubic_stroke_relies_on_cubic_equal
ling_one); |
| 23 // largest seen for normal quads : 11 | 26 SK_COMPILE_ASSERT(SK_ARRAY_COUNT(kRecursiveLimits) == kQuad_RecursiveLimit + 1, |
| 24 static const int kRecursiveLimits[] = { 5*3, 26*3, 11*3, 11*3 }; // 3x limit
s seen in practice | 27 recursive_limits_mismatch); |
| 25 | 28 |
| 26 SK_COMPILE_ASSERT(0 == kTangent_RecursiveLimit, cubic_stroke_relies_on_tange
nt_equalling_zero); | 29 #ifdef SK_DEBUG |
| 27 SK_COMPILE_ASSERT(1 == kCubic_RecursiveLimit, cubic_stroke_relies_on_cubic_e
qualling_one); | 30 int gMaxRecursion[SK_ARRAY_COUNT(kRecursiveLimits)] = { 0 }; |
| 28 SK_COMPILE_ASSERT(SK_ARRAY_COUNT(kRecursiveLimits) == kQuad_RecursiveLimit +
1, | 31 #endif |
| 29 recursive_limits_mismatch); | 32 #ifndef DEBUG_QUAD_STROKER |
| 30 | 33 #define DEBUG_QUAD_STROKER 0 |
| 31 #ifdef SK_DEBUG | |
| 32 int gMaxRecursion[SK_ARRAY_COUNT(kRecursiveLimits)] = { 0 }; | |
| 33 #endif | |
| 34 #ifndef DEBUG_QUAD_STROKER | |
| 35 #define DEBUG_QUAD_STROKER 0 | |
| 36 #endif | |
| 37 | |
| 38 #if DEBUG_QUAD_STROKER | |
| 39 /* Enable to show the decisions made in subdividing the curve -- helpful
when the resulting | |
| 40 stroke has more than the optimal number of quadratics and lines */ | |
| 41 #define STROKER_RESULT(resultType, depth, quadPts, format, ...) \ | |
| 42 SkDebugf("[%d] %s " format "\n", depth, __FUNCTION__, __VA_ARGS_
_), \ | |
| 43 SkDebugf(" " #resultType " t=(%g,%g)\n", quadPts->fStartT, quad
Pts->fEndT), \ | |
| 44 resultType | |
| 45 #define STROKER_DEBUG_PARAMS(...) , __VA_ARGS__ | |
| 46 #else | |
| 47 #define STROKER_RESULT(resultType, depth, quadPts, format, ...) \ | |
| 48 resultType | |
| 49 #define STROKER_DEBUG_PARAMS(...) | |
| 50 #endif | |
| 51 | |
| 52 #endif | 34 #endif |
| 53 | 35 |
| 54 #ifdef SK_LEGACY_STROKE_CURVES | 36 #if DEBUG_QUAD_STROKER |
| 55 #define kMaxQuadSubdivide 5 | 37 /* Enable to show the decisions made in subdividing the curve -- helpful whe
n the resulting |
| 56 #define kMaxCubicSubdivide 7 | 38 stroke has more than the optimal number of quadratics and lines */ |
| 39 #define STROKER_RESULT(resultType, depth, quadPts, format, ...) \ |
| 40 SkDebugf("[%d] %s " format "\n", depth, __FUNCTION__, __VA_ARGS__),
\ |
| 41 SkDebugf(" " #resultType " t=(%g,%g)\n", quadPts->fStartT, quadPts-
>fEndT), \ |
| 42 resultType |
| 43 #define STROKER_DEBUG_PARAMS(...) , __VA_ARGS__ |
| 44 #else |
| 45 #define STROKER_RESULT(resultType, depth, quadPts, format, ...) \ |
| 46 resultType |
| 47 #define STROKER_DEBUG_PARAMS(...) |
| 57 #endif | 48 #endif |
| 58 | 49 |
| 59 static inline bool degenerate_vector(const SkVector& v) { | 50 static inline bool degenerate_vector(const SkVector& v) { |
| 60 return !SkPoint::CanNormalize(v.fX, v.fY); | 51 return !SkPoint::CanNormalize(v.fX, v.fY); |
| 61 } | 52 } |
| 62 | 53 |
| 63 #ifdef SK_LEGACY_STROKE_CURVES | |
| 64 static inline bool normals_too_curvy(const SkVector& norm0, SkVector& norm1) { | |
| 65 /* root2/2 is a 45-degree angle | |
| 66 make this constant bigger for more subdivisions (but not >= 1) | |
| 67 */ | |
| 68 static const SkScalar kFlatEnoughNormalDotProd = | |
| 69 SK_ScalarSqrt2/2 + SK_Scalar1/10; | |
| 70 | |
| 71 SkASSERT(kFlatEnoughNormalDotProd > 0 && | |
| 72 kFlatEnoughNormalDotProd < SK_Scalar1); | |
| 73 | |
| 74 return SkPoint::DotProduct(norm0, norm1) <= kFlatEnoughNormalDotProd; | |
| 75 } | |
| 76 | |
| 77 static inline bool normals_too_pinchy(const SkVector& norm0, SkVector& norm1) { | |
| 78 // if the dot-product is -1, then we are definitely too pinchy. We tweak | |
| 79 // that by an epsilon to ensure we have significant bits in our test | |
| 80 static const int kMinSigBitsForDot = 8; | |
| 81 static const SkScalar kDotEpsilon = FLT_EPSILON * (1 << kMinSigBitsForDot); | |
| 82 static const SkScalar kTooPinchyNormalDotProd = kDotEpsilon - 1; | |
| 83 | |
| 84 // just some sanity asserts to help document the expected range | |
| 85 SkASSERT(kTooPinchyNormalDotProd >= -1); | |
| 86 SkASSERT(kTooPinchyNormalDotProd < SkDoubleToScalar(-0.999)); | |
| 87 | |
| 88 SkScalar dot = SkPoint::DotProduct(norm0, norm1); | |
| 89 return dot <= kTooPinchyNormalDotProd; | |
| 90 } | |
| 91 #endif | |
| 92 | |
| 93 static bool set_normal_unitnormal(const SkPoint& before, const SkPoint& after, | 54 static bool set_normal_unitnormal(const SkPoint& before, const SkPoint& after, |
| 94 SkScalar radius, | 55 SkScalar radius, |
| 95 SkVector* normal, SkVector* unitNormal) { | 56 SkVector* normal, SkVector* unitNormal) { |
| 96 if (!unitNormal->setNormalize(after.fX - before.fX, after.fY - before.fY)) { | 57 if (!unitNormal->setNormalize(after.fX - before.fX, after.fY - before.fY)) { |
| 97 return false; | 58 return false; |
| 98 } | 59 } |
| 99 unitNormal->rotateCCW(); | 60 unitNormal->rotateCCW(); |
| 100 unitNormal->scale(radius, normal); | 61 unitNormal->scale(radius, normal); |
| 101 return true; | 62 return true; |
| 102 } | 63 } |
| 103 | 64 |
| 104 static bool set_normal_unitnormal(const SkVector& vec, | 65 static bool set_normal_unitnormal(const SkVector& vec, |
| 105 SkScalar radius, | 66 SkScalar radius, |
| 106 SkVector* normal, SkVector* unitNormal) { | 67 SkVector* normal, SkVector* unitNormal) { |
| 107 if (!unitNormal->setNormalize(vec.fX, vec.fY)) { | 68 if (!unitNormal->setNormalize(vec.fX, vec.fY)) { |
| 108 return false; | 69 return false; |
| 109 } | 70 } |
| 110 unitNormal->rotateCCW(); | 71 unitNormal->rotateCCW(); |
| 111 unitNormal->scale(radius, normal); | 72 unitNormal->scale(radius, normal); |
| 112 return true; | 73 return true; |
| 113 } | 74 } |
| 114 | 75 |
| 115 /////////////////////////////////////////////////////////////////////////////// | 76 /////////////////////////////////////////////////////////////////////////////// |
| 116 #ifndef SK_LEGACY_STROKE_CURVES | |
| 117 | 77 |
| 118 struct SkQuadConstruct { // The state of the quad stroke under construction. | 78 struct SkQuadConstruct { // The state of the quad stroke under construction. |
| 119 SkPoint fQuad[3]; // the stroked quad parallel to the original curve | 79 SkPoint fQuad[3]; // the stroked quad parallel to the original curve |
| 120 SkPoint fTangentStart; // a point tangent to fQuad[0] | 80 SkPoint fTangentStart; // a point tangent to fQuad[0] |
| 121 SkPoint fTangentEnd; // a point tangent to fQuad[2] | 81 SkPoint fTangentEnd; // a point tangent to fQuad[2] |
| 122 SkScalar fStartT; // a segment of the original curve | 82 SkScalar fStartT; // a segment of the original curve |
| 123 SkScalar fMidT; // " | 83 SkScalar fMidT; // " |
| 124 SkScalar fEndT; // " | 84 SkScalar fEndT; // " |
| 125 bool fStartSet; // state to share common points across structs | 85 bool fStartSet; // state to share common points across structs |
| 126 bool fEndSet; // " | 86 bool fEndSet; // " |
| (...skipping 20 matching lines...) Expand all Loading... |
| 147 bool initWithEnd(SkQuadConstruct* parent) { | 107 bool initWithEnd(SkQuadConstruct* parent) { |
| 148 if (!init(parent->fMidT, parent->fEndT)) { | 108 if (!init(parent->fMidT, parent->fEndT)) { |
| 149 return false; | 109 return false; |
| 150 } | 110 } |
| 151 fQuad[2] = parent->fQuad[2]; | 111 fQuad[2] = parent->fQuad[2]; |
| 152 fTangentEnd = parent->fTangentEnd; | 112 fTangentEnd = parent->fTangentEnd; |
| 153 fEndSet = true; | 113 fEndSet = true; |
| 154 return true; | 114 return true; |
| 155 } | 115 } |
| 156 }; | 116 }; |
| 157 #endif | |
| 158 | 117 |
| 159 class SkPathStroker { | 118 class SkPathStroker { |
| 160 public: | 119 public: |
| 161 SkPathStroker(const SkPath& src, | 120 SkPathStroker(const SkPath& src, |
| 162 SkScalar radius, SkScalar miterLimit, SkPaint::Cap, | 121 SkScalar radius, SkScalar miterLimit, SkPaint::Cap, |
| 163 SkPaint::Join, SkScalar resScale); | 122 SkPaint::Join, SkScalar resScale); |
| 164 | 123 |
| 165 void moveTo(const SkPoint&); | 124 void moveTo(const SkPoint&); |
| 166 void lineTo(const SkPoint&); | 125 void lineTo(const SkPoint&); |
| 167 void quadTo(const SkPoint&, const SkPoint&); | 126 void quadTo(const SkPoint&, const SkPoint&); |
| 168 #ifndef SK_LEGACY_STROKE_CURVES | |
| 169 void conicTo(const SkPoint&, const SkPoint&, SkScalar weight); | 127 void conicTo(const SkPoint&, const SkPoint&, SkScalar weight); |
| 170 #endif | |
| 171 void cubicTo(const SkPoint&, const SkPoint&, const SkPoint&); | 128 void cubicTo(const SkPoint&, const SkPoint&, const SkPoint&); |
| 172 void close(bool isLine) { this->finishContour(true, isLine); } | 129 void close(bool isLine) { this->finishContour(true, isLine); } |
| 173 | 130 |
| 174 void done(SkPath* dst, bool isLine) { | 131 void done(SkPath* dst, bool isLine) { |
| 175 this->finishContour(false, isLine); | 132 this->finishContour(false, isLine); |
| 176 fOuter.addPath(fExtra); | 133 fOuter.addPath(fExtra); |
| 177 dst->swap(fOuter); | 134 dst->swap(fOuter); |
| 178 } | 135 } |
| 179 | 136 |
| 180 SkScalar getResScale() const { return fResScale; } | 137 SkScalar getResScale() const { return fResScale; } |
| 181 | 138 |
| 182 private: | 139 private: |
| 183 SkScalar fRadius; | 140 SkScalar fRadius; |
| 184 SkScalar fInvMiterLimit; | 141 SkScalar fInvMiterLimit; |
| 185 SkScalar fResScale; | 142 SkScalar fResScale; |
| 186 #ifndef SK_LEGACY_STROKE_CURVES | |
| 187 SkScalar fInvResScale; | 143 SkScalar fInvResScale; |
| 188 SkScalar fInvResScaleSquared; | 144 SkScalar fInvResScaleSquared; |
| 189 #endif | |
| 190 | 145 |
| 191 SkVector fFirstNormal, fPrevNormal, fFirstUnitNormal, fPrevUnitNormal; | 146 SkVector fFirstNormal, fPrevNormal, fFirstUnitNormal, fPrevUnitNormal; |
| 192 SkPoint fFirstPt, fPrevPt; // on original path | 147 SkPoint fFirstPt, fPrevPt; // on original path |
| 193 SkPoint fFirstOuterPt; | 148 SkPoint fFirstOuterPt; |
| 194 int fSegmentCount; | 149 int fSegmentCount; |
| 195 bool fPrevIsLine; | 150 bool fPrevIsLine; |
| 196 | 151 |
| 197 SkStrokerPriv::CapProc fCapper; | 152 SkStrokerPriv::CapProc fCapper; |
| 198 SkStrokerPriv::JoinProc fJoiner; | 153 SkStrokerPriv::JoinProc fJoiner; |
| 199 | 154 |
| 200 SkPath fInner, fOuter; // outer is our working answer, inner is temp | 155 SkPath fInner, fOuter; // outer is our working answer, inner is temp |
| 201 SkPath fExtra; // added as extra complete contours | 156 SkPath fExtra; // added as extra complete contours |
| 202 | 157 |
| 203 #ifndef SK_LEGACY_STROKE_CURVES | |
| 204 enum StrokeType { | 158 enum StrokeType { |
| 205 kOuter_StrokeType = 1, // use sign-opposite values later to flip pe
rpendicular axis | 159 kOuter_StrokeType = 1, // use sign-opposite values later to flip pe
rpendicular axis |
| 206 kInner_StrokeType = -1 | 160 kInner_StrokeType = -1 |
| 207 } fStrokeType; | 161 } fStrokeType; |
| 208 | 162 |
| 209 enum ResultType { | 163 enum ResultType { |
| 210 kSplit_ResultType, // the caller should split the quad stroke i
n two | 164 kSplit_ResultType, // the caller should split the quad stroke i
n two |
| 211 kDegenerate_ResultType, // the caller should add a line | 165 kDegenerate_ResultType, // the caller should add a line |
| 212 kQuad_ResultType, // the caller should (continue to try to) ad
d a quad stroke | 166 kQuad_ResultType, // the caller should (continue to try to) ad
d a quad stroke |
| 213 kNormalError_ResultType, // the cubic's normal couldn't be computed -
- abort | 167 kNormalError_ResultType, // the cubic's normal couldn't be computed -
- abort |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 261 const SkVector& normalAB, const SkVector& unitNormalA
B, | 215 const SkVector& normalAB, const SkVector& unitNormalA
B, |
| 262 SkVector* normalCD, SkVector* unitNormalCD); | 216 SkVector* normalCD, SkVector* unitNormalCD); |
| 263 void setQuadEndNormal(const SkPoint quad[3], | 217 void setQuadEndNormal(const SkPoint quad[3], |
| 264 const SkVector& normalAB, const SkVector& unitNormalAB
, | 218 const SkVector& normalAB, const SkVector& unitNormalAB
, |
| 265 SkVector* normalBC, SkVector* unitNormalBC); | 219 SkVector* normalBC, SkVector* unitNormalBC); |
| 266 void setRayPts(const SkPoint& tPt, SkVector* dxy, SkPoint* onPt, SkPoint* ta
ngent) const; | 220 void setRayPts(const SkPoint& tPt, SkVector* dxy, SkPoint* onPt, SkPoint* ta
ngent) const; |
| 267 static bool SlightAngle(SkQuadConstruct* ); | 221 static bool SlightAngle(SkQuadConstruct* ); |
| 268 ResultType strokeCloseEnough(const SkPoint stroke[3], const SkPoint ray[2], | 222 ResultType strokeCloseEnough(const SkPoint stroke[3], const SkPoint ray[2], |
| 269 SkQuadConstruct* STROKER_DEBUG_PARAMS(int dept
h) ) const; | 223 SkQuadConstruct* STROKER_DEBUG_PARAMS(int dept
h) ) const; |
| 270 ResultType tangentsMeet(const SkPoint cubic[4], SkQuadConstruct* ); | 224 ResultType tangentsMeet(const SkPoint cubic[4], SkQuadConstruct* ); |
| 271 #endif | |
| 272 | 225 |
| 273 void finishContour(bool close, bool isLine); | 226 void finishContour(bool close, bool isLine); |
| 274 bool preJoinTo(const SkPoint&, SkVector* normal, SkVector* unitNormal, | 227 bool preJoinTo(const SkPoint&, SkVector* normal, SkVector* unitNormal, |
| 275 bool isLine); | 228 bool isLine); |
| 276 void postJoinTo(const SkPoint&, const SkVector& normal, | 229 void postJoinTo(const SkPoint&, const SkVector& normal, |
| 277 const SkVector& unitNormal); | 230 const SkVector& unitNormal); |
| 278 | 231 |
| 279 void line_to(const SkPoint& currPt, const SkVector& normal); | 232 void line_to(const SkPoint& currPt, const SkVector& normal); |
| 280 #ifdef SK_LEGACY_STROKE_CURVES | |
| 281 void quad_to(const SkPoint pts[3], | |
| 282 const SkVector& normalAB, const SkVector& unitNormalAB, | |
| 283 SkVector* normalBC, SkVector* unitNormalBC, | |
| 284 int subDivide); | |
| 285 void cubic_to(const SkPoint pts[4], | |
| 286 const SkVector& normalAB, const SkVector& unitNormalAB, | |
| 287 SkVector* normalCD, SkVector* unitNormalCD, | |
| 288 int subDivide); | |
| 289 #endif | |
| 290 }; | 233 }; |
| 291 | 234 |
| 292 /////////////////////////////////////////////////////////////////////////////// | 235 /////////////////////////////////////////////////////////////////////////////// |
| 293 | 236 |
| 294 bool SkPathStroker::preJoinTo(const SkPoint& currPt, SkVector* normal, | 237 bool SkPathStroker::preJoinTo(const SkPoint& currPt, SkVector* normal, |
| 295 SkVector* unitNormal, bool currIsLine) { | 238 SkVector* unitNormal, bool currIsLine) { |
| 296 SkASSERT(fSegmentCount >= 0); | 239 SkASSERT(fSegmentCount >= 0); |
| 297 | 240 |
| 298 SkScalar prevX = fPrevPt.fX; | 241 SkScalar prevX = fPrevPt.fX; |
| 299 SkScalar prevY = fPrevPt.fY; | 242 SkScalar prevY = fPrevPt.fY; |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 385 // Need some estimate of how large our final result (fOuter) | 328 // Need some estimate of how large our final result (fOuter) |
| 386 // and our per-contour temp (fInner) will be, so we don't spend | 329 // and our per-contour temp (fInner) will be, so we don't spend |
| 387 // extra time repeatedly growing these arrays. | 330 // extra time repeatedly growing these arrays. |
| 388 // | 331 // |
| 389 // 3x for result == inner + outer + join (swag) | 332 // 3x for result == inner + outer + join (swag) |
| 390 // 1x for inner == 'wag' (worst contour length would be better guess) | 333 // 1x for inner == 'wag' (worst contour length would be better guess) |
| 391 fOuter.incReserve(src.countPoints() * 3); | 334 fOuter.incReserve(src.countPoints() * 3); |
| 392 fOuter.setIsVolatile(true); | 335 fOuter.setIsVolatile(true); |
| 393 fInner.incReserve(src.countPoints()); | 336 fInner.incReserve(src.countPoints()); |
| 394 fInner.setIsVolatile(true); | 337 fInner.setIsVolatile(true); |
| 395 #ifndef SK_LEGACY_STROKE_CURVES | |
| 396 // TODO : write a common error function used by stroking and filling | 338 // TODO : write a common error function used by stroking and filling |
| 397 // The '4' below matches the fill scan converter's error term | 339 // The '4' below matches the fill scan converter's error term |
| 398 fInvResScale = SkScalarInvert(resScale * 4); | 340 fInvResScale = SkScalarInvert(resScale * 4); |
| 399 fInvResScaleSquared = fInvResScale * fInvResScale; | 341 fInvResScaleSquared = fInvResScale * fInvResScale; |
| 400 fRecursionDepth = 0; | 342 fRecursionDepth = 0; |
| 401 #endif | |
| 402 } | 343 } |
| 403 | 344 |
| 404 void SkPathStroker::moveTo(const SkPoint& pt) { | 345 void SkPathStroker::moveTo(const SkPoint& pt) { |
| 405 if (fSegmentCount > 0) { | 346 if (fSegmentCount > 0) { |
| 406 this->finishContour(false, false); | 347 this->finishContour(false, false); |
| 407 } | 348 } |
| 408 fSegmentCount = 0; | 349 fSegmentCount = 0; |
| 409 fFirstPt = fPrevPt = pt; | 350 fFirstPt = fPrevPt = pt; |
| 410 } | 351 } |
| 411 | 352 |
| 412 void SkPathStroker::line_to(const SkPoint& currPt, const SkVector& normal) { | 353 void SkPathStroker::line_to(const SkPoint& currPt, const SkVector& normal) { |
| 413 fOuter.lineTo(currPt.fX + normal.fX, currPt.fY + normal.fY); | 354 fOuter.lineTo(currPt.fX + normal.fX, currPt.fY + normal.fY); |
| 414 fInner.lineTo(currPt.fX - normal.fX, currPt.fY - normal.fY); | 355 fInner.lineTo(currPt.fX - normal.fX, currPt.fY - normal.fY); |
| 415 } | 356 } |
| 416 | 357 |
| 417 void SkPathStroker::lineTo(const SkPoint& currPt) { | 358 void SkPathStroker::lineTo(const SkPoint& currPt) { |
| 418 if (SkPath::IsLineDegenerate(fPrevPt, currPt)) { | 359 if (SkPath::IsLineDegenerate(fPrevPt, currPt)) { |
| 419 return; | 360 return; |
| 420 } | 361 } |
| 421 SkVector normal, unitNormal; | 362 SkVector normal, unitNormal; |
| 422 | 363 |
| 423 if (!this->preJoinTo(currPt, &normal, &unitNormal, true)) { | 364 if (!this->preJoinTo(currPt, &normal, &unitNormal, true)) { |
| 424 return; | 365 return; |
| 425 } | 366 } |
| 426 this->line_to(currPt, normal); | 367 this->line_to(currPt, normal); |
| 427 this->postJoinTo(currPt, normal, unitNormal); | 368 this->postJoinTo(currPt, normal, unitNormal); |
| 428 } | 369 } |
| 429 | 370 |
| 430 #ifdef SK_LEGACY_STROKE_CURVES | |
| 431 void SkPathStroker::quad_to(const SkPoint pts[3], | |
| 432 const SkVector& normalAB, const SkVector& unitNormalAB, | |
| 433 SkVector* normalBC, SkVector* unitNormalBC, | |
| 434 int subDivide) { | |
| 435 if (!set_normal_unitnormal(pts[1], pts[2], fRadius, | |
| 436 normalBC, unitNormalBC)) { | |
| 437 // pts[1] nearly equals pts[2], so just draw a line to pts[2] | |
| 438 this->line_to(pts[2], normalAB); | |
| 439 *normalBC = normalAB; | |
| 440 *unitNormalBC = unitNormalAB; | |
| 441 return; | |
| 442 } | |
| 443 | |
| 444 if (--subDivide >= 0 && normals_too_curvy(unitNormalAB, *unitNormalBC)) { | |
| 445 SkPoint tmp[5]; | |
| 446 SkVector norm, unit; | |
| 447 | |
| 448 SkChopQuadAtHalf(pts, tmp); | |
| 449 this->quad_to(&tmp[0], normalAB, unitNormalAB, &norm, &unit, subDivide); | |
| 450 this->quad_to(&tmp[2], norm, unit, normalBC, unitNormalBC, subDivide); | |
| 451 } else { | |
| 452 SkVector normalB; | |
| 453 | |
| 454 normalB = pts[2] - pts[0]; | |
| 455 normalB.rotateCCW(); | |
| 456 SkScalar dot = SkPoint::DotProduct(unitNormalAB, *unitNormalBC); | |
| 457 SkAssertResult(normalB.setLength(fRadius / SkScalarSqrt((SK_Scalar1 + do
t)/2))); | |
| 458 | |
| 459 fOuter.quadTo( pts[1].fX + normalB.fX, pts[1].fY + normalB.fY, | |
| 460 pts[2].fX + normalBC->fX, pts[2].fY + normalBC->fY); | |
| 461 fInner.quadTo( pts[1].fX - normalB.fX, pts[1].fY - normalB.fY, | |
| 462 pts[2].fX - normalBC->fX, pts[2].fY - normalBC->fY); | |
| 463 } | |
| 464 } | |
| 465 #endif | |
| 466 | |
| 467 #ifndef SK_LEGACY_STROKE_CURVES | |
| 468 void SkPathStroker::setQuadEndNormal(const SkPoint quad[3], const SkVector& norm
alAB, | 371 void SkPathStroker::setQuadEndNormal(const SkPoint quad[3], const SkVector& norm
alAB, |
| 469 const SkVector& unitNormalAB, SkVector* normalBC, SkVector* unitNormalBC
) { | 372 const SkVector& unitNormalAB, SkVector* normalBC, SkVector* unitNormalBC
) { |
| 470 if (!set_normal_unitnormal(quad[1], quad[2], fRadius, normalBC, unitNormalBC
)) { | 373 if (!set_normal_unitnormal(quad[1], quad[2], fRadius, normalBC, unitNormalBC
)) { |
| 471 *normalBC = normalAB; | 374 *normalBC = normalAB; |
| 472 *unitNormalBC = unitNormalAB; | 375 *unitNormalBC = unitNormalAB; |
| 473 } | 376 } |
| 474 } | 377 } |
| 475 | 378 |
| 476 void SkPathStroker::setConicEndNormal(const SkConic& conic, const SkVector& norm
alAB, | 379 void SkPathStroker::setConicEndNormal(const SkConic& conic, const SkVector& norm
alAB, |
| 477 const SkVector& unitNormalAB, SkVector* normalBC, SkVector* unitNormalBC
) { | 380 const SkVector& unitNormalAB, SkVector* normalBC, SkVector* unitNormalBC
) { |
| (...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 693 return kQuad_ReductionType; | 596 return kQuad_ReductionType; |
| 694 } | 597 } |
| 695 SkScalar t = SkFindQuadMaxCurvature(quad); | 598 SkScalar t = SkFindQuadMaxCurvature(quad); |
| 696 if (0 == t) { | 599 if (0 == t) { |
| 697 return kLine_ReductionType; | 600 return kLine_ReductionType; |
| 698 } | 601 } |
| 699 SkEvalQuadAt(quad, t, reduction, NULL); | 602 SkEvalQuadAt(quad, t, reduction, NULL); |
| 700 return kDegenerate_ReductionType; | 603 return kDegenerate_ReductionType; |
| 701 } | 604 } |
| 702 | 605 |
| 703 #else | |
| 704 | |
| 705 void SkPathStroker::cubic_to(const SkPoint pts[4], | |
| 706 const SkVector& normalAB, const SkVector& unitNormalAB, | |
| 707 SkVector* normalCD, SkVector* unitNormalCD, | |
| 708 int subDivide) { | |
| 709 SkVector ab = pts[1] - pts[0]; | |
| 710 SkVector cd = pts[3] - pts[2]; | |
| 711 SkVector normalBC, unitNormalBC; | |
| 712 | |
| 713 bool degenerateAB = degenerate_vector(ab); | |
| 714 bool degenerateCD = degenerate_vector(cd); | |
| 715 | |
| 716 if (degenerateAB && degenerateCD) { | |
| 717 DRAW_LINE: | |
| 718 this->line_to(pts[3], normalAB); | |
| 719 *normalCD = normalAB; | |
| 720 *unitNormalCD = unitNormalAB; | |
| 721 return; | |
| 722 } | |
| 723 | |
| 724 if (degenerateAB) { | |
| 725 ab = pts[2] - pts[0]; | |
| 726 degenerateAB = degenerate_vector(ab); | |
| 727 } | |
| 728 if (degenerateCD) { | |
| 729 cd = pts[3] - pts[1]; | |
| 730 degenerateCD = degenerate_vector(cd); | |
| 731 } | |
| 732 if (degenerateAB || degenerateCD) { | |
| 733 goto DRAW_LINE; | |
| 734 } | |
| 735 SkAssertResult(set_normal_unitnormal(cd, fRadius, normalCD, unitNormalCD)); | |
| 736 bool degenerateBC = !set_normal_unitnormal(pts[1], pts[2], fRadius, | |
| 737 &normalBC, &unitNormalBC); | |
| 738 #ifndef SK_IGNORE_CUBIC_STROKE_FIX | |
| 739 if (--subDivide < 0) { | |
| 740 goto DRAW_LINE; | |
| 741 } | |
| 742 #endif | |
| 743 if (degenerateBC || normals_too_curvy(unitNormalAB, unitNormalBC) || | |
| 744 normals_too_curvy(unitNormalBC, *unitNormalCD)) { | |
| 745 #ifdef SK_IGNORE_CUBIC_STROKE_FIX | |
| 746 // subdivide if we can | |
| 747 if (--subDivide < 0) { | |
| 748 goto DRAW_LINE; | |
| 749 } | |
| 750 #endif | |
| 751 SkPoint tmp[7]; | |
| 752 SkVector norm, unit, dummy, unitDummy; | |
| 753 | |
| 754 SkChopCubicAtHalf(pts, tmp); | |
| 755 this->cubic_to(&tmp[0], normalAB, unitNormalAB, &norm, &unit, | |
| 756 subDivide); | |
| 757 // we use dummys since we already have a valid (and more accurate) | |
| 758 // normals for CD | |
| 759 this->cubic_to(&tmp[3], norm, unit, &dummy, &unitDummy, subDivide); | |
| 760 } else { | |
| 761 SkVector normalB, normalC; | |
| 762 | |
| 763 // need normals to inset/outset the off-curve pts B and C | |
| 764 | |
| 765 SkVector unitBC = pts[2] - pts[1]; | |
| 766 unitBC.normalize(); | |
| 767 unitBC.rotateCCW(); | |
| 768 | |
| 769 normalB = unitNormalAB + unitBC; | |
| 770 normalC = *unitNormalCD + unitBC; | |
| 771 | |
| 772 SkScalar dot = SkPoint::DotProduct(unitNormalAB, unitBC); | |
| 773 SkAssertResult(normalB.setLength(fRadius / SkScalarSqrt((SK_Scalar1 + do
t)/2))); | |
| 774 dot = SkPoint::DotProduct(*unitNormalCD, unitBC); | |
| 775 SkAssertResult(normalC.setLength(fRadius / SkScalarSqrt((SK_Scalar1 + do
t)/2))); | |
| 776 | |
| 777 fOuter.cubicTo( pts[1].fX + normalB.fX, pts[1].fY + normalB.fY, | |
| 778 pts[2].fX + normalC.fX, pts[2].fY + normalC.fY, | |
| 779 pts[3].fX + normalCD->fX, pts[3].fY + normalCD->fY); | |
| 780 | |
| 781 fInner.cubicTo( pts[1].fX - normalB.fX, pts[1].fY - normalB.fY, | |
| 782 pts[2].fX - normalC.fX, pts[2].fY - normalC.fY, | |
| 783 pts[3].fX - normalCD->fX, pts[3].fY - normalCD->fY); | |
| 784 } | |
| 785 } | |
| 786 #endif | |
| 787 | |
| 788 #ifndef SK_LEGACY_STROKE_CURVES | |
| 789 void SkPathStroker::conicTo(const SkPoint& pt1, const SkPoint& pt2, SkScalar wei
ght) { | 606 void SkPathStroker::conicTo(const SkPoint& pt1, const SkPoint& pt2, SkScalar wei
ght) { |
| 790 const SkConic conic(fPrevPt, pt1, pt2, weight); | 607 const SkConic conic(fPrevPt, pt1, pt2, weight); |
| 791 SkPoint reduction; | 608 SkPoint reduction; |
| 792 ReductionType reductionType = CheckConicLinear(conic, &reduction); | 609 ReductionType reductionType = CheckConicLinear(conic, &reduction); |
| 793 if (kPoint_ReductionType == reductionType) { | 610 if (kPoint_ReductionType == reductionType) { |
| 794 return; | 611 return; |
| 795 } | 612 } |
| 796 if (kLine_ReductionType == reductionType) { | 613 if (kLine_ReductionType == reductionType) { |
| 797 this->lineTo(pt2); | 614 this->lineTo(pt2); |
| 798 return; | 615 return; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 812 return; | 629 return; |
| 813 } | 630 } |
| 814 SkQuadConstruct quadPts; | 631 SkQuadConstruct quadPts; |
| 815 this->init(kOuter_StrokeType, &quadPts, 0, 1); | 632 this->init(kOuter_StrokeType, &quadPts, 0, 1); |
| 816 (void) this->conicStroke(conic, &quadPts); | 633 (void) this->conicStroke(conic, &quadPts); |
| 817 this->init(kInner_StrokeType, &quadPts, 0, 1); | 634 this->init(kInner_StrokeType, &quadPts, 0, 1); |
| 818 (void) this->conicStroke(conic, &quadPts); | 635 (void) this->conicStroke(conic, &quadPts); |
| 819 this->setConicEndNormal(conic, normalAB, unitAB, &normalBC, &unitBC); | 636 this->setConicEndNormal(conic, normalAB, unitAB, &normalBC, &unitBC); |
| 820 this->postJoinTo(pt2, normalBC, unitBC); | 637 this->postJoinTo(pt2, normalBC, unitBC); |
| 821 } | 638 } |
| 822 #endif | |
| 823 | 639 |
| 824 void SkPathStroker::quadTo(const SkPoint& pt1, const SkPoint& pt2) { | 640 void SkPathStroker::quadTo(const SkPoint& pt1, const SkPoint& pt2) { |
| 825 #ifndef SK_LEGACY_STROKE_CURVES | |
| 826 const SkPoint quad[3] = { fPrevPt, pt1, pt2 }; | 641 const SkPoint quad[3] = { fPrevPt, pt1, pt2 }; |
| 827 SkPoint reduction; | 642 SkPoint reduction; |
| 828 ReductionType reductionType = CheckQuadLinear(quad, &reduction); | 643 ReductionType reductionType = CheckQuadLinear(quad, &reduction); |
| 829 if (kPoint_ReductionType == reductionType) { | 644 if (kPoint_ReductionType == reductionType) { |
| 830 return; | 645 return; |
| 831 } | 646 } |
| 832 if (kLine_ReductionType == reductionType) { | 647 if (kLine_ReductionType == reductionType) { |
| 833 this->lineTo(pt2); | 648 this->lineTo(pt2); |
| 834 return; | 649 return; |
| 835 } | 650 } |
| (...skipping 10 matching lines...) Expand all Loading... |
| 846 if (!this->preJoinTo(pt1, &normalAB, &unitAB, false)) { | 661 if (!this->preJoinTo(pt1, &normalAB, &unitAB, false)) { |
| 847 this->lineTo(pt2); | 662 this->lineTo(pt2); |
| 848 return; | 663 return; |
| 849 } | 664 } |
| 850 SkQuadConstruct quadPts; | 665 SkQuadConstruct quadPts; |
| 851 this->init(kOuter_StrokeType, &quadPts, 0, 1); | 666 this->init(kOuter_StrokeType, &quadPts, 0, 1); |
| 852 (void) this->quadStroke(quad, &quadPts); | 667 (void) this->quadStroke(quad, &quadPts); |
| 853 this->init(kInner_StrokeType, &quadPts, 0, 1); | 668 this->init(kInner_StrokeType, &quadPts, 0, 1); |
| 854 (void) this->quadStroke(quad, &quadPts); | 669 (void) this->quadStroke(quad, &quadPts); |
| 855 this->setQuadEndNormal(quad, normalAB, unitAB, &normalBC, &unitBC); | 670 this->setQuadEndNormal(quad, normalAB, unitAB, &normalBC, &unitBC); |
| 856 #else | |
| 857 bool degenerateAB = SkPath::IsLineDegenerate(fPrevPt, pt1); | |
| 858 bool degenerateBC = SkPath::IsLineDegenerate(pt1, pt2); | |
| 859 | |
| 860 if (degenerateAB | degenerateBC) { | |
| 861 if (degenerateAB ^ degenerateBC) { | |
| 862 this->lineTo(pt2); | |
| 863 } | |
| 864 return; | |
| 865 } | |
| 866 | |
| 867 SkVector normalAB, unitAB, normalBC, unitBC; | |
| 868 | |
| 869 this->preJoinTo(pt1, &normalAB, &unitAB, false); | |
| 870 | |
| 871 { | |
| 872 SkPoint pts[3], tmp[5]; | |
| 873 pts[0] = fPrevPt; | |
| 874 pts[1] = pt1; | |
| 875 pts[2] = pt2; | |
| 876 | |
| 877 if (SkChopQuadAtMaxCurvature(pts, tmp) == 2) { | |
| 878 unitBC.setNormalize(pts[2].fX - pts[1].fX, pts[2].fY - pts[1].fY); | |
| 879 unitBC.rotateCCW(); | |
| 880 if (normals_too_pinchy(unitAB, unitBC)) { | |
| 881 normalBC = unitBC; | |
| 882 normalBC.scale(fRadius); | |
| 883 | |
| 884 fOuter.lineTo(tmp[2].fX + normalAB.fX, tmp[2].fY + normalAB.fY); | |
| 885 fOuter.lineTo(tmp[2].fX + normalBC.fX, tmp[2].fY + normalBC.fY); | |
| 886 fOuter.lineTo(tmp[4].fX + normalBC.fX, tmp[4].fY + normalBC.fY); | |
| 887 | |
| 888 fInner.lineTo(tmp[2].fX - normalAB.fX, tmp[2].fY - normalAB.fY); | |
| 889 fInner.lineTo(tmp[2].fX - normalBC.fX, tmp[2].fY - normalBC.fY); | |
| 890 fInner.lineTo(tmp[4].fX - normalBC.fX, tmp[4].fY - normalBC.fY); | |
| 891 | |
| 892 fExtra.addCircle(tmp[2].fX, tmp[2].fY, fRadius, | |
| 893 SkPath::kCW_Direction); | |
| 894 } else { | |
| 895 this->quad_to(&tmp[0], normalAB, unitAB, &normalBC, &unitBC, | |
| 896 kMaxQuadSubdivide); | |
| 897 SkVector n = normalBC; | |
| 898 SkVector u = unitBC; | |
| 899 this->quad_to(&tmp[2], n, u, &normalBC, &unitBC, | |
| 900 kMaxQuadSubdivide); | |
| 901 } | |
| 902 } else { | |
| 903 this->quad_to(pts, normalAB, unitAB, &normalBC, &unitBC, | |
| 904 kMaxQuadSubdivide); | |
| 905 } | |
| 906 } | |
| 907 #endif | |
| 908 | 671 |
| 909 this->postJoinTo(pt2, normalBC, unitBC); | 672 this->postJoinTo(pt2, normalBC, unitBC); |
| 910 } | 673 } |
| 911 | 674 |
| 912 #ifndef SK_LEGACY_STROKE_CURVES | |
| 913 // Given a point on the curve and its derivative, scale the derivative by the ra
dius, and | 675 // Given a point on the curve and its derivative, scale the derivative by the ra
dius, and |
| 914 // compute the perpendicular point and its tangent. | 676 // compute the perpendicular point and its tangent. |
| 915 void SkPathStroker::setRayPts(const SkPoint& tPt, SkVector* dxy, SkPoint* onPt, | 677 void SkPathStroker::setRayPts(const SkPoint& tPt, SkVector* dxy, SkPoint* onPt, |
| 916 SkPoint* tangent) const { | 678 SkPoint* tangent) const { |
| 917 SkPoint oldDxy = *dxy; | 679 SkPoint oldDxy = *dxy; |
| 918 if (!dxy->setLength(fRadius)) { // consider moving double logic into SkPoin
t::setLength | 680 if (!dxy->setLength(fRadius)) { // consider moving double logic into SkPoin
t::setLength |
| 919 double xx = oldDxy.fX; | 681 double xx = oldDxy.fX; |
| 920 double yy = oldDxy.fY; | 682 double yy = oldDxy.fY; |
| 921 double dscale = fRadius / sqrt(xx * xx + yy * yy); | 683 double dscale = fRadius / sqrt(xx * xx + yy * yy); |
| 922 dxy->fX = SkDoubleToScalar(xx * dscale); | 684 dxy->fX = SkDoubleToScalar(xx * dscale); |
| (...skipping 460 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1383 return false; | 1145 return false; |
| 1384 } | 1146 } |
| 1385 (void) half.initWithEnd(quadPts); | 1147 (void) half.initWithEnd(quadPts); |
| 1386 if (!this->quadStroke(quad, &half)) { | 1148 if (!this->quadStroke(quad, &half)) { |
| 1387 return false; | 1149 return false; |
| 1388 } | 1150 } |
| 1389 --fRecursionDepth; | 1151 --fRecursionDepth; |
| 1390 return true; | 1152 return true; |
| 1391 } | 1153 } |
| 1392 | 1154 |
| 1393 #endif | |
| 1394 | |
| 1395 void SkPathStroker::cubicTo(const SkPoint& pt1, const SkPoint& pt2, | 1155 void SkPathStroker::cubicTo(const SkPoint& pt1, const SkPoint& pt2, |
| 1396 const SkPoint& pt3) { | 1156 const SkPoint& pt3) { |
| 1397 #ifndef SK_LEGACY_STROKE_CURVES | |
| 1398 const SkPoint cubic[4] = { fPrevPt, pt1, pt2, pt3 }; | 1157 const SkPoint cubic[4] = { fPrevPt, pt1, pt2, pt3 }; |
| 1399 SkPoint reduction[3]; | 1158 SkPoint reduction[3]; |
| 1400 const SkPoint* tangentPt; | 1159 const SkPoint* tangentPt; |
| 1401 ReductionType reductionType = CheckCubicLinear(cubic, reduction, &tangentPt)
; | 1160 ReductionType reductionType = CheckCubicLinear(cubic, reduction, &tangentPt)
; |
| 1402 if (kPoint_ReductionType == reductionType) { | 1161 if (kPoint_ReductionType == reductionType) { |
| 1403 return; | 1162 return; |
| 1404 } | 1163 } |
| 1405 if (kLine_ReductionType == reductionType) { | 1164 if (kLine_ReductionType == reductionType) { |
| 1406 this->lineTo(pt3); | 1165 this->lineTo(pt3); |
| 1407 return; | 1166 return; |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1434 SkQuadConstruct quadPts; | 1193 SkQuadConstruct quadPts; |
| 1435 this->init(kOuter_StrokeType, &quadPts, lastT, nextT); | 1194 this->init(kOuter_StrokeType, &quadPts, lastT, nextT); |
| 1436 (void) this->cubicStroke(cubic, &quadPts); | 1195 (void) this->cubicStroke(cubic, &quadPts); |
| 1437 this->init(kInner_StrokeType, &quadPts, lastT, nextT); | 1196 this->init(kInner_StrokeType, &quadPts, lastT, nextT); |
| 1438 (void) this->cubicStroke(cubic, &quadPts); | 1197 (void) this->cubicStroke(cubic, &quadPts); |
| 1439 lastT = nextT; | 1198 lastT = nextT; |
| 1440 } | 1199 } |
| 1441 // emit the join even if one stroke succeeded but the last one failed | 1200 // emit the join even if one stroke succeeded but the last one failed |
| 1442 // this avoids reversing an inner stroke with a partial path followed by ano
ther moveto | 1201 // this avoids reversing an inner stroke with a partial path followed by ano
ther moveto |
| 1443 this->setCubicEndNormal(cubic, normalAB, unitAB, &normalCD, &unitCD); | 1202 this->setCubicEndNormal(cubic, normalAB, unitAB, &normalCD, &unitCD); |
| 1444 #else | |
| 1445 bool degenerateAB = SkPath::IsLineDegenerate(fPrevPt, pt1); | |
| 1446 bool degenerateBC = SkPath::IsLineDegenerate(pt1, pt2); | |
| 1447 bool degenerateCD = SkPath::IsLineDegenerate(pt2, pt3); | |
| 1448 | |
| 1449 if (degenerateAB + degenerateBC + degenerateCD >= 2 | |
| 1450 || (degenerateAB && SkPath::IsLineDegenerate(fPrevPt, pt2))) { | |
| 1451 this->lineTo(pt3); | |
| 1452 return; | |
| 1453 } | |
| 1454 | |
| 1455 SkVector normalAB, unitAB, normalCD, unitCD; | |
| 1456 | |
| 1457 // find the first tangent (which might be pt1 or pt2 | |
| 1458 { | |
| 1459 const SkPoint* nextPt = &pt1; | |
| 1460 if (degenerateAB) | |
| 1461 nextPt = &pt2; | |
| 1462 this->preJoinTo(*nextPt, &normalAB, &unitAB, false); | |
| 1463 } | |
| 1464 | |
| 1465 { | |
| 1466 SkPoint pts[4], tmp[13]; | |
| 1467 int i, count; | |
| 1468 SkVector n, u; | |
| 1469 SkScalar tValues[3]; | |
| 1470 | |
| 1471 pts[0] = fPrevPt; | |
| 1472 pts[1] = pt1; | |
| 1473 pts[2] = pt2; | |
| 1474 pts[3] = pt3; | |
| 1475 | |
| 1476 count = SkChopCubicAtMaxCurvature(pts, tmp, tValues); | |
| 1477 n = normalAB; | |
| 1478 u = unitAB; | |
| 1479 for (i = 0; i < count; i++) { | |
| 1480 this->cubic_to(&tmp[i * 3], n, u, &normalCD, &unitCD, | |
| 1481 kMaxCubicSubdivide); | |
| 1482 if (i == count - 1) { | |
| 1483 break; | |
| 1484 } | |
| 1485 n = normalCD; | |
| 1486 u = unitCD; | |
| 1487 | |
| 1488 } | |
| 1489 } | |
| 1490 #endif | |
| 1491 | 1203 |
| 1492 this->postJoinTo(pt3, normalCD, unitCD); | 1204 this->postJoinTo(pt3, normalCD, unitCD); |
| 1493 } | 1205 } |
| 1494 | 1206 |
| 1495 /////////////////////////////////////////////////////////////////////////////// | 1207 /////////////////////////////////////////////////////////////////////////////// |
| 1496 /////////////////////////////////////////////////////////////////////////////// | 1208 /////////////////////////////////////////////////////////////////////////////// |
| 1497 | 1209 |
| 1498 #include "SkPaintDefaults.h" | 1210 #include "SkPaintDefaults.h" |
| 1499 | 1211 |
| 1500 SkStroke::SkStroke() { | 1212 SkStroke::SkStroke() { |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1589 this->strokeRect(rect, dst, dir); | 1301 this->strokeRect(rect, dst, dir); |
| 1590 // our answer should preserve the inverseness of the src | 1302 // our answer should preserve the inverseness of the src |
| 1591 if (src.isInverseFillType()) { | 1303 if (src.isInverseFillType()) { |
| 1592 SkASSERT(!dst->isInverseFillType()); | 1304 SkASSERT(!dst->isInverseFillType()); |
| 1593 dst->toggleInverseFillType(); | 1305 dst->toggleInverseFillType(); |
| 1594 } | 1306 } |
| 1595 return; | 1307 return; |
| 1596 } | 1308 } |
| 1597 } | 1309 } |
| 1598 | 1310 |
| 1599 #ifdef SK_LEGACY_STROKE_CURVES | |
| 1600 SkAutoConicToQuads converter; | |
| 1601 const SkScalar conicTol = SK_Scalar1 / 4 / fResScale; | |
| 1602 #endif | |
| 1603 SkPathStroker stroker(src, radius, fMiterLimit, this->getCap(), this->getJ
oin(), fResScale); | 1311 SkPathStroker stroker(src, radius, fMiterLimit, this->getCap(), this->getJ
oin(), fResScale); |
| 1604 SkPath::Iter iter(src, false); | 1312 SkPath::Iter iter(src, false); |
| 1605 SkPath::Verb lastSegment = SkPath::kMove_Verb; | 1313 SkPath::Verb lastSegment = SkPath::kMove_Verb; |
| 1606 | 1314 |
| 1607 for (;;) { | 1315 for (;;) { |
| 1608 SkPoint pts[4]; | 1316 SkPoint pts[4]; |
| 1609 switch (iter.next(pts, false)) { | 1317 switch (iter.next(pts, false)) { |
| 1610 case SkPath::kMove_Verb: | 1318 case SkPath::kMove_Verb: |
| 1611 stroker.moveTo(pts[0]); | 1319 stroker.moveTo(pts[0]); |
| 1612 break; | 1320 break; |
| 1613 case SkPath::kLine_Verb: | 1321 case SkPath::kLine_Verb: |
| 1614 stroker.lineTo(pts[1]); | 1322 stroker.lineTo(pts[1]); |
| 1615 lastSegment = SkPath::kLine_Verb; | 1323 lastSegment = SkPath::kLine_Verb; |
| 1616 break; | 1324 break; |
| 1617 case SkPath::kQuad_Verb: | 1325 case SkPath::kQuad_Verb: |
| 1618 stroker.quadTo(pts[1], pts[2]); | 1326 stroker.quadTo(pts[1], pts[2]); |
| 1619 lastSegment = SkPath::kQuad_Verb; | 1327 lastSegment = SkPath::kQuad_Verb; |
| 1620 break; | 1328 break; |
| 1621 case SkPath::kConic_Verb: { | 1329 case SkPath::kConic_Verb: { |
| 1622 #ifndef SK_LEGACY_STROKE_CURVES | |
| 1623 stroker.conicTo(pts[1], pts[2], iter.conicWeight()); | 1330 stroker.conicTo(pts[1], pts[2], iter.conicWeight()); |
| 1624 lastSegment = SkPath::kConic_Verb; | 1331 lastSegment = SkPath::kConic_Verb; |
| 1625 break; | 1332 break; |
| 1626 #else | |
| 1627 // todo: if we had maxcurvature for conics, perhaps we should | |
| 1628 // natively extrude the conic instead of converting to quads. | |
| 1629 const SkPoint* quadPts = | |
| 1630 converter.computeQuads(pts, iter.conicWeight(), conicTol); | |
| 1631 for (int i = 0; i < converter.countQuads(); ++i) { | |
| 1632 stroker.quadTo(quadPts[1], quadPts[2]); | |
| 1633 quadPts += 2; | |
| 1634 } | |
| 1635 lastSegment = SkPath::kQuad_Verb; | |
| 1636 #endif | |
| 1637 } break; | 1333 } break; |
| 1638 case SkPath::kCubic_Verb: | 1334 case SkPath::kCubic_Verb: |
| 1639 stroker.cubicTo(pts[1], pts[2], pts[3]); | 1335 stroker.cubicTo(pts[1], pts[2], pts[3]); |
| 1640 lastSegment = SkPath::kCubic_Verb; | 1336 lastSegment = SkPath::kCubic_Verb; |
| 1641 break; | 1337 break; |
| 1642 case SkPath::kClose_Verb: | 1338 case SkPath::kClose_Verb: |
| 1643 stroker.close(lastSegment == SkPath::kLine_Verb); | 1339 stroker.close(lastSegment == SkPath::kLine_Verb); |
| 1644 break; | 1340 break; |
| 1645 case SkPath::kDone_Verb: | 1341 case SkPath::kDone_Verb: |
| 1646 goto DONE; | 1342 goto DONE; |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1756 default: | 1452 default: |
| 1757 break; | 1453 break; |
| 1758 } | 1454 } |
| 1759 | 1455 |
| 1760 if (fWidth < SkMinScalar(rw, rh) && !fDoFill) { | 1456 if (fWidth < SkMinScalar(rw, rh) && !fDoFill) { |
| 1761 r = rect; | 1457 r = rect; |
| 1762 r.inset(radius, radius); | 1458 r.inset(radius, radius); |
| 1763 dst->addRect(r, reverse_direction(dir)); | 1459 dst->addRect(r, reverse_direction(dir)); |
| 1764 } | 1460 } |
| 1765 } | 1461 } |
| OLD | NEW |