only call scalar finite when necessary

Mike points that the the ulps compares
rank high in path ops profiles. The
check for finite scalars is rarely
required.

Call it less by:
- specializing _pin version of compares
- checking for 0 divides up front
- handling failing cases before comparing
- casting float to double before adding

R=reed@google.com

Review URL: https://codereview.chromium.org/1522183002
diff --git a/src/pathops/SkDLineIntersection.cpp b/src/pathops/SkDLineIntersection.cpp
index 6fbac97..71e2a06 100644
--- a/src/pathops/SkDLineIntersection.cpp
+++ b/src/pathops/SkDLineIntersection.cpp
@@ -108,7 +108,7 @@
     double ayBxLen = ayLen * bxLen;
     // detect parallel lines the same way here and in SkOpAngle operator <
     // so that non-parallel means they are also sortable
-    bool unparallel = fAllowNear ? NotAlmostEqualUlps(axByLen, ayBxLen)
+    bool unparallel = fAllowNear ? NotAlmostEqualUlps_Pin(axByLen, ayBxLen)
             : NotAlmostDequalUlps(axByLen, ayBxLen);
     if (unparallel && fUsed == 0) {
         double ab0y = a[0].fY - b[0].fY;
diff --git a/src/pathops/SkOpSegment.cpp b/src/pathops/SkOpSegment.cpp
index d066794..67f172e 100644
--- a/src/pathops/SkOpSegment.cpp
+++ b/src/pathops/SkOpSegment.cpp
@@ -1683,7 +1683,8 @@
         coincident = false;
         SkIntersections i;
         SkVector dxdy = (*CurveSlopeAtT[fVerb])(this->pts(), this->weight(), midT);
-        SkDLine ray = {{{midPt.fX, midPt.fY}, {midPt.fX + dxdy.fY, midPt.fY - dxdy.fX}}};
+        SkDLine ray = {{{midPt.fX, midPt.fY},
+                {(double) midPt.fX + dxdy.fY, (double) midPt.fY - dxdy.fX}}};
         (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(), ray, &i);
         // measure distance and see if it's small enough to denote coincidence
         for (int index = 0; index < i.used(); ++index) {
diff --git a/src/pathops/SkPathOpsLine.cpp b/src/pathops/SkPathOpsLine.cpp
index cad54eb..6fa091d 100644
--- a/src/pathops/SkPathOpsLine.cpp
+++ b/src/pathops/SkPathOpsLine.cpp
@@ -41,6 +41,9 @@
     if (!between(0, numer, denom)) {
         return -1;
     }
+    if (!denom) {
+        return 0;
+    }
     double t = numer / denom;
     SkDPoint realPt = ptAtT(t);
     double dist = realPt.distance(xy);   // OPTIMIZATION: can we compare against distSq instead ?
@@ -48,7 +51,7 @@
     double tiniest = SkTMin(SkTMin(SkTMin(fPts[0].fX, fPts[0].fY), fPts[1].fX), fPts[1].fY);
     double largest = SkTMax(SkTMax(SkTMax(fPts[0].fX, fPts[0].fY), fPts[1].fX), fPts[1].fY);
     largest = SkTMax(largest, -tiniest);
-    if (!AlmostEqualUlps(largest, largest + dist)) { // is the dist within ULPS tolerance?
+    if (!AlmostEqualUlps_Pin(largest, largest + dist)) { // is the dist within ULPS tolerance?
         return -1;
     }
     if (unequal) {
diff --git a/src/pathops/SkPathOpsQuad.cpp b/src/pathops/SkPathOpsQuad.cpp
index 12b9658..3deab21 100644
--- a/src/pathops/SkPathOpsQuad.cpp
+++ b/src/pathops/SkPathOpsQuad.cpp
@@ -119,7 +119,8 @@
 int SkDQuad::RootsReal(const double A, const double B, const double C, double s[2]) {
     const double p = B / (2 * A);
     const double q = C / A;
-    if (approximately_zero(A) && (approximately_zero_inverse(p) || approximately_zero_inverse(q))) {
+    if (!A || (approximately_zero(A) && (approximately_zero_inverse(p)
+            || approximately_zero_inverse(q)))) {
         if (approximately_zero(B)) {
             s[0] = 0;
             return C == 0;
diff --git a/src/pathops/SkPathOpsTSect.h b/src/pathops/SkPathOpsTSect.h
index bebdf40..074fe37 100644
--- a/src/pathops/SkPathOpsTSect.h
+++ b/src/pathops/SkPathOpsTSect.h
@@ -1467,11 +1467,17 @@
         workT += tStep;
         workPt = fCurve.ptAtT(workT);
         coinW.setPerp(fCurve, workT, workPt, opp->fCurve);
+        if (coinW.perpT() < 0) {
+            continue;
+        }
         SkDVector perpW = workPt - coinW.perpPt();
         if ((perpS.dot(perpW) >= 0) == (tStep < 0)) {
             tStep = -tStep;
         }
-    } while (!workPt.approximatelyEqual(coinW.perpPt()));
+        if (workPt.approximatelyEqual(coinW.perpPt())) {
+            break;
+        }
+    } while (true);
     double oppTTest = coinW.perpT();
     if (!opp->fHead->contains(oppTTest)) {
         return 0;
diff --git a/src/pathops/SkPathOpsTypes.cpp b/src/pathops/SkPathOpsTypes.cpp
index ca84405..1ed484a 100644
--- a/src/pathops/SkPathOpsTypes.cpp
+++ b/src/pathops/SkPathOpsTypes.cpp
@@ -16,6 +16,16 @@
 // from http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
 // FIXME: move to SkFloatBits.h
 static bool equal_ulps(float a, float b, int epsilon, int depsilon) {
+    if (arguments_denormalized(a, b, depsilon)) {
+        return true;
+    }
+    int aBits = SkFloatAs2sCompliment(a);
+    int bBits = SkFloatAs2sCompliment(b);
+    // Find the difference in ULPs.
+    return aBits < bBits + epsilon && bBits < aBits + epsilon;
+}
+
+static bool equal_ulps_pin(float a, float b, int epsilon, int depsilon) {
     if (!SkScalarIsFinite(a) || !SkScalarIsFinite(b)) {
         return false;
     }
@@ -29,9 +39,6 @@
 }
 
 static bool d_equal_ulps(float a, float b, int epsilon) {
-    if (!SkScalarIsFinite(a) || !SkScalarIsFinite(b)) {
-        return false;
-    }
     int aBits = SkFloatAs2sCompliment(a);
     int bBits = SkFloatAs2sCompliment(b);
     // Find the difference in ULPs.
@@ -39,6 +46,16 @@
 }
 
 static bool not_equal_ulps(float a, float b, int epsilon) {
+    if (arguments_denormalized(a, b, epsilon)) {
+        return false;
+    }
+    int aBits = SkFloatAs2sCompliment(a);
+    int bBits = SkFloatAs2sCompliment(b);
+    // Find the difference in ULPs.
+    return aBits >= bBits + epsilon || bBits >= aBits + epsilon;
+}
+
+static bool not_equal_ulps_pin(float a, float b, int epsilon) {
     if (!SkScalarIsFinite(a) || !SkScalarIsFinite(b)) {
         return false;
     }
@@ -52,9 +69,6 @@
 }
 
 static bool d_not_equal_ulps(float a, float b, int epsilon) {
-    if (!SkScalarIsFinite(a) || !SkScalarIsFinite(b)) {
-        return false;
-    }
     int aBits = SkFloatAs2sCompliment(a);
     int bBits = SkFloatAs2sCompliment(b);
     // Find the difference in ULPs.
@@ -62,9 +76,6 @@
 }
 
 static bool less_ulps(float a, float b, int epsilon) {
-    if (!SkScalarIsFinite(a) || !SkScalarIsFinite(b)) {
-        return false;
-    }
     if (arguments_denormalized(a, b, epsilon)) {
         return a <= b - FLT_EPSILON * epsilon;
     }
@@ -75,9 +86,6 @@
 }
 
 static bool less_or_equal_ulps(float a, float b, int epsilon) {
-    if (!SkScalarIsFinite(a) || !SkScalarIsFinite(b)) {
-        return false;
-    }
     if (arguments_denormalized(a, b, epsilon)) {
         return a < b + FLT_EPSILON * epsilon;
     }
@@ -104,10 +112,7 @@
 }
 
 bool AlmostDequalUlps(double a, double b) {
-    if (SkScalarIsFinite(a) || SkScalarIsFinite(b)) {
-        return AlmostDequalUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
-    }
-    return fabs(a - b) / SkTMax(fabs(a), fabs(b)) < FLT_EPSILON * 16;
+    return AlmostDequalUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
 }
 
 bool AlmostEqualUlps(float a, float b) {
@@ -115,11 +120,21 @@
     return equal_ulps(a, b, UlpsEpsilon, UlpsEpsilon);
 }
 
+bool AlmostEqualUlps_Pin(float a, float b) {
+    const int UlpsEpsilon = 16;
+    return equal_ulps_pin(a, b, UlpsEpsilon, UlpsEpsilon);
+}
+
 bool NotAlmostEqualUlps(float a, float b) {
     const int UlpsEpsilon = 16;
     return not_equal_ulps(a, b, UlpsEpsilon);
 }
 
+bool NotAlmostEqualUlps_Pin(float a, float b) {
+    const int UlpsEpsilon = 16;
+    return not_equal_ulps_pin(a, b, UlpsEpsilon);
+}
+
 bool NotAlmostDequalUlps(float a, float b) {
     const int UlpsEpsilon = 16;
     return d_not_equal_ulps(a, b, UlpsEpsilon);
@@ -148,9 +163,6 @@
 }
 
 int UlpsDistance(float a, float b) {
-    if (!SkScalarIsFinite(a) || !SkScalarIsFinite(b)) {
-        return SK_MaxS32;
-    }
     SkFloatIntUnion floatIntA, floatIntB;
     floatIntA.fFloat = a;
     floatIntB.fFloat = b;
diff --git a/src/pathops/SkPathOpsTypes.h b/src/pathops/SkPathOpsTypes.h
index f85c665..b35c97e 100644
--- a/src/pathops/SkPathOpsTypes.h
+++ b/src/pathops/SkPathOpsTypes.h
@@ -167,6 +167,11 @@
     return AlmostEqualUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
 }
 
+bool AlmostEqualUlps_Pin(float a, float b);
+inline bool AlmostEqualUlps_Pin(double a, double b) {
+    return AlmostEqualUlps_Pin(SkDoubleToScalar(a), SkDoubleToScalar(b));
+}
+
 // Use Almost Dequal when comparing should not special case denormalized values.
 bool AlmostDequalUlps(float a, float b);
 bool AlmostDequalUlps(double a, double b);
@@ -176,6 +181,11 @@
     return NotAlmostEqualUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
 }
 
+bool NotAlmostEqualUlps_Pin(float a, float b);
+inline bool NotAlmostEqualUlps_Pin(double a, double b) {
+    return NotAlmostEqualUlps_Pin(SkDoubleToScalar(a), SkDoubleToScalar(b));
+}
+
 bool NotAlmostDequalUlps(float a, float b);
 inline bool NotAlmostDequalUlps(double a, double b) {
     return NotAlmostDequalUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
diff --git a/src/pathops/SkReduceOrder.cpp b/src/pathops/SkReduceOrder.cpp
index 43a9190..52a19d6 100644
--- a/src/pathops/SkReduceOrder.cpp
+++ b/src/pathops/SkReduceOrder.cpp
@@ -126,7 +126,7 @@
     double sideAx = midX - cubic[3].fX;
     double sideBx = dx23 * 3 / 2;
     if (approximately_zero(sideAx) ? !approximately_equal(sideAx, sideBx)
-            : !AlmostEqualUlps(sideAx, sideBx)) {
+            : !AlmostEqualUlps_Pin(sideAx, sideBx)) {
         return 0;
     }
     double dy10 = cubic[1].fY - cubic[0].fY;
@@ -135,7 +135,7 @@
     double sideAy = midY - cubic[3].fY;
     double sideBy = dy23 * 3 / 2;
     if (approximately_zero(sideAy) ? !approximately_equal(sideAy, sideBy)
-            : !AlmostEqualUlps(sideAy, sideBy)) {
+            : !AlmostEqualUlps_Pin(sideAy, sideBy)) {
         return 0;
     }
     reduction[0] = cubic[0];