shape ops work in progress

git-svn-id: http://skia.googlecode.com/svn/trunk@4006 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/experimental/Intersection/ActiveEdge_Test.cpp b/experimental/Intersection/ActiveEdge_Test.cpp
index 03cb595..3e1b958 100755
--- a/experimental/Intersection/ActiveEdge_Test.cpp
+++ b/experimental/Intersection/ActiveEdge_Test.cpp
@@ -25,24 +25,24 @@
     {{10,  0}, {10, 50},   {20, 10}, {20, 50}},
     {{10,  0}, {10, 50},   {10, 10}, {20, 50}},
     {{10,  0}, {10, 50},   {20, 10}, {10, 50}},
-    {{10,  0}, {10, 50},   {20, 10}, {10 + 0.000001, 40}},
+    {{10,  0}, {10, 50},   {20, 10}, {10 + 0.000001f, 40}},
 // left top lower
     {{10, 20}, {10, 50},   {20, 10}, {20, 50}},
     {{10, 20}, {10, 50},   {10, 10}, {20, 50}},
     {{10, 20}, {10, 50},   {20, 10}, {10, 50}},
-    {{10, 20}, {10, 50},   {20, 10}, {10 + 0.000001, 40}},
+    {{10, 20}, {10, 50},   {20, 10}, {10 + 0.000001f, 40}},
     {{10, 20}, {10, 50},   { 0,  0}, {50, 50}},
 // left bottom higher
     {{10, 10}, {10, 40},   {20, 10}, {20, 50}},
     {{10, 10}, {10, 40},   {10, 10}, {20, 50}},
     {{10, 10}, {10, 40},   {20, 10}, {10, 50}},
-    {{10, 10}, {10, 40},   {20, 10}, { 0 + 0.000001, 70}},
+    {{10, 10}, {10, 40},   {20, 10}, { 0 + 0.000001f, 70}},
 // left bottom lower
     {{10, 10}, {10, 60},   {20, 10}, {20, 50}},
     {{10, 10}, {10, 60},   {10, 10}, {20, 50}},
-    {{10, 10}, {10, 60},   {20, 10}, {10 + 0.000001, 50}},
-    {{10, 10}, {10, 60},   {20, 10}, {10 + 0.000001, 40}},
-    {{10, 10}, {10, 60},   { 0,  0}, {20 + 0.000001, 20}},
+    {{10, 10}, {10, 60},   {20, 10}, {10 + 0.000001f, 50}},
+    {{10, 10}, {10, 60},   {20, 10}, {10 + 0.000001f, 40}},
+    {{10, 10}, {10, 60},   { 0,  0}, {20 + 0.000001f, 20}},
 };
 
 size_t leftRightCount = sizeof(leftRight) / sizeof(leftRight[0]);
diff --git a/experimental/Intersection/CubicIntersection_TestData.cpp b/experimental/Intersection/CubicIntersection_TestData.cpp
index 05d08af..066d9b5 100644
--- a/experimental/Intersection/CubicIntersection_TestData.cpp
+++ b/experimental/Intersection/CubicIntersection_TestData.cpp
@@ -1,3 +1,4 @@
+#define IN_TEST 1
 #include "CubicIntersection_TestData.h"
 #include <limits>
 
diff --git a/experimental/Intersection/CubicIntersection_TestData.h b/experimental/Intersection/CubicIntersection_TestData.h
index 6ed0f49..7dc63a0 100644
--- a/experimental/Intersection/CubicIntersection_TestData.h
+++ b/experimental/Intersection/CubicIntersection_TestData.h
@@ -1,3 +1,7 @@
+#if !defined(IN_TEST)
+    #define IN_TEST 1
+#endif
+
 #include "DataTypes.h"
 
 extern const Cubic pointDegenerates[];
diff --git a/experimental/Intersection/CubicReduceOrder.cpp b/experimental/Intersection/CubicReduceOrder.cpp
index 9c3b843..19c69db 100644
--- a/experimental/Intersection/CubicReduceOrder.cpp
+++ b/experimental/Intersection/CubicReduceOrder.cpp
@@ -150,12 +150,12 @@
     int inner1 = startIndex ^ mask;
     int inner2 = endIndex ^ mask;
     lineParameters.controlPtDistance(cubic, inner1, inner2, distance);
-    double limit = normalSquared * SquaredEpsilon;
+    double limit = normalSquared;
     int index;
     for (index = 0; index < 2; ++index) {
         double distSq = distance[index];
         distSq *= distSq;
-        if (distSq > limit) {
+        if (approximately_greater(distSq, limit)) {
             return false;
         }
     }
diff --git a/experimental/Intersection/DataTypes.cpp b/experimental/Intersection/DataTypes.cpp
index a68cb9a..776d0cf 100644
--- a/experimental/Intersection/DataTypes.cpp
+++ b/experimental/Intersection/DataTypes.cpp
@@ -14,8 +14,12 @@
 #endif
 
 
+#if USE_EPSILON
 const double PointEpsilon = 0.000001;
 const double SquaredEpsilon = PointEpsilon * PointEpsilon;
+#endif
+
+const int UlpsEpsilon = 16;
 
 bool rotate(const Cubic& cubic, int zero, int index, Cubic& rotPath) {
     double dy = cubic[index].y - cubic[zero].y;
diff --git a/experimental/Intersection/DataTypes.h b/experimental/Intersection/DataTypes.h
index 290a336..8b7ff7f 100644
--- a/experimental/Intersection/DataTypes.h
+++ b/experimental/Intersection/DataTypes.h
@@ -12,6 +12,13 @@
 #include <strings.h>
 #include <sys/types.h>
 
+bool AlmostEqualUlps(float A, float B, int maxUlpsDiff);
+int UlpsDiff(float A, float B);
+int FloatAsInt(float A);
+
+#define USE_EPSILON 0
+
+#if USE_EPSILON
 extern const double PointEpsilon;
 extern const double SquaredEpsilon;
 
@@ -42,6 +49,48 @@
 inline bool approximately_negative(double x) {
     return x < PointEpsilon;
 }
+#else
+extern const int UlpsEpsilon;
+
+#if defined(IN_TEST)
+// FIXME: move to test-only header
+const double PointEpsilon = 0.000001;
+const double SquaredEpsilon = PointEpsilon * PointEpsilon;
+#endif
+
+inline bool approximately_zero(double x) {
+    
+    return fabs(x) < FLT_EPSILON;
+}
+
+inline bool approximately_equal(double x, double y) {
+    if (approximately_zero(x - y)) {
+        return true;
+    }
+    return AlmostEqualUlps((float) x, (float) y, UlpsEpsilon);
+}
+
+inline bool approximately_equal_squared(double x, double y) {
+    return approximately_equal(x, y);
+}
+
+inline bool approximately_greater(double x, double y) {
+    return approximately_equal(x, y) ? false : x > y;
+}
+
+inline bool approximately_lesser(double x, double y) {
+    return approximately_equal(x, y) ? false : x < y;
+}
+
+inline bool approximately_zero_squared(double x) {
+    return approximately_zero(x);
+}
+
+inline bool approximately_negative(double x) {
+    return x < FLT_EPSILON;
+}
+
+#endif
 
 struct _Point {
     double x;
@@ -134,8 +183,5 @@
 void xy_at_t(const _Line& , double t, double& x, double& y);
 void xy_at_t(const Quadratic& , double t, double& x, double& y);
 
-bool AlmostEqualUlps(float A, float B, int maxUlpsDiff);
-int UlpsDiff(float A, float B);
-int FloatAsInt(float A);
 
 #endif // __DataTypes_h__
diff --git a/experimental/Intersection/EdgeMain.cpp b/experimental/Intersection/EdgeMain.cpp
index a87a5cd..0042c9e 100644
--- a/experimental/Intersection/EdgeMain.cpp
+++ b/experimental/Intersection/EdgeMain.cpp
@@ -1,11 +1,13 @@
 /*
- *  EdgeMain.cpp
- *  shapeops_edge
+ * Copyright 2012 Google Inc.
  *
- *  Created by Cary Clark on 3/26/12.
- *  Copyright 2012 __MyCompanyName__. All rights reserved.
- *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
  */
 
-#include "EdgeMain.h"
+#include "Intersection_Tests.h"
 
+int main(int argc, char* argv) {
+    Intersection_Tests();
+    return 0;
+}
\ No newline at end of file
diff --git a/experimental/Intersection/EdgeMain.h b/experimental/Intersection/EdgeMain.h
deleted file mode 100644
index 0ab897c..0000000
--- a/experimental/Intersection/EdgeMain.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#include "Intersection_Tests.h"
-
-int main(int argc, char* argv) {
-    Intersection_Tests();
-    return 0;
-}
\ No newline at end of file
diff --git a/experimental/Intersection/EdgeWalker.cpp b/experimental/Intersection/EdgeWalker.cpp
index 002e84c..4aff58f 100644
--- a/experimental/Intersection/EdgeWalker.cpp
+++ b/experimental/Intersection/EdgeWalker.cpp
@@ -767,6 +767,7 @@
         fTs = src.fTs;
         fTopIntercepts = src.fTopIntercepts;
         fBottomIntercepts = src.fBottomIntercepts;
+        return *this;
     }
 
     // OPTIMIZATION: remove this function if it's never called
@@ -1409,7 +1410,8 @@
             curve[1] = &rh.fTangent;
             curve[2] = &rh.fBelow;
         }
-        
+        // FIXME: code has been abandoned, incomplete....
+        return false;
     }
     
     bool abCompare(const SkPoint& a1, const SkPoint& a2, const SkPoint& b1,
@@ -1727,9 +1729,9 @@
             b2 = edge->fTangent.fX;
         }
         if (fabs(t1 - t2) > fabs(b1 - b2)) {
-            ulps = UlpsDiff(t1, t2);
+            ulps = UlpsDiff((float) t1, (float) t2);
         } else {
-            ulps = UlpsDiff(b1, b2);
+            ulps = UlpsDiff((float) b1, (float) b2);
         }
 #if DEBUG_ADJUST_COINCIDENT
         SkDebugf("%s this=%d edge=%d ulps=%d\n", __FUNCTION__, ID(), edge->ID(),
diff --git a/experimental/Intersection/EdgeWalkerPolygons_Mismatches.h b/experimental/Intersection/EdgeWalkerPolygons_Mismatches.h
deleted file mode 100644
index d038172..0000000
--- a/experimental/Intersection/EdgeWalkerPolygons_Mismatches.h
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- *  EdgeWalkerPolygons_Mismatches.h
- *  edge
- *
- *  Created by Cary Clark on 3/6/12.
- *  Copyright 2012 __MyCompanyName__. All rights reserved.
- *
- */
-
diff --git a/experimental/Intersection/EdgeWalkerPolygons_Test.cpp b/experimental/Intersection/EdgeWalkerPolygons_Test.cpp
index f3455ee..80ef527 100644
--- a/experimental/Intersection/EdgeWalkerPolygons_Test.cpp
+++ b/experimental/Intersection/EdgeWalkerPolygons_Test.cpp
@@ -367,7 +367,7 @@
     one.lineTo(0, 3);
     one.lineTo(1, 2);
     one.close();
-    for (float x = .1f; x <= 2.9f; x += .1f) {
+    for (float x = .1f; x <= 2.9ff; x += .1f) {
         SkDebugf("%s x=%g\n", __FUNCTION__, x);
         two.moveTo(0, 0);
         two.lineTo(x, x);
@@ -412,25 +412,25 @@
 static void testSimplifySkinnyTriangle2() {
         SkPath path, out;
 #if 01
-path.moveTo(591.091064, 627.534851);
-path.lineTo(541.088135, 560.707642);
-path.lineTo(491.085175, 493.880310);
-path.lineTo(441.082214, 427.053101);
-//path.lineTo(591.091064, 627.534851);
+path.moveTo(591.091064f, 627.534851f);
+path.lineTo(541.088135f, 560.707642f);
+path.lineTo(491.085175f, 493.880310f);
+path.lineTo(441.082214f, 427.053101f);
+//path.lineTo(591.091064f, 627.534851f);
 path.close();
 #endif
-path.moveTo(317.093445, 592.013306);
-path.lineTo(366.316162, 542.986572);
-path.lineTo(416.051514, 486.978577);
-path.lineTo(465.786865, 430.970581);
-//path.lineTo(317.093445, 592.013306);
+path.moveTo(317.093445f, 592.013306f);
+path.lineTo(366.316162f, 542.986572f);
+path.lineTo(416.051514f, 486.978577f);
+path.lineTo(465.786865f, 430.970581f);
+//path.lineTo(317.093445f, 592.013306f);
 path.close();
 #if 0
-path.moveTo(289.392517, 517.138489);
-path.lineTo(249.886078, 508.598022);
-path.lineTo(217.110916, 450.916443);
-path.lineTo(196.621033, 394.917633);
-//path.lineTo(289.392517, 517.138489);
+path.moveTo(289.392517f, 517.138489f);
+path.lineTo(249.886078f, 508.598022f);
+path.lineTo(217.110916f, 450.916443f);
+path.lineTo(196.621033f, 394.917633f);
+//path.lineTo(289.392517f, 517.138489f);
 path.close();
 #endif
     simplify(__FUNCTION__, path, true, out);
@@ -438,84 +438,84 @@
 
 static void testSimplifySkinnyTriangle3() {
         SkPath path, out;
-        path.moveTo(591, 627.534851);
-        path.lineTo(541, 560.707642);
-        path.lineTo(491, 493.880310);
-        path.lineTo(441, 427.053101);
+        path.moveTo(591, 627.534851f);
+        path.lineTo(541, 560.707642f);
+        path.lineTo(491, 493.880310f);
+        path.lineTo(441, 427.053101f);
         path.close();
-        path.moveTo(317, 592.013306);
-        path.lineTo(366, 542.986572);
-        path.lineTo(416, 486.978577);
-        path.lineTo(465, 430.970581);
+        path.moveTo(317, 592.013306f);
+        path.lineTo(366, 542.986572f);
+        path.lineTo(416, 486.978577f);
+        path.lineTo(465, 430.970581f);
         path.close();
     simplify(__FUNCTION__, path, true, out);
 }
 
 static void testSimplifySkinnyTriangle4() {
         SkPath path, out;
-path.moveTo(572.655212, 614.959961);
-path.lineTo(524.618896, 549.339600);
-path.lineTo(476.582581, 483.719269);
-path.lineTo(428.546265, 418.098938);
-path.lineTo(572.655212, 614.959961);
+path.moveTo(572.655212f, 614.959961f);
+path.lineTo(524.618896f, 549.339600f);
+path.lineTo(476.582581f, 483.719269f);
+path.lineTo(428.546265f, 418.098938f);
+path.lineTo(572.655212f, 614.959961f);
 path.close();
-path.moveTo(312.166382, 583.723083);
-path.lineTo(361.047791, 529.824219);
-path.lineTo(409.929230, 475.925354);
-path.lineTo(458.810669, 422.026520);
-path.lineTo(312.166382, 583.723083);
+path.moveTo(312.166382f, 583.723083f);
+path.lineTo(361.047791f, 529.824219f);
+path.lineTo(409.929230f, 475.925354f);
+path.lineTo(458.810669f, 422.026520f);
+path.lineTo(312.166382f, 583.723083f);
 path.close();
-path.moveTo(278.742737, 508.065643);
-path.lineTo(241.475800, 493.465118);
-path.lineTo(210.344177, 437.315125);
-path.lineTo(197.019455, 383.794556);
-path.lineTo(278.742737, 508.065643);
+path.moveTo(278.742737f, 508.065643f);
+path.lineTo(241.475800f, 493.465118f);
+path.lineTo(210.344177f, 437.315125f);
+path.lineTo(197.019455f, 383.794556f);
+path.lineTo(278.742737f, 508.065643f);
 path.close();
     simplify(__FUNCTION__, path, true, out);
 }
 
 static void testSimplifySkinnyTriangle5() {
         SkPath path, out;
-path.moveTo(554.690613, 602.286072);
-path.lineTo(508.590057, 537.906250);
-path.lineTo(462.489441, 473.526520);
-path.lineTo(416.388855, 409.146729);
-path.lineTo(554.690613, 602.286072);
+path.moveTo(554.690613f, 602.286072f);
+path.lineTo(508.590057f, 537.906250f);
+path.lineTo(462.489441f, 473.526520f);
+path.lineTo(416.388855f, 409.146729f);
+path.lineTo(554.690613f, 602.286072f);
 path.close();
-path.moveTo(307.216949, 575.189270);
-path.lineTo(355.826965, 516.804688);
-path.lineTo(403.815918, 464.990753);
-path.lineTo(451.804871, 413.176819);
-path.lineTo(307.216949, 575.189270);
+path.moveTo(307.216949f, 575.189270f);
+path.lineTo(355.826965f, 516.804688f);
+path.lineTo(403.815918f, 464.990753f);
+path.lineTo(451.804871f, 413.176819f);
+path.lineTo(307.216949f, 575.189270f);
 path.close();
-path.moveTo(271.998901, 521.301025);
-path.lineTo(234.619705, 499.687683);
-path.lineTo(203.059692, 441.332336);
-path.lineTo(195.994370, 386.856506);
-path.lineTo(271.998901, 521.301025);
+path.moveTo(271.998901f, 521.301025f);
+path.lineTo(234.619705f, 499.687683f);
+path.lineTo(203.059692f, 441.332336f);
+path.lineTo(195.994370f, 386.856506f);
+path.lineTo(271.998901f, 521.301025f);
 path.close();
     simplify(__FUNCTION__, path, true, out);
 }
 
 static void testSimplifySkinnyTriangle6() {
         SkPath path, out;
-path.moveTo(591.091064, 627.534851);
-path.lineTo(541.088135, 560.707642);
-path.lineTo(491.085175, 493.880310);
-path.lineTo(441.082214, 427.053101);
-path.lineTo(591.091064, 627.534851);
+path.moveTo(591.091064f, 627.534851f);
+path.lineTo(541.088135f, 560.707642f);
+path.lineTo(491.085175f, 493.880310f);
+path.lineTo(441.082214f, 427.053101f);
+path.lineTo(591.091064f, 627.534851f);
 path.close();
-path.moveTo(317.093445, 592.013306);
-path.lineTo(366.316162, 542.986572);
-path.lineTo(416.051514, 486.978577);
-path.lineTo(465.786865, 430.970581);
-path.lineTo(317.093445, 592.013306);
+path.moveTo(317.093445f, 592.013306f);
+path.lineTo(366.316162f, 542.986572f);
+path.lineTo(416.051514f, 486.978577f);
+path.lineTo(465.786865f, 430.970581f);
+path.lineTo(317.093445f, 592.013306f);
 path.close();
-path.moveTo(289.392517, 517.138489);
-path.lineTo(249.886078, 508.598022);
-path.lineTo(217.110916, 450.916443);
-path.lineTo(196.621033, 394.917633);
-path.lineTo(289.392517, 517.138489);
+path.moveTo(289.392517f, 517.138489f);
+path.lineTo(249.886078f, 508.598022f);
+path.lineTo(217.110916f, 450.916443f);
+path.lineTo(196.621033f, 394.917633f);
+path.lineTo(289.392517f, 517.138489f);
 path.close();
     simplify(__FUNCTION__, path, true, out);
 }
@@ -561,69 +561,69 @@
 
 static void testSimplifySkinnyTriangle7() {
         SkPath path, out;
-path.moveTo(487.502319, 550.811279);
-path.lineTo(448.826050, 491.720123);
-path.lineTo(410.149780, 432.628967);
-path.lineTo(371.473572, 373.537781);
-path.lineTo(487.502319, 550.811279);
+path.moveTo(487.502319f, 550.811279f);
+path.lineTo(448.826050f, 491.720123f);
+path.lineTo(410.149780f, 432.628967f);
+path.lineTo(371.473572f, 373.537781f);
+path.lineTo(487.502319f, 550.811279f);
 path.close();
-path.moveTo(295.817108, 532.655579);
-path.lineTo(342.896271, 485.912292);
-path.lineTo(389.975433, 439.169006);
-path.lineTo(437.054596, 392.425781);
-path.lineTo(295.817108, 532.655579);
+path.moveTo(295.817108f, 532.655579f);
+path.lineTo(342.896271f, 485.912292f);
+path.lineTo(389.975433f, 439.169006f);
+path.lineTo(437.054596f, 392.425781f);
+path.lineTo(295.817108f, 532.655579f);
 path.close();
-path.moveTo(239.726822, 575.025269);
-path.lineTo(204.117569, 521.429688);
-path.lineTo(171.275452, 454.110382);
-path.lineTo(193.328583, 397.859497);
-path.lineTo(239.726822, 575.025269);
+path.moveTo(239.726822f, 575.025269f);
+path.lineTo(204.117569f, 521.429688f);
+path.lineTo(171.275452f, 454.110382f);
+path.lineTo(193.328583f, 397.859497f);
+path.lineTo(239.726822f, 575.025269f);
 path.close();
     simplify(__FUNCTION__, path, true, out);
 }
 
 static void testSimplifySkinnyTriangle8() {
         SkPath path, out;
-path.moveTo(441.943115, 511.678040);
-path.lineTo(408.487549, 456.880920);
-path.lineTo(375.031952, 402.083801);
-path.lineTo(341.576385, 347.286682);
-path.lineTo(441.943115, 511.678040);
+path.moveTo(441.943115f, 511.678040f);
+path.lineTo(408.487549f, 456.880920f);
+path.lineTo(375.031952f, 402.083801f);
+path.lineTo(341.576385f, 347.286682f);
+path.lineTo(441.943115f, 511.678040f);
 path.close();
-path.moveTo(297.548492, 557.246704);
-path.lineTo(350.768494, 507.627014);
-path.lineTo(403.988525, 458.007385);
-path.lineTo(457.208527, 408.387695);
-path.lineTo(297.548492, 557.246704);
+path.moveTo(297.548492f, 557.246704f);
+path.lineTo(350.768494f, 507.627014f);
+path.lineTo(403.988525f, 458.007385f);
+path.lineTo(457.208527f, 408.387695f);
+path.lineTo(297.548492f, 557.246704f);
 path.close();
-path.moveTo(209.857895, 615.802979);
-path.lineTo(178.249481, 534.230347);
-path.lineTo(144.905640, 460.056824);
-path.lineTo(192.953125, 404.972900);
-path.lineTo(209.857895, 615.802979);
+path.moveTo(209.857895f, 615.802979f);
+path.lineTo(178.249481f, 534.230347f);
+path.lineTo(144.905640f, 460.056824f);
+path.lineTo(192.953125f, 404.972900f);
+path.lineTo(209.857895f, 615.802979f);
 path.close();
     simplify(__FUNCTION__, path, true, out);
 }
 
 static void testSimplifySkinnyTriangle9() {
         SkPath path, out;
-path.moveTo(439.867065, 528.291931);
-path.lineTo(405.413025, 469.107178);
-path.lineTo(370.958954, 409.922363);
-path.lineTo(336.504883, 350.737610);
-path.lineTo(439.867065, 528.291931);
+path.moveTo(439.867065f, 528.291931f);
+path.lineTo(405.413025f, 469.107178f);
+path.lineTo(370.958954f, 409.922363f);
+path.lineTo(336.504883f, 350.737610f);
+path.lineTo(439.867065f, 528.291931f);
 path.close();
-path.moveTo(298.922455, 573.251953);
-path.lineTo(356.360962, 521.905090);
-path.lineTo(413.799438, 470.558228);
-path.lineTo(471.237915, 419.211365);
-path.lineTo(298.922455, 573.251953);
+path.moveTo(298.922455f, 573.251953f);
+path.lineTo(356.360962f, 521.905090f);
+path.lineTo(413.799438f, 470.558228f);
+path.lineTo(471.237915f, 419.211365f);
+path.lineTo(298.922455f, 573.251953f);
 path.close();
-path.moveTo(187.200775, 643.035156);
-path.lineTo(159.713165, 540.993774);
-path.lineTo(126.257164, 462.198517);
-path.lineTo(193.534012, 409.266235);
-path.lineTo(187.200775, 643.035156);
+path.moveTo(187.200775f, 643.035156f);
+path.lineTo(159.713165f, 540.993774f);
+path.lineTo(126.257164f, 462.198517f);
+path.lineTo(193.534012f, 409.266235f);
+path.lineTo(187.200775f, 643.035156f);
 path.close();
 path.close();
     simplify(__FUNCTION__, path, true, out);
@@ -632,87 +632,87 @@
 static void testSimplifySkinnyTriangle10() {
         SkPath path, out;
 #if 0
-path.moveTo(99.270325, 239.365234);
-path.lineTo(105.967056, 173.361206);
-path.lineTo(148.821381, 141.309891);
-path.lineTo(159.101013, 189.235138);
-path.lineTo(99.270325, 239.365234);
+path.moveTo(99.270325f, 239.365234f);
+path.lineTo(105.967056f, 173.361206f);
+path.lineTo(148.821381f, 141.309891f);
+path.lineTo(159.101013f, 189.235138f);
+path.lineTo(99.270325f, 239.365234f);
 path.close();
 #endif
-path.moveTo(213.673737, 413.292938);
-path.lineTo(225.200134, 343.616821);
-path.lineTo(236.726532, 273.940704);
-path.lineTo(219.386414, 231.373322);
-path.lineTo(213.673737, 413.292938);
+path.moveTo(213.673737f, 413.292938f);
+path.lineTo(225.200134f, 343.616821f);
+path.lineTo(236.726532f, 273.940704f);
+path.lineTo(219.386414f, 231.373322f);
+path.lineTo(213.673737f, 413.292938f);
 path.close();
-path.moveTo(43.485352, 308.984497);
-path.lineTo(122.610657, 305.950134);
-path.lineTo(201.735962, 302.915802);
-path.lineTo(280.861267, 299.881470);
-path.lineTo(43.485352, 308.984497);
+path.moveTo(43.485352f, 308.984497f);
+path.lineTo(122.610657f, 305.950134f);
+path.lineTo(201.735962f, 302.915802f);
+path.lineTo(280.861267f, 299.881470f);
+path.lineTo(43.485352f, 308.984497f);
 path.close();
     simplify(__FUNCTION__, path, true, out);
 }
 
 static void testSimplifySkinnyTriangle11() {
         SkPath path, out;
-path.moveTo(-177.878387, 265.368988);
-path.lineTo(-254.415771, 303.709961);
-path.lineTo(-317.465363, 271.325562);
-path.lineTo(-374.520386, 207.507660);
-path.lineTo(-177.878387, 265.368988);
+path.moveTo(-177.878387f, 265.368988f);
+path.lineTo(-254.415771f, 303.709961f);
+path.lineTo(-317.465363f, 271.325562f);
+path.lineTo(-374.520386f, 207.507660f);
+path.lineTo(-177.878387f, 265.368988f);
 path.close();
-path.moveTo(-63.582489, -3.679123);
-path.lineTo(-134.496841, 26.434566);
-path.lineTo(-205.411209, 56.548256);
-path.lineTo(-276.325562, 86.661942);
-path.lineTo(-63.582489, -3.679123);
+path.moveTo(-63.582489f, -3.679123f);
+path.lineTo(-134.496841f, 26.434566f);
+path.lineTo(-205.411209f, 56.548256f);
+path.lineTo(-276.325562f, 86.661942f);
+path.lineTo(-63.582489f, -3.679123f);
 path.close();
-path.moveTo(-57.078423, 162.633453);
-path.lineTo(-95.963928, 106.261139);
-path.lineTo(-134.849457, 49.888824);
-path.lineTo(-173.734955, -6.483480);
-path.lineTo(-57.078423, 162.633453);
+path.moveTo(-57.078423f, 162.633453f);
+path.lineTo(-95.963928f, 106.261139f);
+path.lineTo(-134.849457f, 49.888824f);
+path.lineTo(-173.734955f, -6.483480f);
+path.lineTo(-57.078423f, 162.633453f);
 path.close();
     simplify(__FUNCTION__, path, true, out);
 }
 
 static void testSimplifySkinnyTriangle12() {
         SkPath path, out;
-path.moveTo(98.666489, -94.295059);
-path.lineTo(156.584320, -61.939133);
-path.lineTo(174.672974, -12.343765);
-path.lineTo(158.622345, 52.028267);
-path.lineTo(98.666489, -94.295059);
+path.moveTo(98.666489f, -94.295059f);
+path.lineTo(156.584320f, -61.939133f);
+path.lineTo(174.672974f, -12.343765f);
+path.lineTo(158.622345f, 52.028267f);
+path.lineTo(98.666489f, -94.295059f);
 path.close();
-path.moveTo(-133.225616, -48.622055);
-path.lineTo(-73.855499, -10.375397);
-path.lineTo(-14.485367, 27.871277);
-path.lineTo(44.884750, 66.117935);
-path.lineTo(-133.225616, -48.622055);
+path.moveTo(-133.225616f, -48.622055f);
+path.lineTo(-73.855499f, -10.375397f);
+path.lineTo(-14.485367f, 27.871277f);
+path.lineTo(44.884750f, 66.117935f);
+path.lineTo(-133.225616f, -48.622055f);
 path.close();
-path.moveTo( 9.030045, -163.413132);
-path.lineTo(-19.605331, -89.588760);
-path.lineTo(-48.240707, -15.764404);
-path.lineTo(-76.876053, 58.059944);
-path.lineTo( 9.030045, -163.413132);
+path.moveTo( 9.030045f, -163.413132f);
+path.lineTo(-19.605331f, -89.588760f);
+path.lineTo(-48.240707f, -15.764404f);
+path.lineTo(-76.876053f, 58.059944f);
+path.lineTo( 9.030045f, -163.413132f);
 path.close();
     simplify(__FUNCTION__, path, true, out);
 }
 
 static void testSimplifySkinnyTriangle13() {
         SkPath path, out;
-path.moveTo(340.41568, -170.97171);
-path.lineTo(418.846893, -142.428329);
-path.lineTo(497.278107, -113.884933);
-path.lineTo(449.18222, -45.6723022);
-path.lineTo(340.41568, -170.97171);
+path.moveTo(340.41568f, -170.97171f);
+path.lineTo(418.846893f, -142.428329f);
+path.lineTo(497.278107f, -113.884933f);
+path.lineTo(449.18222f, -45.6723022f);
+path.lineTo(340.41568f, -170.97171f);
 path.close();
-path.moveTo(326.610535, 34.0393639);
-path.lineTo(371.334595, -14.9620667);
-path.lineTo(416.058624, -63.9634857);
-path.lineTo(460.782654, -112.96492);
-path.lineTo(326.610535, 34.0393639);
+path.moveTo(326.610535f, 34.0393639f);
+path.lineTo(371.334595f, -14.9620667f);
+path.lineTo(416.058624f, -63.9634857f);
+path.lineTo(460.782654f, -112.96492f);
+path.lineTo(326.610535f, 34.0393639f);
 path.close();
     simplify(__FUNCTION__, path, true, out);
 }
diff --git a/experimental/Intersection/Intersection_Tests.cpp b/experimental/Intersection/Intersection_Tests.cpp
index e3c042c..4e4c8de 100644
--- a/experimental/Intersection/Intersection_Tests.cpp
+++ b/experimental/Intersection/Intersection_Tests.cpp
@@ -7,8 +7,13 @@
 #define TEST_QUADS_FIRST 0
 
 void Intersection_Tests() {
+    SimplifyFindTop_Test();
+    SimplifyAngle_Test();
+    QuadraticReduceOrder_Test();
+    QuadraticBezierClip_Test();
+    QuadraticIntersection_Test();
     SimplifyAddIntersectingTs_Test();
-
+    
     cubecode_test(1);
     convert_testx();
     // tests are in dependency / complexity order
@@ -39,8 +44,6 @@
 #endif
 
     QuadraticCoincidence_Test();
-    QuadraticReduceOrder_Test();
-    QuadraticBezierClip_Test();
     QuadraticIntersection_Test();
 
     CubicParameterization_Test();
diff --git a/experimental/Intersection/Intersection_Tests.h b/experimental/Intersection/Intersection_Tests.h
index a2d9df6..50e5600 100644
--- a/experimental/Intersection/Intersection_Tests.h
+++ b/experimental/Intersection/Intersection_Tests.h
@@ -1,3 +1,7 @@
+#if !defined(IN_TEST)
+    #define IN_TEST 1
+#endif
+
 void ActiveEdge_Test();
 void ConvexHull_Test();
 void ConvexHull_X_Test();
@@ -13,6 +17,9 @@
 void LineParameter_Test();
 void LineQuadraticIntersection_Test();
 void SimplifyAddIntersectingTs_Test();
+void SimplifyAngle_Test();
+void SimplifyFindNext_Test();
+void SimplifyFindTop_Test();
 void SimplifyDegenerate4x4TrianglesThreaded_Test();
 void SimplifyNondegenerate4x4TrianglesThreaded_Test();
 void SimplifyPolygonPaths_Test();
diff --git a/experimental/Intersection/LineParameters.h b/experimental/Intersection/LineParameters.h
index 1889622..202ba46 100644
--- a/experimental/Intersection/LineParameters.h
+++ b/experimental/Intersection/LineParameters.h
@@ -4,6 +4,15 @@
 // computer-aided design - volume 22 number 9 november 1990 pp 538 - 549
 // online at http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf
 
+// This turns a line segment into a parameterized line, of the form
+// ax + by + c = 0
+// When a^2 + b^2 == 1, the line is normalized.
+// The distance to the line for (x, y) is d(x,y) = ax + by + c
+//
+// Note that the distances below are not necessarily normalized. To get the true
+// distance, it's necessary to either call normalize() after xxxEndPoints(), or
+// divide the result of xxxDistance() by sqrt(normalSquared())
+
 class LineParameters {
 public:
     void cubicEndPoints(const Cubic& pts) {
@@ -42,7 +51,7 @@
 
     bool normalize() {
         double normal = sqrt(normalSquared());
-        if (normal < SquaredEpsilon) {
+        if (approximately_zero_squared(normal)) {
             a = b = c = 0;
             return false;
         }
@@ -87,6 +96,7 @@
     double pointDistance(const _Point& pt) {
         return a * pt.x + b * pt.y + c;
     }
+
 private:
     double a;
     double b;
diff --git a/experimental/Intersection/QuadraticBezierClip_Test.cpp b/experimental/Intersection/QuadraticBezierClip_Test.cpp
index a9561fd..289ebdb 100644
--- a/experimental/Intersection/QuadraticBezierClip_Test.cpp
+++ b/experimental/Intersection/QuadraticBezierClip_Test.cpp
@@ -2,7 +2,24 @@
 #include "Intersection_Tests.h"
 #include "QuadraticIntersection_TestData.h"
 
-void QuadraticBezierClip_Test() {
+static const Quadratic testSet[] = {
+    {{8.0000000000000071, 8.0000000000000071},
+     {8.7289570079366854, 8.7289570079366889},
+     {9.3914917259458743, 9.0593802763083691}},
+    {{8.0000000000000142, 8.0000000000000142},
+     {8.1250000000000107, 8.1250000000000071},
+     {8.2500000000000071, 8.2187500000000053}}
+};
+
+static void oneOffTest() {
+    const Quadratic& quad1 = testSet[0];
+    const Quadratic& quad2 = testSet[1];
+    double minT = 0;
+    double maxT = 1;
+    bezier_clip(quad1, quad2, minT, maxT);
+}
+
+void standardTestCases() {
     for (size_t index = 0; index < quadraticTests_count; ++index) {
         const Quadratic& quad1 = quadraticTests[index][0];
         const Quadratic& quad2 = quadraticTests[index][1];
@@ -22,3 +39,8 @@
         }
     }
 }
+
+void QuadraticBezierClip_Test() {
+    oneOffTest();
+    standardTestCases();
+}
diff --git a/experimental/Intersection/QuadraticIntersection_Test.cpp b/experimental/Intersection/QuadraticIntersection_Test.cpp
index 63b7338..582b195 100644
--- a/experimental/Intersection/QuadraticIntersection_Test.cpp
+++ b/experimental/Intersection/QuadraticIntersection_Test.cpp
@@ -3,10 +3,11 @@
 #include "Intersections.h"
 #include "QuadraticIntersection_TestData.h"
 #include "TestUtilities.h"
+#include "SkTypes.h"
 
 const int firstQuadIntersectionTest = 9;
 
-void QuadraticIntersection_Test() {
+static void standardTestCases() {
     for (size_t index = firstQuadIntersectionTest; index < quadraticTests_count; ++index) {
         const Quadratic& quad1 = quadraticTests[index][0];
         const Quadratic& quad2 = quadraticTests[index][1];
@@ -44,3 +45,49 @@
     }
 }
 
+static const Quadratic testSet[] = {
+    {{8, 8}, {10, 10}, {8, -10}},
+    {{8, 8}, {12, 12}, {14, 4}},
+    {{8, 8}, {9, 9}, {10, 8}}
+};
+
+const size_t testSetCount = sizeof(testSet) / sizeof(testSet[0]);
+
+static void oneOffTest() {
+    for (int outer = 0; outer < testSetCount - 1; ++outer) {
+        for (int inner = outer + 1; inner < testSetCount; ++inner) {
+            const Quadratic& quad1 = testSet[outer];
+            const Quadratic& quad2 = testSet[inner];
+            Intersections intersections;
+            intersect(quad1, quad2, intersections);
+            if (!intersections.intersected()) {
+                SkDebugf("%s no intersection!\n", __FUNCTION__);
+            }
+            for (int pt = 0; pt < intersections.used(); ++pt) {
+                double tt1 = intersections.fT[0][pt];
+                double tx1, ty1;
+                xy_at_t(quad1, tt1, tx1, ty1);
+                double tt2 = intersections.fT[1][pt];
+                double tx2, ty2;
+                xy_at_t(quad2, tt2, tx2, ty2);
+                if (!approximately_equal(tx1, tx2)) {
+                    SkDebugf("%s [%d,%d] x!= t1=%g (%g,%g) t2=%g (%g,%g)\n",
+                        __FUNCTION__, (int)index, pt, tt1, tx1, ty1, tt2, tx2, ty2);
+                    SkASSERT(0);
+                }
+                if (!approximately_equal(ty1, ty2)) {
+                    SkDebugf("%s [%d,%d] y!= t1=%g (%g,%g) t2=%g (%g,%g)\n",
+                        __FUNCTION__, (int)index, pt, tt1, tx1, ty1, tt2, tx2, ty2);
+                    SkASSERT(0);
+                }
+                SkDebugf("%s [%d][%d] t1=%1.9g (%1.9g, %1.9g) t2=%1.9g\n", __FUNCTION__,
+                    outer, inner, tt1, tx1, tx2, tt2);
+            }
+        }
+    }
+}
+
+void QuadraticIntersection_Test() {
+    oneOffTest();
+    standardTestCases();
+}
\ No newline at end of file
diff --git a/experimental/Intersection/QuadraticIntersection_TestData.cpp b/experimental/Intersection/QuadraticIntersection_TestData.cpp
index 2fa8a98..9ec585a 100644
--- a/experimental/Intersection/QuadraticIntersection_TestData.cpp
+++ b/experimental/Intersection/QuadraticIntersection_TestData.cpp
@@ -1,10 +1,8 @@
 /*
- *  QuadraticIntersection_TestData.cpp
- *  edge
+ * Copyright 2012 Google Inc.
  *
- *  Created by Cary Clark on 1/10/12.
- *  Copyright 2012 __MyCompanyName__. All rights reserved.
- *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
  */
 
 #include "QuadraticIntersection_TestData.h"
diff --git a/experimental/Intersection/QuadraticIntersection_TestData.h b/experimental/Intersection/QuadraticIntersection_TestData.h
index 54f084c..1852d17 100644
--- a/experimental/Intersection/QuadraticIntersection_TestData.h
+++ b/experimental/Intersection/QuadraticIntersection_TestData.h
@@ -1,3 +1,7 @@
+#if !defined(IN_TEST)
+    #define IN_TEST 1
+#endif
+
 #include "DataTypes.h"
 
 extern const Quadratic quadraticLines[];
diff --git a/experimental/Intersection/QuadraticReduceOrder.cpp b/experimental/Intersection/QuadraticReduceOrder.cpp
index f85cdc8..7429f6e 100644
--- a/experimental/Intersection/QuadraticReduceOrder.cpp
+++ b/experimental/Intersection/QuadraticReduceOrder.cpp
@@ -110,11 +110,10 @@
 bool isLinear(const Quadratic& quad, int startIndex, int endIndex) {
     LineParameters lineParameters;
     lineParameters.quadEndPoints(quad, startIndex, endIndex);
-    double normalSquared = lineParameters.normalSquared();
-    double distance = lineParameters.controlPtDistance(quad); // not normalized
-    double limit = normalSquared * SquaredEpsilon;
-    double distSq = distance * distance;
-    return distSq <= limit;
+    // FIXME: maybe it's possible to avoid this and compare non-normalized
+    lineParameters.normalize();
+    double distance = lineParameters.controlPtDistance(quad);
+    return approximately_zero(distance);
 }
 
 // reduce to a quadratic or smaller
diff --git a/experimental/Intersection/QuadraticReduceOrder_Test.cpp b/experimental/Intersection/QuadraticReduceOrder_Test.cpp
index 397342b..b716cdb 100644
--- a/experimental/Intersection/QuadraticReduceOrder_Test.cpp
+++ b/experimental/Intersection/QuadraticReduceOrder_Test.cpp
@@ -2,8 +2,27 @@
 #include "Intersection_Tests.h"
 #include "QuadraticIntersection_TestData.h"
 #include "TestUtilities.h"
+#include "SkTypes.h"
 
-void QuadraticReduceOrder_Test() {
+static const Quadratic testSet[] = {
+    {{1, 1}, {2, 2}, {1, 1.000003}},
+    {{1, 0}, {2, 6}, {3, 0}}
+};
+
+static const size_t testSetCount = sizeof(testSet) / sizeof(testSet[0]);
+
+
+static void oneOffTest() {
+    SkDebugf("%s FLT_EPSILON=%1.9g\n", __FUNCTION__, FLT_EPSILON);
+    for (int index = 0; index < testSetCount; ++index) {
+        const Quadratic& quad = testSet[index];
+        Quadratic reduce;
+        int order = reduceOrder(quad, reduce);
+        SkASSERT(order == 3);
+    }
+}
+
+static void standardTestCases() {
     size_t index;
     Quadratic reduce;
     int order;
@@ -36,3 +55,8 @@
         }
     }
 }
+
+void QuadraticReduceOrder_Test() {
+    oneOffTest();
+    standardTestCases();
+}
diff --git a/experimental/Intersection/Simplify.cpp b/experimental/Intersection/Simplify.cpp
index cb2e3bc..444b32d 100644
--- a/experimental/Intersection/Simplify.cpp
+++ b/experimental/Intersection/Simplify.cpp
@@ -4,16 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
-#include "CurveIntersection.h"
-#include "Intersections.h"
-#include "LineIntersection.h"
-#include "SkPath.h"
-#include "SkRect.h"
-#include "SkTArray.h"
-#include "SkTDArray.h"
-#include "ShapeOps.h"
-#include "TSearch.h"
-#include <algorithm> // used for std::min
+#include "Simplify.h"
 
 #undef SkASSERT
 #define SkASSERT(cond) while (!(cond)) { sk_throw(); }
@@ -21,8 +12,8 @@
 // Terminology:
 // A Path contains one of more Contours
 // A Contour is made up of Segment array
-// A Segment is described by a Verb and a Point array
-// A Verb is one of Line, Quad(ratic), and Cubic
+// A Segment is described by a Verb and a Point array with 2, 3, or 4 points
+// A Verb is one of Line, Quad(ratic), or Cubic
 // A Segment contains a Span array
 // A Span is describes a portion of a Segment using starting and ending T
 // T values range from 0 to 1, where 0 is the first Point in the Segment
@@ -263,6 +254,14 @@
     sub[3].fY = SkDoubleToScalar(dst[3].y);
 }
 
+static void (* const SegmentSubDivide[])(const SkPoint [], double , double ,
+        SkPoint []) = {
+    NULL,
+    LineSubDivide,
+    QuadSubDivide,
+    CubicSubDivide
+};
+
 static void QuadSubBounds(const SkPoint a[3], double startT, double endT,
         SkRect& bounds) {
     SkPoint dst[3];
@@ -291,6 +290,9 @@
             {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);
@@ -305,6 +307,9 @@
             {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);
@@ -330,19 +335,19 @@
     double x[2];
     xy_at_t(aLine, startT, x[0], *(double*) 0);
     xy_at_t(aLine, endT, x[0], *(double*) 0);
-    return startT < endT ? startT : endT;
+    return startT < endT ? (float) startT : (float) endT;
 }
 
 static SkScalar QuadLeftMost(const SkPoint a[3], double startT, double endT) {
     const Quadratic aQuad = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY},
             {a[2].fX, a[2].fY}};
-    return leftMostT(aQuad, startT, endT);
+    return (float) leftMostT(aQuad, startT, endT);
 }
 
 static SkScalar CubicLeftMost(const SkPoint a[4], double startT, double endT) {
     const Cubic aCubic = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY},
             {a[2].fX, a[2].fY}, {a[3].fX, a[3].fY}};
-    return leftMostT(aCubic, startT, endT);
+    return (float) leftMostT(aCubic, startT, endT);
 }
 
 static SkScalar (* const SegmentLeftMost[])(const SkPoint [], double , double) = {
@@ -359,57 +364,166 @@
     return implicit_matches_ulps(aLine, bLine, 32);
 }
 
+class Segment;
+
 // sorting angles
 // given angles of {dx dy ddx ddy dddx dddy} sort them
 class Angle {
 public:
+    // FIXME: this is bogus for quads and cubics
+    // if the quads and cubics' line from end pt to ctrl pt are coincident,
+    // there's no obvious way to determine the curve ordering from the
+    // derivatives alone. In particular, if one quadratic's coincident tangent
+    // is longer than the other curve, the final control point can place the
+    // longer curve on either side of the shorter one.
+    // Using Bezier curve focus http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf
+    // may provide some help, but nothing has been figured out yet.
     bool operator<(const Angle& rh) const {
-        if ((dy < 0) ^ (rh.dy < 0)) {
-            return dy < 0;
+        if ((fDy < 0) ^ (rh.fDy < 0)) {
+            return fDy < 0;
         }
-        SkScalar cmp = dx * rh.dy - rh.dx * dy;
+        if (fDy == 0 && rh.fDy == 0 && fDx != rh.fDx) {
+            return fDx < rh.fDx;
+        }
+        SkScalar cmp = fDx * rh.fDy - rh.fDx * fDy;
         if (cmp) {
             return cmp < 0;
         }
-        if ((ddy < 0) ^ (rh.ddy < 0)) {
-            return ddy < 0;
+        if ((fDDy < 0) ^ (rh.fDDy < 0)) {
+            return fDDy < 0;
         }
-        cmp = ddx * rh.ddy - rh.ddx * ddy;
+        if (fDDy == 0 && rh.fDDy == 0 && fDDx != rh.fDDx) {
+            return fDDx < rh.fDDx;
+        }
+        cmp = fDDx * rh.fDDy - rh.fDDx * fDDy;
         if (cmp) {
             return cmp < 0;
         }
-        if ((dddy < 0) ^ (rh.dddy < 0)) {
-            return ddy < 0;
+        if ((fDDDy < 0) ^ (rh.fDDDy < 0)) {
+            return fDDDy < 0;
         }
-        return dddx * rh.dddy < rh.dddx * dddy;
+        if (fDDDy == 0 && rh.fDDDy == 0) {
+            return fDDDx < rh.fDDDx;
+        }
+        return fDDDx * rh.fDDDy < rh.fDDDx * fDDDy;
     }
 
-    void set(SkPoint* pts, SkPath::Verb verb) {
-        dx = pts[1].fX - pts[0].fX; // b - a
-        dy = pts[1].fY - pts[0].fY;
+    int end() const {
+        return fEnd;
+    }
+
+    // since all angles share a point, this needs to know which point
+    // is the common origin, i.e., whether the center is at pts[0] or pts[verb]
+    // practically, this should only be called by addAngle
+    void set(const SkPoint* pts, SkPath::Verb verb, const Segment* segment,
+            int start, int end, bool coincident) {
+        SkASSERT(start != end);
+        fSegment = segment;
+        fStart = start;
+        fEnd = end;
+        fCoincident = coincident;
+        fDx = pts[1].fX - pts[0].fX; // b - a
+        fDy = pts[1].fY - pts[0].fY;
         if (verb == SkPath::kLine_Verb) {
-            ddx = ddy = dddx = dddy = 0;
+            fDDx = fDDy = fDDDx = fDDDy = 0;
             return;
         }
-        ddx = pts[2].fX - pts[1].fX - dx; // a - 2b + c
-        ddy = pts[2].fY - pts[2].fY - dy;
+        fDDx = pts[2].fX - pts[1].fX - fDx; // a - 2b + c
+        fDDy = pts[2].fY - pts[1].fY - fDy;
         if (verb == SkPath::kQuad_Verb) {
-            dddx = dddy = 0;
+            fDDDx = fDDDy = 0;
             return;
         }
-        dddx = pts[3].fX + 3 * (pts[1].fX - pts[2].fX) - pts[0].fX;
-        dddy = pts[3].fY + 3 * (pts[1].fY - pts[2].fY) - pts[0].fY;
+        fDDDx = pts[3].fX + 3 * (pts[1].fX - pts[2].fX) - pts[0].fX;
+        fDDDy = pts[3].fY + 3 * (pts[1].fY - pts[2].fY) - pts[0].fY;
+    }
+
+    // noncoincident quads/cubics may have the same initial angle
+    // as lines, so must sort by derivatives as well
+    // if flatness turns out to be a reasonable way to sort, use the below:
+    void setFlat(const SkPoint* pts, SkPath::Verb verb, const Segment* segment,
+            int start, int end, bool coincident) {
+        fSegment = segment;
+        fStart = start;
+        fEnd = end;
+        fCoincident = coincident;
+        fDx = pts[1].fX - pts[0].fX; // b - a
+        fDy = pts[1].fY - pts[0].fY;
+        if (verb == SkPath::kLine_Verb) {
+            fDDx = fDDy = fDDDx = fDDDy = 0;
+            return;
+        }
+        if (verb == SkPath::kQuad_Verb) {
+            int uplsX = FloatAsInt(pts[2].fX - pts[1].fY - fDx);
+            int uplsY = FloatAsInt(pts[2].fY - pts[1].fY - fDy);
+            int larger = std::max(abs(uplsX), abs(uplsY));
+            int shift = 0;
+            double flatT;
+            SkPoint ddPt; // FIXME: get rid of copy (change fDD_ to point)
+            LineParameters implicitLine;
+            _Line tangent = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}};
+            implicitLine.lineEndPoints(tangent);
+            implicitLine.normalize();
+            while (larger > UlpsEpsilon * 1024) {
+                larger >>= 2;
+                ++shift;
+                flatT = 0.5 / (1 << shift);
+                QuadXYAtT(pts, flatT, &ddPt);
+                _Point _pt = {ddPt.fX, ddPt.fY};
+                double distance = implicitLine.pointDistance(_pt);
+                if (approximately_zero(distance)) {
+                    SkDebugf("%s ulps too small %1.9g\n", __FUNCTION__, distance);
+                    break;
+                }
+            }
+            flatT = 0.5 / (1 << shift);
+            QuadXYAtT(pts, flatT, &ddPt);
+            fDDx = ddPt.fX - pts[0].fX;
+            fDDy = ddPt.fY - pts[0].fY;
+            SkASSERT(fDDx != 0 || fDDy != 0);
+            fDDDx = fDDDy = 0;
+            return;
+        }
+        SkASSERT(0); // FIXME: add cubic case
+    }
+    
+    const Segment* segment() const {
+        return fSegment;
+    }
+    
+    int sign() const {
+        int result = fStart - fEnd >> 31 | 1;
+        SkASSERT(result == fStart < fEnd ? -1 : 1);
+        return result;
+    }
+
+    int start() const {
+        return fStart;
     }
 
 private:
-    SkScalar dx;
-    SkScalar dy;
-    SkScalar ddx;
-    SkScalar ddy;
-    SkScalar dddx;
-    SkScalar dddy;
+    SkScalar fDx;
+    SkScalar fDy;
+    SkScalar fDDx;
+    SkScalar fDDy;
+    SkScalar fDDDx;
+    SkScalar fDDDy;
+    const Segment* fSegment;
+    int fStart;
+    int fEnd;
+    bool fCoincident;
 };
 
+static void sortAngles(SkTDArray<Angle>& angles, SkTDArray<Angle*>& angleList) {
+    int angleCount = angles.count();
+    int angleIndex;
+    angleList.setReserve(angleCount);
+    for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
+        *angleList.append() = &angles[angleIndex];
+    }
+    QSort<Angle>(angleList.begin(), angleList.end() - 1);
+}
+
 // Bounds, unlike Rect, does not consider a vertical line to be empty.
 struct Bounds : public SkRect {
     static bool Intersects(const Bounds& a, const Bounds& b) {
@@ -429,7 +543,8 @@
         Cubic cubic  = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY},
             {a[2].fX, a[2].fY}, {a[3].fX, a[3].fY}};
         dRect.setBounds(cubic);
-        set(dRect.left, dRect.top, dRect.right, dRect.bottom);
+        set((float) dRect.left, (float) dRect.top, (float) dRect.right,
+                (float) dRect.bottom);
     }
 
     void setQuadBounds(const SkPoint a[3]) {
@@ -437,16 +552,16 @@
                 {a[2].fX, a[2].fY}};
         _Rect dRect;
         dRect.setBounds(quad);
-        set(dRect.left, dRect.top, dRect.right, dRect.bottom);
+        set((float) dRect.left, (float) dRect.top, (float) dRect.right,
+                (float) dRect.bottom);
     }
 };
 
-class Segment;
-
 struct Span {
     double fT;
     Segment* fOther;
-    double fOtherT;
+    double fOtherT; // value at fOther[fOtherIndex].fT
+    int fOtherIndex;  // can't be used during intersection
     int fWinding; // accumulated from contours surrounding this one
     // OPTIMIZATION: done needs only 2 bits (values are -1, 0, 1)
     int fDone; // set when t to t+fDone is processed 
@@ -462,31 +577,34 @@
 #endif
     }
     
-    void addAngle(SkTDArray<Angle>& angles, double start, double end) {
-        // FIXME complete this
-        // start here;
+    void addAngle(SkTDArray<Angle>& angles, int start, int end,
+            bool coincident) const {
+        SkASSERT(start != end);
+        SkPoint edge[4];
+        (*SegmentSubDivide[fVerb])(fPts, fTs[start].fT, fTs[end].fT, edge);
+        Angle* angle = angles.append();
+        angle->set(edge, fVerb, this, start, end, coincident);
     }
 
-    bool addCubic(const SkPoint pts[4]) {
-        fPts = pts;
-        fVerb = SkPath::kCubic_Verb;
+    void addCubic(const SkPoint pts[4]) {
+        init(pts, SkPath::kCubic_Verb);
         fBounds.setCubicBounds(pts);
     }
 
-    bool addLine(const SkPoint pts[2]) {
-        fPts = pts;
-        fVerb = SkPath::kLine_Verb;
+    void addLine(const SkPoint pts[2]) {
+        init(pts, SkPath::kLine_Verb);
         fBounds.set(pts, 2);
     }
 
     // add 2 to edge or out of range values to get T extremes
-    void addOtherT(int index, double other) {
-        fTs[index].fOtherT = other;
+    void addOtherT(int index, double otherT, int otherIndex) {
+        Span& span = fTs[index];
+        span.fOtherT = otherT;
+        span.fOtherIndex = otherIndex;
     }
 
-    bool addQuad(const SkPoint pts[3]) {
-        fPts = pts;
-        fVerb = SkPath::kQuad_Verb;
+    void addQuad(const SkPoint pts[3]) {
+        init(pts, SkPath::kQuad_Verb);
         fBounds.setQuadBounds(pts);
     }
 
@@ -522,10 +640,70 @@
         return insertedAt;
     }
 
+    void addTwoAngles(int start, int end, const SkPoint& endLoc,
+            const Span* endSpan, bool startCo, SkTDArray<Angle>& angles) const {
+        // add edge leading into junction
+        addAngle(angles, end, start, startCo);
+        // add edge leading away from junction
+        bool coincident;
+        int step = start < end ? 1 : -1;
+        int tIndex = nextSpan(end, step, endLoc, endSpan, NULL, coincident);
+        if (tIndex >= 0) {
+            lastSpan(tIndex, step, endLoc, endSpan, coincident);
+            addAngle(angles, end, tIndex, coincident);
+        }
+    }
+
     const Bounds& bounds() const {
         return fBounds;
     }
 
+    void buildAngles(int index, int last, int step, const SkPoint& loc,
+            SkTDArray<Angle>& angles) const {
+        SkASSERT(index - last != 0);
+        SkASSERT((index - last  < 0) ^ (step < 0));
+        int end = last + step;  
+        do {
+            Span* span = &fTs[index];
+            Segment* other = span->fOther;
+            if (other->fDone) {
+                continue;
+            }
+        // if there is only one live crossing, and no coincidence, continue
+        // in the same direction
+        // if there is coincidence, the only choice may be to reverse direction
+            // find edge on either side of intersection
+            int oIndex = span->fOtherIndex;
+            Span* otherSpan = &other->fTs[oIndex];
+            SkASSERT(otherSpan->fOther == this);
+            // if done == -1, prior span has already been processed
+            bool otherCo;
+            int localStep = step;
+            int next = other->nextSpan(oIndex, localStep, loc, otherSpan,
+                    NULL, otherCo);
+            if (next < 0) {
+                localStep = -step;
+                next = other->nextSpan(oIndex, localStep, loc, otherSpan,
+                    NULL, otherCo);
+            }
+            other->lastSpan(next, localStep, loc, otherSpan, otherCo);
+            // add candidate into and away from junction
+            other->addTwoAngles(next, oIndex, loc, span, otherCo, angles);
+            
+        } while ((index += step) != end);
+    }
+    
+    // figure out if the segment's ascending T goes clockwise or not
+    // not enough context to write this as shown
+    // instead, add all segments meeting at the top
+    // sort them using buildAngleList
+    // find the first in the sort
+    // see if ascendingT goes to top
+    bool clockwise(int tIndex) const {
+        SkASSERT(0); // incomplete
+        return false;
+    }
+
     bool done() const {
         return fDone;
     }
@@ -545,13 +723,13 @@
         SkASSERT(0); // should never get here
         return -1;
     }
-    
+        
     // 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
     // step is in/out -1 or 1
     // spanIndex is returned
-    Segment* findNext(int start, int winding, int& step, int& spanIndex) {
+    Segment* findNext(int start, int winding, int& step, int& spanIndex) const {
         SkASSERT(step == 1 || step == -1);
         int count = fTs.count();
         SkASSERT(step > 0 ? start < count - 1 : start > 0);
@@ -565,129 +743,83 @@
         SkPoint startLoc; // OPTIMIZATION: store this in the t span?
         xyAtT(startSpan->fT, &startLoc);
         SkPoint endLoc;
-        Span* endSpan;
-        int end = nextSpan(start, step, startLoc, startSpan, &endLoc, &endSpan);
+        bool startCo;
+        int end = nextSpan(start, step, startLoc, startSpan, &endLoc, startCo);
         
         // if we hit the end looking for span end, is that always an error?
         SkASSERT(step > 0 ? end + 1 < count : end - 1 >= 0);
 
         // preflight for coincidence -- if present, it may change winding
         // considerations and whether reversed edges can be followed
-        bool foundCoincident = false;
-        int last = lastSpan(end, step, &startLoc, startSpan, foundCoincident);
+        int last = lastSpan(end, step, startLoc, startSpan, startCo);
         
         // Discard opposing direction candidates if no coincidence was found.
+        Span* endSpan = &fTs[end];
         int candidateCount = abs(last - end);
+        Segment* other;
         if (candidateCount == 1) {
-            SkASSERT(!foundCoincident);
+            SkASSERT(!startCo);
             // move in winding direction until edge in correct direction
             // balance wrong direction edges before finding correct one
             // this requres that the intersection is angularly sorted
             // for a single intersection, special case -- choose the opposite
             // edge that steps the same
-            Segment* other = endSpan->fOther;
+            other = endSpan->fOther;
             SkASSERT(!other->fDone);
-            spanIndex = other->matchSpan(this, endSpan->fT);
-            SkASSERT(step < 0 ? spanIndex > 0 : spanIndex < other->fTs.count() - 1);
+            spanIndex = endSpan->fOtherIndex;
+            SkASSERT(step < 0 ? spanIndex > 0
+                    : spanIndex < other->fTs.count() - 1);
             return other;
         }
 
-        // find the next T that describes a length
+        // more than one viable candidate -- measure angles to find best
         SkTDArray<Angle> angles;
-        Segment* segmentCandidate = NULL;
-        int spanCandidate = -1;
-        int directionCandidate;
-        do {
-            endSpan = &fTs[end];
-            Segment* other = endSpan->fOther;
-            if (other->fDone) {
-                continue;
+        SkASSERT(end - start != 0);
+        SkASSERT((end - start < 0) ^ (step < 0));
+        addTwoAngles(start, end, endLoc, endSpan, startCo, angles);
+        buildAngles(end, last, step, endLoc, angles);
+        SkTDArray<Angle*> sorted;
+        sortAngles(angles, sorted);
+        // find the starting edge
+        int startIndex = -1;
+        int angleCount = angles.count();
+        int angleIndex;
+        const Angle* angle;
+        for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
+            angle = sorted[angleIndex];
+            if (angle->segment() == this && angle->start() == end &&
+                    angle->end() == start) {
+                startIndex = angleIndex;
+                break;
             }
-        // if there is only one live crossing, and no coincidence, continue
-        // in the same direction
-        // if there is coincidence, the only choice may be to reverse direction
-            // find edge on either side of intersection
-            int oIndex = other->matchSpan(this, endSpan->fT);
-            int oCount = other->fTs.count();
-            do {
-                Span& otherSpan = other->fTs[oIndex];
-                // if done == -1, prior span has already been processed
-                int next = other->nextSpan(oIndex, step, endLoc, &otherSpan,
-                        NULL, NULL);
-                if (next < 0) {
-                    continue;
-                }
-                bool otherIsCoincident;
-                last = other->lastSpan(next, step, &endLoc, &otherSpan,
-                        otherIsCoincident);
-                if (last < 0) {
-                    continue;
-                }
-            #if 0
-                Span& prior = other->fTs[oIndex - 1];
-                    if (otherSpan.fDone >= 0 && oIndex > 0) {
-                        // FIXME: this needs to loop on -- until t && pt are different
-                        if (prior.fDone > 0) {
-                            continue;
-                        }
-                        
-                    }
-                } else { // step == 1
-                    if (otherSpan.fDone <= 0 && oIndex < oCount - 1) {
-                        // FIXME: this needs to loop on ++ until t && pt are different
-                        Span& next = other->fTs[oIndex + 1];
-                        if (next.fDone < 0) {
-                            continue;
-                        }
-                    }
-                }
-            #endif
-                if (!segmentCandidate) {
-                    segmentCandidate = other;
-                    spanCandidate = oIndex;
-                    directionCandidate = step;
-                    continue;
-                }
-                // there's two or more matches
-                if (spanCandidate >= 0) { // retrieve first stored candidate
-                    // add edge leading into junction
-                    addAngle(angles, endSpan->fT, startSpan->fT);
-                    // add edge leading away from junction
-                    double nextT = nextSpan(end, step, endLoc, endSpan, NULL,
-                            NULL);
-                    if (nextT >= 0) {
-                        addAngle(angles, endSpan->fT, nextT);
-                    }
-                    // add first stored candidate into junction
-                    segmentCandidate->addAngle(angles,
-                            segmentCandidate->fTs[spanCandidate - 1].fT,
-                            segmentCandidate->fTs[spanCandidate].fT);
-                    // add first stored candidate away from junction
-                    segmentCandidate->addAngle(angles,
-                            segmentCandidate->fTs[spanCandidate].fT,
-                            segmentCandidate->fTs[spanCandidate + 1].fT);
-                }
-                // add candidate into and away from junction
-                
-                
-           //     start here;
-                // more than once viable candidate -- need to
-                //  measure angles to find best
-                // noncoincident quads/cubics may have the same initial angle
-                // as lines, so must sort by derivatives as well
-                // while we're here, figure out all connections given the 
-                //  initial winding info
-                // so the span needs to contain the pairing info found here
-                // this should include the winding computed for the edge, and
-                //  what edge it connects to, and whether it is discarded
-                //  (maybe discarded == abs(winding) > 1) ?
-                // only need derivatives for duration of sorting, add a new struct
-                // for pairings, remove extra spans that have zero length and
-                //  reference an unused other
-                // for coincident, the last span on the other may be marked done
-                //  (always?)
-            } while (++oIndex < oCount);
-        } while ((end += step) != last);
+        }
+        SkASSERT(startIndex >= 0);
+        winding += angle->sign();
+        int nextIndex = startIndex;
+        const Angle* nextAngle;
+        do {
+            if (++nextIndex == angleCount) {
+                nextIndex = 0;
+            }
+            SkASSERT(nextIndex != startIndex); // should never wrap around
+            nextAngle = sorted[nextIndex];
+            // OPTIMIZATION: Figure out all connections, given the initial
+            // winding info (e.g., accumulate winding in span for reuse)
+            winding -= nextAngle->sign();
+        } while (winding);
+        // FIXME: get rid of cast
+        return const_cast<Segment*>(nextAngle->segment());
+        
+        // so the span needs to contain the pairing info found here
+        // this should include the winding computed for the edge, and
+        //  what edge it connects to, and whether it is discarded
+        //  (maybe discarded == abs(winding) > 1) ?
+        // only need derivatives for duration of sorting, add a new struct
+        // for pairings, remove extra spans that have zero length and
+        //  reference an unused other
+        // for coincident, the last span on the other may be marked done
+        //  (always?)
+        
         // if loop is exhausted, contour may be closed.
         // FIXME: pass in close point so we can check for closure
 
@@ -760,8 +892,7 @@
                         }
                         continue;
                     }
-                    if (toSpan.fOther == mOther && toSpan.fOtherT
-                            == moSpan.fT) {
+                    if (toSpan.fOther == mOther && toSpan.fOtherT == moSpan.fT) {
                         found = true;
                         break;
                     }
@@ -786,28 +917,15 @@
         }
     }
 
-    int findByT(double t, const Segment* match) const {
-        // OPTIMIZATION: bsearch if count is honkin huge
-        int count = fTs.count();
-        for (int index = 0; index < count; ++index) {
-            const Span& span = fTs[index];
-            if (t == span.fT && match == span.fOther) {
-                return index;
-            }
-        }
-        SkASSERT(0); // should never get here
-        return -1;
-    }
-
     // find the adjacent T that is leftmost, with a point != base
     int findLefty(int tIndex, const SkPoint& base) const {
-        int bestTIndex;
+        int bestTIndex = -1;
         SkPoint test;
-        SkScalar bestX = DBL_MAX;
+        SkScalar bestX = FLT_MAX;
         int testTIndex = tIndex;
         while (--testTIndex >= 0) {
-            xyAtT(testTIndex, &test);
-            if (test != base) {
+            xyAtT(fTs[testTIndex].fT, &test);
+            if (test == base) {
                 continue;
             }
             bestX = test.fX;
@@ -817,20 +935,23 @@
         int count = fTs.count();
         testTIndex = tIndex;
         while (++testTIndex < count) {
-            xyAtT(testTIndex, &test);
+            xyAtT(fTs[testTIndex].fT, &test);
             if (test == base) {
                 continue;
             }
-            return bestX > test.fX ? testTIndex : bestTIndex;
+            if (bestX > test.fX) {
+                bestTIndex = testTIndex;
+            }
+            break;
         }
-        SkASSERT(0); // can't get here (?)
-        return -1;
+        SkASSERT(bestTIndex != -1);
+        return bestTIndex;
     }
 
     // OPTIMIZATION : for a pair of lines, can we compute points at T (cached)
     // and use more concise logic like the old edge walker code?
     // FIXME: this needs to deal with coincident edges
-    const Segment* findTop(int& tIndex) const {
+    const Segment* findTop(int& tIndex, int& direction) const {
         // iterate through T intersections and return topmost
         // topmost tangent from y-min to first pt is closer to horizontal
         int firstT = 0;
@@ -841,7 +962,7 @@
         for (index = 1; index < count; ++index) {
             const Span& span = fTs[index];
             double t = span.fT;
-            SkScalar yIntercept = yAtT(t);
+            SkScalar yIntercept = t == 1 ? fPts[fVerb].fY : yAtT(t);
             if (topY > yIntercept) {
                 topY = yIntercept;
                 firstT = lastT = index;
@@ -850,44 +971,65 @@
             }
         }
         // if there's only a pair of segments, go with the endpoint chosen above
-        if (firstT == lastT && (firstT == 0 || firstT == count - 1)) {
+        if (firstT == lastT) {
             tIndex = firstT;
             return this;
         }
-        // if the topmost T is not on end, or is three-way or more, find left
-        SkPoint leftBase;
-        xyAtT(firstT, &leftBase);
-        int tLeft = findLefty(firstT, leftBase);
-        const Segment* leftSegment = this;
-        // look for left-ness from tLeft to firstT (matching y of other)
-        for (index = firstT; index <= lastT; ++index) {
-            const Segment* other = fTs[index].fOther;
-            double otherT = fTs[index].fOtherT;
-            int otherTIndex = other->findByT(otherT, this);
-            // pick companionT closest (but not too close) on either side
-            int otherTLeft = other->findLefty(otherTIndex, leftBase);
-            // within this span, find highest y
-            SkPoint testPt, otherPt;
-            testPt.fY = yAtT(tLeft);
-            otherPt.fY = other->yAtT(otherTLeft);
-            // FIXME: incomplete
-            // find the y intercept with the opposite segment
-            if (testPt.fY < otherPt.fY) {
-
-            } else if (testPt.fY > otherPt.fY) {
-
-            }
-            // FIXME: leftMost no good. Use y intercept instead
-#if 0
-            SkScalar otherMost = other->leftMost(otherTIndex, otherTLeft);
-            if (otherMost < left) {
-                leftSegment = other;
-            }
-#endif
+        // sort the edges to find the leftmost
+        SkPoint startLoc; // OPTIMIZATION: store this in the t span?
+        const Span* startSpan = &fTs[firstT];
+        xyAtT(startSpan->fT, &startLoc);
+        SkPoint endLoc;
+        bool nextCo;
+        int end = nextSpan(firstT, 1, startLoc, startSpan, &endLoc, nextCo);
+        if (end == -1) {
+            end = nextSpan(firstT, -1, startLoc, startSpan, &endLoc, nextCo);
         }
+        // if the topmost T is not on end, or is three-way or more, find left
+        // look for left-ness from tLeft to firstT (matching y of other)
+        SkTDArray<Angle> angles;
+        SkASSERT(firstT - end != 0);
+        addTwoAngles(end, firstT, endLoc, &fTs[firstT], nextCo, angles);
+        buildAngles(firstT, lastT, 1, startLoc, angles);
+        SkTDArray<Angle*> sorted;
+        sortAngles(angles, sorted);
+        const Segment* leftSegment = sorted[0]->segment();
+        tIndex = sorted[0]->end();
+        direction = sorted[0]->start() - tIndex;
+        SkASSERT(direction);
+        direction = direction < 0 ? -1 : 1; 
         return leftSegment;
     }
 
+    // FIXME: not crazy about this
+    // when the intersections are performed, the other index is into an
+    // incomplete array. as the array grows, the indices become incorrect
+    // while the following fixes the indices up again, it isn't smart about
+    // skipping segments whose indices are already correct
+    // assuming we leave the code that wrote the index in the first place
+    void fixOtherTIndex() {
+        int iCount = fTs.count();
+        for (int i = 0; i < iCount; ++i) {
+            Span& iSpan = fTs[i];
+            double oT = iSpan.fOtherT;
+            Segment* other = iSpan.fOther;
+            int oCount = other->fTs.count();
+            for (int o = 0; o < oCount; ++o) {
+                Span& oSpan = other->fTs[o];
+                if (oT == oSpan.fT && this == oSpan.fOther) {
+                    iSpan.fOtherIndex = o;
+                }
+            }
+        }
+    }
+    
+    void init(const SkPoint pts[], SkPath::Verb verb) {
+        fPts = pts;
+        fVerb = verb;
+        fDone = false;
+        fCoincident = 0;
+    }
+
     bool intersected() const {
         return fTs.count() > 0;
     }
@@ -916,59 +1058,49 @@
         return fBounds.fLeft == fBounds.fRight;
     }
 
-    int lastSpan(int end, int step, const SkPoint* startLoc,
-            const Span* startSpan, bool& coincident) {
+    int lastSpan(int end, int step, const SkPoint& startLoc,
+            const Span* startSpan, bool& coincident) const {
         int last = end;
         int count = fTs.count();
-        coincident = false;
         SkPoint lastLoc;
         do {
-            if (fTs[last].fCoincident == -step) {
+            end = last;
+            if (fTs[end].fCoincident == -step) {
                 coincident = true;
             }
-            if (step > 0 ? ++last < count : --last >= 0) {
-                return -1;
+            if (step > 0 ? ++last >= count : --last < 0) {
+                return end;
             }
             const Span& lastSpan = fTs[last];
             if (lastSpan.fDone == -step) {
-                return -1;
+                return end;
             }
             if (lastSpan.fT == startSpan->fT) {
                 continue;
             }
             xyAtT(lastSpan.fT, &lastLoc);
-        } while (*startLoc == lastLoc);
-        return last;
+        } while (startLoc == lastLoc);
+        return end;
     }
 
     SkScalar leftMost(int start, int end) const {
         return (*SegmentLeftMost[fVerb])(fPts, fTs[start].fT, fTs[end].fT);
     }
 
-    int matchSpan(const Segment* match, double matchT)
-    {
-        int count = fTs.count();
-        for (int index = 0; index < count; ++index) {
-            Span& span = fTs[index];
-            if (span.fOther != match) {
-                continue;
-            }
-            if (span.fOtherT != matchT) {
-                continue;
-            }
-            return index;
-        }
-        SkASSERT(0); // should never get here
-        return -1;
-    }
-
     int nextSpan(int from, int step, const SkPoint& fromLoc,
-            const Span* fromSpan, SkPoint* toLoc, Span** toSpan) {
+            const Span* fromSpan, SkPoint* toLoc, bool& coincident) const {
+        coincident = false;
+        if (fDone) {
+            return -1;
+        }
         int count = fTs.count();
         int to = from;
         while (step > 0 ? ++to < count : --to >= 0) {
             Span* span = &fTs[to];
-            if (span->fT == fromSpan->fT) {
+            if (span->fCoincident == step) {
+                coincident = true;
+            }
+            if (fromSpan->fT == span->fT) {
                 continue;
             }
             SkPoint loc;
@@ -976,12 +1108,12 @@
             if (fromLoc == loc) {
                 continue;
             }
+            if (span->fDone == -step) {
+                return -1;
+            }
             if (toLoc) {
                 *toLoc = loc;
             }
-            if (toSpan) {
-                *toSpan = span;
-            }
             return to;
         }
         return -1;
@@ -992,32 +1124,36 @@
     }
 
     void reset() {
-        fPts = NULL;
-        fVerb = (SkPath::Verb) -1;
+        init(NULL, (SkPath::Verb) -1);
         fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
         fTs.reset();
-        fDone = false;
-        fCoincident = 0;
     }
 
     // OPTIMIZATION: remove this function if it's never called
     double t(int tIndex) const {
         return fTs[tIndex].fT;
     }
+    
+    void updatePts(const SkPoint pts[]) {
+        fPts = pts;
+    }
 
     SkPath::Verb verb() const {
         return fVerb;
     }
 
     SkScalar xAtT(double t) const {
+        SkASSERT(t >= 0 && t <= 1);
         return (*SegmentXAtT[fVerb])(fPts, t);
     }
 
     void xyAtT(double t, SkPoint* pt) const {
+        SkASSERT(t >= 0 && t <= 1);
         (*SegmentXYAtT[fVerb])(fPts, t, pt);
     }
 
     SkScalar yAtT(double t) const {
+        SkASSERT(t >= 0 && t <= 1);
         return (*SegmentYAtT[fVerb])(fPts, t);
     }
 
@@ -1073,13 +1209,15 @@
         fContainsCurves = true;
     }
 
-    void addLine(const SkPoint pts[2]) {
+    int addLine(const SkPoint pts[2]) {
         fSegments.push_back().addLine(pts);
+        return fSegments.count();
     }
 
-    void addQuad(const SkPoint pts[3]) {
+    int addQuad(const SkPoint pts[3]) {
         fSegments.push_back().addQuad(pts);
         fContainsCurves = true;
+        return fSegments.count();
     }
 
     const Bounds& bounds() const {
@@ -1102,6 +1240,13 @@
         }
     }
 
+    void fixOtherTIndex() {
+        int segmentCount = fSegments.count();
+        for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
+            fSegments[sIndex].fixOtherTIndex();
+        }
+    }
+
     void reset() {
         fSegments.reset();
         fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
@@ -1217,12 +1362,6 @@
     }
 }
 
-void startContour() {
-    if (!fCurrentContour) {
-        fCurrentContour = fContours.push_back_n(1);
-    }
-}
-
 void walk() {
     // FIXME:remove once we can access path pts directly
     SkPath::RawIter iter(fPath); // FIXME: access path directly when allowed
@@ -1242,12 +1381,17 @@
     SkPath::Verb reducedVerb;
     uint8_t* verbPtr = fPathVerbs.begin();
     const SkPoint* pointsPtr = fPathPts.begin();
+    const SkPoint* finalCurveStart = NULL;
+    const SkPoint* finalCurveEnd = NULL;
     while ((verb = (SkPath::Verb) *verbPtr++) != SkPath::kDone_Verb) {
         switch (verb) {
             case SkPath::kMove_Verb:
                 complete();
-                startContour();
-                pointsPtr += 1;
+                if (!fCurrentContour) {
+                    fCurrentContour = fContours.push_back_n(1);
+                    finalCurveEnd = pointsPtr++;
+                    *fExtra.append() = -1; // start new contour
+                }
                 continue;
             case SkPath::kLine_Verb:
                 // skip degenerate points
@@ -1257,12 +1401,14 @@
                 }
                 break;
             case SkPath::kQuad_Verb:
+                
                 reducedVerb = QuadReduceOrder(&pointsPtr[-1], fReducePts);
                 if (reducedVerb == 0) {
                     break; // skip degenerate points
                 }
                 if (reducedVerb == 1) {
-                    fCurrentContour->addLine(fReducePts.end() - 2);
+                    *fExtra.append() = 
+                            fCurrentContour->addLine(fReducePts.end() - 2);
                     break;
                 }
                 fCurrentContour->addQuad(&pointsPtr[-1]);
@@ -1273,23 +1419,33 @@
                     break; // skip degenerate points
                 }
                 if (reducedVerb == 1) {
-                    fCurrentContour->addLine(fReducePts.end() - 2);
+                    *fExtra.append() =
+                            fCurrentContour->addLine(fReducePts.end() - 2);
                     break;
                 }
                 if (reducedVerb == 2) {
-                    fCurrentContour->addQuad(fReducePts.end() - 3);
+                    *fExtra.append() =
+                            fCurrentContour->addQuad(fReducePts.end() - 3);
                     break;
                 }
                 fCurrentContour->addCubic(&pointsPtr[-1]);
                 break;
             case SkPath::kClose_Verb:
                 SkASSERT(fCurrentContour);
+                if (finalCurveStart && finalCurveEnd
+                        && *finalCurveStart != *finalCurveEnd) {
+                    *fReducePts.append() = *finalCurveStart;
+                    *fReducePts.append() = *finalCurveEnd;
+                    *fExtra.append() =
+                            fCurrentContour->addLine(fReducePts.end() - 2);
+                }
                 complete();
                 continue;
             default:
                 SkDEBUGFAIL("bad verb");
                 return;
         }
+        finalCurveStart = &pointsPtr[verb - 1];
         pointsPtr += verb;
         SkASSERT(fCurrentContour);
     }
@@ -1297,6 +1453,24 @@
     if (fCurrentContour && !fCurrentContour->fSegments.count()) {
         fContours.pop_back();
     }
+    // correct pointers in contours since fReducePts may have moved as it grew
+    int cIndex = 0;
+    fCurrentContour = &fContours[0];
+    int extraCount = fExtra.count();
+    SkASSERT(fExtra[0] == -1);
+    int eIndex = 0;
+    int rIndex = 0;
+    while (++eIndex < extraCount) {
+        int offset = fExtra[eIndex];
+        if (offset < 0) {
+            fCurrentContour = &fContours[++cIndex];
+            continue;
+        }
+        Segment& segment = fCurrentContour->fSegments[offset - 1];
+        segment.updatePts(&fReducePts[rIndex]);
+        rIndex += segment.verb() + 1;
+    }
+    fExtra.reset(); // we're done with this
 }
 
 private:
@@ -1306,6 +1480,7 @@
     Contour* fCurrentContour;
     SkTArray<Contour>& fContours;
     SkTDArray<SkPoint> fReducePts; // segments created on the fly
+    SkTDArray<int> fExtra; // -1 marks new contour, > 0 offsets into contour
 };
 
 class Work {
@@ -1318,8 +1493,10 @@
         kCubic_Segment = SkPath::kCubic_Verb,
     };
 
-    void addOtherT(int index, double other) {
-        fContour->fSegments[fIndex].addOtherT(index, other);
+    // FIXME: does it make sense to write otherIndex now if we're going to
+    // fix it up later?
+    void addOtherT(int index, double otherT, int otherIndex) {
+        fContour->fSegments[fIndex].addOtherT(index, otherT, otherIndex);
     }
 
     // Avoid collapsing t values that are close to the same since
@@ -1436,29 +1613,34 @@
         const Work& wn, const double wtTs[2], const double wnTs[2]) {
 #if DEBUG_ADD_INTERSECTING_TS
     if (!pts) {
+        SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g %1.9g,%1.9g)\n",
+                __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY,
+                wt.pts()[1].fX, wt.pts()[1].fY, wn.pts()[0].fX, wn.pts()[0].fY,
+                wn.pts()[1].fX, wn.pts()[1].fY);
         return;
     }
     SkPoint wtOutPt, wnOutPt;
     LineXYAtT(wt.pts(), wtTs[0], &wtOutPt);
     LineXYAtT(wn.pts(), wnTs[0], &wnOutPt);
-    SkDebugf("%s wtTs[0]=%g (%g,%g, %g,%g) (%g,%g)\n",
+    SkDebugf("%s wtTs[0]=%g (%g,%g, %g,%g) (%g,%g)",
             __FUNCTION__,
             wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY,
             wt.pts()[1].fX, wt.pts()[1].fY, wtOutPt.fX, wtOutPt.fY);
     if (pts == 2) {
-        SkDebugf("%s wtTs[1]=%g\n", __FUNCTION__, wtTs[1]);
+        SkDebugf(" wtTs[1]=%g", wtTs[1]);
     }
-    SkDebugf("%s wnTs[0]=%g (%g,%g, %g,%g) (%g,%g)\n",
-            __FUNCTION__,
+    SkDebugf(" wnTs[0]=%g (%g,%g, %g,%g) (%g,%g)\n",
             wnTs[0], wn.pts()[0].fX, wn.pts()[0].fY,
             wn.pts()[1].fX, wn.pts()[1].fY, wnOutPt.fX, wnOutPt.fY);
     if (pts == 2) {
-        SkDebugf("%s wnTs[1]=%g\n", __FUNCTION__, wnTs[1]);
+        SkDebugf(" wnTs[1]=%g", wnTs[1]);
+    SkDebugf("\n");
     }
 #endif
 }
 
 static bool addIntersectTs(Contour* test, Contour* next, int winding) {
+
     if (test != next) {
         if (test->bounds().fBottom < next->bounds().fTop) {
             return false;
@@ -1467,10 +1649,11 @@
             return true;
         }
     }
-    Work wt, wn;
+    Work wt;
     wt.init(test);
-    wn.init(next);
     do {
+        Work wn;
+        wn.init(next);
         if (test == next && !wn.startAfter(wt)) {
             continue;
         }
@@ -1490,6 +1673,8 @@
                         case Work::kLine_Segment: {
                             pts = HLineIntersect(wn.pts(), wt.left(),
                                     wt.right(), wt.y(), wt.xFlipped(), ts);
+                            debugShowLineIntersection(pts, wt, wn,
+                                    ts.fT[1], ts.fT[0]);
                             break;
                         }
                         case Work::kQuad_Segment: {
@@ -1514,6 +1699,8 @@
                         case Work::kLine_Segment: {
                             pts = VLineIntersect(wn.pts(), wt.top(),
                                     wt.bottom(), wt.x(), wt.yFlipped(), ts);
+                            debugShowLineIntersection(pts, wt, wn,
+                                    ts.fT[1], ts.fT[0]);
                             break;
                         }
                         case Work::kQuad_Segment: {
@@ -1535,10 +1722,14 @@
                         case Work::kHorizontalLine_Segment:
                             pts = HLineIntersect(wt.pts(), wn.left(),
                                     wn.right(), wn.y(), wn.xFlipped(), ts);
+                            debugShowLineIntersection(pts, wt, wn,
+                                    ts.fT[1], ts.fT[0]);
                             break;
                         case Work::kVerticalLine_Segment:
                             pts = VLineIntersect(wt.pts(), wn.top(),
                                     wn.bottom(), wn.x(), wn.yFlipped(), ts);
+                            debugShowLineIntersection(pts, wt, wn,
+                                    ts.fT[1], ts.fT[0]);
                             break;
                         case Work::kLine_Segment: {
                             pts = LineIntersect(wt.pts(), wn.pts(), ts);
@@ -1625,8 +1816,8 @@
                 SkASSERT(ts.fT[1][pt] >= 0 && ts.fT[1][pt] <= 1);
                 int testTAt = wt.addT(ts.fT[swap][pt], wn, coincident);
                 int nextTAt = wn.addT(ts.fT[!swap][pt], wt, coincident);
-                wt.addOtherT(testTAt, ts.fT[!swap][pt]);
-                wn.addOtherT(nextTAt, ts.fT[swap][pt]);
+                wt.addOtherT(testTAt, ts.fT[!swap][pt], nextTAt);
+                wn.addOtherT(nextTAt, ts.fT[swap][pt], testTAt);
                 coincident = -coincident;
             }
         } while (wn.advance());
@@ -1643,6 +1834,39 @@
     }
 }
 
+    
+// OPTIMIZATION: not crazy about linear search here to find top active y.
+// seems like we should break down and do the sort, or maybe sort each
+// contours' segments? 
+// Once the segment array is built, there's no reason I can think of not to
+// sort it in Y. hmmm
+static Segment* findTopContour(SkTDArray<Contour*>& contourList,
+        int contourCount) {
+    int cIndex = 0;
+    Segment* topStart;
+    do {
+        Contour* topContour = contourList[cIndex];
+        topStart = topContour->topSegment();
+    } while (!topStart && ++cIndex < contourCount);
+    if (!topStart) {
+        return NULL;
+    }
+    SkScalar top = topStart->bounds().fTop;
+    for (int cTest = cIndex + 1; cTest < contourCount; ++cTest) {
+        Contour* contour = contourList[cTest];
+        if (top < contour->bounds().fTop) {
+            continue;
+        }
+        Segment* test = contour->topSegment();
+        if (top > test->bounds().fTop) {
+            cIndex = cTest;
+            topStart = test;
+            top = test->bounds().fTop;
+        }
+    }
+    return topStart;
+}
+
 // Each segment may have an inside or an outside. Segments contained within
 // winding may have insides on either side, and form a contour that should be
 // ignored. Segments that are coincident with opposing direction segments may
@@ -1650,41 +1874,26 @@
 // 'Normal' segments will have one inside and one outside. Subsequent connections
 // when winding should follow the intersection direction. If more than one edge
 // 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) {
     int contourCount = contourList.count();
+    int winding = 0; // there are no contours outside this one
     do {
-    // OPTIMIZATION: not crazy about linear search here to find top active y.
-    // seems like we should break down and do the sort, or maybe sort each
-    // contours' segments? 
-    // Once the segment array is built, there's no reason I can think of not to
-    // sort it in Y. hmmm
-        int cIndex = 0;
-        Segment* topStart;
-        do {
-            Contour* topContour = contourList[cIndex];
-            topStart = topContour->topSegment();
-        } while (!topStart && ++cIndex < contourCount);
+        Segment* topStart = findTopContour(contourList, contourCount);
         if (!topStart) {
             break;
         }
-        SkScalar top = topStart->bounds().fTop;
-        for (int cTest = cIndex + 1; cTest < contourCount; ++cTest) {
-            Contour* contour = contourList[cTest];
-            if (top < contour->bounds().fTop) {
-                continue;
-            }
-            Segment* test = contour->topSegment();
-            if (top > test->bounds().fTop) {
-                cIndex = cTest;
-                topStart = test;
-                top = test->bounds().fTop;
-            }
-        }
-        int index;
-        const Segment* topSegment = topStart->findTop(index);
         // Start at the top. Above the top is outside, below is inside.
-        // follow edges to intersection
+        // follow edges to intersection by changing the tIndex by direction.
+        int tIndex, step;
+        const Segment* topSegment = topStart->findTop(tIndex, step);
+        const Segment* next = topSegment;
+        do {
+            int spanIndex;
+            next = next->findNext(tIndex, winding, step, spanIndex);
+        } while (next != topSegment);
+        
         // at intersection, stay on outside, but mark remaining edges as inside
             // or, only mark first pair as inside?
             // how is this going to work for contained (but not intersecting)
@@ -1700,6 +1909,14 @@
 
 }
 
+static void fixOtherTIndex(SkTDArray<Contour*>& contourList) {
+    int contourCount = contourList.count();
+    for (int cTest = 0; cTest < contourCount; ++cTest) {
+        Contour* contour = contourList[cTest];
+        contour->fixOtherTIndex();
+    }
+}
+
 static void makeContourList(SkTArray<Contour>& contours, Contour& sentinel,
         SkTDArray<Contour*>& list) {
     int count = contours.count();
@@ -1740,6 +1957,7 @@
             next = *nextPtr++;
         } while (next != &sentinel && addIntersectTs(current, next, winding));
     } while (*currentPtr != &sentinel);
+    fixOtherTIndex(contourList);
     // eat through coincident edges
     coincidenceCheck(contourList, winding);
     // construct closed contours
diff --git a/experimental/Intersection/Simplify.h b/experimental/Intersection/Simplify.h
new file mode 100644
index 0000000..ae338ee
--- /dev/null
+++ b/experimental/Intersection/Simplify.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "CurveIntersection.h"
+#include "Intersections.h"
+#include "LineIntersection.h"
+#include "LineParameters.h"
+#include "SkPath.h"
+#include "SkRect.h"
+#include "SkTArray.h"
+#include "SkTDArray.h"
+#include "ShapeOps.h"
+#include "TSearch.h"
+#include <algorithm> // used for std::min
+
diff --git a/experimental/Intersection/SimplifyAddIntersectingTs_Test.cpp b/experimental/Intersection/SimplifyAddIntersectingTs_Test.cpp
index f920eba..d3a9f2e 100644
--- a/experimental/Intersection/SimplifyAddIntersectingTs_Test.cpp
+++ b/experimental/Intersection/SimplifyAddIntersectingTs_Test.cpp
@@ -1,13 +1,10 @@
-#include "CurveIntersection.h"
-#include "Intersections.h"
-#include "LineIntersection.h"
-#include "SkPath.h"
-#include "SkRect.h"
-#include "SkTArray.h"
-#include "SkTDArray.h"
-#include "ShapeOps.h"
-#include "TSearch.h"
-#include <algorithm> // used for std::min
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "Simplify.h"
 
 namespace SimplifyAddIntersectingTsTest {
 
diff --git a/experimental/Intersection/SimplifyAngle_Test.cpp b/experimental/Intersection/SimplifyAngle_Test.cpp
new file mode 100644
index 0000000..89123bd
--- /dev/null
+++ b/experimental/Intersection/SimplifyAngle_Test.cpp
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Simplify.h"
+
+namespace SimplifyAngleTest {
+
+#include "Simplify.cpp"
+
+} // end of SimplifyAngleTest namespace
+
+#include "Intersection_Tests.h"
+
+static const SkPoint lines[][2] = {
+    { { 10,  10}, { 10,  20} },
+    { { 10,  10}, { 20,  10} },
+    { { 10,  10}, {-20,  10} },
+    { { 10,  10}, { 10, -20} },
+    { { 10,  10}, { 20,  20} },
+    { { 10,  10}, {-20, -20} },
+    { { 10,  10}, {-20,  40} },
+    { { 10,  10}, { 40, -20} }
+};
+
+static const size_t lineCount = sizeof(lines) / sizeof(lines[0]);
+
+static const SkPoint quads[][3] = {
+    {{ 1,  1}, { 2,  2}, { 1,  3}}, // 0
+    {{ 1,  1}, { 3,  3}, { 1,  5}}, // 1
+    {{ 1,  1}, { 4,  4}, { 1,  7}}, // 2
+    {{ 1,  1}, { 5,  5}, { 9,  9}}, // 3
+    {{ 1,  1}, { 4,  4}, { 7,  1}}, // 4
+    {{ 1,  1}, { 3,  3}, { 5,  1}}, // 5
+    {{ 1,  1}, { 2,  2}, { 3,  1}}, // 6
+};
+
+static const size_t quadCount = sizeof(quads) / sizeof(quads[0]);
+
+static const SkPoint cubics[][4] = {
+    {{ 1,  1}, { 2,  2}, { 2,  3}, { 1,  4}},
+    {{ 1,  1}, { 3,  3}, { 3,  5}, { 1,  7}},
+    {{ 1,  1}, { 4,  4}, { 4,  7}, { 1,  10}},
+    {{ 1,  1}, { 5,  5}, { 8,  8}, { 9,  9}},
+    {{ 1,  1}, { 4,  4}, { 7,  4}, { 10, 1}},
+    {{ 1,  1}, { 3,  3}, { 5,  3}, { 7,  1}},
+    {{ 1,  1}, { 2,  2}, { 3,  2}, { 4,  1}},
+};
+
+static const size_t cubicCount = sizeof(cubics) / sizeof(cubics[0]);
+
+static void testLines(bool testFlat) {
+    // create angles in a circle
+    SkTDArray<SimplifyAngleTest::Angle> angles;
+    SkTDArray<SimplifyAngleTest::Angle* > angleList;
+    SkTDArray<double> arcTans;
+    size_t x;
+    for (x = 0; x < lineCount; ++x) {
+        SimplifyAngleTest::Angle* angle = angles.append();
+        if (testFlat) {
+            angle->setFlat(lines[x], SkPath::kLine_Verb, 0, x, x + 1, false);
+        } else {
+            angle->set(lines[x], SkPath::kLine_Verb, 0, x, x + 1, false);
+        }
+        double arcTan = atan2(lines[x][0].fX - lines[x][1].fX,
+                lines[x][0].fY - lines[x][1].fY);
+        arcTans.push(arcTan);
+    }
+    for (x = 0; x < lineCount; ++x) {
+        angleList.push(&angles[x]);
+    }
+    QSort<SimplifyAngleTest::Angle>(angleList.begin(), angleList.end() - 1);
+    bool first = true;
+    bool wrap = false;
+    double base, last;
+    for (size_t x = 0; x < lineCount; ++x) {
+        const SimplifyAngleTest::Angle* angle = angleList[x];
+        int span = angle->start();
+//        SkDebugf("%s [%d] %1.9g (%1.9g,%1.9g %1.9g,%1.9g)\n", __FUNCTION__,
+//                span, arcTans[span], lines[span][0].fX, lines[span][0].fY,
+//                lines[span][1].fX, lines[span][1].fY);
+        if (first) {
+            base = last = arcTans[span];
+            first = false;
+            continue;
+        }
+        if (last < arcTans[span]) {
+            last = arcTans[span];
+            continue;
+        }
+        if (!wrap) {
+            if (base < arcTans[span]) {
+                SkDebugf("%s !wrap [%d] %g\n", __FUNCTION__, span, arcTans[span]);
+                SkASSERT(0);
+            }
+            last = arcTans[span];
+            wrap = true;
+            continue;
+        }
+        SkDebugf("%s wrap [%d] %g\n", __FUNCTION__, span, arcTans[span]);
+        SkASSERT(0);
+    }
+}
+
+static void testQuads(bool testFlat) {
+    SkTDArray<SimplifyAngleTest::Angle> angles;
+    SkTDArray<SimplifyAngleTest::Angle* > angleList;
+    size_t x;
+    for (x = 0; x < quadCount; ++x) {
+        SimplifyAngleTest::Angle* angle = angles.append();
+        if (testFlat) {
+            angle->setFlat(quads[x], SkPath::kQuad_Verb, 0, x, x + 1, false);
+        } else {
+            angle->set(quads[x], SkPath::kQuad_Verb, 0, x, x + 1, false);
+        }
+    }
+    for (x = 0; x < quadCount; ++x) {
+        angleList.push(&angles[x]);
+    }
+    QSort<SimplifyAngleTest::Angle>(angleList.begin(), angleList.end() - 1);
+    for (size_t x = 0; x < quadCount; ++x) {
+        *angleList[x] < *angleList[x + 1];
+        SkASSERT(x == quadCount - 1 || *angleList[x] < *angleList[x + 1]);
+        const SimplifyAngleTest::Angle* angle = angleList[x];
+        if (x != angle->start()) {
+            SkDebugf("%s [%d] [%d]\n", __FUNCTION__, x, angle->start());
+            SkASSERT(0);
+        }
+    }
+}
+
+static void testCubics(bool testFlat) {
+    SkTDArray<SimplifyAngleTest::Angle> angles;
+    SkTDArray<SimplifyAngleTest::Angle* > angleList;
+    for (size_t x = 0; x < cubicCount; ++x) {
+        SimplifyAngleTest::Angle* angle = angles.append();
+        if (testFlat) {
+            angle->setFlat(cubics[x], SkPath::kCubic_Verb, 0, x, x + 1, false);
+        } else {
+            angle->set(cubics[x], SkPath::kCubic_Verb, 0, x, x + 1, false);
+        }
+        angleList.push(angle);
+    }
+    QSort<SimplifyAngleTest::Angle>(angleList.begin(), angleList.end() - 1);
+    for (size_t x = 0; x < cubicCount; ++x) {
+        const SimplifyAngleTest::Angle* angle = angleList[x];
+        if (x != angle->start()) {
+            SkDebugf("%s [%d] [%d]\n", __FUNCTION__, x, angle->start());
+            SkASSERT(0);
+        }
+    }
+}
+
+static void (*tests[])(bool) = {
+    testLines,
+    testQuads,
+    testCubics
+};
+
+static const size_t testCount = sizeof(tests) / sizeof(tests[0]);
+
+static void (*firstTest)(bool) = 0;
+static bool skipAll = false;
+
+void SimplifyAngle_Test() {
+    if (skipAll) {
+        return;
+    }
+    size_t index = 0;
+    if (firstTest) {
+        while (index < testCount && tests[index] != firstTest) {
+            ++index;
+        }
+    }
+    bool firstTestComplete = false;
+    for ( ; index < testCount; ++index) {
+        (*tests[index])(true);
+        firstTestComplete = true;
+    }
+}
\ No newline at end of file
diff --git a/experimental/Intersection/SimplifyFindNext_Test.cpp b/experimental/Intersection/SimplifyFindNext_Test.cpp
new file mode 100644
index 0000000..6d47a93
--- /dev/null
+++ b/experimental/Intersection/SimplifyFindNext_Test.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+ 
+#include "Simplify.h"
+
+namespace SimplifyFindNextTest {
+
+#include "Simplify.cpp"
+
+} // end of SimplifyFindNextTest namespace
+
+#include "Intersection_Tests.h"
+
+static const SimplifyFindNextTest::Segment* testCommon(
+        int start, int winding, int step,
+        SkTArray<SimplifyFindNextTest::Contour>& contours,
+        SimplifyFindNextTest::EdgeBuilder& builder, const SkPath& path) {
+    SkTDArray<SimplifyFindNextTest::Contour*> contourList;
+    SimplifyFindNextTest::Contour sentinel;
+    sentinel.reset();
+    makeContourList(contours, sentinel, contourList);
+    addIntersectTs(contourList[0], contourList[0], -1);
+    if (contours.count() > 1) {
+        SkASSERT(contours.count() == 2);
+        addIntersectTs(contourList[0], contourList[1], -1);
+        addIntersectTs(contourList[1], contourList[1], -1);
+    }
+    fixOtherTIndex(contourList);
+    SimplifyFindNextTest::Segment& segment = contours[0].fSegments[0];
+    int spanIndex;
+    SimplifyFindNextTest::Segment* next = segment.findNext(start, winding,
+            step, spanIndex);
+    SkASSERT(spanIndex == 1);
+    return next;
+}
+
+static void test(const SkPath& path) {
+    SkTArray<SimplifyFindNextTest::Contour> contours;
+    SimplifyFindNextTest::EdgeBuilder builder(path, contours);
+    int start = 0;
+    int winding = 0;
+    int step = 1;
+    testCommon(start, winding, step, contours, builder, path);
+}
+
+static void testLine1() {
+    SkPath path;
+    path.moveTo(2,0);
+    path.lineTo(1,1);
+    path.lineTo(0,0);
+    path.close();
+    test(path);
+}
+
+static void (*tests[])() = {
+    testLine1,
+};
+
+static const size_t testCount = sizeof(tests) / sizeof(tests[0]);
+
+static void (*firstTest)() = 0;
+static bool skipAll = false;
+
+void SimplifyFindNext_Test() {
+    if (skipAll) {
+        return;
+    }
+    size_t index = 0;
+    if (firstTest) {
+        while (index < testCount && tests[index] != firstTest) {
+            ++index;
+        }
+    }
+    bool firstTestComplete = false;
+    for ( ; index < testCount; ++index) {
+        (*tests[index])();
+        firstTestComplete = true;
+    }
+}
diff --git a/experimental/Intersection/SimplifyFindTop_Test.cpp b/experimental/Intersection/SimplifyFindTop_Test.cpp
new file mode 100644
index 0000000..ade9299
--- /dev/null
+++ b/experimental/Intersection/SimplifyFindTop_Test.cpp
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Simplify.h"
+
+namespace SimplifyFindTopTest {
+
+#include "Simplify.cpp"
+
+} // end of SimplifyFindTopTest namespace
+
+#include "Intersection_Tests.h"
+
+static const SimplifyFindTopTest::Segment* testCommon(
+        SkTArray<SimplifyFindTopTest::Contour>& contours,
+        SimplifyFindTopTest::EdgeBuilder& builder, const SkPath& path) {
+    SkTDArray<SimplifyFindTopTest::Contour*> contourList;
+    SimplifyFindTopTest::Contour sentinel;
+    sentinel.reset();
+    makeContourList(contours, sentinel, contourList);
+    addIntersectTs(contourList[0], contourList[0], -1);
+    if (contours.count() > 1) {
+        SkASSERT(contours.count() == 2);
+        addIntersectTs(contourList[0], contourList[1], -1);
+        addIntersectTs(contourList[1], contourList[1], -1);
+    }
+    fixOtherTIndex(contourList);
+    SimplifyFindTopTest::Segment* topStart = findTopContour(contourList,
+            contourList.count());
+    int index, direction;
+    const SimplifyFindTopTest::Segment* topSegment = topStart->findTop(index,
+            direction);
+    SkASSERT(direction == 1);
+    return topSegment;
+}
+
+static void test(const SkPath& path) {
+    SkTArray<SimplifyFindTopTest::Contour> contours;
+    SimplifyFindTopTest::EdgeBuilder builder(path, contours);
+    testCommon(contours, builder, path);
+}
+
+static void test(const SkPath& path, SkScalar x1, SkScalar y1,
+        SkScalar x2, SkScalar y2) {
+    SkTArray<SimplifyFindTopTest::Contour> contours;
+    SimplifyFindTopTest::EdgeBuilder builder(path, contours);
+    const SimplifyFindTopTest::Segment* topSegment =
+            testCommon(contours, builder, path);
+    const SkPoint* pts = topSegment->pts();
+    SkPoint top = pts[0];
+    SkPoint bottom = pts[1];
+    if (top.fY > bottom.fY) {
+        SkTSwap<SkPoint>(top, bottom);
+    }
+    SkASSERT(top.fX == x1);
+    SkASSERT(top.fY == y1);
+    SkASSERT(bottom.fX == x2);
+    SkASSERT(bottom.fY == y2);
+}
+
+static void testLine1() {
+    SkPath path;
+    path.moveTo(2,0);
+    path.lineTo(1,1);
+    path.lineTo(0,0);
+    path.close();
+    test(path);
+}
+
+static void addInnerCWTriangle(SkPath& path) {
+    path.moveTo(3,0);
+    path.lineTo(4,1);
+    path.lineTo(2,1);
+    path.close();
+}
+
+static void addInnerCCWTriangle(SkPath& path) {
+    path.moveTo(3,0);
+    path.lineTo(2,1);
+    path.lineTo(4,1);
+    path.close();
+}
+
+static void addOuterCWTriangle(SkPath& path) {
+    path.moveTo(3,0);
+    path.lineTo(6,2);
+    path.lineTo(0,2);
+    path.close();
+}
+
+static void addOuterCCWTriangle(SkPath& path) {
+    path.moveTo(3,0);
+    path.lineTo(0,2);
+    path.lineTo(6,2);
+    path.close();
+}
+
+static void testLine2() {
+    SkPath path;
+    addInnerCWTriangle(path);
+    addOuterCWTriangle(path);
+    test(path, 3, 0, 0, 2);
+}
+
+static void testLine3() {
+    SkPath path;
+    addOuterCWTriangle(path);
+    addInnerCWTriangle(path);
+    test(path, 3, 0, 0, 2);
+}
+
+static void testLine4() {
+    SkPath path;
+    addInnerCCWTriangle(path);
+    addOuterCWTriangle(path);
+    test(path, 3, 0, 0, 2);
+}
+
+static void testLine5() {
+    SkPath path;
+    addOuterCWTriangle(path);
+    addInnerCCWTriangle(path);
+    test(path, 3, 0, 0, 2);
+}
+
+static void testLine6() {
+    SkPath path;
+    addInnerCWTriangle(path);
+    addOuterCCWTriangle(path);
+    test(path, 3, 0, 0, 2);
+}
+
+static void testLine7() {
+    SkPath path;
+    addOuterCCWTriangle(path);
+    addInnerCWTriangle(path);
+    test(path, 3, 0, 0, 2);
+}
+
+static void testLine8() {
+    SkPath path;
+    addInnerCCWTriangle(path);
+    addOuterCCWTriangle(path);
+    test(path, 3, 0, 0, 2);
+}
+
+static void testLine9() {
+    SkPath path;
+    addOuterCCWTriangle(path);
+    addInnerCCWTriangle(path);
+    test(path, 3, 0, 0, 2);
+}
+
+static void testQuads() {
+    SkPath path;
+    path.moveTo(2,0);
+    path.quadTo(1,1, 0,0);
+    path.close();
+    test(path);
+}
+
+static void testCubics() {
+    SkPath path;
+    path.moveTo(2,0);
+    path.cubicTo(2,3, 1,1, 0,0);
+    path.close();
+    test(path);
+}
+
+static void (*tests[])() = {
+    testLine1,
+    testLine2,
+    testLine3,
+    testLine4,
+    testLine5,
+    testLine6,
+    testLine7,
+    testLine8,
+    testLine9,
+    testQuads,
+    testCubics
+};
+
+static const size_t testCount = sizeof(tests) / sizeof(tests[0]);
+
+static void (*firstTest)() = 0;
+static bool skipAll = false;
+
+void SimplifyFindTop_Test() {
+    if (skipAll) {
+        return;
+    }
+    size_t index = 0;
+    if (firstTest) {
+        while (index < testCount && tests[index] != firstTest) {
+            ++index;
+        }
+    }
+    bool firstTestComplete = false;
+    for ( ; index < testCount; ++index) {
+        (*tests[index])();
+        firstTestComplete = true;
+    }
+}
diff --git a/experimental/Intersection/op.htm b/experimental/Intersection/op.htm
index 4df4aeb..5173eab 100644
--- a/experimental/Intersection/op.htm
+++ b/experimental/Intersection/op.htm
@@ -234,24 +234,37 @@
 
 <div id="testSimplifyQuadratic17">
     SkPath path, out;
-    path.moveTo(0, 0);
-    path.quadTo(0, 0, 0, 0);
-    path.lineTo(2, 2);
+    path.moveTo(8, 8);
+    path.quadTo(10, 10, 8, -10);
     path.close();
-    path.moveTo(0, 1);
-    path.lineTo(0, 1);
-    path.quadTo(2, 1, 3, 3);
+    path.moveTo(8, 8);
+    path.quadTo(12, 12, 14, 4);
+    path.close();
+    path.moveTo(8, 8);
+    path.quadTo(9, 9, 10, 8);
     path.close();
     testSimplify(path, true, out, bitmap);
     drawAsciiPaths(path, out, true);
 }
 </div>
 
+<div id="testSimplifyQuadratic18">
+    SkPath path, out;
+    path.moveTo(8.0000000000000071, 8.0000000000000071);
+    path.quadTo(8.7289570079366854, 8.7289570079366889, 9.3914917259458743, 9.0593802763083691);
+    path.close();
+    path.moveTo(8.0000000000000142, 8.0000000000000142);
+    path.quadTo(8.1250000000000107, 8.1250000000000071, 8.2500000000000071, 8.2187500000000053);
+    path.close();
+    testSimplify(path, true, out, bitmap);
+    drawAsciiPaths(path, out, true);
+</div>
 </div>
 
 <script type="text/javascript">
 
 var testDivs = [
+    testSimplifyQuadratic18,
     testSimplifyQuadratic17,
     testSimplifyQuadratic16,
     testSimplifyQuadratic15,
@@ -332,10 +345,12 @@
         for (var verbs in contour) {
             var verb = contour[verbs];
             var last = verb.length;
-            xmin = Math.min(xmin, verb[0]);
-            ymin = Math.min(ymin, verb[1]);
-            xmax = Math.max(xmax, verb[last - 2]);
-            ymax = Math.max(ymax, verb[last - 1]);
+            for (var idx = 0; idx < last; idx += 2) {
+                xmin = Math.min(xmin, verb[idx]);
+                xmax = Math.max(xmax, verb[idx]);
+                ymin = Math.min(ymin, verb[idx + 1]);
+                ymax = Math.max(ymax, verb[idx + 1]);
+            }
         }
     }
     var subscale = 1;
diff --git a/experimental/Intersection/thingsToDo.txt b/experimental/Intersection/thingsToDo.txt
index c6e4563..7dd60d9 100644
--- a/experimental/Intersection/thingsToDo.txt
+++ b/experimental/Intersection/thingsToDo.txt
@@ -139,3 +139,28 @@
 once the edges are exhausted, remaining must be disjoint contours
 send a ray from a disjoint point through all other contours
 count the crossings, determine if disjoint is inside or outside, then continue
+
+===
+
+On Quadratic (and Cubic) Intersections
+
+Currently, if only the end points touch, QuadracticIntersections does a lot of
+work to figure that out. Can I test for that up front, then short circuit the
+recursive search for the end points?
+
+Or, is there something defective in the current approach that makes the end
+point recursion go so deep? I'm seeing 56 stack frames (about 28 divides, but
+thankfully, no splits) to find one matching endpoint.
+
+
+Bezier curve focus may allow more quickly determining that end points with
+identical tangents are practically coicident for some range of T, but I don't
+understand the math yet to know.
+
+Another approach is to determine how flat the curve is to make good guesses
+about how far to move away in T before doing the intersection for the remainder
+and/or to determine whether one curve is to the inside or outside of another.
+According to Mike/Rob, the flatness for quadratics increases by 4 for each
+subdivision, and a crude guess of the curvature can be had by comparing P1 to
+(P0+P2)/2. By looking at the ULPS of the numbers, I can guess what value of
+T may be far enough that the curves diverge but don't cross.
\ No newline at end of file