These tests stress pathops by describing the union of circle-like paths that have tiny line segments embedded and double back to create near-coincident conditions.

The fixes include
- detect when finding the active top loops between two possible answers
- preflight chasing winding to ensure answer is consistent
- binary search more often when quadratic intersection fails
- add more failure paths when an intersect is missed

While this fixes the chrome bug, reenabling path ops in svg should be deferred until additional fixes are landed.

TBR=
BUG=421132

Committed: https://skia.googlesource.com/skia/+/6f726addf3178b01949bb389ef83cf14a1d7b6b2

Review URL: https://codereview.chromium.org/633393002
diff --git a/tests/PathOpsExtendedTest.cpp b/tests/PathOpsExtendedTest.cpp
index d808ed7..73a2387 100644
--- a/tests/PathOpsExtendedTest.cpp
+++ b/tests/PathOpsExtendedTest.cpp
@@ -322,16 +322,23 @@
 SK_DECLARE_STATIC_MUTEX(compareDebugOut4);
 static int comparePaths(skiatest::Reporter* reporter, const char* testName, const SkPath& one,
         const SkPath& scaledOne, const SkPath& two, const SkPath& scaledTwo, SkBitmap& bitmap,
-        const SkPath& a, const SkPath& b, const SkPathOp shapeOp, const SkMatrix& scale) {
+        const SkPath& a, const SkPath& b, const SkPathOp shapeOp, const SkMatrix& scale,
+        bool expectSuccess) {
     int errors2x2;
+    const int MAX_ERRORS = 8;
     (void) pathsDrawTheSame(bitmap, scaledOne, scaledTwo, errors2x2);
+    if (!expectSuccess) {
+        if (errors2x2 <= MAX_ERRORS) {
+            REPORTER_ASSERT(reporter, 0);
+        }
+        return 0;
+    }
     if (errors2x2 == 0) {
         if (gShowPath) {
             showPathOpPath(testName, one, two, a, b, scaledOne, scaledTwo, shapeOp, scale);
         }
         return 0;
     }
-    const int MAX_ERRORS = 8;
     if (errors2x2 > MAX_ERRORS && gComparePathsAssert) {
         SkAutoMutexAcquire autoM(compareDebugOut3);
         SkDebugf("\n*** this test fails ***\n");
@@ -472,7 +479,7 @@
 #endif
 
 static bool innerPathOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
-                 const SkPathOp shapeOp, const char* testName, bool threaded) {
+        const SkPathOp shapeOp, const char* testName, bool threaded, bool expectSuccess) {
 #if DEBUG_SHOW_TEST_NAME
     showName(a, b, shapeOp);
 #endif
@@ -510,7 +517,7 @@
     scaledOut.addPath(out, scale);
     scaledOut.setFillType(out.getFillType());
     int result = comparePaths(reporter, testName, pathOut, scaledPathOut, out, scaledOut, bitmap,
-            a, b, shapeOp, scale);
+            a, b, shapeOp, scale, expectSuccess);
     if (result && gPathStrAssert) {
         REPORTER_ASSERT(reporter, 0);
     }
@@ -519,8 +526,13 @@
 }
 
 bool testPathOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
-                 const SkPathOp shapeOp, const char* testName) {
-    return innerPathOp(reporter, a, b, shapeOp, testName, false);
+        const SkPathOp shapeOp, const char* testName) {
+    return innerPathOp(reporter, a, b, shapeOp, testName, false, true);
+}
+
+bool testPathOpCheck(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
+        const SkPathOp shapeOp, const char* testName, bool checkFail) {
+    return innerPathOp(reporter, a, b, shapeOp, testName, false, checkFail);
 }
 
 bool testPathFailOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
@@ -539,7 +551,7 @@
 
 bool testThreadedPathOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
                  const SkPathOp shapeOp, const char* testName) {
-    return innerPathOp(reporter, a, b, shapeOp, testName, true);
+    return innerPathOp(reporter, a, b, shapeOp, testName, true, true);
 }
 
 SK_DECLARE_STATIC_MUTEX(gMutex);