Index: src/core/SkPath.cpp |
diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp |
index 195424e7c0b79c9ba94a7aa1a5b415635f37e30c..4f5fffb7dd18ae966d9ab5c58c03b22e15979d11 100644 |
--- a/src/core/SkPath.cpp |
+++ b/src/core/SkPath.cpp |
@@ -915,23 +915,22 @@ static bool arc_is_lone_point(const SkRect& oval, SkScalar startAngle, SkScalar |
return false; |
} |
-static int build_arc_points(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, |
- SkPoint pts[kSkBuildQuadArcStorage]) { |
- SkVector start, stop; |
- |
- start.fY = SkScalarSinCos(SkDegreesToRadians(startAngle), &start.fX); |
- stop.fY = SkScalarSinCos(SkDegreesToRadians(startAngle + sweepAngle), |
- &stop.fX); |
+// Return the unit vectors pointing at the start/stop points for the given start/sweep angles |
+// |
+static void angles_to_unit_vectors(SkScalar startAngle, SkScalar sweepAngle, |
+ SkVector* startV, SkVector* stopV, SkRotationDirection* dir) { |
+ startV->fY = SkScalarSinCos(SkDegreesToRadians(startAngle), &startV->fX); |
+ stopV->fY = SkScalarSinCos(SkDegreesToRadians(startAngle + sweepAngle), &stopV->fX); |
/* If the sweep angle is nearly (but less than) 360, then due to precision |
- loss in radians-conversion and/or sin/cos, we may end up with coincident |
- vectors, which will fool SkBuildQuadArc into doing nothing (bad) instead |
- of drawing a nearly complete circle (good). |
- e.g. canvas.drawArc(0, 359.99, ...) |
- -vs- canvas.drawArc(0, 359.9, ...) |
- We try to detect this edge case, and tweak the stop vector |
+ loss in radians-conversion and/or sin/cos, we may end up with coincident |
+ vectors, which will fool SkBuildQuadArc into doing nothing (bad) instead |
+ of drawing a nearly complete circle (good). |
+ e.g. canvas.drawArc(0, 359.99, ...) |
+ -vs- canvas.drawArc(0, 359.9, ...) |
+ We try to detect this edge case, and tweak the stop vector |
*/ |
- if (start == stop) { |
+ if (*startV == *stopV) { |
SkScalar sw = SkScalarAbs(sweepAngle); |
if (sw < SkIntToScalar(360) && sw > SkIntToScalar(359)) { |
SkScalar stopRad = SkDegreesToRadians(startAngle + sweepAngle); |
@@ -940,21 +939,34 @@ static int build_arc_points(const SkRect& oval, SkScalar startAngle, SkScalar sw |
// not sure how much will be enough, so we use a loop |
do { |
stopRad -= deltaRad; |
- stop.fY = SkScalarSinCos(stopRad, &stop.fX); |
- } while (start == stop); |
+ stopV->fY = SkScalarSinCos(stopRad, &stopV->fX); |
+ } while (*startV == *stopV); |
} |
} |
+ *dir = sweepAngle > 0 ? kCW_SkRotationDirection : kCCW_SkRotationDirection; |
+} |
+ |
+#ifdef SK_SUPPORT_LEGACY_ARCTO_QUADS |
+static int build_arc_points(const SkRect& oval, const SkVector& start, const SkVector& stop, |
+ SkRotationDirection dir, SkPoint pts[kSkBuildQuadArcStorage]) { |
+ SkMatrix matrix; |
+ matrix.setScale(SkScalarHalf(oval.width()), SkScalarHalf(oval.height())); |
+ matrix.postTranslate(oval.centerX(), oval.centerY()); |
+ |
+ return SkBuildQuadArc(start, stop, dir, &matrix, pts); |
+} |
+#else |
+static int build_arc_conics(const SkRect& oval, const SkVector& start, const SkVector& stop, |
+ SkRotationDirection dir, SkConic conics[SkConic::kMaxConicsForArc]) { |
SkMatrix matrix; |
matrix.setScale(SkScalarHalf(oval.width()), SkScalarHalf(oval.height())); |
matrix.postTranslate(oval.centerX(), oval.centerY()); |
- return SkBuildQuadArc(start, stop, |
- sweepAngle > 0 ? kCW_SkRotationDirection : |
- kCCW_SkRotationDirection, |
- &matrix, pts); |
+ return SkConic::BuildUnitArc(start, stop, dir, &matrix, conics); |
} |
+#endif |
void SkPath::addRoundRect(const SkRect& rect, const SkScalar radii[], |
Direction dir) { |
@@ -1320,8 +1332,13 @@ void SkPath::arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, |
return; |
} |
+ SkVector startV, stopV; |
+ SkRotationDirection dir; |
+ angles_to_unit_vectors(startAngle, sweepAngle, &startV, &stopV, &dir); |
+ |
+#ifdef SK_SUPPORT_LEGACY_ARCTO_QUADS |
SkPoint pts[kSkBuildQuadArcStorage]; |
- int count = build_arc_points(oval, startAngle, sweepAngle, pts); |
+ int count = build_arc_points(oval, startV, stopV, dir, pts); |
SkASSERT((count & 1) == 1); |
this->incReserve(count); |
@@ -1329,6 +1346,18 @@ void SkPath::arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, |
for (int i = 1; i < count; i += 2) { |
this->quadTo(pts[i], pts[i+1]); |
} |
+#else |
+ SkConic conics[SkConic::kMaxConicsForArc]; |
+ int count = build_arc_conics(oval, startV, stopV, dir, conics); |
+ if (count) { |
+ this->incReserve(count * 2 + 1); |
+ const SkPoint& pt = conics[0].fPts[0]; |
+ forceMoveTo ? this->moveTo(pt) : this->lineTo(pt); |
+ for (int i = 0; i < count; ++i) { |
+ this->conicTo(conics[i].fPts[1], conics[i].fPts[2], conics[i].fW); |
+ } |
+ } |
+#endif |
} |
void SkPath::addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle) { |