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 |