Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Side by Side Diff: src/core/SkStroke.cpp

Issue 1157623003: remove SK_LEGACY_STROKE_CURVES (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: work in progress Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/core/SkStroke.h ('k') | src/core/SkStrokeRec.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « src/core/SkStroke.h ('k') | src/core/SkStrokeRec.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698