When solving the cubic line intersection directly fails, use binary search as a fallback.

The cubic line intersection math empirically works 99.99% of the time (fails 3100 out of 1B random tests) but when it fails, an intersection may be missed altogether.

The binary search is may not find a solution if the cubic line failed to find any solutions at all, but so far that case hasn't arisen.

BUG=skia:2504
TBR=reed@google.com

Author: caryclark@google.com

Review URL: https://codereview.chromium.org/266063003

git-svn-id: http://skia.googlecode.com/svn/trunk@14614 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/tests/PathOpsCubicLineIntersectionTest.cpp b/tests/PathOpsCubicLineIntersectionTest.cpp
index 1a2e188..234a538 100644
--- a/tests/PathOpsCubicLineIntersectionTest.cpp
+++ b/tests/PathOpsCubicLineIntersectionTest.cpp
@@ -49,6 +49,13 @@
 }
 
 static lineCubic lineCubicTests[] = {
+    {{{{-634.60540771484375, -481.262939453125}, {266.2696533203125, -752.70867919921875},
+            {-751.8370361328125, -317.37921142578125}, {-969.7427978515625, 824.7255859375}}},
+            {{{-287.9506133720805678, -557.1376476615772617},
+            {-285.9506133720805678, -557.1376476615772617}}}},
+
+    {{{{36.7184372,0.888650894}, {36.7184372,0.888650894}, {35.1233864,0.554015458},
+            {34.5114098,-0.115255356}}}, {{{35.4531212,0}, {31.9375,0}}}},
 
     {{{{421, 378}, {421, 380.209137f}, {418.761414f, 382}, {416, 382}}},
             {{{320, 378}, {421, 378.000031f}}}},
@@ -83,6 +90,32 @@
 
 static const size_t lineCubicTests_count = SK_ARRAY_COUNT(lineCubicTests);
 
+static int doIntersect(SkIntersections& intersections, const SkDCubic& cubic, const SkDLine& line) {
+    int result;
+    bool flipped = false;
+    if (line[0].fX == line[1].fX) {
+        double top = line[0].fY;
+        double bottom = line[1].fY;
+        flipped = top > bottom;
+        if (flipped) {
+            SkTSwap<double>(top, bottom);
+        }
+        result = intersections.vertical(cubic, top, bottom, line[0].fX, flipped);
+    } else if (line[0].fY == line[1].fY) {
+        double left = line[0].fX;
+        double right = line[1].fX;
+        flipped = left > right;
+        if (flipped) {
+            SkTSwap<double>(left, right);
+        }
+        result = intersections.horizontal(cubic, left, right, line[0].fY, flipped);
+    } else {
+        intersections.intersect(cubic, line);
+        result = intersections.used();
+    }
+    return result;
+}
+
 static void testOne(skiatest::Reporter* reporter, int iIndex) {
     const SkDCubic& cubic = lineCubicTests[iIndex].cubic;
     SkASSERT(ValidCubic(cubic));
@@ -102,7 +135,7 @@
     }
     if (order1 == 4 && order2 == 2) {
         SkIntersections i;
-        int roots = i.intersect(cubic, line);
+        int roots = doIntersect(i, cubic, line);
         for (int pt = 0; pt < roots; ++pt) {
             double tt1 = i[0][pt];
             SkDPoint xy1 = cubic.ptAtT(tt1);