Path ops formerly found the topmost unprocessed edge and determined its angle sort order to initialize the winding. This never worked correctly with cubics and was flaky with paths consisting mostly of vertical edges.

This replacement shoots axis-aligned rays through all intersecting edges to find the outermost one either horizontally or vertically. The resulting code is smaller and twice as fast.

To support this, most of the horizontal / vertical intersection code was rewritten and standardized, and old code supporting the top-directed winding was deleted.

Contours were pointed to by an SkTDArray. Instead, put them in a linked list, and designate the list head with its own class to ensure that methods that take lists of contours start at the top. This change removed a large percentage of memory allocations used by path ops.

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

Review URL: https://codereview.chromium.org/1111333002
diff --git a/tests/PathOpsAngleIdeas.cpp b/tests/PathOpsAngleIdeas.cpp
index d0b0858..79e09b9 100755
--- a/tests/PathOpsAngleIdeas.cpp
+++ b/tests/PathOpsAngleIdeas.cpp
@@ -418,8 +418,8 @@
         int testNo, SkChunkAlloc* allocator) {
     SkPoint shortQuads[2][3];
 
-    SkOpContour contour;
-    SkOpGlobalState state(NULL  SkDEBUGPARAMS(&contour));
+    SkOpContourHead contour;
+    SkOpGlobalState state(NULL, &contour);
     contour.init(&state, false, false);
     makeSegment(&contour, quad1, shortQuads[0], allocator);
     makeSegment(&contour, quad1, shortQuads[1], allocator);
diff --git a/tests/PathOpsAngleTest.cpp b/tests/PathOpsAngleTest.cpp
index 6fead61..9c70774 100644
--- a/tests/PathOpsAngleTest.cpp
+++ b/tests/PathOpsAngleTest.cpp
@@ -234,8 +234,8 @@
 
 DEF_TEST(PathOpsAngleCircle, reporter) {
     SkChunkAlloc allocator(4096);
-    SkOpContour contour;
-    SkOpGlobalState state(NULL  SkDEBUGPARAMS(&contour));
+    SkOpContourHead contour;
+    SkOpGlobalState state(NULL, &contour);
     contour.init(&state, false, false);
     for (int index = 0; index < circleDataSetSize; ++index) {
         CircleData& data = circleDataSet[index];
@@ -426,8 +426,8 @@
 
 DEF_TEST(PathOpsAngleAfter, reporter) {
     SkChunkAlloc allocator(4096);
-    SkOpContour contour;
-    SkOpGlobalState state(NULL  SkDEBUGPARAMS(&contour));
+    SkOpContourHead contour;
+    SkOpGlobalState state(NULL, &contour);
     contour.init(&state, false, false);
     for (int index = intersectDataSetsSize - 1; index >= 0; --index) {
         IntersectData* dataArray = intersectDataSets[index];
diff --git a/tests/PathOpsBattles.cpp b/tests/PathOpsBattles.cpp
index 40abe84..8f59f9f 100644
--- a/tests/PathOpsBattles.cpp
+++ b/tests/PathOpsBattles.cpp
@@ -4831,7 +4831,7 @@
 path.close();
 
     SkPath path2(path);
-    testPathOpCheck(reporter, path1, path2, (SkPathOp) 2, filename, FLAGS_runFail);
+    testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
 }
 // op end success 1
 
@@ -10681,7 +10681,7 @@
     testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
 }
 
-static void (*firstTest)(skiatest::Reporter* , const char* filename) = battleOp1394;
+static void (*firstTest)(skiatest::Reporter* , const char* filename) = battleOp121;
 static void (*stopTest)(skiatest::Reporter* , const char* filename) = 0;
 
 static struct TestDesc tests[] = {
diff --git a/tests/PathOpsBoundsTest.cpp b/tests/PathOpsBoundsTest.cpp
index 0c74b69..573a0ce 100644
--- a/tests/PathOpsBoundsTest.cpp
+++ b/tests/PathOpsBoundsTest.cpp
@@ -29,24 +29,6 @@
 
 static const size_t noSectTestsCount = SK_ARRAY_COUNT(noSectTests);
 
-static const SkRect reallyEmpty[] = {
-    {0, 0, 0, 0},
-    {1, 1, 1, 0},
-    {1, 1, 0, 1},
-    {1, 1, 0, 0},
-    {1, 2, 3, SK_ScalarNaN},
-};
-
-static const size_t emptyTestsCount = SK_ARRAY_COUNT(reallyEmpty);
-
-static const SkRect notReallyEmpty[] = {
-    {0, 0, 1, 0},
-    {0, 0, 0, 1},
-    {0, 0, 1, 1},
-};
-
-static const size_t notEmptyTestsCount = SK_ARRAY_COUNT(notReallyEmpty);
-
 DEF_TEST(PathOpsBounds, reporter) {
     for (size_t index = 0; index < sectTestsCount; ++index) {
         const SkPathOpsBounds& bounds1 = static_cast<const SkPathOpsBounds&>(sectTests[index][0]);
@@ -75,41 +57,18 @@
     ordinal.set(1, 2, 3, 4);
     bounds.add(ordinal);
     REPORTER_ASSERT(reporter, bounds == expected);
-    SkDPoint topLeft = {0, 0};
-    bounds.setPointBounds(topLeft);
+    bounds.setEmpty();
     SkDPoint botRight = {3, 4};
     bounds.add(botRight);
     REPORTER_ASSERT(reporter, bounds == expected);
-    for (size_t index = 0; index < emptyTestsCount; ++index) {
-        const SkPathOpsBounds& bounds = static_cast<const SkPathOpsBounds&>(reallyEmpty[index]);
-        // SkASSERT(ValidBounds(bounds));  // don't check because test may contain nan
-        bool empty = bounds.isReallyEmpty();
-        REPORTER_ASSERT(reporter, empty);
-    }
-    for (size_t index = 0; index < notEmptyTestsCount; ++index) {
-        const SkPathOpsBounds& bounds = static_cast<const SkPathOpsBounds&>(notReallyEmpty[index]);
-        SkASSERT(ValidBounds(bounds));
-        bool empty = bounds.isReallyEmpty();
-        REPORTER_ASSERT(reporter, !empty);
-    }
     const SkPoint curvePts[] = {{0, 0}, {1, 2}, {3, 4}, {5, 6}};
     SkDCurve curve;
-    curve.fLine.set(curvePts);
-    curve.setLineBounds(curvePts, 1, 0, 1, &bounds);
-    expected.set(0, 0, 1, 2);
-    REPORTER_ASSERT(reporter, bounds == expected);
-    (curve.*SetBounds[SkPath::kLine_Verb])(curvePts, 1, 0, 1, &bounds);
-    REPORTER_ASSERT(reporter, bounds == expected);
     curve.fQuad.set(curvePts);
     curve.setQuadBounds(curvePts, 1, 0, 1, &bounds);
     expected.set(0, 0, 3, 4);
     REPORTER_ASSERT(reporter, bounds == expected);
-    (curve.*SetBounds[SkPath::kQuad_Verb])(curvePts, 1, 0, 1, &bounds);
-    REPORTER_ASSERT(reporter, bounds == expected);
     curve.fCubic.set(curvePts);
     curve.setCubicBounds(curvePts, 1, 0, 1, &bounds);
     expected.set(0, 0, 5, 6);
     REPORTER_ASSERT(reporter, bounds == expected);
-    (curve.*SetBounds[SkPath::kCubic_Verb])(curvePts, 1, 0, 1, &bounds);
-    REPORTER_ASSERT(reporter, bounds == expected);
 }
diff --git a/tests/PathOpsCubicReduceOrderTest.cpp b/tests/PathOpsCubicReduceOrderTest.cpp
index dc779b8..6b5cd9b 100644
--- a/tests/PathOpsCubicReduceOrderTest.cpp
+++ b/tests/PathOpsCubicReduceOrderTest.cpp
@@ -172,7 +172,7 @@
     for (index = firstQuadraticPointTest; index < quadraticPoints_count; ++index) {
         const SkDQuad& quad = quadraticPoints[index];
         SkASSERT(ValidQuad(quad));
-        SkDCubic cubic = quad.toCubic();
+        SkDCubic cubic = quad.debugToCubic();
         order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
         if (order != 1) {
             SkDebugf("[%d] point quad order=%d\n", static_cast<int>(index), order);
@@ -182,7 +182,7 @@
     for (index = firstQuadraticLineTest; index < quadraticLines_count; ++index) {
         const SkDQuad& quad = quadraticLines[index];
         SkASSERT(ValidQuad(quad));
-        SkDCubic cubic = quad.toCubic();
+        SkDCubic cubic = quad.debugToCubic();
         order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
         if (order != 2) {
             SkDebugf("[%d] line quad order=%d\n", static_cast<int>(index), order);
@@ -192,7 +192,7 @@
     for (index = firstQuadraticModLineTest; index < quadraticModEpsilonLines_count; ++index) {
         const SkDQuad& quad = quadraticModEpsilonLines[index];
         SkASSERT(ValidQuad(quad));
-        SkDCubic cubic = quad.toCubic();
+        SkDCubic cubic = quad.debugToCubic();
         order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
         if (order != 3) {
             SkDebugf("[%d] line mod quad order=%d\n", static_cast<int>(index), order);
diff --git a/tests/PathOpsDCubicTest.cpp b/tests/PathOpsDCubicTest.cpp
index b5fe8f7..4b5e7b4 100644
--- a/tests/PathOpsDCubicTest.cpp
+++ b/tests/PathOpsDCubicTest.cpp
@@ -8,27 +8,6 @@
 #include "SkPathOpsCubic.h"
 #include "Test.h"
 
-static const SkDCubic tests[] = {
-    {{{2, 0}, {3, 1}, {2, 2}, {1, 1}}},
-    {{{3, 1}, {2, 2}, {1, 1}, {2, 0}}},
-    {{{3, 0}, {2, 1}, {3, 2}, {1, 1}}},
-};
-
-static const size_t tests_count = SK_ARRAY_COUNT(tests);
-
-DEF_TEST(PathOpsDCubic, reporter) {
-    for (size_t index = 0; index < tests_count; ++index) {
-        const SkDCubic& cubic = tests[index];
-        SkASSERT(ValidCubic(cubic));
-        bool skip;
-        bool result = cubic.clockwise(cubic, &skip);
-        if (!result) {
-            SkDebugf("%s [%d] expected clockwise\n", __FUNCTION__, index);
-            REPORTER_ASSERT(reporter, 0);
-        }
-    }
-}
-
 static const SkDCubic hullTests[] = {
 {{{2.6250000819563866, 2.3750000223517418}, {2.833333432674408, 2.3333333432674408}, {3.1111112236976624, 2.3333333134651184}, {3.4074075222015381, 2.3333332538604736}}},
 };
diff --git a/tests/PathOpsDVectorTest.cpp b/tests/PathOpsDVectorTest.cpp
index ab291b2..583a868 100644
--- a/tests/PathOpsDVectorTest.cpp
+++ b/tests/PathOpsDVectorTest.cpp
@@ -28,8 +28,6 @@
         SkASSERT(ValidVector(v2));
         v1 += v2;
         REPORTER_ASSERT(reporter, v1.fX == 0 && v1.fY == 0);
-        SkDPoint p = tests[index + 1] + v2;
-        REPORTER_ASSERT(reporter, p == tests[index]);
         v2 -= v2;
         REPORTER_ASSERT(reporter, v2.fX == 0 && v2.fY == 0);
         v1 = tests[index + 1] - tests[index];
diff --git a/tests/PathOpsDebug.cpp b/tests/PathOpsDebug.cpp
index d2e8bd0..95f06e5 100755
--- a/tests/PathOpsDebug.cpp
+++ b/tests/PathOpsDebug.cpp
@@ -298,60 +298,60 @@
     return span->debugSpan(id);
 }
 
-void SkPathOpsDebug::DumpContours(SkTDArray<SkOpContour* >* contours) {
-    int count = contours->count();
-    for (int index = 0; index < count; ++index) {
-        (*contours)[index]->dump();
-    }
+void SkOpContour::dumpContours() const {
+    SkOpContour* contour = this->globalState()->contourHead();
+    do {
+        contour->dump();
+    } while ((contour = contour->next()));
 }
 
-void SkPathOpsDebug::DumpContoursAll(SkTDArray<SkOpContour* >* contours) {
-    int count = contours->count();
-    for (int index = 0; index < count; ++index) {
-        (*contours)[index]->dumpAll();
-    }
+void SkOpContour::dumpContoursAll() const {
+    SkOpContour* contour = this->globalState()->contourHead();
+    do {
+        contour->dumpAll();
+    } while ((contour = contour->next()));
 }
 
-void SkPathOpsDebug::DumpContoursAngles(const SkTDArray<SkOpContour* >* contours) {
-    int count = contours->count();
-    for (int index = 0; index < count; ++index) {
-        (*contours)[index]->dumpAngles();
-    }
+void SkOpContour::dumpContoursAngles() const {
+    SkOpContour* contour = this->globalState()->contourHead();
+    do {
+        contour->dumpAngles();
+    } while ((contour = contour->next()));
 }
 
-void SkPathOpsDebug::DumpContoursPts(const SkTDArray<SkOpContour* >* contours) {
-    int count = contours->count();
-    for (int index = 0; index < count; ++index) {
-        (*contours)[index]->dumpPts();
-    }
+void SkOpContour::dumpContoursPts() const {
+    SkOpContour* contour = this->globalState()->contourHead();
+    do {
+        contour->dumpPts();
+    } while ((contour = contour->next()));
 }
 
-void SkPathOpsDebug::DumpContoursPt(const SkTDArray<SkOpContour* >* contours, int segmentID) {
-    int count = contours->count();
-    for (int index = 0; index < count; ++index) {
-        (*contours)[index]->dumpPt(segmentID);
-    }
+void SkOpContour::dumpContoursPt(int segmentID) const {
+    SkOpContour* contour = this->globalState()->contourHead();
+    do {
+        contour->dumpPt(segmentID);
+    } while ((contour = contour->next()));
 }
 
-void SkPathOpsDebug::DumpContoursSegment(const SkTDArray<SkOpContour* >* contours,
-        int segmentID) {
-    if (contours->count()) {
-        (*contours)[0]->dumpSegment(segmentID);
-    }
+void SkOpContour::dumpContoursSegment(int segmentID) const {
+    SkOpContour* contour = this->globalState()->contourHead();
+    do {
+        contour->dumpSegment(segmentID);
+    } while ((contour = contour->next()));
 }
 
-void SkPathOpsDebug::DumpContoursSpan(const SkTDArray<SkOpContour* >* contours,
-        int spanID) {
-    if (contours->count()) {
-        (*contours)[0]->dumpSpan(spanID);
-    }
+void SkOpContour::dumpContoursSpan(int spanID) const {
+    SkOpContour* contour = this->globalState()->contourHead();
+    do {
+        contour->dumpSpan(spanID);
+    } while ((contour = contour->next()));
 }
 
-void SkPathOpsDebug::DumpContoursSpans(const SkTDArray<SkOpContour* >* contours) {
-    int count = contours->count();
-    for (int index = 0; index < count; ++index) {
-        (*contours)[index]->dumpSpans();
-    }
+void SkOpContour::dumpContoursSpans() const {
+    SkOpContour* contour = this->globalState()->contourHead();
+    do {
+        contour->dumpSpans();
+    } while ((contour = contour->next()));
 }
 
 template <typename TCurve, typename OppCurve>
@@ -728,6 +728,11 @@
     return this->segment()->debugSegment(id);
 }
 
+int SkOpAngle::debugSign() const {
+    SkASSERT(fStart->t() != fEnd->t());
+    return fStart->t() < fEnd->t() ? -1 : 1;
+}
+
 const SkOpSpanBase* SkOpAngle::debugSpan(int id) const {
     return this->segment()->debugSpan(id);
 }
@@ -756,7 +761,7 @@
     SkDebugf(" sect=%d/%d ", fSectorStart, fSectorEnd);
     SkDebugf(" s=%1.9g [%d] e=%1.9g [%d]", fStart->t(), fStart->debugID(),
                 fEnd->t(), fEnd->debugID());
-    SkDebugf(" sgn=%d windVal=%d", this->sign(), mSpan.windValue());
+    SkDebugf(" sgn=%d windVal=%d", this->debugSign(), mSpan.windValue());
 
     SkDebugf(" windSum=");
     SkPathOpsDebug::WindingPrintf(mSpan.windSum());
@@ -774,9 +779,6 @@
     if (segment->operand()) {
         SkDebugf(" operand");
     }
-    if (fStop) {
-        SkDebugf(" stop");
-    }
 }
 
 void SkOpAngle::dumpTo(const SkOpSegment* segment, const SkOpAngle* to) const {
@@ -1061,7 +1063,7 @@
     } while ((span = span->next()->upCastable()));
 }
 
-void SkOpSegment::dumpPts() const {
+void SkOpSegment::dumpPtsInner() const {
     int last = SkPathOpsVerbToPoints(fVerb);
     SkDebugf("seg=%d {{", this->debugID());
     if (fVerb == SkPath::kConic_Verb) {
@@ -1077,6 +1079,10 @@
     if (fVerb == SkPath::kConic_Verb) {
         SkDebugf(", %1.9gf}", fWeight);
     }
+}
+
+void SkOpSegment::dumpPts() const {
+    dumpPtsInner();
     SkDebugf("\n");
 }
 
@@ -1115,32 +1121,32 @@
     }
 }
 
-void SkOpContour::dump() {
+void SkOpContour::dump() const {
     SkDebugf("contour=%d count=%d op=%d xor=%d\n", this->debugID(), fCount, fOperand, fXor);
     if (!fCount) {
         return;
     }
     const SkOpSegment* segment = &fHead;
-    SkDEBUGCODE(fIndent = 0);
-    indentDump();
+    SkDEBUGCODE(fDebugIndent = 0);
+    this->indentDump();
     do {
         segment->dump();
     } while ((segment = segment->next()));
-    outdentDump();
+    this->outdentDump();
 }
 
-void SkOpContour::dumpAll() {
+void SkOpContour::dumpAll() const {
     SkDebugf("contour=%d count=%d op=%d xor=%d\n", this->debugID(), fCount, fOperand, fXor);
     if (!fCount) {
         return;
     }
     const SkOpSegment* segment = &fHead;
-    SkDEBUGCODE(fIndent = 0);
-    indentDump();
+    SkDEBUGCODE(fDebugIndent = 0);
+    this->indentDump();
     do {
         segment->dumpAll();
     } while ((segment = segment->next()));
-    outdentDump();
+    this->outdentDump();
 }
 
 
@@ -1225,7 +1231,7 @@
 
 #ifdef SK_DEBUG
 const SkOpAngle* SkOpGlobalState::debugAngle(int id) const {
-    const SkOpContour* contour = fHead;
+    const SkOpContour* contour = fContourHead;
     do {
         const SkOpSegment* segment = contour->first();
         while (segment) {
@@ -1252,7 +1258,7 @@
 }
 
 SkOpContour* SkOpGlobalState::debugContour(int id) {
-    SkOpContour* contour = fHead;
+    SkOpContour* contour = fContourHead;
     do {
         if (contour->debugID() == id) {
             return contour;
@@ -1262,7 +1268,7 @@
 }
 
 const SkOpPtT* SkOpGlobalState::debugPtT(int id) const {
-    const SkOpContour* contour = fHead;
+    const SkOpContour* contour = fContourHead;
     do {
         const SkOpSegment* segment = contour->first();
         while (segment) {
@@ -1285,7 +1291,7 @@
 }
 
 const SkOpSegment* SkOpGlobalState::debugSegment(int id) const {
-    const SkOpContour* contour = fHead;
+    const SkOpContour* contour = fContourHead;
     do {
         const SkOpSegment* segment = contour->first();
         while (segment) {
@@ -1299,7 +1305,7 @@
 }
 
 const SkOpSpanBase* SkOpGlobalState::debugSpan(int id) const {
-    const SkOpContour* contour = fHead;
+    const SkOpContour* contour = fContourHead;
     do {
         const SkOpSegment* segment = contour->first();
         while (segment) {
@@ -1320,58 +1326,6 @@
 }
 #endif
 
-const SkOpAngle* DebugAngle(const SkTDArray<SkOpContour* >* contours, int id) {
-    return (*contours)[0]->debugAngle(id);
-}
-
-SkOpContour* DumpContour(const SkTDArray<SkOpContour* >* contours, int id) {
-    return (*contours)[0]->debugContour(id);
-}
-
-const SkOpPtT* DebugPtT(const SkTDArray<SkOpContour* >* contours, int id) {
-    return (*contours)[0]->debugPtT(id);
-}
-
-const SkOpSegment* DebugSegment(const SkTDArray<SkOpContour* >* contours, int id) {
-    return (*contours)[0]->debugSegment(id);
-}
-
-const SkOpSpanBase* DebugSpan(const SkTDArray<SkOpContour* >* contours, int id) {
-    return (*contours)[0]->debugSpan(id);
-}
-
-void Dump(SkTDArray<SkOpContour* >* contours) {
-    SkPathOpsDebug::DumpContours(contours);
-}
-
-void DumpAll(SkTDArray<SkOpContour* >* contours) {
-    SkPathOpsDebug::DumpContoursAll(contours);
-}
-
-void DumpAngles(const SkTDArray<SkOpContour* >* contours) {
-    SkPathOpsDebug::DumpContoursAngles(contours);
-}
-
-void DumpSegment(const SkTDArray<SkOpContour* >* contours, int segmentID) {
-    SkPathOpsDebug::DumpContoursSegment(contours, segmentID);
-}
-
-void DumpSpan(const SkTDArray<SkOpContour* >* contours, int spanID) {
-    SkPathOpsDebug::DumpContoursSpan(contours, spanID);
-}
-
-void DumpSpans(const SkTDArray<SkOpContour* >* contours) {
-    SkPathOpsDebug::DumpContoursSpans(contours);
-}
-
-void DumpPt(const SkTDArray<SkOpContour* >* contours, int segmentID) {
-    SkPathOpsDebug::DumpContoursPt(contours, segmentID);
-}
-
-void DumpPts(const SkTDArray<SkOpContour* >* contours) {
-    SkPathOpsDebug::DumpContoursPts(contours);
-}
-
 #if DEBUG_T_SECT_DUMP > 1
 int gDumpTSectNum;
 #endif
diff --git a/tests/PathOpsExtendedTest.cpp b/tests/PathOpsExtendedTest.cpp
index 9c57797..de5c647 100644
--- a/tests/PathOpsExtendedTest.cpp
+++ b/tests/PathOpsExtendedTest.cpp
@@ -326,7 +326,7 @@
 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,
-        bool expectSuccess) {
+        bool expectSuccess, bool flaky) {
     int errors2x2;
     const int MAX_ERRORS = 8;
     (void) pathsDrawTheSame(bitmap, scaledOne, scaledTwo, errors2x2);
@@ -339,6 +339,9 @@
     if (errors2x2 == 0) {
         return 0;
     }
+    if (flaky) {
+        return 0;
+    }
     if (errors2x2 > MAX_ERRORS) {
         SkAutoMutexAcquire autoM(compareDebugOut3);
         showPathOpPath(testName, one, two, a, b, scaledOne, scaledTwo, shapeOp, scale);
@@ -492,13 +495,16 @@
 }
 #endif
 
+bool OpDebug(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result, bool expectSuccess);
+
 static bool innerPathOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
-        const SkPathOp shapeOp, const char* testName, bool threaded, bool expectSuccess) {
+        const SkPathOp shapeOp, const char* testName, bool threaded, bool expectSuccess,
+        bool flaky) {
 #if 0 && DEBUG_SHOW_TEST_NAME
     showName(a, b, shapeOp);
 #endif
     SkPath out;
-    if (!Op(a, b, shapeOp, &out) ) {
+    if (!OpDebug(a, b, shapeOp, &out, expectSuccess)) {
         SkDebugf("%s did not expect failure\n", __FUNCTION__);
         REPORTER_ASSERT(reporter, 0);
         return false;
@@ -531,24 +537,29 @@
     scaledOut.addPath(out, scale);
     scaledOut.setFillType(out.getFillType());
     int result = comparePaths(reporter, testName, pathOut, scaledPathOut, out, scaledOut, bitmap,
-            a, b, shapeOp, scale, expectSuccess);
+            a, b, shapeOp, scale, expectSuccess, flaky);
     reporter->bumpTestCount();
     return result == 0;
 }
 
 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, true);
+    return innerPathOp(reporter, a, b, shapeOp, testName, false, true, false);
+}
+
+bool testPathOpFlaky(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
+        const SkPathOp shapeOp, const char* testName) {
+    return innerPathOp(reporter, a, b, shapeOp, testName, false, true, 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);
+    return innerPathOp(reporter, a, b, shapeOp, testName, false, checkFail, false);
 }
 
 bool testPathOpFailCheck(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
         const SkPathOp shapeOp, const char* testName) {
-    return innerPathOp(reporter, a, b, shapeOp, testName, false, false);
+    return innerPathOp(reporter, a, b, shapeOp, testName, false, false, false);
 }
 
 bool testPathFailOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
@@ -570,7 +581,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, true);
+    return innerPathOp(reporter, a, b, shapeOp, testName, true, true, false);
 }
 
 SK_DECLARE_STATIC_MUTEX(gMutex);
diff --git a/tests/PathOpsExtendedTest.h b/tests/PathOpsExtendedTest.h
index f81c42e..46ee03b 100644
--- a/tests/PathOpsExtendedTest.h
+++ b/tests/PathOpsExtendedTest.h
@@ -37,6 +37,8 @@
                             const SkPathOp , const char* testName, bool checkFail);
 extern bool testPathOpFailCheck(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
                                 const SkPathOp , const char* testName);
+extern bool testPathOpFlaky(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
+                            const SkPathOp , const char* testName);
 extern bool testPathFailOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
                            const SkPathOp , const char* testName);
 extern bool testThreadedPathOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
diff --git a/tests/PathOpsFuzz763Test.cpp b/tests/PathOpsFuzz763Test.cpp
index 51e4f94..f782941 100755
--- a/tests/PathOpsFuzz763Test.cpp
+++ b/tests/PathOpsFuzz763Test.cpp
@@ -454,7 +454,7 @@
 path.close();
 
     SkPath path2(path);
-    testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+    testPathOpCheck(reporter, path1, path2, (SkPathOp) 2, filename, FLAGS_runFail);
 }
 
 
@@ -932,7 +932,7 @@
 path.close();
 
     SkPath path2(path);
-    testPathOpCheck(reporter, path1, path2, (SkPathOp) 2, filename, FLAGS_runFail);
+    testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
 }
 
 static void fuzz763_24588(skiatest::Reporter* reporter, const char* filename) {
@@ -1528,7 +1528,7 @@
 path.close();
 
     SkPath path2(path);
-    testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+    testPathOpCheck(reporter, path1, path2, (SkPathOp) 2, filename, FLAGS_runFail);
 }
 
 static void fuzz763_34974(skiatest::Reporter* reporter, const char* filename) {
@@ -2198,7 +2198,7 @@
 path.close();
 
     SkPath path2(path);
-    testPathOpCheck(reporter, path1, path2, (SkPathOp) 2, filename, FLAGS_runFail);
+    testPathOpFlaky(reporter, path1, path2, (SkPathOp) 2, filename);
 }
 
 static void fuzz763_2674194(skiatest::Reporter* reporter, const char* filename) {
@@ -2391,11 +2391,11 @@
 path.close();
 
     SkPath path2(path);
-    testPathOpCheck(reporter, path1, path2, (SkPathOp) 2, filename, FLAGS_runFail);
+    testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
 }
 
 static void (*skipTest)(skiatest::Reporter* , const char* filename) = 0;
-static void (*firstTest)(skiatest::Reporter* , const char* filename) = fuzz763_2674194;
+static void (*firstTest)(skiatest::Reporter* , const char* filename) = 0;
 static void (*stopTest)(skiatest::Reporter* , const char* filename) = 0;
 
 static struct TestDesc tests[] = {
diff --git a/tests/PathOpsIssue3651.cpp b/tests/PathOpsIssue3651.cpp
index cb4c7e8..4e732a1 100644
--- a/tests/PathOpsIssue3651.cpp
+++ b/tests/PathOpsIssue3651.cpp
@@ -1094,7 +1094,7 @@
 static void issue3651_1(skiatest::Reporter* reporter, const char* filename) {
     SkPath path = path1();
     SkPath pathB = path2();
-    testPathOp(reporter, path, pathB, SkPathOp::kUnion_SkPathOp, filename);
+    testPathOpCheck(reporter, path, pathB, SkPathOp::kUnion_SkPathOp, filename, FLAGS_runFail);
 }
 
 static void issue3651_2(skiatest::Reporter* reporter, const char* filename) {
@@ -1281,7 +1281,7 @@
 path.lineTo(SkBits2Float(0x4340b333), SkBits2Float(0x43346666));  // 192.7f, 180.4f
 path.lineTo(SkBits2Float(0x433a8ccd), SkBits2Float(0x43346666));  // 186.55f, 180.4f
 path.close();
-    testPathOpCheck(reporter, pathA, path, SkPathOp::kUnion_SkPathOp, filename, FLAGS_runFail);
+    testPathOp(reporter, pathA, path, SkPathOp::kUnion_SkPathOp, filename);
 }
 
 static void issue3651_5(skiatest::Reporter* reporter, const char* filename) {
@@ -1344,7 +1344,7 @@
 path.lineTo(SkBits2Float(0x42ab999a), SkBits2Float(0x4380b333));  // 85.8f, 257.4f
 path.lineTo(SkBits2Float(0x411e6666), SkBits2Float(0x4380b333));  // 9.9f, 257.4f
 path.close();
-    testPathOpCheck(reporter, pathA, path, SkPathOp::kUnion_SkPathOp, filename, FLAGS_runFail);
+    testPathOp(reporter, pathA, path, SkPathOp::kUnion_SkPathOp, filename);
 }
 
 static void issue3651_6(skiatest::Reporter* reporter, const char* filename) {
diff --git a/tests/PathOpsOpTest.cpp b/tests/PathOpsOpTest.cpp
index f25ebc9..bab678b 100644
--- a/tests/PathOpsOpTest.cpp
+++ b/tests/PathOpsOpTest.cpp
@@ -7,7 +7,27 @@
 #include "PathOpsExtendedTest.h"
 #include "PathOpsTestCommon.h"
 
-#define TEST(name) { name, #name }
+class PathTest_Private {
+public:
+    PathTest_Private(SkPath* path)
+        : fPath(path) {}
+
+    void setPt(int index, SkScalar x, SkScalar y) {
+        fPath->setPt(index, x, y);
+    }
+
+    SkPath* fPath;
+};
+
+static void path_edit(const SkPoint& from, const SkPoint& to, SkPath* path) {
+    PathTest_Private testPath(path);
+    for (int index = 0; index < path->countPoints(); ++index) {
+        if (SkDPoint::ApproximatelyEqual(path->getPoint(index), from)) {
+            testPath.setPt(index, to.fX, to.fY);
+            return;
+        }
+    }
+}
 
 static void cubicOp1d(skiatest::Reporter* reporter, const char* filename) {
     SkPath path, pathB;
@@ -2455,7 +2475,7 @@
     pathB.cubicTo(145, 715.477173f, 149.477158f, 711, 155, 711);
     pathB.lineTo(317, 711);
     pathB.close();
-    testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+    testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
 }
 
 static void cubicOp92i(skiatest::Reporter* reporter, const char* filename) {
@@ -3639,7 +3659,7 @@
 
     const char strB[] = "M31.35 57.75L31.35 57.75C31.9 57.7514 32.45 57.7052 33 57.7587C33.55 57.8122 34.1 57.9986 34.65 58.0709C35.2 58.1431 35.75 58.1777 36.3 58.1921C36.85 58.2065 37.4 58.1857 37.95 58.1572C38.5 58.1288 39.05 58.0888 39.6 58.0214C40.15 57.954 40.7 57.7971 41.25 57.7528C41.8 57.7084 42.35 57.7038 42.9 57.7555C43.45 57.8072 44 57.9655 44.55 58.0627C45.1 58.16 45.65 58.2885 46.2 58.3389C46.75 58.3893 47.3 58.3629 47.85 58.3651C48.4 58.3673 48.95 58.356 49.5 58.3522C50.05 58.3484 50.6 58.3447 51.15 58.3421C51.7 58.3395 52.25 58.3399 52.8 58.3366C53.35 58.3333 53.9 58.3269 54.45 58.3224C55 58.318 55.55 58.3084 56.1 58.31C56.65 58.3116 57.2 58.322 57.75 58.332C58.3 58.342 58.85 58.3645 59.4 58.3701C59.95 58.3757 60.5 58.3662 61.05 58.3655C61.6 58.3648 62.15 58.376 62.7 58.366C63.25 58.3559 63.8 58.3269 64.35 58.305C64.9 58.2831 65.45 58.2468 66 58.2345C66.55 58.2222 67.1 58.2353 67.65 58.2313C68.2 58.2272 68.75 58.233 69.3 58.2104C69.85 58.1878 70.4 58.129 70.95 58.0956C71.5 58.0623 72.05 58.0332 72.6 58.0104C73.15 57.9877 73.7 57.955 74.25 57.9592C74.8 57.9635 75.35 57.9932 75.9 58.0359C76.45 58.0787 77 58.1756 77.55 58.2158C78.1 58.256 78.65 58.2837 79.2 58.2772C79.75 58.2707 80.3 58.21 80.85 58.1768C81.4 58.1437 81.95 58.104 82.5 58.0781C83.05 58.0522 83.6 58.0363 84.15 58.0213C84.7 58.0063 85.25 57.9989 85.8 57.9879C86.35 57.977 86.9 57.9589 87.45 57.9556C88 57.9523 88.55 57.9337 89.1 57.9682C89.65 58.0028 90.2 58.1874 90.75 58.163C91.3 58.1387 91.85 57.8912 92.4 57.8224C92.95 57.7535 93.5 57.7621 94.05 57.75C94.6 57.7379 95.15 57.75 95.7 57.75L95.7 57.75L31.35 57.75Z";
     SkParsePath::FromSVGString(strB, &pathB);
-    testPathOp(reporter, path, pathB, kUnion_SkPathOp, filename);
+    testPathOpCheck(reporter, path, pathB, kUnion_SkPathOp, filename, FLAGS_runFail);
 }
 
 static void cubicOp119(skiatest::Reporter* reporter, const char* filename) {
@@ -4030,29 +4050,6 @@
     testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
 }
 
-static void loop15(skiatest::Reporter* reporter, const char* filename) {
-    SkPath path, pathB;
-    path.moveTo(2,6);
-    path.cubicTo(1,2, 7.16666698f,6.66666698f, -4.66666651f,7.66666651f);
-    path.close();
-    pathB.moveTo(1,2);
-    pathB.cubicTo(7.16666698f,6.66666698f, -4.66666651f,7.66666651f, 2,6);
-    pathB.close();
-    testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
-}
-
-// lots of loopy interesections -- all points appear to be present -- needs more investigation
-static void loop16(skiatest::Reporter* reporter, const char* filename) {
-    SkPath path, pathB;
-    path.moveTo(1,5);
-    path.cubicTo(0,1, 7.33333302f,5.33333349f, -7,7);
-    path.close();
-    pathB.moveTo(0,1);
-    pathB.cubicTo(7.33333302f,5.33333349f, -7,7, 1,5);
-    pathB.close();
-    testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
-}
-
 static void cubicOp133(skiatest::Reporter* reporter, const char* filename) {
     SkPath path, pathB;
     path.setFillType(SkPath::kWinding_FillType);
@@ -4540,7 +4537,7 @@
     pathB.moveTo(0, 1);
     pathB.cubicTo(6.16666698f, 5.66666698f, -5.66666651f, 6.66666651f, 1, 5);
     pathB.close();
-    testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+    testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
 }
 
 static void loops24i(skiatest::Reporter* reporter, const char* filename) {
@@ -4579,7 +4576,7 @@
     pathB.moveTo(0, 2);
     pathB.cubicTo(6.16666698f, 6.66666698f, -5.66666651f, 7.66666651f, 1, 6);
     pathB.close();
-    testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+    testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
 }
 
 static void loops27i(skiatest::Reporter* reporter, const char* filename) {
@@ -4670,7 +4667,7 @@
     pathB.moveTo(1, 2);
     pathB.cubicTo(7.16666698f, 6.66666698f, -4.66666651f, 7.66666651f, 2, 6);
     pathB.close();
-    testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+    testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
 }
 
 static void loops33iMod(skiatest::Reporter* reporter, const char* filename) {
@@ -4696,8 +4693,7 @@
         pathB.moveTo(pts[4]);
         pathB.cubicTo(pts[5], pts[6], pts[7]);
         pathB.close();
-        bool result = testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, name.c_str(),
-            FLAGS_runFail);
+        bool result = testPathOp(reporter, path, pathB, kIntersect_SkPathOp, name.c_str());
         if (lastResult != result) {
             up = !up;
         }
@@ -4831,51 +4827,6 @@
     testPathOp(reporter, qPath, qPathB, kIntersect_SkPathOp, filename);
 }
 
-static void loops41i(skiatest::Reporter* reporter, const char* filename) {
-    SkPath path, pathB;
-    path.setFillType(SkPath::kWinding_FillType);
-    path.moveTo(1, 5);
-    path.cubicTo(0, 1, 6.16666698f, 5.66666698f, -5.66666651f, 6.66666651f);
-    path.close();
-    pathB.setFillType(SkPath::kWinding_FillType);
-    pathB.moveTo(0, 1);
-    pathB.cubicTo(6.16666698f, 5.66666698f, -5.66666651f, 6.66666651f, 1, 5);
-    pathB.close();
-    testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
-}
-
-/*
-FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346	0 */
-static void loops42i(skiatest::Reporter* reporter, const char* filename) {
-    SkPath path, pathB;
-    path.setFillType(SkPath::kWinding_FillType);
-    path.moveTo(1, 6);
-    path.cubicTo(0, 2, 6.16666698f, 6.66666698f, -5.66666651f, 7.66666651f);
-    path.close();
-    pathB.setFillType(SkPath::kWinding_FillType);
-    pathB.moveTo(0, 2);
-    pathB.cubicTo(6.16666698f, 6.66666698f, -5.66666651f, 7.66666651f, 1, 6);
-    pathB.close();
-    testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
-}
-
-/*
-FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346	0 */
-static void loops43i(skiatest::Reporter* reporter, const char* filename) {
-    SkPath path, pathB;
-    path.setFillType(SkPath::kWinding_FillType);
-    path.moveTo(2, 6);
-    path.cubicTo(1, 2, 7.16666698f, 6.66666698f, -4.66666651f, 7.66666651f);
-    path.close();
-    pathB.setFillType(SkPath::kWinding_FillType);
-    pathB.moveTo(1, 2);
-    pathB.cubicTo(7.16666698f, 6.66666698f, -4.66666651f, 7.66666651f, 2, 6);
-    pathB.close();
-    testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
-}
-
-/*
-FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346	0 */
 static void loops44i(skiatest::Reporter* reporter, const char* filename) {
     SkPath path, pathB;
     path.setFillType(SkPath::kWinding_FillType);
@@ -4886,11 +4837,9 @@
     pathB.moveTo(0, 1);
     pathB.cubicTo(7.33333302f, 5.33333349f, -7, 7, 1, 5);
     pathB.close();
-    testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+    testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
 }
 
-/*
-FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346	0 */
 static void loops45i(skiatest::Reporter* reporter, const char* filename) {
     SkPath path, pathB;
     path.setFillType(SkPath::kWinding_FillType);
@@ -4901,11 +4850,9 @@
     pathB.moveTo(0, 2);
     pathB.cubicTo(7.33333302f, 6.33333302f, -7, 8, 1, 6);
     pathB.close();
-    testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+    testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
 }
 
-/*
-FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346	0 */
 static void loops46i(skiatest::Reporter* reporter, const char* filename) {
     SkPath path, pathB;
     path.setFillType(SkPath::kWinding_FillType);
@@ -4916,7 +4863,7 @@
     pathB.moveTo(1, 2);
     pathB.cubicTo(8.33333302f, 6.33333302f, -6, 8, 2, 6);
     pathB.close();
-    testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+    testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
 }
 
 /*
@@ -4931,11 +4878,9 @@
     pathB.moveTo(0, 1);
     pathB.cubicTo(6, 5.83333302f, -4, 8, 2, 4);
     pathB.close();
-    testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+    testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
 }
 
-/*
-FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346	0 */
 static void loops48i(skiatest::Reporter* reporter, const char* filename) {
     SkPath path, pathB;
     path.setFillType(SkPath::kWinding_FillType);
@@ -4946,11 +4891,9 @@
     pathB.moveTo(0, 1);
     pathB.cubicTo(9.33333302f, 6.83333302f, -8.33333302f, 9.16666603f, 2, 6);
     pathB.close();
-    testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+    testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
 }
 
-/*
-FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346	0 */
 static void loops49i(skiatest::Reporter* reporter, const char* filename) {
     SkPath path, pathB;
     path.setFillType(SkPath::kWinding_FillType);
@@ -4961,11 +4904,9 @@
     pathB.moveTo(1, 4);
     pathB.cubicTo(-0.166666687f, 2.66666675f, 1.66666675f, 2, 0, 2);
     pathB.close();
-    testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+    testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
 }
 
-/*
-FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346	0 */
 static void loops50i(skiatest::Reporter* reporter, const char* filename) {
     SkPath path, pathB;
     path.setFillType(SkPath::kWinding_FillType);
@@ -4976,11 +4917,9 @@
     pathB.moveTo(1, 5);
     pathB.cubicTo(-0.166666687f, 3.66666675f, 1.66666675f, 3, 0, 3);
     pathB.close();
-    testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+    testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
 }
 
-/*
-FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346	0 */
 static void loops51i(skiatest::Reporter* reporter, const char* filename) {
     SkPath path, pathB;
     path.setFillType(SkPath::kWinding_FillType);
@@ -4991,11 +4930,9 @@
     pathB.moveTo(2, 4);
     pathB.cubicTo(0.833333313f, 2.66666675f, 2.66666675f, 2, 1, 2);
     pathB.close();
-    testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+    testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
 }
 
-/*
-FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346	0 */
 static void loops52i(skiatest::Reporter* reporter, const char* filename) {
     SkPath path, pathB;
     path.setFillType(SkPath::kWinding_FillType);
@@ -5006,11 +4943,9 @@
     pathB.moveTo(2, 5);
     pathB.cubicTo(0.833333313f, 3.66666675f, 2.66666675f, 3, 1, 3);
     pathB.close();
-    testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+    testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
 }
 
-/*
-FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346	0 */
 static void loops53i(skiatest::Reporter* reporter, const char* filename) {
     SkPath path, pathB;
     path.setFillType(SkPath::kWinding_FillType);
@@ -5021,11 +4956,9 @@
     pathB.moveTo(3, 5);
     pathB.cubicTo(1.83333325f, 3.66666675f, 3.66666651f, 3, 2, 3);
     pathB.close();
-    testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+    testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
 }
 
-/*
-FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346	0 */
 static void loops54i(skiatest::Reporter* reporter, const char* filename) {
     SkPath path, pathB;
     path.setFillType(SkPath::kWinding_FillType);
@@ -5036,11 +4969,9 @@
     pathB.moveTo(1, 4);
     pathB.cubicTo(0, 3, 1.66666675f, 2, 0, 2);
     pathB.close();
-    testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+    testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
 }
 
-/*
-FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346	0 */
 static void loops55i(skiatest::Reporter* reporter, const char* filename) {
     SkPath path, pathB;
     path.setFillType(SkPath::kWinding_FillType);
@@ -5051,11 +4982,9 @@
     pathB.moveTo(1, 5);
     pathB.cubicTo(0, 4, 1.66666675f, 3, 0, 3);
     pathB.close();
-    testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+    testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
 }
 
-/*
-FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346	0 */
 static void loops56i(skiatest::Reporter* reporter, const char* filename) {
     SkPath path, pathB;
     path.setFillType(SkPath::kWinding_FillType);
@@ -5066,11 +4995,9 @@
     pathB.moveTo(2, 4);
     pathB.cubicTo(0.99999994f, 3, 2.66666675f, 2, 1, 2);
     pathB.close();
-    testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+    testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
 }
 
-/*
-FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346	0 */
 static void loops57i(skiatest::Reporter* reporter, const char* filename) {
     SkPath path, pathB;
     path.setFillType(SkPath::kWinding_FillType);
@@ -5081,11 +5008,9 @@
     pathB.moveTo(2, 5);
     pathB.cubicTo(0.99999994f, 4, 2.66666675f, 3, 1, 3);
     pathB.close();
-    testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+    testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
 }
 
-/*
-FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346	0 */
 static void loops58i(skiatest::Reporter* reporter, const char* filename) {
     SkPath path, pathB;
     path.setFillType(SkPath::kWinding_FillType);
@@ -5096,11 +5021,28 @@
     pathB.moveTo(3, 5);
     pathB.cubicTo(2, 4, 3.66666651f, 3, 2, 3);
     pathB.close();
-    testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+    testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
 }
 
-/*
-FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346	0 */
+static void loops58iAsQuads(skiatest::Reporter* reporter, const char* filename) {
+    SkPath path, pathB;
+    path.setFillType(SkPath::kWinding_FillType);
+    path.moveTo(2, 3);
+    path.cubicTo(3, 5, 2, 4, 3.66666651f, 3);
+    path.close();
+    pathB.setFillType(SkPath::kWinding_FillType);
+    pathB.moveTo(3, 5);
+    pathB.cubicTo(2, 4, 3.66666651f, 3, 2, 3);
+    pathB.close();
+    SkPath qPath, qPathB;
+    CubicPathToQuads(path, &qPath);
+    CubicPathToQuads(pathB, &qPathB);
+//    SkPoint from = {2.61714339f,1.90228665f};
+//    SkPoint to = {2.617045833359139f,1.9013528935803314f};
+//    path_edit(from, to, &qPathB);
+    testPathOp(reporter, qPath, qPathB, kIntersect_SkPathOp, filename);
+}
+
 static void loops59i(skiatest::Reporter* reporter, const char* filename) {
     SkPath path, pathB;
     path.setFillType(SkPath::kWinding_FillType);
@@ -5114,28 +5056,6 @@
     testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
 }
 
-class PathTest_Private {
-public:
-    PathTest_Private(SkPath* path)
-        : fPath(path) {}
-
-    void setPt(int index, SkScalar x, SkScalar y) {
-        fPath->setPt(index, x, y);
-    }
-
-    SkPath* fPath;
-};
-
-static void path_edit(const SkPoint& from, const SkPoint& to, SkPath* path) {
-    PathTest_Private testPath(path);
-    for (int index = 0; index < path->countPoints(); ++index) {
-        if (SkDPoint::ApproximatelyEqual(path->getPoint(index), from)) {
-            testPath.setPt(index, to.fX, to.fY);
-            return;
-        }
-    }
-}
-
 static void loops59iasQuads(skiatest::Reporter* reporter, const char* filename) {
     SkPath path, pathB;
     path.setFillType(SkPath::kWinding_FillType);
@@ -5168,17 +5088,87 @@
     testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
 }
 
+void loops61i(skiatest::Reporter* reporter, const char* filename) {
+    SkPath path, pathB;
+    path.setFillType(SkPath::kWinding_FillType);
+    path.moveTo(0, 1);
+    path.cubicTo(1, 5, -6.33333302f, 0.666666627f, 8, -1);
+    path.close();
+    pathB.setFillType(SkPath::kWinding_FillType);
+    pathB.moveTo(1, 5);
+    pathB.cubicTo(-6.33333302f, 0.666666627f, 8, -1, 0, 1);
+    pathB.close();
+    testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+}
+
+static void loops62i(skiatest::Reporter* reporter, const char* filename) {
+    SkPath path, pathB;
+    path.setFillType(SkPath::kWinding_FillType);
+    path.moveTo(0, 2);
+    path.cubicTo(1, 6, -6.33333302f, 1.66666663f, 8, 0);
+    path.close();
+    pathB.setFillType(SkPath::kWinding_FillType);
+    pathB.moveTo(1, 6);
+    pathB.cubicTo(-6.33333302f, 1.66666663f, 8, 0, 0, 2);
+    pathB.close();
+    testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+}
+
+static void loops63i(skiatest::Reporter* reporter, const char* filename) {
+    SkPath path, pathB;
+    path.setFillType(SkPath::kWinding_FillType);
+    path.moveTo(0, 1);
+    path.cubicTo(2, 4, -4, -0.833333254f, 6, -3);
+    path.close();
+    pathB.setFillType(SkPath::kWinding_FillType);
+    pathB.moveTo(2, 4);
+    pathB.cubicTo(-4, -0.833333254f, 6, -3, 0, 1);
+    pathB.close();
+    testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+}
+
+static void cubics44d(skiatest::Reporter* reporter, const char* filename) {
+    SkPath path, pathB;
+    path.setFillType(SkPath::kWinding_FillType);
+    path.moveTo(3, 4);
+    path.cubicTo(2, 5, 3, 1, 6, 2);
+    path.close();
+    pathB.setFillType(SkPath::kWinding_FillType);
+    pathB.moveTo(1, 3);
+    pathB.cubicTo(2, 6, 4, 3, 5, 2);
+    pathB.close();
+    testPathOpCheck(reporter, path, pathB, kDifference_SkPathOp, filename, FLAGS_runFail);
+}
+
+static void cubics45u(skiatest::Reporter* reporter, const char* filename) {
+    SkPath path, pathB;
+    path.setFillType(SkPath::kWinding_FillType);
+    path.moveTo(1, 3);
+    path.cubicTo(2, 6, 4, 3, 5, 2);
+    path.close();
+    pathB.setFillType(SkPath::kWinding_FillType);
+    pathB.moveTo(3, 4);
+    pathB.cubicTo(2, 5, 3, 1, 6, 2);
+    pathB.close();
+    testPathOpCheck(reporter, path, pathB, kUnion_SkPathOp, filename, FLAGS_runFail);
+}
+
 static void (*skipTest)(skiatest::Reporter* , const char* filename) = 0;
-static void (*firstTest)(skiatest::Reporter* , const char* filename) = loops59i;
+static void (*firstTest)(skiatest::Reporter* , const char* filename) = 0;
 static void (*stopTest)(skiatest::Reporter* , const char* filename) = 0;
 
+#define TEST(name) { name, #name }
+
 static struct TestDesc tests[] = {
+    TEST(cubics44d),
+    TEST(cubics45u),
+    TEST(loops61i),
+    TEST(loops62i),
+    TEST(loops63i),
+    TEST(loops58iAsQuads),
     TEST(cubics41d),
     TEST(loops59iasQuads),
     TEST(loops59i),
-    TEST(loops41i),
-    TEST(loops42i),
-    TEST(loops43i),
     TEST(loops44i),
     TEST(loops45i),
     TEST(loops46i),
@@ -5254,8 +5244,6 @@
     TEST(cubicOp135),
     TEST(cubicOp134),
     TEST(cubicOp133),
-    TEST(loop16),
-    TEST(loop15),
     TEST(loop12),
     TEST(cubicOp132),
     TEST(loop11),
@@ -5509,58 +5497,16 @@
 static const size_t testCount = SK_ARRAY_COUNT(tests);
 
 static struct TestDesc subTests[] = {
-    TEST(loops40i),
-    TEST(loops39i),
-    TEST(loops38i),
-    TEST(loops37i),
-    TEST(loops36i),
-    TEST(loops35i),
-    TEST(loops34i),
-    TEST(loops33i),
-    TEST(loops32i),
-    TEST(loops31i),
-    TEST(loops30i),
-    TEST(loops29i),
-    TEST(loops28i),
-    TEST(loops27i),
-    TEST(loops26i),
-    TEST(loops25i),
-    TEST(loops24i),
-    TEST(loops23i),
-    TEST(loops22i),
-    TEST(loops21i),
-    TEST(loops20i),
-    TEST(cubics20d),
-    TEST(cubics6d),
-    TEST(cubics7d),
-    TEST(cubics8d),
-    TEST(cubics9d),
-    TEST(cubics10u),
-    TEST(cubics11i),
-    TEST(cubics12d),
-    TEST(cubics13d),
-    TEST(cubics14d),
-    TEST(cubics15d),
-    TEST(cubics16i),
-    TEST(cubics17d),
-    TEST(cubics18d),
-    TEST(cubics19d),
-    TEST(cubicOp157),
-    TEST(cubicOp142),
-    TEST(loops4i),
-    TEST(quadRect1),
-    TEST(quadRect2),
-    TEST(quadRect3),
-    TEST(quadRect4),
-    TEST(quadRect5),
-    TEST(quadRect6),
+    TEST(cubics45u),
+    TEST(loops61i),
+    TEST(loops62i),
 };
 
 static const size_t subTestCount = SK_ARRAY_COUNT(subTests);
 
 static void (*firstSubTest)(skiatest::Reporter* , const char* filename) = 0;
 
-static bool runSubTests = false;
+static bool runSubTests = true;
 static bool runSubTestsFirst = true;
 static bool runReverse = false;
 
@@ -5582,7 +5528,7 @@
     path.addRect(0,0, 300,170141183460469231731687303715884105728.f);
     SkPath pathB;
     pathB.addRect(0,0, 300,16);
-    testPathOp(reporter, path, pathB, kUnion_SkPathOp, filename);
+    testPathOpFailCheck(reporter, path, pathB, kUnion_SkPathOp, filename);
 }
 
 // m 100,0 60,170 -160,-110 200,0 -170,11000000000 z
@@ -5769,10 +5715,10 @@
 }
 
 static struct TestDesc failTests[] = {
+    TEST(fuzz487a),
     TEST(fuzz433),
     TEST(fuzz1),
     TEST(fuzz714),
-    TEST(fuzz487a),
     TEST(fuzz487b),
     TEST(fuzz433b),
     TEST(bufferOverflow),
diff --git a/tests/PathOpsQuadIntersectionTest.cpp b/tests/PathOpsQuadIntersectionTest.cpp
index 577d200..f012622 100644
--- a/tests/PathOpsQuadIntersectionTest.cpp
+++ b/tests/PathOpsQuadIntersectionTest.cpp
@@ -377,9 +377,9 @@
     SkASSERT(ValidQuad(quad2));
     SkIntersections intersections2;
     intersections2.intersect(quad1, quad2);
-    REPORTER_ASSERT(reporter, intersections2.coincidentUsed() >= 2);
+    REPORTER_ASSERT(reporter, intersections2.debugCoincidentUsed() >= 2);
     REPORTER_ASSERT(reporter, intersections2.used() >= 2);
-    for (int pt = 0; pt < intersections2.coincidentUsed(); pt += 2) {
+    for (int pt = 0; pt < intersections2.debugCoincidentUsed(); pt += 2) {
         double tt1 = intersections2[0][pt];
         double tt2 = intersections2[1][pt];
         SkDPoint pt1 = quad1.ptAtT(tt1);
@@ -394,70 +394,6 @@
     }
 }
 
-static int floatSign(double x) {
-    return x < 0 ? -1 : x > 0 ? 1 : 0;
-}
-
-static const SkDQuad pointFinderTestSet[] = {
-                                                                                                                                //>=0.633974464         0.633974846 <=
-{{{1.2071879545809394, 0.82163474041730045}, {1.1534203513372994, 0.52790870069930229},
-        {1.0880000000000001, 0.29599999999999982}}},  //t=0.63155333662549329, 0.80000000000000004
-{{{1.2071879545809394, 0.82163474041730045}, {1.2065040319428038, 0.81766753259119995},
-        {1.2058123269101506, 0.81370135061854221}}},  //t=0.63155333662549329, 0.6339049773632347
-{{{1.2058123269101506, 0.81370135061854221}, {1.152376363978022, 0.5244097415381026},
-        {1.0880000000000001, 0.29599999999999982}}},  //t=0.6339049773632347,  0.80000000000000004
-                                                                                                                                //>=0.633974083         0.633975227 <=
-{{{0.33333333333333326, 0.81481481481481488}, {0.63395173631977997, 0.68744136726313931},
-        {1.205684411948591, 0.81344322326274499}}},   //t=0.33333333333333331, 0.63395173631977986
-{{{0.33333333333333326, 0.81481481481481488}, {0.63396444791444551, 0.68743368362444768},
-        {1.205732763658403, 0.81345617746834109}}},   //t=0.33333333333333331, 0.63396444791444551
-{{{1.205684411948591, 0.81344322326274499}, {1.2057085875611198, 0.81344969999329253},
-        {1.205732763658403, 0.81345617746834109}}},   //t=0.63395173631977986, 0.63396444791444551
-{{{1.205732763658403, 0.81345617746834109}, {1.267928895828891, 0.83008534558465619},
-        {1.3333333333333333, 0.85185185185185175}}},  //t=0.63396444791444551, 0.66666666666666663
-};
-
-static void pointFinder(const SkDQuad& q1, const SkDQuad& q2) {
-    for (int index = 0; index < 3; ++index) {
-        double t = q1.nearestT(q2[index]);
-        SkDPoint onQuad = q1.ptAtT(t);
-        SkDebugf("%s t=%1.9g (%1.9g,%1.9g) dist=%1.9g\n", __FUNCTION__, t, onQuad.fX, onQuad.fY,
-                onQuad.distance(q2[index]));
-        double left[3];
-        left[0] = ((const SkDLine&) q1[0]).isLeft(q2[index]);
-        left[1] = ((const SkDLine&) q1[1]).isLeft(q2[index]);
-        SkDLine diag = {{q1[0], q1[2]}};
-        left[2] = diag.isLeft(q2[index]);
-        SkDebugf("%s left=(%d, %d, %d)\n", __FUNCTION__, floatSign(left[0]),
-                floatSign(left[1]), floatSign(left[2]));
-    }
-    SkDebugf("\n");
-}
-
-static void hullIntersect(const SkDQuad& q1, const SkDQuad& q2) {
-    SkDebugf("%s", __FUNCTION__);
-    SkIntersections ts;
-    for (int i1 = 0; i1 < 3; ++i1) {
-        SkDLine l1 = {{q1[i1], q1[(i1 + 1) % 3]}};
-        for (int i2 = 0; i2 < 3; ++i2) {
-            SkDLine l2 = {{q2[i2], q2[(i2 + 1) % 3]}};
-            if (ts.intersect(l1, l2)) {
-                SkDebugf(" [%d,%d]", i1, i2);
-            }
-        }
-    }
-    SkDebugf("\n");
-}
-
-static void QuadraticIntersection_PointFinder() {
-    pointFinder(pointFinderTestSet[0], pointFinderTestSet[4]);
-    pointFinder(pointFinderTestSet[4], pointFinderTestSet[0]);
-    pointFinder(pointFinderTestSet[0], pointFinderTestSet[6]);
-    pointFinder(pointFinderTestSet[6], pointFinderTestSet[0]);
-    hullIntersect(pointFinderTestSet[0], pointFinderTestSet[4]);
-    hullIntersect(pointFinderTestSet[0], pointFinderTestSet[6]);
-}
-
 static void intersectionFinder(int test1, int test2) {
     const SkDQuad& quad1 = testSet[test1];
     const SkDQuad& quad2 = testSet[test2];
@@ -569,7 +505,6 @@
     coincidentTest(reporter);
     standardTestCases(reporter);
     if (false) QuadraticIntersection_IntersectionFinder();
-    if (false) QuadraticIntersection_PointFinder();
 }
 
 #include "SkCommonFlags.h"
diff --git a/tests/PathOpsSimplifyTest.cpp b/tests/PathOpsSimplifyTest.cpp
index 599fb1a..de08bd8 100644
--- a/tests/PathOpsSimplifyTest.cpp
+++ b/tests/PathOpsSimplifyTest.cpp
@@ -4726,11 +4726,39 @@
     testSimplify(reporter, path, filename);
 }
 
+static void testTriangle1(skiatest::Reporter* reporter,const char* filename) {
+    SkPath path;
+    path.moveTo(0, 0);
+    path.lineTo(1, 0);
+    path.lineTo(2, 3);
+    path.close();
+    path.moveTo(0, 0);
+    path.lineTo(1, 2);
+    path.lineTo(1, 0);
+    path.close();
+    testSimplify(reporter, path, filename);
+}
+
+static void testTriangle2(skiatest::Reporter* reporter,const char* filename) {
+    SkPath path;
+    path.moveTo(0, 0);
+    path.lineTo(1, 0);
+    path.lineTo(0, 1);
+    path.close();
+    path.moveTo(2, 0);
+    path.lineTo(0, 2);
+    path.lineTo(2, 2);
+    path.close();
+    testSimplify(reporter, path, filename);
+}
+
 static void (*skipTest)(skiatest::Reporter* , const char* filename) = 0;
 static void (*firstTest)(skiatest::Reporter* , const char* filename) = 0;
 static void (*stopTest)(skiatest::Reporter* , const char* filename) = 0;
 
 static TestDesc tests[] = {
+    TEST(testTriangle2),
+    TEST(testTriangle1),
     TEST(testQuads64),
     TEST(testQuads63),
     TEST(testQuads62),
diff --git a/tests/PathOpsSkpTest.cpp b/tests/PathOpsSkpTest.cpp
index a86218d..bbf3453 100755
--- a/tests/PathOpsSkpTest.cpp
+++ b/tests/PathOpsSkpTest.cpp
@@ -1090,7 +1090,7 @@
     // FIXME: this generates quads and cubics that are (correctly) not coincident unlike the old code
     // however, somewhere the angles are sorted incorrectly and the winding is computed to be -1/-2
     // but I can't find the error
-    testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+    testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
 }
 
 static void skpwww_fj_p_com_22(skiatest::Reporter* reporter, const char* filename) {
@@ -3769,7 +3769,7 @@
 }
 
 static void (*skipTest)(skiatest::Reporter* , const char* filename) = 0;
-static void (*firstTest)(skiatest::Reporter* , const char* filename) = skpwww_macrumors_com_131;
+static void (*firstTest)(skiatest::Reporter* , const char* filename) = skpwww_cooksnaps_com_32;
 static void (*stopTest)(skiatest::Reporter* , const char* filename) = 0;
 
 static struct TestDesc tests[] = {