rename hasValidCoordinates to isFinite (on SkRect) and reimplement for speed



git-svn-id: http://skia.googlecode.com/svn/trunk@2811 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/bench/MathBench.cpp b/bench/MathBench.cpp
index 1644a9e..ffee901 100644
--- a/bench/MathBench.cpp
+++ b/bench/MathBench.cpp
@@ -3,6 +3,7 @@
 #include "SkMatrix.h"
 #include "SkRandom.h"
 #include "SkString.h"
+#include "SkPaint.h"
 
 class MathBench : public SkBenchmark {
     enum {
@@ -211,6 +212,21 @@
 
 #undef MAKEREC
 
+static bool SkScalarIsNaN_new(SkScalar x) {
+    float y = x * 0;
+    return y == y;
+}
+
+static bool isFinite(const SkRect& r) {
+    // x * 0 will be NaN iff x is infinity or NaN.
+    // a + b will be NaN iff either a or b is NaN.
+    float value = r.fLeft * 0 + r.fTop * 0 + r.fRight * 0 + r.fBottom * 0;
+    
+    // value is either NaN or it is finite (zero).
+    // value==value will be true iff value is not NaN
+    return value == value;
+}
+
 class IsFiniteBench : public SkBenchmark {
     enum {
         N = SkBENCHLOOP(1000),
@@ -225,20 +241,41 @@
         for (int i = 0; i < N; ++i) {
             fData[i] = rand.nextSScalar1();
         }
-        
-        fProc = gRec[index].fProc;
-        fName = gRec[index].fName;
+
+        if (index < 0) {
+            fProc = NULL;
+            fName = "isfinite_rect";
+        } else {
+            fProc = gRec[index].fProc;
+            fName = gRec[index].fName;
+        }
     }
 
 protected:
     virtual void onDraw(SkCanvas* canvas) {
         IsFiniteProc proc = fProc;
         const float* data = fData;
+        // do this so the compiler won't throw away the function call
+        int counter = 0;
 
-        for (int j = 0; j < NN; ++j) {
-            for (int i = 0; i < N - 4; ++i) {
-                proc(&data[i]);
+        if (proc) {
+            for (int j = 0; j < NN; ++j) {
+                for (int i = 0; i < N - 4; ++i) {
+                    counter += proc(&data[i]);
+                }
             }
+        } else {
+            for (int j = 0; j < NN; ++j) {
+                for (int i = 0; i < N - 4; ++i) {
+                    const SkRect* r = reinterpret_cast<const SkRect*>(&data[i]);
+                    counter += r->isFinite();
+                }
+            }
+        }
+        
+        SkPaint paint;
+        if (paint.getAlpha() == 0) {
+            SkDebugf("%d\n", counter);
         }
     }
 
@@ -261,6 +298,7 @@
 static SkBenchmark* M3(void* p) { return new QMul64Bench(p); }
 static SkBenchmark* M4(void* p) { return new QMul32Bench(p); }
 
+static SkBenchmark* M5neg1(void* p) { return new IsFiniteBench(p, -1); }
 static SkBenchmark* M50(void* p) { return new IsFiniteBench(p, 0); }
 static SkBenchmark* M51(void* p) { return new IsFiniteBench(p, 1); }
 static SkBenchmark* M52(void* p) { return new IsFiniteBench(p, 2); }
@@ -274,6 +312,7 @@
 static BenchRegistry gReg3(M3);
 static BenchRegistry gReg4(M4);
 
+static BenchRegistry gReg5neg1(M5neg1);
 static BenchRegistry gReg50(M50);
 static BenchRegistry gReg51(M51);
 static BenchRegistry gReg52(M52);
diff --git a/include/core/SkRect.h b/include/core/SkRect.h
index 76c99df..65e7611 100644
--- a/include/core/SkRect.h
+++ b/include/core/SkRect.h
@@ -335,10 +335,34 @@
         return r;
     }
 
-    /** Return true if the rectangle's width or height are <= 0
-    */
-    bool        isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
-    bool        hasValidCoordinates() const;
+    /**
+     *  Return true if the rectangle's width or height are <= 0
+     */
+    bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
+    
+    /**
+     *  Returns true iff all values in the rect are finite. If any are
+     *  infinite or NaN (or SK_FixedNaN when SkScalar is fixed) then this
+     *  returns false.
+     */
+    bool isFinite() const {
+#ifdef SK_SCALAR_IS_FLOAT
+        // x * 0 will be NaN iff x is infinity or NaN.
+        // a + b will be NaN iff either a or b is NaN.
+        float value = fLeft * 0 + fTop * 0 + fRight * 0 + fBottom * 0;
+        
+        // value is either NaN or it is finite (zero).
+        // value==value will be true iff value is not NaN
+        return value == value;
+#else
+        // use bit-or for speed, since we don't care about short-circuting the
+        // tests, and we expect the common case will be that we need to check all.
+        int isNaN = (SK_FixedNaN == fLeft)  | (SK_FixedNaN == fTop) |
+                    (SK_FixedNaN == fRight) | (SK_FixedNaN == fBottom);
+        return !isNaN;
+#endif
+    }
+
     SkScalar    left() const { return fLeft; }
     SkScalar    top() const { return fTop; }
     SkScalar    right() const { return fRight; }
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 70ee430..f382893 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -1068,7 +1068,7 @@
  */
 bool SkCanvas::quickReject(const SkRect& rect, EdgeType et) const {
 
-    if (!rect.hasValidCoordinates())
+    if (!rect.isFinite())
         return true;
 
     if (fMCRec->fRasterClip->isEmpty()) {
diff --git a/src/core/SkRect.cpp b/src/core/SkRect.cpp
index fab1412..5e3d93c 100644
--- a/src/core/SkRect.cpp
+++ b/src/core/SkRect.cpp
@@ -37,13 +37,6 @@
 
 /////////////////////////////////////////////////////////////////////////////
 
-bool SkRect::hasValidCoordinates() const {
-    return  SkScalarIsFinite(fLeft) &&
-            SkScalarIsFinite(fTop) &&
-            SkScalarIsFinite(fRight) &&
-            SkScalarIsFinite(fBottom);
-}
-
 void SkRect::sort() {
     if (fLeft > fRight) {
         SkTSwap<SkScalar>(fLeft, fRight);
diff --git a/tests/InfRectTest.cpp b/tests/InfRectTest.cpp
index a78eba6..12356d9 100644
--- a/tests/InfRectTest.cpp
+++ b/tests/InfRectTest.cpp
@@ -18,10 +18,10 @@
                           SkScalar l, SkScalar t, SkScalar r, SkScalar b) {
     SkRect rect;
     rect.set(l, t, r, b);
-    REPORTER_ASSERT(reporter, !rect.hasValidCoordinates());
+    REPORTER_ASSERT(reporter, !rect.isFinite());
 }
 
-// Tests that hasValidCoordinates() will reject any rect with +/-inf values
+// Tests that isFinite() will reject any rect with +/-inf values
 // as one of its coordinates.
 static void TestInfRect(skiatest::Reporter* reporter) {
 #ifdef SK_SCALAR_IS_FLOAT
@@ -33,7 +33,7 @@
     SkScalar big = SkIntToScalar(100);
 
     SkRect rect = SkRect::MakeXYWH(small, small, big, big);
-    REPORTER_ASSERT(reporter, rect.hasValidCoordinates());
+    REPORTER_ASSERT(reporter, rect.isFinite());
 
     check_invalid(reporter, small, small, big, invalid);
     check_invalid(reporter, small, small, invalid, big);