OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2008 The Android Open Source Project | 2 * Copyright 2008 The Android Open Source Project |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkStrokerPriv.h" | 8 #include "SkStrokerPriv.h" |
9 #include "SkGeometry.h" | 9 #include "SkGeometry.h" |
10 #include "SkPathPriv.h" | 10 #include "SkPathPriv.h" |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
119 class SkPathStroker { | 119 class SkPathStroker { |
120 public: | 120 public: |
121 SkPathStroker(const SkPath& src, | 121 SkPathStroker(const SkPath& src, |
122 SkScalar radius, SkScalar miterLimit, SkPaint::Cap, | 122 SkScalar radius, SkScalar miterLimit, SkPaint::Cap, |
123 SkPaint::Join, SkScalar resScale); | 123 SkPaint::Join, SkScalar resScale); |
124 | 124 |
125 bool hasOnlyMoveTo() const { return 0 == fSegmentCount; } | 125 bool hasOnlyMoveTo() const { return 0 == fSegmentCount; } |
126 SkPoint moveToPt() const { return fFirstPt; } | 126 SkPoint moveToPt() const { return fFirstPt; } |
127 | 127 |
128 void moveTo(const SkPoint&); | 128 void moveTo(const SkPoint&); |
129 void lineTo(const SkPoint&); | 129 void lineTo(const SkPoint&, const SkPath::Iter* iter = nullptr); |
130 void quadTo(const SkPoint&, const SkPoint&); | 130 void quadTo(const SkPoint&, const SkPoint&); |
131 void conicTo(const SkPoint&, const SkPoint&, SkScalar weight); | 131 void conicTo(const SkPoint&, const SkPoint&, SkScalar weight); |
132 void cubicTo(const SkPoint&, const SkPoint&, const SkPoint&); | 132 void cubicTo(const SkPoint&, const SkPoint&, const SkPoint&); |
133 void close(bool isLine) { this->finishContour(true, isLine); } | 133 void close(bool isLine) { this->finishContour(true, isLine); } |
134 | 134 |
135 void done(SkPath* dst, bool isLine) { | 135 void done(SkPath* dst, bool isLine) { |
136 this->finishContour(false, isLine); | 136 this->finishContour(false, isLine); |
137 fOuter.addPath(fExtra); | 137 fOuter.addPath(fExtra); |
138 dst->swap(fOuter); | 138 dst->swap(fOuter); |
139 } | 139 } |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
180 kDegenerate3_ReductionType, // three areas of max curvature found (for c
ubic) | 180 kDegenerate3_ReductionType, // three areas of max curvature found (for c
ubic) |
181 }; | 181 }; |
182 | 182 |
183 enum IntersectRayType { | 183 enum IntersectRayType { |
184 kCtrlPt_RayType, | 184 kCtrlPt_RayType, |
185 kResultType_RayType, | 185 kResultType_RayType, |
186 }; | 186 }; |
187 | 187 |
188 int fRecursionDepth; // track stack depth to abort if numerics ru
n amok | 188 int fRecursionDepth; // track stack depth to abort if numerics ru
n amok |
189 bool fFoundTangents; // do less work until tangents meet (cubic) | 189 bool fFoundTangents; // do less work until tangents meet (cubic) |
| 190 bool fJoinCompleted; // previous join was not degenerate |
190 | 191 |
191 void addDegenerateLine(const SkQuadConstruct* ); | 192 void addDegenerateLine(const SkQuadConstruct* ); |
192 static ReductionType CheckConicLinear(const SkConic& , SkPoint* reduction); | 193 static ReductionType CheckConicLinear(const SkConic& , SkPoint* reduction); |
193 static ReductionType CheckCubicLinear(const SkPoint cubic[4], SkPoint reduct
ion[3], | 194 static ReductionType CheckCubicLinear(const SkPoint cubic[4], SkPoint reduct
ion[3], |
194 const SkPoint** tanPtPtr); | 195 const SkPoint** tanPtPtr); |
195 static ReductionType CheckQuadLinear(const SkPoint quad[3], SkPoint* reducti
on); | 196 static ReductionType CheckQuadLinear(const SkPoint quad[3], SkPoint* reducti
on); |
196 ResultType compareQuadConic(const SkConic& , SkQuadConstruct* ) const; | 197 ResultType compareQuadConic(const SkConic& , SkQuadConstruct* ) const; |
197 ResultType compareQuadCubic(const SkPoint cubic[4], SkQuadConstruct* ); | 198 ResultType compareQuadCubic(const SkPoint cubic[4], SkQuadConstruct* ); |
198 ResultType compareQuadQuad(const SkPoint quad[3], SkQuadConstruct* ); | 199 ResultType compareQuadQuad(const SkPoint quad[3], SkQuadConstruct* ); |
199 void conicPerpRay(const SkConic& , SkScalar t, SkPoint* tPt, SkPoint* onPt, | 200 void conicPerpRay(const SkConic& , SkScalar t, SkPoint* tPt, SkPoint* onPt, |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
266 } else { // we have a previous segment | 267 } else { // we have a previous segment |
267 fJoiner(&fOuter, &fInner, fPrevUnitNormal, fPrevPt, *unitNormal, | 268 fJoiner(&fOuter, &fInner, fPrevUnitNormal, fPrevPt, *unitNormal, |
268 fRadius, fInvMiterLimit, fPrevIsLine, currIsLine); | 269 fRadius, fInvMiterLimit, fPrevIsLine, currIsLine); |
269 } | 270 } |
270 fPrevIsLine = currIsLine; | 271 fPrevIsLine = currIsLine; |
271 return true; | 272 return true; |
272 } | 273 } |
273 | 274 |
274 void SkPathStroker::postJoinTo(const SkPoint& currPt, const SkVector& normal, | 275 void SkPathStroker::postJoinTo(const SkPoint& currPt, const SkVector& normal, |
275 const SkVector& unitNormal) { | 276 const SkVector& unitNormal) { |
| 277 fJoinCompleted = true; |
276 fPrevPt = currPt; | 278 fPrevPt = currPt; |
277 fPrevUnitNormal = unitNormal; | 279 fPrevUnitNormal = unitNormal; |
278 fPrevNormal = normal; | 280 fPrevNormal = normal; |
279 fSegmentCount += 1; | 281 fSegmentCount += 1; |
280 } | 282 } |
281 | 283 |
282 void SkPathStroker::finishContour(bool close, bool currIsLine) { | 284 void SkPathStroker::finishContour(bool close, bool currIsLine) { |
283 if (fSegmentCount > 0) { | 285 if (fSegmentCount > 0) { |
284 SkPoint pt; | 286 SkPoint pt; |
285 | 287 |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
352 fInvResScaleSquared = fInvResScale * fInvResScale; | 354 fInvResScaleSquared = fInvResScale * fInvResScale; |
353 fRecursionDepth = 0; | 355 fRecursionDepth = 0; |
354 } | 356 } |
355 | 357 |
356 void SkPathStroker::moveTo(const SkPoint& pt) { | 358 void SkPathStroker::moveTo(const SkPoint& pt) { |
357 if (fSegmentCount > 0) { | 359 if (fSegmentCount > 0) { |
358 this->finishContour(false, false); | 360 this->finishContour(false, false); |
359 } | 361 } |
360 fSegmentCount = 0; | 362 fSegmentCount = 0; |
361 fFirstPt = fPrevPt = pt; | 363 fFirstPt = fPrevPt = pt; |
| 364 fJoinCompleted = false; |
362 } | 365 } |
363 | 366 |
364 void SkPathStroker::line_to(const SkPoint& currPt, const SkVector& normal) { | 367 void SkPathStroker::line_to(const SkPoint& currPt, const SkVector& normal) { |
365 fOuter.lineTo(currPt.fX + normal.fX, currPt.fY + normal.fY); | 368 fOuter.lineTo(currPt.fX + normal.fX, currPt.fY + normal.fY); |
366 fInner.lineTo(currPt.fX - normal.fX, currPt.fY - normal.fY); | 369 fInner.lineTo(currPt.fX - normal.fX, currPt.fY - normal.fY); |
367 } | 370 } |
368 | 371 |
369 void SkPathStroker::lineTo(const SkPoint& currPt) { | 372 static bool has_valid_tangent(const SkPath::Iter* iter) { |
| 373 SkPath::Iter copy = *iter; |
| 374 SkPath::Verb verb; |
| 375 SkPoint pts[4]; |
| 376 while ((verb = copy.next(pts))) { |
| 377 switch (verb) { |
| 378 case SkPath::kMove_Verb: |
| 379 return false; |
| 380 case SkPath::kLine_Verb: |
| 381 if (pts[0] == pts[1]) { |
| 382 continue; |
| 383 } |
| 384 return true; |
| 385 case SkPath::kQuad_Verb: |
| 386 case SkPath::kConic_Verb: |
| 387 if (pts[0] == pts[1] && pts[0] == pts[2]) { |
| 388 continue; |
| 389 } |
| 390 return true; |
| 391 case SkPath::kCubic_Verb: |
| 392 if (pts[0] == pts[1] && pts[0] == pts[2] && pts[0] == pts[3]) { |
| 393 continue; |
| 394 } |
| 395 return true; |
| 396 case SkPath::kClose_Verb: |
| 397 case SkPath::kDone_Verb: |
| 398 return false; |
| 399 } |
| 400 } |
| 401 return false; |
| 402 } |
| 403 |
| 404 void SkPathStroker::lineTo(const SkPoint& currPt, const SkPath::Iter* iter) { |
370 if (SkStrokerPriv::CapFactory(SkPaint::kButt_Cap) == fCapper | 405 if (SkStrokerPriv::CapFactory(SkPaint::kButt_Cap) == fCapper |
371 && fPrevPt.equalsWithinTolerance(currPt, SK_ScalarNearlyZero * fInvR
esScale)) { | 406 && fPrevPt.equalsWithinTolerance(currPt, SK_ScalarNearlyZero * fInvR
esScale)) { |
372 return; | 407 return; |
373 } | 408 } |
| 409 if (fPrevPt == currPt && (fJoinCompleted || (iter && has_valid_tangent(iter)
))) { |
| 410 return; |
| 411 } |
374 SkVector normal, unitNormal; | 412 SkVector normal, unitNormal; |
375 | 413 |
376 if (!this->preJoinTo(currPt, &normal, &unitNormal, true)) { | 414 if (!this->preJoinTo(currPt, &normal, &unitNormal, true)) { |
377 return; | 415 return; |
378 } | 416 } |
379 this->line_to(currPt, normal); | 417 this->line_to(currPt, normal); |
380 this->postJoinTo(currPt, normal, unitNormal); | 418 this->postJoinTo(currPt, normal, unitNormal); |
381 } | 419 } |
382 | 420 |
383 void SkPathStroker::setQuadEndNormal(const SkPoint quad[3], const SkVector& norm
alAB, | 421 void SkPathStroker::setQuadEndNormal(const SkPoint quad[3], const SkVector& norm
alAB, |
(...skipping 948 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1332 SkPath::Iter iter(src, false); | 1370 SkPath::Iter iter(src, false); |
1333 SkPath::Verb lastSegment = SkPath::kMove_Verb; | 1371 SkPath::Verb lastSegment = SkPath::kMove_Verb; |
1334 | 1372 |
1335 for (;;) { | 1373 for (;;) { |
1336 SkPoint pts[4]; | 1374 SkPoint pts[4]; |
1337 switch (iter.next(pts, false)) { | 1375 switch (iter.next(pts, false)) { |
1338 case SkPath::kMove_Verb: | 1376 case SkPath::kMove_Verb: |
1339 stroker.moveTo(pts[0]); | 1377 stroker.moveTo(pts[0]); |
1340 break; | 1378 break; |
1341 case SkPath::kLine_Verb: | 1379 case SkPath::kLine_Verb: |
1342 stroker.lineTo(pts[1]); | 1380 stroker.lineTo(pts[1], &iter); |
1343 lastSegment = SkPath::kLine_Verb; | 1381 lastSegment = SkPath::kLine_Verb; |
1344 break; | 1382 break; |
1345 case SkPath::kQuad_Verb: | 1383 case SkPath::kQuad_Verb: |
1346 stroker.quadTo(pts[1], pts[2]); | 1384 stroker.quadTo(pts[1], pts[2]); |
1347 lastSegment = SkPath::kQuad_Verb; | 1385 lastSegment = SkPath::kQuad_Verb; |
1348 break; | 1386 break; |
1349 case SkPath::kConic_Verb: { | 1387 case SkPath::kConic_Verb: { |
1350 stroker.conicTo(pts[1], pts[2], iter.conicWeight()); | 1388 stroker.conicTo(pts[1], pts[2], iter.conicWeight()); |
1351 lastSegment = SkPath::kConic_Verb; | 1389 lastSegment = SkPath::kConic_Verb; |
1352 break; | 1390 break; |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1480 default: | 1518 default: |
1481 break; | 1519 break; |
1482 } | 1520 } |
1483 | 1521 |
1484 if (fWidth < SkMinScalar(rw, rh) && !fDoFill) { | 1522 if (fWidth < SkMinScalar(rw, rh) && !fDoFill) { |
1485 r = rect; | 1523 r = rect; |
1486 r.inset(radius, radius); | 1524 r.inset(radius, radius); |
1487 dst->addRect(r, reverse_direction(dir)); | 1525 dst->addRect(r, reverse_direction(dir)); |
1488 } | 1526 } |
1489 } | 1527 } |
OLD | NEW |