Revert of pathops version two (patchset #16 id:150001 of https://codereview.chromium.org/1002693002/)

Reason for revert:
ASAN investigation

Original issue's description:
> pathops version two
>
> R=reed@google.com
>
> marked 'no commit' to attempt to get trybots to run
>
> TBR=reed@google.com
>
> Committed: https://skia.googlesource.com/skia/+/ccec0f958ffc71a9986d236bc2eb335cb2111119

TBR=caryclark@google.com
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true

Review URL: https://codereview.chromium.org/1029993002
diff --git a/tests/PathOpsAngleIdeas.cpp b/tests/PathOpsAngleIdeas.cpp
index 1a2bce7..901cab2 100755
--- a/tests/PathOpsAngleIdeas.cpp
+++ b/tests/PathOpsAngleIdeas.cpp
@@ -6,8 +6,8 @@
  */
 #include "PathOpsTestCommon.h"
 #include "SkIntersections.h"
-#include "SkOpContour.h"
 #include "SkOpSegment.h"
+#include "SkPathOpsTriangle.h"
 #include "SkRandom.h"
 #include "SkTArray.h"
 #include "SkTSort.h"
@@ -18,12 +18,12 @@
 
 class PathOpsAngleTester {
 public:
-    static int ConvexHullOverlaps(SkOpAngle& lh, SkOpAngle& rh) {
-        return lh.convexHullOverlaps(&rh);
+    static int ConvexHullOverlaps(const SkOpAngle& lh, const SkOpAngle& rh) {
+        return lh.convexHullOverlaps(rh);
     }
 
-    static int EndsIntersect(SkOpAngle& lh, SkOpAngle& rh) {
-        return lh.endsIntersect(&rh);
+    static int EndsIntersect(const SkOpAngle& lh, const SkOpAngle& rh) {
+        return lh.endsIntersect(rh);
     }
 };
 
@@ -406,29 +406,28 @@
     return ccw == upperRange.ccw;
 }
 
-static void makeSegment(SkOpContour* contour, const SkDQuad& quad, SkPoint shortQuad[3],
-        SkChunkAlloc* allocator) {
+class PathOpsSegmentTester {
+public:
+    static void ConstructQuad(SkOpSegment* segment, SkPoint shortQuad[3]) {
+        segment->debugConstructQuad(shortQuad);
+    }
+};
+
+static void makeSegment(const SkDQuad& quad, SkPoint shortQuad[3], SkOpSegment* result) {
     shortQuad[0] = quad[0].asSkPoint();
     shortQuad[1] = quad[1].asSkPoint();
     shortQuad[2] = quad[2].asSkPoint();
-    contour->addQuad(shortQuad, allocator);
+    PathOpsSegmentTester::ConstructQuad(result, shortQuad);
 }
 
 static void testQuadAngles(skiatest::Reporter* reporter, const SkDQuad& quad1, const SkDQuad& quad2,
-        int testNo, SkChunkAlloc* allocator) {
+        int testNo) {
     SkPoint shortQuads[2][3];
-
-    SkOpContour contour;
-    SkOpGlobalState state(NULL  PATH_OPS_DEBUG_PARAMS(&contour));
-    contour.init(&state, false, false);
-    makeSegment(&contour, quad1, shortQuads[0], allocator);
-    makeSegment(&contour, quad1, shortQuads[1], allocator);
-    SkOpSegment* seg1 = contour.first();
-    seg1->debugAddAngle(0, 1, allocator);
-    SkOpSegment* seg2 = seg1->next();
-    seg2->debugAddAngle(0, 1, allocator);
-    int realOverlap = PathOpsAngleTester::ConvexHullOverlaps(*seg1->debugLastAngle(),
-            *seg2->debugLastAngle());
+    SkOpSegment seg[2];
+    makeSegment(quad1, shortQuads[0], &seg[0]);
+    makeSegment(quad2, shortQuads[1], &seg[1]);
+    int realOverlap = PathOpsAngleTester::ConvexHullOverlaps(*seg[0].debugLastAngle(),
+            *seg[1].debugLastAngle());
     const SkDPoint& origin = quad1[0];
     REPORTER_ASSERT(reporter, origin == quad2[0]);
     double a1s = atan2(origin.fY - quad1[1].fY, quad1[1].fX - origin.fX);
@@ -546,27 +545,25 @@
     }
     if (overlap < 0) {
         SkDEBUGCODE(int realEnds =)
-                PathOpsAngleTester::EndsIntersect(*seg1->debugLastAngle(),
-                *seg2->debugLastAngle());
+                PathOpsAngleTester::EndsIntersect(*seg[0].debugLastAngle(),
+                *seg[1].debugLastAngle());
         SkASSERT(realEnds == (firstInside ? 1 : 0));
     }
     bruteForce(reporter, quad1, quad2, firstInside);
 }
 
 DEF_TEST(PathOpsAngleOverlapHullsOne, reporter) {
-    SkChunkAlloc allocator(4096);
 //    gPathOpsAngleIdeasVerbose = true;
     const SkDQuad quads[] = {
 {{{939.4808349609375, 914.355224609375}, {-357.7921142578125, 590.842529296875}, {736.8936767578125, -350.717529296875}}},
 {{{939.4808349609375, 914.355224609375}, {-182.85418701171875, 634.4552001953125}, {-509.62615966796875, 576.1182861328125}}}
     };
     for (int index = 0; index < (int) SK_ARRAY_COUNT(quads); index += 2) {
-        testQuadAngles(reporter, quads[index], quads[index + 1], 0, &allocator);
+        testQuadAngles(reporter, quads[index], quads[index + 1], 0);
     }
 }
 
 DEF_TEST(PathOpsAngleOverlapHulls, reporter) {
-    SkChunkAlloc allocator(4096);
     if (!gPathOpsAngleIdeasVerbose) {  // takes a while to run -- so exclude it by default
         return;
     }
@@ -590,7 +587,7 @@
         if (i.used() > 1) {
             continue;
         }
-        testQuadAngles(reporter, quad1, quad2, index, &allocator);
+        testQuadAngles(reporter, quad1, quad2, index);
     }
 }
 
diff --git a/tests/PathOpsAngleTest.cpp b/tests/PathOpsAngleTest.cpp
index db3e864..faf6158 100644
--- a/tests/PathOpsAngleTest.cpp
+++ b/tests/PathOpsAngleTest.cpp
@@ -6,9 +6,10 @@
  */
 #include "PathOpsTestCommon.h"
 #include "SkIntersections.h"
-#include "SkOpContour.h"
 #include "SkOpSegment.h"
+#include "SkPathOpsTriangle.h"
 #include "SkRandom.h"
+#include "SkTArray.h"
 #include "SkTSort.h"
 #include "Test.h"
 
@@ -190,20 +191,20 @@
 
 class PathOpsAngleTester {
 public:
-    static int After(SkOpAngle& lh, SkOpAngle& rh) {
+    static int After(const SkOpAngle& lh, const SkOpAngle& rh) {
         return lh.after(&rh);
     }
 
-    static int ConvexHullOverlaps(SkOpAngle& lh, SkOpAngle& rh) {
-        return lh.convexHullOverlaps(&rh);
+    static int ConvexHullOverlaps(const SkOpAngle& lh, const SkOpAngle& rh) {
+        return lh.convexHullOverlaps(rh);
     }
 
-    static int Orderable(SkOpAngle& lh, SkOpAngle& rh) {
-        return lh.orderable(&rh);
+    static int Orderable(const SkOpAngle& lh, const SkOpAngle& rh) {
+        return lh.orderable(rh);
     }
 
-    static int EndsIntersect(SkOpAngle& lh, SkOpAngle& rh) {
-        return lh.endsIntersect(&rh);
+    static int EndsIntersect(const SkOpAngle& lh, const SkOpAngle& rh) {
+        return lh.endsIntersect(rh);
     }
 
     static void SetNext(SkOpAngle& lh, SkOpAngle& rh) {
@@ -213,6 +214,18 @@
 
 class PathOpsSegmentTester {
 public:
+    static void ConstructCubic(SkOpSegment* segment, SkPoint shortCubic[4]) {
+        segment->debugConstructCubic(shortCubic);
+    }
+
+    static void ConstructLine(SkOpSegment* segment, SkPoint shortLine[2]) {
+        segment->debugConstructLine(shortLine);
+    }
+
+    static void ConstructQuad(SkOpSegment* segment, SkPoint shortQuad[3]) {
+        segment->debugConstructQuad(shortQuad);
+    }
+
     static void DebugReset(SkOpSegment* segment) {
         segment->debugReset();
     }
@@ -233,10 +246,7 @@
 static const int circleDataSetSize = (int) SK_ARRAY_COUNT(circleDataSet);
 
 DEF_TEST(PathOpsAngleCircle, reporter) {
-    SkOpContour contour;
-    SkOpGlobalState state(NULL  PATH_OPS_DEBUG_PARAMS(&contour));
-    contour.init(&state, false, false);
-    SkChunkAlloc allocator(4096);
+    SkOpSegment segment[2];
     for (int index = 0; index < circleDataSetSize; ++index) {
         CircleData& data = circleDataSet[index];
         for (int idx2 = 0; idx2 < data.fPtCount; ++idx2) {
@@ -244,21 +254,17 @@
         }
         switch (data.fPtCount) {
             case 2:
-                contour.addLine(data.fShortPts, &allocator);
+                PathOpsSegmentTester::ConstructLine(&segment[index], data.fShortPts);
                 break;
             case 3:
-                contour.addQuad(data.fShortPts, &allocator);
+                PathOpsSegmentTester::ConstructQuad(&segment[index], data.fShortPts);
                 break;
             case 4:
-                contour.addCubic(data.fShortPts, &allocator);
+                PathOpsSegmentTester::ConstructCubic(&segment[index], data.fShortPts);
                 break;
         }
     }
-    SkOpSegment* first = contour.first();
-    first->debugAddAngle(0, 1, &allocator);
-    SkOpSegment* next = first->next();
-    next->debugAddAngle(0, 1, &allocator);
-    PathOpsAngleTester::Orderable(*first->debugLastAngle(), *next->debugLastAngle());
+    PathOpsAngleTester::Orderable(*segment[0].debugLastAngle(), *segment[1].debugLastAngle());
 }
 
 struct IntersectData {
@@ -373,39 +379,11 @@
     { {{{5.000,4.000}, {2.000,3.000}}}, 2, 0.5, 0, {} }, // pathops_visualizer.htm:7377
 }; //
 
-// from skpi_gino_com_16
-static IntersectData intersectDataSet17[] = {
-    { /*seg=7*/ {{{270.974121f, 770.025879f}, {234.948273f, 734}, {184, 734}}}
-        , 3, 0.74590454, 0.547660352, {} },
-    { /*seg=8*/ {{{185, 734}, {252.93103f, 734}, {308, 789.06897f}, {308, 857}}}
-        , 4, 0.12052623, 0, {} },
-    { /*seg=7*/ {{{270.974121f, 770.025879f}, {234.948273f, 734}, {184, 734}}}
-        , 3, 0.74590454, 1, {} },
-};
-
-static IntersectData intersectDataSet18[] = {
-    { /*seg=7*/ {{{270.974121f, 770.025879f}, {234.948273f, 734}, {184, 734}}}
-        , 3, 0.74590454, 1, {} },
-    { /*seg=8*/ {{{185, 734}, {252.93103f, 734}, {308, 789.06897f}, {308, 857}}}
-        , 4, 0.12052623, 0.217351928, {} },
-    { /*seg=7*/ {{{270.974121f, 770.025879f}, {234.948273f, 734}, {184, 734}}}
-        , 3, 0.74590454, 0.547660352, {} },
-};
-
-static IntersectData intersectDataSet19[] = {
-    { /*seg=1*/ {{{0, 1}, {3, 5}, {2, 1}, {3, 1}}}
-        , 4, 0.135148995, 0.134791946, {} },
-    { /*seg=3*/ {{{1, 2}, {1, 2.15061641f}, {1, 2.21049166f}, {1.01366711f, 2.21379328f}}}
-        , 4, 0.956740456, 0.894913214, {} },
-    { /*seg=1*/ {{{0, 1}, {3, 5}, {2, 1}, {3, 1}}}
-        , 4, 0.135148995, 0.551812363, {} },
-};
-
 #define I(x) intersectDataSet##x
 
 static IntersectData* intersectDataSets[] = {
     I(1), I(2), I(3), I(4), I(5), I(6), I(7), I(8), I(9), I(10),
-    I(11), I(12), I(13), I(14), I(15), I(16), I(17), I(18), I(19),
+    I(11), I(12), I(13), I(14), I(15), I(16),
 };
 
 #undef I
@@ -413,55 +391,56 @@
 
 static const int intersectDataSetSizes[] = {
     I(1), I(2), I(3), I(4), I(5), I(6), I(7), I(8), I(9), I(10),
-    I(11), I(12), I(13), I(14), I(15), I(16), I(17), I(18), I(19),
+    I(11), I(12), I(13), I(14), I(15), I(16),
 };
 
 #undef I
 
 static const int intersectDataSetsSize = (int) SK_ARRAY_COUNT(intersectDataSetSizes);
 
-struct FourPoints {
-    SkPoint pts[4];
-};
-
 DEF_TEST(PathOpsAngleAfter, reporter) {
-    SkChunkAlloc allocator(4096);
-    SkOpContour contour;
-    SkOpGlobalState state(NULL  PATH_OPS_DEBUG_PARAMS(&contour));
-    contour.init(&state, false, false);
     for (int index = intersectDataSetsSize - 1; index >= 0; --index) {
         IntersectData* dataArray = intersectDataSets[index];
         const int dataSize = intersectDataSetSizes[index];
+        SkOpSegment segment[3];
         for (int index2 = 0; index2 < dataSize - 2; ++index2) {
-            allocator.reset();
-            contour.reset();
-            for (int index3 = 0; index3 < 3; ++index3) {
+            for (int temp = 0; temp < (int) SK_ARRAY_COUNT(segment); ++temp) {
+                PathOpsSegmentTester::DebugReset(&segment[temp]);
+            }
+            for (int index3 = 0; index3 < (int) SK_ARRAY_COUNT(segment); ++index3) {
                 IntersectData& data = dataArray[index2 + index3];
-                SkPoint* temp = (SkPoint*) SkOpTAllocator<FourPoints>::Allocate(&allocator);
+                SkPoint temp[4];
                 for (int idx2 = 0; idx2 < data.fPtCount; ++idx2) {
                     temp[idx2] = data.fPts.fPts[idx2].asSkPoint();
                 }
                 switch (data.fPtCount) {
                     case 2: {
-                        contour.addLine(temp, &allocator);
+                        SkDLine seg = SkDLine::SubDivide(temp, data.fTStart,
+                                data.fTStart < data.fTEnd ? 1 : 0);
+                        data.fShortPts[0] = seg[0].asSkPoint();
+                        data.fShortPts[1] = seg[1].asSkPoint();
+                        PathOpsSegmentTester::ConstructLine(&segment[index3], data.fShortPts);
                         } break;
                     case 3: {
-                        contour.addQuad(temp, &allocator);
+                        SkDQuad seg = SkDQuad::SubDivide(temp, data.fTStart, data.fTEnd);
+                        data.fShortPts[0] = seg[0].asSkPoint();
+                        data.fShortPts[1] = seg[1].asSkPoint();
+                        data.fShortPts[2] = seg[2].asSkPoint();
+                        PathOpsSegmentTester::ConstructQuad(&segment[index3], data.fShortPts);
                         } break;
                     case 4: {
-                        contour.addCubic(temp, &allocator);
+                        SkDCubic seg = SkDCubic::SubDivide(temp, data.fTStart, data.fTEnd);
+                        data.fShortPts[0] = seg[0].asSkPoint();
+                        data.fShortPts[1] = seg[1].asSkPoint();
+                        data.fShortPts[2] = seg[2].asSkPoint();
+                        data.fShortPts[3] = seg[3].asSkPoint();
+                        PathOpsSegmentTester::ConstructCubic(&segment[index3], data.fShortPts);
                         } break;
                 }
             }
-            SkOpSegment* seg1 = contour.first();
-            seg1->debugAddAngle(dataArray[index2 + 0].fTStart, dataArray[index2 + 0].fTEnd, &allocator);
-            SkOpSegment* seg2 = seg1->next();
-            seg2->debugAddAngle(dataArray[index2 + 1].fTStart, dataArray[index2 + 1].fTEnd, &allocator);
-            SkOpSegment* seg3 = seg2->next();
-            seg3->debugAddAngle(dataArray[index2 + 2].fTStart, dataArray[index2 + 2].fTEnd, &allocator);
-            SkOpAngle& angle1 = *seg1->debugLastAngle();
-            SkOpAngle& angle2 = *seg2->debugLastAngle();
-            SkOpAngle& angle3 = *seg3->debugLastAngle();
+            SkOpAngle& angle1 = *const_cast<SkOpAngle*>(segment[0].debugLastAngle());
+            SkOpAngle& angle2 = *const_cast<SkOpAngle*>(segment[1].debugLastAngle());
+            SkOpAngle& angle3 = *const_cast<SkOpAngle*>(segment[2].debugLastAngle());
             PathOpsAngleTester::SetNext(angle1, angle3);
        // These data sets are seeded when the set itself fails, so likely the dataset does not
        // match the expected result. The tests above return 1 when first added, but
@@ -472,26 +451,35 @@
     }
 }
 
-void SkOpSegment::debugAddAngle(double startT, double endT, SkChunkAlloc* allocator) {
-    SkOpPtT* startPtT = startT == 0 ? fHead.ptT() : startT == 1 ? fTail.ptT()
-            : this->addT(startT, kNoAlias, allocator);
-    SkOpPtT* endPtT = endT == 0 ? fHead.ptT() : endT == 1 ? fTail.ptT()
-            : this->addT(endT, kNoAlias, allocator);
-    SkOpAngle* angle = SkOpTAllocator<SkOpAngle>::Allocate(allocator);
-    SkOpSpanBase* startSpan = &fHead;
-    while (startSpan->ptT() != startPtT) {
-        startSpan = startSpan->upCast()->next();
-    }
-    SkOpSpanBase* endSpan = &fHead;
-    while (endSpan->ptT() != endPtT) {
-        endSpan = endSpan->upCast()->next();
-    }
-    angle->set(startSpan, endSpan);
-    if (startT < endT) {
-        startSpan->upCast()->setToAngle(angle);
-        endSpan->setFromAngle(angle);
-    } else {
-        endSpan->upCast()->setToAngle(angle);
-        startSpan->setFromAngle(angle);
-    }
+void SkOpSegment::debugConstruct() {
+    addStartSpan(1);
+    addEndSpan(1);
+    debugAddAngle(0, 1);
+}
+
+void SkOpSegment::debugAddAngle(int start, int end) {
+    SkASSERT(start != end);
+    SkOpAngle& angle = fAngles.push_back();
+    angle.set(this, start, end);
+}
+
+void SkOpSegment::debugConstructCubic(SkPoint shortQuad[4]) {
+    addCubic(shortQuad, false, false);
+    addT(NULL, shortQuad[0], 0);
+    addT(NULL, shortQuad[3], 1);
+    debugConstruct();
+}
+
+void SkOpSegment::debugConstructLine(SkPoint shortQuad[2]) {
+    addLine(shortQuad, false, false);
+    addT(NULL, shortQuad[0], 0);
+    addT(NULL, shortQuad[1], 1);
+    debugConstruct();
+}
+
+void SkOpSegment::debugConstructQuad(SkPoint shortQuad[3]) {
+    addQuad(shortQuad, false, false);
+    addT(NULL, shortQuad[0], 0);
+    addT(NULL, shortQuad[2], 1);
+    debugConstruct();
 }
diff --git a/tests/PathOpsBattles.cpp b/tests/PathOpsBattles.cpp
index fbe12c0..455f2e9 100644
--- a/tests/PathOpsBattles.cpp
+++ b/tests/PathOpsBattles.cpp
@@ -59,6 +59,7 @@
 path2.cubicTo(SkBits2Float(0x42383446), SkBits2Float(0x421ac98f), SkBits2Float(0x4242b98a), SkBits2Float(0x420d5308), SkBits2Float(0x424bbb17), SkBits2Float(0x41fdb8ee));
 path2.lineTo(SkBits2Float(0x428ce9ef), SkBits2Float(0x422f7dc6));
 path2.close();
+// SkOpSegment.cpp:3488: failed assertion "other->fTs[min].fWindSum == oppWinding"
     testPathOp(reporter, path1, path2, kUnion_PathOp, filename);
 }
 
@@ -1295,7 +1296,7 @@
 path.close();
 
     SkPath path2(path);
-    testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+    testPathOpCheck(reporter, path1, path2, (SkPathOp) 2, filename, FLAGS_runFail);
 }
 // op end success 1
 
@@ -1511,7 +1512,7 @@
 path.close();
 
     SkPath path2(path);
-    testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+    testPathOpCheck(reporter, path1, path2, (SkPathOp) 2, filename, FLAGS_runFail);
 }
 // op end success 1
 
@@ -1753,7 +1754,7 @@
 path.close();
 
     SkPath path2(path);
-    testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+    testPathOpCheck(reporter, path1, path2, (SkPathOp) 2, filename, FLAGS_runFail);
 }
 // op end success 1
 
@@ -1883,7 +1884,11 @@
 path.close();
 
     SkPath path2(path);
-    testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+    if (FLAGS_runFail) {
+        testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+    } else {
+        testPathFailOp(reporter, path1, path2, (SkPathOp) 2, filename);
+    }
 }
 // op end success 1
 
@@ -3977,7 +3982,7 @@
 path.close();
 
     SkPath path2(path);
-    testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+    testPathOpCheck(reporter, path1, path2, (SkPathOp) 2, filename, FLAGS_runFail);
 }
 // op end success 1
 
@@ -4087,7 +4092,7 @@
 path.close();
 
     SkPath path2(path);
-    testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+    testPathOpCheck(reporter, path1, path2, (SkPathOp) 2, filename, FLAGS_runFail);
 }
 // op end success 1
 
@@ -4235,7 +4240,7 @@
 path.close();
 
     SkPath path2(path);
-    testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+    testPathOpCheck(reporter, path1, path2, (SkPathOp) 2, filename, FLAGS_runFail);
 }
 // op end success 1
 
@@ -4409,7 +4414,7 @@
 path.close();
 
     SkPath path2(path);
-    testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+    testPathOpCheck(reporter, path1, path2, (SkPathOp) 2, filename, FLAGS_runFail);
 }
 // op end success 1
 
@@ -4831,7 +4836,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
 
@@ -4951,7 +4956,7 @@
 path.close();
 
     SkPath path2(path);
-    testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+    testPathOpCheck(reporter, path1, path2, (SkPathOp) 2, filename, FLAGS_runFail);
 }
 // op end success 1
 
@@ -5362,7 +5367,7 @@
 path.close();
 
     SkPath path2(path);
-    testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+    testPathOpCheck(reporter, path1, path2, (SkPathOp) 2, filename, FLAGS_runFail);
 }
 // op end success 1
 
@@ -5438,7 +5443,7 @@
 path.close();
 
     SkPath path2(path);
-    testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+    testPathOpCheck(reporter, path1, path2, (SkPathOp) 2, filename, FLAGS_runFail);
 }
 // op end success 1
 
@@ -6292,7 +6297,7 @@
 path.close();
 
     SkPath path2(path);
-    testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+    testPathOpCheck(reporter, path1, path2, (SkPathOp) 2, filename, FLAGS_runFail);
 }
 // op end success 1
 
@@ -7049,7 +7054,7 @@
 path.close();
 
     SkPath path2(path);
-    testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+    testPathOpCheck(reporter, path1, path2, (SkPathOp) 2, filename, FLAGS_runFail);
 }
 // op end success 1
 
@@ -7438,7 +7443,7 @@
 path.close();
 
     SkPath path2(path);
-    testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+    testPathOpCheck(reporter, path1, path2, (SkPathOp) 2, filename, FLAGS_runFail);
 }
 // op end success 1
 
@@ -7555,7 +7560,7 @@
 path.close();
 
     SkPath path2(path);
-    testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+    testPathOpCheck(reporter, path1, path2, (SkPathOp) 2, filename, FLAGS_runFail);
 }
 // op end success 1
 
@@ -7858,7 +7863,7 @@
 path.close();
 
     SkPath path2(path);
-    testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+    testPathOpCheck(reporter, path1, path2, (SkPathOp) 2, filename, FLAGS_runFail);
 }
 // op end success 1
 
@@ -10681,7 +10686,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) = battleOp68;
 static void (*stopTest)(skiatest::Reporter* , const char* filename) = 0;
 
 static struct TestDesc tests[] = {
@@ -11123,5 +11128,5 @@
 #if DEBUG_SHOW_TEST_NAME
     strncpy(DEBUG_FILENAME_STRING, "", DEBUG_FILENAME_STRING_LENGTH);
 #endif
-    RunTestSet(reporter, tests, testCount, firstTest, NULL, stopTest, runReverse);
+    RunTestSet(reporter, tests, testCount, firstTest, stopTest, runReverse);
 }
diff --git a/tests/PathOpsBuilderTest.cpp b/tests/PathOpsBuilderTest.cpp
index 5fdeb3e..1eadebc 100644
--- a/tests/PathOpsBuilderTest.cpp
+++ b/tests/PathOpsBuilderTest.cpp
@@ -4,10 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
-
-#include "PathOpsExtendedTest.h"
 #include "PathOpsTestCommon.h"
-#include "SkBitmap.h"
 #include "Test.h"
 
 DEF_TEST(PathOpsBuilder, reporter) {
@@ -25,7 +22,6 @@
     REPORTER_ASSERT(reporter, result.isEmpty());
 
     SkPath rectPath;
-    rectPath.setFillType(SkPath::kEvenOdd_FillType);
     rectPath.addRect(0, 1, 2, 3, SkPath::kCW_Direction);
     builder.add(rectPath, kUnion_PathOp);
     REPORTER_ASSERT(reporter, builder.resolve(&result));
@@ -37,14 +33,13 @@
     REPORTER_ASSERT(reporter, rectPath == result);
 
     rectPath.reset();
-    rectPath.setFillType(SkPath::kEvenOdd_FillType);
     rectPath.addRect(0, 1, 2, 3, SkPath::kCCW_Direction);
     builder.add(rectPath, kUnion_PathOp);
     REPORTER_ASSERT(reporter, builder.resolve(&result));
     REPORTER_ASSERT(reporter, result.isRect(NULL, &closed, &dir));
     REPORTER_ASSERT(reporter, closed);
     REPORTER_ASSERT(reporter, dir == SkPath::kCCW_Direction);
-     REPORTER_ASSERT(reporter, rectPath == result);
+    REPORTER_ASSERT(reporter, rectPath == result);
 
     builder.add(rectPath, kDifference_PathOp);
     REPORTER_ASSERT(reporter, builder.resolve(&result));
@@ -74,7 +69,5 @@
     builder.add(circle2, kUnion_PathOp);
     builder.add(circle3, kDifference_PathOp);
     REPORTER_ASSERT(reporter, builder.resolve(&result));
-    SkBitmap bitmap;
-    int pixelDiff = comparePaths(reporter, __FUNCTION__, opCompare, result, bitmap);
-    REPORTER_ASSERT(reporter, pixelDiff == 0);
+    REPORTER_ASSERT(reporter, opCompare == result);
 }
diff --git a/tests/PathOpsCubicIntersectionTest.cpp b/tests/PathOpsCubicIntersectionTest.cpp
index a424c50..b6a9e59 100644
--- a/tests/PathOpsCubicIntersectionTest.cpp
+++ b/tests/PathOpsCubicIntersectionTest.cpp
@@ -6,7 +6,6 @@
  */
 #include "PathOpsCubicIntersectionTestData.h"
 #include "PathOpsTestCommon.h"
-#include "SkGeometry.h"
 #include "SkIntersections.h"
 #include "SkPathOpsRect.h"
 #include "SkReduceOrder.h"
@@ -163,60 +162,6 @@
 const int testSetCount = (int) SK_ARRAY_COUNT(testSet);
 
 static const SkDCubic newTestSet[] = {
-{{{980.026001,1481.276}, {980.026001,1481.276}, {980.02594,1481.27576}, {980.025879,1481.27527}}},
-{{{980.025879,1481.27527}, {980.025452,1481.27222}, {980.023743,1481.26038}, {980.02179,1481.24072}}},
-
-{{{1.80943513,3.07782435}, {1.66686702,2.16806936}, {1.68301272,0}, {3,0}}},
-{{{0,1}, {0,3}, {3,2}, {5,2}}},
-
-{{{3.4386673,2.66977954}, {4.06668949,2.17046738}, {4.78887367,1.59629118}, {6,2}}},
-{{{1.71985495,3.49467373}, {2.11620402,2.7201426}, {2.91897964,1.15138781}, {6,3}}},
-
-{{{0,1}, {0.392703831,1.78540766}, {0.219947904,2.05676103}, {0.218561709,2.05630541}}},
-{{{0.218561709,2.05630541}, {0.216418028,2.05560064}, {0.624105453,1.40486407}, {4.16666651,1.00000012}}},
-
-{{{0, 1}, {3, 5}, {2, 1}, {3, 1}}},
-{{{1.01366711f, 2.21379328f}, {1.09074128f, 2.23241305f}, {1.60246587f, 0.451849401f}, {5, 3}}},
-
-{{{0, 1}, {0.541499972f, 3.16599989f}, {1.08299994f, 2.69299984f}, {2.10083938f, 1.80391729f}}},
-{{{0.806384504f, 2.85426903f}, {1.52740121f, 1.99355423f}, {2.81689167f, 0.454222918f}, {5, 1}}},
-
-{{{0, 1}, {1.90192389f, 2.90192389f}, {2.59807634f, 2.79422879f}, {3.1076951f, 2.71539044f}}},
-{{{2, 3}, {2.36602545f, 3.36602545f}, {2.330127f, 3.06217766f}, {2.28460979f, 2.67691422f}}},
-
-{{{0, 1}, {1.90192389f, 2.90192389f}, {2.59807634f, 2.79422879f}, {3.1076951f, 2.71539044f}}},
-{{{2.28460979f, 2.67691422f}, {2.20577145f, 2.00961876f}, {2.09807634f, 1.09807622f}, {4, 3}}},
-
-{{{0, 1}, {0.8211091160774231, 2.0948121547698975}, {0.91805583238601685, 2.515404224395752}, {0.91621249914169312, 2.5146586894989014}}},
-{{{0.91621249914169312, 2.5146586894989014}, {0.91132104396820068, 2.5126807689666748}, {0.21079301834106445, -0.45617169141769409}, {10.5, -1.6666665077209473}}},
-
-{{{42.6237564,68.9841232}, {32.449646,81.963089}, {14.7713947,103.565269}, {12.6310005,105.247002}}},
-{{{37.2640038,95.3540039}, {37.2640038,95.3540039}, {11.3710003,83.7339935}, {-25.0779991,124.912003}}},
-
-{{{0,1}, {4,5}, {6,0}, {1,0}}},
-{{{0,6}, {0,1}, {1,0}, {5,4}}},
-
-{{{0,1}, {4,6}, {5,1}, {6,2}}},
-{{{1,5}, {2,6}, {1,0}, {6,4}}},
-
-{{{322, 896.04803466796875}, {314.09201049804687, 833.4376220703125}, {260.24713134765625, 785}, {195, 785}}},
-{{{195, 785}, {265.14016723632812, 785}, {322, 842.30755615234375}, {322, 913}}},
-
-{{{1, 4}, {4, 5}, {3, 2}, {6, 3}}},
-{{{2, 3}, {3, 6}, {4, 1}, {5, 4}}},
-
-{{{67, 913}, {67, 917.388916015625}, {67.224380493164063, 921.72576904296875}, {67.662384033203125, 926}}},
-{{{194, 1041}, {123.85984039306641, 1041}, {67, 983.69244384765625}, {67, 913}}},
-
-{{{1,4}, {1,5}, {6,0}, {5,1}}},
-{{{0,6}, {1,5}, {4,1}, {5,1}}},
-
-{{{0,1}, {4,5}, {6,0}, {1,0}}},
-{{{0,6}, {0,1}, {1,0}, {5,4}}},
-
-{{{0,1}, {4,6}, {2,0}, {2,0}}},
-{{{0,2}, {0,2}, {1,0}, {6,4}}},
-
 {{{980.9000244140625, 1474.3280029296875}, {980.9000244140625, 1474.3280029296875}, {978.89300537109375, 1471.95703125}, {981.791015625, 1469.487060546875}}},
 {{{981.791015625, 1469.487060546875}, {981.791015625, 1469.4859619140625}, {983.3580322265625, 1472.72900390625}, {980.9000244140625, 1474.3280029296875}}},
 
@@ -361,6 +306,7 @@
 };
 
 const int newTestSetCount = (int) SK_ARRAY_COUNT(newTestSet);
+
 static void oneOff(skiatest::Reporter* reporter, const SkDCubic& cubic1, const SkDCubic& cubic2,
         bool coin) {
     SkASSERT(ValidCubic(cubic1));
@@ -374,22 +320,28 @@
         cubic2[0].fX, cubic2[0].fY, cubic2[1].fX, cubic2[1].fY,
         cubic2[2].fX, cubic2[2].fY, cubic2[3].fX, cubic2[3].fY);
 #endif
-#if DEBUG_T_SECT_DUMP > 1
-    gDumpTSectNum = 0;
+    SkTArray<SkDQuad, true> quads1;
+    CubicToQuads(cubic1, cubic1.calcPrecision(), quads1);
+#if ONE_OFF_DEBUG
+    SkDebugf("computed quadratics set 1\n");
+    for (int index = 0; index < quads1.count(); ++index) {
+        const SkDQuad& q = quads1[index];
+        SkDebugf("  {{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}},\n", q[0].fX, q[0].fY,
+                 q[1].fX, q[1].fY,  q[2].fX, q[2].fY);
+    }
+#endif
+    SkTArray<SkDQuad, true> quads2;
+    CubicToQuads(cubic2, cubic2.calcPrecision(), quads2);
+#if ONE_OFF_DEBUG
+    SkDebugf("computed quadratics set 2\n");
+    for (int index = 0; index < quads2.count(); ++index) {
+        const SkDQuad& q = quads2[index];
+        SkDebugf("  {{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}},\n", q[0].fX, q[0].fY,
+                 q[1].fX, q[1].fY,  q[2].fX, q[2].fY);
+    }
 #endif
     SkIntersections intersections;
     intersections.intersect(cubic1, cubic2);
-#if DEBUG_T_SECT_DUMP == 3
-    SkDebugf("</div>\n\n");
-    SkDebugf("<script type=\"text/javascript\">\n\n");
-    SkDebugf("var testDivs = [\n");
-    for (int index = 1; index <= gDumpTSectNum; ++index) {
-        SkDebugf("sect%d,\n", index);
-    }
-#endif
-    if (coin && intersections.used() != 2) {
-        SkDebugf("");
-    }
     REPORTER_ASSERT(reporter, !coin || intersections.used() == 2);
     double tt1, tt2;
     SkDPoint xy1, xy2;
@@ -606,30 +558,37 @@
 
 static void selfOneOff(skiatest::Reporter* reporter, int index) {
     const SkDCubic& cubic = selfSet[index];
-    SkPoint c[4];
-    for (int i = 0; i < 4; ++i) {
-        c[i] = cubic[i].asSkPoint();
+#if ONE_OFF_DEBUG
+    int idx2;
+    double max[3];
+    int ts = cubic.findMaxCurvature(max);
+    for (idx2 = 0; idx2 < ts; ++idx2) {
+        SkDebugf("%s max[%d]=%1.9g (%1.9g, %1.9g)\n", __FUNCTION__, idx2,
+                max[idx2], cubic.ptAtT(max[idx2]).fX, cubic.ptAtT(max[idx2]).fY);
     }
-    SkScalar loopT;
-    SkScalar d[3];
-    SkCubicType cubicType = SkClassifyCubic(c, d);
-    if (SkDCubic::ComplexBreak(c, &loopT) && cubicType == SkCubicType::kLoop_SkCubicType) {
-        SkIntersections i;
-        SkPoint twoCubics[7];
-        SkChopCubicAt(c, twoCubics, loopT);
-        SkDCubic chopped[2];
-        chopped[0].set(&twoCubics[0]);
-        chopped[1].set(&twoCubics[3]);
-        int result = i.intersect(chopped[0], chopped[1]);
-        REPORTER_ASSERT(reporter, result == 2);
-        REPORTER_ASSERT(reporter, i.used() == 2);
-        for (int index = 0; index < result; ++index) {
-            SkDPoint pt1 = chopped[0].ptAtT(i[0][index]);
-            SkDPoint pt2 = chopped[1].ptAtT(i[1][index]);
-            REPORTER_ASSERT(reporter, pt1.approximatelyEqual(pt2));
-            reporter->bumpTestCount();
-        }
+    SkTArray<double, true> ts1;
+    SkTArray<SkDQuad, true> quads1;
+    cubic.toQuadraticTs(cubic.calcPrecision(), &ts1);
+    for (idx2 = 0; idx2 < ts1.count(); ++idx2) {
+        SkDebugf("%s t[%d]=%1.9g\n", __FUNCTION__, idx2, ts1[idx2]);
     }
+    CubicToQuads(cubic, cubic.calcPrecision(), quads1);
+    for (idx2 = 0; idx2 < quads1.count(); ++idx2) {
+        const SkDQuad& q = quads1[idx2];
+        SkDebugf("  {{{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}}},\n",
+                q[0].fX, q[0].fY,  q[1].fX, q[1].fY,  q[2].fX, q[2].fY);
+    }
+    SkDebugf("\n");
+#endif
+    SkIntersections i;
+    int result = i.intersect(cubic);
+    REPORTER_ASSERT(reporter, result == 1);
+    REPORTER_ASSERT(reporter, i.used() == 1);
+    REPORTER_ASSERT(reporter, !approximately_equal(i[0][0], i[1][0]));
+    SkDPoint pt1 = cubic.ptAtT(i[0][0]);
+    SkDPoint pt2 = cubic.ptAtT(i[1][0]);
+    REPORTER_ASSERT(reporter, pt1.approximatelyEqual(pt2));
+    reporter->bumpTestCount();
 }
 
 static void cubicIntersectionSelfTest(skiatest::Reporter* reporter) {
@@ -640,12 +599,12 @@
 }
 
 static const SkDCubic coinSet[] = {
-    {{{2, 3}, {0, 4}, {3, 2}, {5, 3}}},
-    {{{2, 3}, {0, 4}, {3, 2}, {5, 3}}},
-
     {{{317, 711}, {322.52285766601562, 711}, {327, 715.4771728515625}, {327, 721}}},
     {{{324.07107543945312, 713.928955078125}, {324.4051513671875, 714.26300048828125},
             {324.71566772460937, 714.62060546875}, {325, 714.9990234375}}},
+
+    {{{2, 3}, {0, 4}, {3, 2}, {5, 3}}},
+    {{{2, 3}, {0, 4}, {3, 2}, {5, 3}}},
 };
 
 static int coinSetCount = (int) SK_ARRAY_COUNT(coinSet);
@@ -683,72 +642,3 @@
     if (false) CubicIntersection_IntersectionFinder();
     if (false) CubicIntersection_RandTest(reporter);
 }
-
-static void binaryTest(const SkDCubic& cubic1, const SkDCubic& cubic2,
-        skiatest::Reporter* reporter) {
-    SkASSERT(ValidCubic(cubic1));
-    SkASSERT(ValidCubic(cubic2));
-    SkIntersections intersections;
-    SkReduceOrder reduce1, reduce2;
-    int order1 = reduce1.reduce(cubic1, SkReduceOrder::kNo_Quadratics);
-    int order2 = reduce2.reduce(cubic2, SkReduceOrder::kNo_Quadratics);
-    if (order1 == 4 && order2 == 4) {
-        intersections.intersect(cubic1, cubic2);
-    } else {
-        intersections.reset();
-    }
-    SkIntersections intersections2;
-    (void) intersections2.intersect(cubic1, cubic2);
-    REPORTER_ASSERT(reporter, intersections.used() <= intersections2.used()
-            || intersections[0][0] + 0.01 > intersections[0][1]);
-    for (int index = 0; index < intersections2.used(); ++index) {
-//            SkASSERT(intersections.pt(index).approximatelyEqual(intersections2.pt(index)));
-        double tt1 = intersections2[0][index];
-        SkDPoint xy1 = cubic1.ptAtT(tt1);
-        double tt2 = intersections2[1][index];
-        SkDPoint xy2 = cubic2.ptAtT(tt2);
-        REPORTER_ASSERT(reporter, xy1.approximatelyEqual(xy2));
-    }
-}
-
-DEF_TEST(PathOpsCubicBinaryTest, reporter) {
-    int outer = 0;
-    int inner = outer + 1;
-    do {
-        const SkDCubic& cubic1 = testSet[outer];
-        const SkDCubic& cubic2 = testSet[inner];
-        binaryTest(cubic1, cubic2, reporter);
-        inner += 2;
-        outer += 2;
-    } while (outer < (int) testSetCount);
-}
-
-DEF_TEST(PathOpsCubicBinaryNew, reporter) {
-    int outer = 62;
-    int inner = outer + 1;
-    do {
-        const SkDCubic& cubic1 = newTestSet[outer];
-        const SkDCubic& cubic2 = newTestSet[inner];
-        binaryTest(cubic1, cubic2, reporter);
-        inner += 2;
-        outer += 2;
-    } while (outer < (int) newTestSetCount);
-}
-
-DEF_TEST(PathOpsCubicBinaryStd, reporter) {
-    const int firstTest = 0;
-    for (size_t index = firstTest; index < tests_count; ++index) {
-        const SkDCubic& cubic1 = tests[index][0];
-        const SkDCubic& cubic2 = tests[index][1];
-        binaryTest(cubic1, cubic2, reporter);
-    }
-}
-
-DEF_TEST(PathOpsCubicBinaryCoin, reporter) {
-    int firstFail = 0;
-    for (int index = firstFail; index < coinSetCount; index += 2) {
-        const SkDCubic& cubic1 = coinSet[index];
-        const SkDCubic& cubic2 = coinSet[index + 1];
-        binaryTest(cubic1, cubic2, reporter);
-    }
-}
diff --git a/tests/PathOpsCubicIntersectionTestData.cpp b/tests/PathOpsCubicIntersectionTestData.cpp
index 7f725ef..31056d2 100644
--- a/tests/PathOpsCubicIntersectionTestData.cpp
+++ b/tests/PathOpsCubicIntersectionTestData.cpp
@@ -46,8 +46,8 @@
 const size_t pointDegenerates_count = SK_ARRAY_COUNT(pointDegenerates);
 
 const SkDCubic notPointDegenerates[] = {
-    {{{1 + FLT_EPSILON * 8, 1}, {1, FLT_EPSILON * 8}, {1, 1}, {1, 1}}},
-    {{{1 + FLT_EPSILON * 8, 1}, {1 - FLT_EPSILON * 8, 1}, {1, 1}, {1, 1}}}
+    {{{1 + FLT_EPSILON * 2, 1}, {1, FLT_EPSILON * 2}, {1, 1}, {1, 1}}},
+    {{{1 + FLT_EPSILON * 2, 1}, {1 - FLT_EPSILON * 2, 1}, {1, 1}, {1, 1}}}
 };
 
 const size_t notPointDegenerates_count =
@@ -156,8 +156,8 @@
 
 const size_t notLines_count = SK_ARRAY_COUNT(notLines);
 
-static const double E = FLT_EPSILON * 8;
-static const double F = FLT_EPSILON * 8;
+static const double E = FLT_EPSILON * 2;
+static const double F = FLT_EPSILON * 3;
 
 const SkDCubic modEpsilonLines[] = {
     {{{0, E}, {0, 0}, {0, 0}, {1, 0}}},  // horizontal
@@ -187,8 +187,8 @@
     {{{1, 1}, {2, 2}, {2, 2+E}, {1, 1}}},
     {{{1, 1}, {1, 1+E}, {3, 3}, {3, 3}}},  // first-middle middle-last coincident
     {{{1, 1}, {2+E, 2}, {3, 3}, {4, 4}}},  // no coincident
-    {{{1, 1}, {3, 3}, {2, 2}, {4, 4+F+F}}},  // INVESTIGATE: why the epsilon is bigger
-    {{{1, 1+F+F}, {2, 2}, {4, 4}, {3, 3}}},  // INVESTIGATE: why the epsilon is bigger
+    {{{1, 1}, {3, 3}, {2, 2}, {4, 4+F}}},  // INVESTIGATE: why the epsilon is bigger
+    {{{1, 1+F}, {2, 2}, {4, 4}, {3, 3}}},  // INVESTIGATE: why the epsilon is bigger
     {{{1, 1}, {3, 3}, {4, 4+E}, {2, 2}}},
     {{{1, 1}, {4, 4}, {2, 2}, {3, 3+E}}},
     {{{1, 1}, {4, 4}, {3, 3}, {2+E, 2}}},
diff --git a/tests/PathOpsCubicLineIntersectionTest.cpp b/tests/PathOpsCubicLineIntersectionTest.cpp
index 6fdce3c..234a538 100644
--- a/tests/PathOpsCubicLineIntersectionTest.cpp
+++ b/tests/PathOpsCubicLineIntersectionTest.cpp
@@ -49,9 +49,6 @@
 }
 
 static lineCubic lineCubicTests[] = {
-    {{{{0.468027353,4}, {1.06734705,1.33333337}, {1.36700678,0}, {3,0}}},
-    {{{2,1}, {0,1}}}},
-
     {{{{-634.60540771484375, -481.262939453125}, {266.2696533203125, -752.70867919921875},
             {-751.8370361328125, -317.37921142578125}, {-969.7427978515625, 824.7255859375}}},
             {{{-287.9506133720805678, -557.1376476615772617},
diff --git a/tests/PathOpsCubicQuadIntersectionTest.cpp b/tests/PathOpsCubicQuadIntersectionTest.cpp
index d1ce05b..967dfc7 100644
--- a/tests/PathOpsCubicQuadIntersectionTest.cpp
+++ b/tests/PathOpsCubicQuadIntersectionTest.cpp
@@ -15,32 +15,44 @@
 static struct quadCubic {
     SkDCubic cubic;
     SkDQuad quad;
+    int answerCount;
+    SkDPoint answers[2];
 } quadCubicTests[] = {
+#if 0  // FIXME : this should not fail (root problem behind skpcarrot_is24 )
     {{{{1020.08099,672.161987}, {1020.08002,630.73999}, {986.502014,597.161987}, {945.080994,597.161987}}},
-     {{{1020,672}, {1020,640.93396}, {998.03302,618.96698}}}},
+     {{{1020,672}, {1020,640.93396}, {998.03302,618.96698}}}, 1,
+      {{1019.421, 662.449}}},
+#endif
 
     {{{{778, 14089}, {778, 14091.208984375}, {776.20916748046875, 14093}, {774, 14093}}},
-     {{{778, 14089}, {777.99957275390625, 14090.65625}, {776.82843017578125, 14091.828125}}}},
+     {{{778, 14089}, {777.99957275390625, 14090.65625}, {776.82843017578125, 14091.828125}}}, 2,
+     {{778, 14089}, {776.82855609581270,14091.828250841330}}},
 
     {{{{1110, 817}, {1110.55225f, 817}, {1111, 817.447693f}, {1111, 818}}},
-     {{{1110.70715f, 817.292908f}, {1110.41406f, 817.000122f}, {1110, 817}}}},
+     {{{1110.70715f, 817.292908f}, {1110.41406f, 817.000122f}, {1110, 817}}}, 2,
+      {{1110, 817}, {1110.70715f, 817.292908f}}},
 
     {{{{1110, 817}, {1110.55225f, 817}, {1111, 817.447693f}, {1111, 818}}},
-     {{{1111, 818}, {1110.99988f, 817.585876f}, {1110.70715f, 817.292908f}}}},
+     {{{1111, 818}, {1110.99988f, 817.585876f}, {1110.70715f, 817.292908f}}}, 2,
+      {{1110.70715f, 817.292908f}, {1111, 818}}},
 
     {{{{55, 207}, {52.238574981689453, 207}, {50, 204.76142883300781}, {50, 202}}},
      {{{55, 207}, {52.929431915283203, 206.99949645996094},
-       {51.464466094970703, 205.53553771972656}}}},
+       {51.464466094970703, 205.53553771972656}}}, 2,
+      {{55, 207}, {51.464466094970703, 205.53553771972656}}},
 
     {{{{49, 47}, {49, 74.614250183105469}, {26.614250183105469, 97}, {-1, 97}}},
      {{{-8.659739592076221e-015, 96.991401672363281}, {20.065492630004883, 96.645187377929688},
-       {34.355339050292969, 82.355339050292969}}}},
+       {34.355339050292969, 82.355339050292969}}}, 2,
+      {{34.355339050292969,82.355339050292969}, {34.28654835573549, 82.424006509351585}}},
 
     {{{{10,234}, {10,229.58172607421875}, {13.581720352172852,226}, {18,226}}},
-     {{{18,226}, {14.686291694641113,226}, {12.342399597167969,228.3424072265625}}}},
+     {{{18,226}, {14.686291694641113,226}, {12.342399597167969,228.3424072265625}}}, 1,
+      {{18,226}, {0,0}}},
 
     {{{{10,234}, {10,229.58172607421875}, {13.581720352172852,226}, {18,226}}},
-     {{{12.342399597167969,228.3424072265625}, {10,230.68629455566406}, {10,234}}}},
+     {{{12.342399597167969,228.3424072265625}, {10,230.68629455566406}, {10,234}}}, 1,
+      {{10,234}, {0,0}}},
 };
 
 static const int quadCubicTests_count = (int) SK_ARRAY_COUNT(quadCubicTests);
@@ -63,9 +75,9 @@
         SkDebugf("[%d] quad order=%d\n", iIndex, order2);
         REPORTER_ASSERT(reporter, 0);
     }
-    SkDCubic quadToCubic = quad.toCubic();
     SkIntersections i;
-    int roots = i.intersect(cubic, quadToCubic);
+    int roots = i.intersect(cubic, quad);
+    SkASSERT(roots == quadCubicTests[index].answerCount);
     for (int pt = 0; pt < roots; ++pt) {
         double tt1 = i[0][pt];
         SkDPoint xy1 = cubic.ptAtT(tt1);
@@ -76,6 +88,15 @@
                 __FUNCTION__, iIndex, pt, tt1, xy1.fX, xy1.fY, tt2, xy2.fX, xy2.fY);
         }
         REPORTER_ASSERT(reporter, xy1.approximatelyEqual(xy2));
+        bool found = false;
+        for (int idx2 = 0; idx2 < quadCubicTests[index].answerCount; ++idx2) {
+            found |= quadCubicTests[index].answers[idx2].approximatelyEqual(xy1);
+        }
+        if (!found) {
+            SkDebugf("%s [%d,%d] xy1=(%g,%g) != \n",
+                __FUNCTION__, iIndex, pt, xy1.fX, xy1.fY);
+        }
+        REPORTER_ASSERT(reporter, found);
     }
     reporter->bumpTestCount();
 }
@@ -90,3 +111,195 @@
 DEF_TEST(PathOpsCubicQuadIntersectionOneOff, reporter) {
     cubicQuadIntersection(reporter, 0);
 }
+
+static bool gPathOpCubicQuadSlopVerbose = false;
+static const int kCubicToQuadSubdivisionDepth = 8; // slots reserved for cubic to quads subdivision
+
+// determine that slop required after quad/quad finds a candidate intersection
+// use the cross of the tangents plus the distance from 1 or 0 as knobs
+DEF_TEST(PathOpsCubicQuadSlop, reporter) {
+    // create a random non-selfintersecting cubic
+    // break it into quadratics
+    // offset the quadratic, measuring the slop required to find the intersection
+    if (!gPathOpCubicQuadSlopVerbose) {  // takes a while to run -- so exclude it by default
+        return;
+    }
+    int results[101];
+    sk_bzero(results, sizeof(results));
+    double minCross[101];
+    sk_bzero(minCross, sizeof(minCross));
+    double maxCross[101];
+    sk_bzero(maxCross, sizeof(maxCross));
+    double sumCross[101];
+    sk_bzero(sumCross, sizeof(sumCross));
+    int foundOne = 0;
+    int slopCount = 1;
+    SkRandom ran;
+    for (int index = 0; index < 10000000; ++index) {
+        if (index % 1000 == 999) SkDebugf(".");
+        SkDCubic cubic = {{
+                {ran.nextRangeF(-1000, 1000), ran.nextRangeF(-1000, 1000)},
+                {ran.nextRangeF(-1000, 1000), ran.nextRangeF(-1000, 1000)},
+                {ran.nextRangeF(-1000, 1000), ran.nextRangeF(-1000, 1000)},
+                {ran.nextRangeF(-1000, 1000), ran.nextRangeF(-1000, 1000)}
+        }};
+        SkIntersections i;
+        if (i.intersect(cubic)) {
+            continue;
+        }
+        SkSTArray<kCubicToQuadSubdivisionDepth, double, true> ts;
+        cubic.toQuadraticTs(cubic.calcPrecision(), &ts);
+        double tStart = 0;
+        int tsCount = ts.count();
+        for (int i1 = 0; i1 <= tsCount; ++i1) {
+            const double tEnd = i1 < tsCount ? ts[i1] : 1;
+            SkDCubic part = cubic.subDivide(tStart, tEnd);
+            SkDQuad quad = part.toQuad();
+            SkReduceOrder reducer;
+            int order = reducer.reduce(quad);
+            if (order != 3) {
+                continue;
+            }
+            for (int i2 = 0; i2 < 100; ++i2) {
+                SkDPoint endDisplacement = {ran.nextRangeF(-100, 100), ran.nextRangeF(-100, 100)};
+                SkDQuad nearby = {{
+                        {quad[0].fX + endDisplacement.fX, quad[0].fY + endDisplacement.fY},
+                        {quad[1].fX + ran.nextRangeF(-100, 100), quad[1].fY + ran.nextRangeF(-100, 100)},
+                        {quad[2].fX - endDisplacement.fX, quad[2].fY - endDisplacement.fY}
+                }};
+                order = reducer.reduce(nearby);
+                if (order != 3) {
+                    continue;
+                }
+                SkIntersections locals;
+                locals.allowNear(false);
+                locals.intersect(quad, nearby);
+                if (locals.used() != 1) {
+                    continue;
+                }
+                // brute force find actual intersection
+                SkDLine cubicLine = {{ {0, 0}, {cubic[0].fX, cubic[0].fY } }};
+                SkIntersections liner;
+                int i3;
+                int found = -1;
+                int foundErr = true;
+                for (i3 = 1; i3 <= 1000; ++i3) {
+                    cubicLine[0] = cubicLine[1];
+                    cubicLine[1] = cubic.ptAtT(i3 / 1000.);
+                    liner.reset();
+                    liner.allowNear(false);
+                    liner.intersect(nearby, cubicLine);
+                    if (liner.used() == 0) {
+                        continue;
+                    }
+                    if (liner.used() > 1) {
+                        foundErr = true;
+                        break;
+                    }
+                    if (found > 0) {
+                        foundErr = true;
+                        break;
+                    }
+                    foundErr = false;
+                    found = i3;
+                }
+                if (foundErr) {
+                    continue;
+                }
+                SkDVector dist = liner.pt(0) - locals.pt(0);
+                SkDVector qV = nearby.dxdyAtT(locals[0][0]);
+                double cubicT = (found - 1 + liner[1][0]) / 1000.;
+                SkDVector cV = cubic.dxdyAtT(cubicT);
+                double qxc = qV.crossCheck(cV);
+                double qvLen = qV.length();
+                double cvLen = cV.length();
+                double maxLen = SkTMax(qvLen, cvLen);
+                qxc /= maxLen;
+                double quadT = tStart + (tEnd - tStart) * locals[0][0];
+                double diffT = fabs(cubicT - quadT);
+                int diffIdx = (int) (diffT * 100);
+                results[diffIdx]++;
+                double absQxc = fabs(qxc);
+                if (sumCross[diffIdx] == 0) {
+                    minCross[diffIdx] = maxCross[diffIdx] = sumCross[diffIdx] = absQxc;
+                } else {
+                    minCross[diffIdx] = SkTMin(minCross[diffIdx], absQxc);
+                    maxCross[diffIdx] = SkTMax(maxCross[diffIdx], absQxc);
+                    sumCross[diffIdx] +=  absQxc;
+                }
+                if (diffIdx >= 20) {
+#if 01
+                    SkDebugf("cubic={{{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}}}"
+                        " quad={{{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}}}"
+                        " {{{%1.9g,%1.9g}, {%1.9g,%1.9g}}}"
+                        " qT=%1.9g cT=%1.9g dist=%1.9g cross=%1.9g\n",
+                        cubic[0].fX, cubic[0].fY, cubic[1].fX, cubic[1].fY,
+                        cubic[2].fX, cubic[2].fY, cubic[3].fX, cubic[3].fY,
+                        nearby[0].fX, nearby[0].fY, nearby[1].fX, nearby[1].fY,
+                        nearby[2].fX, nearby[2].fY,
+                        liner.pt(0).fX, liner.pt(0).fY,
+                        locals.pt(0).fX, locals.pt(0).fY, quadT, cubicT, dist.length(), qxc);
+#else
+                    SkDebugf("qT=%1.9g cT=%1.9g dist=%1.9g cross=%1.9g\n",
+                        quadT, cubicT, dist.length(), qxc);
+                    SkDebugf("<div id=\"slop%d\">\n", ++slopCount);
+                    SkDebugf("{{{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}}}\n"
+                        "{{{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}}}\n"
+                        "{{{%1.9g,%1.9g}, {%1.9g,%1.9g}}}\n",
+                        cubic[0].fX, cubic[0].fY, cubic[1].fX, cubic[1].fY,
+                        cubic[2].fX, cubic[2].fY, cubic[3].fX, cubic[3].fY,
+                        nearby[0].fX, nearby[0].fY, nearby[1].fX, nearby[1].fY,
+                        nearby[2].fX, nearby[2].fY,
+                        liner.pt(0).fX, liner.pt(0).fY,
+                        locals.pt(0).fX, locals.pt(0).fY);
+                    SkDebugf("</div>\n\n");
+#endif
+                }
+                ++foundOne;
+            }
+            tStart = tEnd;
+        }
+        if (++foundOne >= 100000) {
+            break;
+        }
+    }
+#if 01
+    SkDebugf("slopCount=%d\n", slopCount);
+    int max = 100;
+    while (results[max] == 0) {
+        --max;
+    }
+    for (int i = 0; i <= max; ++i) {
+        if (i > 0 && i % 10 == 0) {
+            SkDebugf("\n");
+        }
+        SkDebugf("%d ", results[i]);
+    }
+    SkDebugf("min\n");
+    for (int i = 0; i <= max; ++i) {
+        if (i > 0 && i % 10 == 0) {
+            SkDebugf("\n");
+        }
+        SkDebugf("%1.9g ", minCross[i]);
+    }
+    SkDebugf("max\n");
+    for (int i = 0; i <= max; ++i) {
+        if (i > 0 && i % 10 == 0) {
+            SkDebugf("\n");
+        }
+        SkDebugf("%1.9g ", maxCross[i]);
+    }
+    SkDebugf("avg\n");
+    for (int i = 0; i <= max; ++i) {
+        if (i > 0 && i % 10 == 0) {
+            SkDebugf("\n");
+        }
+        SkDebugf("%1.9g ", sumCross[i] / results[i]);
+    }
+#else
+    for (int i = 1; i < slopCount; ++i) {
+        SkDebugf("        slop%d,\n", i);
+    }
+#endif
+    SkDebugf("\n");
+}
diff --git a/tests/PathOpsCubicToQuadsTest.cpp b/tests/PathOpsCubicToQuadsTest.cpp
new file mode 100644
index 0000000..ab22a83
--- /dev/null
+++ b/tests/PathOpsCubicToQuadsTest.cpp
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsCubicIntersectionTestData.h"
+#include "PathOpsQuadIntersectionTestData.h"
+#include "PathOpsTestCommon.h"
+#include "SkGeometry.h"
+#include "SkIntersections.h"
+#include "SkPathOpsRect.h"
+#include "SkReduceOrder.h"
+#include "Test.h"
+
+static void test(skiatest::Reporter* reporter, const SkDCubic* cubics, const char* name,
+                 int firstTest, size_t testCount) {
+    for (size_t index = firstTest; index < testCount; ++index) {
+        const SkDCubic& cubic = cubics[index];
+        SkASSERT(ValidCubic(cubic));
+        double precision = cubic.calcPrecision();
+        SkTArray<SkDQuad, true> quads;
+        CubicToQuads(cubic, precision, quads);
+        if (quads.count() != 1 && quads.count() != 2) {
+            SkDebugf("%s [%d] cubic to quadratics failed count=%d\n", name, static_cast<int>(index),
+                    quads.count());
+        }
+        REPORTER_ASSERT(reporter, quads.count() == 1);
+    }
+}
+
+static void test(skiatest::Reporter* reporter, const SkDQuad* quadTests, const char* name,
+                 int firstTest, size_t testCount) {
+    for (size_t index = firstTest; index < testCount; ++index) {
+        const SkDQuad& quad = quadTests[index];
+        SkASSERT(ValidQuad(quad));
+        SkDCubic cubic = quad.toCubic();
+        double precision = cubic.calcPrecision();
+        SkTArray<SkDQuad, true> quads;
+        CubicToQuads(cubic, precision, quads);
+        if (quads.count() != 1 && quads.count() != 2) {
+            SkDebugf("%s [%d] cubic to quadratics failed count=%d\n", name, static_cast<int>(index),
+                    quads.count());
+        }
+        REPORTER_ASSERT(reporter, quads.count() <= 2);
+    }
+}
+
+static void testC(skiatest::Reporter* reporter, const SkDCubic* cubics, const char* name,
+                  int firstTest, size_t testCount) {
+    // test if computed line end points are valid
+    for (size_t index = firstTest; index < testCount; ++index) {
+        const SkDCubic& cubic = cubics[index];
+        SkASSERT(ValidCubic(cubic));
+        double precision = cubic.calcPrecision();
+        SkTArray<SkDQuad, true> quads;
+        CubicToQuads(cubic, precision, quads);
+        if (!AlmostEqualUlps(cubic[0].fX, quads[0][0].fX)
+                || !AlmostEqualUlps(cubic[0].fY, quads[0][0].fY)) {
+            SkDebugf("[%d] unmatched start\n", static_cast<int>(index));
+            REPORTER_ASSERT(reporter, 0);
+        }
+        int last = quads.count() - 1;
+        if (!AlmostEqualUlps(cubic[3].fX, quads[last][2].fX)
+                || !AlmostEqualUlps(cubic[3].fY, quads[last][2].fY)) {
+            SkDebugf("[%d] unmatched end\n", static_cast<int>(index));
+            REPORTER_ASSERT(reporter, 0);
+        }
+    }
+}
+
+static void testC(skiatest::Reporter* reporter, const SkDCubic(* cubics)[2], const char* name,
+                  int firstTest, size_t testCount) {
+    for (size_t index = firstTest; index < testCount; ++index) {
+        for (int idx2 = 0; idx2 < 2; ++idx2) {
+            const SkDCubic& cubic = cubics[index][idx2];
+            SkASSERT(ValidCubic(cubic));
+            double precision = cubic.calcPrecision();
+            SkTArray<SkDQuad, true> quads;
+            CubicToQuads(cubic, precision, quads);
+            if (!AlmostEqualUlps(cubic[0].fX, quads[0][0].fX)
+                    || !AlmostEqualUlps(cubic[0].fY, quads[0][0].fY)) {
+                SkDebugf("[%d][%d] unmatched start\n", static_cast<int>(index), idx2);
+                REPORTER_ASSERT(reporter, 0);
+            }
+            int last = quads.count() - 1;
+            if (!AlmostEqualUlps(cubic[3].fX, quads[last][2].fX)
+                    || !AlmostEqualUlps(cubic[3].fY, quads[last][2].fY)) {
+                SkDebugf("[%d][%d] unmatched end\n", static_cast<int>(index), idx2);
+                REPORTER_ASSERT(reporter, 0);
+            }
+        }
+    }
+}
+
+DEF_TEST(CubicToQuads, reporter) {
+    enum {
+        RunAll,
+        RunPointDegenerates,
+        RunNotPointDegenerates,
+        RunLines,
+        RunNotLines,
+        RunModEpsilonLines,
+        RunLessEpsilonLines,
+        RunNegEpsilonLines,
+        RunQuadraticLines,
+        RunQuadraticModLines,
+        RunComputedLines,
+        RunComputedTests,
+        RunNone
+    } run = RunAll;
+    int firstTestIndex = 0;
+#if 0
+    run = RunComputedLines;
+    firstTestIndex = 18;
+#endif
+    int firstPointDegeneratesTest = run == RunAll ? 0 : run == RunPointDegenerates
+            ? firstTestIndex : SK_MaxS32;
+    int firstNotPointDegeneratesTest = run == RunAll ? 0 : run == RunNotPointDegenerates
+            ? firstTestIndex : SK_MaxS32;
+    int firstLinesTest = run == RunAll ? 0 : run == RunLines ? firstTestIndex : SK_MaxS32;
+    int firstNotLinesTest = run == RunAll ? 0 : run == RunNotLines ? firstTestIndex : SK_MaxS32;
+    int firstModEpsilonTest = run == RunAll ? 0 : run == RunModEpsilonLines
+            ? firstTestIndex : SK_MaxS32;
+    int firstLessEpsilonTest = run == RunAll ? 0 : run == RunLessEpsilonLines
+            ? firstTestIndex : SK_MaxS32;
+    int firstNegEpsilonTest = run == RunAll ? 0 : run == RunNegEpsilonLines
+            ? firstTestIndex : SK_MaxS32;
+    int firstQuadraticLineTest = run == RunAll ? 0 : run == RunQuadraticLines
+            ? firstTestIndex : SK_MaxS32;
+    int firstQuadraticModLineTest = run == RunAll ? 0 : run == RunQuadraticModLines
+            ? firstTestIndex : SK_MaxS32;
+    int firstComputedLinesTest = run == RunAll ? 0 : run == RunComputedLines
+            ? firstTestIndex : SK_MaxS32;
+    int firstComputedCubicsTest = run == RunAll ? 0 : run == RunComputedTests
+            ? firstTestIndex : SK_MaxS32;
+
+    test(reporter, pointDegenerates, "pointDegenerates", firstPointDegeneratesTest,
+            pointDegenerates_count);
+    testC(reporter, notPointDegenerates, "notPointDegenerates", firstNotPointDegeneratesTest,
+            notPointDegenerates_count);
+    test(reporter, lines, "lines", firstLinesTest, lines_count);
+    testC(reporter, notLines, "notLines", firstNotLinesTest, notLines_count);
+    testC(reporter, modEpsilonLines, "modEpsilonLines", firstModEpsilonTest, modEpsilonLines_count);
+    test(reporter, lessEpsilonLines, "lessEpsilonLines", firstLessEpsilonTest,
+            lessEpsilonLines_count);
+    test(reporter, negEpsilonLines, "negEpsilonLines", firstNegEpsilonTest, negEpsilonLines_count);
+    test(reporter, quadraticLines, "quadraticLines", firstQuadraticLineTest, quadraticLines_count);
+    test(reporter, quadraticModEpsilonLines, "quadraticModEpsilonLines", firstQuadraticModLineTest,
+            quadraticModEpsilonLines_count);
+    testC(reporter, lines, "computed lines", firstComputedLinesTest, lines_count);
+    testC(reporter, tests, "computed tests", firstComputedCubicsTest, tests_count);
+}
+
+static SkDCubic locals[] = {
+    {{{0, 1}, {1.9274705288631189e-19, 1.0000000000000002},
+            {0.0017190297609673323, 0.99828097023903239},
+            {0.0053709083094631276, 0.99505672974365911}}},
+    {{{14.5975863, 41.632436}, {16.3518929, 26.2639684}, {18.5165519, 7.68775139},
+            {8.03767257, 89.1628526}}},
+    {{{69.7292014, 38.6877352}, {24.7648688, 23.1501713}, {84.9283191, 90.2588441},
+            {80.392774, 61.3533852}}},
+    {{{60.776536520932126, 71.249307306133829}, {87.107894191103014, 22.377669868235323},
+            {1.4974754310666936, 68.069569937917208}, {45.261946574441133, 17.536076632112298}}},
+};
+
+static size_t localsCount = SK_ARRAY_COUNT(locals);
+
+#define DEBUG_CRASH 0
+#define TEST_AVERAGE_END_POINTS 0  // must take const off to test
+extern const bool AVERAGE_END_POINTS;
+
+static void oneOff(skiatest::Reporter* reporter, size_t x) {
+    const SkDCubic& cubic = locals[x];
+    SkASSERT(ValidCubic(cubic));
+    const SkPoint skcubic[4] = {
+            {static_cast<float>(cubic[0].fX), static_cast<float>(cubic[0].fY)},
+            {static_cast<float>(cubic[1].fX), static_cast<float>(cubic[1].fY)},
+            {static_cast<float>(cubic[2].fX), static_cast<float>(cubic[2].fY)},
+            {static_cast<float>(cubic[3].fX), static_cast<float>(cubic[3].fY)}};
+    SkScalar skinflect[2];
+    int skin = SkFindCubicInflections(skcubic, skinflect);
+    if (false) SkDebugf("%s %d %1.9g\n", __FUNCTION__, skin, skinflect[0]);
+    SkTArray<SkDQuad, true> quads;
+    double precision = cubic.calcPrecision();
+    CubicToQuads(cubic, precision, quads);
+    if (false) SkDebugf("%s quads=%d\n", __FUNCTION__, quads.count());
+}
+
+DEF_TEST(CubicsToQuadratics_OneOff_Loop, reporter) {
+    for (size_t x = 0; x < localsCount; ++x) {
+        oneOff(reporter, x);
+    }
+}
+
+DEF_TEST(CubicsToQuadratics_OneOff_Single, reporter) {
+    oneOff(reporter, 0);
+}
diff --git a/tests/PathOpsDLineTest.cpp b/tests/PathOpsDLineTest.cpp
index bfad134..dd86dd3 100644
--- a/tests/PathOpsDLineTest.cpp
+++ b/tests/PathOpsDLineTest.cpp
@@ -43,6 +43,10 @@
             SkDebugf("%s [%d] expected left\n", __FUNCTION__, index);
             REPORTER_ASSERT(reporter, 0);
         }
+        line2 = line.subDivide(1, 0);
+        REPORTER_ASSERT(reporter, line[0] == line2[1] && line[1] == line2[0]);
+        line2 = SkDLine::SubDivide(pts, 1, 0);
+        REPORTER_ASSERT(reporter, line[0] == line2[1] && line[1] == line2[0]);
         SkDPoint mid = line.ptAtT(.5);
         REPORTER_ASSERT(reporter, approximately_equal((line[0].fX + line[1].fX) / 2, mid.fX));
         REPORTER_ASSERT(reporter, approximately_equal((line[0].fY + line[1].fY) / 2, mid.fY));
diff --git a/tests/PathOpsDPointTest.cpp b/tests/PathOpsDPointTest.cpp
index e197d5d..186d691 100644
--- a/tests/PathOpsDPointTest.cpp
+++ b/tests/PathOpsDPointTest.cpp
@@ -38,6 +38,7 @@
         REPORTER_ASSERT(reporter, p == pt);
         REPORTER_ASSERT(reporter, p.approximatelyEqual(sPt));
         REPORTER_ASSERT(reporter, p.roughlyEqual(pt));
+        REPORTER_ASSERT(reporter, p.moreRoughlyEqual(pt));
         p.fX = p.fY = 0;
         REPORTER_ASSERT(reporter, p.fX == 0 && p.fY == 0);
         REPORTER_ASSERT(reporter, p.approximatelyZero());
diff --git a/tests/PathOpsDQuadTest.cpp b/tests/PathOpsDQuadTest.cpp
new file mode 100644
index 0000000..bd29ff1
--- /dev/null
+++ b/tests/PathOpsDQuadTest.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsTestCommon.h"
+#include "SkPath.h"
+#include "SkPathOpsQuad.h"
+#include "SkRRect.h"
+#include "Test.h"
+
+static const SkDQuad tests[] = {
+    {{{1, 1}, {2, 1}, {0, 2}}},
+    {{{0, 0}, {1, 1}, {3, 1}}},
+    {{{2, 0}, {1, 1}, {2, 2}}},
+    {{{4, 0}, {0, 1}, {4, 2}}},
+    {{{0, 0}, {0, 1}, {1, 1}}},
+};
+
+static const SkDPoint inPoint[]= {
+    {1,   1.2},
+    {1,   0.8},
+    {1.8, 1},
+    {1.5, 1},
+    {0.4999, 0.5},  // was 0.5, 0.5; points on the hull are considered outside
+};
+
+static const SkDPoint outPoint[]= {
+    {1,   1.6},
+    {1,   1.5},
+    {2.2, 1},
+    {1.5, 1.5},
+    {1.1, 0.5},
+};
+
+static const size_t tests_count = SK_ARRAY_COUNT(tests);
+
+DEF_TEST(PathOpsDQuad, reporter) {
+    for (size_t index = 0; index < tests_count; ++index) {
+        const SkDQuad& quad = tests[index];
+        SkASSERT(ValidQuad(quad));
+        bool result = quad.pointInHull(inPoint[index]);
+        if (!result) {
+            SkDebugf("%s [%d] expected in hull\n", __FUNCTION__, index);
+            REPORTER_ASSERT(reporter, 0);
+        }
+        result = quad.pointInHull(outPoint[index]);
+        if (result) {
+            SkDebugf("%s [%d] expected outside hull\n", __FUNCTION__, index);
+            REPORTER_ASSERT(reporter, 0);
+        }
+    }
+}
+
+DEF_TEST(PathOpsRRect, reporter) {
+    SkPath path;
+    SkRRect rRect;
+    SkRect rect = {135, 143, 250, 177};
+    SkVector radii[4] = {{8, 8}, {8, 8}, {0, 0}, {0, 0}};
+    rRect.setRectRadii(rect, radii);
+    path.addRRect(rRect);
+}
diff --git a/tests/PathOpsDRectTest.cpp b/tests/PathOpsDRectTest.cpp
index 70d39d1..874e82b 100644
--- a/tests/PathOpsDRectTest.cpp
+++ b/tests/PathOpsDRectTest.cpp
@@ -11,6 +11,15 @@
 #include "SkPathOpsRect.h"
 #include "Test.h"
 
+static const SkDLine lineTests[] = {
+    {{{2, 1}, {2, 1}}},
+    {{{2, 1}, {1, 1}}},
+    {{{2, 1}, {2, 2}}},
+    {{{1, 1}, {2, 2}}},
+    {{{3, 0}, {2, 1}}},
+    {{{3, 2}, {1, 1}}},
+};
+
 static const SkDQuad quadTests[] = {
     {{{1, 1}, {2, 1}, {0, 2}}},
     {{{0, 0}, {1, 1}, {3, 1}}},
@@ -25,31 +34,44 @@
     {{{3, 0}, {2, 1}, {3, 2}, {1, 1}}},
 };
 
+static const size_t lineTests_count = SK_ARRAY_COUNT(lineTests);
 static const size_t quadTests_count = SK_ARRAY_COUNT(quadTests);
 static const size_t cubicTests_count = SK_ARRAY_COUNT(cubicTests);
 
-static void setRawBounds(const SkDQuad& quad, SkDRect* rect) {
-    rect->set(quad[0]);
-    rect->add(quad[1]);
-    rect->add(quad[2]);
-}
-
-static void setRawBounds(const SkDCubic& cubic, SkDRect* rect) {
-    rect->set(cubic[0]);
-    rect->add(cubic[1]);
-    rect->add(cubic[2]);
-    rect->add(cubic[3]);
-}
-
 DEF_TEST(PathOpsDRect, reporter) {
     size_t index;
     SkDRect rect, rect2;
+    for (index = 0; index < lineTests_count; ++index) {
+        const SkDLine& line = lineTests[index];
+        SkASSERT(ValidLine(line));
+        rect.setBounds(line);
+        REPORTER_ASSERT(reporter, rect.fLeft == SkTMin(line[0].fX, line[1].fX));
+        REPORTER_ASSERT(reporter, rect.fTop == SkTMin(line[0].fY, line[1].fY));
+        REPORTER_ASSERT(reporter, rect.fRight == SkTMax(line[0].fX, line[1].fX));
+        REPORTER_ASSERT(reporter, rect.fBottom == SkTMax(line[0].fY, line[1].fY));
+        rect2.set(line[0]);
+        rect2.add(line[1]);
+        REPORTER_ASSERT(reporter, rect2.fLeft == SkTMin(line[0].fX, line[1].fX));
+        REPORTER_ASSERT(reporter, rect2.fTop == SkTMin(line[0].fY, line[1].fY));
+        REPORTER_ASSERT(reporter, rect2.fRight == SkTMax(line[0].fX, line[1].fX));
+        REPORTER_ASSERT(reporter, rect2.fBottom == SkTMax(line[0].fY, line[1].fY));
+        REPORTER_ASSERT(reporter, rect.contains(line[0]));
+        REPORTER_ASSERT(reporter, rect.intersects(&rect2));
+    }
     for (index = 0; index < quadTests_count; ++index) {
         const SkDQuad& quad = quadTests[index];
         SkASSERT(ValidQuad(quad));
-        setRawBounds(quad, &rect);
+        rect.setRawBounds(quad);
+        REPORTER_ASSERT(reporter, rect.fLeft == SkTMin(quad[0].fX,
+                SkTMin(quad[1].fX, quad[2].fX)));
+        REPORTER_ASSERT(reporter, rect.fTop == SkTMin(quad[0].fY,
+                SkTMin(quad[1].fY, quad[2].fY)));
+        REPORTER_ASSERT(reporter, rect.fRight == SkTMax(quad[0].fX,
+                SkTMax(quad[1].fX, quad[2].fX)));
+        REPORTER_ASSERT(reporter, rect.fBottom == SkTMax(quad[0].fY,
+                SkTMax(quad[1].fY, quad[2].fY)));
         rect2.setBounds(quad);
-        REPORTER_ASSERT(reporter, rect.intersects(rect2));
+        REPORTER_ASSERT(reporter, rect.intersects(&rect2));
         // FIXME: add a recursive box subdivision method to verify that tight bounds is correct
         SkDPoint leftTop = {rect2.fLeft, rect2.fTop};
         REPORTER_ASSERT(reporter, rect.contains(leftTop));
@@ -59,9 +81,17 @@
     for (index = 0; index < cubicTests_count; ++index) {
         const SkDCubic& cubic = cubicTests[index];
         SkASSERT(ValidCubic(cubic));
-        setRawBounds(cubic, &rect);
+        rect.setRawBounds(cubic);
+        REPORTER_ASSERT(reporter, rect.fLeft == SkTMin(cubic[0].fX,
+                SkTMin(cubic[1].fX, SkTMin(cubic[2].fX, cubic[3].fX))));
+        REPORTER_ASSERT(reporter, rect.fTop == SkTMin(cubic[0].fY,
+                SkTMin(cubic[1].fY, SkTMin(cubic[2].fY, cubic[3].fY))));
+        REPORTER_ASSERT(reporter, rect.fRight == SkTMax(cubic[0].fX,
+                SkTMax(cubic[1].fX, SkTMax(cubic[2].fX, cubic[3].fX))));
+        REPORTER_ASSERT(reporter, rect.fBottom == SkTMax(cubic[0].fY,
+                SkTMax(cubic[1].fY, SkTMax(cubic[2].fY, cubic[3].fY))));
         rect2.setBounds(cubic);
-        REPORTER_ASSERT(reporter, rect.intersects(rect2));
+        REPORTER_ASSERT(reporter, rect.intersects(&rect2));
         // FIXME: add a recursive box subdivision method to verify that tight bounds is correct
         SkDPoint leftTop = {rect2.fLeft, rect2.fTop};
         REPORTER_ASSERT(reporter, rect.contains(leftTop));
diff --git a/tests/PathOpsDTriangleTest.cpp b/tests/PathOpsDTriangleTest.cpp
new file mode 100644
index 0000000..b5e2d41
--- /dev/null
+++ b/tests/PathOpsDTriangleTest.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsTestCommon.h"
+#include "SkPathOpsTriangle.h"
+#include "Test.h"
+
+static const SkDTriangle tests[] = {
+    {{{2, 0}, {3, 1}, {2, 2}}},
+    {{{3, 1}, {2, 2}, {1, 1}}},
+    {{{3, 0}, {2, 1}, {3, 2}}},
+};
+
+static const SkDPoint inPoint[] = {
+    {2.5, 1},
+    {2, 1.5},
+    {2.5, 1},
+};
+
+static const SkDPoint outPoint[] = {
+    {3, 0},
+    {2.5, 2},
+    {2.5, 2},
+};
+
+static const size_t tests_count = SK_ARRAY_COUNT(tests);
+
+DEF_TEST(PathOpsTriangleUtilities, reporter) {
+    for (size_t index = 0; index < tests_count; ++index) {
+        const SkDTriangle& triangle = tests[index];
+        SkASSERT(ValidTriangle(triangle));
+        bool result = triangle.contains(inPoint[index]);
+        if (!result) {
+            SkDebugf("%s [%d] expected point in triangle\n", __FUNCTION__, index);
+            REPORTER_ASSERT(reporter, 0);
+        }
+        result = triangle.contains(outPoint[index]);
+        if (result) {
+            SkDebugf("%s [%d] expected point outside triangle\n", __FUNCTION__, index);
+            REPORTER_ASSERT(reporter, 0);
+        }
+    }
+}
+
+static const SkDTriangle oneOff[] = {
+    {{{271.03291625750461, 5.0402503630087025e-05}, {275.21652430019037, 3.6997300650817753},
+      {279.25839233398438, 7.7416000366210938}}},
+
+    {{{271.03291625750461, 5.0402503617874572e-05}, {275.21652430019037, 3.6997300650817877},
+      {279.25839233398438, 7.7416000366210938}}}
+};
+
+static const size_t oneOff_count = SK_ARRAY_COUNT(oneOff);
+
+DEF_TEST(PathOpsTriangleOneOff, reporter) {
+    for (size_t index = 0; index < oneOff_count; ++index) {
+        const SkDTriangle& triangle = oneOff[index];
+        SkASSERT(ValidTriangle(triangle));
+        for (int inner = 0; inner < 3; ++inner) {
+            bool result = triangle.contains(triangle.fPts[inner]);
+            if (result) {
+                SkDebugf("%s [%d][%d] point on triangle is not in\n", __FUNCTION__, index, inner);
+                REPORTER_ASSERT(reporter, 0);
+            }
+        }
+    }
+}
diff --git a/tests/PathOpsDebug.cpp b/tests/PathOpsDebug.cpp
index 9930453..c4fbbfa 100755
--- a/tests/PathOpsDebug.cpp
+++ b/tests/PathOpsDebug.cpp
@@ -1,12 +1,3 @@
-/*
- * Copyright 2014 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "PathOpsTSectDebug.h"
-#include "SkOpCoincidence.h"
 #include "SkOpContour.h"
 #include "SkIntersectionHelper.h"
 #include "SkOpSegment.h"
@@ -59,6 +50,7 @@
             SkDebugf(", ");
         }
     }
+    SkDebugf(");\n");
 }
 
 static void showPathContours(SkPath::RawIter& iter, const char* pathName) {
@@ -69,27 +61,18 @@
             case SkPath::kMove_Verb:
                 SkDebugf("    %s.moveTo(", pathName);
                 output_points(&pts[0], 1);
-                SkDebugf(");\n");
                 continue;
             case SkPath::kLine_Verb:
                 SkDebugf("    %s.lineTo(", pathName);
                 output_points(&pts[1], 1);
-                SkDebugf(");\n");
                 break;
             case SkPath::kQuad_Verb:
                 SkDebugf("    %s.quadTo(", pathName);
                 output_points(&pts[1], 2);
-                SkDebugf(");\n");
-                break;
-            case SkPath::kConic_Verb:
-                SkDebugf("    %s.conicTo(", pathName);
-                output_points(&pts[1], 2);
-                SkDebugf(", %1.9gf);\n", iter.conicWeight());
                 break;
             case SkPath::kCubic_Verb:
                 SkDebugf("    %s.cubicTo(", pathName);
                 output_points(&pts[1], 3);
-                SkDebugf(");\n");
                 break;
             case SkPath::kClose_Verb:
                 SkDebugf("    %s.close();\n", pathName);
@@ -185,35 +168,228 @@
 }
 #endif
 
+void SkOpAngle::dump() const {
+    dumpOne(true);
+    SkDebugf("\n");
+}
+
+void SkOpAngle::dumpOne(bool functionHeader) const {
+//    fSegment->debugValidate();
+    const SkOpSpan& mSpan = fSegment->span(SkMin32(fStart, fEnd));
+    if (functionHeader) {
+        SkDebugf("%s ", __FUNCTION__);
+    }
+    SkDebugf("[%d", fSegment->debugID());
+    SkDebugf("/%d", debugID());
+    SkDebugf("] next=");
+    if (fNext) {
+        SkDebugf("%d", fNext->fSegment->debugID());
+        SkDebugf("/%d", fNext->debugID());
+    } else {
+        SkDebugf("?");
+    }
+    SkDebugf(" sect=%d/%d ", fSectorStart, fSectorEnd);
+    SkDebugf(" s=%1.9g [%d] e=%1.9g [%d]", fSegment->span(fStart).fT, fStart,
+            fSegment->span(fEnd).fT, fEnd);
+    SkDebugf(" sgn=%d windVal=%d", sign(), mSpan.fWindValue);
+
+    SkDebugf(" windSum=");
+    SkPathOpsDebug::WindingPrintf(mSpan.fWindSum);
+    if (mSpan.fOppValue != 0 || mSpan.fOppSum != SK_MinS32) {
+        SkDebugf(" oppVal=%d", mSpan.fOppValue);
+        SkDebugf(" oppSum=");
+        SkPathOpsDebug::WindingPrintf(mSpan.fOppSum);
+    }
+    if (mSpan.fDone) {
+        SkDebugf(" done");
+    }
+    if (unorderable()) {
+        SkDebugf(" unorderable");
+    }
+    if (small()) {
+        SkDebugf(" small");
+    }
+    if (mSpan.fTiny) {
+        SkDebugf(" tiny");
+    }
+    if (fSegment->operand()) {
+        SkDebugf(" operand");
+    }
+    if (fStop) {
+        SkDebugf(" stop");
+    }
+}
+
+void SkOpAngle::dumpTo(const SkOpSegment* segment, const SkOpAngle* to) const {
+    const SkOpAngle* first = this;
+    const SkOpAngle* next = this;
+    const char* indent = "";
+    do {
+        SkDebugf("%s", indent);
+        next->dumpOne(false);
+        if (segment == next->fSegment) {
+            if (this == fNext) {
+                SkDebugf(" << from");
+            }
+            if (to == fNext) {
+                SkDebugf(" << to");
+            }
+        }
+        SkDebugf("\n");
+        indent = "           ";
+        next = next->fNext;
+    } while (next && next != first);
+}
+
+void SkOpAngle::dumpLoop() const {
+    const SkOpAngle* first = this;
+    const SkOpAngle* next = this;
+    do {
+        next->dumpOne(false);
+        SkDebugf("\n");
+        next = next->fNext;
+    } while (next && next != first);
+}
+
+void SkOpAngle::dumpPartials() const {
+    const SkOpAngle* first = this;
+    const SkOpAngle* next = this;
+    do {
+        next->fCurvePart.dumpNumber();
+        next = next->fNext;
+    } while (next && next != first);
+}
+
+void SkOpAngleSet::dump() const {
+    // FIXME: unimplemented
+/* This requires access to the internal SkChunkAlloc data
+   Defer implementing this until it is needed for debugging
+*/
+    SkASSERT(0);
+}
+
+void SkOpContour::dump() const {
+    int segmentCount = fSegments.count();
+    SkDebugf("((SkOpContour*) 0x%p) [%d]\n", this, debugID());
+    for (int test = 0; test < segmentCount; ++test) {
+        SkDebugf("  [%d] ((SkOpSegment*) 0x%p) [%d]\n", test, &fSegments[test],
+                fSegments[test].debugID());
+    }
+}
+
+void SkOpContour::dumpAngles() const {
+    int segmentCount = fSegments.count();
+    SkDebugf("((SkOpContour*) 0x%p) [%d]\n", this, debugID());
+    for (int test = 0; test < segmentCount; ++test) {
+        SkDebugf("  [%d] ", test);
+        fSegments[test].dumpAngles();
+    }
+}
+
+void SkOpContour::dumpCoincidence(const SkCoincidence& coin) const {
+    int thisIndex = coin.fSegments[0];
+    const SkOpSegment& s1 = fSegments[thisIndex];
+    int otherIndex = coin.fSegments[1];
+    const SkOpSegment& s2 = coin.fOther->fSegments[otherIndex];
+    SkDebugf("((SkOpSegment*) 0x%p) [%d]  ((SkOpSegment*) 0x%p) [%d]\n", &s1, s1.debugID(),
+            &s2, s2.debugID());
+    for (int index = 0; index < 2; ++index) {
+        SkDebugf("    {%1.9gf, %1.9gf}", coin.fPts[0][index].fX, coin.fPts[0][index].fY);
+        if (coin.fNearly[index]) {
+            SkDebugf("    {%1.9gf, %1.9gf}", coin.fPts[1][index].fX, coin.fPts[1][index].fY);
+        }
+        SkDebugf("  seg1t=%1.9g seg2t=%1.9g\n", coin.fTs[0][index], coin.fTs[1][index]);
+    }
+}
+
+void SkOpContour::dumpCoincidences() const {
+    int count = fCoincidences.count();
+    if (count > 0) {
+        SkDebugf("fCoincidences count=%d\n", count);
+        for (int test = 0; test < count; ++test) {
+            dumpCoincidence(fCoincidences[test]);
+        }
+    }
+    count = fPartialCoincidences.count();
+    if (count == 0) {
+        return;
+    }
+    SkDebugf("fPartialCoincidences count=%d\n", count);
+    for (int test = 0; test < count; ++test) {
+        dumpCoincidence(fPartialCoincidences[test]);
+    }
+}
+
+void SkOpContour::dumpPt(int index) const {
+    int segmentCount = fSegments.count();
+    for (int test = 0; test < segmentCount; ++test) {
+        const SkOpSegment& segment = fSegments[test];
+        if (segment.debugID() == index) {
+            fSegments[test].dumpPts();
+        }
+    }
+}
+
+void SkOpContour::dumpPts() const {
+    int segmentCount = fSegments.count();
+    SkDebugf("((SkOpContour*) 0x%p) [%d]\n", this, debugID());
+    for (int test = 0; test < segmentCount; ++test) {
+        SkDebugf("  [%d] ", test);
+        fSegments[test].dumpPts();
+    }
+}
+
+void SkOpContour::dumpSpan(int index) const {
+    int segmentCount = fSegments.count();
+    for (int test = 0; test < segmentCount; ++test) {
+        const SkOpSegment& segment = fSegments[test];
+        if (segment.debugID() == index) {
+            fSegments[test].dumpSpans();
+        }
+    }
+}
+
+void SkOpContour::dumpSpans() const {
+    int segmentCount = fSegments.count();
+    SkDebugf("((SkOpContour*) 0x%p) [%d]\n", this, debugID());
+    for (int test = 0; test < segmentCount; ++test) {
+        SkDebugf("  [%d] ", test);
+        fSegments[test].dumpSpans();
+    }
+}
+
 void SkDCubic::dump() const {
-    dumpInner();
-    SkDebugf("}},\n");
-}
-
-void SkDCubic::dumpID(int id) const {
-    dumpInner();
-    SkDebugf("}} id=%d\n", id);
-}
-
-static inline bool double_is_NaN(double x) { return x != x; }
-
-void SkDCubic::dumpInner() const {
     SkDebugf("{{");
     int index = 0;
     do {
-        if (index != 0) {
-            if (double_is_NaN(fPts[index].fX) && double_is_NaN(fPts[index].fY)) {
-                return;
-            }
+        fPts[index].dump();
+        SkDebugf(", ");
+    } while (++index < 3);
+    fPts[index].dump();
+    SkDebugf("}}\n");
+}
+
+void SkDCubic::dumpNumber() const {
+    SkDebugf("{{");
+    int index = 0;
+    bool dumpedOne = false;
+    do {
+        if (!(fPts[index].fX == fPts[index].fX && fPts[index].fY == fPts[index].fY)) {
+            continue;
+        }
+        if (dumpedOne) {
             SkDebugf(", ");
         }
         fPts[index].dump();
+        dumpedOne = true;
     } while (++index < 3);
-    if (double_is_NaN(fPts[index].fX) && double_is_NaN(fPts[index].fY)) {
-        return;
+    if (fPts[index].fX == fPts[index].fX && fPts[index].fY == fPts[index].fY) {
+        if (dumpedOne) {
+            SkDebugf(", ");
+        }
+        fPts[index].dump();
     }
-    SkDebugf(", ");
-    fPts[index].dump();
+    SkDebugf("}}\n");
 }
 
 void SkDLine::dump() const {
@@ -221,7 +397,7 @@
     fPts[0].dump();
     SkDebugf(", ");
     fPts[1].dump();
-    SkDebugf("}},\n");
+    SkDebugf("}}\n");
 }
 
 void SkDPoint::dump() const {
@@ -249,16 +425,10 @@
 }
 
 void SkDQuad::dump() const {
-    dumpInner();
-    SkDebugf("}},\n");
+    dumpComma("");
 }
 
-void SkDQuad::dumpID(int id) const {
-    dumpInner();
-    SkDebugf("}} id=%d\n", id);
-}
-
-void SkDQuad::dumpInner() const {
+void SkDQuad::dumpComma(const char* comma) const {
     SkDebugf("{{");
     int index = 0;
     do {
@@ -266,262 +436,436 @@
         SkDebugf(", ");
     } while (++index < 2);
     fPts[index].dump();
+    SkDebugf("}}%s\n", comma ? comma : "");
 }
 
-void SkIntersections::dump() const {
-    SkDebugf("used=%d of %d", fUsed, fMax);
-    for (int index = 0; index < fUsed; ++index) {
-        SkDebugf(" t=(%s%1.9g,%s%1.9g) pt=(%1.9g,%1.9g)",
-                fIsCoincident[0] & (1 << index) ? "*" : "", fT[0][index],
-                fIsCoincident[1] & (1 << index) ? "*" : "", fT[1][index],
-                fPt[index].fX, fPt[index].fY);
-        if (index < 2 && fNearlySame[index]) {
-            SkDebugf(" pt2=(%1.9g,%1.9g)",fPt2[index].fX, fPt2[index].fY);
+void SkIntersectionHelper::dump() const {
+    SkDPoint::Dump(pts()[0]);
+    SkDPoint::Dump(pts()[1]);
+    if (verb() >= SkPath::kQuad_Verb) {
+        SkDPoint::Dump(pts()[2]);
+    }
+    if (verb() >= SkPath::kCubic_Verb) {
+        SkDPoint::Dump(pts()[3]);
+    }
+}
+
+const SkTDArray<SkOpSpan>& SkOpSegment::debugSpans() const {
+    return fTs;
+}
+
+void SkOpSegment::dumpAngles() const {
+    SkDebugf("((SkOpSegment*) 0x%p) [%d]\n", this, debugID());
+    const SkOpAngle* fromAngle = NULL;
+    const SkOpAngle* toAngle = NULL;
+    for (int index = 0; index < count(); ++index) {
+        const SkOpAngle* fAngle = fTs[index].fFromAngle;
+        const SkOpAngle* tAngle = fTs[index].fToAngle;
+        if (fromAngle == fAngle && toAngle == tAngle) {
+            continue;
         }
+        if (fAngle) {
+            SkDebugf("  [%d] from=%d ", index, fAngle->debugID());
+            fAngle->dumpTo(this, tAngle);
+        }
+        if (tAngle) {
+            SkDebugf("  [%d] to=%d   ", index, tAngle->debugID());
+            tAngle->dumpTo(this, fAngle);
+        }
+        fromAngle = fAngle;
+        toAngle = tAngle;
+    }
+}
+
+void SkOpSegment::dumpContour(int firstID, int lastID) const {
+    if (debugID() < 0) {
+        return;
+    }
+    const SkOpSegment* test = this - (debugID() - 1);
+    test += (firstID - 1);
+    const SkOpSegment* last = test + (lastID - firstID);
+    while (test <= last) {
+        test->dumpSpans();
+        ++test;
+    }
+}
+
+void SkOpSegment::dumpPts() const {
+    int last = SkPathOpsVerbToPoints(fVerb);
+    SkDebugf("((SkOpSegment*) 0x%p) [%d] {{", this, debugID());
+    int index = 0;
+    do {
+        SkDPoint::Dump(fPts[index]);
+        SkDebugf(", ");
+    } while (++index < last);
+    SkDPoint::Dump(fPts[index]);
+    SkDebugf("}}\n");
+}
+
+void SkOpSegment::dumpHexPts() const {
+    int last = SkPathOpsVerbToPoints(fVerb);
+    SkDebugf("((SkOpSegment*) 0x%p) [%d] {{", this, debugID());
+    int index = 0;
+    do {
+        SkDPoint::DumpHex(fPts[index]);
+        SkDebugf(", ");
+    } while (++index < last);
+    SkDPoint::DumpHex(fPts[index]);
+    SkDebugf("}}\n");
+}
+
+void SkOpSegment::dumpDPts() const {
+    int count = SkPathOpsVerbToPoints(fVerb);
+    SkDebugf("((SkOpSegment*) 0x%p) [%d] {{", this, debugID());
+    int index = 0;
+    do {
+        SkDPoint dPt = {fPts[index].fX, fPts[index].fY};
+        dPt.dump();
+        if (index != count) {
+            SkDebugf(", ");
+        }
+    } while (++index <= count);
+    SkDebugf("}}\n");
+}
+
+void SkOpSegment::dumpSpans() const {
+    int count = this->count();
+    SkDebugf("((SkOpSegment*) 0x%p) [%d]\n", this, debugID());
+    for (int index = 0; index < count; ++index) {
+        const SkOpSpan& span = this->span(index);
+        SkDebugf("  [%d] ", index);
+        span.dumpOne();
+    }
+}
+
+void SkPathOpsDebug::DumpCoincidence(const SkTArray<SkOpContour, true>& contours) {
+    int count = contours.count();
+    for (int index = 0; index < count; ++index) {
+        contours[index].dumpCoincidences();
+    }
+}
+
+void SkPathOpsDebug::DumpCoincidence(const SkTArray<SkOpContour* , true>& contours) {
+    int count = contours.count();
+    for (int index = 0; index < count; ++index) {
+        contours[index]->dumpCoincidences();
+    }
+}
+
+void SkPathOpsDebug::DumpContours(const SkTArray<SkOpContour, true>& contours) {
+    int count = contours.count();
+    for (int index = 0; index < count; ++index) {
+        contours[index].dump();
+    }
+}
+
+void SkPathOpsDebug::DumpContours(const SkTArray<SkOpContour* , true>& contours) {
+    int count = contours.count();
+    for (int index = 0; index < count; ++index) {
+        contours[index]->dump();
+    }
+}
+
+void SkPathOpsDebug::DumpContourAngles(const SkTArray<SkOpContour, true>& contours) {
+    int count = contours.count();
+    for (int index = 0; index < count; ++index) {
+        contours[index].dumpAngles();
+    }
+}
+
+void SkPathOpsDebug::DumpContourAngles(const SkTArray<SkOpContour* , true>& contours) {
+    int count = contours.count();
+    for (int index = 0; index < count; ++index) {
+        contours[index]->dumpAngles();
+    }
+}
+
+void SkPathOpsDebug::DumpContourPts(const SkTArray<SkOpContour, true>& contours) {
+    int count = contours.count();
+    for (int index = 0; index < count; ++index) {
+        contours[index].dumpPts();
+    }
+}
+
+void SkPathOpsDebug::DumpContourPts(const SkTArray<SkOpContour* , true>& contours) {
+    int count = contours.count();
+    for (int index = 0; index < count; ++index) {
+        contours[index]->dumpPts();
+    }
+}
+
+void SkPathOpsDebug::DumpContourPt(const SkTArray<SkOpContour, true>& contours, int segmentID) {
+    int count = contours.count();
+    for (int index = 0; index < count; ++index) {
+        contours[index].dumpPt(segmentID);
+    }
+}
+
+void SkPathOpsDebug::DumpContourPt(const SkTArray<SkOpContour* , true>& contours, int segmentID) {
+    int count = contours.count();
+    for (int index = 0; index < count; ++index) {
+        contours[index]->dumpPt(segmentID);
+    }
+}
+
+void SkPathOpsDebug::DumpContourSpans(const SkTArray<SkOpContour, true>& contours) {
+    int count = contours.count();
+    for (int index = 0; index < count; ++index) {
+        contours[index].dumpSpans();
+    }
+}
+
+void SkPathOpsDebug::DumpContourSpans(const SkTArray<SkOpContour* , true>& contours) {
+    int count = contours.count();
+    for (int index = 0; index < count; ++index) {
+        contours[index]->dumpSpans();
+    }
+}
+
+void SkPathOpsDebug::DumpContourSpan(const SkTArray<SkOpContour, true>& contours, int segmentID) {
+    int count = contours.count();
+    for (int index = 0; index < count; ++index) {
+        contours[index].dumpSpan(segmentID);
+    }
+}
+
+void SkPathOpsDebug::DumpContourSpan(const SkTArray<SkOpContour* , true>& contours, int segmentID) {
+    int count = contours.count();
+    for (int index = 0; index < count; ++index) {
+        contours[index]->dumpSpan(segmentID);
+    }
+}
+
+void SkPathOpsDebug::DumpSpans(const SkTDArray<SkOpSpan *>& spans) {
+    int count = spans.count();
+    for (int index = 0; index < count; ++index) {
+        const SkOpSpan* span = spans[index];
+        const SkOpSpan& oSpan = span->fOther->span(span->fOtherIndex);
+        const SkOpSegment* segment = oSpan.fOther;
+        SkDebugf("((SkOpSegment*) 0x%p) [%d] ", segment, segment->debugID());
+        SkDebugf("spanIndex:%d ", oSpan.fOtherIndex);
+        span->dumpOne();
+    }
+}
+
+// this does not require that other T index is initialized or correct
+const SkOpSegment* SkOpSpan::debugToSegment(ptrdiff_t* spanIndex) const {
+    if (!fOther) {
+        return NULL;
+    }
+    int oppCount = fOther->count();
+    for (int index = 0; index < oppCount; ++index) {
+        const SkOpSpan& otherSpan = fOther->span(index);
+        double otherTestT = otherSpan.fT;
+        if (otherTestT < fOtherT) {
+            continue;
+        }
+        SkASSERT(otherTestT == fOtherT);
+        const SkOpSegment* candidate = otherSpan.fOther;
+        const SkOpSpan* first = candidate->debugSpans().begin();
+        const SkOpSpan* last = candidate->debugSpans().end() - 1;
+        if (first <= this && this <= last) {
+            if (spanIndex) {
+                *spanIndex = this - first;
+            }
+            return candidate;
+        }
+    }
+    SkASSERT(0);
+    return NULL;
+}
+
+void SkOpSpan::dumpOne() const {
+    SkDebugf("t=");
+    DebugDumpDouble(fT);
+    SkDebugf(" pt=");
+    SkDPoint::Dump(fPt);
+    if (fOther) {
+        SkDebugf(" other.fID=%d", fOther->debugID());
+        SkDebugf(" [%d] otherT=", fOtherIndex);
+        DebugDumpDouble(fOtherT);
+    } else {
+        SkDebugf(" other.fID=? [?] otherT=?");
+    }
+    if (fWindSum != SK_MinS32) {
+        SkDebugf(" windSum=%d", fWindSum);
+    }
+    if (fOppSum != SK_MinS32 && (SkPathOpsDebug::ValidWind(fOppSum) || fOppValue != 0)) {
+        SkDebugf(" oppSum=%d", fOppSum);
+    }
+    SkDebugf(" windValue=%d", fWindValue);
+    if (SkPathOpsDebug::ValidWind(fOppSum) || fOppValue != 0) {
+        SkDebugf(" oppValue=%d", fOppValue);
+    }
+    if (fFromAngle && fFromAngle->debugID()) {
+        SkDebugf(" from=%d", fFromAngle->debugID());
+    }
+    if (fToAngle && fToAngle->debugID()) {
+        SkDebugf(" to=%d", fToAngle->debugID());
+    }
+    if (fChased) {
+        SkDebugf(" chased");
+    }
+    if (fCoincident) {
+        SkDebugf(" coincident");
+    }
+    if (fDone) {
+        SkDebugf(" done");
+    }
+    if (fLoop) {
+        SkDebugf(" loop");
+    }
+    if (fMultiple) {
+        SkDebugf(" multiple");
+    }
+    if (fNear) {
+        SkDebugf(" near");
+    }
+    if (fSmall) {
+        SkDebugf(" small");
+    }
+    if (fTiny) {
+        SkDebugf(" tiny");
     }
     SkDebugf("\n");
 }
 
-const SkOpAngle* SkPathOpsDebug::DebugAngleAngle(const SkOpAngle* angle, int id) {
-    return angle->debugAngle(id);
-}
-
-SkOpContour* SkPathOpsDebug::DebugAngleContour(SkOpAngle* angle, int id) {
-    return angle->debugContour(id);
-}
-
-const SkOpPtT* SkPathOpsDebug::DebugAnglePtT(const SkOpAngle* angle, int id) {
-    return angle->debugPtT(id);
-}
-
-const SkOpSegment* SkPathOpsDebug::DebugAngleSegment(const SkOpAngle* angle, int id) {
-    return angle->debugSegment(id);
-}
-
-const SkOpSpanBase* SkPathOpsDebug::DebugAngleSpan(const SkOpAngle* angle, int id) {
-    return angle->debugSpan(id);
-}
-
-const SkOpAngle* SkPathOpsDebug::DebugContourAngle(SkOpContour* contour, int id) {
-    return contour->debugAngle(id);
-}
-
-SkOpContour* SkPathOpsDebug::DebugContourContour(SkOpContour* contour, int id) {
-    return contour->debugContour(id);
-}
-
-const SkOpPtT* SkPathOpsDebug::DebugContourPtT(SkOpContour* contour, int id) {
-    return contour->debugPtT(id);
-}
-
-const SkOpSegment* SkPathOpsDebug::DebugContourSegment(SkOpContour* contour, int id) {
-    return contour->debugSegment(id);
-}
-
-const SkOpSpanBase* SkPathOpsDebug::DebugContourSpan(SkOpContour* contour, int id) {
-    return contour->debugSpan(id);
-}
-
-const SkOpAngle* SkPathOpsDebug::DebugPtTAngle(const SkOpPtT* ptT, int id) {
-    return ptT->debugAngle(id);
-}
-
-SkOpContour* SkPathOpsDebug::DebugPtTContour(SkOpPtT* ptT, int id) {
-    return ptT->debugContour(id);
-}
-
-const SkOpPtT* SkPathOpsDebug::DebugPtTPtT(const SkOpPtT* ptT, int id) {
-    return ptT->debugPtT(id);
-}
-
-const SkOpSegment* SkPathOpsDebug::DebugPtTSegment(const SkOpPtT* ptT, int id) {
-    return ptT->debugSegment(id);
-}
-
-const SkOpSpanBase* SkPathOpsDebug::DebugPtTSpan(const SkOpPtT* ptT, int id) {
-    return ptT->debugSpan(id);
-}
-
-const SkOpAngle* SkPathOpsDebug::DebugSegmentAngle(const SkOpSegment* span, int id) {
-    return span->debugAngle(id);
-}
-
-SkOpContour* SkPathOpsDebug::DebugSegmentContour(SkOpSegment* span, int id) {
-    return span->debugContour(id);
-}
-
-const SkOpPtT* SkPathOpsDebug::DebugSegmentPtT(const SkOpSegment* span, int id) {
-    return span->debugPtT(id);
-}
-
-const SkOpSegment* SkPathOpsDebug::DebugSegmentSegment(const SkOpSegment* span, int id) {
-    return span->debugSegment(id);
-}
-
-const SkOpSpanBase* SkPathOpsDebug::DebugSegmentSpan(const SkOpSegment* span, int id) {
-    return span->debugSpan(id);
-}
-
-const SkOpAngle* SkPathOpsDebug::DebugSpanAngle(const SkOpSpanBase* span, int id) {
-    return span->debugAngle(id);
-}
-
-SkOpContour* SkPathOpsDebug::DebugSpanContour(SkOpSpanBase* span, int id) {
-    return span->debugContour(id);
-}
-
-const SkOpPtT* SkPathOpsDebug::DebugSpanPtT(const SkOpSpanBase* span, int id) {
-    return span->debugPtT(id);
-}
-
-const SkOpSegment* SkPathOpsDebug::DebugSpanSegment(const SkOpSpanBase* span, int id) {
-    return span->debugSegment(id);
-}
-
-const SkOpSpanBase* SkPathOpsDebug::DebugSpanSpan(const SkOpSpanBase* span, int id) {
-    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 SkOpSpan::dump() const {
+    ptrdiff_t spanIndex;
+    const SkOpSegment* segment = debugToSegment(&spanIndex);
+    if (segment) {
+        SkDebugf("((SkOpSegment*) 0x%p) [%d]\n", segment, segment->debugID());
+        SkDebugf("  [%d] ", spanIndex);
+    } else {
+        SkDebugf("((SkOpSegment*) ?) [?]\n");
+        SkDebugf("  [?] ");
     }
+    dumpOne();
 }
 
-void SkPathOpsDebug::DumpContoursAll(SkTDArray<SkOpContour* >* contours) {
-    int count = contours->count();
-    for (int index = 0; index < count; ++index) {
-        (*contours)[index]->dumpAll();
-    }
+void Dump(const SkTArray<class SkOpContour, true>& contours) {
+    SkPathOpsDebug::DumpContours(contours);
 }
 
-void SkPathOpsDebug::DumpContoursAngles(const SkTDArray<SkOpContour* >* contours) {
-    int count = contours->count();
-    for (int index = 0; index < count; ++index) {
-        (*contours)[index]->dumpAngles();
-    }
+void Dump(const SkTArray<class SkOpContour* , true>& contours) {
+    SkPathOpsDebug::DumpContours(contours);
 }
 
-void SkPathOpsDebug::DumpContoursPts(const SkTDArray<SkOpContour* >* contours) {
-    int count = contours->count();
-    for (int index = 0; index < count; ++index) {
-        (*contours)[index]->dumpPts();
-    }
+void Dump(const SkTArray<class SkOpContour, true>* contours) {
+    SkPathOpsDebug::DumpContours(*contours);
 }
 
-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 Dump(const SkTArray<class SkOpContour* , true>* contours) {
+    SkPathOpsDebug::DumpContours(*contours);
 }
 
-void SkPathOpsDebug::DumpContoursSegment(const SkTDArray<SkOpContour* >* contours,
-        int segmentID) {
-    if (contours->count()) {
-        (*contours)[0]->dumpSegment(segmentID);
-    }
+void Dump(const SkTDArray<SkOpSpan *>& chase) {
+    SkPathOpsDebug::DumpSpans(chase);
 }
 
-void SkPathOpsDebug::DumpContoursSpan(const SkTDArray<SkOpContour* >* contours,
-        int spanID) {
-    if (contours->count()) {
-        (*contours)[0]->dumpSpan(spanID);
-    }
+void Dump(const SkTDArray<SkOpSpan *>* chase) {
+    SkPathOpsDebug::DumpSpans(*chase);
 }
 
-void SkPathOpsDebug::DumpContoursSpans(const SkTDArray<SkOpContour* >* contours) {
-    int count = contours->count();
-    for (int index = 0; index < count; ++index) {
-        (*contours)[index]->dumpSpans();
-    }
+void DumpAngles(const SkTArray<class SkOpContour, true>& contours) {
+    SkPathOpsDebug::DumpContourAngles(contours);
 }
 
-const SkTSpan<SkDCubic>* DebugSpan(const SkTSect<SkDCubic>* sect, int id) {
-    return sect->debugSpan(id);
+void DumpAngles(const SkTArray<class SkOpContour* , true>& contours) {
+    SkPathOpsDebug::DumpContourAngles(contours);
 }
 
-const SkTSpan<SkDQuad>* DebugSpan(const SkTSect<SkDQuad>* sect, int id) {
-    return sect->debugSpan(id);
+void DumpAngles(const SkTArray<class SkOpContour, true>* contours) {
+    SkPathOpsDebug::DumpContourAngles(*contours);
 }
 
-const SkTSpan<SkDCubic>* DebugT(const SkTSect<SkDCubic>* sect, double t) {
-    return sect->debugT(t);
+void DumpAngles(const SkTArray<class SkOpContour* , true>* contours) {
+    SkPathOpsDebug::DumpContourAngles(*contours);
 }
 
-const SkTSpan<SkDQuad>* DebugT(const SkTSect<SkDQuad>* sect, double t) {
-    return sect->debugT(t);
+void DumpCoin(const SkTArray<class SkOpContour, true>& contours) {
+    SkPathOpsDebug::DumpCoincidence(contours);
 }
 
-const SkTSpan<SkDCubic>* DebugSpan(const SkTSpan<SkDCubic>* span, int id) {
-    return span->debugSpan(id);
+void DumpCoin(const SkTArray<class SkOpContour* , true>& contours) {
+    SkPathOpsDebug::DumpCoincidence(contours);
 }
 
-const SkTSpan<SkDQuad>* DebugSpan(const SkTSpan<SkDQuad>* span, int id) {
-    return span->debugSpan(id);
+void DumpCoin(const SkTArray<class SkOpContour, true>* contours) {
+    SkPathOpsDebug::DumpCoincidence(*contours);
 }
 
-const SkTSpan<SkDCubic>* DebugT(const SkTSpan<SkDCubic>* span, double t) {
-    return span->debugT(t);
+void DumpCoin(const SkTArray<class SkOpContour* , true>* contours) {
+    SkPathOpsDebug::DumpCoincidence(*contours);
 }
 
-const SkTSpan<SkDQuad>* DebugT(const SkTSpan<SkDQuad>* span, double t) {
-    return span->debugT(t);
+void DumpSpans(const SkTArray<class SkOpContour, true>& contours) {
+    SkPathOpsDebug::DumpContourSpans(contours);
 }
 
-void Dump(const SkTSect<SkDCubic>* sect) {
-    sect->dump();
+void DumpSpans(const SkTArray<class SkOpContour* , true>& contours) {
+    SkPathOpsDebug::DumpContourSpans(contours);
 }
 
-void Dump(const SkTSect<SkDQuad>* sect) {
-    sect->dump();
+void DumpSpans(const SkTArray<class SkOpContour, true>* contours) {
+    SkPathOpsDebug::DumpContourSpans(*contours);
 }
 
-void Dump(const SkTSpan<SkDCubic>* span) {
-    span->dump();
+void DumpSpans(const SkTArray<class SkOpContour* , true>* contours) {
+    SkPathOpsDebug::DumpContourSpans(*contours);
 }
 
-void Dump(const SkTSpan<SkDQuad>* span) {
-    span->dump();
+void DumpSpan(const SkTArray<class SkOpContour, true>& contours, int segmentID) {
+    SkPathOpsDebug::DumpContourSpan(contours, segmentID);
 }
 
-void DumpBoth(SkTSect<SkDCubic>* sect1, SkTSect<SkDCubic>* sect2) {
-    sect1->dumpBoth(sect2);
+void DumpSpan(const SkTArray<class SkOpContour* , true>& contours, int segmentID) {
+    SkPathOpsDebug::DumpContourSpan(contours, segmentID);
 }
 
-void DumpBoth(SkTSect<SkDQuad>* sect1, SkTSect<SkDQuad>* sect2) {
-    sect1->dumpBoth(sect2);
+void DumpSpan(const SkTArray<class SkOpContour, true>* contours, int segmentID) {
+    SkPathOpsDebug::DumpContourSpan(*contours, segmentID);
 }
 
-void DumpCoin(SkTSect<SkDCubic>* sect1) {
-    sect1->dumpCoin();
+void DumpSpan(const SkTArray<class SkOpContour* , true>* contours, int segmentID) {
+    SkPathOpsDebug::DumpContourSpan(*contours, segmentID);
 }
 
-void DumpCoin(SkTSect<SkDQuad>* sect1) {
-    sect1->dumpCoin();
+void DumpPts(const SkTArray<class SkOpContour, true>& contours) {
+    SkPathOpsDebug::DumpContourPts(contours);
 }
 
-void DumpCoinCurves(SkTSect<SkDCubic>* sect1) {
-    sect1->dumpCoinCurves();
+void DumpPts(const SkTArray<class SkOpContour* , true>& contours) {
+    SkPathOpsDebug::DumpContourPts(contours);
 }
 
-void DumpCoinCurves(SkTSect<SkDQuad>* sect1) {
-    sect1->dumpCoinCurves();
+void DumpPts(const SkTArray<class SkOpContour, true>* contours) {
+    SkPathOpsDebug::DumpContourPts(*contours);
 }
 
-void DumpCurves(const SkTSect<SkDQuad>* sect) {
-    sect->dumpCurves();
+void DumpPts(const SkTArray<class SkOpContour* , true>* contours) {
+    SkPathOpsDebug::DumpContourPts(*contours);
 }
 
-void DumpCurves(const SkTSect<SkDCubic>* sect) {
-    sect->dumpCurves();
+void DumpPt(const SkTArray<class SkOpContour, true>& contours, int segmentID) {
+    SkPathOpsDebug::DumpContourPt(contours, segmentID);
+}
+
+void DumpPt(const SkTArray<class SkOpContour* , true>& contours, int segmentID) {
+    SkPathOpsDebug::DumpContourPt(contours, segmentID);
+}
+
+void DumpPt(const SkTArray<class SkOpContour, true>* contours, int segmentID) {
+    SkPathOpsDebug::DumpContourPt(*contours, segmentID);
+}
+
+void DumpPt(const SkTArray<class SkOpContour* , true>* contours, int segmentID) {
+    SkPathOpsDebug::DumpContourPt(*contours, segmentID);
 }
 
 static void dumpTestCase(const SkDQuad& quad1, const SkDQuad& quad2, int testNo) {
-    SkDebugf("\n<div id=\"quad%d\">\n", testNo);
-    quad1.dumpInner();
-    SkDebugf("}}, ");
+    SkDebugf("<div id=\"quad%d\">\n", testNo);
+    quad1.dumpComma(",");
     quad2.dump();
     SkDebugf("</div>\n\n");
 }
@@ -551,649 +895,3 @@
     SkDLine line = {{quad.ptAtT(t), quad[0]}};
     line.dump();
 }
-
-const SkOpAngle* SkOpAngle::debugAngle(int id) const {
-    return this->segment()->debugAngle(id);
-}
-
-SkOpContour* SkOpAngle::debugContour(int id) {
-    return this->segment()->debugContour(id);
-}
-
-const SkOpPtT* SkOpAngle::debugPtT(int id) const {
-    return this->segment()->debugPtT(id);
-}
-
-const SkOpSegment* SkOpAngle::debugSegment(int id) const {
-    return this->segment()->debugSegment(id);
-}
-
-const SkOpSpanBase* SkOpAngle::debugSpan(int id) const {
-    return this->segment()->debugSpan(id);
-}
-
-void SkOpAngle::dump() const {
-    dumpOne(true);
-    SkDebugf("\n");
-}
-
-void SkOpAngle::dumpOne(bool functionHeader) const {
-//    fSegment->debugValidate();
-    const SkOpSegment* segment = this->segment();
-    const SkOpSpan& mSpan = *fStart->starter(fEnd);
-    if (functionHeader) {
-        SkDebugf("%s ", __FUNCTION__);
-    }
-    SkDebugf("[%d", segment->debugID());
-    SkDebugf("/%d", debugID());
-    SkDebugf("] next=");
-    if (fNext) {
-        SkDebugf("%d", fNext->fStart->segment()->debugID());
-        SkDebugf("/%d", fNext->debugID());
-    } else {
-        SkDebugf("?");
-    }
-    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(" windSum=");
-    SkPathOpsDebug::WindingPrintf(mSpan.windSum());
-    if (mSpan.oppValue() != 0 || mSpan.oppSum() != SK_MinS32) {
-        SkDebugf(" oppVal=%d", mSpan.oppValue());
-        SkDebugf(" oppSum=");
-        SkPathOpsDebug::WindingPrintf(mSpan.oppSum());
-    }
-    if (mSpan.done()) {
-        SkDebugf(" done");
-    }
-    if (unorderable()) {
-        SkDebugf(" unorderable");
-    }
-    if (segment->operand()) {
-        SkDebugf(" operand");
-    }
-    if (fStop) {
-        SkDebugf(" stop");
-    }
-}
-
-void SkOpAngle::dumpTo(const SkOpSegment* segment, const SkOpAngle* to) const {
-    const SkOpAngle* first = this;
-    const SkOpAngle* next = this;
-    const char* indent = "";
-    do {
-        SkDebugf("%s", indent);
-        next->dumpOne(false);
-        if (segment == next->fStart->segment()) {
-            if (this == fNext) {
-                SkDebugf(" << from");
-            }
-            if (to == fNext) {
-                SkDebugf(" << to");
-            }
-        }
-        SkDebugf("\n");
-        indent = "           ";
-        next = next->fNext;
-    } while (next && next != first);
-}
-
-void SkOpAngle::dumpCurves() const {
-    const SkOpAngle* first = this;
-    const SkOpAngle* next = this;
-    do {
-        next->fCurvePart.dumpID(next->segment()->debugID());
-        next = next->fNext;
-    } while (next && next != first);
-}
-
-void SkOpAngle::dumpLoop() const {
-    const SkOpAngle* first = this;
-    const SkOpAngle* next = this;
-    do {
-        next->dumpOne(false);
-        SkDebugf("\n");
-        next = next->fNext;
-    } while (next && next != first);
-}
-
-void SkOpAngle::dumpTest() const {
-    const SkOpAngle* first = this;
-    const SkOpAngle* next = this;
-    do {
-        SkDebugf("{ ");
-        SkOpSegment* segment = next->segment();
-        segment->dumpPts();
-        SkDebugf(", %d, %1.9g, %1.9g, {} },\n", SkPathOpsVerbToPoints(segment->verb()) + 1,
-                next->start()->t(), next->end()->t());
-        next = next->fNext;
-    } while (next && next != first);
-}
-
-bool SkOpPtT::debugMatchID(int id) const {
-    int limit = this->debugLoopLimit(false);
-    int loop = 0;
-    const SkOpPtT* ptT = this;
-    do {
-        if (ptT->debugID() == id) {
-            return true;
-        }
-    } while ((!limit || ++loop <= limit) && (ptT = ptT->next()) && ptT != this);
-    return false;
-}
-
-const SkOpAngle* SkOpPtT::debugAngle(int id) const {
-    return this->span()->debugAngle(id);
-}
-
-SkOpContour* SkOpPtT::debugContour(int id) {
-    return this->span()->debugContour(id);
-}
-
-const SkOpPtT* SkOpPtT::debugPtT(int id) const {
-    return this->span()->debugPtT(id);
-}
-
-const SkOpSegment* SkOpPtT::debugSegment(int id) const {
-    return this->span()->debugSegment(id);
-}
-
-const SkOpSpanBase* SkOpPtT::debugSpan(int id) const {
-    return this->span()->debugSpan(id);
-}
-
-void SkOpPtT::dump() const {
-    SkDebugf("seg=%d span=%d ptT=%d",
-            this->segment()->debugID(), this->span()->debugID(), this->debugID());
-    this->dumpBase();
-    SkDebugf("\n");
-}
-
-void SkOpPtT::dumpAll() const {
-    contour()->indentDump();
-    const SkOpPtT* next = this;
-    int limit = debugLoopLimit(true);
-    int loop = 0;
-    do {
-        SkDebugf("%.*s", contour()->debugIndent(), "        ");
-        SkDebugf("seg=%d span=%d ptT=%d",
-                next->segment()->debugID(), next->span()->debugID(), next->debugID());
-        next->dumpBase();
-        SkDebugf("\n");
-        if (limit && ++loop >= limit) {
-            SkDebugf("*** abort loop ***\n");
-            break;
-        }
-    } while ((next = next->fNext) && next != this);
-    contour()->outdentDump();
-}
-
-void SkOpPtT::dumpBase() const {
-    SkDebugf(" t=%1.9g pt=(%1.9g,%1.9g)%s%s", this->fT, this->fPt.fX, this->fPt.fY,
-            this->fDuplicatePt ? " dup" : "", this->fDeleted ? " deleted" : "");
-}
-
-const SkOpAngle* SkOpSpanBase::debugAngle(int id) const {
-    return this->segment()->debugAngle(id);
-}
-
-SkOpContour* SkOpSpanBase::debugContour(int id) {
-    return this->segment()->debugContour(id);
-}
-
-const SkOpPtT* SkOpSpanBase::debugPtT(int id) const {
-    return this->segment()->debugPtT(id);
-}
-
-const SkOpSegment* SkOpSpanBase::debugSegment(int id) const {
-    return this->segment()->debugSegment(id);
-}
-
-const SkOpSpanBase* SkOpSpanBase::debugSpan(int id) const {
-    return this->segment()->debugSpan(id);
-}
-
-void SkOpSpanBase::dump() const {
-    this->dumpAll();
-    SkDebugf("\n");
-}
-
-void SkOpSpanBase::dumpAll() const {
-    SkDebugf("%.*s", contour()->debugIndent(), "        ");
-    SkDebugf("seg=%d span=%d", this->segment()->debugID(), this->debugID());
-    this->dumpBase();
-    SkDebugf("\n");
-    this->fPtT.dumpAll();
-}
-
-void SkOpSpanBase::dumpBase() const {
-    if (this->fAligned) {
-        SkDebugf(" aligned");
-    }
-    if (this->fChased) {
-        SkDebugf(" chased");
-    }
-    if (!this->final()) {
-        this->upCast()->dumpSpan();
-    }
-    const SkOpSpanBase* coin = this->coinEnd();
-    if (this != coin) {
-        SkDebugf(" coinEnd seg/span=%d/%d", coin->segment()->debugID(), coin->debugID());
-    } else if (this->final() || !this->upCast()->isCoincident()) {
-        const SkOpPtT* oPt = this->ptT()->next();
-        SkDebugf(" seg/span=%d/%d", oPt->segment()->debugID(), oPt->span()->debugID());
-    }
-}
-
-void SkOpSpanBase::dumpCoin() const {
-    const SkOpSpan* span = this->upCastable();
-    if (!span) {
-        return;
-    }
-    if (!span->isCoincident()) {
-        return;
-    }
-    span->dumpCoin();
-}
-
-void SkOpSpan::dumpCoin() const {
-    const SkOpSpan* coincident = fCoincident;
-    bool ok = debugCoinLoopCheck();
-    this->dump();
-    int loop = 0;
-    do {
-        coincident->dump();
-        if (!ok && ++loop > 10) {
-            SkDebugf("*** abort loop ***\n");
-            break;
-        }
-    } while ((coincident = coincident->fCoincident) != this);
-}
-
-bool SkOpSpan::dumpSpan() const {
-    SkOpSpan* coin = fCoincident;
-    if (this != coin) {
-        SkDebugf(" coinStart seg/span=%d/%d", coin->segment()->debugID(), coin->debugID());
-    }
-    SkDebugf(" windVal=%d", this->windValue());
-    SkDebugf(" windSum=");
-    SkPathOpsDebug::WindingPrintf(this->windSum());
-    if (this->oppValue() != 0 || this->oppSum() != SK_MinS32) {
-        SkDebugf(" oppVal=%d", this->oppValue());
-        SkDebugf(" oppSum=");
-        SkPathOpsDebug::WindingPrintf(this->oppSum());
-    }
-    if (this->done()) {
-        SkDebugf(" done");
-    }
-    return this != coin;
-}
-
-const SkOpAngle* SkOpSegment::debugAngle(int id) const {
-    return this->contour()->debugAngle(id);
-}
-
-SkOpContour* SkOpSegment::debugContour(int id) {
-    return this->contour()->debugContour(id);
-}
-
-const SkOpPtT* SkOpSegment::debugPtT(int id) const {
-    return this->contour()->debugPtT(id);
-}
-
-const SkOpSegment* SkOpSegment::debugSegment(int id) const {
-    return this->contour()->debugSegment(id);
-}
-
-const SkOpSpanBase* SkOpSegment::debugSpan(int id) const {
-    return this->contour()->debugSpan(id);
-}
-
-void SkOpSegment::dump() const {
-    SkDebugf("%.*s", contour()->debugIndent(), "        ");
-    this->dumpPts();
-    const SkOpSpanBase* span = &fHead;
-    contour()->indentDump();
-    do {
-        SkDebugf("%.*s span=%d ", contour()->debugIndent(), "        ", span->debugID());
-        span->ptT()->dumpBase();
-        span->dumpBase();
-        SkDebugf("\n");
-    } while (!span->final() && (span = span->upCast()->next()));
-    contour()->outdentDump();
-}
-
-void SkOpSegment::dumpAll() const {
-    SkDebugf("%.*s", contour()->debugIndent(), "        ");
-    this->dumpPts();
-    const SkOpSpanBase* span = &fHead;
-    contour()->indentDump();
-    do {
-        span->dumpAll();
-    } while (!span->final() && (span = span->upCast()->next()));
-    contour()->outdentDump();
-}
-
-void SkOpSegment::dumpAngles() const {
-    SkDebugf("seg=%d\n", debugID());
-    const SkOpSpanBase* span = &fHead;
-    do {
-        const SkOpAngle* fAngle = span->fromAngle();
-        const SkOpAngle* tAngle = span->final() ? NULL : span->upCast()->toAngle();
-        if (fAngle) {
-            SkDebugf("  span=%d from=%d ", span->debugID(), fAngle->debugID());
-            fAngle->dumpTo(this, tAngle);
-        }
-        if (tAngle) {
-            SkDebugf("  span=%d to=%d   ", span->debugID(), tAngle->debugID());
-            tAngle->dumpTo(this, fAngle);
-        }
-    } while (!span->final() && (span = span->upCast()->next()));
-}
-
-void SkOpSegment::dumpCoin() const {
-    const SkOpSpan* span = &fHead;
-    do {
-        span->dumpCoin();
-    } while ((span = span->next()->upCastable()));
-}
-
-void SkOpSegment::dumpPts() const {
-    int last = SkPathOpsVerbToPoints(fVerb);
-    SkDebugf("seg=%d {{", this->debugID());
-    int index = 0;
-    do {
-        SkDPoint::Dump(fPts[index]);
-        SkDebugf(", ");
-    } while (++index < last);
-    SkDPoint::Dump(fPts[index]);
-    SkDebugf("}}\n");
-}
-
-void SkCoincidentSpans::dump() const {
-    SkDebugf("- seg=%d span=%d ptT=%d ", fCoinPtTStart->segment()->debugID(),
-        fCoinPtTStart->span()->debugID(), fCoinPtTStart->debugID());
-    fCoinPtTStart->dumpBase();
-    SkDebugf(" span=%d ptT=%d ", fCoinPtTEnd->span()->debugID(), fCoinPtTEnd->debugID());
-    fCoinPtTEnd->dumpBase();
-    if (fCoinPtTStart->segment()->operand()) {
-        SkDebugf(" operand");
-    }
-    if (fCoinPtTStart->segment()->isXor()) {
-        SkDebugf(" xor");
-    }
-    SkDebugf("\n");
-    SkDebugf("+ seg=%d span=%d ptT=%d ", fOppPtTStart->segment()->debugID(),
-        fOppPtTStart->span()->debugID(), fOppPtTStart->debugID());
-    fOppPtTStart->dumpBase();
-    SkDebugf(" span=%d ptT=%d ", fOppPtTEnd->span()->debugID(), fOppPtTEnd->debugID());
-    fOppPtTEnd->dumpBase();
-    if (fOppPtTStart->segment()->operand()) {
-        SkDebugf(" operand");
-    }
-    if (fOppPtTStart->segment()->isXor()) {
-        SkDebugf(" xor");
-    }
-    SkDebugf("\n");
-}
-
-void SkOpCoincidence::dump() const {
-    SkCoincidentSpans* span = fHead;
-    while (span) {
-        span->dump();
-        span = span->fNext;
-    }
-}
-
-void SkOpContour::dump() {
-    SkDebugf("contour=%d count=%d\n", this->debugID(), fCount);
-    if (!fCount) {
-        return;
-    }
-    const SkOpSegment* segment = &fHead;
-    PATH_OPS_DEBUG_CODE(fIndent = 0);
-    indentDump();
-    do {
-        segment->dump();
-    } while ((segment = segment->next()));
-    outdentDump();
-}
-
-void SkOpContour::dumpAll() {
-    SkDebugf("contour=%d count=%d\n", this->debugID(), fCount);
-    if (!fCount) {
-        return;
-    }
-    const SkOpSegment* segment = &fHead;
-    PATH_OPS_DEBUG_CODE(fIndent = 0);
-    indentDump();
-    do {
-        segment->dumpAll();
-    } while ((segment = segment->next()));
-    outdentDump();
-}
-
-
-void SkOpContour::dumpAngles() const {
-    SkDebugf("contour=%d\n", this->debugID());
-    const SkOpSegment* segment = &fHead;
-    do {
-        SkDebugf("  seg=%d ", segment->debugID());
-        segment->dumpAngles();
-    } while ((segment = segment->next()));
-}
-
-void SkOpContour::dumpPt(int index) const {
-    const SkOpSegment* segment = &fHead;
-    do {
-        if (segment->debugID() == index) {
-            segment->dumpPts();
-        }
-    } while ((segment = segment->next()));
-}
-
-void SkOpContour::dumpPts() const {
-    SkDebugf("contour=%d\n", this->debugID());
-    const SkOpSegment* segment = &fHead;
-    do {
-        SkDebugf("  seg=%d ", segment->debugID());
-        segment->dumpPts();
-    } while ((segment = segment->next()));
-}
-
-void SkOpContour::dumpPtsX() const {
-    if (!this->fCount) {
-        SkDebugf("<empty>\n");
-        return;
-    }
-    const SkOpSegment* segment = &fHead;
-    do {
-        segment->dumpPts();
-    } while ((segment = segment->next()));
-}
-
-void SkOpContour::dumpSegment(int index) const {
-    debugSegment(index)->dump();
-}
-
-void SkOpContour::dumpSegments(SkPathOp op) const {
-    bool firstOp = false;
-    const SkOpContour* c = this;
-    do {
-        if (!firstOp && c->operand()) {
-#if DEBUG_ACTIVE_OP
-            SkDebugf("op %s\n", SkPathOpsDebug::kPathOpStr[op]);
-#endif
-            firstOp = true;
-        }
-        c->dumpPtsX();
-    } while ((c = c->next()));
-}
-
-void SkOpContour::dumpSpan(int index) const {
-    debugSpan(index)->dump();
-}
-
-void SkOpContour::dumpSpans() const {
-    SkDebugf("contour=%d\n", this->debugID());
-    const SkOpSegment* segment = &fHead;
-    do {
-        SkDebugf("  seg=%d ", segment->debugID());
-        segment->dump();
-    } while ((segment = segment->next()));
-}
-
-#ifdef SK_DEBUG
-const SkOpAngle* SkOpGlobalState::debugAngle(int id) const {
-    const SkOpContour* contour = fHead;
-    do {
-        const SkOpSegment* segment = contour->first();
-        while (segment) {
-            const SkOpSpan* span = segment->head();
-            do {
-                SkOpAngle* angle = span->fromAngle();
-                if (angle && angle->debugID() == id) {
-                    return angle;
-                }
-                angle = span->toAngle();
-                if (angle && angle->debugID() == id) {
-                    return angle;
-                }
-            } while ((span = span->next()->upCastable()));
-            const SkOpSpanBase* tail = segment->tail();
-            SkOpAngle* angle = tail->fromAngle();
-            if (angle && angle->debugID() == id) {
-                return angle;
-            }
-            segment = segment->next();
-        }
-    } while ((contour = contour->next()));
-    return NULL;
-}
-
-SkOpContour* SkOpGlobalState::debugContour(int id) {
-    SkOpContour* contour = fHead;
-    do {
-        if (contour->debugID() == id) {
-            return contour;
-        }
-    } while ((contour = contour->next()));
-    return NULL;
-}
-
-const SkOpPtT* SkOpGlobalState::debugPtT(int id) const {
-    const SkOpContour* contour = fHead;
-    do {
-        const SkOpSegment* segment = contour->first();
-        while (segment) {
-            const SkOpSpan* span = segment->head();
-            do {
-                const SkOpPtT* ptT = span->ptT();
-                if (ptT->debugMatchID(id)) {
-                    return ptT;
-                }
-            } while ((span = span->next()->upCastable()));
-            const SkOpSpanBase* tail = segment->tail();
-            const SkOpPtT* ptT = tail->ptT();
-            if (ptT->debugMatchID(id)) {
-                return ptT;
-            }
-            segment = segment->next();
-        }
-    } while ((contour = contour->next()));
-    return NULL;
-}
-
-const SkOpSegment* SkOpGlobalState::debugSegment(int id) const {
-    const SkOpContour* contour = fHead;
-    do {
-        const SkOpSegment* segment = contour->first();
-        while (segment) {
-            if (segment->debugID() == id) {
-                return segment;
-            }
-            segment = segment->next();
-        }
-    } while ((contour = contour->next()));
-    return NULL;
-}
-
-const SkOpSpanBase* SkOpGlobalState::debugSpan(int id) const {
-    const SkOpContour* contour = fHead;
-    do {
-        const SkOpSegment* segment = contour->first();
-        while (segment) {
-            const SkOpSpan* span = segment->head();
-            do {
-                if (span->debugID() == id) {
-                    return span;
-                }
-            } while ((span = span->next()->upCastable()));
-            const SkOpSpanBase* tail = segment->tail();
-            if (tail->debugID() == id) {
-                return tail;
-            }
-            segment = segment->next();
-        }
-    } while ((contour = contour->next()));
-    return NULL;
-}
-#endif
-
-const SkOpAngle* DebugAngle(const SkTArray<SkOpContour*, true>* contours, int id) {
-    return (*contours)[0]->debugAngle(id);
-}
-
-SkOpContour* DumpContour(const SkTArray<SkOpContour*, true>* contours, int id) {
-    return (*contours)[0]->debugContour(id);
-}
-
-const SkOpPtT* DebugPtT(const SkTArray<SkOpContour*, true>* contours, int id) {
-    return (*contours)[0]->debugPtT(id);
-}
-
-const SkOpSegment* DebugSegment(const SkTArray<SkOpContour*, true>* contours, int id) {
-    return (*contours)[0]->debugSegment(id);
-}
-
-const SkOpSpanBase* DebugSpan(const SkTArray<SkOpContour*, true>* 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 4a806c2..e0d30ba 100644
--- a/tests/PathOpsExtendedTest.cpp
+++ b/tests/PathOpsExtendedTest.cpp
@@ -24,7 +24,6 @@
 __SK_FORCE_IMAGE_DECODER_LINKING;
 
 DEFINE_bool2(runFail, f, false, "run tests known to fail.");
-DEFINE_bool2(runBinary, f, false, "run tests known to fail binary sect.");
 
 static const char marker[] =
     "</div>\n"
@@ -48,6 +47,10 @@
     "o",
 };
 
+static bool gShowPath = false;
+static bool gComparePathsAssert = true;
+static bool gPathStrAssert = true;
+
 #if DEBUG_SHOW_TEST_NAME
 static void showPathData(const SkPath& path) {
     SkPath::RawIter iter(path);
@@ -79,13 +82,6 @@
                 lastPt = pts[2];
                 lastPtSet = true;
                 break;
-            case SkPath::kConic_Verb:
-                SkDebugf("{{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}},  //weight=%1.9g\n",
-                        pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY,
-                        iter.conicWeight());
-                lastPt = pts[2];
-                lastPtSet = true;
-                break;
             case SkPath::kCubic_Verb:
                 SkDebugf("{{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}},\n",
                         pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY,
@@ -277,7 +273,7 @@
     return true;
 }
 
-int comparePaths(skiatest::Reporter* reporter, const char* filename, const SkPath& one,
+static int comparePaths(skiatest::Reporter* reporter, const char* filename, const SkPath& one,
         const SkPath& two, SkBitmap& bitmap) {
     int errors2x2;
     SkPath scaledOne, scaledTwo;
@@ -286,6 +282,7 @@
         return 0;
     }
     const int MAX_ERRORS = 9;
+    REPORTER_ASSERT(reporter, errors2x2 <= MAX_ERRORS || !gComparePathsAssert);
     return errors2x2 > MAX_ERRORS ? errors2x2 : 0;
 }
 
@@ -306,7 +303,7 @@
     *gTestOp.append() = shapeOp;
     ++gTestNo;
     SkDebugf("    SkPath path, pathB;\n");
-#if 0 && DEBUG_SHOW_TEST_NAME
+#if DEBUG_SHOW_TEST_NAME
     SkPathOpsDebug::ShowOnePath(a, "path", false);
     SkPathOpsDebug::ShowOnePath(b, "pathB", false);
 #endif
@@ -337,14 +334,17 @@
         return 0;
     }
     if (errors2x2 == 0) {
+        if (gShowPath) {
+            showPathOpPath(testName, one, two, a, b, scaledOne, scaledTwo, shapeOp, scale);
+        }
         return 0;
     }
-    if (errors2x2 > MAX_ERRORS) {
+    if (errors2x2 > MAX_ERRORS && gComparePathsAssert) {
         SkAutoMutexAcquire autoM(compareDebugOut3);
         SkDebugf("\n*** this test fails ***\n");
         showPathOpPath(testName, one, two, a, b, scaledOne, scaledTwo, shapeOp, scale);
         REPORTER_ASSERT(reporter, 0);
-    } else if (errors2x2 == MAX_ERRORS || errors2x2 == MAX_ERRORS - 1) {
+    } else if (gShowPath || errors2x2 == MAX_ERRORS || errors2x2 == MAX_ERRORS - 1) {
         SkAutoMutexAcquire autoM(compareDebugOut4);
         showPathOpPath(testName, one, two, a, b, scaledOne, scaledTwo, shapeOp, scale);
     }
@@ -367,7 +367,7 @@
 static void outputToStream(const char* pathStr, const char* pathPrefix, const char* nameSuffix,
         const char* testFunction, bool twoPaths, SkMemoryWStream& outFile) {
 #if 0
-    outFile.writeText("\n<div id=\"");
+    outFile.writeText("<div id=\"");
     writeTestName(nameSuffix, outFile);
     outFile.writeText("\">\n");
     if (pathPrefix) {
@@ -412,12 +412,15 @@
 }
 
 SK_DECLARE_STATIC_MUTEX(simplifyDebugOut);
-
 bool testSimplify(SkPath& path, bool useXor, SkPath& out, PathOpsThreadState& state,
                   const char* pathStr) {
     SkPath::FillType fillType = useXor ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType;
     path.setFillType(fillType);
-    state.fReporter->bumpTestCount();
+#if DEBUG_SHOW_TEST_NAME
+    if (gShowPath) {
+        SkPathOpsDebug::ShowOnePath(path, "path", false);
+    }
+#endif
     if (!Simplify(path, &out)) {
         SkDebugf("%s did not expect failure\n", __FUNCTION__);
         REPORTER_ASSERT(state.fReporter, 0);
@@ -427,7 +430,7 @@
         return true;
     }
     int result = comparePaths(state.fReporter, NULL, path, out, *state.fBitmap);
-    if (result) {
+    if (result && gPathStrAssert) {
         SkAutoMutexAcquire autoM(simplifyDebugOut);
         char temp[8192];
         sk_bzero(temp, sizeof(temp));
@@ -447,39 +450,23 @@
     return result == 0;
 }
 
-static bool inner_simplify(skiatest::Reporter* reporter, const SkPath& path, const char* filename,
-        bool checkFail) {
-#if 0 && DEBUG_SHOW_TEST_NAME
+bool testSimplify(skiatest::Reporter* reporter, const SkPath& path, const char* filename) {
+#if DEBUG_SHOW_TEST_NAME
     showPathData(path);
 #endif
     SkPath out;
     if (!Simplify(path, &out)) {
-        SkDebugf("%s did not expect %s failure\n", __FUNCTION__, filename);
+        SkDebugf("%s did not expect failure\n", __FUNCTION__);
         REPORTER_ASSERT(reporter, 0);
         return false;
     }
     SkBitmap bitmap;
-    int errors = comparePaths(reporter, filename, path, out, bitmap);
-    if (!checkFail) {
-        if (!errors) {
-            SkDebugf("%s failing test %s now succeeds\n", __FUNCTION__, filename);
-            REPORTER_ASSERT(reporter, 0);
-            return false;
-        }
-    } else if (errors) {
+    int result = comparePaths(reporter, filename, path, out, bitmap);
+    if (result && gPathStrAssert) {
         REPORTER_ASSERT(reporter, 0);
     }
     reporter->bumpTestCount();
-    return errors == 0;
-}
-
-bool testSimplify(skiatest::Reporter* reporter, const SkPath& path, const char* filename) {
-    return inner_simplify(reporter, path, filename, true);
-}
-
-bool testSimplifyCheck(skiatest::Reporter* reporter, const SkPath& path, const char* filename,
-        bool checkFail) {
-    return inner_simplify(reporter, path, filename, checkFail);
+    return result == 0;
 }
 
 #if DEBUG_SHOW_TEST_NAME
@@ -493,7 +480,7 @@
 
 static bool innerPathOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
         const SkPathOp shapeOp, const char* testName, bool threaded, bool expectSuccess) {
-#if 0 && DEBUG_SHOW_TEST_NAME
+#if DEBUG_SHOW_TEST_NAME
     showName(a, b, shapeOp);
 #endif
     SkPath out;
@@ -502,7 +489,7 @@
         REPORTER_ASSERT(reporter, 0);
         return false;
     }
-    if (!reporter->verbose()) {
+    if (threaded && !reporter->verbose()) {
         return true;
     }
     SkPath pathOut, scaledPathOut;
@@ -531,7 +518,7 @@
     scaledOut.setFillType(out.getFillType());
     int result = comparePaths(reporter, testName, pathOut, scaledPathOut, out, scaledOut, bitmap,
             a, b, shapeOp, scale, expectSuccess);
-    if (result) {
+    if (result && gPathStrAssert) {
         REPORTER_ASSERT(reporter, 0);
     }
     reporter->bumpTestCount();
@@ -617,7 +604,6 @@
 
 void RunTestSet(skiatest::Reporter* reporter, TestDesc tests[], size_t count,
                 void (*firstTest)(skiatest::Reporter* , const char* filename),
-                void (*skipTest)(skiatest::Reporter* , const char* filename),
                 void (*stopTest)(skiatest::Reporter* , const char* filename), bool reverse) {
     size_t index;
     if (firstTest) {
@@ -626,7 +612,8 @@
             --index;
         }
 #if DEBUG_SHOW_TEST_NAME
-        SkDebugf("\n<div id=\"%s\">\n", tests[index].str);
+        SkDebugf("<div id=\"%s\">\n", tests[index].str);
+        SkDebugf("  %s [%s]\n", __FUNCTION__, tests[index].str);
 #endif
         (*tests[index].fun)(reporter, tests[index].str);
         if (tests[index].fun == stopTest) {
@@ -635,14 +622,11 @@
     }
     index = reverse ? count - 1 : 0;
     size_t last = reverse ? 0 : count - 1;
-    bool foundSkip = !skipTest;
     do {
-        if (tests[index].fun == skipTest) {
-            foundSkip = true;
-        }
-        if (foundSkip && tests[index].fun != firstTest) {
+        if (tests[index].fun != firstTest) {
     #if DEBUG_SHOW_TEST_NAME
-            SkDebugf("\n<div id=\"%s\">\n", tests[index].str);
+            SkDebugf("<div id=\"%s\">\n", tests[index].str);
+            SkDebugf("  %s [%s]\n", __FUNCTION__, tests[index].str);
     #endif
             (*tests[index].fun)(reporter, tests[index].str);
         }
diff --git a/tests/PathOpsExtendedTest.h b/tests/PathOpsExtendedTest.h
index 0428457..5f7e972 100644
--- a/tests/PathOpsExtendedTest.h
+++ b/tests/PathOpsExtendedTest.h
@@ -17,7 +17,6 @@
 #include "Test.h"
 
 DECLARE_bool(runFail);
-DECLARE_bool(runBinary);
 
 struct PathOpsThreadState;
 
@@ -27,8 +26,7 @@
 };
 
 //extern int comparePaths(const SkPath& one, const SkPath& two);
-extern int comparePaths(skiatest::Reporter* reporter, const char* filename,
-                        const SkPath& one, const SkPath& two, SkBitmap& bitmap);
+extern int comparePaths(const SkPath& one, const SkPath& two, SkBitmap& bitmap);
 extern bool drawAsciiPaths(const SkPath& one, const SkPath& two, bool drawPaths);
 extern void showOp(const SkPathOp op);
 extern bool testPathOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
@@ -42,8 +40,6 @@
 extern bool testSimplify(SkPath& path, bool useXor, SkPath& out, PathOpsThreadState& state,
                          const char* pathStr);
 extern bool testSimplify(skiatest::Reporter* reporter, const SkPath& path, const char* filename);
-extern bool testSimplifyCheck(skiatest::Reporter* reporter, const SkPath& path,
-                              const char* filename, bool checkFail);
 
 void initializeTests(skiatest::Reporter* reporter, const char* testName);
 void outputProgress(char* ramStr, const char* pathStr, SkPath::FillType );
@@ -51,7 +47,6 @@
 
 void RunTestSet(skiatest::Reporter* reporter, TestDesc tests[], size_t count,
                 void (*firstTest)(skiatest::Reporter* , const char* filename),
-                void (*skipTest)(skiatest::Reporter* , const char* filename),
                 void (*stopTest)(skiatest::Reporter* , const char* filename), bool reverse);
 void ShowTestArray();
 void ShowTestName(PathOpsThreadState* data, int a, int b, int c, int d);
diff --git a/tests/PathOpsFuzz763Test.cpp b/tests/PathOpsFuzz763Test.cpp
index 64eb819..cd851a7 100755
--- a/tests/PathOpsFuzz763Test.cpp
+++ b/tests/PathOpsFuzz763Test.cpp
@@ -121,6 +121,11 @@
 }
 
 static void fuzz763_378(skiatest::Reporter* reporter, const char* filename) {
+#ifdef SK_BUILD_FOR_ANDROID
+	if (!FLAGS_runFail) {
+		return;  // fails on nexus 9 in release, possibly related to fused multiply-add
+	}
+#endif
     SkPath path;
     path.setFillType((SkPath::FillType) 1);
 path.moveTo(SkBits2Float(0x41013776), SkBits2Float(0xc25007a8));
@@ -214,6 +219,11 @@
 }
 
 static void fuzz763_378b(skiatest::Reporter* reporter, const char* filename) {
+#ifdef SK_BUILD_FOR_ANDROID
+	if (!FLAGS_runFail) {
+		return;  // fails on nexus 9 in release, possibly related to fused multiply-add
+	}
+#endif
     SkPath path;
     path.setFillType((SkPath::FillType) 1);
 path.moveTo(-47.1494f, 4.35143f);
@@ -233,7 +243,7 @@
 path.quadTo(SkBits2Float(0xc238d4f6), SkBits2Float(0x41a554c0), SkBits2Float(0xc2444fb0), SkBits2Float(0x419813d4));
 path.close();
     SkPath path2(path);
-    testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+    testPathOpCheck(reporter, path1, path2, (SkPathOp) 2, filename, FLAGS_runFail);
 }
 
 static void fuzz763_378c(skiatest::Reporter* reporter, const char* filename) {
@@ -254,7 +264,7 @@
     path.quadTo(-39.8065f, 18.9507f, -43.0072f, 19.8086f);
     path.close();
     SkPath path2(path);
-    testPathOpCheck(reporter, path1, path2, (SkPathOp) 2, filename, FLAGS_runFail);
+    testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
 }
 
 static void fuzz763_378d(skiatest::Reporter* reporter, const char* filename) {
@@ -495,7 +505,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_8712(skiatest::Reporter* reporter, const char* filename) {
@@ -585,7 +595,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_8712a(skiatest::Reporter* reporter, const char* filename) {
@@ -620,7 +630,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_4014(skiatest::Reporter* reporter, const char* filename) {
@@ -709,7 +719,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_4014a(skiatest::Reporter* reporter, const char* filename) {
@@ -932,7 +942,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) {
@@ -1131,6 +1141,7 @@
     testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
 }
 
+//SkOpSegment.cpp:3475: failed assertion "firstAngle"
 static void fuzz763_17370(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType((SkPath::FillType) 1);
@@ -1436,7 +1447,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_1597464(skiatest::Reporter* reporter, const char* filename) {
@@ -1531,10 +1542,10 @@
     testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
 }
 
+// SkOpSegment.cpp:4010: failed assertion "span->fOppSum == -0x7FFFFFFF || span->fOppSum == oppWinding
 static void fuzz763_34974(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType((SkPath::FillType) 1);
-#if 00
 path.moveTo(SkBits2Float(0x41015326), SkBits2Float(0xc2500694));
 path.quadTo(SkBits2Float(0x412f3e30), SkBits2Float(0xc256a6fa), SkBits2Float(0x41627462), SkBits2Float(0xc253387e));
 path.quadTo(SkBits2Float(0x418ad549), SkBits2Float(0xc24fca02), SkBits2Float(0x41981613), SkBits2Float(0xc2444f40));
@@ -1545,8 +1556,6 @@
 path.quadTo(SkBits2Float(0x405fd0f0), SkBits2Float(0xc22fcb17), SkBits2Float(0x408b5c58), SkBits2Float(0xc23c98a3));
 path.quadTo(SkBits2Float(0x40a6d038), SkBits2Float(0xc249662f), SkBits2Float(0x41015326), SkBits2Float(0xc2500694));
 path.close();
-#endif
-#if 000
 path.moveTo(SkBits2Float(0xc21a9c18), SkBits2Float(0xc21aa524));
 path.quadTo(SkBits2Float(0xc2113c71), SkBits2Float(0xc2240440), SkBits2Float(0xc203fb34), SkBits2Float(0xc22403dc));
 path.quadTo(SkBits2Float(0xc1ed73ee), SkBits2Float(0xc2240379), SkBits2Float(0xc1dab5b7), SkBits2Float(0xc21aa3d1));
@@ -1557,8 +1566,6 @@
 path.quadTo(SkBits2Float(0xc223fc87), SkBits2Float(0xc1ed871e), SkBits2Float(0xc223fc24), SkBits2Float(0xc20404cc));
 path.quadTo(SkBits2Float(0xc223fbc0), SkBits2Float(0xc2114609), SkBits2Float(0xc21a9c18), SkBits2Float(0xc21aa524));
 path.close();
-#endif
-#if 00
 path.moveTo(SkBits2Float(0xc19e6455), SkBits2Float(0xc19e6455));
 path.quadTo(SkBits2Float(0xc1399153), SkBits2Float(0xc1e00000), SkBits2Float(0x00000000), SkBits2Float(0xc1e00000));
 path.quadTo(SkBits2Float(0x41399153), SkBits2Float(0xc1e00000), SkBits2Float(0x419e6455), SkBits2Float(0xc19e6455));
@@ -1575,15 +1582,11 @@
 path.quadTo(SkBits2Float(0xc1e00000), SkBits2Float(0x41399153), SkBits2Float(0xc1e00000), SkBits2Float(0x00000000));
 path.quadTo(SkBits2Float(0xc1e00000), SkBits2Float(0xc1399153), SkBits2Float(0xc19e6455), SkBits2Float(0xc19e6455));
 path.close();
-#endif
-#if 01
 path.moveTo(SkBits2Float(0xc2533a24), SkBits2Float(0x41625bba));
 path.lineTo(SkBits2Float(0xc2533ab2), SkBits2Float(0x4162536e));
 path.lineTo(SkBits2Float(0xc2533af7), SkBits2Float(0x41624f68));
 path.quadTo(SkBits2Float(0xc2533a8e), SkBits2Float(0x41625591), SkBits2Float(0xc2533a24), SkBits2Float(0x41625bba));
 path.close();
-#endif
-#if 0
 path.moveTo(SkBits2Float(0x41dac664), SkBits2Float(0x41dab723));
 path.quadTo(SkBits2Float(0x41ed82ea), SkBits2Float(0x41c80000), SkBits2Float(0x42040000), SkBits2Float(0x41c80000));
 path.quadTo(SkBits2Float(0x4211413d), SkBits2Float(0x41c80000), SkBits2Float(0x421aa09e), SkBits2Float(0x41dabec3));
@@ -1599,8 +1602,6 @@
 path.lineTo(SkBits2Float(0x41dabec3), SkBits2Float(0x41dabec3));
 path.quadTo(SkBits2Float(0x41dac293), SkBits2Float(0x41dabaf3), SkBits2Float(0x41dac664), SkBits2Float(0x41dab723));
 path.close();
-#endif
-#if 00001
 path.moveTo(SkBits2Float(0xc23c9951), SkBits2Float(0x408b2180));
 path.quadTo(SkBits2Float(0xc22fcba2), SkBits2Float(0x405f6340), SkBits2Float(0xc2245122), SkBits2Float(0x40a4b85c));
 path.quadTo(SkBits2Float(0xc218dd36), SkBits2Float(0x40d9a0b8), SkBits2Float(0xc2156c96), SkBits2Float(0x411fdb9a));
@@ -1621,12 +1622,10 @@
 path.quadTo(SkBits2Float(0xc256a842), SkBits2Float(0x412f19c8), SkBits2Float(0xc25007d7), SkBits2Float(0x410132b2));
 path.quadTo(SkBits2Float(0xc24966ff), SkBits2Float(0x40a69160), SkBits2Float(0xc23c9951), SkBits2Float(0x408b2180));
 path.close();
-#endif
 
     SkPath path1(path);
     path.reset();
     path.setFillType((SkPath::FillType) 0);
-#if 01
 path.moveTo(SkBits2Float(0xc2445236), SkBits2Float(0x419806c2));
 path.quadTo(SkBits2Float(0xc24fccb6), SkBits2Float(0x418ac513), SkBits2Float(0xc2533ab2), SkBits2Float(0x4162536e));
 path.quadTo(SkBits2Float(0xc256a8ae), SkBits2Float(0x412f1cb2), SkBits2Float(0xc25007d7), SkBits2Float(0x410132b2));
@@ -1637,9 +1636,9 @@
 path.quadTo(SkBits2Float(0xc21f3c59), SkBits2Float(0x41979082), SkBits2Float(0xc22c0a07), SkBits2Float(0x419e6c7a));
 path.quadTo(SkBits2Float(0xc238d7b6), SkBits2Float(0x41a54872), SkBits2Float(0xc2445236), SkBits2Float(0x419806c2));
 path.close();
-#endif
+
     SkPath path2(path);
-    testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+    testPathOpCheck(reporter, path1, path2, (SkPathOp) 2, filename, FLAGS_runFail);
 }
 
 static void fuzz763_2211264(skiatest::Reporter* reporter, const char* filename) {
@@ -2198,10 +2197,13 @@
 path.close();
 
     SkPath path2(path);
-    testPathOpCheck(reporter, path1, path2, (SkPathOp) 2, filename, FLAGS_runFail);
+    testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
 }
 
 static void fuzz763_2674194(skiatest::Reporter* reporter, const char* filename) {
+    if (!FLAGS_runFail) { // FIXME: asserts in alignSpanState
+        return;
+    }
     SkPath path;
     path.setFillType((SkPath::FillType) 1);
 path.moveTo(SkBits2Float(0xbfb16e10), SkBits2Float(0xc252733b));
@@ -2394,7 +2396,6 @@
     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 (*stopTest)(skiatest::Reporter* , const char* filename) = 0;
 
@@ -2439,5 +2440,5 @@
 #if DEBUG_SHOW_TEST_NAME
     strncpy(DEBUG_FILENAME_STRING, "", DEBUG_FILENAME_STRING_LENGTH);
 #endif
-    RunTestSet(reporter, tests, testCount, firstTest, skipTest, stopTest, runReverse);
+    RunTestSet(reporter, tests, testCount, firstTest, stopTest, runReverse);
 }
diff --git a/tests/PathOpsLineIntersectionTest.cpp b/tests/PathOpsLineIntersectionTest.cpp
index bc0259c..105187b 100644
--- a/tests/PathOpsLineIntersectionTest.cpp
+++ b/tests/PathOpsLineIntersectionTest.cpp
@@ -11,9 +11,6 @@
 
 // FIXME: add tests for intersecting, non-intersecting, degenerate, coincident
 static const SkDLine tests[][2] = {
-{{{{0.00010360032320022583, 1.0172703415155411}, {0.00014114845544099808, 1.0200891587883234}}},
- {{{0.00010259449481964111, 1.017270140349865}, {0.00018215179443359375, 1.022890567779541}}}},
-
 #if 0
     // these do intersect at a pair of points, but not close enough for check results liking
     {{{{365.848175,5081.15186}, {368,5103}}}, {{{367.967712,5102.61084}, {368.278717,5105.71045}}}},
@@ -85,13 +82,10 @@
 static const size_t coincidentTests_count = SK_ARRAY_COUNT(coincidentTests);
 
 static void check_results(skiatest::Reporter* reporter, const SkDLine& line1, const SkDLine& line2,
-                          const SkIntersections& ts, bool nearAllowed) {
+                          const SkIntersections& ts) {
     for (int i = 0; i < ts.used(); ++i) {
         SkDPoint result1 = line1.ptAtT(ts[0][i]);
         SkDPoint result2 = line2.ptAtT(ts[1][i]);
-        if (nearAllowed && result1.roughlyEqual(result2)) {
-            continue;
-        }
         if (!result1.approximatelyEqual(result2) && !ts.nearlySame(i)) {
             REPORTER_ASSERT(reporter, ts.used() != 1);
             result2 = line2.ptAtT(ts[1][i ^ 1]);
@@ -104,16 +98,14 @@
     }
 }
 
-static void testOne(skiatest::Reporter* reporter, const SkDLine& line1, const SkDLine& line2,
-        bool nearAllowed) {
+static void testOne(skiatest::Reporter* reporter, const SkDLine& line1, const SkDLine& line2) {
     SkASSERT(ValidLine(line1));
     SkASSERT(ValidLine(line2));
     SkIntersections i;
-    i.allowNear(nearAllowed);
     int pts = i.intersect(line1, line2);
     REPORTER_ASSERT(reporter, pts);
     REPORTER_ASSERT(reporter, pts == i.used());
-    check_results(reporter, line1, line2, i, nearAllowed);
+    check_results(reporter, line1, line2, i);
     if (line1[0] == line1[1] || line2[0] == line2[1]) {
         return;
     }
@@ -122,28 +114,28 @@
         double right = SkTMax(line1[0].fX, line1[1].fX);
         SkIntersections ts;
         ts.horizontal(line2, left, right, line1[0].fY, line1[0].fX != left);
-        check_results(reporter, line2, line1, ts, nearAllowed);
+        check_results(reporter, line2, line1, ts);
     }
     if (line2[0].fY == line2[1].fY) {
         double left = SkTMin(line2[0].fX, line2[1].fX);
         double right = SkTMax(line2[0].fX, line2[1].fX);
         SkIntersections ts;
         ts.horizontal(line1, left, right, line2[0].fY, line2[0].fX != left);
-        check_results(reporter, line1, line2, ts, nearAllowed);
+        check_results(reporter, line1, line2, ts);
     }
     if (line1[0].fX == line1[1].fX) {
         double top = SkTMin(line1[0].fY, line1[1].fY);
         double bottom = SkTMax(line1[0].fY, line1[1].fY);
         SkIntersections ts;
         ts.vertical(line2, top, bottom, line1[0].fX, line1[0].fY != top);
-        check_results(reporter, line2, line1, ts, nearAllowed);
+        check_results(reporter, line2, line1, ts);
     }
     if (line2[0].fX == line2[1].fX) {
         double top = SkTMin(line2[0].fY, line2[1].fY);
         double bottom = SkTMax(line2[0].fY, line2[1].fY);
         SkIntersections ts;
         ts.vertical(line1, top, bottom, line2[0].fX, line2[0].fY != top);
-        check_results(reporter, line1, line2, ts, nearAllowed);
+        check_results(reporter, line1, line2, ts);
     }
     reporter->bumpTestCount();
 }
@@ -156,7 +148,7 @@
     int pts = ts.intersect(line1, line2);
     REPORTER_ASSERT(reporter, pts == 2);
     REPORTER_ASSERT(reporter, pts == ts.used());
-    check_results(reporter, line1, line2, ts, false);
+    check_results(reporter, line1, line2, ts);
     if (line1[0] == line1[1] || line2[0] == line2[1]) {
         return;
     }
@@ -167,7 +159,7 @@
         ts.horizontal(line2, left, right, line1[0].fY, line1[0].fX != left);
         REPORTER_ASSERT(reporter, pts == 2);
         REPORTER_ASSERT(reporter, pts == ts.used());
-        check_results(reporter, line2, line1, ts, false);
+        check_results(reporter, line2, line1, ts);
     }
     if (line2[0].fY == line2[1].fY) {
         double left = SkTMin(line2[0].fX, line2[1].fX);
@@ -176,7 +168,7 @@
         ts.horizontal(line1, left, right, line2[0].fY, line2[0].fX != left);
         REPORTER_ASSERT(reporter, pts == 2);
         REPORTER_ASSERT(reporter, pts == ts.used());
-        check_results(reporter, line1, line2, ts, false);
+        check_results(reporter, line1, line2, ts);
     }
     if (line1[0].fX == line1[1].fX) {
         double top = SkTMin(line1[0].fY, line1[1].fY);
@@ -185,7 +177,7 @@
         ts.vertical(line2, top, bottom, line1[0].fX, line1[0].fY != top);
         REPORTER_ASSERT(reporter, pts == 2);
         REPORTER_ASSERT(reporter, pts == ts.used());
-        check_results(reporter, line2, line1, ts, false);
+        check_results(reporter, line2, line1, ts);
     }
     if (line2[0].fX == line2[1].fX) {
         double top = SkTMin(line2[0].fY, line2[1].fY);
@@ -194,7 +186,7 @@
         ts.vertical(line1, top, bottom, line2[0].fX, line2[0].fY != top);
         REPORTER_ASSERT(reporter, pts == 2);
         REPORTER_ASSERT(reporter, pts == ts.used());
-        check_results(reporter, line1, line2, ts, false);
+        check_results(reporter, line1, line2, ts);
     }
     reporter->bumpTestCount();
 }
@@ -209,7 +201,7 @@
     for (index = 0; index < tests_count; ++index) {
         const SkDLine& line1 = tests[index][0];
         const SkDLine& line2 = tests[index][1];
-        testOne(reporter, line1, line2, true);
+        testOne(reporter, line1, line2);
     }
     for (index = 0; index < noIntersect_count; ++index) {
         const SkDLine& line1 = noIntersect[index][0];
@@ -225,13 +217,8 @@
 DEF_TEST(PathOpsLineIntersectionOneOff, reporter) {
     int index = 0;
     SkASSERT(index < (int) tests_count);
-    testOne(reporter, tests[index][0], tests[index][1], true);
-}
-
-DEF_TEST(PathOpsLineIntersectionExactOneOff, reporter) {
-    int index = 0;
-    SkASSERT(index < (int) tests_count);
-    testOne(reporter, tests[index][0], tests[index][1], false);
+    testOne(reporter, tests[index][0], tests[index][1]);
+    testOne(reporter, tests[1][0], tests[1][1]);
 }
 
 DEF_TEST(PathOpsLineIntersectionOneCoincident, reporter) {
diff --git a/tests/PathOpsOpCubicThreadedTest.cpp b/tests/PathOpsOpCubicThreadedTest.cpp
index 5815cf6..751ccc5 100644
--- a/tests/PathOpsOpCubicThreadedTest.cpp
+++ b/tests/PathOpsOpCubicThreadedTest.cpp
@@ -27,10 +27,6 @@
         SkPath pathA, pathB;
         if (progress) {
             char* str = pathStr;
-            const int loopNo = 129;
-            str += sprintf(str, "static void cubicOp%d(skiatest::Reporter* reporter,"
-                    " const char* filename) {\n", loopNo);
-            str += sprintf(str, "    SkPath path, pathB;\n");
             str += sprintf(str, "    path.setFillType(SkPath::k%s_FillType);\n",
                     e == SkPath::kWinding_FillType ? "Winding" : e == SkPath::kEvenOdd_FillType
                     ? "EvenOdd" : "?UNDEFINED");
@@ -45,9 +41,6 @@
             str += sprintf(str, "    pathB.cubicTo(%d,%d, %d,%d, %d,%d);\n", c, d,
                     state.fB, state.fA, state.fD, state.fC);
             str += sprintf(str, "    pathB.close();\n");
-            str += sprintf(str, "    testPathOp(reporter, path, pathB, kDifference_PathOp,"
-                    " filename);\n");
-            str += sprintf(str, "}\n");
         }
         pathA.setFillType((SkPath::FillType) e);
         pathA.moveTo(SkIntToScalar(state.fA), SkIntToScalar(state.fB));
diff --git a/tests/PathOpsOpLoopThreadedTest.cpp b/tests/PathOpsOpLoopThreadedTest.cpp
index 40bf2cb..c50e23b 100755
--- a/tests/PathOpsOpLoopThreadedTest.cpp
+++ b/tests/PathOpsOpLoopThreadedTest.cpp
@@ -7,24 +7,6 @@
 #include "PathOpsExtendedTest.h"
 #include "PathOpsThreadedCommon.h"
 
-static int add_point(char* str, SkScalar x, SkScalar y) {
-    int result;
-    int asInt = SkScalarRoundToInt(x);
-    if (SkIntToScalar(asInt) == x) {
-        result = sprintf(str, "%d", asInt);
-    } else {
-        result = sprintf(str, "%1.9gf", x);
-    }
-    result += sprintf(str + result, ",");
-    asInt = SkScalarRoundToInt(y);
-    if (SkIntToScalar(asInt) == y) {
-        result += sprintf(str + result, "%d", asInt);
-    } else {
-        result += sprintf(str + result, "%1.9gf", y);
-    }
-    return result;
-}
-
 static void testOpLoopsMain(PathOpsThreadState* data) {
 #if DEBUG_SHOW_TEST_NAME
     strncpy(DEBUG_FILENAME_STRING, "", DEBUG_FILENAME_STRING_LENGTH);
@@ -53,27 +35,14 @@
         SkPath pathA, pathB;
         if (progress) {
             char* str = pathStr;
-            const int loopNo = 7;
-            str += sprintf(str, "static void loop%d(skiatest::Reporter* reporter,"
-                    " const char* filename) {\n", loopNo);
-            str += sprintf(str, "    SkPath path, pathB;\n");
             str += sprintf(str, "    path.moveTo(%d,%d);\n", a, b);
-            str += sprintf(str, "    path.cubicTo(%d,%d, ", c, d);
-            str += add_point(str, endC.fX, endC.fY);
-            str += sprintf(str, ", ");
-            str += add_point(str, endD.fX, endD.fY);
-            str += sprintf(str, ");\n");
+            str += sprintf(str, "    path.cubicTo(%d,%d, %1.9gf,%1.9gf, %1.9gf,%1.9gf);\n",
+                    c, d, endC.fX, endC.fY, endD.fX, endD.fY);
             str += sprintf(str, "    path.close();\n");
             str += sprintf(str, "    pathB.moveTo(%d,%d);\n", c, d);
-            str += sprintf(str, "    pathB.cubicTo(");
-            str += add_point(str, endC.fX, endC.fY);
-            str += sprintf(str, ", ");
-            str += add_point(str, endD.fX, endD.fY);
-            str += sprintf(str, ", %d,%d);\n", a, b);
+            str += sprintf(str, "    pathB.cubicTo(%1.9gf,%1.9gf, %1.9gf,%1.9gf, %d,%d);\n",
+                    endC.fX, endC.fY, endD.fX, endD.fY, a, b);
             str += sprintf(str, "    pathB.close();\n");
-            str += sprintf(str, "    testPathOp(reporter, path, pathB, kIntersect_PathOp,"
-                    " filename);\n");
-            str += sprintf(str, "}\n");
         }
         pathA.moveTo(SkIntToScalar(a), SkIntToScalar(b));
         pathA.cubicTo(SkIntToScalar(c), SkIntToScalar(d), endC.fX, endC.fY, endD.fX, endD.fY);
@@ -93,6 +62,9 @@
 }
 
 DEF_TEST(PathOpsOpLoopsThreaded, reporter) {
+    if (!FLAGS_runFail) {
+        return;
+    }
     initializeTests(reporter, "cubicOp");
     PathOpsThreadedTestRunner testRunner(reporter);
     for (int a = 0; a < 6; ++a) {  // outermost
@@ -112,6 +84,9 @@
 }
 
 DEF_TEST(PathOpsOpLoops, reporter) {
+    if (!FLAGS_runFail) {
+        return;
+    }
     initializeTests(reporter, "cubicOp");
     PathOpsThreadState state;
     state.fReporter = reporter;
diff --git a/tests/PathOpsOpTest.cpp b/tests/PathOpsOpTest.cpp
index 6b50cc9..fbfa0b5 100644
--- a/tests/PathOpsOpTest.cpp
+++ b/tests/PathOpsOpTest.cpp
@@ -713,6 +713,11 @@
     testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
 }
 
+// this fails to detect a cubic/cubic intersection
+// the slight overlap is missed when the cubics are approximated by quadratics
+// and the subsequent line/cubic intersection also (correctly) misses the intersection
+// if the line/cubic was a matching line/approx.quadratic then the missing intersection
+// could have been detected
 static void cubicOp38d(skiatest::Reporter* reporter, const char* filename) {
     SkPath path, pathB;
     path.setFillType(SkPath::kWinding_FillType);
@@ -1790,6 +1795,9 @@
     testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
 }
 
+// this fails because the pair of nearly coincident cubics intersect at the ends
+// but the line connected to one of the cubics at the same point does not intersect
+// the other
 static void skpkkiste_to98(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -1926,7 +1934,7 @@
     path2.lineTo(113.232177734375f, 173.5789947509765625f);
     path2.lineTo(113.232177734375f, 173.5789947509765625f);
     path2.close();
-    // FIXME : difficult data, circle back later
+
     testPathOp(reporter, path1, path2, kUnion_PathOp, filename);
 }
 
@@ -2048,6 +2056,9 @@
     testPathOp(reporter, path, pathB, kXOR_PathOp, filename);
 }
 
+// this fails to generate two interior line segments 
+// an earlier pathops succeeded, but still failed to generate one interior line segment
+// (but was saved by assemble, which works around a single line missing segment)
 static void issue1435(skiatest::Reporter* reporter, const char* filename) {
     SkPath path1;
     path1.moveTo(160, 60);
@@ -2245,7 +2256,7 @@
     testPathOp(reporter, path, pathB, kUnion_PathOp, filename);
 }
 
-static void skpaaalgarve_org53(skiatest::Reporter* reporter, const char* filename) {
+static void skpaaalgarve_org53(skiatest::Reporter* reporter, const char* filename) {  //  add t cancel
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
    path.moveTo(-1.24344979e-014f, 348);
@@ -2266,7 +2277,7 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
-static void skpabcspark_ca103(skiatest::Reporter* reporter, const char* filename) {
+static void skpabcspark_ca103(skiatest::Reporter* reporter, const char* filename) {  //  add t cancel
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
     path.moveTo(1.99840144e-015f, 494);
@@ -2289,7 +2300,7 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
-static void skpacesoftech_com47(skiatest::Reporter* reporter, const char* filename) {
+static void skpacesoftech_com47(skiatest::Reporter* reporter, const char* filename) {  // partial coincidence
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
     path.moveTo(670.537415f, 285);
@@ -2315,7 +2326,7 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
-static void skpact_com43(skiatest::Reporter* reporter, const char* filename) {
+static void skpact_com43(skiatest::Reporter* reporter, const char* filename) {  // bridge op
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
     path.moveTo(1.45716772e-016f, 924.336121f);
@@ -2340,7 +2351,7 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
-static void skpadbox_lt8(skiatest::Reporter* reporter, const char* filename) {
+static void skpadbox_lt8(skiatest::Reporter* reporter, const char* filename) {  // zero span
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
     path.moveTo(320.097229f, 628.573669f);
@@ -2364,7 +2375,7 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
-static void skpadindex_de4(skiatest::Reporter* reporter, const char* filename) {
+static void skpadindex_de4(skiatest::Reporter* reporter, const char* filename) {  // find chase op
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
     path.moveTo(0, 926);
@@ -2383,7 +2394,7 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
-static void skpadithya_putr4_blogspot_com551(skiatest::Reporter* reporter, const char* filename) {
+static void skpadithya_putr4_blogspot_com551(skiatest::Reporter* reporter, const char* filename) { // calc common
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
     path.moveTo(205.605804f, 142.334625f);
@@ -2407,7 +2418,7 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
-static void skpadspert_de11(skiatest::Reporter* reporter, const char* filename) {
+static void skpadspert_de11(skiatest::Reporter* reporter, const char* filename) {  // mark and chase winding
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
     path.moveTo(-4.4408921e-016f, 682.5f);
@@ -2428,7 +2439,7 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
-static void skpaiaigames_com870(skiatest::Reporter* reporter, const char* filename) {
+static void skpaiaigames_com870(skiatest::Reporter* reporter, const char* filename) {  // cubic/cubic intersect
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
     path.moveTo(324.071075f, 845.071045f);
@@ -2455,7 +2466,7 @@
     pathB.cubicTo(145, 715.477173f, 149.477158f, 711, 155, 711);
     pathB.lineTo(317, 711);
     pathB.close();
-    testPathOpCheck(reporter, path, pathB, kIntersect_PathOp, filename, FLAGS_runFail);
+    testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
 static void cubicOp92i(skiatest::Reporter* reporter, const char* filename) {
@@ -2713,6 +2724,7 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
+// this fails because cubic/quad misses an intersection (failure is isolated in c/q int test)
 static void skpcarrot_is24(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -2736,7 +2748,7 @@
     pathB.cubicTo(1019.77502f, 679.955017f, 1020.08099f, 676.094971f, 1020.08099f, 672.161987f);
     pathB.cubicTo(1020.08002f, 630.73999f, 986.502014f, 597.161987f, 945.080994f, 597.161987f);
     pathB.close();
-    testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+    testPathOpCheck(reporter, path, pathB, kIntersect_PathOp, filename, FLAGS_runFail);
 }
 
 static void skpbangalorenest_com4(skiatest::Reporter* reporter, const char* filename) {
@@ -3235,6 +3247,7 @@
     testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
 }
 
+// triggers addSimpleAngle with non-zero argument
 static void cubicOp112(skiatest::Reporter* reporter, const char* filename) {
     SkPath path, pathB;
     path.setFillType(SkPath::kWinding_FillType);
@@ -3269,7 +3282,7 @@
     pathB.moveTo(1, 3);
     pathB.cubicTo(-1, 2, 3.5f, 1.33333337f, 0, 1);
     pathB.close();
-    testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+    testPathOpCheck(reporter, path, pathB, kIntersect_PathOp, filename, FLAGS_runFail);
 }
 
 static void cubicOp114asQuad(skiatest::Reporter* reporter, const char* filename) {
@@ -3451,7 +3464,7 @@
     path2.cubicTo(188.201f, 117.601f, 174.801f, 93, 39, 124.001f);
     path2.close();
 
-    testPathOp(reporter, path1, path2, kUnion_PathOp, filename);
+    testPathOpCheck(reporter, path1, path2, kUnion_PathOp, filename, FLAGS_runFail);
 }
 
 static void issue2808(skiatest::Reporter* reporter, const char* filename) {
@@ -3496,335 +3509,12 @@
     testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
 }
 
-static void testRect1(skiatest::Reporter* reporter, const char* filename) {
-    SkPath path, path2;
-    path.addRect(0, 0, 60, 60, SkPath::kCCW_Direction);
-    path.addRect(30, 20, 50, 50, SkPath::kCCW_Direction);
-    path.addRect(24, 20, 36, 30, SkPath::kCCW_Direction);
-//    path.addRect(32, 24, 36, 41, SkPath::kCCW_Direction);
-    testPathOp(reporter, path, path2, kUnion_PathOp, filename);
-}
-
-static void testRect2(skiatest::Reporter* reporter, const char* filename) {
-    SkPath path, pathB;
-    path.setFillType(SkPath::kWinding_FillType);
-    path.addRect(0, 0, 1, 1, SkPath::kCW_Direction);
-    path.addRect(4, 4, 5, 5, SkPath::kCW_Direction);
-    pathB.setFillType(SkPath::kEvenOdd_FillType);
-    pathB.addRect(0, 0, 2, 2, SkPath::kCW_Direction);
-    pathB.addRect(0, 0, 6, 6, SkPath::kCW_Direction);
-    testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
-}
-
-static void cubicOp116(skiatest::Reporter* reporter, const char* filename) {
-    SkPath path, pathB;
-    path.setFillType(SkPath::kWinding_FillType);
-    path.moveTo(0,1);
-    path.cubicTo(4,6, 2,0, 2,0);
-    path.close();
-    pathB.setFillType(SkPath::kWinding_FillType);
-    pathB.moveTo(0,2);
-    pathB.cubicTo(0,2, 1,0, 6,4);
-    pathB.close();
-    testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
-}
-
-static void cubicOp117(skiatest::Reporter* reporter, const char* filename) {
-    SkPath path, pathB;
-    path.setFillType(SkPath::kWinding_FillType);
-    path.moveTo(0,1);
-    path.cubicTo(4,5, 6,0, 1,0);
-    path.close();
-    pathB.setFillType(SkPath::kWinding_FillType);
-    pathB.moveTo(0,6);
-    pathB.cubicTo(0,1, 1,0, 5,4);
-    pathB.close();
-    testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
-}
-
-static void cubicOp118(skiatest::Reporter* reporter, const char* filename) {
-    SkPath path, pathB;
-    path.setFillType(SkPath::kWinding_FillType);
-    path.moveTo(0,1);
-    path.cubicTo(4,6, 5,1, 6,2);
-    path.close();
-    pathB.setFillType(SkPath::kWinding_FillType);
-    pathB.moveTo(1,5);
-    pathB.cubicTo(2,6, 1,0, 6,4);
-    pathB.close();
-    testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
-}
-
-static void loop1(skiatest::Reporter* reporter, const char* filename) {
-    SkPath path, pathB;
-    path.moveTo(0,1);
-    path.cubicTo(1,5, -5.66666651f,3.33333349f, 8.83333302f,2.33333349f);
-    path.close();
-    pathB.moveTo(1,5);
-    pathB.cubicTo(-5.66666651f,3.33333349f, 8.83333302f,2.33333349f, 0,1);
-    pathB.close();
-    testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
-}
-
-#include "SkPathOpsCubic.h"
-
-static void loop1asQuad(skiatest::Reporter* reporter, const char* filename) {
-    SkDCubic c1 = {{{0,1}, {1,5}, {-5.66666651f,3.33333349f}, {8.83333302f,2.33333349f}}};
-    SkDCubic c2 = {{{1,5}, {-5.66666651f,3.33333349f}, {8.83333302f,2.33333349f}, {0,1}}};
-    double c1InflectionTs[2], c2InflectionTs[2];
-    SkDEBUGCODE(int c1InfTCount =) c1.findInflections(c1InflectionTs);
-    SkASSERT(c1InfTCount == 2);
-    SkDEBUGCODE(int c2InfTCount =) c2.findInflections(c2InflectionTs);
-    SkASSERT(c2InfTCount == 1);
-    SkASSERT(c1InflectionTs[0] > c1InflectionTs[1]);
-    SkDCubicPair c1pair = c1.chopAt(c1InflectionTs[0]);
-    SkDCubicPair c1apair = c1pair.first().chopAt(c1InflectionTs[1]);
-    SkDCubicPair c2pair = c2.chopAt(c2InflectionTs[0]);
-    SkDQuad q1[2] = { c1pair.first().toQuad(), c1pair.second().toQuad() };
-    SkDQuad q1a[2] = { c1apair.first().toQuad(), c1apair.second().toQuad() };
-    SkDQuad q2[2] = { c2pair.first().toQuad(), c2pair.second().toQuad() };
-    SkPath path, pathB;
-    path.moveTo(q1a[0].fPts[0].asSkPoint());
-    path.quadTo(q1a[0].fPts[1].asSkPoint(), q1a[0].fPts[2].asSkPoint());
-    path.quadTo(q1a[1].fPts[1].asSkPoint(), q1a[1].fPts[2].asSkPoint());
-    path.quadTo(q1[1].fPts[1].asSkPoint(), q1[1].fPts[2].asSkPoint());
-    path.close();
-    pathB.moveTo(q2[0].fPts[0].asSkPoint());
-    pathB.quadTo(q2[0].fPts[1].asSkPoint(), q2[0].fPts[2].asSkPoint());
-    pathB.quadTo(q2[1].fPts[1].asSkPoint(), q2[1].fPts[2].asSkPoint());
-    pathB.close();
-    testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
-}
-
-static void loop2(skiatest::Reporter* reporter, const char* filename) {
-    SkPath path, pathB;
-    path.moveTo(0,1);
-    path.cubicTo(3,4, 3.f,4.f, 4.5f,1.5f);
-    path.close();
-    pathB.moveTo(3,4);
-    pathB.cubicTo(3.f,4.f, 4.5f,1.5f, 0,1);
-    pathB.close();
-    testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
-}
-
-static void loop3(skiatest::Reporter* reporter, const char* filename) {
-    SkPath path, pathB;
-    path.moveTo(0,1);
-    path.cubicTo(3,5, -3.66666651f,0, 10.5f,-1.66666651f);
-    path.close();
-    pathB.moveTo(3,5);
-    pathB.cubicTo(-3.66666651f,0, 10.5f,-1.66666651f, 0,1);
-    pathB.close();
-    testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
-}
-
-static void loop4(skiatest::Reporter* reporter, const char* filename) {
-    SkPath path, pathB;
-    path.moveTo(0,5);
-    path.cubicTo(1,5, 1,4, 0.833333313f,3);
-    path.close();
-    pathB.moveTo(1,5);
-    pathB.cubicTo(1,4, 0.833333313f,3, 0,5);
-    pathB.close();
-    testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
-}
-
-#include "SkParsePath.h"
-
-static void issue3517(skiatest::Reporter* reporter, const char* filename) {
-    SkPath path, pathB;
-
-    const char str[] = "M31.35 57.75L31.35 57.75C31.9 57.7486 32.45 57.7948 33 57.7413C33.55 57.6878 34.1 57.5014 34.65 57.4291C35.2 57.3569 35.75 57.3223 36.3 57.3079C36.85 57.2935 37.4 57.3143 37.95 57.3428C38.5 57.3712 39.05 57.4112 39.6 57.4786C40.15 57.546 40.7 57.7029 41.25 57.7472C41.8 57.7916 42.35 57.7962 42.9 57.7445C43.45 57.6928 44 57.5345 44.55 57.4373C45.1 57.34 45.65 57.2115 46.2 57.1611C46.75 57.1107 47.3 57.1371 47.85 57.1349C48.4 57.1327 48.95 57.144 49.5 57.1478C50.05 57.1516 50.6 57.1553 51.15 57.1579C51.7 57.1605 52.25 57.1601 52.8 57.1634C53.35 57.1667 53.9 57.1731 54.45 57.1776C55 57.182 55.55 57.1916 56.1 57.19C56.65 57.1884 57.2 57.178 57.75 57.168C58.3 57.158 58.85 57.1355 59.4 57.1299C59.95 57.1243 60.5 57.1338 61.05 57.1345C61.6 57.1352 62.15 57.124 62.7 57.134C63.25 57.1441 63.8 57.1731 64.35 57.195C64.9 57.2169 65.45 57.2532 66 57.2655C66.55 57.2778 67.1 57.2647 67.65 57.2687C68.2 57.2728 68.75 57.267 69.3 57.2896C69.85 57.3122 70.4 57.371 70.95 57.4044C71.5 57.4377 72.05 57.4668 72.6 57.4896C73.15 57.5123 73.7 57.545 74.25 57.5408C74.8 57.5365 75.35 57.5068 75.9 57.4641C76.45 57.4213 77 57.3244 77.55 57.2842C78.1 57.244 78.65 57.2163 79.2 57.2228C79.75 57.2293 80.3 57.29 80.85 57.3232C81.4 57.3563 81.95 57.396 82.5 57.4219C83.05 57.4478 83.6 57.4637 84.15 57.4787C84.7 57.4937 85.25 57.5011 85.8 57.5121C86.35 57.523 86.9 57.5411 87.45 57.5444C88 57.5477 88.55 57.5663 89.1 57.5318C89.65 57.4972 90.2 57.3126 90.75 57.337C91.3 57.3613 91.85 57.6088 92.4 57.6776C92.95 57.7465 93.5 57.7379 94.05 57.75C94.6 57.7621 95.15 57.75 95.7 57.75L95.7 57.75L31.35 57.75Z";
-    SkParsePath::FromSVGString(str, &path);
-
-    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_PathOp, filename);
-}
-
-static void cubicOp119(skiatest::Reporter* reporter, const char* filename) {
-    SkPath path, pathB;
-    path.setFillType(SkPath::kWinding_FillType);
-    path.moveTo(0,1);
-    path.cubicTo(3,5, 2,1, 3,1);
-    path.close();
-    pathB.setFillType(SkPath::kWinding_FillType);
-    pathB.moveTo(1,2);
-    pathB.cubicTo(1,3, 1,0, 5,3);
-    pathB.close();
-    testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
-}
-
-static void cubicOp120(skiatest::Reporter* reporter, const char* filename) {
-    SkPath path, pathB;
-    path.setFillType(SkPath::kWinding_FillType);
-    path.moveTo(0,1);
-    path.cubicTo(2,4, 2,1, 4,0);
-    path.close();
-    pathB.setFillType(SkPath::kWinding_FillType);
-    pathB.moveTo(1,2);
-    pathB.cubicTo(0,4, 1,0, 4,2);
-    pathB.close();
-    testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
-}
-
-static void cubicOp121(skiatest::Reporter* reporter, const char* filename) {
-    SkPath path, pathB;
-    path.setFillType(SkPath::kWinding_FillType);
-    path.moveTo(0,1);
-    path.cubicTo(3,4, 3,2, 4,3);
-    path.close();
-    pathB.setFillType(SkPath::kWinding_FillType);
-    pathB.moveTo(2,3);
-    pathB.cubicTo(3,4, 1,0, 4,3);
-    pathB.close();
-    testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
-}
-
-// FIXME : haven't debugged this failure yet
-static void cubicOp122(skiatest::Reporter* reporter, const char* filename) {
-    SkPath path, pathB;
-    path.setFillType(SkPath::kWinding_FillType);
-    path.moveTo(0,1);
-    path.cubicTo(3,5, 4,1, 4,0);
-    path.close();
-    pathB.setFillType(SkPath::kWinding_FillType);
-    pathB.moveTo(1,4);
-    pathB.cubicTo(0,4, 1,0, 5,3);
-    pathB.close();
-    testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
-}
-
-static void cubicOp123(skiatest::Reporter* reporter, const char* filename) {
-    SkPath path, pathB;
-    path.setFillType(SkPath::kWinding_FillType);
-    path.moveTo(0,1);
-    path.cubicTo(1,5, 2,0, 6,0);
-    path.close();
-    pathB.setFillType(SkPath::kWinding_FillType);
-    pathB.moveTo(0,2);
-    pathB.cubicTo(0,6, 1,0, 5,1);
-    pathB.close();
-    testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
-}
-
-static void loop5(skiatest::Reporter* reporter, const char* filename) {
-    SkPath path, pathB;
-    path.moveTo(0,2);
-    path.cubicTo(1,2, 1,1.66666663f, 0.833333313f,1.33333325f);
-    path.close();
-    pathB.moveTo(1,2);
-    pathB.cubicTo(1,1.66666663f, 0.833333313f,1.33333325f, 0,2);
-    pathB.close();
-    testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
-}
-
-static void loop6(skiatest::Reporter* reporter, const char* filename) {
-    SkPath path, pathB;
-    path.moveTo(0,1);
-    path.cubicTo(1,3, -1.66666675f,1.66666663f, 4.16666651f,1.00000012f);
-    path.close();
-    pathB.moveTo(1,3);
-    pathB.cubicTo(-1.66666675f,1.66666663f, 4.16666651f,1.00000012f, 0,1);
-    pathB.close();
-    testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
-}
-
-static void cubicOp124(skiatest::Reporter* reporter, const char* filename) {
-    SkPath path, pathB;
-    path.setFillType(SkPath::kWinding_FillType);
-    path.moveTo(0,1);
-    path.cubicTo(1,5, 6,0, 3,0);
-    path.close();
-    pathB.setFillType(SkPath::kWinding_FillType);
-    pathB.moveTo(0,6);
-    pathB.cubicTo(0,3, 1,0, 5,1);
-    pathB.close();
-    testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
-}
-
-static void cubicOp125(skiatest::Reporter* reporter, const char* filename) {
-    SkPath path, pathB;
-    path.setFillType(SkPath::kWinding_FillType);
-    path.moveTo(0,1);
-    path.cubicTo(3,6, 3,1, 6,2);
-    path.close();
-    pathB.setFillType(SkPath::kWinding_FillType);
-    pathB.moveTo(1,3);
-    pathB.cubicTo(2,6, 1,0, 6,3);
-    pathB.close();
-    testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
-}
-
-static void cubicOp126(skiatest::Reporter* reporter, const char* filename) {
-    SkPath path, pathB;
-    path.setFillType(SkPath::kWinding_FillType);
-    path.moveTo(0,1);
-    path.cubicTo(0,3, 6,0, 2,1);
-    path.close();
-    pathB.setFillType(SkPath::kWinding_FillType);
-    pathB.moveTo(0,6);
-    pathB.cubicTo(1,2, 1,0, 3,0);
-    pathB.close();
-    testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
-}
-
-static void cubicOp127(skiatest::Reporter* reporter, const char* filename) {
-    SkPath path, pathB;
-    path.setFillType(SkPath::kWinding_FillType);
-    path.moveTo(0,1);
-    path.cubicTo(1,5, 6,0, 3,0);
-    path.close();
-    pathB.setFillType(SkPath::kWinding_FillType);
-    pathB.moveTo(0,6);
-    pathB.cubicTo(0,3, 1,0, 5,1);
-    pathB.close();
-    testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
-}
-
-static void cubicOp128(skiatest::Reporter* reporter, const char* filename) {
-    SkPath path, pathB;
-    path.setFillType(SkPath::kWinding_FillType);
-    path.moveTo(0,1);
-    path.cubicTo(0,3, 3,2, 5,2);
-    path.close();
-    pathB.setFillType(SkPath::kWinding_FillType);
-    pathB.moveTo(2,3);
-    pathB.cubicTo(2,5, 1,0, 3,0);
-    pathB.close();
-    testPathOp(reporter, path, pathB, kDifference_PathOp, 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 struct TestDesc tests[] = {
-    TEST(cubicOp128),
-    TEST(cubicOp127),
-    TEST(cubicOp126),
-    TEST(cubicOp125),
-    TEST(cubicOp124),
-    TEST(loop6),
-    TEST(loop5),
-    TEST(cubicOp123),
-    TEST(cubicOp122),
-    TEST(cubicOp121),
-    TEST(cubicOp120),
-    TEST(cubicOp119),
-    TEST(loop4),
-    TEST(loop3),
-    TEST(loop2),
-    TEST(loop1asQuad),
-    TEST(loop1),
-    TEST(issue3517),
-    TEST(cubicOp118),
-    TEST(cubicOp117),
-    TEST(cubicOp116),
-    TEST(testRect2),
-    TEST(testRect1),
     TEST(cubicOp115),
-    TEST(issue2753),
+    TEST(issue2753),  // FIXME: pair of cubics miss intersection
     TEST(cubicOp114),  // FIXME: curve with inflection is ordered the wrong way
     TEST(issue2808),
     TEST(cubicOp114asQuad),
@@ -3837,6 +3527,8 @@
     TEST(kari1),
     TEST(quadOp10i),
     TEST(cubicOp113),
+    // fails because a cubic/quadratic intersection is missed
+    // the internal quad/quad is far enough away from the real cubic/quad that it is rejected
     TEST(skpcarrot_is24),
     TEST(issue1417),
     TEST(cubicOp112),
@@ -3863,7 +3555,7 @@
     TEST(issue1435),
     TEST(cubicOp98x),
     TEST(cubicOp97x),
-    TEST(skpcarpetplanet_ru22),
+    TEST(skpcarpetplanet_ru22),  // cubic/cubic intersect detects unwanted coincidence
     TEST(cubicOp96d),
     TEST(cubicOp95u),
     TEST(skpadbox_lt15),
@@ -4055,11 +3747,11 @@
     strncpy(DEBUG_FILENAME_STRING, "", DEBUG_FILENAME_STRING_LENGTH);
 #endif
     if (runSubTests && runSubTestsFirst) {
-        RunTestSet(reporter, subTests, subTestCount, firstSubTest, NULL, stopTest, runReverse);
+        RunTestSet(reporter, subTests, subTestCount, firstSubTest, stopTest, runReverse);
     }
-    RunTestSet(reporter, tests, testCount, firstTest, skipTest, stopTest, runReverse);
+    RunTestSet(reporter, tests, testCount, firstTest, stopTest, runReverse);
     if (runSubTests && !runSubTestsFirst) {
-        RunTestSet(reporter, subTests, subTestCount, firstSubTest, NULL, stopTest, runReverse);
+        RunTestSet(reporter, subTests, subTestCount, firstSubTest, stopTest, runReverse);
     }
 }
 
@@ -4068,7 +3760,7 @@
     path.addRect(0,0, 300,170141183460469231731687303715884105728.f);
     SkPath pathB;
     pathB.addRect(0,0, 300,16);
-    testPathOp(reporter, path, pathB, kUnion_PathOp, filename);
+    testPathFailOp(reporter, path, pathB, kUnion_PathOp, filename);
 }
 
 // m 100,0 60,170 -160,-110 200,0 -170,11000000000 z
@@ -4088,7 +3780,7 @@
     path2.lineTo(-170 + 20,11000000000.0f + 20);
     path2.close();
 
-    testPathOpCheck(reporter, path1, path2, kIntersect_PathOp, filename, FLAGS_runFail);
+    testPathFailOp(reporter, path1, path2, kIntersect_PathOp, filename);
 }
 
 static void fuzz433b(skiatest::Reporter* reporter, const char* filename) {
@@ -4111,7 +3803,7 @@
     path2.lineTo(190, 60);
     path2.close();
 
-    testPathOpCheck(reporter, path1, path2, kUnion_PathOp, filename, FLAGS_runFail);
+    testPathFailOp(reporter, path1, path2, kUnion_PathOp, filename);
 }
 
 static void fuzz487a(skiatest::Reporter* reporter, const char* filename) {
@@ -4157,7 +3849,7 @@
 path.close();
 
     SkPath path2(path);
-    testPathOpCheck(reporter, path1, path2, (SkPathOp) 2, filename, FLAGS_runFail);
+    testPathFailOp(reporter, path1, path2, (SkPathOp) 2, filename);
 }
 
 static void fuzz487b(skiatest::Reporter* reporter, const char* filename) {
@@ -4203,7 +3895,7 @@
 path.close();
 
     SkPath path2(path);
-    testPathOpCheck(reporter, path1, path2, (SkPathOp) 2, filename, FLAGS_runFail);
+    testPathFailOp(reporter, path1, path2, (SkPathOp) 2, filename);
 }
 
 static void fuzz714(skiatest::Reporter* reporter, const char* filename) {
@@ -4270,5 +3962,5 @@
 #if DEBUG_SHOW_TEST_NAME
     strncpy(DEBUG_FILENAME_STRING, "", DEBUG_FILENAME_STRING_LENGTH);
 #endif
-    RunTestSet(reporter, failTests, failTestCount, NULL, NULL, NULL, false);
+    RunTestSet(reporter, failTests, failTestCount, 0, 0, false);
 }
diff --git a/tests/PathOpsQuadIntersectionTest.cpp b/tests/PathOpsQuadIntersectionTest.cpp
index 0455802..565098a 100644
--- a/tests/PathOpsQuadIntersectionTest.cpp
+++ b/tests/PathOpsQuadIntersectionTest.cpp
@@ -53,36 +53,6 @@
 }
 
 static const SkDQuad testSet[] = {
-{{{4981.9990234375, 1590}, {4981.9990234375, 1617.7523193359375}, {4962.375, 1637.3760986328125}}},
-{{{4962.3759765625, 1637.3760986328125}, {4982, 1617.7523193359375}, {4982, 1590}}},
-
-{{{48.7416f, 7.74160004f}, {96.4831848f, -40}, {164, -40}}},
-{{{56.9671326f, 0}, {52.7835083f, 3.69968891f}, {48.7416f, 7.74160004f}}},
-
-{{{138, 80}, {147.15692138671875, 80}, {155.12803649902344, 82.86279296875}}},
-{{{155.12803649902344, 82.86279296875}, {153.14971923828125, 82.152290344238281}, {151.09841918945312, 81.618133544921875}}},
-
-{{{88, 130}, {88, 131.54483032226562}, {88.081489562988281, 133.0560302734375}}},
-{{{88.081489562988281, 133.0560302734375}, {88, 131.54483032226562}, {88, 130}}},
-
-{{{0.59987992,2.14448452}, {0.775417507,1.95606446}, {1.00564098,1.79310346}}},
-{{{1.00564098,1.79310346}, {1.25936198,1.615623}, {1.35901463,1.46834028}}},
-
-{{{3,0}, {0,1}, {3,2}}},
-{{{2,0}, {1,1}, {2,2}}},
-
-{{{38.656852722167969, 38.656852722167969}, {38.651023864746094, 38.662681579589844}, {38.644744873046875, 38.668937683105469}}},
-{{{38.656852722167969, 38.656852722167969}, {36.313709259033203, 41}, {33, 41}}},
-
-{{{4914.9990234375, 1523}, {4942.75146484375, 1523}, {4962.375, 1542.6239013671875}}},
-{{{4962.3759765625, 1542.6239013671875}, {4942.75244140625, 1523}, {4915, 1523}}},
-
-{{{4867.623046875, 1637.3760986328125}, {4847.9990234375, 1617.7523193359375}, {4847.9990234375, 1590}}},
-{{{4848, 1590}, {4848, 1617.7523193359375}, {4867.6240234375, 1637.3760986328125}}},
-
-{{{102.64466094970703, 165.3553466796875}, {110.79246520996094, 173.50314331054687}, {120.81797790527344, 177.11778259277344}}},
-{{{113.232177734375, 173.57899475097656}, {116.88026428222656, 175.69805908203125}, {120.81797790527344, 177.11778259277344}}},
-
 {{{-37.3484879,10.0192947}, {-36.4966316,13.2140198}, {-38.1506348,16.0788383}}},
 {{{-38.1462746,16.08918}, {-36.4904327,13.2193804}, {-37.3484879,10.0192947}}},
 
@@ -350,8 +320,6 @@
 }
 
 static const SkDQuad coincidentTestSet[] = {
-    {{{4914.9990234375, 1523}, {4942.75146484375, 1523}, {4962.375, 1542.6239013671875}}},
-    {{{4962.3759765625, 1542.6239013671875}, {4942.75244140625, 1523}, {4915, 1523}}},
 #if 0
     {{{97.9337615966796875,100}, {88,112.94264984130859375}, {88,130}}},
     {{{88,130}, {88,124.80951690673828125}, {88.91983795166015625,120}}},
@@ -371,9 +339,9 @@
     SkASSERT(ValidQuad(quad2));
     SkIntersections intersections2;
     intersections2.intersect(quad1, quad2);
-    REPORTER_ASSERT(reporter, intersections2.coincidentUsed() >= 2);
-    REPORTER_ASSERT(reporter, intersections2.used() >= 2);
-    for (int pt = 0; pt < intersections2.coincidentUsed(); pt += 2) {
+    REPORTER_ASSERT(reporter, intersections2.coincidentUsed() == 2);
+    REPORTER_ASSERT(reporter, intersections2.used() == 2);
+    for (int pt = 0; pt < intersections2.coincidentUsed(); ++pt) {
         double tt1 = intersections2[0][pt];
         double tt2 = intersections2[1][pt];
         SkDPoint pt1 = quad1.ptAtT(tt1);
@@ -422,8 +390,9 @@
         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("%s left=(%d, %d, %d) inHull=%s\n", __FUNCTION__, floatSign(left[0]),
+                floatSign(left[1]), floatSign(left[2]),
+                q1.pointInHull(q2[index]) ? "true" : "false");
     }
     SkDebugf("\n");
 }
@@ -550,14 +519,6 @@
     intersectionFinder(0, 1);
 }
 
-DEF_TEST(PathOpsQuadIntersectionOneOff, reporter) {
-    oneOffTest1(reporter, 10, 11);
-}
-
-DEF_TEST(PathOpsQuadIntersectionCoincidenceOneOff, reporter) {
-    coincidentTestOne(reporter, 0, 1);
-}
-
 DEF_TEST(PathOpsQuadIntersection, reporter) {
     oneOffTests(reporter);
     coincidentTest(reporter);
@@ -566,31 +527,10 @@
     if (false) QuadraticIntersection_PointFinder();
 }
 
-#include "SkCommonFlags.h"
+DEF_TEST(PathOpsQuadIntersectionCoincidenceOneOff, reporter) {
+    coincidentTestOne(reporter, 0, 1);
+}
 
-DEF_TEST(PathOpsQuadBinaryProfile, reporter) {
-    if (!FLAGS_veryVerbose) {
-            return;
-    }
-    SkIntersections intersections;
-    for (int x = 0; x < 100; ++x) {
-        int outer = 0;
-        int inner = outer + 1;
-        do {
-            const SkDQuad& quad1 = testSet[outer];
-            const SkDQuad& quad2 = testSet[inner];
-            (void) intersections.intersect(quad1, quad2);
-            REPORTER_ASSERT(reporter, intersections.used() >= 0);  // make sure code isn't tossed
-            inner += 2;
-            outer += 2;
-        } while (outer < (int) testSetCount);
-    }
-    for (int x = 0; x < 100; ++x) {
-        for (size_t test = 0; test < quadraticTests_count; ++test) {
-            const SkDQuad& quad1 = quadraticTests[test][0];
-            const SkDQuad& quad2 = quadraticTests[test][1];
-            (void) intersections.intersect(quad1, quad2);
-            REPORTER_ASSERT(reporter, intersections.used() >= 0);  // make sure code isn't tossed
-        }
-    }
+DEF_TEST(PathOpsQuadIntersectionOneOff, reporter) {
+    oneOffTest1(reporter, 0, 1);
 }
diff --git a/tests/PathOpsQuadIntersectionTestData.cpp b/tests/PathOpsQuadIntersectionTestData.cpp
index f51f951..0706efc 100644
--- a/tests/PathOpsQuadIntersectionTestData.cpp
+++ b/tests/PathOpsQuadIntersectionTestData.cpp
@@ -44,10 +44,10 @@
 
 const size_t quadraticLines_count = SK_ARRAY_COUNT(quadraticLines);
 
-static const double F = FLT_EPSILON * 32;
-static const double H = FLT_EPSILON * 32;
-static const double J = FLT_EPSILON * 32;
-static const double K = FLT_EPSILON * 32;  // INVESTIGATE: why are larger multiples necessary?
+static const double F = FLT_EPSILON * 3;
+static const double H = FLT_EPSILON * 4;
+static const double J = FLT_EPSILON * 5;
+static const double K = FLT_EPSILON * 8;  // INVESTIGATE: why are larger multiples necessary?
 
 const SkDQuad quadraticModEpsilonLines[] = {
     {{{0, F}, {0, 0}, {1, 0}}},
@@ -64,7 +64,7 @@
     {{{1, 1+J}, {2, 2}, {3, 3}}},
     {{{1, 1}, {3, 3}, {3+F, 3}}},
     {{{1, 1}, {1+F, 1}, {2, 2}}},
-    {{{1, 1}, {2, 2}, {1, 1+K}}},
+    {{{1, 1}, {2, 2}, {1, 1+F}}},
     {{{1, 1}, {1, 1+F}, {3, 3}}},
     {{{1+H, 1}, {2, 2}, {4, 4}}},  // no coincident
     {{{1, 1+K}, {3, 3}, {4, 4}}},
diff --git a/tests/PathOpsQuadParameterizationTest.cpp b/tests/PathOpsQuadParameterizationTest.cpp
new file mode 100644
index 0000000..c7a2e87
--- /dev/null
+++ b/tests/PathOpsQuadParameterizationTest.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SkDQuadImplicit.h"
+#include "SkPathOpsQuad.h"
+#include "Test.h"
+
+static bool point_on_parameterized_curve(const SkDQuad& quad, const SkDPoint& point) {
+    SkDQuadImplicit q(quad);
+    double  xx = q.x2() * point.fX * point.fX;
+    double  xy = q.xy() * point.fX * point.fY;
+    double  yy = q.y2() * point.fY * point.fY;
+    double   x = q.x() * point.fX;
+    double   y = q.y() * point.fY;
+    double   c = q.c();
+    double sum = xx + xy + yy + x + y + c;
+    return approximately_zero(sum);
+}
+
+static const SkDQuad quadratics[] = {
+    {{{0, 0}, {1, 0}, {1, 1}}},
+};
+
+static const int quadratics_count = (int) SK_ARRAY_COUNT(quadratics);
+
+DEF_TEST(PathOpsQuadImplicit, reporter) {
+    // split large quadratic
+    // compare original, parts, to see if the are coincident
+    for (int index = 0; index < quadratics_count; ++index) {
+        const SkDQuad& test = quadratics[index];
+        SkDQuadPair split = test.chopAt(0.5);
+        SkDQuad midThird = test.subDivide(1.0/3, 2.0/3);
+        const SkDQuad* quads[] = {
+            &test, &midThird, &split.first(), &split.second()
+        };
+        int quadsCount = (int) SK_ARRAY_COUNT(quads);
+        for (int one = 0; one < quadsCount; ++one) {
+            for (int two = 0; two < quadsCount; ++two) {
+                for (int inner = 0; inner < 3; inner += 2) {
+                     REPORTER_ASSERT(reporter, point_on_parameterized_curve(*quads[one],
+                            (*quads[two])[inner]));
+                }
+                REPORTER_ASSERT(reporter, SkDQuadImplicit::Match(*quads[one], *quads[two]));
+            }
+        }
+    }
+}
diff --git a/tests/PathOpsSimplifyFailTest.cpp b/tests/PathOpsSimplifyFailTest.cpp
index 53e33bc..2a4b0a0 100644
--- a/tests/PathOpsSimplifyFailTest.cpp
+++ b/tests/PathOpsSimplifyFailTest.cpp
@@ -86,7 +86,10 @@
     SkPath result;
     result.setFillType(SkPath::kWinding_FillType);
     bool success = Simplify(path, &result);
-    REPORTER_ASSERT(reporter, success);
+    // linux 32 debug fails test 13 because the quad is not treated as linear
+    // there's no error in the math that I can find -- it looks like a processor
+    // or compiler bug -- so for now, allow either to work
+    REPORTER_ASSERT(reporter, success || index == 13);
     REPORTER_ASSERT(reporter, result.getFillType() != SkPath::kWinding_FillType);
     reporter->bumpTestCount();
 }
diff --git a/tests/PathOpsSimplifyTest.cpp b/tests/PathOpsSimplifyTest.cpp
index 6a7b425..88547a0 100644
--- a/tests/PathOpsSimplifyTest.cpp
+++ b/tests/PathOpsSimplifyTest.cpp
@@ -3649,7 +3649,7 @@
     testSimplify(reporter, path, filename);
 }
 
-// A test for this case:
+// A test this for this case:
 // contourA has two segments that are coincident
 // contourB has two segments that are coincident in the same place
 // each ends up with +2/0 pairs for winding count
@@ -4506,6 +4506,8 @@
     testSimplify(reporter, path, filename);
 }
 
+// this fails because there is a short unorderable segment and the unordered state isn't handled
+// correctly later on.
 static void testQuads46x(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -4677,9 +4679,7 @@
     testSimplify(reporter, path, filename);
 }
 
-static void (*skipTest)(skiatest::Reporter* , const char* filename) = 0;
-static void (*firstTest)(skiatest::Reporter* , const char* filename) = testCubic2;
-static void (*stopTest)(skiatest::Reporter* , const char* filename) = 0;
+static void (*firstTest)(skiatest::Reporter* , const char* filename) = 0;
 
 static TestDesc tests[] = {
     TEST(testRect3),
@@ -4738,7 +4738,7 @@
     TEST(testQuadralateral3),
     TEST(testDegenerate5),
     TEST(testQuad12),
-    TEST(testQuadratic51),
+    TEST(testQuadratic51),  // has unorderable angles
     TEST(testQuad8),
     TEST(testQuad11),
     TEST(testQuad10),
@@ -5111,13 +5111,14 @@
 static bool runSubTests = false;
 static bool runSubTestsFirst = false;
 static bool runReverse = false;
+static void (*stopTest)(skiatest::Reporter* , const char* filename) = 0;
 
 DEF_TEST(PathOpsSimplify, reporter) {
     if (runSubTests && runSubTestsFirst) {
-        RunTestSet(reporter, subTests, subTestCount, firstSubTest, NULL, stopTest, runReverse);
+        RunTestSet(reporter, subTests, subTestCount, firstSubTest, stopTest, runReverse);
     }
-    RunTestSet(reporter, tests, testCount, firstTest, skipTest, stopTest, runReverse);
+    RunTestSet(reporter, tests, testCount, firstTest, stopTest, runReverse);
     if (runSubTests && !runSubTestsFirst) {
-        RunTestSet(reporter, subTests, subTestCount, firstSubTest, NULL, stopTest, runReverse);
+        RunTestSet(reporter, subTests, subTestCount, firstSubTest, stopTest, runReverse);
     }
 }
diff --git a/tests/PathOpsSkpTest.cpp b/tests/PathOpsSkpTest.cpp
index 58a69ad..6af790f 100755
--- a/tests/PathOpsSkpTest.cpp
+++ b/tests/PathOpsSkpTest.cpp
@@ -896,6 +896,19 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
+/* this cubic/quad pair
+ c = 430,280 430,278.895416 473.876068,278 528,278
+ q = 430,280 430.009796,277.101196 458.703552,275.050262
+ only intersect at the shared point (430,280)
+ they sort backwards because the tangent from pt[0] to control pt[1]
+ c' = (0.00000000000000000, -1.1045837402343750)
+ q' = (0.0097961425781250000, -2.8988037109375000)
+ suggests that the quad is counterclockwise of the cubic, when the reverse is true
+ the angle code is fooled because the control pt[1] of both the quad and cubic
+ is far away from cubic cntl [2] and quad pt [2].
+ Maybe in angle setup, this instability can be detected to suppress sorting on the initial tangent
+ Or the error term can be passed to NearRay that is magnified by the distance from the next ctrl?
+ */
 static void skpnaoxrane_ru23(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -928,6 +941,11 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
+/* didn't investigate thoroughly, but looks to be missorting quad and cubic
+    {{468.507751,560.724426}, {467.275146,552.856262}, {465.84668,547.288391}}
+    {{463.779907,542.671143}, {464.829529,542.672974}, {466.946289,550.755676}, {468.507751,560.724426}}
+    decision maker is case 14 leftLessThanRight
+ */
 static void skptcmevents_org23(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -1061,7 +1079,7 @@
     pathB.lineTo(149, 675);
     pathB.cubicTo(149, 672.790833f, 151.238571f, 671, 154, 671);
     pathB.close();
-    testPathOpCheck(reporter, path, pathB, kIntersect_PathOp, filename, FLAGS_runFail);
+    testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
 static void skpcyclist_friends_gr52(skiatest::Reporter* reporter, const char* filename) {
@@ -1087,12 +1105,10 @@
     pathB.cubicTo(52.238575f, 207, 50, 204.761429f, 50, 202);
     pathB.lineTo(50, 183);
     pathB.close();
-    // 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
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
+/* cubic ends just above opp line */
 static void skpwww_fj_p_com_22(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -1112,6 +1128,7 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
+// pair of lines are not quite coincident, so sorting line/cubic fails (i think)
 static void skpwww_lavoixdunord_fr_11(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -1144,6 +1161,9 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
+// pair of curves have nearly the same initial tangent but are sorting by
+// that alone sorts them incorrectly. Need to detect that tangents are nearly
+// identical and not reliable by themselves
 static void skppptv_com_62(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -1170,6 +1190,7 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
+// nearly identical to lavoixdunord -- to not-quite-coincident lines
 static void skpwww_booking_com_68(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -1202,6 +1223,7 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
+// visually looks like lavoixdunord and www_booking_com
 static void skpwww_despegar_com_mx_272(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -1561,6 +1583,11 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
+/* Three edges are partially coincident. Only one of the three knows about the other two.
+   Subsequently, when the angle loop is created, it misses one of the edges.
+   After coincident edges are processed, probably need a check-and-correct that makes sure the
+   coincidences are all self-consistent.
+ */
 static void skpelpais_com_18(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -1579,6 +1606,13 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
+/* this generates a pair of lines that are essentially coincident; but the next line at a right
+   angle is not treated as if it intersects at the same point.
+   There are several of options:
+     move the intersection of the right angle line to the coincident point (should 'near' do this?
+     construct another coincident pair from the right angle line to the coincident point
+     treat the intersection as simple and not coincident
+ */
 static void skpnamecheap_com_405(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -1597,6 +1631,7 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
+// fails on angle insert -- haven't investigated yet
 static void skpwww_alrakoba_net_62(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -1622,6 +1657,7 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
+/* asserts in alignSpanState looks like a coincident related bug */
 static void skpwww_cityads_ru_249(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -1658,6 +1694,7 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
+// fails on angle insert
 static void skpwww_dealnews_com_315(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -1684,6 +1721,7 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
+// fails in intersections insert
 static void skpwww_inmotionhosting_com_9(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -1728,6 +1766,7 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
+// /SkOpContour.cpp:278: failed assertion "!approximately_negative(oEndT - oStartT)
 static void skpwww_hairjobsearch_com_31(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -1748,6 +1787,7 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
+// SkOpSegment::checkSmallCoincidence; line 1958 SkASSERT(span.fWindValue);
 static void skpwww_heartiste_wordpress_com_86(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -1785,6 +1825,7 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
+// SkOpSegment::checkSmallCoincidence; line 1958 SkASSERT(span.fWindValue);
 static void skpwww_320kbps_net_2231(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -1803,6 +1844,7 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
+// debugValidateLoop loop sum fails
 static void skpwww_exystence_net_61(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -1821,6 +1863,7 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
+// debugValidateLoop loop sum fails
 static void skpwww_trashness_com_36(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -1839,6 +1882,7 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
+// SkIntersections::lineVertical fUsed >= fMax
 static void skpwww_getgold_jp_731(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -1860,6 +1904,7 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
+// SkOpContour::calcPartialCoincidentWinding SkASSERT(!approximately_negative(endT - startT));
 static void skpwww_maturesupertube_com_21(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -1900,6 +1945,7 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
+// can't find winding of remaining vertical edges
 static void skpwww_hubbyscook_com_22(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -1947,6 +1993,7 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
+// asserts in bridgeOp simple->isClosed()
 static void skpwww_phototransferapp_com_24(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -2087,6 +2134,7 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
+// !simple->isClosed()
 static void skpwww_contextualnewsfeeds_com_346(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -2110,6 +2158,7 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
+// line quad intersection SkIntersections::assert
 static void skpwww_pindosiya_com_99(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -2131,6 +2180,7 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
+// SkOpAngle::setSector SkASSERT(fSectorStart >= 0);
 static void skpwww_karnivool_com_au_11(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -2253,6 +2303,7 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
+// joinCoincidence / findT / assert
 static void skpwww_jessicaslens_wordpress_com_222(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -2281,6 +2332,7 @@
     testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
 }
 
+// joinCoincidence / findT / assert
 static void skpwww_simplysaru_com_40(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -2309,6 +2361,7 @@
     testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
 }
 
+// cubic-cubic intersection reduce checkLinear assert
 static void skpwww_partsdata_de_53(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -2607,6 +2660,7 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
+// SkOpAngle::setSector SkASSERT(fSectorStart >= 0);
 static void skpwww_seopack_blogspot_com_2153(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -2630,6 +2684,7 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
+// joinCoincidence / findT / assert
 static void skpwww_lokado_de_173(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -2666,6 +2721,7 @@
     testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
 }
 
+// !simple->isClosed()
 static void skpwww_wartepop_blogspot_com_br_6(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -2730,6 +2786,7 @@
     testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
 }
 
+// !simple->isClosed()
 static void skpwww_odia_com_br_26(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -2813,6 +2870,7 @@
     testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
 }
 
+// hangs
 static void skpwww_catingueiraonline_com_352(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -2831,6 +2889,7 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
+// hangs
 static void skpwww_galaxystwo_com_4(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -3554,7 +3613,12 @@
     pathB.quadTo(4942.75146f, 1523, 4962.375f, 1542.6239f);
     pathB.quadTo(4981.99902f, 1562.24768f, 4981.99902f, 1590);
     pathB.close();
-    testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+    if (FLAGS_runFail) {
+        testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+    } else {
+        // INVESTIGATE : why this normal test takes fail case (test has never worked)
+        testPathFailOp(reporter, path, pathB, kIntersect_PathOp, filename);
+    }
 }
 
 static void skpwww_alamdi_com_3(skiatest::Reporter* reporter, const char* filename) {
@@ -3643,6 +3707,7 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
+// addSimpleAngle: failed assertion "index == count() - 2"
 static void skpwww_shinydemos_com_5(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -3662,6 +3727,7 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
+// addTCoincident oPeek = &other->fTs[++oPeekIndex];
 static void skpwww_lptemp_com_3(skiatest::Reporter* reporter, const char* filename) {
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -3715,7 +3781,11 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
 }
 
+// SkOpSegment.cpp:4398: failed assertion "!span->fDone"
 static void skpwww_lptemp_com_5(skiatest::Reporter* reporter, const char* filename) {
+    if (/* 0 && */ !FLAGS_runFail) {  // has never worked MUST BE FIXED BEFORE NEXT CHECKIN
+        return;
+    }
     SkPath path;
     path.setFillType(SkPath::kEvenOdd_FillType);
     path.moveTo(78.6429825f, 3150.97632f);
@@ -3744,36 +3814,12 @@
     pathB.lineTo(77.6666718f, 3153.3335f);
     pathB.cubicTo(77.6666718f, 3151.49268f, 79.15905f, 3150, 81, 3150);
     pathB.close();
-    testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+    testPathOpCheck(reporter, path, pathB, kIntersect_PathOp, filename, FLAGS_runFail);
 }
 
-static void skpwww_educationalcraft_com_4a(skiatest::Reporter* reporter, const char* filename) {
-    SkPath path;
-    path.setFillType(SkPath::kEvenOdd_FillType);
-    path.moveTo(941, 1494);
-    path.lineTo(941, 1464);
-    path.lineTo(985, 1464);
-    path.lineTo(985, 1494);
-    path.lineTo(941, 1494);
-    path.close();
-    SkPath pathB;
-    pathB.setFillType(SkPath::kWinding_FillType);
-
-pathB.moveTo(984.546021f, 1478.31494f);
-pathB.cubicTo(984.546021f, 1478.31494f, 984.543213f, 1478.32239f, 984.537598f, 1478.33655f);
-pathB.cubicTo(984.419006f, 1478.63477f, 983.044373f, 1481.90405f, 980.026001f, 1481.276f);
-pathB.cubicTo(980.026001f, 1481.276f, 980.02594f, 1481.27576f, 980.025879f, 1481.27527f);
-pathB.cubicTo(980.018494f, 1481.22131f, 979.602478f, 1478.38831f, 984.546021f, 1478.31494f);
-    testPathOp(reporter, path, pathB, kIntersect_PathOp, 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 struct TestDesc tests[] = {
-    TEST(skpwww_educationalcraft_com_4a),
     TEST(skpwww_lptemp_com_3),
     TEST(skpwww_shinydemos_com_5),
     TEST(skpwww_lptemp_com_5),
@@ -3893,10 +3939,11 @@
 static const size_t testCount = SK_ARRAY_COUNT(tests);
 
 static bool runReverse = false;
+static void (*stopTest)(skiatest::Reporter* , const char* filename) = 0;
 
 DEF_TEST(PathOpsSkp, reporter) {
 #if DEBUG_SHOW_TEST_NAME
     strncpy(DEBUG_FILENAME_STRING, "", DEBUG_FILENAME_STRING_LENGTH);
 #endif
-    RunTestSet(reporter, tests, testCount, firstTest, skipTest, stopTest, runReverse);
+    RunTestSet(reporter, tests, testCount, firstTest, stopTest, runReverse);
 }
diff --git a/tests/PathOpsTSectDebug.h b/tests/PathOpsTSectDebug.h
index b4715e6..5f8915f 100644
--- a/tests/PathOpsTSectDebug.h
+++ b/tests/PathOpsTSectDebug.h
@@ -8,158 +8,77 @@
 #include "SkPathOpsTSect.h"
 
 template<typename TCurve>
-const SkTSpan<TCurve>* SkTSect<TCurve>::debugSpan(int id) const {
-    const SkTSpan<TCurve>* test = fHead;
-    do {
-        if (test->debugID() == id) {
-            return test;
-        }
-    } while ((test = test->next()));
-#ifndef SK_RELEASE
-    test = fOppSect->fHead;
-    do {
-        if (test->debugID() == id) {
-            return test;
-        }
-    } while ((test = test->next()));
-#endif
-    return NULL;
-}
-
-template<typename TCurve>
-const SkTSpan<TCurve>* SkTSect<TCurve>::debugT(double t) const {
-    const SkTSpan<TCurve>* test = fHead;
-    const SkTSpan<TCurve>* closest = NULL;
-    double bestDist = DBL_MAX;
-    do {
-        if (between(test->fStartT, t, test->fEndT)) {
-            return test;
-        }
-        double testDist = SkTMin(fabs(test->fStartT - t), fabs(test->fEndT - t));
-        if (bestDist > testDist) {
-            bestDist = testDist;
-            closest = test;
-        }
-    } while ((test = test->next()));
-    SkASSERT(closest);
-    return closest;
-}
-
-template<typename TCurve>
 void SkTSect<TCurve>::dump() const {
-    dumpCommon(fHead);
-}
-
-extern int gDumpTSectNum;
-
-template<typename TCurve>
-void SkTSect<TCurve>::dumpBoth(SkTSect* opp) const {
-#if DEBUG_T_SECT_DUMP <= 2
-#if DEBUG_T_SECT_DUMP == 2
-    SkDebugf("%d ", ++gDumpTSectNum);
-#endif
-    this->dump();
-    SkDebugf(" ");
-    opp->dump();
-    SkDebugf("\n");
-#elif DEBUG_T_SECT_DUMP == 3
-    SkDebugf("<div id=\"sect%d\">\n", ++gDumpTSectNum);
-    if (this->fHead) {
-        this->dumpCurves();
-    }
-    if (opp->fHead) {
-        PATH_OPS_DEBUG_CODE(opp->dumpCurves());
-    }
-    SkDebugf("</div>\n\n");
-#endif
-}
-
-template<typename TCurve>
-void SkTSect<TCurve>::dumpBounds(int id) const {
-    const SkTSpan<TCurve>* bounded = debugSpan(id);
-    if (!bounded) {
-        SkDebugf("no span matches %d\n", id);
-        return;
-    }
-    const SkTSpan<TCurve>* test = bounded->debugOpp()->fHead;
-    do {
-        if (test->findOppSpan(bounded)) {
-            test->dump();
-        }
-    } while ((test = test->next()));
-}
-
-template<typename TCurve>
-void SkTSect<TCurve>::dumpCoin() const {
-    dumpCommon(fCoincident);
-}
-
-template<typename TCurve>
-void SkTSect<TCurve>::dumpCoinCurves() const {
-    dumpCommonCurves(fCoincident);
-}
-
-template<typename TCurve>
-void SkTSect<TCurve>::dumpCommon(const SkTSpan<TCurve>* test) const {
     SkDebugf("id=%d", debugID());
+    const SkTSpan<TCurve>* test = fHead;
     if (!test) {
         SkDebugf(" (empty)");
         return;
     }
     do {
         SkDebugf(" ");
-        test->dump();
+        test->dump(this);
     } while ((test = test->next()));
 }
 
 template<typename TCurve>
-void SkTSect<TCurve>::dumpCommonCurves(const SkTSpan<TCurve>* test) const {
-    do {
-        test->fPart.dumpID(test->debugID());
-    } while ((test = test->next()));
+void SkTSect<TCurve>::dumpBoth(const SkTSect& opp) const {
+    dump();
+    SkDebugf(" ");
+    opp.dump();
+    SkDebugf("\n");
+}
+
+template<typename TCurve>
+void SkTSect<TCurve>::dumpBoth(const SkTSect* opp) const {
+    dumpBoth(*opp);
 }
 
 template<typename TCurve>
 void SkTSect<TCurve>::dumpCurves() const {
-    dumpCommonCurves(fHead);
+    const SkTSpan<TCurve>* test = fHead;
+    do {
+        test->fPart.dump();
+    } while ((test = test->next()));
+}
+
+#if !DEBUG_T_SECT
+template<typename TCurve>
+int SkTSpan<TCurve>::debugID(const SkTSect<TCurve>* sect) const {
+    if (!sect) {
+        return -1;
+    }
+    int id = 1;
+    const SkTSpan* test = sect->fHead;
+    while (test && test != this) {
+        ++id;
+        test = test->fNext;
+    }
+    return id;
+}
+#endif
+
+template<typename TCurve>
+void SkTSpan<TCurve>::dumpID(const SkTSect<TCurve>* sect) const {
+    if (fCoinStart.isCoincident()) {
+        SkDebugf("%c", '*');
+    }
+    SkDebugf("%d", debugID(sect));
+    if (fCoinEnd.isCoincident()) {
+        SkDebugf("%c", '*');
+    }
 }
 
 template<typename TCurve>
-const SkTSpan<TCurve>* SkTSpan<TCurve>::debugSpan(int id) const {
-    return PATH_OPS_DEBUG_RELEASE(fDebugSect->debugSpan(id), NULL);
-}
-
-template<typename TCurve>
-const SkTSpan<TCurve>* SkTSpan<TCurve>::debugT(double t) const {
-    return PATH_OPS_DEBUG_RELEASE(fDebugSect->debugT(t), NULL);
-}
-
-template<typename TCurve>
-void SkTSpan<TCurve>::dump() const {
-    dumpID();
+void SkTSpan<TCurve>::dump(const SkTSect<TCurve>* sect) const {
+    dumpID(sect);
     SkDebugf("=(%g,%g) [", fStartT, fEndT);
     for (int index = 0; index < fBounded.count(); ++index) {
         SkTSpan* span = fBounded[index];
-        span->dumpID();
+        span->dumpID(sect);
         if (index < fBounded.count() - 1) {
             SkDebugf(",");
         }
     }
     SkDebugf("]");
 }
-
-template<typename TCurve>
-void SkTSpan<TCurve>::dumpBounds(int id) const {
-    PATH_OPS_DEBUG_CODE(fDebugSect->dumpBounds(id));
-}
-
-template<typename TCurve>
-void SkTSpan<TCurve>::dumpID() const {
-    if (fCoinStart.isCoincident()) {
-        SkDebugf("%c", '*');
-    }
-    SkDebugf("%d", debugID());
-    if (fCoinEnd.isCoincident()) {
-        SkDebugf("%c", '*');
-    }
-}
diff --git a/tests/PathOpsTestCommon.cpp b/tests/PathOpsTestCommon.cpp
index f1cba8e..60a12ee 100644
--- a/tests/PathOpsTestCommon.cpp
+++ b/tests/PathOpsTestCommon.cpp
@@ -9,129 +9,11 @@
 #include "SkPathOpsCubic.h"
 #include "SkPathOpsLine.h"
 #include "SkPathOpsQuad.h"
-#include "SkReduceOrder.h"
-#include "SkTSort.h"
-
-static double calc_t_div(const SkDCubic& cubic, double precision, double start) {
-    const double adjust = sqrt(3.) / 36;
-    SkDCubic sub;
-    const SkDCubic* cPtr;
-    if (start == 0) {
-        cPtr = &cubic;
-    } else {
-        // OPTIMIZE: special-case half-split ?
-        sub = cubic.subDivide(start, 1);
-        cPtr = &sub;
-    }
-    const SkDCubic& c = *cPtr;
-    double dx = c[3].fX - 3 * (c[2].fX - c[1].fX) - c[0].fX;
-    double dy = c[3].fY - 3 * (c[2].fY - c[1].fY) - c[0].fY;
-    double dist = sqrt(dx * dx + dy * dy);
-    double tDiv3 = precision / (adjust * dist);
-    double t = SkDCubeRoot(tDiv3);
-    if (start > 0) {
-        t = start + (1 - start) * t;
-    }
-    return t;
-}
-
-static bool add_simple_ts(const SkDCubic& cubic, double precision, SkTArray<double, true>* ts) {
-    double tDiv = calc_t_div(cubic, precision, 0);
-    if (tDiv >= 1) {
-        return true;
-    }
-    if (tDiv >= 0.5) {
-        ts->push_back(0.5);
-        return true;
-    }
-    return false;
-}
-
-static void addTs(const SkDCubic& cubic, double precision, double start, double end,
-        SkTArray<double, true>* ts) {
-    double tDiv = calc_t_div(cubic, precision, 0);
-    double parts = ceil(1.0 / tDiv);
-    for (double index = 0; index < parts; ++index) {
-        double newT = start + (index / parts) * (end - start);
-        if (newT > 0 && newT < 1) {
-            ts->push_back(newT);
-        }
-    }
-}
-
-static void toQuadraticTs(const SkDCubic* cubic, double precision, SkTArray<double, true>* ts) {
-    SkReduceOrder reducer;
-    int order = reducer.reduce(*cubic, SkReduceOrder::kAllow_Quadratics);
-    if (order < 3) {
-        return;
-    }
-    double inflectT[5];
-    int inflections = cubic->findInflections(inflectT);
-    SkASSERT(inflections <= 2);
-    if (!cubic->endsAreExtremaInXOrY()) {
-        inflections += cubic->findMaxCurvature(&inflectT[inflections]);
-        SkASSERT(inflections <= 5);
-    }
-    SkTQSort<double>(inflectT, &inflectT[inflections - 1]);
-    // OPTIMIZATION: is this filtering common enough that it needs to be pulled out into its
-    // own subroutine?
-    while (inflections && approximately_less_than_zero(inflectT[0])) {
-        memmove(inflectT, &inflectT[1], sizeof(inflectT[0]) * --inflections);
-    }
-    int start = 0;
-    int next = 1;
-    while (next < inflections) {
-        if (!approximately_equal(inflectT[start], inflectT[next])) {
-            ++start;
-        ++next;
-            continue;
-        }
-        memmove(&inflectT[start], &inflectT[next], sizeof(inflectT[0]) * (--inflections - start));
-    }
-
-    while (inflections && approximately_greater_than_one(inflectT[inflections - 1])) {
-        --inflections;
-    }
-    SkDCubicPair pair;
-    if (inflections == 1) {
-        pair = cubic->chopAt(inflectT[0]);
-        int orderP1 = reducer.reduce(pair.first(), SkReduceOrder::kNo_Quadratics);
-        if (orderP1 < 2) {
-            --inflections;
-        } else {
-            int orderP2 = reducer.reduce(pair.second(), SkReduceOrder::kNo_Quadratics);
-            if (orderP2 < 2) {
-                --inflections;
-            }
-        }
-    }
-    if (inflections == 0 && add_simple_ts(*cubic, precision, ts)) {
-        return;
-    }
-    if (inflections == 1) {
-        pair = cubic->chopAt(inflectT[0]);
-        addTs(pair.first(), precision, 0, inflectT[0], ts);
-        addTs(pair.second(), precision, inflectT[0], 1, ts);
-        return;
-    }
-    if (inflections > 1) {
-        SkDCubic part = cubic->subDivide(0, inflectT[0]);
-        addTs(part, precision, 0, inflectT[0], ts);
-        int last = inflections - 1;
-        for (int idx = 0; idx < last; ++idx) {
-            part = cubic->subDivide(inflectT[idx], inflectT[idx + 1]);
-            addTs(part, precision, inflectT[idx], inflectT[idx + 1], ts);
-        }
-        part = cubic->subDivide(inflectT[last], 1);
-        addTs(part, precision, inflectT[last], 1, ts);
-        return;
-    }
-    addTs(*cubic, precision, 0, 1, ts);
-}
+#include "SkPathOpsTriangle.h"
 
 void CubicToQuads(const SkDCubic& cubic, double precision, SkTArray<SkDQuad, true>& quads) {
     SkTArray<double, true> ts;
-    toQuadraticTs(&cubic, precision, &ts);
+    cubic.toQuadraticTs(precision, &ts);
     if (ts.count() <= 0) {
         SkDQuad quad = cubic.toQuad();
         quads.push_back(quad);
@@ -298,6 +180,15 @@
     return true;
 }
 
+bool ValidTriangle(const SkDTriangle& triangle) {
+    for (int index = 0; index < 3; ++index) {
+        if (!ValidPoint(triangle.fPts[index])) {
+            return false;
+        }
+    }
+    return true;
+}
+
 bool ValidVector(const SkDVector& v) {
     if (SkDoubleIsNaN(v.fX)) {
         return false;
diff --git a/tests/PathOpsTestCommon.h b/tests/PathOpsTestCommon.h
index 7a72ff2..0c42bfb 100644
--- a/tests/PathOpsTestCommon.h
+++ b/tests/PathOpsTestCommon.h
@@ -21,6 +21,7 @@
 bool ValidPoint(const SkDPoint& pt);
 bool ValidPoints(const SkPoint* pts, int count);
 bool ValidQuad(const SkDQuad& quad);
+bool ValidTriangle(const SkDTriangle& triangle);
 bool ValidVector(const SkDVector& v);
 
 #endif
diff --git a/tests/PathOpsThreeWayTest.cpp b/tests/PathOpsThreeWayTest.cpp
index bf634f9..15d6e54 100644
--- a/tests/PathOpsThreeWayTest.cpp
+++ b/tests/PathOpsThreeWayTest.cpp
@@ -49,16 +49,14 @@
             const Curve& iTest = testSet.tests[inner];
             SkIntersections* i = combos.append();
             sk_bzero(i, sizeof(SkIntersections));
-            SkDLine oLine = {{ oTest.curve[0], oTest.curve[1] }};
-            SkDLine iLine = {{ iTest.curve[0], iTest.curve[1] }};
             if (oTest.ptCount == 1 && iTest.ptCount == 1) {
-                i->intersect(oLine, iLine);
+                i->intersect(*(const SkDLine*) &oTest.curve, *(const SkDLine*) &iTest.curve);
             } else if (oTest.ptCount == 1 && iTest.ptCount == 4) {
-                i->intersect(iTest.curve, oLine);
+                i->intersect(iTest.curve, *(const SkDLine*) &oTest.curve);
             } else if (oTest.ptCount == 4 && iTest.ptCount == 1) {
-                i->intersect(oTest.curve, iLine);
+                i->intersect(oTest.curve, *(const SkDLine*) &oTest.curve);
             } else if (oTest.ptCount == 4 && iTest.ptCount == 4) {
-                i->intersect(oTest.curve, iTest.curve);
+                i->intersectB(oTest.curve, iTest.curve);
             } else {
                 SkASSERT(0);
             }
diff --git a/tests/PathOpsTightBoundsTest.cpp b/tests/PathOpsTightBoundsTest.cpp
index d50c26a..cea3752 100644
--- a/tests/PathOpsTightBoundsTest.cpp
+++ b/tests/PathOpsTightBoundsTest.cpp
@@ -8,6 +8,7 @@
 #include "PathOpsThreadedCommon.h"
 #include "SkCanvas.h"
 #include "SkRandom.h"
+#include "SkTArray.h"
 #include "SkTSort.h"
 #include "Test.h"