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

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

Issue 932113002: Revive quad approximation stroker (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: add macro to suppress uninitialized warning Created 5 years, 10 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 #if QUAD_STROKE_APPROXIMATION 12 #ifdef SK_QUAD_STROKE_APPROXIMATION
13 13
14 enum { 14 enum {
15 kTangent_RecursiveLimit, 15 kTangent_RecursiveLimit,
16 kCubic_RecursiveLimit, 16 kCubic_RecursiveLimit,
17 kConic_RecursiveLimit,
17 kQuad_RecursiveLimit 18 kQuad_RecursiveLimit
18 }; 19 };
19 20
20 // quads with extreme widths (e.g. (0,1) (1,6) (0,3) width=5e7) recurse to p oint of failure 21 // quads with extreme widths (e.g. (0,1) (1,6) (0,3) width=5e7) recurse to p oint of failure
21 // largest seen for normal cubics : 5, 26 22 // largest seen for normal cubics : 5, 26
22 // largest seen for normal quads : 11 23 // largest seen for normal quads : 11
23 static const int kRecursiveLimits[] = { 5*3, 26*3, 11*3 }; // 3x limits see n in practical tests 24 static const int kRecursiveLimits[] = { 5*3, 26*3, 11*3, 11*3 }; // 3x limit s seen in practice
24 25
26 SK_COMPILE_ASSERT(0 == kTangent_RecursiveLimit, cubic_stroke_relies_on_tange nt_equalling_zero);
27 SK_COMPILE_ASSERT(1 == kCubic_RecursiveLimit, cubic_stroke_relies_on_cubic_e qualling_one);
25 SK_COMPILE_ASSERT(SK_ARRAY_COUNT(kRecursiveLimits) == kQuad_RecursiveLimit + 1, 28 SK_COMPILE_ASSERT(SK_ARRAY_COUNT(kRecursiveLimits) == kQuad_RecursiveLimit + 1,
26 recursive_limits_mismatch); 29 recursive_limits_mismatch);
27 30
28 #ifdef SK_DEBUG // enables tweaking these values at runtime from SampleApp 31 #ifdef SK_DEBUG
29 bool gDebugStrokerErrorSet = false;
30 SkScalar gDebugStrokerError;
31
32 int gMaxRecursion[SK_ARRAY_COUNT(kRecursiveLimits)] = { 0 }; 32 int gMaxRecursion[SK_ARRAY_COUNT(kRecursiveLimits)] = { 0 };
33 #endif 33 #endif
34 #ifndef DEBUG_QUAD_STROKER 34 #ifndef DEBUG_QUAD_STROKER
35 #define DEBUG_QUAD_STROKER 0 35 #define DEBUG_QUAD_STROKER 0
36 #endif 36 #endif
37 37
38 #if DEBUG_QUAD_STROKER 38 #if DEBUG_QUAD_STROKER
39 /* Enable to show the decisions made in subdividing the curve -- helpful when the resulting 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 */ 40 stroke has more than the optimal number of quadratics and lines */
41 #define STROKER_RESULT(resultType, depth, quadPts, format, ...) \ 41 #define STROKER_RESULT(resultType, depth, quadPts, format, ...) \
42 SkDebugf("[%d] %s " format "\n", depth, __FUNCTION__, __VA_ARGS_ _), \ 42 SkDebugf("[%d] %s " format "\n", depth, __FUNCTION__, __VA_ARGS_ _), \
43 SkDebugf(" " #resultType " t=(%g,%g)\n", quadPts->fStartT, quad Pts->fEndT), \ 43 SkDebugf(" " #resultType " t=(%g,%g)\n", quadPts->fStartT, quad Pts->fEndT), \
44 resultType 44 resultType
45 #define STROKER_DEBUG_PARAMS(...) , __VA_ARGS__ 45 #define STROKER_DEBUG_PARAMS(...) , __VA_ARGS__
46 #else 46 #else
47 #define STROKER_RESULT(resultType, depth, quadPts, format, ...) \ 47 #define STROKER_RESULT(resultType, depth, quadPts, format, ...) \
48 resultType 48 resultType
49 #define STROKER_DEBUG_PARAMS(...) 49 #define STROKER_DEBUG_PARAMS(...)
50 #endif 50 #endif
51 51
52 #endif 52 #endif
53 53
54 #ifndef SK_QUAD_STROKE_APPROXIMATION
54 #define kMaxQuadSubdivide 5 55 #define kMaxQuadSubdivide 5
55 #define kMaxCubicSubdivide 7 56 #define kMaxCubicSubdivide 7
57 #endif
56 58
57 static inline bool degenerate_vector(const SkVector& v) { 59 static inline bool degenerate_vector(const SkVector& v) {
58 return !SkPoint::CanNormalize(v.fX, v.fY); 60 return !SkPoint::CanNormalize(v.fX, v.fY);
59 } 61 }
60 62
61 #if !QUAD_STROKE_APPROXIMATION 63 #ifndef SK_QUAD_STROKE_APPROXIMATION
62 static inline bool normals_too_curvy(const SkVector& norm0, SkVector& norm1) { 64 static inline bool normals_too_curvy(const SkVector& norm0, SkVector& norm1) {
63 /* root2/2 is a 45-degree angle 65 /* root2/2 is a 45-degree angle
64 make this constant bigger for more subdivisions (but not >= 1) 66 make this constant bigger for more subdivisions (but not >= 1)
65 */ 67 */
66 static const SkScalar kFlatEnoughNormalDotProd = 68 static const SkScalar kFlatEnoughNormalDotProd =
67 SK_ScalarSqrt2/2 + SK_Scalar1/10; 69 SK_ScalarSqrt2/2 + SK_Scalar1/10;
68 70
69 SkASSERT(kFlatEnoughNormalDotProd > 0 && 71 SkASSERT(kFlatEnoughNormalDotProd > 0 &&
70 kFlatEnoughNormalDotProd < SK_Scalar1); 72 kFlatEnoughNormalDotProd < SK_Scalar1);
71 73
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
104 SkVector* normal, SkVector* unitNormal) { 106 SkVector* normal, SkVector* unitNormal) {
105 if (!unitNormal->setNormalize(vec.fX, vec.fY)) { 107 if (!unitNormal->setNormalize(vec.fX, vec.fY)) {
106 return false; 108 return false;
107 } 109 }
108 unitNormal->rotateCCW(); 110 unitNormal->rotateCCW();
109 unitNormal->scale(radius, normal); 111 unitNormal->scale(radius, normal);
110 return true; 112 return true;
111 } 113 }
112 114
113 /////////////////////////////////////////////////////////////////////////////// 115 ///////////////////////////////////////////////////////////////////////////////
114 #if QUAD_STROKE_APPROXIMATION 116 #ifdef SK_QUAD_STROKE_APPROXIMATION
115 117
116 struct SkQuadConstruct { // The state of the quad stroke under construction. 118 struct SkQuadConstruct { // The state of the quad stroke under construction.
117 SkPoint fQuad[3]; // the stroked quad parallel to the original curve 119 SkPoint fQuad[3]; // the stroked quad parallel to the original curve
118 SkPoint fTangentStart; // a point tangent to fQuad[0] 120 SkPoint fTangentStart; // a point tangent to fQuad[0]
119 SkPoint fTangentEnd; // a point tangent to fQuad[2] 121 SkPoint fTangentEnd; // a point tangent to fQuad[2]
120 SkScalar fStartT; // a segment of the original curve 122 SkScalar fStartT; // a segment of the original curve
121 SkScalar fMidT; // " 123 SkScalar fMidT; // "
122 SkScalar fEndT; // " 124 SkScalar fEndT; // "
123 bool fStartSet; // state to share common points across structs 125 bool fStartSet; // state to share common points across structs
124 bool fEndSet; // " 126 bool fEndSet; // "
(...skipping 24 matching lines...) Expand all
149 fQuad[2] = parent->fQuad[2]; 151 fQuad[2] = parent->fQuad[2];
150 fTangentEnd = parent->fTangentEnd; 152 fTangentEnd = parent->fTangentEnd;
151 fEndSet = true; 153 fEndSet = true;
152 return true; 154 return true;
153 } 155 }
154 }; 156 };
155 #endif 157 #endif
156 158
157 class SkPathStroker { 159 class SkPathStroker {
158 public: 160 public:
159 #if QUAD_STROKE_APPROXIMATION
160 SkPathStroker(const SkPath& src,
161 SkScalar radius, SkScalar miterLimit, SkScalar error, SkPaint: :Cap,
162 SkPaint::Join, SkScalar resScale);
163 #else
164 SkPathStroker(const SkPath& src, 161 SkPathStroker(const SkPath& src,
165 SkScalar radius, SkScalar miterLimit, SkPaint::Cap, 162 SkScalar radius, SkScalar miterLimit, SkPaint::Cap,
166 SkPaint::Join, SkScalar resScale); 163 SkPaint::Join, SkScalar resScale);
167 #endif
168 164
169 void moveTo(const SkPoint&); 165 void moveTo(const SkPoint&);
170 void lineTo(const SkPoint&); 166 void lineTo(const SkPoint&);
171 void quadTo(const SkPoint&, const SkPoint&); 167 void quadTo(const SkPoint&, const SkPoint&);
168 #ifdef SK_QUAD_STROKE_APPROXIMATION
169 void conicTo(const SkPoint&, const SkPoint&, SkScalar weight);
170 #endif
172 void cubicTo(const SkPoint&, const SkPoint&, const SkPoint&); 171 void cubicTo(const SkPoint&, const SkPoint&, const SkPoint&);
173 void close(bool isLine) { this->finishContour(true, isLine); } 172 void close(bool isLine) { this->finishContour(true, isLine); }
174 173
175 void done(SkPath* dst, bool isLine) { 174 void done(SkPath* dst, bool isLine) {
176 this->finishContour(false, isLine); 175 this->finishContour(false, isLine);
177 fOuter.addPath(fExtra); 176 fOuter.addPath(fExtra);
178 dst->swap(fOuter); 177 dst->swap(fOuter);
179 } 178 }
180 179
181 SkScalar getResScale() const { return fResScale; } 180 SkScalar getResScale() const { return fResScale; }
182 181
183 private: 182 private:
184 #if QUAD_STROKE_APPROXIMATION
185 SkScalar fError;
186 #endif
187 SkScalar fRadius; 183 SkScalar fRadius;
188 SkScalar fInvMiterLimit; 184 SkScalar fInvMiterLimit;
189 SkScalar fResScale; 185 SkScalar fResScale;
186 #ifdef SK_QUAD_STROKE_APPROXIMATION
187 SkScalar fInvResScale;
188 SkScalar fInvResScaleSquared;
189 #endif
190 190
191 SkVector fFirstNormal, fPrevNormal, fFirstUnitNormal, fPrevUnitNormal; 191 SkVector fFirstNormal, fPrevNormal, fFirstUnitNormal, fPrevUnitNormal;
192 SkPoint fFirstPt, fPrevPt; // on original path 192 SkPoint fFirstPt, fPrevPt; // on original path
193 SkPoint fFirstOuterPt; 193 SkPoint fFirstOuterPt;
194 int fSegmentCount; 194 int fSegmentCount;
195 bool fPrevIsLine; 195 bool fPrevIsLine;
196 196
197 SkStrokerPriv::CapProc fCapper; 197 SkStrokerPriv::CapProc fCapper;
198 SkStrokerPriv::JoinProc fJoiner; 198 SkStrokerPriv::JoinProc fJoiner;
199 199
200 SkPath fInner, fOuter; // outer is our working answer, inner is temp 200 SkPath fInner, fOuter; // outer is our working answer, inner is temp
201 SkPath fExtra; // added as extra complete contours 201 SkPath fExtra; // added as extra complete contours
202 202
203 #if QUAD_STROKE_APPROXIMATION 203 #ifdef SK_QUAD_STROKE_APPROXIMATION
204 enum StrokeType { 204 enum StrokeType {
205 kOuter_StrokeType = 1, // use sign-opposite values later to flip pe rpendicular axis 205 kOuter_StrokeType = 1, // use sign-opposite values later to flip pe rpendicular axis
206 kInner_StrokeType = -1 206 kInner_StrokeType = -1
207 } fStrokeType; 207 } fStrokeType;
208 208
209 enum ResultType { 209 enum ResultType {
210 kSplit_ResultType, // the caller should split the quad stroke i n two 210 kSplit_ResultType, // the caller should split the quad stroke i n two
211 kDegenerate_ResultType, // the caller should add a line 211 kDegenerate_ResultType, // the caller should add a line
212 kQuad_ResultType, // the caller should (continue to try to) ad d a quad stroke 212 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 213 kNormalError_ResultType, // the cubic's normal couldn't be computed - - abort
(...skipping 10 matching lines...) Expand all
224 224
225 enum IntersectRayType { 225 enum IntersectRayType {
226 kCtrlPt_RayType, 226 kCtrlPt_RayType,
227 kResultType_RayType, 227 kResultType_RayType,
228 }; 228 };
229 229
230 int fRecursionDepth; // track stack depth to abort if numerics ru n amok 230 int fRecursionDepth; // track stack depth to abort if numerics ru n amok
231 bool fFoundTangents; // do less work until tangents meet (cubic) 231 bool fFoundTangents; // do less work until tangents meet (cubic)
232 232
233 void addDegenerateLine(const SkQuadConstruct* ); 233 void addDegenerateLine(const SkQuadConstruct* );
234 ReductionType CheckConicLinear(const SkConic& , SkPoint* reduction);
234 ReductionType CheckCubicLinear(const SkPoint cubic[4], SkPoint reduction[3], 235 ReductionType CheckCubicLinear(const SkPoint cubic[4], SkPoint reduction[3],
235 const SkPoint** tanPtPtr); 236 const SkPoint** tanPtPtr);
236 ReductionType CheckQuadLinear(const SkPoint quad[3], SkPoint* reduction); 237 ReductionType CheckQuadLinear(const SkPoint quad[3], SkPoint* reduction);
238 ResultType compareQuadConic(const SkConic& , SkQuadConstruct* );
237 ResultType compareQuadCubic(const SkPoint cubic[4], SkQuadConstruct* ); 239 ResultType compareQuadCubic(const SkPoint cubic[4], SkQuadConstruct* );
238 ResultType compareQuadQuad(const SkPoint quad[3], SkQuadConstruct* ); 240 ResultType compareQuadQuad(const SkPoint quad[3], SkQuadConstruct* );
241 bool conicPerpRay(const SkConic& , SkScalar t, SkPoint* tPt, SkPoint* onPt,
242 SkPoint* tangent) const;
243 bool conicQuadEnds(const SkConic& , SkQuadConstruct* );
244 bool conicStroke(const SkConic& , SkQuadConstruct* );
239 bool cubicMidOnLine(const SkPoint cubic[4], const SkQuadConstruct* ) const; 245 bool cubicMidOnLine(const SkPoint cubic[4], const SkQuadConstruct* ) const;
240 bool cubicPerpRay(const SkPoint cubic[4], SkScalar t, SkPoint* tPt, SkPoint* onPt, 246 bool cubicPerpRay(const SkPoint cubic[4], SkScalar t, SkPoint* tPt, SkPoint* onPt,
241 SkPoint* tangent) const; 247 SkPoint* tangent) const;
242 bool cubicQuadEnds(const SkPoint cubic[4], SkQuadConstruct* ); 248 bool cubicQuadEnds(const SkPoint cubic[4], SkQuadConstruct* );
243 bool cubicQuadMid(const SkPoint cubic[4], const SkQuadConstruct* , SkPoint* mid) const; 249 bool cubicQuadMid(const SkPoint cubic[4], const SkQuadConstruct* , SkPoint* mid) const;
244 bool cubicStroke(const SkPoint cubic[4], SkQuadConstruct* ); 250 bool cubicStroke(const SkPoint cubic[4], SkQuadConstruct* );
245 void init(StrokeType strokeType, SkQuadConstruct* , SkScalar tStart, SkScala r tEnd); 251 void init(StrokeType strokeType, SkQuadConstruct* , SkScalar tStart, SkScala r tEnd);
246 ResultType intersectRay(SkQuadConstruct* , IntersectRayType STROKER_DEBUG_P ARAMS(int) ) const; 252 ResultType intersectRay(SkQuadConstruct* , IntersectRayType STROKER_DEBUG_P ARAMS(int) ) const;
247 bool ptInQuadBounds(const SkPoint quad[3], const SkPoint& pt) const; 253 bool ptInQuadBounds(const SkPoint quad[3], const SkPoint& pt) const;
248 void quadPerpRay(const SkPoint quad[3], SkScalar t, SkPoint* tPt, SkPoint* o nPt, 254 void quadPerpRay(const SkPoint quad[3], SkScalar t, SkPoint* tPt, SkPoint* o nPt,
249 SkPoint* tangent) const; 255 SkPoint* tangent) const;
250 bool quadStroke(const SkPoint quad[3], SkQuadConstruct* ); 256 bool quadStroke(const SkPoint quad[3], SkQuadConstruct* );
257 void setConicEndNormal(const SkConic& ,
258 const SkVector& normalAB, const SkVector& unitNormalA B,
259 SkVector* normalBC, SkVector* unitNormalBC);
251 void setCubicEndNormal(const SkPoint cubic[4], 260 void setCubicEndNormal(const SkPoint cubic[4],
252 const SkVector& normalAB, const SkVector& unitNormalA B, 261 const SkVector& normalAB, const SkVector& unitNormalA B,
253 SkVector* normalCD, SkVector* unitNormalCD); 262 SkVector* normalCD, SkVector* unitNormalCD);
254 void setQuadEndNormal(const SkPoint quad[3], 263 void setQuadEndNormal(const SkPoint quad[3],
255 const SkVector& normalAB, const SkVector& unitNormalAB , 264 const SkVector& normalAB, const SkVector& unitNormalAB ,
256 SkVector* normalBC, SkVector* unitNormalBC); 265 SkVector* normalBC, SkVector* unitNormalBC);
257 void setRayPts(const SkPoint& tPt, SkVector* dxy, SkPoint* onPt, SkPoint* ta ngent) const; 266 void setRayPts(const SkPoint& tPt, SkVector* dxy, SkPoint* onPt, SkPoint* ta ngent) const;
258 static bool SlightAngle(SkQuadConstruct* ); 267 static bool SlightAngle(SkQuadConstruct* );
259 ResultType strokeCloseEnough(const SkPoint stroke[3], const SkPoint ray[2], 268 ResultType strokeCloseEnough(const SkPoint stroke[3], const SkPoint ray[2],
260 SkQuadConstruct* STROKER_DEBUG_PARAMS(int dept h) ) const; 269 SkQuadConstruct* STROKER_DEBUG_PARAMS(int dept h) ) const;
261 ResultType tangentsMeet(const SkPoint cubic[4], SkQuadConstruct* ); 270 ResultType tangentsMeet(const SkPoint cubic[4], SkQuadConstruct* );
262 #endif 271 #endif
263 272
264 void finishContour(bool close, bool isLine); 273 void finishContour(bool close, bool isLine);
265 void preJoinTo(const SkPoint&, SkVector* normal, SkVector* unitNormal, 274 void preJoinTo(const SkPoint&, SkVector* normal, SkVector* unitNormal,
266 bool isLine); 275 bool isLine);
267 void postJoinTo(const SkPoint&, const SkVector& normal, 276 void postJoinTo(const SkPoint&, const SkVector& normal,
268 const SkVector& unitNormal); 277 const SkVector& unitNormal);
269 278
270 void line_to(const SkPoint& currPt, const SkVector& normal); 279 void line_to(const SkPoint& currPt, const SkVector& normal);
271 #if !QUAD_STROKE_APPROXIMATION 280 #ifndef SK_QUAD_STROKE_APPROXIMATION
272 void quad_to(const SkPoint pts[3], 281 void quad_to(const SkPoint pts[3],
273 const SkVector& normalAB, const SkVector& unitNormalAB, 282 const SkVector& normalAB, const SkVector& unitNormalAB,
274 SkVector* normalBC, SkVector* unitNormalBC, 283 SkVector* normalBC, SkVector* unitNormalBC,
275 int subDivide); 284 int subDivide);
276 void cubic_to(const SkPoint pts[4], 285 void cubic_to(const SkPoint pts[4],
277 const SkVector& normalAB, const SkVector& unitNormalAB, 286 const SkVector& normalAB, const SkVector& unitNormalAB,
278 SkVector* normalCD, SkVector* unitNormalCD, 287 SkVector* normalCD, SkVector* unitNormalCD,
279 int subDivide); 288 int subDivide);
280 #endif 289 #endif
281 }; 290 };
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
341 } 350 }
342 } 351 }
343 // since we may re-use fInner, we rewind instead of reset, to save on 352 // since we may re-use fInner, we rewind instead of reset, to save on
344 // reallocating its internal storage. 353 // reallocating its internal storage.
345 fInner.rewind(); 354 fInner.rewind();
346 fSegmentCount = -1; 355 fSegmentCount = -1;
347 } 356 }
348 357
349 /////////////////////////////////////////////////////////////////////////////// 358 ///////////////////////////////////////////////////////////////////////////////
350 359
351 #if QUAD_STROKE_APPROXIMATION
352 SkPathStroker::SkPathStroker(const SkPath& src,
353 SkScalar radius, SkScalar miterLimit, SkScalar erro r,
354 SkPaint::Cap cap, SkPaint::Join join, SkScalar resS cale)
355 #else
356 SkPathStroker::SkPathStroker(const SkPath& src, 360 SkPathStroker::SkPathStroker(const SkPath& src,
357 SkScalar radius, SkScalar miterLimit, 361 SkScalar radius, SkScalar miterLimit,
358 SkPaint::Cap cap, SkPaint::Join join, SkScalar resS cale) 362 SkPaint::Cap cap, SkPaint::Join join, SkScalar resS cale)
359 #endif 363 : fRadius(radius)
360 : fRadius(radius), fResScale(resScale) { 364 , fResScale(resScale) {
361 365
362 /* This is only used when join is miter_join, but we initialize it here 366 /* This is only used when join is miter_join, but we initialize it here
363 so that it is always defined, to fis valgrind warnings. 367 so that it is always defined, to fis valgrind warnings.
364 */ 368 */
365 fInvMiterLimit = 0; 369 fInvMiterLimit = 0;
366 370
367 if (join == SkPaint::kMiter_Join) { 371 if (join == SkPaint::kMiter_Join) {
368 if (miterLimit <= SK_Scalar1) { 372 if (miterLimit <= SK_Scalar1) {
369 join = SkPaint::kBevel_Join; 373 join = SkPaint::kBevel_Join;
370 } else { 374 } else {
371 fInvMiterLimit = SkScalarInvert(miterLimit); 375 fInvMiterLimit = SkScalarInvert(miterLimit);
372 } 376 }
373 } 377 }
374 fCapper = SkStrokerPriv::CapFactory(cap); 378 fCapper = SkStrokerPriv::CapFactory(cap);
375 fJoiner = SkStrokerPriv::JoinFactory(join); 379 fJoiner = SkStrokerPriv::JoinFactory(join);
376 fSegmentCount = -1; 380 fSegmentCount = -1;
377 fPrevIsLine = false; 381 fPrevIsLine = false;
378 382
379 // Need some estimate of how large our final result (fOuter) 383 // Need some estimate of how large our final result (fOuter)
380 // and our per-contour temp (fInner) will be, so we don't spend 384 // and our per-contour temp (fInner) will be, so we don't spend
381 // extra time repeatedly growing these arrays. 385 // extra time repeatedly growing these arrays.
382 // 386 //
383 // 3x for result == inner + outer + join (swag) 387 // 3x for result == inner + outer + join (swag)
384 // 1x for inner == 'wag' (worst contour length would be better guess) 388 // 1x for inner == 'wag' (worst contour length would be better guess)
385 fOuter.incReserve(src.countPoints() * 3); 389 fOuter.incReserve(src.countPoints() * 3);
386 fOuter.setIsVolatile(true); 390 fOuter.setIsVolatile(true);
387 fInner.incReserve(src.countPoints()); 391 fInner.incReserve(src.countPoints());
388 fInner.setIsVolatile(true); 392 fInner.setIsVolatile(true);
389 #if QUAD_STROKE_APPROXIMATION 393 #ifdef SK_QUAD_STROKE_APPROXIMATION
390 #ifdef SK_DEBUG 394 // TODO : write a common error function used by stroking and filling
391 if (!gDebugStrokerErrorSet) { 395 // The '4' below matches the fill scan converter's error term
392 gDebugStrokerError = error; 396 fInvResScale = SkScalarInvert(resScale * 4);
393 } 397 fInvResScaleSquared = fInvResScale * fInvResScale;
394 fError = gDebugStrokerError;
395 #else
396 fError = error;
397 #endif
398 fRecursionDepth = 0; 398 fRecursionDepth = 0;
399 #endif 399 #endif
400 } 400 }
401 401
402 void SkPathStroker::moveTo(const SkPoint& pt) { 402 void SkPathStroker::moveTo(const SkPoint& pt) {
403 if (fSegmentCount > 0) { 403 if (fSegmentCount > 0) {
404 this->finishContour(false, false); 404 this->finishContour(false, false);
405 } 405 }
406 fSegmentCount = 0; 406 fSegmentCount = 0;
407 fFirstPt = fPrevPt = pt; 407 fFirstPt = fPrevPt = pt;
408 } 408 }
409 409
410 void SkPathStroker::line_to(const SkPoint& currPt, const SkVector& normal) { 410 void SkPathStroker::line_to(const SkPoint& currPt, const SkVector& normal) {
411 fOuter.lineTo(currPt.fX + normal.fX, currPt.fY + normal.fY); 411 fOuter.lineTo(currPt.fX + normal.fX, currPt.fY + normal.fY);
412 fInner.lineTo(currPt.fX - normal.fX, currPt.fY - normal.fY); 412 fInner.lineTo(currPt.fX - normal.fX, currPt.fY - normal.fY);
413 } 413 }
414 414
415 void SkPathStroker::lineTo(const SkPoint& currPt) { 415 void SkPathStroker::lineTo(const SkPoint& currPt) {
416 if (SkPath::IsLineDegenerate(fPrevPt, currPt)) { 416 if (SkPath::IsLineDegenerate(fPrevPt, currPt)) {
417 return; 417 return;
418 } 418 }
419 SkVector normal, unitNormal; 419 SkVector normal, unitNormal;
420 420
421 this->preJoinTo(currPt, &normal, &unitNormal, true); 421 this->preJoinTo(currPt, &normal, &unitNormal, true);
422 this->line_to(currPt, normal); 422 this->line_to(currPt, normal);
423 this->postJoinTo(currPt, normal, unitNormal); 423 this->postJoinTo(currPt, normal, unitNormal);
424 } 424 }
425 425
426 #if !QUAD_STROKE_APPROXIMATION 426 #ifndef SK_QUAD_STROKE_APPROXIMATION
427 void SkPathStroker::quad_to(const SkPoint pts[3], 427 void SkPathStroker::quad_to(const SkPoint pts[3],
428 const SkVector& normalAB, const SkVector& unitNormalAB, 428 const SkVector& normalAB, const SkVector& unitNormalAB,
429 SkVector* normalBC, SkVector* unitNormalBC, 429 SkVector* normalBC, SkVector* unitNormalBC,
430 int subDivide) { 430 int subDivide) {
431 if (!set_normal_unitnormal(pts[1], pts[2], fRadius, 431 if (!set_normal_unitnormal(pts[1], pts[2], fRadius,
432 normalBC, unitNormalBC)) { 432 normalBC, unitNormalBC)) {
433 // pts[1] nearly equals pts[2], so just draw a line to pts[2] 433 // pts[1] nearly equals pts[2], so just draw a line to pts[2]
434 this->line_to(pts[2], normalAB); 434 this->line_to(pts[2], normalAB);
435 *normalBC = normalAB; 435 *normalBC = normalAB;
436 *unitNormalBC = unitNormalAB; 436 *unitNormalBC = unitNormalAB;
(...skipping 17 matching lines...) Expand all
454 SkScalarSqrt((SK_Scalar1 + dot)/2)))); 454 SkScalarSqrt((SK_Scalar1 + dot)/2))));
455 455
456 fOuter.quadTo( pts[1].fX + normalB.fX, pts[1].fY + normalB.fY, 456 fOuter.quadTo( pts[1].fX + normalB.fX, pts[1].fY + normalB.fY,
457 pts[2].fX + normalBC->fX, pts[2].fY + normalBC->fY); 457 pts[2].fX + normalBC->fX, pts[2].fY + normalBC->fY);
458 fInner.quadTo( pts[1].fX - normalB.fX, pts[1].fY - normalB.fY, 458 fInner.quadTo( pts[1].fX - normalB.fX, pts[1].fY - normalB.fY,
459 pts[2].fX - normalBC->fX, pts[2].fY - normalBC->fY); 459 pts[2].fX - normalBC->fX, pts[2].fY - normalBC->fY);
460 } 460 }
461 } 461 }
462 #endif 462 #endif
463 463
464 #if QUAD_STROKE_APPROXIMATION 464 #ifdef SK_QUAD_STROKE_APPROXIMATION
465 void SkPathStroker::setQuadEndNormal(const SkPoint quad[3], const SkVector& norm alAB, 465 void SkPathStroker::setQuadEndNormal(const SkPoint quad[3], const SkVector& norm alAB,
466 const SkVector& unitNormalAB, SkVector* normalBC, SkVector* unitNormalBC ) { 466 const SkVector& unitNormalAB, SkVector* normalBC, SkVector* unitNormalBC ) {
467 if (!set_normal_unitnormal(quad[1], quad[2], fRadius, normalBC, unitNormalBC )) { 467 if (!set_normal_unitnormal(quad[1], quad[2], fRadius, normalBC, unitNormalBC )) {
468 *normalBC = normalAB; 468 *normalBC = normalAB;
469 *unitNormalBC = unitNormalAB; 469 *unitNormalBC = unitNormalAB;
470 } 470 }
471 } 471 }
472 472
473 void SkPathStroker::setConicEndNormal(const SkConic& conic, const SkVector& norm alAB,
474 const SkVector& unitNormalAB, SkVector* normalBC, SkVector* unitNormalBC ) {
475 setQuadEndNormal(conic.fPts, normalAB, unitNormalAB, normalBC, unitNormalBC) ;
476 }
477
473 void SkPathStroker::setCubicEndNormal(const SkPoint cubic[4], const SkVector& no rmalAB, 478 void SkPathStroker::setCubicEndNormal(const SkPoint cubic[4], const SkVector& no rmalAB,
474 const SkVector& unitNormalAB, SkVector* normalCD, SkVector* unitNormalCD ) { 479 const SkVector& unitNormalAB, SkVector* normalCD, SkVector* unitNormalCD ) {
475 SkVector ab = cubic[1] - cubic[0]; 480 SkVector ab = cubic[1] - cubic[0];
476 SkVector cd = cubic[3] - cubic[2]; 481 SkVector cd = cubic[3] - cubic[2];
477 482
478 bool degenerateAB = degenerate_vector(ab); 483 bool degenerateAB = degenerate_vector(ab);
479 bool degenerateCD = degenerate_vector(cd); 484 bool degenerateCD = degenerate_vector(cd);
480 485
481 if (degenerateAB && degenerateCD) { 486 if (degenerateAB && degenerateCD) {
482 goto DEGENERATE_NORMAL; 487 goto DEGENERATE_NORMAL;
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
540 If outer_1 == 0 and outer_2 == 1, the smaller of the remaining indices (2 an d 3) is 2. 545 If outer_1 == 0 and outer_2 == 1, the smaller of the remaining indices (2 an d 3) is 2.
541 546
542 This table can be collapsed to: (1 + (2 >> outer_2)) >> outer_1 547 This table can be collapsed to: (1 + (2 >> outer_2)) >> outer_1
543 548
544 Given three indices (outer_1 outer_2 mid_1) from 0..3, the remaining index i s: 549 Given three indices (outer_1 outer_2 mid_1) from 0..3, the remaining index i s:
545 550
546 mid_2 == (outer_1 ^ outer_2 ^ mid_1) 551 mid_2 == (outer_1 ^ outer_2 ^ mid_1)
547 */ 552 */
548 static bool cubic_in_line(const SkPoint cubic[4]) { 553 static bool cubic_in_line(const SkPoint cubic[4]) {
549 SkScalar ptMax = -1; 554 SkScalar ptMax = -1;
550 int outer1, outer2; 555 int outer1 SK_INIT_TO_AVOID_WARNING;
556 int outer2 SK_INIT_TO_AVOID_WARNING;
551 for (int index = 0; index < 3; ++index) { 557 for (int index = 0; index < 3; ++index) {
552 for (int inner = index + 1; inner < 4; ++inner) { 558 for (int inner = index + 1; inner < 4; ++inner) {
553 SkVector testDiff = cubic[inner] - cubic[index]; 559 SkVector testDiff = cubic[inner] - cubic[index];
554 SkScalar testMax = SkTMax(SkScalarAbs(testDiff.fX), SkScalarAbs(test Diff.fY)); 560 SkScalar testMax = SkTMax(SkScalarAbs(testDiff.fX), SkScalarAbs(test Diff.fY));
555 if (ptMax < testMax) { 561 if (ptMax < testMax) {
556 outer1 = index; 562 outer1 = index;
557 outer2 = inner; 563 outer2 = inner;
558 ptMax = testMax; 564 ptMax = testMax;
559 } 565 }
560 } 566 }
(...skipping 15 matching lines...) Expand all
576 582
577 /* Given quad, see if all there points are in a line. 583 /* Given quad, see if all there points are in a line.
578 Return true if the inside point is close to a line connecting the outermost p oints. 584 Return true if the inside point is close to a line connecting the outermost p oints.
579 585
580 Find the outermost point by looking for the largest difference in X or Y. 586 Find the outermost point by looking for the largest difference in X or Y.
581 Since the XOR of the indices is 3 (0 ^ 1 ^ 2) 587 Since the XOR of the indices is 3 (0 ^ 1 ^ 2)
582 the missing index equals: outer_1 ^ outer_2 ^ 3 588 the missing index equals: outer_1 ^ outer_2 ^ 3
583 */ 589 */
584 static bool quad_in_line(const SkPoint quad[3]) { 590 static bool quad_in_line(const SkPoint quad[3]) {
585 SkScalar ptMax = -1; 591 SkScalar ptMax = -1;
586 int outer1, outer2; 592 int outer1 SK_INIT_TO_AVOID_WARNING;
593 int outer2 SK_INIT_TO_AVOID_WARNING;
587 for (int index = 0; index < 2; ++index) { 594 for (int index = 0; index < 2; ++index) {
588 for (int inner = index + 1; inner < 3; ++inner) { 595 for (int inner = index + 1; inner < 3; ++inner) {
589 SkVector testDiff = quad[inner] - quad[index]; 596 SkVector testDiff = quad[inner] - quad[index];
590 SkScalar testMax = SkTMax(SkScalarAbs(testDiff.fX), SkScalarAbs(test Diff.fY)); 597 SkScalar testMax = SkTMax(SkScalarAbs(testDiff.fX), SkScalarAbs(test Diff.fY));
591 if (ptMax < testMax) { 598 if (ptMax < testMax) {
592 outer1 = index; 599 outer1 = index;
593 outer2 = inner; 600 outer2 = inner;
594 ptMax = testMax; 601 ptMax = testMax;
595 } 602 }
596 } 603 }
597 } 604 }
598 SkASSERT(outer1 >= 0 && outer1 <= 1); 605 SkASSERT(outer1 >= 0 && outer1 <= 1);
599 SkASSERT(outer2 >= 1 && outer2 <= 2); 606 SkASSERT(outer2 >= 1 && outer2 <= 2);
600 SkASSERT(outer1 < outer2); 607 SkASSERT(outer1 < outer2);
601 int mid = outer1 ^ outer2 ^ 3; 608 int mid = outer1 ^ outer2 ^ 3;
602 SkScalar lineSlop = ptMax * ptMax * 0.00001f; // this multiplier is pulled out of the air 609 SkScalar lineSlop = ptMax * ptMax * 0.00001f; // this multiplier is pulled out of the air
603 return pt_to_line(quad[mid], quad[outer1], quad[outer2]) <= lineSlop; 610 return pt_to_line(quad[mid], quad[outer1], quad[outer2]) <= lineSlop;
604 } 611 }
605 612
613 static bool conic_in_line(const SkConic& conic) {
614 return quad_in_line(conic.fPts);
615 }
616
606 SkPathStroker::ReductionType SkPathStroker::CheckCubicLinear(const SkPoint cubic [4], 617 SkPathStroker::ReductionType SkPathStroker::CheckCubicLinear(const SkPoint cubic [4],
607 SkPoint reduction[3], const SkPoint** tangentPtPtr) { 618 SkPoint reduction[3], const SkPoint** tangentPtPtr) {
608 bool degenerateAB = degenerate_vector(cubic[1] - cubic[0]); 619 bool degenerateAB = degenerate_vector(cubic[1] - cubic[0]);
609 bool degenerateBC = degenerate_vector(cubic[2] - cubic[1]); 620 bool degenerateBC = degenerate_vector(cubic[2] - cubic[1]);
610 bool degenerateCD = degenerate_vector(cubic[3] - cubic[2]); 621 bool degenerateCD = degenerate_vector(cubic[3] - cubic[2]);
611 if (degenerateAB & degenerateBC & degenerateCD) { 622 if (degenerateAB & degenerateBC & degenerateCD) {
612 return kPoint_ReductionType; 623 return kPoint_ReductionType;
613 } 624 }
614 if (degenerateAB + degenerateBC + degenerateCD == 2) { 625 if (degenerateAB + degenerateBC + degenerateCD == 2) {
615 return kLine_ReductionType; 626 return kLine_ReductionType;
(...skipping 11 matching lines...) Expand all
627 SkScalar t = tValues[index]; 638 SkScalar t = tValues[index];
628 SkEvalCubicAt(cubic, t, &reduction[index], NULL, NULL); 639 SkEvalCubicAt(cubic, t, &reduction[index], NULL, NULL);
629 } 640 }
630 SK_COMPILE_ASSERT(kQuad_ReductionType + 1 == kDegenerate_ReductionType, enum _out_of_whack); 641 SK_COMPILE_ASSERT(kQuad_ReductionType + 1 == kDegenerate_ReductionType, enum _out_of_whack);
631 SK_COMPILE_ASSERT(kQuad_ReductionType + 2 == kDegenerate2_ReductionType, enu m_out_of_whack); 642 SK_COMPILE_ASSERT(kQuad_ReductionType + 2 == kDegenerate2_ReductionType, enu m_out_of_whack);
632 SK_COMPILE_ASSERT(kQuad_ReductionType + 3 == kDegenerate3_ReductionType, enu m_out_of_whack); 643 SK_COMPILE_ASSERT(kQuad_ReductionType + 3 == kDegenerate3_ReductionType, enu m_out_of_whack);
633 644
634 return (ReductionType) (kQuad_ReductionType + count); 645 return (ReductionType) (kQuad_ReductionType + count);
635 } 646 }
636 647
648 SkPathStroker::ReductionType SkPathStroker::CheckConicLinear(const SkConic& coni c,
649 SkPoint* reduction) {
650 bool degenerateAB = degenerate_vector(conic.fPts[1] - conic.fPts[0]);
651 bool degenerateBC = degenerate_vector(conic.fPts[2] - conic.fPts[1]);
652 if (degenerateAB & degenerateBC) {
653 return kPoint_ReductionType;
654 }
655 if (degenerateAB | degenerateBC) {
656 return kLine_ReductionType;
657 }
658 if (!conic_in_line(conic)) {
659 return kQuad_ReductionType;
660 }
661 SkScalar t;
662 if (!conic.findMaxCurvature(&t) || 0 == t) {
663 return kLine_ReductionType;
664 }
665 conic.evalAt(t, reduction, NULL);
666 return kDegenerate_ReductionType;
667 }
668
637 SkPathStroker::ReductionType SkPathStroker::CheckQuadLinear(const SkPoint quad[3 ], 669 SkPathStroker::ReductionType SkPathStroker::CheckQuadLinear(const SkPoint quad[3 ],
638 SkPoint* reduction) { 670 SkPoint* reduction) {
639 bool degenerateAB = degenerate_vector(quad[1] - quad[0]); 671 bool degenerateAB = degenerate_vector(quad[1] - quad[0]);
640 bool degenerateBC = degenerate_vector(quad[2] - quad[1]); 672 bool degenerateBC = degenerate_vector(quad[2] - quad[1]);
641 if (degenerateAB & degenerateBC) { 673 if (degenerateAB & degenerateBC) {
642 return kPoint_ReductionType; 674 return kPoint_ReductionType;
643 } 675 }
644 if (degenerateAB | degenerateBC) { 676 if (degenerateAB | degenerateBC) {
645 return kLine_ReductionType; 677 return kLine_ReductionType;
646 } 678 }
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
735 pts[2].fX + normalC.fX, pts[2].fY + normalC.fY, 767 pts[2].fX + normalC.fX, pts[2].fY + normalC.fY,
736 pts[3].fX + normalCD->fX, pts[3].fY + normalCD->fY); 768 pts[3].fX + normalCD->fX, pts[3].fY + normalCD->fY);
737 769
738 fInner.cubicTo( pts[1].fX - normalB.fX, pts[1].fY - normalB.fY, 770 fInner.cubicTo( pts[1].fX - normalB.fX, pts[1].fY - normalB.fY,
739 pts[2].fX - normalC.fX, pts[2].fY - normalC.fY, 771 pts[2].fX - normalC.fX, pts[2].fY - normalC.fY,
740 pts[3].fX - normalCD->fX, pts[3].fY - normalCD->fY); 772 pts[3].fX - normalCD->fX, pts[3].fY - normalCD->fY);
741 } 773 }
742 } 774 }
743 #endif 775 #endif
744 776
777 #ifdef SK_QUAD_STROKE_APPROXIMATION
778 void SkPathStroker::conicTo(const SkPoint& pt1, const SkPoint& pt2, SkScalar wei ght) {
779 const SkConic conic(fPrevPt, pt1, pt2, weight);
780 SkPoint reduction;
781 ReductionType reductionType = CheckConicLinear(conic, &reduction);
782 if (kPoint_ReductionType == reductionType) {
783 return;
784 }
785 if (kLine_ReductionType == reductionType) {
786 this->lineTo(pt2);
787 return;
788 }
789 if (kDegenerate_ReductionType == reductionType) {
790 this->lineTo(reduction);
791 SkStrokerPriv::JoinProc saveJoiner = fJoiner;
792 fJoiner = SkStrokerPriv::JoinFactory(SkPaint::kRound_Join);
793 this->lineTo(pt2);
794 fJoiner = saveJoiner;
795 return;
796 }
797 SkASSERT(kQuad_ReductionType == reductionType);
798 SkVector normalAB, unitAB, normalBC, unitBC;
799 this->preJoinTo(pt1, &normalAB, &unitAB, false);
800 SkQuadConstruct quadPts;
801 this->init(kOuter_StrokeType, &quadPts, 0, 1);
802 if (!this->conicStroke(conic, &quadPts)) {
803 return;
804 }
805 this->init(kInner_StrokeType, &quadPts, 0, 1);
806 if (!this->conicStroke(conic, &quadPts)) {
807 return;
808 }
809 this->setConicEndNormal(conic, normalAB, unitAB, &normalBC, &unitBC);
810 this->postJoinTo(pt2, normalBC, unitBC);
811 }
812 #endif
813
745 void SkPathStroker::quadTo(const SkPoint& pt1, const SkPoint& pt2) { 814 void SkPathStroker::quadTo(const SkPoint& pt1, const SkPoint& pt2) {
746 #if QUAD_STROKE_APPROXIMATION 815 #ifdef SK_QUAD_STROKE_APPROXIMATION
747 const SkPoint quad[3] = { fPrevPt, pt1, pt2 }; 816 const SkPoint quad[3] = { fPrevPt, pt1, pt2 };
748 SkPoint reduction; 817 SkPoint reduction;
749 ReductionType reductionType = CheckQuadLinear(quad, &reduction); 818 ReductionType reductionType = CheckQuadLinear(quad, &reduction);
750 if (kPoint_ReductionType == reductionType) { 819 if (kPoint_ReductionType == reductionType) {
751 return; 820 return;
752 } 821 }
753 if (kLine_ReductionType == reductionType) { 822 if (kLine_ReductionType == reductionType) {
754 this->lineTo(pt2); 823 this->lineTo(pt2);
755 return; 824 return;
756 } 825 }
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
824 } else { 893 } else {
825 this->quad_to(pts, normalAB, unitAB, &normalBC, &unitBC, 894 this->quad_to(pts, normalAB, unitAB, &normalBC, &unitBC,
826 kMaxQuadSubdivide); 895 kMaxQuadSubdivide);
827 } 896 }
828 } 897 }
829 #endif 898 #endif
830 899
831 this->postJoinTo(pt2, normalBC, unitBC); 900 this->postJoinTo(pt2, normalBC, unitBC);
832 } 901 }
833 902
834 #if QUAD_STROKE_APPROXIMATION 903 #ifdef SK_QUAD_STROKE_APPROXIMATION
835 // Given a point on the curve and its derivative, scale the derivative by the ra dius, and 904 // Given a point on the curve and its derivative, scale the derivative by the ra dius, and
836 // compute the perpendicular point and its tangent. 905 // compute the perpendicular point and its tangent.
837 void SkPathStroker::setRayPts(const SkPoint& tPt, SkVector* dxy, SkPoint* onPt, 906 void SkPathStroker::setRayPts(const SkPoint& tPt, SkVector* dxy, SkPoint* onPt,
838 SkPoint* tangent) const { 907 SkPoint* tangent) const {
839 if (!dxy->setLength(fRadius)) { // consider moving double logic into SkPoin t::setLength 908 if (!dxy->setLength(fRadius)) { // consider moving double logic into SkPoin t::setLength
840 double xx = dxy->fX; 909 double xx = dxy->fX;
841 double yy = dxy->fY; 910 double yy = dxy->fY;
842 double dscale = fRadius / sqrt(xx * xx + yy * yy); 911 double dscale = fRadius / sqrt(xx * xx + yy * yy);
843 dxy->fX = SkDoubleToScalar(xx * dscale); 912 dxy->fX = SkDoubleToScalar(xx * dscale);
844 dxy->fY = SkDoubleToScalar(yy * dscale); 913 dxy->fY = SkDoubleToScalar(yy * dscale);
845 } 914 }
846 SkScalar axisFlip = SkIntToScalar(fStrokeType); // go opposite ways for out er, inner 915 SkScalar axisFlip = SkIntToScalar(fStrokeType); // go opposite ways for out er, inner
847 onPt->fX = tPt.fX + axisFlip * dxy->fY; 916 onPt->fX = tPt.fX + axisFlip * dxy->fY;
848 onPt->fY = tPt.fY - axisFlip * dxy->fX; 917 onPt->fY = tPt.fY - axisFlip * dxy->fX;
849 if (tangent) { 918 if (tangent) {
850 tangent->fX = onPt->fX + dxy->fX; 919 tangent->fX = onPt->fX + dxy->fX;
851 tangent->fY = onPt->fY + dxy->fY; 920 tangent->fY = onPt->fY + dxy->fY;
852 } 921 }
853 } 922 }
854 923
924 // Given a conic and t, return the point on curve, its perpendicular, and the pe rpendicular tangent.
925 // Returns false if the perpendicular could not be computed (because the derivat ive collapsed to 0)
926 bool SkPathStroker::conicPerpRay(const SkConic& conic, SkScalar t, SkPoint* tPt, SkPoint* onPt,
927 SkPoint* tangent) const {
928 SkVector dxy;
929 conic.evalAt(t, tPt, &dxy);
930 if (dxy.fX == 0 && dxy.fY == 0) {
931 dxy = conic.fPts[2] - conic.fPts[0];
932 }
933 setRayPts(*tPt, &dxy, onPt, tangent);
934 return true;
935 }
936
937 // Given a conic and a t range, find the start and end if they haven't been foun d already.
938 bool SkPathStroker::conicQuadEnds(const SkConic& conic, SkQuadConstruct* quadPts ) {
939 if (!quadPts->fStartSet) {
940 SkPoint conicStartPt;
941 if (!this->conicPerpRay(conic, quadPts->fStartT, &conicStartPt, &quadPts ->fQuad[0],
942 &quadPts->fTangentStart)) {
943 return false;
944 }
945 quadPts->fStartSet = true;
946 }
947 if (!quadPts->fEndSet) {
948 SkPoint conicEndPt;
949 if (!this->conicPerpRay(conic, quadPts->fEndT, &conicEndPt, &quadPts->fQ uad[2],
950 &quadPts->fTangentEnd)) {
951 return false;
952 }
953 quadPts->fEndSet = true;
954 }
955 return true;
956 }
957
958
855 // Given a cubic and t, return the point on curve, its perpendicular, and the pe rpendicular tangent. 959 // Given a cubic and t, return the point on curve, its perpendicular, and the pe rpendicular tangent.
856 // Returns false if the perpendicular could not be computed (because the derivat ive collapsed to 0) 960 // Returns false if the perpendicular could not be computed (because the derivat ive collapsed to 0)
857 bool SkPathStroker::cubicPerpRay(const SkPoint cubic[4], SkScalar t, SkPoint* tP t, SkPoint* onPt, 961 bool SkPathStroker::cubicPerpRay(const SkPoint cubic[4], SkScalar t, SkPoint* tP t, SkPoint* onPt,
858 SkPoint* tangent) const { 962 SkPoint* tangent) const {
859 SkVector dxy; 963 SkVector dxy;
860 SkEvalCubicAt(cubic, t, tPt, &dxy, NULL); 964 SkEvalCubicAt(cubic, t, tPt, &dxy, NULL);
861 if (dxy.fX == 0 && dxy.fY == 0) { 965 if (dxy.fX == 0 && dxy.fY == 0) {
862 if (SkScalarNearlyZero(t)) { 966 if (SkScalarNearlyZero(t)) {
863 dxy = cubic[2] - cubic[0]; 967 dxy = cubic[2] - cubic[0];
864 } else if (SkScalarNearlyZero(1 - t)) { 968 } else if (SkScalarNearlyZero(1 - t)) {
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
923 SkVector bLen = quadPts->fTangentEnd - end; 1027 SkVector bLen = quadPts->fTangentEnd - end;
924 SkScalar denom = aLen.cross(bLen); 1028 SkScalar denom = aLen.cross(bLen);
925 SkVector ab0 = start - end; 1029 SkVector ab0 = start - end;
926 SkScalar numerA = bLen.cross(ab0); 1030 SkScalar numerA = bLen.cross(ab0);
927 SkScalar numerB = aLen.cross(ab0); 1031 SkScalar numerB = aLen.cross(ab0);
928 if (!SkScalarNearlyZero(denom)) { 1032 if (!SkScalarNearlyZero(denom)) {
929 // if the perpendicular distances from the quad points to the opposite t angent line 1033 // if the perpendicular distances from the quad points to the opposite t angent line
930 // are small, a straight line is good enough 1034 // are small, a straight line is good enough
931 SkScalar dist1 = pt_to_line(start, end, quadPts->fTangentEnd); 1035 SkScalar dist1 = pt_to_line(start, end, quadPts->fTangentEnd);
932 SkScalar dist2 = pt_to_line(end, start, quadPts->fTangentStart); 1036 SkScalar dist2 = pt_to_line(end, start, quadPts->fTangentStart);
933 if (SkTMax(dist1, dist2) <= fError * fError) {
934 return STROKER_RESULT(kDegenerate_ResultType, depth, quadPts,
935 "SkTMax(dist1=%g, dist2=%g) <= fError * fError", dist1, dist 2);
936 }
937 if ((numerA >= 0) != (numerB >= 0)) { 1037 if ((numerA >= 0) != (numerB >= 0)) {
938 if (kCtrlPt_RayType == intersectRayType) { 1038 if (kCtrlPt_RayType == intersectRayType) {
939 numerA /= denom; 1039 numerA /= denom;
940 SkPoint* ctrlPt = &quadPts->fQuad[1]; 1040 SkPoint* ctrlPt = &quadPts->fQuad[1];
941 ctrlPt->fX = start.fX * (1 - numerA) + quadPts->fTangentStart.fX * numerA; 1041 ctrlPt->fX = start.fX * (1 - numerA) + quadPts->fTangentStart.fX * numerA;
942 ctrlPt->fY = start.fY * (1 - numerA) + quadPts->fTangentStart.fY * numerA; 1042 ctrlPt->fY = start.fY * (1 - numerA) + quadPts->fTangentStart.fY * numerA;
943 } 1043 }
944 return STROKER_RESULT(kQuad_ResultType, depth, quadPts, 1044 return STROKER_RESULT(kQuad_ResultType, depth, quadPts,
945 "(numerA=%g >= 0) != (numerB=%g >= 0)", numerA, numerB); 1045 "(numerA=%g >= 0) != (numerB=%g >= 0)", numerA, numerB);
946 } 1046 }
1047 if (SkTMax(dist1, dist2) <= fInvResScaleSquared) {
1048 return STROKER_RESULT(kDegenerate_ResultType, depth, quadPts,
1049 "SkTMax(dist1=%g, dist2=%g) <= fInvResScaleSquared", dist1, dist2);
1050 }
947 return STROKER_RESULT(kSplit_ResultType, depth, quadPts, 1051 return STROKER_RESULT(kSplit_ResultType, depth, quadPts,
948 "(numerA=%g >= 0) == (numerB=%g >= 0)", numerA, numerB); 1052 "(numerA=%g >= 0) == (numerB=%g >= 0)", numerA, numerB);
949 } else { // if the lines are parallel, straight line is good enough 1053 } else { // if the lines are parallel, straight line is good enough
950 return STROKER_RESULT(kDegenerate_ResultType, depth, quadPts, 1054 return STROKER_RESULT(kDegenerate_ResultType, depth, quadPts,
951 "SkScalarNearlyZero(denom=%g)", denom); 1055 "SkScalarNearlyZero(denom=%g)", denom);
952 } 1056 }
953 } 1057 }
954 1058
955 // Given a cubic and a t-range, determine if the stroke can be described by a qu adratic. 1059 // Given a cubic and a t-range, determine if the stroke can be described by a qu adratic.
956 SkPathStroker::ResultType SkPathStroker::tangentsMeet(const SkPoint cubic[4], 1060 SkPathStroker::ResultType SkPathStroker::tangentsMeet(const SkPoint cubic[4],
(...skipping 15 matching lines...) Expand all
972 SkScalar B = r[1]; 1076 SkScalar B = r[1];
973 SkScalar C = r[0]; 1077 SkScalar C = r[0];
974 A += C - 2 * B; // A = a - 2*b + c 1078 A += C - 2 * B; // A = a - 2*b + c
975 B -= C; // B = -(b - c) 1079 B -= C; // B = -(b - c)
976 return SkFindUnitQuadRoots(A, 2 * B, C, roots); 1080 return SkFindUnitQuadRoots(A, 2 * B, C, roots);
977 } 1081 }
978 1082
979 // Return true if the point is close to the bounds of the quad. This is used as a quick reject. 1083 // Return true if the point is close to the bounds of the quad. This is used as a quick reject.
980 bool SkPathStroker::ptInQuadBounds(const SkPoint quad[3], const SkPoint& pt) con st { 1084 bool SkPathStroker::ptInQuadBounds(const SkPoint quad[3], const SkPoint& pt) con st {
981 SkScalar xMin = SkTMin(SkTMin(quad[0].fX, quad[1].fX), quad[2].fX); 1085 SkScalar xMin = SkTMin(SkTMin(quad[0].fX, quad[1].fX), quad[2].fX);
982 if (pt.fX + fError < xMin) { 1086 if (pt.fX + fInvResScale < xMin) {
983 return false; 1087 return false;
984 } 1088 }
985 SkScalar xMax = SkTMax(SkTMax(quad[0].fX, quad[1].fX), quad[2].fX); 1089 SkScalar xMax = SkTMax(SkTMax(quad[0].fX, quad[1].fX), quad[2].fX);
986 if (pt.fX - fError > xMax) { 1090 if (pt.fX - fInvResScale > xMax) {
987 return false; 1091 return false;
988 } 1092 }
989 SkScalar yMin = SkTMin(SkTMin(quad[0].fY, quad[1].fY), quad[2].fY); 1093 SkScalar yMin = SkTMin(SkTMin(quad[0].fY, quad[1].fY), quad[2].fY);
990 if (pt.fY + fError < yMin) { 1094 if (pt.fY + fInvResScale < yMin) {
991 return false; 1095 return false;
992 } 1096 }
993 SkScalar yMax = SkTMax(SkTMax(quad[0].fY, quad[1].fY), quad[2].fY); 1097 SkScalar yMax = SkTMax(SkTMax(quad[0].fY, quad[1].fY), quad[2].fY);
994 if (pt.fY - fError > yMax) { 1098 if (pt.fY - fInvResScale > yMax) {
995 return false; 1099 return false;
996 } 1100 }
997 return true; 1101 return true;
998 } 1102 }
999 1103
1000 static bool points_within_dist(const SkPoint& nearPt, const SkPoint& farPt, SkSc alar limit) { 1104 static bool points_within_dist(const SkPoint& nearPt, const SkPoint& farPt, SkSc alar limit) {
1001 return nearPt.distanceToSqd(farPt) <= limit * limit; 1105 return nearPt.distanceToSqd(farPt) <= limit * limit;
1002 } 1106 }
1003 1107
1004 static bool sharp_angle(const SkPoint quad[3]) { 1108 static bool sharp_angle(const SkPoint quad[3]) {
(...skipping 10 matching lines...) Expand all
1015 } 1119 }
1016 SkScalar dot = smaller.dot(larger); 1120 SkScalar dot = smaller.dot(larger);
1017 return dot > 0; 1121 return dot > 0;
1018 } 1122 }
1019 1123
1020 SkPathStroker::ResultType SkPathStroker::strokeCloseEnough(const SkPoint stroke[ 3], 1124 SkPathStroker::ResultType SkPathStroker::strokeCloseEnough(const SkPoint stroke[ 3],
1021 const SkPoint ray[2], SkQuadConstruct* quadPts STROKER_DEBUG_PARAMS(int depth)) const { 1125 const SkPoint ray[2], SkQuadConstruct* quadPts STROKER_DEBUG_PARAMS(int depth)) const {
1022 SkPoint strokeMid; 1126 SkPoint strokeMid;
1023 SkEvalQuadAt(stroke, SK_ScalarHalf, &strokeMid); 1127 SkEvalQuadAt(stroke, SK_ScalarHalf, &strokeMid);
1024 // measure the distance from the curve to the quad-stroke midpoint, compare to radius 1128 // measure the distance from the curve to the quad-stroke midpoint, compare to radius
1025 if (points_within_dist(ray[0], strokeMid, fError)) { // if the difference i s small 1129 if (points_within_dist(ray[0], strokeMid, fInvResScaleSquared)) { // if the difference is small
1026 if (sharp_angle(quadPts->fQuad)) { 1130 if (sharp_angle(quadPts->fQuad)) {
1027 return STROKER_RESULT(kSplit_ResultType, depth, quadPts, 1131 return STROKER_RESULT(kSplit_ResultType, depth, quadPts,
1028 "sharp_angle (1) =%g,%g, %g,%g, %g,%g", 1132 "sharp_angle (1) =%g,%g, %g,%g, %g,%g",
1029 quadPts->fQuad[0].fX, quadPts->fQuad[0].fY, 1133 quadPts->fQuad[0].fX, quadPts->fQuad[0].fY,
1030 quadPts->fQuad[1].fX, quadPts->fQuad[1].fY, 1134 quadPts->fQuad[1].fX, quadPts->fQuad[1].fY,
1031 quadPts->fQuad[2].fX, quadPts->fQuad[2].fY); 1135 quadPts->fQuad[2].fX, quadPts->fQuad[2].fY);
1032 } 1136 }
1033 return STROKER_RESULT(kQuad_ResultType, depth, quadPts, 1137 return STROKER_RESULT(kQuad_ResultType, depth, quadPts,
1034 "points_within_dist(ray[0]=%g,%g, strokeMid=%g,%g, fError)", 1138 "points_within_dist(ray[0]=%g,%g, strokeMid=%g,%g, fInvResScaleS quared=%g)",
1035 ray[0].fX, ray[0].fY, strokeMid.fX, strokeMid.fY); 1139 ray[0].fX, ray[0].fY, strokeMid.fX, strokeMid.fY, fInvResScaleSq uared);
1036 } 1140 }
1037 // measure the distance to quad's bounds (quick reject) 1141 // measure the distance to quad's bounds (quick reject)
1038 // an alternative : look for point in triangle 1142 // an alternative : look for point in triangle
1039 if (!ptInQuadBounds(stroke, ray[0])) { // if far, subdivide 1143 if (!ptInQuadBounds(stroke, ray[0])) { // if far, subdivide
1040 return STROKER_RESULT(kSplit_ResultType, depth, quadPts, 1144 return STROKER_RESULT(kSplit_ResultType, depth, quadPts,
1041 "!pt_in_quad_bounds(stroke=(%g,%g %g,%g %g,%g), ray[0]=%g,%g)", 1145 "!pt_in_quad_bounds(stroke=(%g,%g %g,%g %g,%g), ray[0]=%g,%g)",
1042 stroke[0].fX, stroke[0].fY, stroke[1].fX, stroke[1].fY, stroke[2 ].fX, stroke[2].fY, 1146 stroke[0].fX, stroke[0].fY, stroke[1].fX, stroke[1].fY, stroke[2 ].fX, stroke[2].fY,
1043 ray[0].fX, ray[0].fY); 1147 ray[0].fX, ray[0].fY);
1044 } 1148 }
1045 // measure the curve ray distance to the quad-stroke 1149 // measure the curve ray distance to the quad-stroke
1046 SkScalar roots[2]; 1150 SkScalar roots[2];
1047 int rootCount = intersect_quad_ray(ray, stroke, roots); 1151 int rootCount = intersect_quad_ray(ray, stroke, roots);
1048 if (rootCount != 1) { 1152 if (rootCount != 1) {
1049 return STROKER_RESULT(kSplit_ResultType, depth, quadPts, 1153 return STROKER_RESULT(kSplit_ResultType, depth, quadPts,
1050 "rootCount=%d != 1", rootCount); 1154 "rootCount=%d != 1", rootCount);
1051 } 1155 }
1052 SkPoint quadPt; 1156 SkPoint quadPt;
1053 SkEvalQuadAt(stroke, roots[0], &quadPt); 1157 SkEvalQuadAt(stroke, roots[0], &quadPt);
1054 SkScalar error = fError * (SK_Scalar1 - SkScalarAbs(roots[0] - 0.5f) * 2); 1158 SkScalar error = fInvResScale * (SK_Scalar1 - SkScalarAbs(roots[0] - 0.5f) * 2);
1055 if (points_within_dist(ray[0], quadPt, error)) { // if the difference is sm all, we're done 1159 if (points_within_dist(ray[0], quadPt, error)) { // if the difference is sm all, we're done
1056 if (sharp_angle(quadPts->fQuad)) { 1160 if (sharp_angle(quadPts->fQuad)) {
1057 return STROKER_RESULT(kSplit_ResultType, depth, quadPts, 1161 return STROKER_RESULT(kSplit_ResultType, depth, quadPts,
1058 "sharp_angle (2) =%g,%g, %g,%g, %g,%g", 1162 "sharp_angle (2) =%g,%g, %g,%g, %g,%g",
1059 quadPts->fQuad[0].fX, quadPts->fQuad[0].fY, 1163 quadPts->fQuad[0].fX, quadPts->fQuad[0].fY,
1060 quadPts->fQuad[1].fX, quadPts->fQuad[1].fY, 1164 quadPts->fQuad[1].fX, quadPts->fQuad[1].fY,
1061 quadPts->fQuad[2].fX, quadPts->fQuad[2].fY); 1165 quadPts->fQuad[2].fX, quadPts->fQuad[2].fY);
1062 } 1166 }
1063 return STROKER_RESULT(kQuad_ResultType, depth, quadPts, 1167 return STROKER_RESULT(kQuad_ResultType, depth, quadPts,
1064 "points_within_dist(ray[0]=%g,%g, quadPt=%g,%g, error=%g)", 1168 "points_within_dist(ray[0]=%g,%g, quadPt=%g,%g, error=%g)",
1065 ray[0].fX, ray[0].fY, quadPt.fX, quadPt.fY, error); 1169 ray[0].fX, ray[0].fY, quadPt.fX, quadPt.fY, error);
1066 } 1170 }
1067 // otherwise, subdivide 1171 // otherwise, subdivide
1068 return STROKER_RESULT(kSplit_ResultType, depth, quadPts, "%s", "fall through "); 1172 return STROKER_RESULT(kSplit_ResultType, depth, quadPts, "%s", "fall through ");
1069 } 1173 }
1070 1174
1071 SkPathStroker::ResultType SkPathStroker::compareQuadCubic(const SkPoint cubic[4] , 1175 SkPathStroker::ResultType SkPathStroker::compareQuadCubic(const SkPoint cubic[4] ,
1072 SkQuadConstruct* quadPts) { 1176 SkQuadConstruct* quadPts) {
1073 // get the quadratic approximation of the stroke 1177 // get the quadratic approximation of the stroke
1074 if (!this->cubicQuadEnds(cubic, quadPts)) { 1178 if (!this->cubicQuadEnds(cubic, quadPts)) {
1075 return kNormalError_ResultType; 1179 return kNormalError_ResultType;
1076 } 1180 }
1077 ResultType resultType = intersectRay(quadPts, kCtrlPt_RayType 1181 ResultType resultType = intersectRay(quadPts, kCtrlPt_RayType
1078 STROKER_DEBUG_PARAMS(fRecursionDepth) ); 1182 STROKER_DEBUG_PARAMS(fRecursionDepth) );
1079 if (resultType != kQuad_ResultType) { 1183 if (resultType != kQuad_ResultType) {
1080 return resultType; 1184 return resultType;
1081 } 1185 }
1082 // project a ray from the curve to the stroke 1186 // project a ray from the curve to the stroke
1083 SkPoint ray[2]; // point near midpoint on quad, midpoint on cubic 1187 SkPoint ray[2]; // points near midpoint on quad, midpoint on cubic
1084 if (!this->cubicPerpRay(cubic, quadPts->fMidT, &ray[1], &ray[0], NULL)) { 1188 if (!this->cubicPerpRay(cubic, quadPts->fMidT, &ray[1], &ray[0], NULL)) {
1085 return kNormalError_ResultType; 1189 return kNormalError_ResultType;
1086 } 1190 }
1087 return strokeCloseEnough(quadPts->fQuad, ray, quadPts STROKER_DEBUG_PARAMS( fRecursionDepth)); 1191 return strokeCloseEnough(quadPts->fQuad, ray, quadPts STROKER_DEBUG_PARAMS( fRecursionDepth));
1088 } 1192 }
1089 1193
1090 // if false is returned, caller splits quadratic approximation 1194 SkPathStroker::ResultType SkPathStroker::compareQuadConic(const SkConic& conic,
1195 SkQuadConstruct* quadPts) {
1196 // get the quadratic approximation of the stroke
1197 if (!this->conicQuadEnds(conic, quadPts)) {
1198 return kNormalError_ResultType;
1199 }
1200 ResultType resultType = intersectRay(quadPts, kCtrlPt_RayType
1201 STROKER_DEBUG_PARAMS(fRecursionDepth) );
1202 if (resultType != kQuad_ResultType) {
1203 return resultType;
1204 }
1205 // project a ray from the curve to the stroke
1206 SkPoint ray[2]; // points near midpoint on quad, midpoint on conic
1207 if (!this->conicPerpRay(conic, quadPts->fMidT, &ray[1], &ray[0], NULL)) {
1208 return kNormalError_ResultType;
1209 }
1210 return strokeCloseEnough(quadPts->fQuad, ray, quadPts STROKER_DEBUG_PARAMS( fRecursionDepth));
1211 }
1212
1091 SkPathStroker::ResultType SkPathStroker::compareQuadQuad(const SkPoint quad[3], 1213 SkPathStroker::ResultType SkPathStroker::compareQuadQuad(const SkPoint quad[3],
1092 SkQuadConstruct* quadPts) { 1214 SkQuadConstruct* quadPts) {
1093 // get the quadratic approximation of the stroke 1215 // get the quadratic approximation of the stroke
1094 if (!quadPts->fStartSet) { 1216 if (!quadPts->fStartSet) {
1095 SkPoint quadStartPt; 1217 SkPoint quadStartPt;
1096 this->quadPerpRay(quad, quadPts->fStartT, &quadStartPt, &quadPts->fQuad[ 0], 1218 this->quadPerpRay(quad, quadPts->fStartT, &quadStartPt, &quadPts->fQuad[ 0],
1097 &quadPts->fTangentStart); 1219 &quadPts->fTangentStart);
1098 quadPts->fStartSet = true; 1220 quadPts->fStartSet = true;
1099 } 1221 }
1100 if (!quadPts->fEndSet) { 1222 if (!quadPts->fEndSet) {
(...skipping 18 matching lines...) Expand all
1119 SkPath* path = fStrokeType == kOuter_StrokeType ? &fOuter : &fInner; 1241 SkPath* path = fStrokeType == kOuter_StrokeType ? &fOuter : &fInner;
1120 path->lineTo(quad[2].fX, quad[2].fY); 1242 path->lineTo(quad[2].fX, quad[2].fY);
1121 } 1243 }
1122 1244
1123 bool SkPathStroker::cubicMidOnLine(const SkPoint cubic[4], const SkQuadConstruct * quadPts) const { 1245 bool SkPathStroker::cubicMidOnLine(const SkPoint cubic[4], const SkQuadConstruct * quadPts) const {
1124 SkPoint strokeMid; 1246 SkPoint strokeMid;
1125 if (!cubicQuadMid(cubic, quadPts, &strokeMid)) { 1247 if (!cubicQuadMid(cubic, quadPts, &strokeMid)) {
1126 return false; 1248 return false;
1127 } 1249 }
1128 SkScalar dist = pt_to_line(strokeMid, quadPts->fQuad[0], quadPts->fQuad[2]); 1250 SkScalar dist = pt_to_line(strokeMid, quadPts->fQuad[0], quadPts->fQuad[2]);
1129 return dist < fError * fError; 1251 return dist < fInvResScaleSquared;
1130 } 1252 }
1131 1253
1132 bool SkPathStroker::cubicStroke(const SkPoint cubic[4], SkQuadConstruct* quadPts ) { 1254 bool SkPathStroker::cubicStroke(const SkPoint cubic[4], SkQuadConstruct* quadPts ) {
1133 if (!fFoundTangents) { 1255 if (!fFoundTangents) {
1134 ResultType resultType = this->tangentsMeet(cubic, quadPts); 1256 ResultType resultType = this->tangentsMeet(cubic, quadPts);
1135 if (kQuad_ResultType != resultType) { 1257 if (kQuad_ResultType != resultType) {
1136 if (kNormalError_ResultType == resultType) { 1258 if (kNormalError_ResultType == resultType) {
1137 return false; 1259 return false;
1138 } 1260 }
1139 if ((kDegenerate_ResultType == resultType 1261 if ((kDegenerate_ResultType == resultType
1140 || points_within_dist(quadPts->fQuad[0], quadPts->fQuad[2], fError)) 1262 || points_within_dist(quadPts->fQuad[0], quadPts->fQuad[2],
1141 && cubicMidOnLine(cubic, quadPts)) { 1263 fInvResScaleSquared)) && cubicMidOnLine(cubic, quadPts)) {
1142 addDegenerateLine(quadPts); 1264 addDegenerateLine(quadPts);
1143 return true; 1265 return true;
1144 } 1266 }
1145 } else { 1267 } else {
1146 fFoundTangents = true; 1268 fFoundTangents = true;
1147 } 1269 }
1148 } 1270 }
1149 if (fFoundTangents) { 1271 if (fFoundTangents) {
1150 ResultType resultType = this->compareQuadCubic(cubic, quadPts); 1272 ResultType resultType = this->compareQuadCubic(cubic, quadPts);
1151 if (kQuad_ResultType == resultType) { 1273 if (kQuad_ResultType == resultType) {
(...skipping 30 matching lines...) Expand all
1182 addDegenerateLine(quadPts); 1304 addDegenerateLine(quadPts);
1183 return true; 1305 return true;
1184 } 1306 }
1185 if (!this->cubicStroke(cubic, &half)) { 1307 if (!this->cubicStroke(cubic, &half)) {
1186 return false; 1308 return false;
1187 } 1309 }
1188 --fRecursionDepth; 1310 --fRecursionDepth;
1189 return true; 1311 return true;
1190 } 1312 }
1191 1313
1314 bool SkPathStroker::conicStroke(const SkConic& conic, SkQuadConstruct* quadPts) {
1315 ResultType resultType = this->compareQuadConic(conic, quadPts);
1316 if (kQuad_ResultType == resultType) {
1317 const SkPoint* stroke = quadPts->fQuad;
1318 SkPath* path = fStrokeType == kOuter_StrokeType ? &fOuter : &fInner;
1319 path->quadTo(stroke[1].fX, stroke[1].fY, stroke[2].fX, stroke[2].fY);
1320 return true;
1321 }
1322 if (kDegenerate_ResultType == resultType) {
1323 addDegenerateLine(quadPts);
1324 return true;
1325 }
1326 SkDEBUGCODE(gMaxRecursion[kConic_RecursiveLimit] = SkTMax(gMaxRecursion[kCon ic_RecursiveLimit],
1327 fRecursionDepth + 1));
1328 if (++fRecursionDepth > kRecursiveLimits[kConic_RecursiveLimit]) {
1329 return false; // just abort if projected quad isn't representable
1330 }
1331 SkQuadConstruct half;
1332 (void) half.initWithStart(quadPts);
1333 if (!this->conicStroke(conic, &half)) {
1334 return false;
1335 }
1336 (void) half.initWithEnd(quadPts);
1337 if (!this->conicStroke(conic, &half)) {
1338 return false;
1339 }
1340 --fRecursionDepth;
1341 return true;
1342 }
1343
1192 bool SkPathStroker::quadStroke(const SkPoint quad[3], SkQuadConstruct* quadPts) { 1344 bool SkPathStroker::quadStroke(const SkPoint quad[3], SkQuadConstruct* quadPts) {
1193 ResultType resultType = this->compareQuadQuad(quad, quadPts); 1345 ResultType resultType = this->compareQuadQuad(quad, quadPts);
1194 if (kQuad_ResultType == resultType) { 1346 if (kQuad_ResultType == resultType) {
1195 const SkPoint* stroke = quadPts->fQuad; 1347 const SkPoint* stroke = quadPts->fQuad;
1196 SkPath* path = fStrokeType == kOuter_StrokeType ? &fOuter : &fInner; 1348 SkPath* path = fStrokeType == kOuter_StrokeType ? &fOuter : &fInner;
1197 path->quadTo(stroke[1].fX, stroke[1].fY, stroke[2].fX, stroke[2].fY); 1349 path->quadTo(stroke[1].fX, stroke[1].fY, stroke[2].fX, stroke[2].fY);
1198 return true; 1350 return true;
1199 } 1351 }
1200 if (kDegenerate_ResultType == resultType) { 1352 if (kDegenerate_ResultType == resultType) {
1201 addDegenerateLine(quadPts); 1353 addDegenerateLine(quadPts);
(...skipping 14 matching lines...) Expand all
1216 return false; 1368 return false;
1217 } 1369 }
1218 --fRecursionDepth; 1370 --fRecursionDepth;
1219 return true; 1371 return true;
1220 } 1372 }
1221 1373
1222 #endif 1374 #endif
1223 1375
1224 void SkPathStroker::cubicTo(const SkPoint& pt1, const SkPoint& pt2, 1376 void SkPathStroker::cubicTo(const SkPoint& pt1, const SkPoint& pt2,
1225 const SkPoint& pt3) { 1377 const SkPoint& pt3) {
1226 #if QUAD_STROKE_APPROXIMATION 1378 #ifdef SK_QUAD_STROKE_APPROXIMATION
1227 const SkPoint cubic[4] = { fPrevPt, pt1, pt2, pt3 }; 1379 const SkPoint cubic[4] = { fPrevPt, pt1, pt2, pt3 };
1228 SkPoint reduction[3]; 1380 SkPoint reduction[3];
1229 const SkPoint* tangentPt; 1381 const SkPoint* tangentPt;
1230 ReductionType reductionType = CheckCubicLinear(cubic, reduction, &tangentPt) ; 1382 ReductionType reductionType = CheckCubicLinear(cubic, reduction, &tangentPt) ;
1231 if (kPoint_ReductionType == reductionType) { 1383 if (kPoint_ReductionType == reductionType) {
1232 return; 1384 return;
1233 } 1385 }
1234 if (kLine_ReductionType == reductionType) { 1386 if (kLine_ReductionType == reductionType) {
1235 this->lineTo(pt3); 1387 this->lineTo(pt3);
1236 return; 1388 return;
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
1342 } 1494 }
1343 1495
1344 SkStroke::SkStroke(const SkPaint& p, SkScalar width) { 1496 SkStroke::SkStroke(const SkPaint& p, SkScalar width) {
1345 fWidth = width; 1497 fWidth = width;
1346 fMiterLimit = p.getStrokeMiter(); 1498 fMiterLimit = p.getStrokeMiter();
1347 fCap = (uint8_t)p.getStrokeCap(); 1499 fCap = (uint8_t)p.getStrokeCap();
1348 fJoin = (uint8_t)p.getStrokeJoin(); 1500 fJoin = (uint8_t)p.getStrokeJoin();
1349 fDoFill = SkToU8(p.getStyle() == SkPaint::kStrokeAndFill_Style); 1501 fDoFill = SkToU8(p.getStyle() == SkPaint::kStrokeAndFill_Style);
1350 } 1502 }
1351 1503
1352 #if QUAD_STROKE_APPROXIMATION
1353 void SkStroke::setError(SkScalar error) {
1354 SkASSERT(error > 0);
1355 fError = error;
1356 }
1357 #endif
1358
1359 void SkStroke::setWidth(SkScalar width) { 1504 void SkStroke::setWidth(SkScalar width) {
1360 SkASSERT(width >= 0); 1505 SkASSERT(width >= 0);
1361 fWidth = width; 1506 fWidth = width;
1362 } 1507 }
1363 1508
1364 void SkStroke::setMiterLimit(SkScalar miterLimit) { 1509 void SkStroke::setMiterLimit(SkScalar miterLimit) {
1365 SkASSERT(miterLimit >= 0); 1510 SkASSERT(miterLimit >= 0);
1366 fMiterLimit = miterLimit; 1511 fMiterLimit = miterLimit;
1367 } 1512 }
1368 1513
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
1425 // our answer should preserve the inverseness of the src 1570 // our answer should preserve the inverseness of the src
1426 if (src.isInverseFillType()) { 1571 if (src.isInverseFillType()) {
1427 SkASSERT(!dst->isInverseFillType()); 1572 SkASSERT(!dst->isInverseFillType());
1428 dst->toggleInverseFillType(); 1573 dst->toggleInverseFillType();
1429 } 1574 }
1430 return; 1575 return;
1431 } 1576 }
1432 } 1577 }
1433 1578
1434 SkAutoConicToQuads converter; 1579 SkAutoConicToQuads converter;
1580 #ifndef SK_QUAD_STROKE_APPROXIMATION
1435 const SkScalar conicTol = SK_Scalar1 / 4 / fResScale; 1581 const SkScalar conicTol = SK_Scalar1 / 4 / fResScale;
1436 1582 #endif
1437 #if QUAD_STROKE_APPROXIMATION
1438 SkPathStroker stroker(src, radius, fMiterLimit, fError, this->getCap(),
1439 this->getJoin(), fResScale);
1440 #else
1441 SkPathStroker stroker(src, radius, fMiterLimit, this->getCap(), this->getJ oin(), fResScale); 1583 SkPathStroker stroker(src, radius, fMiterLimit, this->getCap(), this->getJ oin(), fResScale);
1442 #endif
1443 SkPath::Iter iter(src, false); 1584 SkPath::Iter iter(src, false);
1444 SkPath::Verb lastSegment = SkPath::kMove_Verb; 1585 SkPath::Verb lastSegment = SkPath::kMove_Verb;
1445 1586
1446 for (;;) { 1587 for (;;) {
1447 SkPoint pts[4]; 1588 SkPoint pts[4];
1448 switch (iter.next(pts, false)) { 1589 switch (iter.next(pts, false)) {
1449 case SkPath::kMove_Verb: 1590 case SkPath::kMove_Verb:
1450 stroker.moveTo(pts[0]); 1591 stroker.moveTo(pts[0]);
1451 break; 1592 break;
1452 case SkPath::kLine_Verb: 1593 case SkPath::kLine_Verb:
1453 stroker.lineTo(pts[1]); 1594 stroker.lineTo(pts[1]);
1454 lastSegment = SkPath::kLine_Verb; 1595 lastSegment = SkPath::kLine_Verb;
1455 break; 1596 break;
1456 case SkPath::kQuad_Verb: 1597 case SkPath::kQuad_Verb:
1457 stroker.quadTo(pts[1], pts[2]); 1598 stroker.quadTo(pts[1], pts[2]);
1458 lastSegment = SkPath::kQuad_Verb; 1599 lastSegment = SkPath::kQuad_Verb;
1459 break; 1600 break;
1460 case SkPath::kConic_Verb: { 1601 case SkPath::kConic_Verb: {
1602 #ifdef SK_QUAD_STROKE_APPROXIMATION
1603 stroker.conicTo(pts[1], pts[2], iter.conicWeight());
1604 lastSegment = SkPath::kConic_Verb;
1605 break;
1606 #else
1461 // todo: if we had maxcurvature for conics, perhaps we should 1607 // todo: if we had maxcurvature for conics, perhaps we should
1462 // natively extrude the conic instead of converting to quads. 1608 // natively extrude the conic instead of converting to quads.
1463 const SkPoint* quadPts = 1609 const SkPoint* quadPts =
1464 converter.computeQuads(pts, iter.conicWeight(), conicTol); 1610 converter.computeQuads(pts, iter.conicWeight(), conicTol);
1465 for (int i = 0; i < converter.countQuads(); ++i) { 1611 for (int i = 0; i < converter.countQuads(); ++i) {
1466 stroker.quadTo(quadPts[1], quadPts[2]); 1612 stroker.quadTo(quadPts[1], quadPts[2]);
1467 quadPts += 2; 1613 quadPts += 2;
1468 } 1614 }
1469 lastSegment = SkPath::kQuad_Verb; 1615 lastSegment = SkPath::kQuad_Verb;
1616 #endif
1470 } break; 1617 } break;
1471 case SkPath::kCubic_Verb: 1618 case SkPath::kCubic_Verb:
1472 stroker.cubicTo(pts[1], pts[2], pts[3]); 1619 stroker.cubicTo(pts[1], pts[2], pts[3]);
1473 lastSegment = SkPath::kCubic_Verb; 1620 lastSegment = SkPath::kCubic_Verb;
1474 break; 1621 break;
1475 case SkPath::kClose_Verb: 1622 case SkPath::kClose_Verb:
1476 stroker.close(lastSegment == SkPath::kLine_Verb); 1623 stroker.close(lastSegment == SkPath::kLine_Verb);
1477 break; 1624 break;
1478 case SkPath::kDone_Verb: 1625 case SkPath::kDone_Verb:
1479 goto DONE; 1626 goto DONE;
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
1589 default: 1736 default:
1590 break; 1737 break;
1591 } 1738 }
1592 1739
1593 if (fWidth < SkMinScalar(rw, rh) && !fDoFill) { 1740 if (fWidth < SkMinScalar(rw, rh) && !fDoFill) {
1594 r = rect; 1741 r = rect;
1595 r.inset(radius, radius); 1742 r.inset(radius, radius);
1596 dst->addRect(r, reverse_direction(dir)); 1743 dst->addRect(r, reverse_direction(dir));
1597 } 1744 }
1598 } 1745 }
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