add SkScalarIsFinite(), and use it for a more portable impl of SkRect::isValidCoords()



git-svn-id: http://skia.googlecode.com/svn/trunk@775 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/core/SkScalar.h b/include/core/SkScalar.h
index e1a8a33..09f24b5 100644
--- a/include/core/SkScalar.h
+++ b/include/core/SkScalar.h
@@ -60,6 +60,12 @@
     /** SkScalarIsNaN(n) returns true if argument is not a number
     */
     static inline bool SkScalarIsNaN(float x) { return x != x; }
+    /** Returns true if x is not NaN and not infinite */
+    static inline bool SkScalarIsFinite(float x) {
+        uint32_t bits = SkFloat2Bits(x);    // need unsigned for our shifts
+        int exponent = bits << 1 >> 24;
+        return exponent != 0xFF;
+    }
     /** SkIntToScalar(n) returns its integer argument as an SkScalar
     */
     #define SkIntToScalar(n)        ((float)(n))
@@ -177,6 +183,8 @@
     #define SK_ScalarMin            SK_FixedMin
     #define SK_ScalarNaN            SK_FixedNaN
     #define SkScalarIsNaN(x)        ((x) == SK_FixedNaN)
+    #define SkScalarIsFinite(x)     ((x) != SK_FixedNaN)
+
     #define SkIntToScalar(n)        SkIntToFixed(n)
     #define SkFixedToScalar(x)      (x)
     #define SkScalarToFixed(x)      (x)
diff --git a/src/core/SkRect.cpp b/src/core/SkRect.cpp
index b9e6f19..a358c3c 100644
--- a/src/core/SkRect.cpp
+++ b/src/core/SkRect.cpp
@@ -15,7 +15,6 @@
  */
 
 #include "SkRect.h"
-#include <limits>
 
 void SkIRect::join(int32_t left, int32_t top, int32_t right, int32_t bottom)
 {
@@ -45,17 +44,11 @@
 
 /////////////////////////////////////////////////////////////////////////////
 
-template <typename NumType> static inline bool isValidRange(const NumType& x)
-{
-    static const NumType max = std::numeric_limits<NumType>::max();
-    return x >= -max && x <= max;
-}
-
-
-bool SkRect::hasValidCoordinates() const
-{
-    return isValidRange<SkScalar>(fLeft) && isValidRange<SkScalar>(fRight) &&
-           isValidRange<SkScalar>(fTop) && isValidRange<SkScalar>(fBottom);
+bool SkRect::hasValidCoordinates() const {
+    return  SkScalarIsFinite(fLeft) &&
+            SkScalarIsFinite(fTop) &&
+            SkScalarIsFinite(fRight) &&
+            SkScalarIsFinite(fBottom);
 }
 
 void SkRect::sort()
@@ -85,14 +78,14 @@
     } else {
 #ifdef SK_SCALAR_SLOW_COMPARES
         int32_t    l, t, r, b;
-        
+
         l = r = SkScalarAs2sCompliment(pts[0].fX);
         t = b = SkScalarAs2sCompliment(pts[0].fY);
-        
+
         for (int i = 1; i < count; i++) {
             int32_t x = SkScalarAs2sCompliment(pts[i].fX);
             int32_t y = SkScalarAs2sCompliment(pts[i].fY);
-            
+
             if (x < l) l = x; else if (x > r) r = x;
             if (y < t) t = y; else if (y > b) b = y;
         }
@@ -143,7 +136,7 @@
     // do nothing if the params are empty
     if (left >= right || top >= bottom)
         return;
-    
+
     // if we are empty, just assign
     if (fLeft >= fRight || fTop >= fBottom)
         this->set(left, top, right, bottom);
diff --git a/tests/MathTest.cpp b/tests/MathTest.cpp
index 2555d73..9aed9f9 100644
--- a/tests/MathTest.cpp
+++ b/tests/MathTest.cpp
@@ -146,6 +146,40 @@
     }
 }
 
+static float make_zero() {
+    return sk_float_sin(0);
+}
+
+static void unittest_isfinite(skiatest::Reporter* reporter) {
+#ifdef SK_SCALAR_IS_FLOAT
+    float nan = ::asin(2);
+    float inf = 1.0 / make_zero();
+    float big = 3.40282e+038;
+
+    REPORTER_ASSERT(reporter,  SkScalarIsNaN(nan));
+    REPORTER_ASSERT(reporter, !SkScalarIsNaN(inf));
+    REPORTER_ASSERT(reporter, !SkScalarIsNaN(big));
+    REPORTER_ASSERT(reporter, !SkScalarIsNaN(-big));
+    REPORTER_ASSERT(reporter, !SkScalarIsNaN(0));
+
+    REPORTER_ASSERT(reporter, !SkScalarIsFinite(nan));
+    REPORTER_ASSERT(reporter, !SkScalarIsFinite(inf));
+    REPORTER_ASSERT(reporter,  SkScalarIsFinite(big));
+    REPORTER_ASSERT(reporter,  SkScalarIsFinite(-big));
+    REPORTER_ASSERT(reporter,  SkScalarIsFinite(0));
+#else
+    REPORTER_ASSERT(reporter,  SkScalarIsNaN(0x80000000));
+    REPORTER_ASSERT(reporter, !SkScalarIsNaN(0x7FFFFFFF));
+    REPORTER_ASSERT(reporter, !SkScalarIsNaN(0x80000001));
+    REPORTER_ASSERT(reporter, !SkScalarIsNaN(0));
+
+    REPORTER_ASSERT(reporter, !SkScalarIsFinite(0x80000000));
+    REPORTER_ASSERT(reporter,  SkScalarIsFinite(0x7FFFFFFF));
+    REPORTER_ASSERT(reporter,  SkScalarIsFinite(0x80000001));
+    REPORTER_ASSERT(reporter,  SkScalarIsFinite(0));
+#endif
+}
+
 #endif
 
 static void test_muldiv255(skiatest::Reporter* reporter) {
@@ -309,6 +343,7 @@
 
 #ifdef SK_CAN_USE_FLOAT
     unittest_fastfloat(reporter);
+    unittest_isfinite(reporter);
 #endif
 
 #ifdef SkLONGLONG