shape ops work in progress
major milestone: 35.8M tests pass
(all rect/triangle/quadralateral)

git-svn-id: http://skia.googlecode.com/svn/trunk@5166 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/experimental/Intersection/EdgeWalkerPolygon4x4_Test.cpp b/experimental/Intersection/EdgeWalkerPolygon4x4_Test.cpp
index e795cd0..befac71 100755
--- a/experimental/Intersection/EdgeWalkerPolygon4x4_Test.cpp
+++ b/experimental/Intersection/EdgeWalkerPolygon4x4_Test.cpp
@@ -53,15 +53,13 @@
                             str += sprintf(str, "    path.lineTo(%d, %d);\n", hx, hy);
                             str += sprintf(str, "    path.close();\n");
                         }
-                        outputProgress(state, pathStr);
-                        testSimplifyx(path, out, state, pathStr);
+                        outputProgress(state, pathStr, SkPath::kWinding_FillType);
+                        testSimplifyx(path, false, out, state, pathStr);
                         state.testsRun++;
-                #if 0 // FIXME: enable once we have support for even/odd
                         path.setFillType(SkPath::kEvenOdd_FillType);
                         outputProgress(state, pathStr, SkPath::kEvenOdd_FillType);
                         testSimplifyx(path, true, out, state, pathStr);
                         state.testsRun++;
-                #endif
                     }
                 }
             }
@@ -70,7 +68,7 @@
     return NULL;
 }
 
-void Simplify4x4QuadralateralsThreaded_Test()
+void Simplify4x4QuadralateralsThreaded_Test(int& testsRun)
 {
     SkDebugf("%s\n", __FUNCTION__);
 #ifdef SK_DEBUG
@@ -79,7 +77,7 @@
 #endif
     const char testStr[] = "testQuadralateral";
     initializeTests(testStr, sizeof(testStr));
-    int testsRun = 0;
+    int testsStart = testsRun;
     for (int a = 0; a < 16; ++a) {
         for (int b = a ; b < 16; ++b) {
             for (int c = b ; c < 16; ++c) {
@@ -94,7 +92,7 @@
         if (!gRunTestsInOneThread) SkDebugf("\n%d", a);
     }
     testsRun += waitForCompletion();
-    SkDebugf("%s total tests run=%d\n", __FUNCTION__, testsRun);
+    SkDebugf("%s tests=%d total=%d\n", __FUNCTION__, testsRun - testsStart, testsRun);
 }
 
 
@@ -146,15 +144,13 @@
                         str += sprintf(str, "    path.lineTo(%d, %d);\n", fx, fy);
                         str += sprintf(str, "    path.close();\n");
                     }
-                    outputProgress(state, pathStr);
-                    testSimplifyx(path, out, state, pathStr);
+                    outputProgress(state, pathStr, SkPath::kWinding_FillType);
+                    testSimplifyx(path, false, out, state, pathStr);
                     state.testsRun++;
-            #if 0 // FIXME: enable once we have support for even/odd
                     path.setFillType(SkPath::kEvenOdd_FillType);
                     outputProgress(state, pathStr, SkPath::kEvenOdd_FillType);
                     testSimplifyx(path, true, out, state, pathStr);
                     state.testsRun++;
-            #endif
                 }
             }
         }
@@ -162,7 +158,7 @@
     return NULL;
 }
 
-void SimplifyNondegenerate4x4TrianglesThreaded_Test() {
+void SimplifyNondegenerate4x4TrianglesThreaded_Test(int& testsRun) {
     SkDebugf("%s\n", __FUNCTION__);
 #ifdef SK_DEBUG
     gDebugMaxWindSum = 2;
@@ -170,7 +166,7 @@
 #endif
     const char testStr[] = "testNondegenerate";
     initializeTests(testStr, sizeof(testStr));
-    int testsRun = 0;
+    int testsStart = testsRun;
     for (int a = 0; a < 15; ++a) {
         int ax = a & 0x03;
         int ay = a >> 2;
@@ -194,7 +190,7 @@
         if (!gRunTestsInOneThread) SkDebugf("\n%d", a);
     }
     testsRun += waitForCompletion();
-    SkDebugf("%s total tests run=%d\n", __FUNCTION__, testsRun);
+    SkDebugf("%s tests=%d total=%d\n", __FUNCTION__, testsRun - testsStart, testsRun);
 }
 
 static void* testSimplify4x4DegeneratesMain(void* data) {
@@ -243,15 +239,13 @@
                         str += sprintf(str, "    path.lineTo(%d, %d);\n", fx, fy);
                         str += sprintf(str, "    path.close();\n");
                     }
-                    outputProgress(state, pathStr);
-                    testSimplifyx(path, out, state, pathStr);
+                    outputProgress(state, pathStr, SkPath::kWinding_FillType);
+                    testSimplifyx(path, false, out, state, pathStr);
                     state.testsRun++;
-            #if 0 // FIXME: enable once we have support for even/odd
                     path.setFillType(SkPath::kEvenOdd_FillType);
                     outputProgress(state, pathStr, SkPath::kEvenOdd_FillType);
                     testSimplifyx(path, true, out, state, pathStr);
                     state.testsRun++;
-            #endif
                 }
             }
         }
@@ -259,7 +253,7 @@
     return NULL;
 }
 
-void SimplifyDegenerate4x4TrianglesThreaded_Test() {
+void SimplifyDegenerate4x4TrianglesThreaded_Test(int& testsRun) {
     SkDebugf("%s\n", __FUNCTION__);
 #ifdef SK_DEBUG
     gDebugMaxWindSum = 2;
@@ -267,7 +261,7 @@
 #endif
     const char testStr[] = "testDegenerate";
     initializeTests(testStr, sizeof(testStr));
-    int testsRun = 0;
+    int testsStart = testsRun;
     for (int a = 0; a < 16; ++a) {
         int ax = a & 0x03;
         int ay = a >> 2;
@@ -286,6 +280,6 @@
         if (!gRunTestsInOneThread) SkDebugf("\n%d", a);
     }
     testsRun += waitForCompletion();
-    SkDebugf("%s total tests run=%d\n", __FUNCTION__, testsRun);
+    SkDebugf("%s tests=%d total=%d\n", __FUNCTION__, testsRun - testsStart, testsRun);
 }
 
diff --git a/experimental/Intersection/EdgeWalkerQuadratic4x4_Test.cpp b/experimental/Intersection/EdgeWalkerQuadratic4x4_Test.cpp
index f714249..1f5af8e 100644
--- a/experimental/Intersection/EdgeWalkerQuadratic4x4_Test.cpp
+++ b/experimental/Intersection/EdgeWalkerQuadratic4x4_Test.cpp
@@ -53,15 +53,13 @@
                             str += sprintf(str, "    path.quadTo(%d, %d, %d, %d);\n", gx, gy, hx, hy);
                             str += sprintf(str, "    path.close();\n");
                         }
-                        outputProgress(state, pathStr);
-                        testSimplifyx(path, out, state, pathStr);
+                        outputProgress(state, pathStr, SkPath::kWinding_FillType);
+                        testSimplifyx(path, false, out, state, pathStr);
                         state.testsRun++;
-                #if 0 // FIXME: enable once we have support for even/odd
                         path.setFillType(SkPath::kEvenOdd_FillType);
                         outputProgress(state, pathStr, SkPath::kEvenOdd_FillType);
                         testSimplifyx(path, true, out, state, pathStr);
                         state.testsRun++;
-                #endif
                     }
                 }
             }
@@ -70,7 +68,7 @@
     return NULL;
 }
 
-void Simplify4x4QuadraticsThreaded_Test()
+void Simplify4x4QuadraticsThreaded_Test(int& testsRun)
 {
     SkDebugf("%s\n", __FUNCTION__);
 #ifdef SK_DEBUG
@@ -79,7 +77,7 @@
 #endif
     const char testStr[] = "testQuadratic";
     initializeTests(testStr, sizeof(testStr));
-    int testsRun = 0;
+    int testsStart = testsRun;
     for (int a = 0; a < 16; ++a) {
         for (int b = a ; b < 16; ++b) {
             for (int c = b ; c < 16; ++c) {
@@ -94,5 +92,5 @@
         if (!gRunTestsInOneThread) SkDebugf("\n%d", a);
     }
     testsRun += waitForCompletion();
-    SkDebugf("%s total tests run=%d\n", __FUNCTION__, testsRun);
+    SkDebugf("%s tests=%d total=%d\n", __FUNCTION__, testsRun - testsStart, testsRun);
 }
diff --git a/experimental/Intersection/EdgeWalker_Test.h b/experimental/Intersection/EdgeWalker_Test.h
index 229a94d..c86cefd 100644
--- a/experimental/Intersection/EdgeWalker_Test.h
+++ b/experimental/Intersection/EdgeWalker_Test.h
@@ -16,7 +16,7 @@
 extern void showPath(const SkPath& path, const char* str = NULL);
 extern bool testSimplify(const SkPath& path, bool fill, SkPath& out,
         SkBitmap& bitmap, SkCanvas* canvas = 0);
-extern bool testSimplifyx(const SkPath& path, SkPath& out,
+extern bool testSimplifyx(SkPath& path, bool useXor, SkPath& out,
         State4& state, const char* pathStr);
 extern bool testSimplifyx(const SkPath& path);
 
@@ -44,7 +44,7 @@
 void createThread(State4* statePtr, void* (*test)(void* ));
 int dispatchTest4(void* (*testFun)(void* ), int a, int b, int c, int d);
 void initializeTests(const char* testName, size_t testNameSize);
-void outputProgress(const State4& state, const char* pathStr);
-void outputToStream(const State4& state, const char* pathStr, SkWStream& outFile);
+void outputProgress(const State4& state, const char* pathStr, SkPath::FillType );
+void outputToStream(const State4& state, const char* pathStr, SkPath::FillType, SkWStream& outFile);
 bool runNextTestSet(State4& state);
 int waitForCompletion();
diff --git a/experimental/Intersection/EdgeWalker_TestUtility.cpp b/experimental/Intersection/EdgeWalker_TestUtility.cpp
index 7baa17b..0fb37b0 100644
--- a/experimental/Intersection/EdgeWalker_TestUtility.cpp
+++ b/experimental/Intersection/EdgeWalker_TestUtility.cpp
@@ -22,11 +22,9 @@
     "<script type=\"text/javascript\">\n"
     "\n"
     "var testDivs = [\n";
-#if 0
-static const char filename[] = "../../experimental/Intersection/debugXX.txt";
-#else
-static const char filename[] = "/flash/debug/XX.txt";
-#endif
+
+static const char preferredFilename[] = "/flash/debug/XX.txt";
+static const char backupFilename[] = "../../experimental/Intersection/debugXX.txt";
 
 static bool gShowPath = false;
 static bool gComparePaths = true;
@@ -278,8 +276,10 @@
     return comparePaths(path, out, bitmap, canvas) == 0;
 }
 
-bool testSimplifyx(const SkPath& path, SkPath& out, State4& state,
+bool testSimplifyx(SkPath& path, bool useXor, SkPath& out, State4& state,
         const char* pathStr) {
+    SkPath::FillType fillType = useXor ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType;
+    path.setFillType(fillType);
     if (gShowPath) {
         showPath(path);
     }
@@ -292,7 +292,7 @@
         char temp[8192];
         bzero(temp, sizeof(temp));
         SkMemoryWStream stream(temp, sizeof(temp));
-        outputToStream(state, pathStr, stream);
+        outputToStream(state, pathStr, fillType, stream);
         SkDebugf(temp);
         SkASSERT(0);
     }
@@ -300,16 +300,14 @@
 }
 
 bool testSimplifyx(const SkPath& path) {
-    if (false) {
-        showPath(path);
-    }
     SkPath out;
     simplifyx(path, out);
-    if (false) {
-        return true;
-    }
     SkBitmap bitmap;
-    return comparePaths(path, out, bitmap, 0) == 0;
+    int result = comparePaths(path, out, bitmap, 0);
+    if (result && gPathStrAssert) {
+        SkASSERT(0);
+    }
+    return result == 0;
 }
 
 const int maxThreadsAllocated = 64;
@@ -422,18 +420,26 @@
             }
         }
     }
+    const char* filename = preferredFilename;
+    SkFILEWStream preferredTest(filename);
+    if (!preferredTest.isValid()) {
+        filename = backupFilename;
+        SkFILEWStream backupTest(filename);
+        SkASSERT(backupTest.isValid());
+    }
     for (int index = 0; index < maxThreads; ++index) {
         State4* statePtr = &threadState[index];
         strcpy(statePtr->filename, filename);
-        SkASSERT(statePtr->filename[sizeof(filename) - 7] == 'X');
-        SkASSERT(statePtr->filename[sizeof(filename) - 6] == 'X');
-        statePtr->filename[sizeof(filename) - 7] = '0' + index / 10;
-        statePtr->filename[sizeof(filename) - 6] = '0' + index % 10;
+        size_t len = strlen(filename);
+        SkASSERT(statePtr->filename[len - 6] == 'X');
+        SkASSERT(statePtr->filename[len - 5] == 'X');
+        statePtr->filename[len - 6] = '0' + index / 10;
+        statePtr->filename[len - 5] = '0' + index % 10;
     }
     threadIndex = 0;
 }
 
-void outputProgress(const State4& state, const char* pathStr) {
+void outputProgress(const State4& state, const char* pathStr, SkPath::FillType pathFillType) {
     if (gRunTestsInOneThread) {
         SkDebugf("%s\n", pathStr);
     } else {
@@ -442,33 +448,43 @@
             SkASSERT(0);
             return;
         }
-        outputToStream(state, pathStr, outFile);
+        outputToStream(state, pathStr, pathFillType, outFile);
     }
 }
 
-void outputToStream(const State4& state, const char* pathStr, SkWStream& outFile) {
-    outFile.writeText("<div id=\"");
+static void writeTestName(SkPath::FillType pathFillType, SkWStream& outFile) {
     outFile.writeText(testName);
     outFile.writeDecAsText(testNumber);
+    if (pathFillType == SkPath::kEvenOdd_FillType) {
+        outFile.writeText("x");
+    }
+}
+
+void outputToStream(const State4& state, const char* pathStr, SkPath::FillType pathFillType, SkWStream& outFile) {
+    outFile.writeText("<div id=\"");
+    writeTestName(pathFillType, outFile);
     outFile.writeText("\">\n");
+    if (pathFillType == SkPath::kEvenOdd_FillType) {
+        outFile.writeText("    path.setFillType(SkPath::kEvenOdd_FillType);\n");
+    }
     outFile.writeText(pathStr);
     outFile.writeText("</div>\n\n");
     
     outFile.writeText(marker);
     outFile.writeText("    ");
-    outFile.writeText(testName);
-    outFile.writeDecAsText(testNumber);
+    writeTestName(pathFillType, outFile);
     outFile.writeText(",\n\n\n");
     
     outFile.writeText("static void ");
-    outFile.writeText(testName);
-    outFile.writeDecAsText(testNumber);
+    writeTestName(pathFillType, outFile);
     outFile.writeText("() {\n    SkPath path;\n");
+    if (pathFillType == SkPath::kEvenOdd_FillType) {
+        outFile.writeText("    path.setFillType(SkPath::kEvenOdd_FillType);\n");
+    }
     outFile.writeText(pathStr);
     outFile.writeText("    testSimplifyx(path);\n}\n\n");
     outFile.writeText("static void (*firstTest)() = ");
-    outFile.writeText(testName);
-    outFile.writeDecAsText(testNumber);
+    writeTestName(pathFillType, outFile);
     outFile.writeText(";\n\n");
 
     outFile.writeText("static struct {\n");
@@ -476,8 +492,7 @@
     outFile.writeText("    const char* str;\n");
     outFile.writeText("} tests[] = {\n");
     outFile.writeText("    TEST(");
-    outFile.writeText(testName);
-    outFile.writeDecAsText(testNumber);
+    writeTestName(pathFillType, outFile);
     outFile.writeText("),\n");
     outFile.flush();
 }
@@ -515,7 +530,7 @@
                 --runningThreads;
                 SkDebugf("•");
                 State4::queue->last = true;
-                State4* next;
+                State4* next = NULL;
                 for (index = 0; index < maxThreads; ++index) {
                     State4& test = threadState[index];
                     if (test.done && !test.last) {
diff --git a/experimental/Intersection/Intersection_Tests.cpp b/experimental/Intersection/Intersection_Tests.cpp
index 414b911..67885b3 100644
--- a/experimental/Intersection/Intersection_Tests.cpp
+++ b/experimental/Intersection/Intersection_Tests.cpp
@@ -1,17 +1,21 @@
 #include "CubicIntersection_TestData.h"
 #include "Intersection_Tests.h"
+#include "SkTypes.h"
 
 void cubecode_test(int test);
 
 #define TEST_QUADS_FIRST 0
 
 void Intersection_Tests() {
+    int testsRun = 0;
+    QuadLineIntersectThreaded_Test(testsRun);
     SimplifyNew_Test();
-    Simplify4x4QuadralateralsThreaded_Test();
-    Simplify4x4QuadraticsThreaded_Test();
-    Simplify4x4RectsThreaded_Test();
-    SimplifyNondegenerate4x4TrianglesThreaded_Test();
-    SimplifyDegenerate4x4TrianglesThreaded_Test();
+    Simplify4x4QuadraticsThreaded_Test(testsRun);
+    Simplify4x4RectsThreaded_Test(testsRun);
+    SimplifyNondegenerate4x4TrianglesThreaded_Test(testsRun);
+    SimplifyDegenerate4x4TrianglesThreaded_Test(testsRun);
+    Simplify4x4QuadralateralsThreaded_Test(testsRun);
+    SkDebugf("%s total testsRun=%d\n", __FUNCTION__, testsRun);
     SimplifyFindNext_Test();
     SimplifyFindTop_Test();
     SimplifyAngle_Test();
diff --git a/experimental/Intersection/Intersection_Tests.h b/experimental/Intersection/Intersection_Tests.h
index 4873bf9..4dcadef 100644
--- a/experimental/Intersection/Intersection_Tests.h
+++ b/experimental/Intersection/Intersection_Tests.h
@@ -18,18 +18,19 @@
 void LineQuadraticIntersection_Test();
 void SimplifyAddIntersectingTs_Test();
 void SimplifyAngle_Test();
-void SimplifyDegenerate4x4TrianglesThreaded_Test();
+void SimplifyDegenerate4x4TrianglesThreaded_Test(int& );
 void SimplifyFindNext_Test();
 void SimplifyFindTop_Test();
 void SimplifyNew_Test();
-void SimplifyNondegenerate4x4TrianglesThreaded_Test();
+void SimplifyNondegenerate4x4TrianglesThreaded_Test(int& );
 void SimplifyPolygonPaths_Test();
 void SimplifyQuadralateralPaths_Test();
 void SimplifyQuadraticPaths_Test();
-void Simplify4x4QuadralateralsThreaded_Test();
-void Simplify4x4QuadraticsThreaded_Test();
-void Simplify4x4RectsThreaded_Test();
+void Simplify4x4QuadralateralsThreaded_Test(int& );
+void Simplify4x4QuadraticsThreaded_Test(int& );
+void Simplify4x4RectsThreaded_Test(int& );
 void SimplifyRectangularPaths_Test();
+void QuadLineIntersectThreaded_Test(int& );
 void QuadraticBezierClip_Test();
 void QuadraticCoincidence_Test();
 void QuadraticIntersection_Test();
diff --git a/experimental/Intersection/LineCubicIntersection.cpp b/experimental/Intersection/LineCubicIntersection.cpp
index 6f2cf6c..aaee2a1 100644
--- a/experimental/Intersection/LineCubicIntersection.cpp
+++ b/experimental/Intersection/LineCubicIntersection.cpp
@@ -178,7 +178,7 @@
             }
             continue;
         }
-        intersections.fT[0][index] = (x - left) / (right - left);
+        intersections.fT[1][index] = (x - left) / (right - left);
         ++index;
     }
     if (flipped) {
@@ -199,7 +199,7 @@
         xy_at_t(cubic, intersections.fT[0][index], x, y);
         if (y < top || y > bottom) {
             if (--result > index) {
-                intersections.fT[0][index] = intersections.fT[0][result];
+                intersections.fT[1][index] = intersections.fT[0][result];
             }
             continue;
         }
diff --git a/experimental/Intersection/LineQuadraticIntersection.cpp b/experimental/Intersection/LineQuadraticIntersection.cpp
index 1bc831b..e2e712f 100644
--- a/experimental/Intersection/LineQuadraticIntersection.cpp
+++ b/experimental/Intersection/LineQuadraticIntersection.cpp
@@ -128,6 +128,29 @@
     for (int x = 0; x < roots; ++x) {
         intersections.add(t[x], findLineT(t[x]));
     }
+    // FIXME: quadratic root doesn't find t=0 or t=1, necessitating the hack below
+    if (roots == 0 || (roots == 1 && intersections.fT[0][0] >= FLT_EPSILON)) {
+        if (quad[0] == line[0]) {
+            intersections.fT[0][roots] = 0;
+            intersections.fT[1][roots++] = 0;
+            intersections.fUsed++;
+        } else if (quad[0] == line[1]) {
+            intersections.fT[0][roots] = 0;
+            intersections.fT[1][roots++] = 1;
+            intersections.fUsed++;
+        }
+    }
+    if (roots == 0 || (roots == 1 && intersections.fT[0][0] <= 1 - FLT_EPSILON)) {
+        if (quad[2] == line[1]) {
+            intersections.fT[0][roots] = 1;
+            intersections.fT[1][roots++] = 1;
+            intersections.fUsed++;
+        } else if (quad[2] == line[0]) {
+            intersections.fT[0][roots] = 1;
+            intersections.fT[1][roots++] = 0;
+            intersections.fUsed++;
+        }
+    }
     return roots > 0;
 }
 
@@ -138,7 +161,17 @@
     D += F - 2 * E; // D = d - 2*e + f
     E -= F; // E = -(d - e)
     F -= axisIntercept;
-    return quadraticRoots(D, E, F, intersections.fT[0]);
+    int roots = quadraticRoots(D, E, F, intersections.fT[0]);
+    // FIXME: ? quadraticRoots doesn't pick up intersections at 0, 1
+    if (roots < 2 && fabs(F) < FLT_EPSILON
+            && (roots == 0 || intersections.fT[0][0] >= FLT_EPSILON)) {
+        intersections.fT[0][roots++] = 0;
+    }
+    if (roots < 2 && fabs(quad[2].y - axisIntercept) < FLT_EPSILON
+            && (roots == 0 || intersections.fT[0][0] <= 1 - FLT_EPSILON)) {
+        intersections.fT[0][roots++] = 1;
+    }
+    return roots;
 }
 
 int verticalIntersect(double axisIntercept) {
@@ -148,7 +181,17 @@
     D += F - 2 * E; // D = d - 2*e + f
     E -= F; // E = -(d - e)
     F -= axisIntercept;
-    return quadraticRoots(D, E, F, intersections.fT[0]);
+    int roots = quadraticRoots(D, E, F, intersections.fT[0]);
+    // FIXME: ? quadraticRoots doesn't pick up intersections at 0, 1
+    if (roots < 2 && fabs(F) < FLT_EPSILON
+            && (roots == 0 || intersections.fT[0][0] >= FLT_EPSILON)) {
+        intersections.fT[0][roots++] = 0;
+    }
+    if (roots < 2 && fabs(quad[2].x - axisIntercept) < FLT_EPSILON
+            && (roots == 0 || intersections.fT[0][0] <= 1 - FLT_EPSILON)) {
+        intersections.fT[0][roots++] = 1;
+    }
+    return roots;
 }
 
 protected:
@@ -247,7 +290,7 @@
             }
             continue;
         }
-        intersections.fT[0][index] = (x - left) / (right - left);
+        intersections.fT[1][index] = (x - left) / (right - left);
         ++index;
     }
     if (flipped) {
@@ -272,7 +315,7 @@
             }
             continue;
         }
-        intersections.fT[0][index] = (y - top) / (bottom - top);
+        intersections.fT[1][index] = (y - top) / (bottom - top);
         ++index;
     }
     if (flipped) {
diff --git a/experimental/Intersection/LineQuadraticIntersection_Test.cpp b/experimental/Intersection/LineQuadraticIntersection_Test.cpp
index 7551dc3..1161d2d 100644
--- a/experimental/Intersection/LineQuadraticIntersection_Test.cpp
+++ b/experimental/Intersection/LineQuadraticIntersection_Test.cpp
@@ -1,5 +1,6 @@
 #include "CurveIntersection.h"
 #include "CurveUtilities.h"
+#include "EdgeWalker_Test.h"
 #include "Intersection_Tests.h"
 #include "Intersections.h"
 #include "TestUtilities.h"
@@ -55,3 +56,120 @@
         }
     }
 }
+
+static void testLineIntersect(State4& state, const Quadratic& quad, const _Line& line, 
+        const double x, const double y) {
+    char pathStr[1024];
+    bzero(pathStr, sizeof(pathStr));
+    char* str = pathStr;
+    str += sprintf(str, "    path.moveTo(%1.9g, %1.9g);\n", quad[0].x, quad[0].y);
+    str += sprintf(str, "    path.quadTo(%1.9g, %1.9g, %1.9g, %1.9g);\n", quad[1].x, quad[1].y, quad[2].x, quad[2].y);
+    str += sprintf(str, "    path.moveTo(%1.9g, %1.9g);\n", line[0].x, line[0].y);
+    str += sprintf(str, "    path.lineTo(%1.9g, %1.9g);\n", line[1].x, line[1].y);
+    
+    Intersections intersections;
+    int result;
+    bool flipped = false;
+    if (line[0].x == line[1].x) {
+        double top = line[0].y;
+        double bottom = line[1].y;
+        bool flipped = top > bottom;
+        if (flipped) {
+            SkTSwap<double>(top, bottom);
+        }
+        result = verticalIntersect(quad, top, bottom, line[0].x, flipped, intersections);
+    } else if (line[0].y == line[1].y) {
+        double left = line[0].x;
+        double right = line[1].x;
+        bool flipped = left > right;
+        if (flipped) {
+            SkTSwap<double>(left, right);
+        }
+        result = horizontalIntersect(quad, left, right, line[0].y, flipped, intersections);
+    } else {
+        intersect(quad, line, intersections);
+        result = intersections.fUsed;
+    }
+    bool found = false;
+    for (int index = 0; index < result; ++index) {
+        double quadT = intersections.fT[0][index];
+        double quadX, quadY;
+        xy_at_t(quad, quadT, quadX, quadY);
+        double lineT = intersections.fT[1][index];
+        if (flipped) {
+            lineT = 1 - lineT;
+        }
+        double lineX, lineY;
+        xy_at_t(line, lineT, lineX, lineY);
+        if (fabs(quadX - lineX) < FLT_EPSILON && fabs(quadY - lineY) < FLT_EPSILON
+                && fabs(x - lineX) < FLT_EPSILON && fabs(y - lineY) < FLT_EPSILON) {
+            found = true;
+        }
+    }
+    SkASSERT(found);
+    state.testsRun++;
+}
+
+
+// find a point on a quad by choosing a t from 0 to 1
+// create a vertical span above and below the point
+// verify that intersecting the vertical span and the quad returns t
+// verify that a vertical span starting at quad[0] intersects at t=0
+// verify that a vertical span starting at quad[2] intersects at t=1
+static void* testQuadLineIntersectMain(void* data)
+{
+    SkASSERT(data);
+    State4& state = *(State4*) data;
+    do {
+        int ax = state.a & 0x03;
+        int ay = state.a >> 2;
+        int bx = state.b & 0x03;
+        int by = state.b >> 2;
+        int cx = state.c & 0x03;
+        int cy = state.c >> 2;
+        Quadratic quad = {{ax, ay}, {bx, by}, {cx, cy}};
+        Quadratic reduced;
+        int order = reduceOrder(quad, reduced);
+        if (order < 3) {
+            continue; // skip degenerates
+        }
+        for (int tIndex = 0; tIndex <= 4; ++tIndex) {
+            double x, y;
+            xy_at_t(quad, tIndex / 4.0, x, y);
+            for (int h = -2; h <= 2; ++h) {
+                for (int v = -2; v <= 2; ++v) {
+                    if (h == v && abs(h) != 1) {
+                        continue;
+                    }
+                    _Line line = {{x - h, y - v}, {x, y}};
+                    testLineIntersect(state, quad, line, x, y);
+                    _Line line2 = {{x, y}, {x + h, y + v}};
+                    testLineIntersect(state, quad, line2, x, y);
+                    _Line line3 = {{x - h, y - v}, {x + h, y + v}};
+                    testLineIntersect(state, quad, line3, x, y);
+                }
+            }
+        }
+    } while (runNextTestSet(state));
+    return NULL;
+}
+
+void QuadLineIntersectThreaded_Test(int& testsRun)
+{
+    SkDebugf("%s\n", __FUNCTION__);
+    const char testStr[] = "testQuadLineIntersect";
+    initializeTests(testStr, sizeof(testStr));
+    int testsStart = testsRun;
+    for (int a = 0; a < 16; ++a) {
+        for (int b = 0 ; b < 16; ++b) {
+            for (int c = 0 ; c < 16; ++c) {
+                testsRun += dispatchTest4(testQuadLineIntersectMain,
+                        a, b, c, 0);
+            }
+            if (!gRunTestsInOneThread) SkDebugf(".");
+        }
+        if (!gRunTestsInOneThread) SkDebugf("%d", a);
+    }
+    testsRun += waitForCompletion();
+    SkDebugf("\n%s tests=%d total=%d\n", __FUNCTION__, testsRun - testsStart, testsRun);
+}
diff --git a/experimental/Intersection/Simplify.cpp b/experimental/Intersection/Simplify.cpp
index 9ffa33c..eb6bda5 100644
--- a/experimental/Intersection/Simplify.cpp
+++ b/experimental/Intersection/Simplify.cpp
@@ -48,12 +48,12 @@
 const bool gRunTestsInOneThread = true;
 
 #define DEBUG_ACTIVE_SPANS 1
-#define DEBUG_ADD_INTERSECTING_TS 0
-#define DEBUG_ADD_T_PAIR 1
+#define DEBUG_ADD_INTERSECTING_TS 1
+#define DEBUG_ADD_T_PAIR 0
 #define DEBUG_CONCIDENT 1
 #define DEBUG_CROSS 0
 #define DEBUG_DUMP 1
-#define DEBUG_MARK_DONE 1
+#define DEBUG_MARK_DONE 0
 #define DEBUG_PATH_CONSTRUCTION 1
 #define DEBUG_SORT 1
 #define DEBUG_WIND_BUMP 0
@@ -359,13 +359,12 @@
             {a[2].fX, a[2].fY}};
     Quadratic dst;
     int order = reduceOrder(aQuad, dst);
-    if (order == 3) {
-        return SkPath::kQuad_Verb;
-    }
-    for (int index = 0; index < order; ++index) {
-        SkPoint* pt = reducePts.append();
-        pt->fX = SkDoubleToScalar(dst[index].x);
-        pt->fY = SkDoubleToScalar(dst[index].y);
+    if (order == 2) { // quad became line
+        for (int index = 0; index < order; ++index) {
+            SkPoint* pt = reducePts.append();
+            pt->fX = SkDoubleToScalar(dst[index].x);
+            pt->fY = SkDoubleToScalar(dst[index].y);
+        }
     }
     return (SkPath::Verb) (order - 1);
 }
@@ -376,13 +375,12 @@
             {a[2].fX, a[2].fY}, {a[3].fX, a[3].fY}};
     Cubic dst;
     int order = reduceOrder(aCubic, dst, kReduceOrder_QuadraticsAllowed);
-    if (order == 4) {
-        return SkPath::kCubic_Verb;
-    }
-    for (int index = 0; index < order; ++index) {
-        SkPoint* pt = reducePts.append();
-        pt->fX = SkDoubleToScalar(dst[index].x);
-        pt->fY = SkDoubleToScalar(dst[index].y);
+    if (order == 2 || order == 3) { // cubic became line or quad
+        for (int index = 0; index < order; ++index) {
+            SkPoint* pt = reducePts.append();
+            pt->fX = SkDoubleToScalar(dst[index].x);
+            pt->fY = SkDoubleToScalar(dst[index].y);
+        }
     }
     return (SkPath::Verb) (order - 1);
 }
@@ -661,7 +659,7 @@
     bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
     if (outerWinding * innerWinding < 0) {
 #if DEBUG_WINDING
-        SkDebugf("%s *** outer=%d inner=%d result=%s\n", __FUNCTION__,
+        SkDebugf("%s outer=%d inner=%d result=%s\n", __FUNCTION__,
                 outerWinding, innerWinding, result ? "true" : "false");
 #endif
     }
@@ -1067,7 +1065,7 @@
 
     // set spans from start to end to increment the greater by one and decrement
     // the lesser
-    void addTCoincident(double startT, double endT, Segment& other,
+    void addTCoincident(const int xorMask, double startT, double endT, Segment& other,
             double oStartT, double oEndT) {
         SkASSERT(endT - startT >= FLT_EPSILON);
         SkASSERT(oEndT - oStartT >= FLT_EPSILON);
@@ -1088,7 +1086,9 @@
         SkTDArray<double> oxOutsideTs;
         do {
             bool transfer = test->fWindValue && oTest->fWindValue;
-            bool decrementOther = test->fWindValue >= oTest->fWindValue;
+            bool winding = xorMask < 0;
+            bool decrementThis = (test->fWindValue < oTest->fWindValue) & winding;
+            bool decrementOther = (test->fWindValue >= oTest->fWindValue) & winding;
             Span* end = test;
             double startT = end->fT;
             int startIndex = index;
@@ -1118,7 +1118,7 @@
             Span* oEnd = oTest;
             while (oEnd->fT < oEndT - FLT_EPSILON && oEnd->fT - otherTMatch < FLT_EPSILON) {
                 if (transfer) {
-                    if (!decrementOther) {
+                    if (decrementThis) {
                         SkASSERT(abs(oEnd->fWindValue) < gDebugMaxWindValue);
                         ++(oEnd->fWindValue);
                     } else if (other.decrementSpan(oEnd)) {
@@ -1271,7 +1271,7 @@
         int spanWinding = base->spanSign(angle);
         bool inner = useInnerWinding(winding + spanWinding, winding);
     #if DEBUG_WINDING
-        SkDebugf("%s --- spanWinding=%d winding=%d sign=%d inner=%d result=%d\n", __FUNCTION__,
+        SkDebugf("%s spanWinding=%d winding=%d sign=%d inner=%d result=%d\n", __FUNCTION__,
             spanWinding, winding, angle->sign(), inner,
             inner ? winding + spanWinding : winding);
     #endif
@@ -1316,7 +1316,9 @@
             SkPoint edge[4];
             // OPTIMIZE: wrap this so that if start==0 end==fTCount-1 we can 
             // work with the original data directly
-            (*SegmentSubDivide[fVerb])(fPts, fTs[start].fT, fTs[end].fT, edge);
+            double startT = fTs[start].fT;
+            double endT = fTs[end].fT;
+            (*SegmentSubDivide[fVerb])(fPts, startT, endT, edge);
             // intersect ray starting at basePt with edge
             Intersections intersections;
             int pts = (*VSegmentIntersect[fVerb])(edge, top, bottom, basePt.fX,
@@ -1331,11 +1333,12 @@
             SkASSERT(pts == 1); // FIXME: more code required to disambiguate
             SkPoint pt;
             double foundT = intersections.fT[0][0];
-            (*SegmentXYAtT[fVerb])(fPts, foundT, &pt);
+            double testT = startT + (endT - startT) * foundT;
+            (*SegmentXYAtT[fVerb])(fPts, testT, &pt);
             if (bestY < pt.fY && pt.fY < basePt.fY) {
                 bestY = pt.fY;
                 bestT = foundT < 1 ? start : end;
-                hitT = fTs[start].fT + (fTs[end].fT - fTs[start].fT) * foundT;
+                hitT = testT;
             }
         } while (fTs[end].fT != 1);
         return bestT;
@@ -1421,10 +1424,10 @@
     // start is the index of the beginning T of this edge
     // it is guaranteed to have an end which describes a non-zero length (?)
     // winding -1 means ccw, 1 means cw
-    // firstFind allows coincident edges to be treated differently
-    Segment* findNext(SkTDArray<Span*>& chase, bool firstFind, bool active,
-            const int startIndex, const int endIndex, int& nextStart,
-            int& nextEnd, int& winding, int& spanWinding) {
+    Segment* findNextWinding(SkTDArray<Span*>& chase, bool active,
+            int& nextStart, int& nextEnd, int& winding, int& spanWinding) {
+        const int startIndex = nextStart;
+        const int endIndex = nextEnd;
         int outerWinding = winding;
         int innerWinding = winding + spanWinding;
     #if DEBUG_WINDING
@@ -1476,90 +1479,71 @@
     #endif
         SkASSERT(sorted[firstIndex]->segment() == this);
     #if DEBUG_WINDING
-        SkDebugf("%s sign=%d\n", __FUNCTION__, sorted[firstIndex]->sign());
+        SkDebugf("%s [%d] sign=%d\n", __FUNCTION__, firstIndex, sorted[firstIndex]->sign());
     #endif
         int sumWinding = winding - spanSign(sorted[firstIndex]);
         int nextIndex = firstIndex + 1;
         int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
         const Angle* foundAngle = NULL;
+        // FIXME: found done logic probably fails if there are more than 4
+        // sorted angles. It should bias towards the first and last undone
+        // edges -- but not sure that it won't choose a middle (incorrect)
+        // edge if one is undone 
         bool foundDone = false;
+        bool foundDone2 = false;
         // iterate through the angle, and compute everyone's winding
-        int toggleWinding = SK_MinS32;
-        bool flipFound = false;
-        int flipped = 1;
+        bool altFlipped = false;
+        bool foundFlipped = false;
+        int foundMax = SK_MinS32;
+        int foundSum = SK_MinS32;
         Segment* nextSegment;
+        int lastNonZeroSum = winding;
         do {
             if (nextIndex == angleCount) {
                 nextIndex = 0;
             }
             const Angle* nextAngle = sorted[nextIndex];
             int maxWinding = sumWinding;
+            if (sumWinding) {
+                lastNonZeroSum = sumWinding;
+            }
             nextSegment = nextAngle->segment();
             sumWinding -= nextSegment->spanSign(nextAngle);
+            altFlipped ^= lastNonZeroSum * sumWinding < 0; // flip if different signs
             SkASSERT(abs(sumWinding) <= gDebugMaxWindSum);
     #if DEBUG_WINDING
-            SkDebugf("%s maxWinding=%d sumWinding=%d sign=%d\n", __FUNCTION__,
-                    maxWinding, sumWinding, nextAngle->sign());
+            SkDebugf("%s [%d] maxWinding=%d sumWinding=%d sign=%d altFlipped=%d\n", __FUNCTION__,
+                    nextIndex, maxWinding, sumWinding, nextAngle->sign(), altFlipped);
     #endif
-            if (maxWinding * sumWinding < 0) {
-                flipFound ^= true;
-    #if DEBUG_WINDING
-                SkDebugf("%s flipFound=%d maxWinding=%d sumWinding=%d\n",
-                        __FUNCTION__, flipFound, maxWinding, sumWinding);
-    #endif
-            }
-            if (!sumWinding) {
+           if (!sumWinding) {
                 if (!active) {
                     markDone(SkMin32(startIndex, endIndex), outerWinding);
                     // FIXME: seems like a bug that this isn't calling userInnerWinding
                     nextSegment->markWinding(SkMin32(nextAngle->start(),
                                 nextAngle->end()), maxWinding);
     #if DEBUG_WINDING
-                    SkDebugf("%s inactive\n", __FUNCTION__);
+                    SkDebugf("%s [%d] inactive\n", __FUNCTION__, nextIndex);
     #endif
                     return NULL;
                 }
                 if (!foundAngle || foundDone) {
                     foundAngle = nextAngle;
                     foundDone = nextSegment->done(*nextAngle);
-                    if (flipFound || (maxWinding * outerWinding < 0)) {
-                        flipped = -flipped;
-            #if DEBUG_WINDING
-                        SkDebugf("%s flipped=%d flipFound=%d maxWinding=%d"
-                                " outerWinding=%d\n", __FUNCTION__, flipped,
-                                flipFound, maxWinding, outerWinding);
-            #endif
-                    }
+                    foundFlipped = altFlipped;
+                    foundMax = maxWinding;
                 }
                 continue;
             }
-            if (!maxWinding && !foundAngle) {
+            if (!maxWinding && (!foundAngle || foundDone2)) {
         #if DEBUG_WINDING
-                if (flipped > 0) {
-                    SkDebugf("%s sumWinding=%d * outerWinding=%d < 0 (%s)\n",
-                            __FUNCTION__, sumWinding, outerWinding, 
-                            sumWinding * outerWinding < 0 ? "true" : "false");
+                if (foundAngle && foundDone2) {
+                    SkDebugf("%s [%d] !foundAngle && foundDone2\n", __FUNCTION__, nextIndex);
                 }
         #endif
-                if (sumWinding * outerWinding < 0 && flipped > 0) {
-        #if DEBUG_WINDING
-                    SkDebugf("%s toggleWinding=%d\n", __FUNCTION__, sumWinding);
-        #endif
-                    toggleWinding = sumWinding;
-                } else if (outerWinding != sumWinding) {
-        #if DEBUG_WINDING
-                    SkDebugf("%s outerWinding=%d != sumWinding=%d winding=%d\n",
-                            __FUNCTION__, outerWinding, sumWinding, winding);
-        #endif
-                    winding = sumWinding;
-                }
                 foundAngle = nextAngle;
-                if (flipFound) {
-                    flipped = -flipped;
-        #if DEBUG_WINDING
-                    SkDebugf("%s flipped flipFound=%d\n", __FUNCTION__, flipFound);
-        #endif
-                }
+                foundDone2 = nextSegment->done(*nextAngle);
+                foundFlipped = altFlipped;
+                foundSum = sumWinding;
             }
             if (nextSegment->done()) {
                 continue;
@@ -1583,7 +1567,6 @@
                 }
             }
         } while (++nextIndex != lastIndex);
-        SkASSERT(sorted[firstIndex]->segment() == this);
         markDone(SkMin32(startIndex, endIndex), outerWinding);
         if (!foundAngle) {
             return NULL;
@@ -1591,17 +1574,109 @@
         nextStart = foundAngle->start();
         nextEnd = foundAngle->end();
         nextSegment = foundAngle->segment();
+        int flipped = foundFlipped ? -1 : 1;
         spanWinding = SkSign32(spanWinding) * flipped * nextSegment->windValue(
                 SkMin32(nextStart, nextEnd));
-        if (toggleWinding != SK_MinS32) {
-            winding = toggleWinding;
-            spanWinding = -spanWinding;
+        if (winding) {
+    #if DEBUG_WINDING
+            SkDebugf("%s ---6 winding=%d foundSum=", __FUNCTION__, winding);
+            if (foundSum == SK_MinS32) {
+                SkDebugf("?");
+            } else {
+                SkDebugf("%d", foundSum);
+            }
+            SkDebugf(" foundMax=");
+            if (foundMax == SK_MinS32) {
+                SkDebugf("?");
+            } else {
+                SkDebugf("%d", foundMax);
+            }
+            SkDebugf("\n");
+     #endif
+            winding = foundSum;
         }
     #if DEBUG_WINDING
-        SkDebugf("%s spanWinding=%d\n", __FUNCTION__, spanWinding);
+        SkDebugf("%s spanWinding=%d flipped=%d\n", __FUNCTION__, spanWinding, flipped);
     #endif
         return nextSegment;
     }
+    
+    Segment* findNextXor(int& nextStart, int& nextEnd) {
+        const int startIndex = nextStart;
+        const int endIndex = nextEnd;
+        SkASSERT(startIndex != endIndex);
+        int count = fTs.count();
+        SkASSERT(startIndex < endIndex ? startIndex < count - 1
+                : startIndex > 0);
+        int step = SkSign32(endIndex - startIndex);
+        int end = nextSpan(startIndex, step);
+        SkASSERT(end >= 0);
+        Span* endSpan = &fTs[end];
+        Segment* other;
+        markDone(SkMin32(startIndex, endIndex), 1);
+        if (isSimple(end)) {
+    #if DEBUG_WINDING
+            SkDebugf("%s simple\n", __FUNCTION__);
+    #endif
+            other = endSpan->fOther;
+            nextStart = endSpan->fOtherIndex;
+            double startT = other->fTs[nextStart].fT;
+            SkDEBUGCODE(bool firstLoop = true;)
+            if ((startT < FLT_EPSILON && step < 0)
+                    || (startT > 1 - FLT_EPSILON && step > 0)) {
+                step = -step;
+                SkDEBUGCODE(firstLoop = false;)
+            }
+            do {
+                nextEnd = nextStart;
+                do {
+                    nextEnd += step;
+                } while (fabs(startT - other->fTs[nextEnd].fT) < FLT_EPSILON);
+                if (other->fTs[SkMin32(nextStart, nextEnd)].fWindValue) {
+                    break;
+                }
+                SkASSERT(firstLoop);
+                SkDEBUGCODE(firstLoop = false;)
+                step = -step;
+            } while (true);
+            SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
+            return other;
+        }
+        SkTDArray<Angle> angles;
+        SkASSERT(startIndex - endIndex != 0);
+        SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
+        addTwoAngles(startIndex, end, angles);
+        buildAngles(end, angles);
+        SkTDArray<Angle*> sorted;
+        sortAngles(angles, sorted);
+        int angleCount = angles.count();
+        int firstIndex = findStartingEdge(sorted, startIndex, end);
+        SkASSERT(firstIndex >= 0);
+    #if DEBUG_SORT
+        debugShowSort(sorted, firstIndex, 0);
+    #endif
+        SkASSERT(sorted[firstIndex]->segment() == this);
+        int nextIndex = firstIndex + 1;
+        int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
+        const Angle* nextAngle;
+        Segment* nextSegment;
+        do {
+            if (nextIndex == angleCount) {
+                nextIndex = 0;
+            }
+            nextAngle = sorted[nextIndex];
+            nextSegment = nextAngle->segment();
+            if (!nextSegment->done(*nextAngle)) {
+                break;
+            }
+            if (++nextIndex == lastIndex) {
+                return NULL;
+            }
+        } while (true);
+        nextStart = nextAngle->start();
+        nextEnd = nextAngle->end();
+        return nextSegment;
+    }
 
     int findStartingEdge(SkTDArray<Angle*>& sorted, int start, int end) {
         int angleCount = sorted.count();
@@ -1947,70 +2022,51 @@
     // always called to mark segments done).
     void markDone(int index, int winding) {
       //  SkASSERT(!done());
+        SkASSERT(winding);
         double referenceT = fTs[index].fT;
         int lesser = index;
         while (--lesser >= 0 && referenceT - fTs[lesser].fT < FLT_EPSILON) {
-            Span& span = fTs[lesser];
-            if (span.fDone) {
-                continue;
-            }
-        #if DEBUG_MARK_DONE
-            debugShowNewWinding(__FUNCTION__, span, winding);
-        #endif
-            span.fDone = true;
-            SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
-            SkASSERT(abs(winding) <= gDebugMaxWindSum);
-            span.fWindSum = winding;
-            fDoneSpans++;
+            markOneDone(__FUNCTION__, lesser, winding);
         }
         do {
-            Span& span = fTs[index];
-     //       SkASSERT(!span.fDone);
-            if (span.fDone) {
-                continue;
-            }
-        #if DEBUG_MARK_DONE
-            debugShowNewWinding(__FUNCTION__, span, winding);
-        #endif
-            span.fDone = true;
-            SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
-            SkASSERT(abs(winding) <= gDebugMaxWindSum);
-            span.fWindSum = winding;
-            fDoneSpans++;
+            markOneDone(__FUNCTION__, index, winding);
         } while (++index < fTs.count() && fTs[index].fT - referenceT < FLT_EPSILON);
     }
+    
+    void markOneDone(const char* funName, int tIndex, int winding) {
+        Span* span = markOneWinding(funName, tIndex, winding);
+        if (!span) {
+            return;
+        }
+        span->fDone = true;
+        fDoneSpans++;
+    }
+    
+    Span* markOneWinding(const char* funName, int tIndex, int winding) {
+        Span& span = fTs[tIndex];
+        if (span.fDone) {
+            return NULL;
+        }
+    #if DEBUG_MARK_DONE
+        debugShowNewWinding(funName, span, winding);
+    #endif
+        SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
+        SkASSERT(abs(winding) <= gDebugMaxWindSum);
+        span.fWindSum = winding;
+        return &span;
+    }
 
     void markWinding(int index, int winding) {
     //    SkASSERT(!done());
+        SkASSERT(winding);
         double referenceT = fTs[index].fT;
         int lesser = index;
         while (--lesser >= 0 && referenceT - fTs[lesser].fT < FLT_EPSILON) {
-            Span& span = fTs[lesser];
-            if (span.fDone) {
-                continue;
-            }
-      //      SkASSERT(span.fWindValue == 1 || winding == 0);
-        #if DEBUG_MARK_DONE
-            debugShowNewWinding(__FUNCTION__, span, winding);
-        #endif
-            SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
-            SkASSERT(abs(winding) <= gDebugMaxWindSum);
-            span.fWindSum = winding;
+            markOneWinding(__FUNCTION__, lesser, winding);
         }
         do {
-            Span& span = fTs[index];
-     //       SkASSERT(!span.fDone || span.fCoincident);
-            if (span.fDone) {
-                continue;
-            }
-     //       SkASSERT(span.fWindValue == 1 || winding == 0);
-            SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
-        #if DEBUG_MARK_DONE
-            debugShowNewWinding(__FUNCTION__, span, winding);
-        #endif
-            SkASSERT(abs(winding) <= gDebugMaxWindSum);
-            span.fWindSum = winding;
-        } while (++index < fTs.count() && fTs[index].fT - referenceT < FLT_EPSILON);
+            markOneWinding(__FUNCTION__, index, winding);
+       } while (++index < fTs.count() && fTs[index].fT - referenceT < FLT_EPSILON);
     }
 
     void matchWindingValue(int tIndex, double t, bool borrowWind) {
@@ -2104,7 +2160,7 @@
     double t(int tIndex) const {
         return fTs[tIndex].fT;
     }
-
+    
     static void TrackOutside(SkTDArray<double>& outsideTs, double end,
             double start) {
         int outCount = outsideTs.count();
@@ -2113,6 +2169,23 @@
             *outsideTs.append() = start;
         }
     }
+    
+    void undoneSpan(int& start, int& end) {
+        size_t tCount = fTs.count();
+        size_t index;
+        for (index = 0; index < tCount; ++index) {
+            if (!fTs[index].fDone) {
+                break;
+            }
+        }
+        SkASSERT(index < tCount - 1);
+        start = index;
+        double startT = fTs[index].fT;
+        while (fTs[++index].fT - startT < FLT_EPSILON)
+            SkASSERT(index < tCount);
+        SkASSERT(index < tCount);
+        end = index;
+    }
 
     void updatePts(const SkPoint pts[]) {
         fPts = pts;
@@ -2210,9 +2283,27 @@
     }
 #endif
 
+#if DEBUG_WINDING
+    void debugShowSums() const {
+        SkDebugf("%s id=%d (%1.9g,%1.9g %1.9g,%1.9g)", __FUNCTION__, fID,
+            fPts[0].fX, fPts[0].fY, fPts[fVerb].fX, fPts[fVerb].fY);
+        for (int i = 0; i < fTs.count(); ++i) {
+            const Span& span = fTs[i];
+            SkDebugf(" [t=%1.3g %1.9g,%1.9g w=", span.fT, xAtT(&span), yAtT(&span));
+            if (span.fWindSum == SK_MinS32) {
+                SkDebugf("?");
+            } else {
+                SkDebugf("%d", span.fWindSum);
+            }
+            SkDebugf("]");
+        }
+        SkDebugf("\n");
+    }
+#endif
+
 #if DEBUG_CONCIDENT
     void debugShowTs() const {
-        SkDebugf("%s %d", __FUNCTION__, fID);
+        SkDebugf("%s id=%d", __FUNCTION__, fID);
         for (int i = 0; i < fTs.count(); ++i) {
             SkDebugf(" [o=%d t=%1.3g %1.9g,%1.9g w=%d]", fTs[i].fOther->fID,
                     fTs[i].fT, xAtT(&fTs[i]), yAtT(&fTs[i]), fTs[i].fWindValue);
@@ -2277,7 +2368,7 @@
         SkASSERT(angles.count() > 1);
         int lastSum = contourWinding;
         int windSum = lastSum - spanSign(angles[first]);
-        SkDebugf("%s contourWinding=%d bump=%d\n", __FUNCTION__,
+        SkDebugf("%s contourWinding=%d sign=%d\n", __FUNCTION__,
                 contourWinding, spanSign(angles[first]));
         int index = first;
         bool firstTime = true;
@@ -2332,7 +2423,7 @@
     SkPath::Verb fVerb;
     Bounds fBounds;
     SkTDArray<Span> fTs; // two or more (always includes t=0 t=1)
-    int fDoneSpans; // used for quick check that segment is finished
+    int fDoneSpans; // quick check that segment is finished
 #if DEBUG_DUMP
     int fID;
 #endif
@@ -2491,7 +2582,7 @@
         fContainsCurves = fContainsIntercepts = false;
     }
 
-    void resolveCoincidence(int winding) {
+    void resolveCoincidence(int xorMask) {
         int count = fCoincidences.count();
         for (int index = 0; index < count; ++index) {
             Coincidence& coincidence = fCoincidences[index];
@@ -2517,7 +2608,7 @@
                 SkTSwap<double>(oStartT, oEndT);
             }
             SkASSERT(oEndT - oStartT >= FLT_EPSILON);
-            if (winding > 0 || thisOne.cancels(other)) {
+            if (thisOne.cancels(other)) {
                         // make sure startT and endT have t entries
                 if (startT > 0 || oEndT < 1
                         || thisOne.isMissing(startT) || other.isMissing(oEndT)) {
@@ -2537,7 +2628,7 @@
                         || thisOne.isMissing(endT) || other.isMissing(oEndT)) {
                     other.addTPair(oEndT, thisOne, endT, true);
                 }
-                thisOne.addTCoincident(startT, endT, other, oStartT, oEndT);
+                thisOne.addTCoincident(xorMask, startT, endT, other, oStartT, oEndT);
             }
         #if DEBUG_CONCIDENT
             thisOne.debugShowTs();
@@ -2590,6 +2681,19 @@
         return bestSegment;
     }
 
+    Segment* undoneSegment(int& start, int& end) {
+        int segmentCount = fSegments.count();
+        for (int test = 0; test < segmentCount; ++test) {
+            Segment* testSegment = &fSegments[test];
+            if (testSegment->done()) {
+                continue;
+            }
+            testSegment->undoneSpan(start, end);
+            return testSegment;
+        }
+        return NULL;
+    }
+
     int updateSegment(int index, const SkPoint* pts) {
         Segment& segment = fSegments[index];
         segment.updatePts(pts);
@@ -3170,15 +3274,15 @@
 
 // resolve any coincident pairs found while intersecting, and
 // see if coincidence is formed by clipping non-concident segments
-static void coincidenceCheck(SkTDArray<Contour*>& contourList, int winding) {
+static void coincidenceCheck(SkTDArray<Contour*>& contourList, int xorMask) {
     int contourCount = contourList.count();
     for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
         Contour* contour = contourList[cIndex];
-        contour->findTooCloseToCall(winding);
+        contour->findTooCloseToCall(xorMask);
     }
     for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
         Contour* contour = contourList[cIndex];
-        contour->resolveCoincidence(winding);
+        contour->resolveCoincidence(xorMask);
     }
 }
 
@@ -3242,7 +3346,7 @@
         SkASSERT(angles.count() > 0);
         if (angles[0].segment()->yAtT(angles[0].start()) >= basePt.fY) {
 #if DEBUG_SORT
-            SkDebugf("%s *** early return\n", __FUNCTION__);
+            SkDebugf("%s early return\n", __FUNCTION__);
 #endif
             return 0;
         }
@@ -3370,6 +3474,21 @@
     return topStart;
 }
 
+static Segment* findUndone(SkTDArray<Contour*>& contourList, int& start, int& end) {
+    int contourCount = contourList.count();
+    Segment* result;
+    for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
+        Contour* contour = contourList[cIndex];
+        result = contour->undoneSegment(start, end);
+        if (result) {
+            return result;
+        }
+    }
+    return NULL;
+}
+
+
+
 static Segment* findChase(SkTDArray<Span*>& chase, int& tIndex, int& endIndex,
         int contourWinding) {
     while (chase.count()) {
@@ -3479,7 +3598,7 @@
 // is an option, choose first edge that continues the inside.
     // since we start with leftmost top edge, we'll traverse through a
     // smaller angle counterclockwise to get to the next edge.  
-static void bridge(SkTDArray<Contour*>& contourList, SkPath& simple) {
+static void bridgeWinding(SkTDArray<Contour*>& contourList, SkPath& simple) {
     bool firstContour = true;
     do {
         Segment* topStart = findTopContour(contourList);
@@ -3511,7 +3630,7 @@
                     contourWinding -= spanWinding;
                 }
 #if DEBUG_WINDING
-                SkDebugf("%s --- sumWinding=%d spanWinding=%d sign=%d inner=%d result=%d\n", __FUNCTION__,
+                SkDebugf("%s sumWinding=%d spanWinding=%d sign=%d inner=%d result=%d\n", __FUNCTION__,
                         sumWinding, spanWinding, SkSign32(index - endIndex), 
                         inner, contourWinding);
 #endif
@@ -3522,7 +3641,6 @@
 #endif
         }
         SkPoint lastPt;
-        bool firstTime = true;
         int winding = contourWinding;
         int spanWinding = current->spanSign(index, endIndex);
         // FIXME: needs work. While it works in limited situations, it does
@@ -3542,9 +3660,9 @@
             const SkPoint* firstPt = NULL;
             do {
                 SkASSERT(!current->done());
-                int nextStart, nextEnd;
-                Segment* next = current->findNext(chaseArray,
-                        firstTime, active, index, endIndex,
+                int nextStart = index;
+                int nextEnd = endIndex;
+                Segment* next = current->findNextWinding(chaseArray, active,
                         nextStart, nextEnd, winding, spanWinding);
                 if (!next) {
                     break;
@@ -3556,7 +3674,6 @@
                 current = next;
                 index = nextStart;
                 endIndex = nextEnd;
-                firstTime = false;
             } while (*firstPt != lastPt && (active || !current->done()));
             if (firstPt && active) {
         #if DEBUG_PATH_CONSTRUCTION
@@ -3576,7 +3693,7 @@
             winding = current->windSum(lesser);
             bool inner = useInnerWinding(winding - spanWinding, winding);
         #if DEBUG_WINDING
-            SkDebugf("%s --- id=%d t=%1.9g spanWinding=%d winding=%d sign=%d"
+            SkDebugf("%s id=%d t=%1.9g spanWinding=%d winding=%d sign=%d"
                     " inner=%d result=%d\n",
                     __FUNCTION__, current->debugID(), current->t(lesser),
                     spanWinding, winding, SkSign32(index - endIndex),
@@ -3591,6 +3708,37 @@
     } while (true);
 }
 
+static void bridgeXor(SkTDArray<Contour*>& contourList, SkPath& simple) {
+    Segment* current;
+    int start, end;
+    while ((current = findUndone(contourList, start, end))) {
+        const SkPoint* firstPt = NULL;
+        SkPoint lastPt;
+        do {
+            SkASSERT(!current->done());
+            int nextStart = start;
+            int nextEnd = end;
+            Segment* next = current->findNextXor(nextStart, nextEnd);
+            if (!next) {
+                break;
+            }
+            if (!firstPt) {
+                firstPt = &current->addMoveTo(start, simple, true);
+            }
+            lastPt = current->addCurveTo(start, end, simple, true);
+            current = next;
+            start = nextStart;
+            end = nextEnd;
+        } while (*firstPt != lastPt);
+        if (firstPt) {
+    #if DEBUG_PATH_CONSTRUCTION
+            SkDebugf("%s close\n", __FUNCTION__);
+    #endif
+            simple.close();
+        }
+    } 
+}
+
 static void fixOtherTIndex(SkTDArray<Contour*>& contourList) {
     int contourCount = contourList.count();
     for (int cTest = 0; cTest < contourCount; ++cTest) {
@@ -3613,7 +3761,7 @@
 
 void simplifyx(const SkPath& path, SkPath& simple) {
     // returns 1 for evenodd, -1 for winding, regardless of inverse-ness
-    int winding = (path.getFillType() & 1) ? 1 : -1;
+    int xorMask = (path.getFillType() & 1) ? 1 : -1;
     simple.reset();
     simple.setFillType(SkPath::kEvenOdd_FillType);
 
@@ -3638,9 +3786,13 @@
         } while (addIntersectTs(current, next) && nextPtr != listEnd);
     } while (currentPtr != listEnd);
     // eat through coincident edges
-    coincidenceCheck(contourList, winding);
+    coincidenceCheck(contourList, xorMask);
     fixOtherTIndex(contourList);
     // construct closed contours
-    bridge(contourList, simple);
+    if (xorMask < 0) {
+        bridgeWinding(contourList, simple);
+    } else {
+        bridgeXor(contourList, simple);
+    }
 }
 
diff --git a/experimental/Intersection/SimplifyFindNext_Test.cpp b/experimental/Intersection/SimplifyFindNext_Test.cpp
index 5fc6305..7d33c11 100644
--- a/experimental/Intersection/SimplifyFindNext_Test.cpp
+++ b/experimental/Intersection/SimplifyFindNext_Test.cpp
@@ -32,11 +32,11 @@
     SimplifyFindNextTest::Segment& segment = contours[0].debugSegments()[0];
     SkPoint pts[2];
     pts[0] = segment.xyAtT(&segment.span(endIndex));
-    int nextStart, nextEnd;
+    int nextStart = startIndex;
+    int nextEnd = endIndex;
     SkTDArray<SimplifyFindNextTest::Span*> chaseArray;
-    SimplifyFindNextTest::Segment* next = segment.findNext(chaseArray,
-            true, true, startIndex, endIndex, nextStart, nextEnd,
-            contourWinding, spanWinding);
+    SimplifyFindNextTest::Segment* next = segment.findNextWinding(chaseArray,
+            true, nextStart, nextEnd, contourWinding, spanWinding);
     pts[1] = next->xyAtT(&next->span(nextStart));
     SkASSERT(pts[0] == pts[1]);
     return next;
diff --git a/experimental/Intersection/SimplifyNew_Test.cpp b/experimental/Intersection/SimplifyNew_Test.cpp
index 3d21908..b708652 100644
--- a/experimental/Intersection/SimplifyNew_Test.cpp
+++ b/experimental/Intersection/SimplifyNew_Test.cpp
@@ -961,13 +961,234 @@
     testSimplifyx(path);
 }
 
-static void (*firstTest)() = 0;
+static void testFauxQuadralateral6() {
+    SkPath path;
+    path.moveTo(0, 0);
+    path.lineTo(1, 0);
+    path.lineTo(1, 1);
+    path.close();
+    path.moveTo(1, 0);
+    path.lineTo(2, 0);
+    path.lineTo(1 + 1.0f/3, 2.0f/3);
+    path.close();
+    path.moveTo(1 + 1.0f/3, 2.0f/3);
+    path.lineTo(0, 2);
+    path.lineTo(2, 2);
+    path.close();
+    testSimplifyx(path);
+}
+
+static void testFauxQuadralateral6a() {
+    SkPath path;
+    path.moveTo(0, 0);
+    path.lineTo(3, 0);
+    path.lineTo(3, 3);
+    path.close();
+    path.moveTo(3, 0);
+    path.lineTo(6, 0);
+    path.lineTo(4, 2);
+    path.close();
+    path.moveTo(4, 2);
+    path.lineTo(0, 6);
+    path.lineTo(6, 6);
+    path.close();
+    testSimplifyx(path);
+}
+
+static void testFauxQuadralateral6b() {
+    SkPath path;
+    path.moveTo(0, 0);
+    path.lineTo(3, 0);
+    path.lineTo(3, 3);
+    path.close();
+    path.moveTo(3, 0);
+    path.lineTo(6, 0);
+    path.lineTo(4, 2);
+    path.close();
+    path.moveTo(4, 2);
+    path.lineTo(6, 6);
+    path.lineTo(0, 6);
+    path.close();
+    testSimplifyx(path);
+}
+
+static void testFauxQuadralateral6c() {
+    SkPath path;
+    path.moveTo(0, 0);
+    path.lineTo(3, 3);
+    path.lineTo(3, 0);
+    path.close();
+    path.moveTo(3, 0);
+    path.lineTo(6, 0);
+    path.lineTo(4, 2);
+    path.close();
+    path.moveTo(4, 2);
+    path.lineTo(0, 6);
+    path.lineTo(6, 6);
+    path.close();
+    testSimplifyx(path);
+}
+
+static void testFauxQuadralateral6d() {
+    SkPath path;
+    path.moveTo(0, 0);
+    path.lineTo(3, 3);
+    path.lineTo(3, 0);
+    path.close();
+    path.moveTo(3, 0);
+    path.lineTo(6, 0);
+    path.lineTo(4, 2);
+    path.close();
+    path.moveTo(4, 2);
+    path.lineTo(6, 6);
+    path.lineTo(0, 6);
+    path.close();
+    testSimplifyx(path);
+}
+
+static void testQuadralateral6a() {
+    SkPath path;
+    path.moveTo(0, 0);
+    path.lineTo(0, 0);
+    path.lineTo(3, 0);
+    path.lineTo(3, 3);
+    path.close();
+    path.moveTo(3, 0);
+    path.lineTo(6, 0);
+    path.lineTo(0, 6);
+    path.lineTo(6, 6);
+    path.close();
+    testSimplifyx(path);
+}
+
+static void testQuadralateral7() {
+    SkPath path;
+    path.moveTo(0, 0);
+    path.lineTo(0, 0);
+    path.lineTo(1, 0);
+    path.lineTo(2, 1);
+    path.close();
+    path.moveTo(1, 0);
+    path.lineTo(1, 1);
+    path.lineTo(2, 2);
+    path.lineTo(1, 3);
+    path.close();
+    testSimplifyx(path);
+}
+
+static void testQuadralateral8() {
+    SkPath path;
+    path.moveTo(0, 0);
+    path.lineTo(3, 1);
+    path.lineTo(1, 3);
+    path.lineTo(3, 3);
+    path.close();
+    path.moveTo(2, 1);
+    path.lineTo(0, 2);
+    path.lineTo(3, 2);
+    path.lineTo(2, 3);
+    path.close();
+    testSimplifyx(path);
+}
+
+static void testQuadralateral9() {
+    SkPath path;
+    path.moveTo(0, 0);
+    path.lineTo(1, 0);
+    path.lineTo(1, 2);
+    path.lineTo(2, 2);
+    path.close();
+    path.moveTo(1, 1);
+    path.lineTo(2, 1);
+    path.lineTo(1, 3);
+    path.lineTo(2, 3);
+    path.close();
+    testSimplifyx(path);
+}
+
+static void testLine1x() {
+    SkPath path;
+    path.setFillType(SkPath::kEvenOdd_FillType);
+    path.addRect(0, 0, 12, 12, (SkPath::Direction) 0);
+    path.addRect(4, 0, 13, 13, (SkPath::Direction) 0);
+    testSimplifyx(path);
+}
+
+static void testLine2x() {
+    SkPath path;
+    path.setFillType(SkPath::kEvenOdd_FillType);
+    path.addRect(0, 20, 20, 20, (SkPath::Direction) 0);
+    path.addRect(0, 20, 12, 30, (SkPath::Direction) 0);
+    path.addRect(12, 0, 21, 21, (SkPath::Direction) 1);
+    testSimplifyx(path);
+}
+
+static void testLine3x() {
+    SkPath path;
+    path.setFillType(SkPath::kEvenOdd_FillType);
+    path.addRect(10, 30, 30, 30, (SkPath::Direction) 0);
+    path.addRect(18, 20, 30, 30, (SkPath::Direction) 1);
+    path.addRect(0, 32, 9, 36, (SkPath::Direction) 1);
+    testSimplifyx(path);
+}
+
+static void testLine4x() {
+    SkPath path;
+    path.setFillType(SkPath::kEvenOdd_FillType);
+    path.addRect(10, 30, 30, 30, (SkPath::Direction) 0);
+    path.addRect(24, 20, 36, 30, (SkPath::Direction) 1);
+    path.addRect(0, 32, 9, 36, (SkPath::Direction) 1);
+    testSimplifyx(path);
+}
+
+static void testQuadratic1() {
+    SkPath path;
+    path.moveTo(0, 0);
+    path.quadTo(0, 0, 0, 0);
+    path.lineTo(1, 0);
+    path.close();
+    path.moveTo(0, 0);
+    path.lineTo(0, 0);
+    path.quadTo(0, 0, 0, 0);
+    path.close();
+    testSimplifyx(path);
+}
+
+static void testQuadratic2() {
+    SkPath path;
+    path.moveTo(0, 0);
+    path.quadTo(0, 0, 0, 0);
+    path.lineTo(3, 0);
+    path.close();
+    path.moveTo(0, 0);
+    path.lineTo(0, 0);
+    path.quadTo(1, 0, 0, 1);
+    path.close();
+    testSimplifyx(path);
+}
+
+static void (*firstTest)() = testQuadratic2;
 
 static struct {
     void (*fun)();
     const char* str;
 } tests[] = {
+    TEST(testQuadratic2),
+    TEST(testQuadratic1),
+    TEST(testLine4x),
+    TEST(testLine3x),
+    TEST(testLine2x),
+    TEST(testLine1x),
+    TEST(testQuadralateral9),
+    TEST(testQuadralateral8),
+    TEST(testQuadralateral7),
     TEST(testQuadralateral6),
+    TEST(testQuadralateral6a),
+    TEST(testFauxQuadralateral6d),
+    TEST(testFauxQuadralateral6c),
+    TEST(testFauxQuadralateral6b),
+    TEST(testFauxQuadralateral6a),
+    TEST(testFauxQuadralateral6),
     TEST(testQuadralateral5),
     TEST(testNondegenerate4),
     TEST(testNondegenerate3),
@@ -1076,14 +1297,13 @@
     void (*fun)();
     const char* str;
 } subTests[] = {
-    TEST(testLine68h),
-    TEST(testLine68g),
-    TEST(testLine68f),
-    TEST(testLine68e),
-    TEST(testLine68d),
-    TEST(testLine68c),
-    TEST(testLine68b),
-    TEST(testLine68a),
+    TEST(testQuadralateral6),
+    TEST(testQuadralateral6a),
+    TEST(testFauxQuadralateral6d),
+    TEST(testFauxQuadralateral6c),
+    TEST(testFauxQuadralateral6b),
+    TEST(testFauxQuadralateral6a),
+    TEST(testFauxQuadralateral6),
 };
 
 static const size_t subTestCount = sizeof(subTests) / sizeof(subTests[0]);
@@ -1112,6 +1332,7 @@
         while (index > 0 && tests[index].fun != firstTest) {
             --index;
         }
+        SkDebugf("  %s [%s]\n", __FUNCTION__, tests[index].str);
         (*tests[index].fun)();
     }
     index = testCount - 1;
diff --git a/experimental/Intersection/SimplifyRect4x4_Test.cpp b/experimental/Intersection/SimplifyRect4x4_Test.cpp
index 6782d53..3768da9 100644
--- a/experimental/Intersection/SimplifyRect4x4_Test.cpp
+++ b/experimental/Intersection/SimplifyRect4x4_Test.cpp
@@ -155,8 +155,11 @@
                 dYAlign = 5;
             }
             path.close();
-            outputProgress(state, pathStr);
-            testSimplifyx(path, out, state, pathStr);
+            outputProgress(state, pathStr, SkPath::kWinding_FillType);
+            testSimplifyx(path, false, out, state, pathStr);
+            state.testsRun++;
+            outputProgress(state, pathStr, SkPath::kEvenOdd_FillType);
+            testSimplifyx(path, true, out, state, pathStr);
             state.testsRun++;
                                     }
                                 }
@@ -170,7 +173,7 @@
     return NULL;
 }
 
-void Simplify4x4RectsThreaded_Test()
+void Simplify4x4RectsThreaded_Test(int& testsRun)
 {
     SkDebugf("%s\n", __FUNCTION__);
 #ifdef SK_DEBUG
@@ -179,7 +182,7 @@
 #endif
     const char testLineStr[] = "testLine";
     initializeTests(testLineStr, sizeof(testLineStr));
-    int testsRun = 0;
+    int testsStart = testsRun;
     for (int a = 0; a < 8; ++a) { // outermost
         for (int b = a ; b < 8; ++b) {
             for (int c = b ; c < 8; ++c) {
@@ -193,6 +196,6 @@
         if (!gRunTestsInOneThread) SkDebugf("\n%d", a);
     }
     testsRun += waitForCompletion();
-    SkDebugf("%s total tests run=%d\n", __FUNCTION__, testsRun);
+    SkDebugf("%s tests=%d total=%d\n", __FUNCTION__, testsRun - testsStart, testsRun);
 }
 
diff --git a/experimental/Intersection/op.htm b/experimental/Intersection/op.htm
index ce40130..b844053 100644
--- a/experimental/Intersection/op.htm
+++ b/experimental/Intersection/op.htm
@@ -862,11 +862,200 @@
     path.close();
 </div>
 
+<div id="testFauxQuadralateral6">
+    path.moveTo(0, 0);
+    path.lineTo(1, 0);
+    path.lineTo(1, 1);
+    path.close();
+    path.moveTo(1, 0);
+    path.lineTo(2, 0);
+    path.lineTo(1.333, 0.667);
+    path.close();
+    path.moveTo(1.333, 0.667);
+    path.lineTo(0, 2);
+    path.lineTo(2, 2);
+    path.close();
+</div>
+
+<div id="testFauxQuadralateral6a">
+    path.moveTo(0, 0);
+    path.lineTo(3, 0);
+    path.lineTo(3, 3);
+    path.close();
+    path.moveTo(3, 0);
+    path.lineTo(6, 0);
+    path.lineTo(4, 2);
+    path.close();
+    path.moveTo(4, 2);
+    path.lineTo(0, 6);
+    path.lineTo(6, 6);
+    path.close();
+</div>
+
+<div id="testFauxQuadralateral6b">
+    path.moveTo(0, 0);
+    path.lineTo(3, 0);
+    path.lineTo(3, 3);
+    path.close();
+    path.moveTo(3, 0);
+    path.lineTo(6, 0);
+    path.lineTo(4, 2);
+    path.close();
+    path.moveTo(4, 2);
+    path.lineTo(6, 6);
+    path.lineTo(0, 6);
+    path.close();
+</div>
+
+<div id="testFauxQuadralateral6c">
+    path.moveTo(0, 0);
+    path.lineTo(3, 3);
+    path.lineTo(3, 0);
+    path.close();
+    path.moveTo(3, 0);
+    path.lineTo(6, 0);
+    path.lineTo(4, 2);
+    path.close();
+    path.moveTo(4, 2);
+    path.lineTo(0, 6);
+    path.lineTo(6, 6);
+    path.close();
+</div>
+
+<div id="testFauxQuadralateral6d">
+    path.moveTo(0, 0);
+    path.lineTo(3, 3);
+    path.lineTo(3, 0);
+    path.close();
+    path.moveTo(3, 0);
+    path.lineTo(6, 0);
+    path.lineTo(4, 2);
+    path.close();
+    path.moveTo(4, 2);
+    path.lineTo(6, 6);
+    path.lineTo(0, 6);
+</div>
+
+<div id="testQuadralateral6a">
+    path.moveTo(0, 0);
+    path.lineTo(0, 0);
+    path.lineTo(3, 0);
+    path.lineTo(3, 3);
+    path.close();
+    path.moveTo(3, 0);
+    path.lineTo(6, 0);
+    path.lineTo(0, 6);
+    path.lineTo(6, 6);
+</div>
+
+<div id="testQuadralateral7">
+    path.moveTo(0, 0);
+    path.lineTo(0, 0);
+    path.lineTo(1, 0);
+    path.lineTo(2, 1);
+    path.close();
+    path.moveTo(1, 0);
+    path.lineTo(1, 1);
+    path.lineTo(2, 2);
+    path.lineTo(1, 3);
+    path.close();
+</div>
+
+<div id="testQuadralateral8">
+    path.moveTo(0, 0);
+    path.lineTo(3, 1);
+    path.lineTo(1, 3);
+    path.lineTo(3, 3);
+    path.close();
+    path.moveTo(2, 1);
+    path.lineTo(0, 2);
+    path.lineTo(3, 2);
+    path.lineTo(2, 3);
+    path.close();
+</div>
+
+<div id="testQuadralateral9">
+    path.moveTo(0, 0);
+    path.lineTo(1, 0);
+    path.lineTo(1, 2);
+    path.lineTo(2, 2);
+    path.close();
+    path.moveTo(1, 1);
+    path.lineTo(2, 1);
+    path.lineTo(1, 3);
+    path.lineTo(2, 3);
+    path.close();
+</div>
+
+<div id="testLine1x">
+    path.setFillType(SkPath::kEvenOdd_FillType);
+    path.addRect(0, 0, 12, 12, (SkPath::Direction) 0);
+    path.addRect(4, 0, 13, 13, (SkPath::Direction) 0);
+</div>
+
+<div id="testLine2x">
+    path.setFillType(SkPath::kEvenOdd_FillType);
+    path.addRect(0, 20, 20, 20, (SkPath::Direction) 0);
+    path.addRect(0, 20, 12, 30, (SkPath::Direction) 0);
+    path.addRect(12, 0, 21, 21, (SkPath::Direction) 1);
+</div>
+
+<div id="testLine3x">
+    path.setFillType(SkPath::kEvenOdd_FillType);
+    path.addRect(10, 30, 30, 30, (SkPath::Direction) 0);
+    path.addRect(18, 20, 30, 30, (SkPath::Direction) 1);
+    path.addRect(0, 32, 9, 36, (SkPath::Direction) 1);
+</div>
+
+<div id="testLine4x">
+    path.setFillType(SkPath::kEvenOdd_FillType);
+    path.addRect(10, 30, 30, 30, (SkPath::Direction) 0);
+    path.addRect(24, 20, 36, 30, (SkPath::Direction) 1);
+    path.addRect(0, 32, 9, 36, (SkPath::Direction) 1);
+</div>
+
+<div id="testQuadratic1">
+    path.moveTo(0, 0);
+    path.quadTo(0, 0, 0, 0);
+    path.lineTo(1, 0);
+    path.close();
+    path.moveTo(0, 0);
+    path.lineTo(0, 0);
+    path.quadTo(0, 0, 0, 0);
+    path.close();
+</div>
+
+<div id="testQuadratic2">
+    path.moveTo(0, 0);
+    path.quadTo(0, 0, 0, 0);
+    path.lineTo(3, 0);
+    path.close();
+    path.moveTo(0, 0);
+    path.lineTo(0, 0);
+    path.quadTo(1, 0, 0, 1);
+    path.close();
+</div>
+
 </div>
 
 <script type="text/javascript">
 
 var testDivs = [
+    testQuadratic2,
+    testQuadratic1,
+    testLine4x,
+    testLine3x,
+    testLine2x,
+    testLine1x,
+    testQuadralateral9,
+    testQuadralateral8,
+    testQuadralateral7,
+    testFauxQuadralateral6d,
+    testFauxQuadralateral6c,
+    testFauxQuadralateral6b,
+    testFauxQuadralateral6a,
+    testFauxQuadralateral6,
+    testQuadralateral6a,
     testQuadralateral6,
     testQuadralateral5,
     testNondegenerate4,
@@ -976,6 +1165,7 @@
 var tests = [];
 var testTitles = [];
 var testIndex = 0;
+var hasXor = false;
 
 var ctx;
 
@@ -983,6 +1173,7 @@
     var contours = [];
     var contourStrs = test.split("path.close();");
     var pattern = /-?\d+\.*\d*/g;
+    hasXor = test.split("kEvenOdd_FillType").length > 1;
     for (var c in contourStrs) {
         var contour = contourStrs[c];
         var verbStrs = contour.split("path");
@@ -1022,6 +1213,7 @@
     var contours = [];
     var rectStrs = test.split("path.addRect");
     var pattern = /-?\d+\.*\d*/g;
+    hasXor = test.split("kEvenOdd_FillType").length > 1;
     for (var r in rectStrs) {
         var rect = rectStrs[r];
         var sideStrs = rect.match(pattern);
@@ -1176,6 +1368,9 @@
         }
         ctx.closePath();
     }
+    if (hasXor) {
+        ctx.fillType=xor; // how is this done?
+    }
     ctx.stroke();
     ctx.fillStyle="rgba(192,192,255, 0.3)";
     ctx.fill();