path ops -- rewrite angle sort

This is a major change resulting from a minor
tweak. In the old code, the intersection point
of two curves was shared between them, but the
intersection points and end points of sorted edges was
computed directly from the intersection T value.

In this CL, both intersection points and sorted points
are the same, and intermediate control points are computed
to preserve their slope.

The sort itself has been completely rewritten to be more
robust and remove 'magic' checks, conditions that empirically
worked but couldn't be rationalized.

This CL was triggered by errors generated computing the clips
of SKP files. At this point, all 73M standard tests work and
at least the first troublesome SKPs work.

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

git-svn-id: http://skia.googlecode.com/svn/trunk@9432 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/tests/PathOpsAngleTest.cpp b/tests/PathOpsAngleTest.cpp
index 003b8c8..ad91c87 100644
--- a/tests/PathOpsAngleTest.cpp
+++ b/tests/PathOpsAngleTest.cpp
@@ -5,6 +5,7 @@
  * found in the LICENSE file.
  */
 #include "SkOpSegment.h"
+#include "SkTArray.h"
 #include "Test.h"
 
 static const SkPoint cubics[][4] = {
@@ -22,11 +23,18 @@
 /* 10 */   {{0,1}, {1,3}, {1,0}, {6,4}},
 /* 11 */   {{0,1}, {2,3}, {2,1}, {4,3}},
 /* 12 */   {{1,2}, {3,4}, {1,0}, {3,2}},
+/* 13 */   {{0,1}, {4,6}, {4,3}, {5,4}},
+/* 14 */   {{806,11419}, {806.962890625,11419}, {807.76690673828125,11418.3193359375}, {807.957275390625,11417.4130859375}},
+/* 15 */   {{808,11417}, {808,11418.1044921875}, {807.10455322265625,11419}, {806,11419}},
+/* 16 */   {{132,11419}, {130.89543151855469,11419}, {130,11418.1044921875}, {130,11417}},
+/* 17 */   {{130.04275512695312,11417.4130859375}, {130.23312377929687,11418.3193359375}, {131.03707885742187,11419}, {132,11419}},
 };
 
 static const SkPoint quads[][3] = {
 /* 0 */    {{12.3423996f, 228.342407f}, {10, 230.686295f}, {10, 234}},
 /* 1 */    {{304.24319458007812f,591.75677490234375f}, {306,593.51470947265625f}, {306,596}},
+/* 2 */    {{0,0}, {3,1}, {0,3}},
+/* 3 */    {{0,1}, {3,1}, {0,2}},
 };
 
 static const SkPoint lines[][2] = {
@@ -40,6 +48,7 @@
 /* 7 */    {{192,4}, {243,4}},
 /* 8 */    {{4,3}, {0,1}},
 /* 9 */    {{3,2}, {1,2}},
+/* 10 */   {{6,4}, {3,4}},
 };
 
 struct SortSet {
@@ -47,133 +56,214 @@
     int ptCount;
     double tStart;
     double tEnd;
+    SkPoint endPt;
 };
 
 static const SortSet set1[] = {
-    {cubics[0], 4, 0.66666987081928919, 0.875},
-    {lines[0], 2, 0.574070336, 0.388888889},
-    {cubics[0], 4, 0.66666987081928919, 0.4050371120499307 },
-    {lines[0], 2, 0.574070336, 0.9140625},
+    {cubics[0], 4, 0.66666987081928919, 0.875, {0, 0}},
+    {lines[0], 2, 0.574070336, 0.388888889, {0, 0}},
+    {cubics[0], 4, 0.66666987081928919, 0.4050371120499307, {0, 0}},
+    {lines[0], 2, 0.574070336, 0.9140625, {0, 0}},
+};
+
+static const SortSet set1a[] = {
+    {cubics[0], 4, 0.666666667, 0.405037112, {4.58007812f,2.83203125f}},
+    {lines[0], 2, 0.574074074, 0.9140625, {4.44444466f,2.77777767f}},
 };
 
 static const SortSet set2[] = {
-    {cubics[0], 4, 0.666666667, 0.875},
-    {lines[0], 2, 0.574074074, 0.388888889},
-    {cubics[0], 4, 0.666666667, 0.405037112},
-    {lines[0], 2, 0.574074074, 0.9140625},
+    {cubics[0], 4, 0.666666667, 0.875, {0, 0}},
+    {lines[0], 2, 0.574074074, 0.388888889, {0, 0}},
+    {cubics[0], 4, 0.666666667, 0.405037112, {0, 0}},
+    {lines[0], 2, 0.574074074, 0.9140625, {0, 0}},
 };
 
 static const SortSet set3[] = {
-    {cubics[1], 4, 0, 1},
-    {quads[0], 3, 1, 0},
+    {cubics[1], 4, 0, 1, {0, 0}},
+    {quads[0], 3, 1, 0, {0, 0}},
 };
 
 static const SortSet set4[] = {
-    {cubics[2], 4, 0.812114222, 1},
-    {cubics[3], 4, 0.0684734759, 0},
+    {cubics[2], 4, 0.812114222, 1, {0, 0}},
+    {cubics[3], 4, 0.0684734759, 0, {0, 0}},
 };
 
 static const SortSet set5[] = {
-    {lines[1], 2, 0.777777778, 1},
-    {quads[1], 3, 1, 4.34137342e-06},
-    {lines[2], 2, 0, 1},
+    {lines[1], 2, 0.777777778, 1, {0, 0}},
+    {quads[1], 3, 1, 4.34137342e-06, {0, 0}},
+    {lines[2], 2, 0, 1, {0, 0}},
+};
+
+static const SortSet set5a[] = {
+    {lines[1], 2, 0.777777778, 1, {306,590}},
+    {quads[1], 3, 1, 4.34137342e-06, {304.243195f,591.756775f}},
+    {lines[2], 2, 0, 1, {306,617}},
 };
 
 static const SortSet set6[] = {
-    {lines[3], 2, 0.407407407, 0.554627832},
-    {cubics[4], 4, 0.666666667, 0.548022446},
-    {lines[3], 2, 0.407407407, 0},
-    {cubics[4], 4, 0.666666667, 1},
+    {lines[3], 2, 0.407407407, 0.554627832, {0, 0}},
+    {cubics[4], 4, 0.666666667, 0.548022446, {0, 0}},
+    {lines[3], 2, 0.407407407, 0, {0, 0}},
+    {cubics[4], 4, 0.666666667, 1, {0, 0}},
+};
+
+static const SortSet set6a[] = {
+    {lines[3], 2, 0.407407407, 0.554627832, {2.6722331f,2.33611655f}},
+    {cubics[4], 4, 0.666666667, 0.548022446, {2.61642241f,2.83718514f}},
+    {lines[3], 2, 0.407407407, 0, {6,4}},
+    {cubics[4], 4, 0.666666667, 1, {6,4}},
 };
 
 static const SortSet set7[] = {
-    {cubics[5], 4, 0.545233342, 0.545454545},
-    {cubics[6], 4, 0.484938134, 0.484805744},
-    {cubics[5], 4, 0.545233342, 0},
-    {cubics[6], 4, 0.484938134, 0.545454545},
+    {cubics[5], 4, 0.545233342, 0.545454545, {0, 0}},
+    {cubics[6], 4, 0.484938134, 0.484805744, {0, 0}},
+    {cubics[5], 4, 0.545233342, 0, {0, 0}},
+    {cubics[6], 4, 0.484938134, 0.545454545, {0, 0}},
 };
 
 static const SortSet set8[] = {
-    {cubics[7], 4, 0.5, 0.522986744 },
-    {lines[4], 2, 0.75, 1},
-    {cubics[7], 4, 0.5, 0},
-    {lines[4], 2, 0.75, 0.737654321},
+    {cubics[7], 4, 0.5, 0.522986744, {0, 0}},
+    {lines[4], 2, 0.75, 1, {0, 0}},
+    {cubics[7], 4, 0.5, 0, {0, 0}},
+    {lines[4], 2, 0.75, 0.737654321, {0, 0}},
+};
+
+static const SortSet set8a[] = {
+    {cubics[7], 4, 0.5, 0.522986744, {1.60668361f,0.965592742f}},
+    {lines[4], 2, 0.75, 1, {0,1}},
+    {cubics[7], 4, 0.5, 0, {0,1}},
+    {lines[4], 2, 0.75, 0.737654321, {1.57407403f,1}},
 };
 
 static const SortSet set9[] = {
-    {cubics[8], 4, 0.4, 1},
-    {lines[5], 2, 0.36, 0},
-    {cubics[8], 4, 0.4, 0.394675838},
-    {lines[5], 2, 0.36, 0.363999782},
+    {cubics[8], 4, 0.4, 1, {0, 0}},
+    {lines[5], 2, 0.36, 0, {0, 0}},
+    {cubics[8], 4, 0.4, 0.394675838, {0, 0}},
+    {lines[5], 2, 0.36, 0.363999782, {0, 0}},
 };
 
 static const SortSet set10[] = {
-    {lines[6], 2, 0.947368421, 1},
-    {cubics[9], 4, 1, 0.500000357},
-    {lines[7], 2, 0, 1},
+    {lines[6], 2, 0.947368421, 1, {0, 0}},
+    {cubics[9], 4, 1, 0.500000357, {0, 0}},
+    {lines[7], 2, 0, 1, {0, 0}},
 };
 
 static const SortSet set11[] = {
-    {lines[3], 2, 0.75, 1},
-    {cubics[10], 4, 0.5, 0.228744269},
-    {lines[3], 2, 0.75, 0.627112191},
-    {cubics[10], 4, 0.5, 0.6339746},
+    {lines[3], 2, 0.75, 1, {0, 0}},
+    {cubics[10], 4, 0.5, 0.228744269, {0, 0}},
+    {lines[3], 2, 0.75, 0.627112191, {0, 0}},
+    {cubics[10], 4, 0.5, 0.6339746, {0, 0}},
 };
 
 static const SortSet set12[] = {
-    {cubics[12], 4, 0.5, 1},
-    {lines[8], 2, 0.5, 1},
-    {cubics[11], 4, 0.5, 0},
-    {lines[9], 2, 0.5, 1},
-    {cubics[12], 4, 0.5, 0},
-    {lines[8], 2, 0.5, 0},
-    {cubics[11], 4, 0.5, 1},
-    {lines[9], 2, 0.5, 0},
+    {cubics[12], 4, 0.5, 1, {0, 0}},
+    {lines[8], 2, 0.5, 1, {0, 0}},
+    {cubics[11], 4, 0.5, 0, {0, 0}},
+    {lines[9], 2, 0.5, 1, {0, 0}},
+    {cubics[12], 4, 0.5, 0, {0, 0}},
+    {lines[8], 2, 0.5, 0, {0, 0}},
+    {cubics[11], 4, 0.5, 1, {0, 0}},
+    {lines[9], 2, 0.5, 0, {0, 0}},
+};
+
+static const SortSet set13[] = {
+    {cubics[13], 4, 0.5, 0.400631046, {0, 0}},
+    {lines[10], 2, 0.791666667, 0.928, {0, 0}},
+    {lines[10], 2, 0.791666667, 0.333333333, {0, 0}},
+    {cubics[13], 4, 0.5, 0.866666667, {0, 0}},
+};
+
+static const SortSet set14[] = {
+    {quads[2], 3, 0.5, 0.310102051, {0, 0}},
+    {quads[3], 3, 0.5, 0.2, {0, 0}},
+    {quads[3], 3, 0.5, 0.770156212, {0, 0}},
+    {quads[2], 3, 0.5, 0.7, {0, 0}},
+};
+
+static const SortSet set15[] = {
+    {cubics[14], 4, 0.93081374, 1, {0, 0}},
+    {cubics[15], 4, 0.188518131, 0, {0, 0}},
+    {cubics[14], 4, 0.93081374, 0, {0, 0}},
+};
+
+static const SortSet set16[] = {
+    {cubics[17], 4, 0.0682619216, 0, {130.042755f,11417.4131f}},
+    {cubics[16], 4, 0.812302088, 1, {130,11417}},
+    {cubics[17], 4, 0.0682619216, 1, {132,11419}},
 };
 
 struct SortSetTests {
+    const char* name;
     const SortSet* set;
     size_t count;
+    SkPoint startPt;
 };
 
+#define TEST_ENTRY(name) #name, name, SK_ARRAY_COUNT(name)
+
 static const SortSetTests tests[] = {
-    { set12, SK_ARRAY_COUNT(set12) },
-    { set11, SK_ARRAY_COUNT(set11) },
-    { set10, SK_ARRAY_COUNT(set10) },
-    { set9, SK_ARRAY_COUNT(set9) },
-    { set8, SK_ARRAY_COUNT(set8) },
-    { set7, SK_ARRAY_COUNT(set7) },
-    { set6, SK_ARRAY_COUNT(set6) },
-    { set2, SK_ARRAY_COUNT(set2) },
-    { set5, SK_ARRAY_COUNT(set5) },
-    { set4, SK_ARRAY_COUNT(set4) },
-    { set3, SK_ARRAY_COUNT(set3) },
-    { set1, SK_ARRAY_COUNT(set1) },
+    { TEST_ENTRY(set16), {130.090179f,11417.5957f} },
+//    { TEST_ENTRY(set15), {0, 0}},
+    { TEST_ENTRY(set14), {0, 0}},
+    { TEST_ENTRY(set13), {0, 0}},
+    { TEST_ENTRY(set12), {0, 0}},
+    { TEST_ENTRY(set11), {0, 0}},
+    { TEST_ENTRY(set10), {0, 0}},
+    { TEST_ENTRY(set9), {0, 0}},
+    { TEST_ENTRY(set6a), {3.55555558f,2.77777767f} },
+    { TEST_ENTRY(set8a), {1.5f,1} },
+    { TEST_ENTRY(set8), {0, 0}},
+    { TEST_ENTRY(set7), {0, 0}},
+    { TEST_ENTRY(set6a), {3.55555558f,2.77777767f} },
+    { TEST_ENTRY(set6), {0, 0}},
+    { TEST_ENTRY(set5a), {306,596} },
+    { TEST_ENTRY(set5), {0, 0}},
+//    { TEST_ENTRY(set4), {0, 0}},
+    { TEST_ENTRY(set3), {0, 0}},
+    { TEST_ENTRY(set2), {0, 0}},
+//    { TEST_ENTRY(set1a), {3.70370364f,3.14814806f} },
+    { TEST_ENTRY(set1), {0, 0}},
 };
 
-static void setup(const SortSet* set, const size_t idx, SkPoint const ** data,
-        SkOpSegment* seg, int* ts) {
+#undef TEST_ENTRY
+
+static void setup(const SortSet* set, const size_t idx,
+        SkOpSegment* seg, int* ts, const SkPoint& startPt) {
     SkPoint start, end;
-    *data = set[idx].ptData;
+    const SkPoint* data = set[idx].ptData;
+    bool useIntersectPt = startPt.fX != 0 || startPt.fY != 0;
+    if (useIntersectPt) {
+        start = startPt;
+        end = set[idx].endPt;
+    }
     switch(set[idx].ptCount) {
         case 2: {
-            seg->addLine(*data, false, false);
+            seg->addLine(data, false, false);
             SkDLine dLine;
             dLine.set(set[idx].ptData);
+            if (useIntersectPt) {
+                break;
+            }
             start = dLine.xyAtT(set[idx].tStart).asSkPoint();
             end = dLine.xyAtT(set[idx].tEnd).asSkPoint();
             } break;
         case 3: {
-            seg->addQuad(*data, false, false);
+            seg->addQuad(data, false, false);
             SkDQuad dQuad;
             dQuad.set(set[idx].ptData);
+             if (useIntersectPt) {
+                break;
+            }
             start = dQuad.xyAtT(set[idx].tStart).asSkPoint();
             end = dQuad.xyAtT(set[idx].tEnd).asSkPoint();
             } break;
         case 4: {
-            seg->addCubic(*data, false, false);
+            seg->addCubic(data, false, false);
             SkDCubic dCubic;
             dCubic.set(set[idx].ptData);
+            if (useIntersectPt) {
+                break;
+            }
             start = dCubic.xyAtT(set[idx].tStart).asSkPoint();
             end = dCubic.xyAtT(set[idx].tEnd).asSkPoint();
             } break;
@@ -182,13 +272,11 @@
     double tEnd = set[idx].tEnd;
     seg->addT(NULL, start, tStart);
     seg->addT(NULL, end, tEnd);
-    double tLeft = tStart < tEnd ? 0 : 1;
-    if (tStart != tLeft && tEnd != tLeft) {
-        seg->addT(NULL, set[idx].ptData[0], tLeft);
+    if (tStart != 0 && tEnd != 0) {
+        seg->addT(NULL, set[idx].ptData[0], 0);
     }
-    double tRight = tStart < tEnd ? 1 : 0;
-    if (tStart != tRight && tEnd != tRight) {
-        seg->addT(NULL, set[idx].ptData[set[idx].ptCount - 1], tRight);
+    if (tStart != 1 && tEnd != 1) {
+        seg->addT(NULL, set[idx].ptData[set[idx].ptCount - 1], 1);
     }
     int tIndex = 0;
     do {
@@ -207,30 +295,153 @@
 static void PathOpsAngleTest(skiatest::Reporter* reporter) {
     for (size_t index = 0; index < SK_ARRAY_COUNT(tests); ++index) {
         const SortSetTests& test = tests[index];
-        for (size_t idxL = 0; idxL < test.count - 1; ++idxL) {
-            SkOpSegment lesser, greater;
-            int lesserTs[2], greaterTs[2];
-            const SkPoint* lesserData, * greaterData;
+        SkTDArray<SkOpAngle> angles;
+        bool unsortable = false;
+        bool unorderable = false;
+        SkTArray<SkOpSegment> segs;
+        for (size_t idx = 0; idx < test.count; ++idx) {
+            int ts[2];
             const SortSet* set = test.set;
-            setup(set, idxL, &lesserData, &lesser, lesserTs);
-            size_t idxG = idxL + 1;
-            setup(set, idxG, &greaterData, &greater, greaterTs);
-            SkOpAngle first, second;
-            first.set(lesserData, SkPathOpsPointsToVerb(set[idxL].ptCount - 1), &lesser,
-                    lesserTs[0], lesserTs[1], lesser.spans());
-            second.set(greaterData, SkPathOpsPointsToVerb(set[idxG].ptCount - 1), &greater,
-                    greaterTs[0], greaterTs[1], greater.spans());
-            bool compare = first < second;
-            if (!compare) {
-                SkDebugf("%s test[%d]:  lesser[%d] > greater[%d]\n", __FUNCTION__,
-                        index, idxL,  idxG);
-                compare = first < second;
+            SkOpSegment& seg = segs.push_back();
+            setup(set, idx, &seg, ts, test.startPt);
+            SkOpAngle* angle = angles.append();
+            angle->set(&seg, ts[0], ts[1]);
+#if DEBUG_ANGLE
+            angle->setID(idx);
+#endif
+           if (angle->unsortable()) {
+#if DEBUG_ANGLE
+                SkDebugf("%s test[%s]:  angle[%d] unsortable\n", __FUNCTION__, test.name, idx);
+#endif
+                unsortable = true;
             }
-            REPORTER_ASSERT(reporter, compare);
+            if (angle->unorderable()) {
+#if DEBUG_ANGLE
+                SkDebugf("%s test[%s]:  angle[%d] unorderable\n", __FUNCTION__, test.name, idx);
+#endif
+                unorderable = true;
+            }
             reporter->bumpTestCount();
         }
+        if (unsortable || unorderable) {
+            continue;
+        }
+#if DEBUG_ANGLE
+        SkDebugf("%s test[%s]\n", __FUNCTION__, test.name);
+#endif
+        for (size_t idxL = 0; idxL < test.count; ++idxL) {
+            const SkOpAngle& first = angles[idxL];
+            for (size_t idxG = 0; idxG < test.count; ++idxG) {
+                if (idxL == idxG) {
+                    continue;
+                }
+                const SkOpAngle& second = angles[idxG];
+                bool compare = first < second;
+                if (idxL < idxG) {
+                    if (!compare) {
+                        SkDebugf("%s test[%s]:  first[%d] > second[%d]\n", __FUNCTION__,
+                                test.name,  idxL,  idxG);
+                        compare = first < second;
+                    }
+                    REPORTER_ASSERT(reporter, compare);
+                } else {
+                    SkASSERT(idxL > idxG);
+                    if (compare) {
+                        SkDebugf("%s test[%s]:  first[%d] < second[%d]\n", __FUNCTION__,
+                                test.name,  idxL,  idxG);
+                        compare = first < second;
+                    }
+                    REPORTER_ASSERT(reporter, !compare);
+                }
+                compare = second < first;
+                if (idxL < idxG) {
+                    if (compare) {
+                        SkDebugf("%s test[%s]:  second[%d] < first[%d]\n", __FUNCTION__,
+                                test.name,  idxL,  idxG);
+                        compare = second < first;
+                    }
+                    REPORTER_ASSERT(reporter, !compare);
+                } else {
+                    SkASSERT(idxL > idxG);
+                    if (!compare) {
+                        SkDebugf("%s test[%s]:  second[%d] > first[%d]\n", __FUNCTION__,
+                                test.name,  idxL,  idxG);
+                        compare = second < first;
+                    }
+                    REPORTER_ASSERT(reporter, compare);
+                }
+            }
+        }
+        reporter->bumpTestCount();
     }
 }
 
+#if 0
+static int find_slop(double x, double y, double rx, double ry) {
+    int slopBits = 0;
+    bool less1, less2;
+    double absX = fabs(x);
+    double absY = fabs(y);
+    double length = absX < absY ? absX / 2 + absY : absX + absY / 2;
+    int exponent;
+    (void) frexp(length, &exponent);
+    double epsilon = ldexp(FLT_EPSILON, exponent);
+    do {
+        // get the length as the larger plus half the smaller (both same signs)
+        // find the ulps of the length
+        // compute the offsets from there
+        double xSlop = epsilon * slopBits;
+        double ySlop = x * y < 0 ? -xSlop : xSlop; // OPTIMIZATION: use copysign / _copysign ?
+        double x1 = x - xSlop;
+        double y1 = y + ySlop;
+        double x_ry1 = x1 * ry;
+        double rx_y1 = rx * y1;
+        less1 = x_ry1 < rx_y1;
+        double x2 = x + xSlop;
+        double y2 = y - ySlop;
+        double x_ry2 = x2 * ry;
+        double rx_y2 = rx * y2;
+        less2 = x_ry2 < rx_y2;
+    } while (less1 == less2 && ++slopBits);
+    return slopBits;
+}
+
+// from http://stackoverflow.com/questions/1427422/cheap-algorithm-to-find-measure-of-angle-between-vectors
+static double diamond_angle(double y, double x)
+{
+    if (y >= 0)
+        return (x >= 0 ? y/(x+y) : 1-x/(-x+y)); 
+    else
+        return (x < 0 ? 2-y/(-x-y) : 3+x/(x-y)); 
+}
+
+static const double slopTests[][4] = {
+   // x                      y                       rx                      ry
+    {-0.058554756452593892, -0.18804585843827226, -0.018568569646021160, -0.059615294434479438},
+    {-0.0013717412948608398, 0.0041152238845825195, -0.00045837944195925573, 0.0013753175735478074},
+    {-2.1033774145221198, -1.4046019261273715e-008, -0.70062688352066704, -1.2706324683777995e-008},
+};
+
+static void PathOpsAngleFindSlop(skiatest::Reporter* reporter) {
+    for (size_t index = 0; index < SK_ARRAY_COUNT(slopTests); ++index) {
+        const double* slopTest = slopTests[index];
+        double x = slopTest[0];
+        double y = slopTest[1];
+        double rx = slopTest[2];
+        double ry = slopTest[3];
+        SkDebugf("%s  xy %d=%d\n", __FUNCTION__, (int) index, find_slop(x, y, rx, ry)); 
+        SkDebugf("%s rxy %d=%d\n", __FUNCTION__, (int) index, find_slop(rx, ry, x, y)); 
+        double angle = diamond_angle(y, x);
+        double rAngle = diamond_angle(ry, rx);
+        double diff = fabs(angle - rAngle);
+        SkDebugf("%s diamond xy=%1.9g rxy=%1.9g diff=%1.9g factor=%d\n", __FUNCTION__,
+                angle, rAngle, diff, (int) (diff / FLT_EPSILON));
+
+    }
+}
+#endif
+
 #include "TestClassDef.h"
 DEFINE_TESTCLASS_SHORT(PathOpsAngleTest)
+
+// DEFINE_TESTCLASS_SHORT(PathOpsAngleFindSlop)
diff --git a/tests/PathOpsCubicIntersectionTest.cpp b/tests/PathOpsCubicIntersectionTest.cpp
index 58d7d98..b0d6bd8 100644
--- a/tests/PathOpsCubicIntersectionTest.cpp
+++ b/tests/PathOpsCubicIntersectionTest.cpp
@@ -163,6 +163,12 @@
 const size_t testSetCount = SK_ARRAY_COUNT(testSet);
 
 static const SkDCubic newTestSet[] = {
+{{{134,11414}, {131.990234375,11414}, {130.32666015625,11415.482421875}, {130.04275512695312,11417.4130859375}}},
+{{{132,11419}, {130.89543151855469,11419}, {130,11418.1044921875}, {130,11417}}},
+
+{{{132,11419}, {130.89543151855469,11419}, {130,11418.1044921875}, {130,11417}}},
+{{{130.04275512695312,11417.4130859375}, {130.23312377929687,11418.3193359375}, {131.03707885742187,11419}, {132,11419}}},
+
 {{{0, 1}, {2, 3}, {5, 1}, {4, 3}}},
 {{{1, 5}, {3, 4}, {1, 0}, {3, 2}}},
 
@@ -231,10 +237,10 @@
 static void oneOff(skiatest::Reporter* reporter, const SkDCubic& cubic1, const SkDCubic& cubic2) {
 #if ONE_OFF_DEBUG
     SkDebugf("computed quadratics given\n");
-    SkDebugf("  {{{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}}},\n",
+    SkDebugf("  {{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}},\n",
         cubic1[0].fX, cubic1[0].fY, cubic1[1].fX, cubic1[1].fY,
         cubic1[2].fX, cubic1[2].fY, cubic1[3].fX, cubic1[3].fY);
-    SkDebugf("  {{{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}}},\n",
+    SkDebugf("  {{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}},\n",
         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
@@ -244,7 +250,7 @@
     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,
+        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
@@ -254,7 +260,7 @@
     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,
+        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
@@ -267,12 +273,15 @@
         xy1 = cubic1.xyAtT(tt1);
         tt2 = intersections[1][pt3];
         xy2 = cubic2.xyAtT(tt2);
+        const SkDPoint& iPt = intersections.pt(pt3);
 #if ONE_OFF_DEBUG
         SkDebugf("%s t1=%1.9g (%1.9g, %1.9g) (%1.9g, %1.9g) (%1.9g, %1.9g) t2=%1.9g\n",
-                __FUNCTION__, tt1, xy1.fX, xy1.fY, intersections.pt(pt3).fX,
-                intersections.pt(pt3).fY, xy2.fX, xy2.fY, tt2);
+                __FUNCTION__, tt1, xy1.fX, xy1.fY, iPt.fX,
+                iPt.fY, xy2.fX, xy2.fY, tt2);
 #endif
-        REPORTER_ASSERT(reporter, xy1.approximatelyEqual(xy2));
+       REPORTER_ASSERT(reporter, xy1.approximatelyEqual(iPt));
+       REPORTER_ASSERT(reporter, xy2.approximatelyEqual(iPt));
+       REPORTER_ASSERT(reporter, xy1.approximatelyEqual(xy2));
     }
 }
 
diff --git a/tests/PathOpsCubicToQuadsTest.cpp b/tests/PathOpsCubicToQuadsTest.cpp
index f18784f..f738e07 100644
--- a/tests/PathOpsCubicToQuadsTest.cpp
+++ b/tests/PathOpsCubicToQuadsTest.cpp
@@ -20,7 +20,7 @@
         double precision = cubic.calcPrecision();
         SkTDArray<SkDQuad> quads;
         CubicToQuads(cubic, precision, quads);
-        if (quads.count() != 1) {
+        if (quads.count() != 1 && quads.count() != 2) {
             SkDebugf("%s [%d] cubic to quadratics failed count=%d\n", name, static_cast<int>(index),
                     quads.count());
         }
@@ -36,11 +36,11 @@
         double precision = cubic.calcPrecision();
         SkTDArray<SkDQuad> quads;
         CubicToQuads(cubic, precision, quads);
-        if (quads.count() != 1) {
+        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);
+        REPORTER_ASSERT(reporter, quads.count() <= 2);
     }
 }
 
diff --git a/tests/PathOpsExtendedTest.cpp b/tests/PathOpsExtendedTest.cpp
index 71631c1..a9ca58b 100644
--- a/tests/PathOpsExtendedTest.cpp
+++ b/tests/PathOpsExtendedTest.cpp
@@ -45,27 +45,27 @@
 static bool gComparePathsAssert = true;
 static bool gPathStrAssert = true;
 
-static void showPathContours(SkPath::Iter& iter) {
+static void showPathContours(SkPath::Iter& iter, const char* suffix) {
     uint8_t verb;
     SkPoint pts[4];
     while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
         switch (verb) {
             case SkPath::kMove_Verb:
-                SkDebugf("path.moveTo(%1.9g,%1.9g);\n", pts[0].fX, pts[0].fY);
+                SkDebugf("    path%s.moveTo(%1.9g,%1.9g);\n", suffix, pts[0].fX, pts[0].fY);
                 continue;
             case SkPath::kLine_Verb:
-                SkDebugf("path.lineTo(%1.9g,%1.9g);\n", pts[1].fX, pts[1].fY);
+                SkDebugf("    path%s.lineTo(%1.9g,%1.9g);\n", suffix, pts[1].fX, pts[1].fY);
                 break;
             case SkPath::kQuad_Verb:
-                SkDebugf("path.quadTo(%1.9g,%1.9g, %1.9g,%1.9g);\n",
+                SkDebugf("    path%s.quadTo(%1.9g,%1.9g, %1.9g,%1.9g);\n", suffix,
                     pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY);
                 break;
             case SkPath::kCubic_Verb:
-                SkDebugf("path.cubicTo(%1.9g,%1.9g, %1.9g,%1.9g, %1.9g,%1.9g);\n",
+                SkDebugf("    path%s.cubicTo(%1.9g,%1.9g, %1.9g,%1.9g, %1.9g,%1.9g);\n", suffix,
                     pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY, pts[3].fX, pts[3].fY);
                 break;
             case SkPath::kClose_Verb:
-                SkDebugf("path.close();\n");
+                SkDebugf("    path%s.close();\n", suffix);
                 break;
             default:
                 SkDEBUGFAIL("bad verb");
@@ -74,11 +74,6 @@
     }
 }
 
-void showPath(const SkPath& path, const char* str) {
-    SkDebugf("%s\n", !str ? "original:" : str);
-    showPath(path);
-}
-
 static const char* fillTypeStr[] = {
     "kWinding_FillType",
     "kEvenOdd_FillType",
@@ -86,7 +81,7 @@
     "kInverseEvenOdd_FillType"
 };
 
-void showPath(const SkPath& path) {
+static void showPath(const SkPath& path, const char* suffix) {
     SkPath::Iter iter(path, true);
 #define SUPPORT_RECT_CONTOUR_DETECTION 0
 #if SUPPORT_RECT_CONTOUR_DETECTION
@@ -108,12 +103,13 @@
 #endif
     SkPath::FillType fillType = path.getFillType();
     SkASSERT(fillType >= SkPath::kWinding_FillType && fillType <= SkPath::kInverseEvenOdd_FillType);
-    SkDebugf("path.setFillType(%s);\n", fillTypeStr[fillType]);
+    SkDebugf("    path%s.setFillType(SkPath::%s);\n", suffix, fillTypeStr[fillType]);
     iter.setPath(path, true);
-    showPathContours(iter);
+    showPathContours(iter, suffix);
 }
 
-void showPathData(const SkPath& path) {
+#if DEBUG_SHOW_TEST_NAME
+static void showPathData(const SkPath& path) {
     SkPath::Iter iter(path, true);
     uint8_t verb;
     SkPoint pts[4];
@@ -142,6 +138,7 @@
         }
     }
 }
+#endif
 
 void showOp(const SkPathOp op) {
     switch (op) {
@@ -165,6 +162,7 @@
     }
 }
 
+#if 0
 static void showPath(const SkPath& path, const char* str, const SkMatrix& scale) {
     SkPath scaled;
     SkMatrix inverse;
@@ -175,6 +173,7 @@
     path.transform(inverse, &scaled);
     showPath(scaled, str);
 }
+#endif
 
 #if DEBUG_SHOW_TEST_NAME
 static char hexorator(int x) {
@@ -326,8 +325,8 @@
 
 static void showSimplifiedPath(const SkPath& one, const SkPath& two,
         const SkPath& scaledOne, const SkPath& scaledTwo) {
-    showPath(one, "original:");
-    showPath(two, "simplified:");
+    showPath(one, "");
+ //   showPath(two, "simplified:");
     drawAsciiPaths(scaledOne, scaledTwo, true);
 }
 
@@ -355,12 +354,15 @@
         const SkPath& scaledOne, const SkPath& scaledTwo, const SkPathOp shapeOp,
         const SkMatrix& scale) {
     SkASSERT((unsigned) shapeOp < SK_ARRAY_COUNT(opStrs));
-    showPath(a, "minuend:");
-    SkDebugf("op: %s\n", opStrs[shapeOp]);
-    showPath(b, "subtrahend:");
+    SkDebugf("static void xOp#%s(skiatest::Reporter* reporter) {\n", opSuffixes[shapeOp]);
+    SkDebugf("    SkPath path, pathB;\n");
+    showPath(a, "");
+    showPath(b, "B");
+    SkDebugf("    testPathOp(reporter, path, pathB, %s);\n", opStrs[shapeOp]);
+    SkDebugf("}\n");
     // the region often isn't very helpful since it approximates curves with a lot of line-tos
-    if (0) showPath(scaledOne, "region:", scale);
-    showPath(two, "op result:");
+ //   if (0) showPath(scaledOne, "region:", scale);
+ //   showPath(two, "op result:");
     drawAsciiPaths(scaledOne, scaledTwo, true);
 }
 
@@ -448,7 +450,7 @@
     SkPath::FillType fillType = useXor ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType;
     path.setFillType(fillType);
     if (gShowPath) {
-        showPath(path);
+        showPath(path, "");
     }
     if (!Simplify(path, &out)) {
         SkDebugf("%s did not expect failure\n", __FUNCTION__);
diff --git a/tests/PathOpsExtendedTest.h b/tests/PathOpsExtendedTest.h
index 5644c94..5e91dc1 100644
--- a/tests/PathOpsExtendedTest.h
+++ b/tests/PathOpsExtendedTest.h
@@ -26,9 +26,6 @@
 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 void showPath(const SkPath& path, const char* str);
-extern void showPath(const SkPath& path);
-extern void showPathData(const SkPath& path);
 extern bool testPathOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
                         const SkPathOp );
 extern bool testSimplify(SkPath& path, bool useXor, SkPath& out, PathOpsThreadState& state,
diff --git a/tests/PathOpsLineParametetersTest.cpp b/tests/PathOpsLineParametetersTest.cpp
index 0361e1a..3b223ae 100644
--- a/tests/PathOpsLineParametetersTest.cpp
+++ b/tests/PathOpsLineParametetersTest.cpp
@@ -40,7 +40,7 @@
     for (size_t index = 0; index < tests_count; ++index) {
         SkLineParameters lineParameters;
         const SkDCubic& cubic = tests[index];
-        lineParameters.cubicEndPoints(cubic);
+        lineParameters.cubicEndPoints(cubic, 0, 3);
         double denormalizedDistance[2];
         denormalizedDistance[0] = lineParameters.controlPtDistance(cubic, 1);
         denormalizedDistance[1] = lineParameters.controlPtDistance(cubic, 2);
diff --git a/tests/PathOpsOpTest.cpp b/tests/PathOpsOpTest.cpp
index 48ed866..9a48f78 100644
--- a/tests/PathOpsOpTest.cpp
+++ b/tests/PathOpsOpTest.cpp
@@ -1385,6 +1385,21 @@
     testPathOp(reporter, path, pathB, kDifference_PathOp);
 }
 
+static void cubicOp74d(skiatest::Reporter* reporter) {
+    SkPath path, pathB;
+    path.setFillType(SkPath::kWinding_FillType);
+    path.moveTo(0,1);
+    path.cubicTo(1,5, 5,1, 5,1);
+    path.lineTo(0,1);
+    path.close();
+    pathB.setFillType(SkPath::kWinding_FillType);
+    pathB.moveTo(1,5);
+    pathB.cubicTo(1,5, 1,0, 5,1);
+    pathB.lineTo(1,5);
+    pathB.close();
+    testPathOp(reporter, path, pathB, kDifference_PathOp);
+}
+
 static void cubicOp75d(skiatest::Reporter* reporter) {
     SkPath path, pathB;
     path.setFillType(SkPath::kWinding_FillType);
@@ -1400,6 +1415,19 @@
     testPathOp(reporter, path, pathB, kDifference_PathOp);
 }
 
+static void cubicOp76u(skiatest::Reporter* reporter) {
+    SkPath path, pathB;
+    path.setFillType(SkPath::kWinding_FillType);
+    path.moveTo(0,1);
+    path.cubicTo(0,2, 2,0, 5,3);
+    path.close();
+    pathB.setFillType(SkPath::kWinding_FillType);
+    pathB.moveTo(0,2);
+    pathB.cubicTo(3,5, 1,0, 2,0);
+    pathB.close();
+    testPathOp(reporter, path, pathB, kUnion_PathOp);
+}
+
 static void cubicOp77i(skiatest::Reporter* reporter) {
     SkPath path, pathB;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -1430,19 +1458,6 @@
     testPathOp(reporter, path, pathB, kUnion_PathOp);
 }
 
-static void cubicOp79d(skiatest::Reporter* reporter) {
-    SkPath path, pathB;
-    path.setFillType(SkPath::kWinding_FillType);
-    path.moveTo(0,2);
-    path.cubicTo(0,1, 3,-0.1f, 1,0);
-    path.close();
-    pathB.setFillType(SkPath::kWinding_FillType);
-    pathB.moveTo(0,3);
-    pathB.cubicTo(0,1, 2,0, 1,0);
-    pathB.close();
-    testPathOp(reporter, path, pathB, kDifference_PathOp);
-}
-
 static void cubicOp79u(skiatest::Reporter* reporter) {
     SkPath path, pathB;
     path.setFillType(SkPath::kWinding_FillType);
@@ -1471,6 +1486,19 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp);
 }
 
+static void cubicOp81d(skiatest::Reporter* reporter) {
+    SkPath path, pathB;
+    path.setFillType(SkPath::kWinding_FillType);
+    path.moveTo(0,1);
+    path.cubicTo(4,6, 4,3, 5,4);
+    path.close();
+    pathB.setFillType(SkPath::kWinding_FillType);
+    pathB.moveTo(3,4);
+    pathB.cubicTo(4,5, 1,0, 6,4);
+    pathB.close();
+    testPathOp(reporter, path, pathB, kDifference_PathOp);
+}
+
 static void cubicOp82i(skiatest::Reporter* reporter) {
     SkPath path, pathB;
     path.setFillType(SkPath::kEvenOdd_FillType);
@@ -1486,30 +1514,110 @@
     testPathOp(reporter, path, pathB, kIntersect_PathOp);
 }
 
-static void cubicOp81d(skiatest::Reporter* reporter) {
+static void cubicOp83i(skiatest::Reporter* reporter) {
     SkPath path, pathB;
     path.setFillType(SkPath::kWinding_FillType);
     path.moveTo(0,1);
-    path.cubicTo(4,6, 4,3, 5,4);
+    path.cubicTo(0,3, 2,1, 4,1);
+    path.lineTo(0,1);
     path.close();
     pathB.setFillType(SkPath::kWinding_FillType);
-    pathB.moveTo(3,4);
-    pathB.cubicTo(4,5, 1,0, 6,4);
+    pathB.moveTo(1,2);
+    pathB.cubicTo(1,4, 1,0, 3,0);
+    pathB.lineTo(1,2);
+    pathB.close();
+    testPathOp(reporter, path, pathB, kIntersect_PathOp);
+}
+
+static void cubicOp84d(skiatest::Reporter* reporter) {
+    SkPath path, pathB;
+    path.setFillType(SkPath::kWinding_FillType);
+    path.moveTo(0,4);
+    path.cubicTo(2,3, 6,3, 3,2);
+    path.close();
+    pathB.setFillType(SkPath::kWinding_FillType);
+    pathB.moveTo(3,6);
+    pathB.cubicTo(2,3, 4,0, 3,2);
     pathB.close();
     testPathOp(reporter, path, pathB, kDifference_PathOp);
 }
 
-static void (*firstTest)(skiatest::Reporter* ) = cubicOp81d;
+static void skpClip1(skiatest::Reporter* reporter) {
+    SkPath path;
+    path.setFillType(SkPath::kEvenOdd_FillType);
+    path.moveTo(1126.17114f, 877.171204f);
+    path.quadTo(1127.34314f, 876.000000f, 1129.00000f, 876.000000f);
+    path.lineTo(1243.00000f, 876.000000f);
+    path.quadTo(1244.65686f, 876.000000f, 1245.82886f, 877.171204f);
+    path.quadTo(1247.00000f, 878.343140f, 1247.00000f, 880.000000f);
+    path.lineTo(1247.00000f, 907.000000f);
+    path.lineTo(1246.00000f, 907.000000f);
+    path.lineTo(1246.00000f, 880.000000f);
+    path.cubicTo(1246.00000f, 878.343140f, 1244.65686f, 877.000000f, 1243.00000f, 877.000000f);
+    path.lineTo(1129.00000f, 877.000000f);
+    path.cubicTo(1127.34314f, 877.000000f, 1126.00000f, 878.343140f, 1126.00000f, 880.000000f);
+    path.lineTo(1126.00000f, 907.000000f);
+    path.lineTo(1125.00000f, 907.000000f);
+    path.lineTo(1125.00000f, 880.000000f);
+    path.quadTo(1125.00000f, 878.343140f, 1126.17114f, 877.171204f);
+    path.close();
+    SkPath pathB;
+    pathB.setFillType(SkPath::kWinding_FillType);
+    pathB.moveTo(1247.00000f, 876.000000f);
+    pathB.lineTo(1231.00000f, 892.000000f);
+    pathB.lineTo(1246.00000f, 907.000000f);
+    pathB.lineTo(1247.00000f, 907.000000f);
+    pathB.lineTo(1247.00000f, 876.000000f);
+    pathB.close();
+    testPathOp(reporter, path, pathB, kIntersect_PathOp);
+}
+
+#if 1 // FIXME: work in progress -- coincident cubic undetected
+static void skpClip2(skiatest::Reporter* reporter) {
+    SkPath path;
+    path.setFillType(SkPath::kEvenOdd_FillType);
+    path.moveTo(134.000000f, 11414.0000f);
+    path.cubicTo(131.990234f, 11414.0000f, 130.326660f, 11415.4824f, 130.042755f, 11417.4131f);
+    path.cubicTo(130.233124f, 11418.3193f, 131.037079f, 11419.0000f, 132.000000f, 11419.0000f);
+    path.lineTo(806.000000f, 11419.0000f);
+    path.cubicTo(806.962891f, 11419.0000f, 807.766907f, 11418.3193f, 807.957275f, 11417.4131f);
+    path.cubicTo(807.673401f, 11415.4824f, 806.009766f, 11414.0000f, 804.000000f, 11414.0000f);
+    path.lineTo(134.000000f, 11414.0000f);
+    path.close();
+    SkPath pathB;
+    pathB.setFillType(SkPath::kInverseWinding_FillType);
+    pathB.moveTo(132.000000f, 11415.0000f);
+    pathB.lineTo(806.000000f, 11415.0000f);
+    pathB.cubicTo(807.104553f, 11415.0000f, 808.000000f, 11415.4473f, 808.000000f, 11416.0000f);
+    pathB.lineTo(808.000000f, 11417.0000f);
+    pathB.cubicTo(808.000000f, 11418.1045f, 807.104553f, 11419.0000f, 806.000000f, 11419.0000f);
+    pathB.lineTo(132.000000f, 11419.0000f);
+    pathB.cubicTo(130.895432f, 11419.0000f, 130.000000f, 11418.1045f, 130.000000f, 11417.0000f);
+    pathB.lineTo(130.000000f, 11416.0000f);
+    pathB.cubicTo(130.000000f, 11415.4473f, 130.895432f, 11415.0000f, 132.000000f, 11415.0000f);
+    pathB.close();
+    testPathOp(reporter, path, pathB, kIntersect_PathOp);
+}
+#endif
+
+static void (*firstTest)(skiatest::Reporter* ) = 0;
 
 static struct TestDesc tests[] = {
+#if 1 // FIXME: work in progress -- coincident cubic undetected
+    TEST(skpClip2),
+#endif
+    TEST(skpClip1),
+    TEST(cubicOp84d),
+    TEST(cubicOp83i),
     TEST(cubicOp82i),
     TEST(cubicOp81d),
     TEST(cubicOp80i),
     TEST(cubicOp79u),
-    TEST(cubicOp79d),
     TEST(cubicOp78u),
     TEST(cubicOp77i),
+    TEST(cubicOp76u),
     TEST(cubicOp75d),
+    TEST(cubicOp74d),
     TEST(cubicOp73d),
     TEST(cubicOp72i),
     TEST(cubicOp71d),
diff --git a/tests/PathOpsQuadIntersectionTest.cpp b/tests/PathOpsQuadIntersectionTest.cpp
index 4276051..4bb0b34 100644
--- a/tests/PathOpsQuadIntersectionTest.cpp
+++ b/tests/PathOpsQuadIntersectionTest.cpp
@@ -50,6 +50,19 @@
 }
 
 static const SkDQuad testSet[] = {
+    {{{131.37418,11414.9825}, {130.28798,11415.9328}, {130.042755,11417.4131}}},
+    {{{130.585787,11418.4142}, {130.021447,11417.8498}, {130,11417}}},
+
+    {{{130.73167037963867, 11418.546386718750}, {131.26360225677490, 11418.985778808592},
+            {132, 11419 }}},
+    {{{132, 11419}, {131.15012693405151, 11418.978546142578},
+            {130.58578681945801, 11418.414184570313}}},
+
+    {{{132, 11419},
+            {130.73167037963867, 11418.546386718750}, {131.26360225677490, 11418.985778808592}}},
+    {{{131.15012693405151, 11418.978546142578},
+            {130.58578681945801, 11418.414184570313}, {132, 11419}}},
+
     {{{3.0774019473063863, 3.35198509346713}, {3.0757503498668397, 3.327320623945933},
             {3.0744102085015879, 3.3025879417907196}}},
     {{{3.053913680774329, 3.3310471586283938}, {3.0758730889691694, 3.3273466070370152},
@@ -252,7 +265,7 @@
 }
 
 static void QuadraticIntersection_OneOffTest(skiatest::Reporter* reporter) {
-    oneOffTest1(reporter, 43, 47);
+    oneOffTest1(reporter, 0, 1);
 }
 
 static void oneOffTests(skiatest::Reporter* reporter) {
diff --git a/tests/PathOpsSimplifyTest.cpp b/tests/PathOpsSimplifyTest.cpp
index f4a332e..fe5f4e1 100644
--- a/tests/PathOpsSimplifyTest.cpp
+++ b/tests/PathOpsSimplifyTest.cpp
@@ -3772,9 +3772,51 @@
     testSimplify(reporter, path);
 }
 
-static void (*firstTest)(skiatest::Reporter* ) = testQuadratic85;
+static void testQuadLineIntersect1(skiatest::Reporter* reporter) {
+    SkPath path;
+    path.moveTo(0, 0);
+    path.quadTo(3, 1, 0, 3);
+    path.lineTo(2, 3);
+    path.close();
+    path.moveTo(2, 0);
+    path.lineTo(0, 1);
+    path.quadTo(3, 1, 0, 2);
+    path.close();
+    testSimplify(reporter, path);
+}
+
+static void testQuadLineIntersect2(skiatest::Reporter* reporter) {
+    SkPath path;
+    path.moveTo(0, 0);
+    path.quadTo(3, 1, 0, 3);
+    path.lineTo(0, 3);
+    path.close();
+    path.moveTo(2, 0);
+    path.lineTo(0, 1);
+    path.quadTo(3, 1, 0, 2);
+    path.close();
+    testSimplify(reporter, path);
+}
+
+static void testQuadLineIntersect3(skiatest::Reporter* reporter) {
+    SkPath path;
+    path.moveTo(0, 0);
+    path.quadTo(3, 1, 0, 3);
+    path.lineTo(1, 3);
+    path.close();
+    path.moveTo(2, 0);
+    path.lineTo(0, 1);
+    path.quadTo(3, 1, 0, 2);
+    path.close();
+    testSimplify(reporter, path);
+}
+
+static void (*firstTest)(skiatest::Reporter* ) = 0;
 
 static TestDesc tests[] = {
+    TEST(testQuadLineIntersect1),
+    TEST(testQuadLineIntersect2),
+    TEST(testQuadLineIntersect3),
     TEST(testQuad7),
     TEST(testQuad6),
     TEST(testQuad5),
diff --git a/tests/PathOpsSkpClipTest.cpp b/tests/PathOpsSkpClipTest.cpp
index d14cde5..98e5553 100644
--- a/tests/PathOpsSkpClipTest.cpp
+++ b/tests/PathOpsSkpClipTest.cpp
@@ -1,6 +1,7 @@
 #include "SkBitmap.h"
 #include "SkDevice.h"
 #include "SkCanvas.h"
+#include "SkImageDecoder.h"
 #include "SkImageEncoder.h"
 #include "SkStream.h"
 #include "SkOSFile.h"
@@ -18,14 +19,14 @@
 }
 
 static void PathOpsSkpClipTest(skiatest::Reporter* reporter) {
-const char pictDir[] = "C:\\Users\\caryclark\\skp";
-    const char outSkpClipDir[] = "C:\\Users\\caryclark\\skpClip";
-    const char outOldClipDir[] = "C:\\Users\\caryclark\\oldClip";
+    const char pictDir[] = "D:\\skp";
+    const char outSkpClipDir[] = "D:\\skpClip";
+    const char outOldClipDir[] = "D:\\oldClip";
     SkOSFile::Iter iter(pictDir, "skp");
     SkString filename;
     while (iter.next(&filename)) {
-#if 0
-        if (strcmp(filename.c_str(), "tabl_androidpolice.skp")) {
+#if 01
+        if (strcmp(filename.c_str(), "desk_15min-lt.skp")) {
             continue;
         }
 #endif
@@ -35,7 +36,11 @@
         if (!stream.isValid()) {
             continue;
         }
-        SkPicture* pic = SkNEW_ARGS(SkPicture, (&stream));
+        bool success;
+        SkPicture* pic = SkNEW_ARGS(SkPicture, (&stream, &success, &SkImageDecoder::DecodeMemory));
+        if (!success) {
+            continue;
+        }
         int width = pic->width();
         int height = pic->height();
         SkBitmap bitmap;
diff --git a/tests/PathOpsTestCommon.cpp b/tests/PathOpsTestCommon.cpp
index 86f6859..aab7d6e 100644
--- a/tests/PathOpsTestCommon.cpp
+++ b/tests/PathOpsTestCommon.cpp
@@ -10,7 +10,7 @@
 void CubicToQuads(const SkDCubic& cubic, double precision, SkTDArray<SkDQuad>& quads) {
     SkTDArray<double> ts;
     cubic.toQuadraticTs(precision, &ts);
-    if (ts.count() <= 1) {
+    if (ts.count() <= 0) {
         SkDQuad quad = cubic.toQuad();
         *quads.append() = quad;
         return;