aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/private/SkFixed.h36
-rw-r--r--tests/MathTest.cpp40
2 files changed, 67 insertions, 9 deletions
diff --git a/include/private/SkFixed.h b/include/private/SkFixed.h
index 56821d4d82..c90d5e9ffd 100644
--- a/include/private/SkFixed.h
+++ b/include/private/SkFixed.h
@@ -9,6 +9,8 @@
#define SkFixed_DEFINED
#include "SkScalar.h"
+#include "math.h"
+
#include "SkTypes.h"
/** \file SkFixed.h
@@ -29,15 +31,18 @@ typedef int32_t SkFixed;
#define SK_FixedRoot2Over2 (0xB505)
#define SkFixedToFloat(x) ((x) * 1.52587890625e-5f)
-#if 1
- #define SkFloatToFixed(x) ((SkFixed)((x) * SK_Fixed1))
-#else
- // pins over/under flows to max/min int32 (slower than just a cast)
- static inline SkFixed SkFloatToFixed(float x) {
- int64_t n = x * SK_Fixed1;
- return (SkFixed)n;
- }
-#endif
+#define SkFloatToFixed(x) ((SkFixed)((x) * SK_Fixed1))
+
+// Pins over/under flows to SK_FixedMax/SK_FixedMin (slower than just a cast).
+static inline SkFixed SkFloatPinToFixed(float x) {
+ x *= SK_Fixed1;
+ // Casting float to int outside the range of the target type (int32_t) is undefined behavior.
+ if (x >= SK_FixedMax) return SK_FixedMax;
+ if (x <= SK_FixedMin) return SK_FixedMin;
+ const SkFixed result = static_cast<SkFixed>(x);
+ SkASSERT(truncf(x) == static_cast<float>(result));
+ return result;
+}
#ifdef SK_DEBUG
static inline SkFixed SkFloatToFixed_Check(float x) {
@@ -53,6 +58,17 @@ typedef int32_t SkFixed;
#define SkFixedToDouble(x) ((x) * 1.52587890625e-5)
#define SkDoubleToFixed(x) ((SkFixed)((x) * SK_Fixed1))
+// Pins over/under flows to SK_FixedMax/SK_FixedMin (slower than just a cast).
+static inline SkFixed SkDoublePinToFixed(double x) {
+ x *= SK_Fixed1;
+ // Casting double to int outside the range of the target type (int32_t) is undefined behavior.
+ if (x >= SK_FixedMax) return SK_FixedMax;
+ if (x <= SK_FixedMin) return SK_FixedMin;
+ const SkFixed result = static_cast<SkFixed>(x);
+ SkASSERT(trunc(x) == static_cast<double>(result));
+ return result;
+}
+
/** Converts an integer to a SkFixed, asserting that the result does not overflow
a 32 bit signed integer
*/
@@ -147,11 +163,13 @@ inline SkFixed SkFixedMul_longlong(SkFixed a, SkFixed b) {
#define SkFixedToScalar(x) SkFixedToFloat(x)
#define SkScalarToFixed(x) SkFloatToFixed(x)
+#define SkScalarPinToFixed(x) SkFloatPinToFixed(x)
#else // SK_SCALAR_IS_DOUBLE
#define SkFixedToScalar(x) SkFixedToDouble(x)
#define SkScalarToFixed(x) SkDoubleToFixed(x)
+#define SkScalarPinToFixed(x) SkDoublePinToFixed(x)
#endif
diff --git a/tests/MathTest.cpp b/tests/MathTest.cpp
index 580cd941fa..9343277f8d 100644
--- a/tests/MathTest.cpp
+++ b/tests/MathTest.cpp
@@ -5,6 +5,8 @@
* found in the LICENSE file.
*/
+#include "float.h"
+
#include "SkColorPriv.h"
#include "SkEndian.h"
#include "SkFixed.h"
@@ -697,3 +699,41 @@ DEF_TEST(divmod_s32, r) {
DEF_TEST(divmod_s64, r) {
test_divmod<int64_t>(r);
}
+
+DEF_TEST(PinToFixed, reporter) {
+ // double
+ REPORTER_ASSERT(reporter, 0 == SkDoublePinToFixed(0.0));
+ REPORTER_ASSERT(reporter, 0x10000 == SkDoublePinToFixed(1.0));
+ REPORTER_ASSERT(reporter, 0x7FFFFFFE == SkDoublePinToFixed(32767.999984741));
+ REPORTER_ASSERT(reporter, 0x7FFFFFFF == SkDoublePinToFixed(32767.999984742));
+ REPORTER_ASSERT(reporter, 0x7FFFFFFF == SkDoublePinToFixed(32767.999999999));
+ REPORTER_ASSERT(reporter, 0x7FFFFFFF == SkDoublePinToFixed(32768.0));
+ REPORTER_ASSERT(reporter, 0x7FFFFFFF == SkDoublePinToFixed(5e10));
+ REPORTER_ASSERT(reporter, 0x7FFFFFFF == SkDoublePinToFixed(DBL_MAX));
+ REPORTER_ASSERT(reporter, -0x10000 == SkDoublePinToFixed(-1.0));
+ // SK_FixedMin is defined to be -SK_FixedMax.
+ REPORTER_ASSERT(reporter, -0x7FFFFFFE == SkDoublePinToFixed(-32767.999984741));
+ REPORTER_ASSERT(reporter, -0x7FFFFFFF == SkDoublePinToFixed(-32767.999984742));
+ REPORTER_ASSERT(reporter, -0x7FFFFFFF == SkDoublePinToFixed(-32767.999999999));
+ REPORTER_ASSERT(reporter, -0x7FFFFFFF == SkDoublePinToFixed(-32768.0));
+ REPORTER_ASSERT(reporter, -0x7FFFFFFF == SkDoublePinToFixed(-5e10));
+ REPORTER_ASSERT(reporter, -0x7FFFFFFF == SkDoublePinToFixed(-DBL_MAX));
+
+ // float
+ REPORTER_ASSERT(reporter, 0 == SkFloatPinToFixed(0.0f));
+ REPORTER_ASSERT(reporter, 0x10000 == SkFloatPinToFixed(1.0f));
+ // SkFixed has more precision than float near SK_FixedMax, so SkFloatPinToFixed will never
+ // produce output between 0x7FFFFF80 and 0x7FFFFFFF.
+ REPORTER_ASSERT(reporter, 0x7FFFFF80 == SkFloatPinToFixed(32767.9990f));
+ REPORTER_ASSERT(reporter, 0x7FFFFFFF == SkFloatPinToFixed(32767.9991f));
+ REPORTER_ASSERT(reporter, 0x7FFFFFFF == SkFloatPinToFixed(32768.0f));
+ REPORTER_ASSERT(reporter, 0x7FFFFFFF == SkFloatPinToFixed(5e10f));
+ REPORTER_ASSERT(reporter, 0x7FFFFFFF == SkFloatPinToFixed(FLT_MAX));
+ REPORTER_ASSERT(reporter, -0x10000 == SkFloatPinToFixed(-1.0f));
+ // SK_FixedMin is defined to be -SK_FixedMax.
+ REPORTER_ASSERT(reporter, -0x7FFFFF80 == SkFloatPinToFixed(-32767.9990f));
+ REPORTER_ASSERT(reporter, -0x7FFFFFFF == SkFloatPinToFixed(-32767.9991f));
+ REPORTER_ASSERT(reporter, -0x7FFFFFFF == SkFloatPinToFixed(-32768.0f));
+ REPORTER_ASSERT(reporter, -0x7FFFFFFF == SkFloatPinToFixed(-5e10f));
+ REPORTER_ASSERT(reporter, -0x7FFFFFFF == SkFloatPinToFixed(-FLT_MAX));
+}