diff options
-rw-r--r-- | include/core/SkFloatingPoint.h | 6 | ||||
-rw-r--r-- | include/core/SkMath.h | 5 | ||||
-rw-r--r-- | include/core/SkScalar.h | 4 | ||||
-rw-r--r-- | src/core/SkPath.cpp | 24 |
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())); |