aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/core/SkFloatingPoint.h6
-rw-r--r--include/core/SkMath.h5
-rw-r--r--include/core/SkScalar.h4
-rw-r--r--src/core/SkPath.cpp24
4 files changed, 38 insertions, 1 deletions
diff --git a/include/core/SkFloatingPoint.h b/include/core/SkFloatingPoint.h
index e6856cf750..8c3bb835ca 100644
--- a/include/core/SkFloatingPoint.h
+++ b/include/core/SkFloatingPoint.h
@@ -31,6 +31,12 @@ static inline float sk_float_pow(float base, float exp) {
static_cast<double>(exp)));
}
+static inline float sk_float_copysign(float x, float y) {
+ int32_t xbits = SkFloat2Bits(x);
+ int32_t ybits = SkFloat2Bits(y);
+ return SkBits2Float((xbits & 0x7FFFFFFF) | (ybits & 0x80000000));
+}
+
#ifdef SK_BUILD_FOR_WINCE
#define sk_float_sqrt(x) (float)::sqrt(x)
#define sk_float_sin(x) (float)::sin(x)
diff --git a/include/core/SkMath.h b/include/core/SkMath.h
index 3f3c660bcb..e0f23617ee 100644
--- a/include/core/SkMath.h
+++ b/include/core/SkMath.h
@@ -64,6 +64,11 @@ static inline int32_t SkApplySign(int32_t n, int32_t sign) {
return (n ^ sign) - sign;
}
+/** Return x with the sign of y */
+static inline int32_t SkCopySign32(int32_t x, int32_t y) {
+ return SkApplySign(x, SkExtractSign(x ^ y));
+}
+
/** Returns (value < 0 ? 0 : value) efficiently (i.e. no compares or branches)
*/
static inline int SkClampPos(int value) {
diff --git a/include/core/SkScalar.h b/include/core/SkScalar.h
index 5be809f9e3..9130a7cf12 100644
--- a/include/core/SkScalar.h
+++ b/include/core/SkScalar.h
@@ -91,6 +91,9 @@
/** Returns the absolute value of the specified SkScalar
*/
#define SkScalarAbs(x) sk_float_abs(x)
+ /** Return x with the sign of y
+ */
+ #define SkScalarCopySign(x, y) sk_float_copysign(x, y)
/** Returns the value pinned between 0 and max inclusive
*/
inline SkScalar SkScalarClampMax(SkScalar x, SkScalar max) {
@@ -189,6 +192,7 @@
#define SkScalarCeil(x) SkFixedCeil(x)
#define SkScalarFloor(x) SkFixedFloor(x)
#define SkScalarAbs(x) SkFixedAbs(x)
+ #define SkScalarCopySign(x, y) SkCopySign32(x, y)
#define SkScalarClampMax(x, max) SkClampMax(x, max)
#define SkScalarPin(x, min, max) SkPin32(x, min, max)
#define SkScalarSquare(x) SkFixedSquare(x)
diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp
index 2308ec67ad..9c0b8afa98 100644
--- a/src/core/SkPath.cpp
+++ b/src/core/SkPath.cpp
@@ -587,7 +587,29 @@ static int build_arc_points(const SkRect& oval, SkScalar startAngle,
start.fY = SkScalarSinCos(SkDegreesToRadians(startAngle), &start.fX);
stop.fY = SkScalarSinCos(SkDegreesToRadians(startAngle + sweepAngle),
&stop.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
+ */
+ if (start == stop) {
+ SkScalar sw = SkScalarAbs(sweepAngle);
+ if (sw < SkIntToScalar(360) && sw > SkIntToScalar(359)) {
+ SkScalar stopRad = SkDegreesToRadians(startAngle + sweepAngle);
+ // make a guess at a tiny angle (in radians) to tweak by
+ SkScalar deltaRad = SkScalarCopySign(SK_Scalar1/512, sweepAngle);
+ // not sure how much will be enough, so we use a loop
+ do {
+ stopRad -= deltaRad;
+ stop.fY = SkScalarSinCos(stopRad, &stop.fX);
+ } while (start == stop);
+ }
+ }
+
SkMatrix matrix;
matrix.setScale(SkScalarHalf(oval.width()), SkScalarHalf(oval.height()));