Now, path ops natively intersect conics, quads, and cubics in any combination. There are still a class of cubic tests that fail and a handful of undiagnosed failures from skps and fuzz tests, but things are much better overall.

Extended tests (150M+) run to completion in release in about 6 minutes; the standard test suite exceeds 100K and finishes in a few seconds on desktops.

TBR=reed
BUG=skia:3588

Review URL: https://codereview.chromium.org/1037953004
diff --git a/tests/PathOpsTSectDebug.h b/tests/PathOpsTSectDebug.h
index e28cba8..5780610 100644
--- a/tests/PathOpsTSectDebug.h
+++ b/tests/PathOpsTSectDebug.h
@@ -7,29 +7,27 @@
 
 #include "SkPathOpsTSect.h"
 
-template<typename TCurve>
-const SkTSpan<TCurve>* SkTSect<TCurve>::debugSpan(int id) const {
-    const SkTSpan<TCurve>* test = fHead;
+template<typename TCurve, typename OppCurve>
+void SkTCoincident<TCurve, OppCurve>::dump() const {
+    SkDebugf("t=%1.9g pt=(%1.9g,%1.9g)%s\n", fPerpT, fPerpPt.fX, fPerpPt.fY,
+            fCoincident ? " coincident" : "");
+}
+
+template<typename TCurve, typename OppCurve>
+const SkTSpan<TCurve, OppCurve>* SkTSect<TCurve, OppCurve>::debugSpan(int id) const {
+    const SkTSpan<TCurve, OppCurve>* test = fHead;
     do {
         if (test->debugID() == id) {
             return test;
         }
     } while ((test = test->next()));
-#ifndef SK_RELEASE
-    test = fOppSect->fHead;
-    do {
-        if (test->debugID() == id) {
-            return test;
-        }
-    } while ((test = test->next()));
-#endif
     return NULL;
 }
 
-template<typename TCurve>
-const SkTSpan<TCurve>* SkTSect<TCurve>::debugT(double t) const {
-    const SkTSpan<TCurve>* test = fHead;
-    const SkTSpan<TCurve>* closest = NULL;
+template<typename TCurve, typename OppCurve>
+const SkTSpan<TCurve, OppCurve>* SkTSect<TCurve, OppCurve>::debugT(double t) const {
+    const SkTSpan<TCurve, OppCurve>* test = fHead;
+    const SkTSpan<TCurve, OppCurve>* closest = NULL;
     double bestDist = DBL_MAX;
     do {
         if (between(test->fStartT, t, test->fEndT)) {
@@ -45,15 +43,15 @@
     return closest;
 }
 
-template<typename TCurve>
-void SkTSect<TCurve>::dump() const {
+template<typename TCurve, typename OppCurve>
+void SkTSect<TCurve, OppCurve>::dump() const {
     dumpCommon(fHead);
 }
 
 extern int gDumpTSectNum;
 
-template<typename TCurve>
-void SkTSect<TCurve>::dumpBoth(SkTSect* opp) const {
+template<typename TCurve, typename OppCurve>
+void SkTSect<TCurve, OppCurve>::dumpBoth(SkTSect<OppCurve, TCurve>* opp) const {
 #if DEBUG_T_SECT_DUMP <= 2
 #if DEBUG_T_SECT_DUMP == 2
     SkDebugf("%d ", ++gDumpTSectNum);
@@ -68,20 +66,20 @@
         this->dumpCurves();
     }
     if (opp->fHead) {
-        PATH_OPS_DEBUG_CODE(opp->dumpCurves());
+        opp->dumpCurves();
     }
     SkDebugf("</div>\n\n");
 #endif
 }
 
-template<typename TCurve>
-void SkTSect<TCurve>::dumpBounds(int id) const {
-    const SkTSpan<TCurve>* bounded = debugSpan(id);
+template<typename TCurve, typename OppCurve>
+void SkTSect<TCurve, OppCurve>::dumpBounded(int id) const {
+    const SkTSpan<TCurve, OppCurve>* bounded = debugSpan(id);
     if (!bounded) {
         SkDebugf("no span matches %d\n", id);
         return;
     }
-    const SkTSpan<TCurve>* test = bounded->debugOpp()->fHead;
+    const SkTSpan<OppCurve, TCurve>* test = bounded->debugOpp()->fHead;
     do {
         if (test->findOppSpan(bounded)) {
             test->dump();
@@ -89,18 +87,26 @@
     } while ((test = test->next()));
 }
 
-template<typename TCurve>
-void SkTSect<TCurve>::dumpCoin() const {
+template<typename TCurve, typename OppCurve>
+void SkTSect<TCurve, OppCurve>::dumpBounds() const {
+    const SkTSpan<TCurve, OppCurve>* test = fHead;
+    do {
+        test->dumpBounds();
+    } while ((test = test->next()));
+}
+
+template<typename TCurve, typename OppCurve>
+void SkTSect<TCurve, OppCurve>::dumpCoin() const {
     dumpCommon(fCoincident);
 }
 
-template<typename TCurve>
-void SkTSect<TCurve>::dumpCoinCurves() const {
+template<typename TCurve, typename OppCurve>
+void SkTSect<TCurve, OppCurve>::dumpCoinCurves() const {
     dumpCommonCurves(fCoincident);
 }
 
-template<typename TCurve>
-void SkTSect<TCurve>::dumpCommon(const SkTSpan<TCurve>* test) const {
+template<typename TCurve, typename OppCurve>
+void SkTSect<TCurve, OppCurve>::dumpCommon(const SkTSpan<TCurve, OppCurve>* test) const {
     SkDebugf("id=%d", debugID());
     if (!test) {
         SkDebugf(" (empty)");
@@ -112,36 +118,36 @@
     } while ((test = test->next()));
 }
 
-template<typename TCurve>
-void SkTSect<TCurve>::dumpCommonCurves(const SkTSpan<TCurve>* test) const {
+template<typename TCurve, typename OppCurve>
+void SkTSect<TCurve, OppCurve>::dumpCommonCurves(const SkTSpan<TCurve, OppCurve>* test) const {
     do {
         test->fPart.dumpID(test->debugID());
     } while ((test = test->next()));
 }
 
-template<typename TCurve>
-void SkTSect<TCurve>::dumpCurves() const {
+template<typename TCurve, typename OppCurve>
+void SkTSect<TCurve, OppCurve>::dumpCurves() const {
     dumpCommonCurves(fHead);
 }
 
-template<typename TCurve>
-const SkTSpan<TCurve>* SkTSpan<TCurve>::debugSpan(int id) const {
-    return PATH_OPS_DEBUG_RELEASE(fDebugSect->debugSpan(id), NULL);
+template<typename TCurve, typename OppCurve>
+const SkTSpan<TCurve, OppCurve>* SkTSpan<TCurve, OppCurve>::debugSpan(int id) const {
+    return SkDEBUGRELEASE(fDebugSect->debugSpan(id), NULL);
 }
 
-template<typename TCurve>
-const SkTSpan<TCurve>* SkTSpan<TCurve>::debugT(double t) const {
-    return PATH_OPS_DEBUG_RELEASE(fDebugSect->debugT(t), NULL);
+template<typename TCurve, typename OppCurve>
+const SkTSpan<TCurve, OppCurve>* SkTSpan<TCurve, OppCurve>::debugT(double t) const {
+    return SkDEBUGRELEASE(fDebugSect->debugT(t), NULL);
 }
 
-template<typename TCurve>
-void SkTSpan<TCurve>::dump() const {
+template<typename TCurve, typename OppCurve>
+void SkTSpan<TCurve, OppCurve>::dump() const {
     dumpID();
     SkDebugf("=(%g,%g) [", fStartT, fEndT);
-    const SkTSpanBounded<TCurve>* testBounded = fBounded;
+    const SkTSpanBounded<OppCurve, TCurve>* testBounded = fBounded;
     while (testBounded) {
-        const SkTSpan* span = testBounded->fBounded;
-        const SkTSpanBounded<TCurve>* next = testBounded->fNext;
+        const SkTSpan<OppCurve, TCurve>* span = testBounded->fBounded;
+        const SkTSpanBounded<OppCurve, TCurve>* next = testBounded->fNext;
         span->dumpID();
         if (next) {
             SkDebugf(",");
@@ -151,13 +157,30 @@
     SkDebugf("]");
 }
 
-template<typename TCurve>
-void SkTSpan<TCurve>::dumpBounds(int id) const {
-    PATH_OPS_DEBUG_CODE(fDebugSect->dumpBounds(id));
+template<typename TCurve, typename OppCurve>
+void SkTSpan<TCurve, OppCurve>::dumpBounded(int id) const {
+    SkDEBUGCODE(fDebugSect->dumpBounded(id));
 }
 
-template<typename TCurve>
-void SkTSpan<TCurve>::dumpID() const {
+template<typename TCurve, typename OppCurve>
+void SkTSpan<TCurve, OppCurve>::dumpBounds() const {
+    dumpID();
+    SkDebugf(" bounds=(%1.9g,%1.9g, %1.9g,%1.9g) boundsMax=%1.9g%s\n",
+            fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom, fBoundsMax,
+            fCollapsed ? " collapsed" : ""); 
+}
+
+template<typename TCurve, typename OppCurve>
+void SkTSpan<TCurve, OppCurve>::dumpCoin() const {
+    dumpID();
+    SkDebugf(" coinStart ");
+    fCoinStart.dump();
+    SkDebugf(" coinEnd ");
+    fCoinEnd.dump();
+}
+
+template<typename TCurve, typename OppCurve>
+void SkTSpan<TCurve, OppCurve>::dumpID() const {
     if (fCoinStart.isCoincident()) {
         SkDebugf("%c", '*');
     }