reduce pathops templated code

Pathops uses a template to intersect a pair of curves.
This generates six copies: quad/quad, quad/conic, quad/cubic,
conic/conic, conic/cubic, cubic/cubic.

This CL rewrites the template to generate a single copy,
and leverages a new abstract class, SkTCurve, to dispatch
to one of SkTQuad, SkTConic, or SkTCubic. These classes
are thin wrappers on the existing double curves classes
SkDQuad, SkDConic, and SkDCubic, which do work.

Kevin's BuildStats bot says this saves around 180K on the
release build. Running pathops_unittest shows no significant
performance difference, and the smaller version may be
slightly faster.

Bug: skia:
Change-Id: I17f94fd57a317035bc105cd43a06be6da9541cb6
Reviewed-on: https://skia-review.googlesource.com/c/161146
Reviewed-by: Mike Reed <reed@google.com>
Reviewed-by: Jim Van Verth <jvanverth@google.com>
Commit-Queue: Cary Clark <caryclark@skia.org>
diff --git a/src/pathops/SkIntersections.h b/src/pathops/SkIntersections.h
index d5d217c..fe70284 100644
--- a/src/pathops/SkIntersections.h
+++ b/src/pathops/SkIntersections.h
@@ -269,6 +269,11 @@
     int intersectRay(const SkDQuad&, const SkDLine&);
     int intersectRay(const SkDConic&, const SkDLine&);
     int intersectRay(const SkDCubic&, const SkDLine&);
+#if PATH_OP_COMPILE_FOR_SIZE
+    int intersectRay(const SkTCurve& tCurve, const SkDLine& line) {
+        return tCurve.intersectRay(this, line);
+    }
+#endif
     void merge(const SkIntersections& , int , const SkIntersections& , int );
     int mostOutside(double rangeStart, double rangeEnd, const SkDPoint& origin) const;
     void removeOne(int index);
diff --git a/src/pathops/SkPathOpsConic.cpp b/src/pathops/SkPathOpsConic.cpp
index ced3809..1cc5431 100644
--- a/src/pathops/SkPathOpsConic.cpp
+++ b/src/pathops/SkPathOpsConic.cpp
@@ -9,6 +9,7 @@
 #include "SkPathOpsConic.h"
 #include "SkPathOpsCubic.h"
 #include "SkPathOpsQuad.h"
+#include "SkPathOpsRect.h"
 
 // cribbed from the float version in SkGeometry.cpp
 static void conic_deriv_coeff(const double src[],
@@ -171,3 +172,23 @@
     *weight = chopped.fWeight;
     return chopped[1];
 }
+
+#if PATH_OP_COMPILE_FOR_SIZE
+
+    int SkTConic::intersectRay(SkIntersections* i, const SkDLine& line) const {
+        return i->intersectRay(fConic, line);
+    }
+
+    bool SkTConic::hullIntersects(const SkDQuad& quad, bool* isLinear) const  {
+        return quad.hullIntersects(fConic, isLinear);
+    }
+
+    bool SkTConic::hullIntersects(const SkDCubic& cubic, bool* isLinear) const {
+        return cubic.hullIntersects(fConic, isLinear);
+    }
+
+    void SkTConic::setBounds(SkDRect* rect) const {
+        rect->setBounds(fConic);
+    }
+
+#endif
diff --git a/src/pathops/SkPathOpsConic.h b/src/pathops/SkPathOpsConic.h
index 4236279..88a234f 100644
--- a/src/pathops/SkPathOpsConic.h
+++ b/src/pathops/SkPathOpsConic.h
@@ -80,6 +80,8 @@
         return fPts.isLinear(startIndex, endIndex);
     }
 
+    static int maxIntersections() { return kMaxIntersections; }
+
     bool monotonicInX() const {
         return fPts.monotonicInX();
     }
@@ -92,6 +94,8 @@
         fPts.otherPts(oddMan, endPt);
     }
 
+    static int pointCount() { return kPointCount; }
+    static int pointLast() { return kPointLast; }
     SkDPoint ptAtT(double t) const;
 
     static int RootsReal(double A, double B, double C, double t[2]) {
@@ -103,6 +107,7 @@
     }
 
     SkDConic subDivide(double t1, double t2) const;
+    void subDivide(double t1, double t2, SkDConic* c) const { *c = this->subDivide(t1, t2); }
 
     static SkDConic SubDivide(const SkPoint a[kPointCount], SkScalar weight, double t1, double t2) {
         SkDConic conic;
@@ -128,5 +133,64 @@
 
 };
 
+#if PATH_OP_COMPILE_FOR_SIZE
 
+#include "SkArenaAlloc.h"
+#include "SkPathOpsTCurve.h"
+
+class SkTConic : public SkTCurve {
+public:
+    SkDConic fConic;
+
+    SkTConic() {}
+
+    SkTConic(const SkDConic& c)
+        : fConic(c) {
+    }
+
+    ~SkTConic() override {}
+
+    const SkDPoint& operator[](int n) const override { return fConic[n]; }
+    SkDPoint& operator[](int n) override { return fConic[n]; }
+
+    bool collapsed() const override { return fConic.collapsed(); }
+    bool controlsInside() const override { return fConic.controlsInside(); }
+    void debugInit() override { return fConic.debugInit(); }
+    SkDVector dxdyAtT(double t) const override { return fConic.dxdyAtT(t); }
+#ifdef SK_DEBUG
+    SkOpGlobalState* globalState() const override { return fConic.globalState(); }
+#endif
+    bool hullIntersects(const SkDQuad& quad, bool* isLinear) const override;
+
+    bool hullIntersects(const SkDConic& conic, bool* isLinear) const override {
+        return conic.hullIntersects(fConic, isLinear);
+    }
+
+    bool hullIntersects(const SkDCubic& cubic, bool* isLinear) const override;
+
+    bool hullIntersects(const SkTCurve& curve, bool* isLinear) const override {
+        return curve.hullIntersects(fConic, isLinear);
+    }
+
+    int intersectRay(SkIntersections* i, const SkDLine& line) const override;
+    bool IsConic() const override { return true; }
+    SkTCurve* make(SkArenaAlloc& heap) const override { return heap.make<SkTConic>(); }
+
+    int maxIntersections() const override { return SkDConic::kMaxIntersections; }
+
+    void otherPts(int oddMan, const SkDPoint* endPt[2]) const override {
+        fConic.otherPts(oddMan, endPt);
+    }
+
+    int pointCount() const override { return SkDConic::kPointCount; }
+    int pointLast() const override { return SkDConic::kPointLast; }
+    SkDPoint ptAtT(double t) const override { return fConic.ptAtT(t); }
+    void setBounds(SkDRect* ) const override;
+
+    void subDivide(double t1, double t2, SkTCurve* curve) const override {
+        ((SkTConic*) curve)->fConic = fConic.subDivide(t1, t2);
+    }
+};
+
+#endif // PATH_OP_COMPILE_FOR_SIZE
 #endif
diff --git a/src/pathops/SkPathOpsCubic.cpp b/src/pathops/SkPathOpsCubic.cpp
index 8d3baa0..b3a10cd 100644
--- a/src/pathops/SkPathOpsCubic.cpp
+++ b/src/pathops/SkPathOpsCubic.cpp
@@ -732,3 +732,23 @@
     }
     return topT;
 }
+
+#if PATH_OP_COMPILE_FOR_SIZE
+
+    int SkTCubic::intersectRay(SkIntersections* i, const SkDLine& line) const {
+        return i->intersectRay(fCubic, line);
+    }
+
+    bool SkTCubic::hullIntersects(const SkDQuad& quad, bool* isLinear) const {
+        return quad.hullIntersects(fCubic, isLinear);
+    }
+
+    bool SkTCubic::hullIntersects(const SkDConic& conic, bool* isLinear) const  {
+        return conic.hullIntersects(fCubic, isLinear);
+    }
+
+    void SkTCubic::setBounds(SkDRect* rect) const {
+        rect->setBounds(fCubic);
+    }
+
+#endif
diff --git a/src/pathops/SkPathOpsCubic.h b/src/pathops/SkPathOpsCubic.h
index 2e8a5db..4f043fd 100644
--- a/src/pathops/SkPathOpsCubic.h
+++ b/src/pathops/SkPathOpsCubic.h
@@ -80,9 +80,12 @@
     bool hullIntersects(const SkDQuad& c2, bool* isLinear) const;
     bool hullIntersects(const SkDPoint* pts, int ptCount, bool* isLinear) const;
     bool isLinear(int startIndex, int endIndex) const;
+    static int maxIntersections() { return kMaxIntersections; }
     bool monotonicInX() const;
     bool monotonicInY() const;
     void otherPts(int index, const SkDPoint* o1Pts[kPointCount - 1]) const;
+    static int pointCount() { return kPointCount; }
+    static int pointLast() { return kPointLast; }
     SkDPoint ptAtT(double t) const;
     static int RootsReal(double A, double B, double C, double D, double t[3]);
     static int RootsValidT(const double A, const double B, const double C, double D, double s[3]);
@@ -114,6 +117,7 @@
     }
 
     SkDCubic subDivide(double t1, double t2) const;
+    void subDivide(double t1, double t2, SkDCubic* c) const { *c = this->subDivide(t1, t2); }
 
     static SkDCubic SubDivide(const SkPoint a[kPointCount], double t1, double t2) {
         SkDCubic cubic;
@@ -176,4 +180,64 @@
     SkDPoint pts[7];
 };
 
+#if PATH_OP_COMPILE_FOR_SIZE
+
+#include "SkArenaAlloc.h"
+#include "SkPathOpsTCurve.h"
+
+class SkTCubic : public SkTCurve {
+public:
+    SkDCubic fCubic;
+
+    SkTCubic() {}
+
+    SkTCubic(const SkDCubic& c)
+        : fCubic(c) {
+    }
+
+    ~SkTCubic() override {}
+
+    const SkDPoint& operator[](int n) const override { return fCubic[n]; }
+    SkDPoint& operator[](int n) override { return fCubic[n]; }
+
+    bool collapsed() const override { return fCubic.collapsed(); }
+    bool controlsInside() const override { return fCubic.controlsInside(); }
+    void debugInit() override { return fCubic.debugInit(); }
+    SkDVector dxdyAtT(double t) const override { return fCubic.dxdyAtT(t); }
+#ifdef SK_DEBUG
+    SkOpGlobalState* globalState() const override { return fCubic.globalState(); }
+#endif
+    bool hullIntersects(const SkDQuad& quad, bool* isLinear) const override;
+    bool hullIntersects(const SkDConic& conic, bool* isLinear) const override;
+
+    bool hullIntersects(const SkDCubic& cubic, bool* isLinear) const override {
+        return cubic.hullIntersects(fCubic, isLinear);
+    }
+
+    bool hullIntersects(const SkTCurve& curve, bool* isLinear) const override {
+        return curve.hullIntersects(fCubic, isLinear);
+    }
+
+    int intersectRay(SkIntersections* i, const SkDLine& line) const override;
+    bool IsConic() const override { return false; }
+    SkTCurve* make(SkArenaAlloc& heap) const override { return heap.make<SkTCubic>(); }
+
+    int maxIntersections() const override { return SkDCubic::kMaxIntersections; }
+
+    void otherPts(int oddMan, const SkDPoint* endPt[2]) const override {
+        fCubic.otherPts(oddMan, endPt);
+    }
+
+    int pointCount() const override { return SkDCubic::kPointCount; }
+    int pointLast() const override { return SkDCubic::kPointLast; }
+    SkDPoint ptAtT(double t) const override { return fCubic.ptAtT(t); }
+    void setBounds(SkDRect* ) const override;
+
+    void subDivide(double t1, double t2, SkTCurve* curve) const override {
+        ((SkTCubic*) curve)->fCubic = fCubic.subDivide(t1, t2);
+    }
+};
+
+#endif // PATH_OP_COMPILE_FOR_SIZE
+
 #endif
diff --git a/src/pathops/SkPathOpsQuad.cpp b/src/pathops/SkPathOpsQuad.cpp
index 9a104bf..bcc894e 100644
--- a/src/pathops/SkPathOpsQuad.cpp
+++ b/src/pathops/SkPathOpsQuad.cpp
@@ -9,6 +9,7 @@
 #include "SkPathOpsCubic.h"
 #include "SkPathOpsCurve.h"
 #include "SkPathOpsQuad.h"
+#include "SkPathOpsRect.h"
 
 // from blackpawn.com/texts/pointinpoly
 static bool pointInTriangle(const SkDPoint fPts[3], const SkDPoint& test) {
@@ -397,3 +398,23 @@
     *a -= *b;          // a = A - 2*B +   C
     *b -= *c;          // b =     2*B - 2*C
 }
+
+#if PATH_OP_COMPILE_FOR_SIZE
+
+    int SkTQuad::intersectRay(SkIntersections* i, const SkDLine& line) const {
+        return i->intersectRay(fQuad, line);
+    }
+
+    bool SkTQuad::hullIntersects(const SkDConic& conic, bool* isLinear) const  {
+        return conic.hullIntersects(fQuad, isLinear);
+    }
+
+    bool SkTQuad::hullIntersects(const SkDCubic& cubic, bool* isLinear) const {
+        return cubic.hullIntersects(fQuad, isLinear);
+    }
+
+    void SkTQuad::setBounds(SkDRect* rect) const {
+        rect->setBounds(fQuad);
+    }
+
+#endif
diff --git a/src/pathops/SkPathOpsQuad.h b/src/pathops/SkPathOpsQuad.h
index 34740d6..2de1422 100644
--- a/src/pathops/SkPathOpsQuad.h
+++ b/src/pathops/SkPathOpsQuad.h
@@ -81,14 +81,19 @@
     bool hullIntersects(const SkDConic& , bool* isLinear) const;
     bool hullIntersects(const SkDCubic& , bool* isLinear) const;
     bool isLinear(int startIndex, int endIndex) const;
+    static int maxIntersections() { return kMaxIntersections; }
     bool monotonicInX() const;
     bool monotonicInY() const;
     void otherPts(int oddMan, const SkDPoint* endPt[2]) const;
+    static int pointCount() { return kPointCount; }
+    static int pointLast() { return kPointLast; }
     SkDPoint ptAtT(double t) const;
     static int RootsReal(double A, double B, double C, double t[2]);
     static int RootsValidT(const double A, const double B, const double C, double s[2]);
     static void SetABC(const double* quad, double* a, double* b, double* c);
     SkDQuad subDivide(double t1, double t2) const;
+    void subDivide(double t1, double t2, SkDQuad* quad) const { *quad = this->subDivide(t1, t2); }
+
     static SkDQuad SubDivide(const SkPoint a[kPointCount], double t1, double t2) {
         SkDQuad quad;
         quad.set(a);
@@ -117,4 +122,65 @@
     SkDEBUGCODE(SkOpGlobalState* fDebugGlobalState);
 };
 
+#if PATH_OP_COMPILE_FOR_SIZE
+
+#include "SkArenaAlloc.h"
+#include "SkPathOpsTCurve.h"
+
+class SkTQuad : public SkTCurve {
+public:
+    SkDQuad fQuad;
+
+    SkTQuad() {}
+
+    SkTQuad(const SkDQuad& q)
+        : fQuad(q) {
+    }
+
+    ~SkTQuad() override {}
+
+    const SkDPoint& operator[](int n) const override { return fQuad[n]; }
+    SkDPoint& operator[](int n) override { return fQuad[n]; }
+
+    bool collapsed() const override { return fQuad.collapsed(); }
+    bool controlsInside() const override { return fQuad.controlsInside(); }
+    void debugInit() override { return fQuad.debugInit(); }
+    SkDVector dxdyAtT(double t) const override { return fQuad.dxdyAtT(t); }
+#ifdef SK_DEBUG
+    SkOpGlobalState* globalState() const override { return fQuad.globalState(); }
+#endif
+
+    bool hullIntersects(const SkDQuad& quad, bool* isLinear) const override {
+        return quad.hullIntersects(fQuad, isLinear);
+    }
+
+    bool hullIntersects(const SkDConic& conic, bool* isLinear) const override;
+    bool hullIntersects(const SkDCubic& cubic, bool* isLinear) const override;
+
+    bool hullIntersects(const SkTCurve& curve, bool* isLinear) const override {
+        return curve.hullIntersects(fQuad, isLinear);
+    }
+
+    int intersectRay(SkIntersections* i, const SkDLine& line) const override;
+    bool IsConic() const override { return false; }
+    SkTCurve* make(SkArenaAlloc& heap) const override { return heap.make<SkTQuad>(); }
+
+    int maxIntersections() const override { return SkDQuad::kMaxIntersections; }
+
+    void otherPts(int oddMan, const SkDPoint* endPt[2]) const override {
+        fQuad.otherPts(oddMan, endPt);
+    }
+
+    int pointCount() const override { return SkDQuad::kPointCount; }
+    int pointLast() const override { return SkDQuad::kPointLast; }
+    SkDPoint ptAtT(double t) const override { return fQuad.ptAtT(t); }
+    void setBounds(SkDRect* ) const override;
+
+    void subDivide(double t1, double t2, SkTCurve* curve) const override {
+        ((SkTQuad*) curve)->fQuad = fQuad.subDivide(t1, t2);
+    }
+};
+
+#endif // PATH_OP_COMPILE_FOR_SIZE
+
 #endif
diff --git a/src/pathops/SkPathOpsRect.cpp b/src/pathops/SkPathOpsRect.cpp
index 8c01153..18a1a0b 100644
--- a/src/pathops/SkPathOpsRect.cpp
+++ b/src/pathops/SkPathOpsRect.cpp
@@ -60,3 +60,11 @@
         add(curve.ptAtT(t));
     }
 }
+
+#if PATH_OP_COMPILE_FOR_SIZE
+
+    void SkDRect::setBounds(const SkTCurve& curve) {
+        curve.setBounds(this);
+    }
+
+#endif
diff --git a/src/pathops/SkPathOpsRect.h b/src/pathops/SkPathOpsRect.h
index 1efbb8c..a429273 100644
--- a/src/pathops/SkPathOpsRect.h
+++ b/src/pathops/SkPathOpsRect.h
@@ -9,6 +9,8 @@
 
 #include "SkPathOpsPoint.h"
 
+class SkTCurve;
+
 struct SkDRect {
     double fLeft, fTop, fRight, fBottom;
 
@@ -65,6 +67,8 @@
 
     void setBounds(const SkDQuad& curve, const SkDQuad& sub, double tStart, double tEnd);
 
+    void setBounds(const SkTCurve& curve);
+
     bool valid() const {
         return fLeft <= fRight && fTop <= fBottom;
     }
diff --git a/src/pathops/SkPathOpsTCurve.h b/src/pathops/SkPathOpsTCurve.h
new file mode 100644
index 0000000..4981dea
--- /dev/null
+++ b/src/pathops/SkPathOpsTCurve.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkPathOpsTCurve_DEFINED
+#define SkPathOpsTCurve_DEFINED
+
+#include "SkPathOpsPoint.h"
+
+class SkArenaAlloc;
+class SkIntersections;
+
+class SkTCurve {
+public:
+    virtual ~SkTCurve() {}
+    virtual const SkDPoint& operator[](int n) const = 0;
+    virtual SkDPoint& operator[](int n) = 0;
+
+    virtual bool collapsed() const = 0;
+    virtual bool controlsInside() const = 0;
+    virtual void debugInit() = 0;
+    virtual SkDVector dxdyAtT(double t) const = 0;
+    virtual bool hullIntersects(const SkDQuad& , bool* isLinear) const = 0;
+    virtual bool hullIntersects(const SkDConic& , bool* isLinear) const = 0;
+    virtual bool hullIntersects(const SkDCubic& , bool* isLinear) const = 0;
+    virtual bool hullIntersects(const SkTCurve& , bool* isLinear) const = 0;
+    virtual int intersectRay(SkIntersections* i, const SkDLine& line) const = 0;
+    virtual bool IsConic() const = 0;
+    virtual SkTCurve* make(SkArenaAlloc& ) const = 0;
+    virtual int maxIntersections() const = 0;
+    virtual void otherPts(int oddMan, const SkDPoint* endPt[2]) const = 0;
+    virtual int pointCount() const = 0;
+    virtual int pointLast() const = 0;
+    virtual SkDPoint ptAtT(double t) const = 0;
+    virtual void setBounds(SkDRect* ) const = 0;
+    virtual void subDivide(double t1, double t2, SkTCurve* curve) const = 0;
+#ifdef SK_DEBUG
+    virtual SkOpGlobalState* globalState() const = 0;
+#endif
+};
+
+#endif
diff --git a/src/pathops/SkPathOpsTSect.cpp b/src/pathops/SkPathOpsTSect.cpp
index e096837..e765c21 100644
--- a/src/pathops/SkPathOpsTSect.cpp
+++ b/src/pathops/SkPathOpsTSect.cpp
@@ -7,6 +7,77 @@
 
 #include "SkPathOpsTSect.h"
 
+#if PATH_OP_COMPILE_FOR_SIZE
+
+int SkIntersections::intersect(const SkDQuad& q1, const SkDQuad& q2) {
+    SkTQuad quad1(q1);
+    SkTQuad quad2(q2);
+    SkTSect<SkTCurve, SkTCurve> sect1(quad1
+        SkDEBUGPARAMS(globalState())  PATH_OPS_DEBUG_T_SECT_PARAMS(1));
+    SkTSect<SkTCurve, SkTCurve> sect2(quad2
+        SkDEBUGPARAMS(globalState())  PATH_OPS_DEBUG_T_SECT_PARAMS(2));
+    SkTSect<SkTCurve, SkTCurve>::BinarySearch(&sect1, &sect2, this);
+    return used();
+}
+
+int SkIntersections::intersect(const SkDConic& c, const SkDQuad& q) {
+    SkTConic conic(c);
+    SkTQuad quad(q);
+    SkTSect<SkTCurve, SkTCurve> sect1(conic
+        SkDEBUGPARAMS(globalState())  PATH_OPS_DEBUG_T_SECT_PARAMS(1));
+    SkTSect<SkTCurve, SkTCurve> sect2(quad
+        SkDEBUGPARAMS(globalState())  PATH_OPS_DEBUG_T_SECT_PARAMS(2));
+    SkTSect<SkTCurve, SkTCurve>::BinarySearch(&sect1, &sect2, this);
+    return used();
+}
+
+int SkIntersections::intersect(const SkDConic& c1, const SkDConic& c2) {
+    SkTConic conic1(c1);
+    SkTConic conic2(c2);
+    SkTSect<SkTCurve, SkTCurve> sect1(conic1
+        SkDEBUGPARAMS(globalState())  PATH_OPS_DEBUG_T_SECT_PARAMS(1));
+    SkTSect<SkTCurve, SkTCurve> sect2(conic2
+        SkDEBUGPARAMS(globalState())  PATH_OPS_DEBUG_T_SECT_PARAMS(2));
+    SkTSect<SkTCurve, SkTCurve>::BinarySearch(&sect1, &sect2, this);
+    return used();
+}
+
+int SkIntersections::intersect(const SkDCubic& c, const SkDQuad& q) {
+    SkTCubic cubic(c);
+    SkTQuad quad(q);
+    SkTSect<SkTCurve, SkTCurve> sect1(cubic
+        SkDEBUGPARAMS(globalState())  PATH_OPS_DEBUG_T_SECT_PARAMS(1));
+    SkTSect<SkTCurve, SkTCurve> sect2(quad
+        SkDEBUGPARAMS(globalState())  PATH_OPS_DEBUG_T_SECT_PARAMS(2));
+    SkTSect<SkTCurve, SkTCurve>::BinarySearch(&sect1, &sect2, this);
+    return used();
+}
+
+int SkIntersections::intersect(const SkDCubic& cu, const SkDConic& co) {
+    SkTCubic cubic(cu);
+    SkTConic conic(co);
+    SkTSect<SkTCurve, SkTCurve> sect1(cubic
+        SkDEBUGPARAMS(globalState())  PATH_OPS_DEBUG_T_SECT_PARAMS(1));
+    SkTSect<SkTCurve, SkTCurve> sect2(conic
+        SkDEBUGPARAMS(globalState())  PATH_OPS_DEBUG_T_SECT_PARAMS(2));
+    SkTSect<SkTCurve, SkTCurve>::BinarySearch(&sect1, &sect2, this);
+    return used();
+
+}
+
+int SkIntersections::intersect(const SkDCubic& c1, const SkDCubic& c2) {
+    SkTCubic cubic1(c1);
+    SkTCubic cubic2(c2);
+    SkTSect<SkTCurve, SkTCurve> sect1(cubic1
+        SkDEBUGPARAMS(globalState())  PATH_OPS_DEBUG_T_SECT_PARAMS(1));
+    SkTSect<SkTCurve, SkTCurve> sect2(cubic2
+        SkDEBUGPARAMS(globalState())  PATH_OPS_DEBUG_T_SECT_PARAMS(2));
+    SkTSect<SkTCurve, SkTCurve>::BinarySearch(&sect1, &sect2, this);
+    return used();
+}
+
+#else
+
 int SkIntersections::intersect(const SkDQuad& quad1, const SkDQuad& quad2) {
     SkTSect<SkDQuad, SkDQuad> sect1(quad1
         SkDEBUGPARAMS(globalState())  PATH_OPS_DEBUG_T_SECT_PARAMS(1));
@@ -60,3 +131,6 @@
     SkTSect<SkDCubic, SkDCubic>::BinarySearch(&sect1, &sect2, this);
     return used();
 }
+
+#endif
+
diff --git a/src/pathops/SkPathOpsTSect.h b/src/pathops/SkPathOpsTSect.h
index c9b51a2..1bf4f7f 100644
--- a/src/pathops/SkPathOpsTSect.h
+++ b/src/pathops/SkPathOpsTSect.h
@@ -92,17 +92,25 @@
 template<typename TCurve, typename OppCurve>
 class SkTSpan {
 public:
+    SkTSpan(const TCurve& curve, SkArenaAlloc& heap) {
+#if PATH_OP_COMPILE_FOR_SIZE
+        fPart = curve.make(heap);
+#endif
+    }
+
     void addBounded(SkTSpan<OppCurve, TCurve>* , SkArenaAlloc* );
     double closestBoundedT(const SkDPoint& pt) const;
     bool contains(double t) const;
 
     void debugInit() {
+#if !PATH_OP_COMPILE_FOR_SIZE
         TCurve dummy;
         dummy.debugInit();
         init(dummy);
         initBounds(dummy);
         fCoinStart.init();
         fCoinEnd.init();
+#endif
     }
 
     const SkTSect<OppCurve, TCurve>* debugOpp() const;
@@ -165,8 +173,20 @@
     bool onlyEndPointsInCommon(const SkTSpan<OppCurve, TCurve>* opp, bool* start,
             bool* oppStart, bool* ptsInCommon);
 
-    const TCurve& part() const {
+    TCurve& part() {
+#if PATH_OP_COMPILE_FOR_SIZE
+        return *fPart;
+#else
         return fPart;
+#endif
+    }
+
+    const TCurve& part() const {
+#if PATH_OP_COMPILE_FOR_SIZE
+        return *fPart;
+#else
+        return fPart;
+#endif
     }
 
     bool removeAllBounded();
@@ -209,7 +229,11 @@
     void validatePerpT(double oppT) const;
     void validatePerpPt(double t, const SkDPoint& ) const;
 
+#if PATH_OP_COMPILE_FOR_SIZE
+    TCurve* fPart;
+#else
     TCurve fPart;
+#endif
     SkTCoincident<TCurve, OppCurve> fCoinStart;
     SkTCoincident<TCurve, OppCurve> fCoinEnd;
     SkTSpanBounded<OppCurve, TCurve>* fBounded;
@@ -460,12 +484,12 @@
     const SkTSpanBounded<OppCurve, TCurve>* testBounded = fBounded;
     while (testBounded) {
         const SkTSpan<OppCurve, TCurve>* test = testBounded->fBounded;
-        double startDist = test->fPart[0].distanceSquared(pt);
+        double startDist = test->part()[0].distanceSquared(pt);
         if (closest > startDist) {
             closest = startDist;
             result = test->fStartT;
         }
-        double endDist = test->fPart[OppCurve::kPointLast].distanceSquared(pt);
+        double endDist = test->part()[test->part().pointLast()].distanceSquared(pt);
         if (closest > endDist) {
             closest = endDist;
             result = test->fEndT;
@@ -535,12 +559,12 @@
         return 2;
     }
     bool linear;
-    if (fPart.hullIntersects(opp->fPart, &linear)) {
+    if (part().hullIntersects(opp->part(), &linear)) {
         if (!linear) {  // check set true if linear
             return 1;
         }
         fIsLinear = true;
-        fIsLine = fPart.controlsInside();
+        fIsLine = part().controlsInside();
         return ptsInCommon ? 1 : -1;
     } else {  // hull is not linear; check set true if intersected at the end points
         return ((int) ptsInCommon) << 1;  // 0 or 2
@@ -582,12 +606,12 @@
     if (SkDoubleIsNaN(fStartT) || SkDoubleIsNaN(fEndT)) {
         return false;
     }
-    fPart = c.subDivide(fStartT, fEndT);
-    fBounds.setBounds(fPart);
+    c.subDivide(fStartT, fEndT, &part());
+    fBounds.setBounds(part());
     fCoinStart.init();
     fCoinEnd.init();
     fBoundsMax = SkTMax(fBounds.width(), fBounds.height());
-    fCollapsed = fPart.collapsed();
+    fCollapsed = part().collapsed();
     fHasPerp = false;
     fDeleted = false;
 #if DEBUG_T_SECT
@@ -600,33 +624,33 @@
 
 template<typename TCurve, typename OppCurve>
 bool SkTSpan<TCurve, OppCurve>::linearsIntersect(SkTSpan<OppCurve, TCurve>* span) {
-    int result = this->linearIntersects(span->fPart);
+    int result = this->linearIntersects(span->part());
     if (result <= 1) {
         return SkToBool(result);
     }
     SkASSERT(span->fIsLinear);
-    result = span->linearIntersects(this->fPart);
+    result = span->linearIntersects(this->part());
 //    SkASSERT(result <= 1);
     return SkToBool(result);
 }
 
 template<typename TCurve, typename OppCurve>
 double SkTSpan<TCurve, OppCurve>::linearT(const SkDPoint& pt) const {
-    SkDVector len = fPart[TCurve::kPointLast] - fPart[0];
+    SkDVector len = part()[part().pointLast()] - part()[0];
     return fabs(len.fX) > fabs(len.fY)
-            ? (pt.fX - fPart[0].fX) / len.fX
-            : (pt.fY - fPart[0].fY) / len.fY;
+            ? (pt.fX - part()[0].fX) / len.fX
+            : (pt.fY - part()[0].fY) / len.fY;
 }
 
 template<typename TCurve, typename OppCurve>
 int SkTSpan<TCurve, OppCurve>::linearIntersects(const OppCurve& q2) const {
     // looks like q1 is near-linear
-    int start = 0, end = TCurve::kPointLast;  // the outside points are usually the extremes
-    if (!fPart.controlsInside()) {
+    int start = 0, end = part().pointLast();  // the outside points are usually the extremes
+    if (!part().controlsInside()) {
         double dist = 0;  // if there's any question, compute distance to find best outsiders
-        for (int outer = 0; outer < TCurve::kPointCount - 1; ++outer) {
-            for (int inner = outer + 1; inner < TCurve::kPointCount; ++inner) {
-                double test = (fPart[outer] - fPart[inner]).lengthSquared();
+        for (int outer = 0; outer < part().pointCount() - 1; ++outer) {
+            for (int inner = outer + 1; inner < part().pointCount(); ++inner) {
+                double test = (part()[outer] - part()[inner]).lengthSquared();
                 if (dist > test) {
                     continue;
                 }
@@ -637,13 +661,13 @@
         }
     }
     // see if q2 is on one side of the line formed by the extreme points
-    double origX = fPart[start].fX;
-    double origY = fPart[start].fY;
-    double adj = fPart[end].fX - origX;
-    double opp = fPart[end].fY - origY;
+    double origX = part()[start].fX;
+    double origY = part()[start].fY;
+    double adj = part()[end].fX - origX;
+    double opp = part()[end].fY - origY;
     double maxPart = SkTMax(fabs(adj), fabs(opp));
     double sign = 0;  // initialization to shut up warning in release build
-    for (int n = 0; n < OppCurve::kPointCount; ++n) {
+    for (int n = 0; n < q2.pointCount(); ++n) {
         double dx = q2[n].fY - origY;
         double dy = q2[n].fX - origX;
         double maxVal = SkTMax(maxPart, SkTMax(fabs(dx), fabs(dy)));
@@ -668,29 +692,30 @@
 template<typename TCurve, typename OppCurve>
 bool SkTSpan<TCurve, OppCurve>::onlyEndPointsInCommon(const SkTSpan<OppCurve, TCurve>* opp,
         bool* start, bool* oppStart, bool* ptsInCommon) {
-    if (opp->fPart[0] == fPart[0]) {
+    if (opp->part()[0] == part()[0]) {
         *start = *oppStart = true;
-    } else if (opp->fPart[0] == fPart[TCurve::kPointLast]) {
+    } else if (opp->part()[0] == part()[part().pointLast()]) {
         *start = false;
         *oppStart = true;
-    } else if (opp->fPart[OppCurve::kPointLast] == fPart[0]) {
+    } else if (opp->part()[opp->part().pointLast()] == part()[0]) {
         *start = true;
         *oppStart = false;
-    } else if (opp->fPart[OppCurve::kPointLast] == fPart[TCurve::kPointLast]) {
+    } else if (opp->part()[opp->part().pointLast()] == part()[part().pointLast()]) {
         *start = *oppStart = false;
     } else {
         *ptsInCommon = false;
         return false;
     }
     *ptsInCommon = true;
-    const SkDPoint* otherPts[TCurve::kPointCount - 1], * oppOtherPts[OppCurve::kPointCount - 1];
-    int baseIndex = *start ? 0 : TCurve::kPointLast;
-    fPart.otherPts(baseIndex, otherPts);
-    opp->fPart.otherPts(*oppStart ? 0 : OppCurve::kPointLast, oppOtherPts);
-    const SkDPoint& base = fPart[baseIndex];
-    for (int o1 = 0; o1 < (int) SK_ARRAY_COUNT(otherPts); ++o1) {
+    const SkDPoint* otherPts[4], * oppOtherPts[4];
+//    const SkDPoint* otherPts[part().pointCount() - 1], * oppOtherPts[opp->part().pointCount() - 1];
+    int baseIndex = *start ? 0 : part().pointLast();
+    part().otherPts(baseIndex, otherPts);
+    opp->part().otherPts(*oppStart ? 0 : opp->part().pointLast(), oppOtherPts);
+    const SkDPoint& base = part()[baseIndex];
+    for (int o1 = 0; o1 < part().pointCount() - 1; ++o1) {
         SkDVector v1 = *otherPts[o1] - base;
-        for (int o2 = 0; o2 < (int) SK_ARRAY_COUNT(oppOtherPts); ++o2) {
+        for (int o2 = 0; o2 < opp->part().pointCount() - 1; ++o2) {
             SkDVector v2 = *oppOtherPts[o2] - base;
             if (v2.dot(v1) >= 0) {
                 return false;
@@ -895,7 +920,7 @@
         result = fDeleted;
         fDeleted = result->fNext;
     } else {
-        result = fHeap.make<SkTSpan<TCurve, OppCurve>>();
+        result = fHeap.make<SkTSpan<TCurve, OppCurve>>(fCurve, fHeap);
 #if DEBUG_T_SECT
         ++fDebugAllocatedCount;
 #endif
@@ -907,7 +932,9 @@
     PATH_OPS_DEBUG_T_SECT_CODE(result->fID = fDebugCount++ * 2 + fID);
     SkDEBUGCODE(result->fDebugSect = this);
 #ifdef SK_DEBUG
-    result->fPart.debugInit();
+#if !PATH_OP_COMPILE_FOR_SIZE
+    result->debugInit();
+#endif
     result->fCoinStart.debugInit();
     result->fCoinEnd.debugInit();
     result->fPrev = result->fNext = nullptr;
@@ -921,7 +948,7 @@
 template<typename TCurve, typename OppCurve>
 bool SkTSect<TCurve, OppCurve>::binarySearchCoin(SkTSect<OppCurve, TCurve>* sect2, double tStart,
         double tStep, double* resultT, double* oppT, SkTSpan<OppCurve, TCurve>** oppFirst) {
-    SkTSpan<TCurve, OppCurve> work;
+    SkTSpan<TCurve, OppCurve> work(fCurve, fHeap);
     double result = work.fStartT = work.fEndT = tStart;
     SkDEBUGCODE(work.fDebugSect = this);
     SkDPoint last = fCurve.ptAtT(tStart);
@@ -941,10 +968,10 @@
         if (work.fCollapsed) {
             return false;
         }
-        if (last.approximatelyEqual(work.fPart[0])) {
+        if (last.approximatelyEqual(work.part()[0])) {
             break;
         }
-        last = work.fPart[0];
+        last = work.part()[0];
         work.fCoinStart.setPerp(fCurve, work.fStartT, last, opp);
         if (work.fCoinStart.isMatch()) {
 #if DEBUG_T_SECT
@@ -971,12 +998,12 @@
     }
     if (last.approximatelyEqual(fCurve[0])) {
         result = 0;
-    } else if (last.approximatelyEqual(fCurve[TCurve::kPointLast])) {
+    } else if (last.approximatelyEqual(fCurve[fCurve.pointLast()])) {
         result = 1;
     }
     if (oppPt.approximatelyEqual(opp[0])) {
         *oppT = 0;
-    } else if (oppPt.approximatelyEqual(opp[OppCurve::kPointLast])) {
+    } else if (oppPt.approximatelyEqual(opp[sect2->fCurve.pointLast()])) {
         *oppT = 1;
     }
     *resultT = result;
@@ -1058,7 +1085,7 @@
     first->fEndT = start1e;
     first->resetBounds(fCurve);
     first->fCoinStart.setPerp(fCurve, start1s, fCurve[0], sect2->fCurve);
-    first->fCoinEnd.setPerp(fCurve, start1e, fCurve[TCurve::kPointLast], sect2->fCurve);
+    first->fCoinEnd.setPerp(fCurve, start1e, fCurve[fCurve.pointLast()], sect2->fCurve);
     bool oppMatched = first->fCoinStart.perpT() < first->fCoinEnd.perpT();
     double oppStartT = first->fCoinStart.perpT() == -1 ? 0 : SkTMax(0., first->fCoinStart.perpT());
     double oppEndT = first->fCoinEnd.perpT() == -1 ? 1 : SkTMin(1., first->fCoinEnd.perpT());
@@ -1113,7 +1140,7 @@
             if (prior) {
                 work->fCoinStart = prior->fCoinEnd;
             } else {
-                work->fCoinStart.setPerp(fCurve, work->fStartT, work->fPart[0], opp);
+                work->fCoinStart.setPerp(fCurve, work->fStartT, work->part()[0], opp);
             }
             if (work->fCoinStart.isMatch()) {
                 double perpT = work->fCoinStart.perpT();
@@ -1123,7 +1150,7 @@
                     sect2->addForPerp(work, perpT);
                 }
             }
-            work->fCoinEnd.setPerp(fCurve, work->fEndT, work->fPart[TCurve::kPointLast], opp);
+            work->fCoinEnd.setPerp(fCurve, work->fEndT, work->part()[fCurve.pointLast()], opp);
             if (work->fCoinEnd.isMatch()) {
                 double perpT = work->fCoinEnd.perpT();
                 if (sect2->coincidentHasT(perpT)) {
@@ -1282,8 +1309,8 @@
     sect2->removeSpanRange(oppFirst, oppLast);
     first->fEndT = last->fEndT;
     first->resetBounds(this->fCurve);
-    first->fCoinStart.setPerp(fCurve, first->fStartT, first->fPart[0], sect2->fCurve);
-    first->fCoinEnd.setPerp(fCurve, first->fEndT, first->fPart[TCurve::kPointLast], sect2->fCurve);
+    first->fCoinStart.setPerp(fCurve, first->fStartT, first->part()[0], sect2->fCurve);
+    first->fCoinEnd.setPerp(fCurve, first->fEndT, first->part()[fCurve.pointLast()], sect2->fCurve);
     oppStartT = first->fCoinStart.perpT();
     oppEndT = first->fCoinEnd.perpT();
     if (between(0, oppStartT, 1) && between(0, oppEndT, 1)) {
@@ -1447,8 +1474,8 @@
         SkTSpan<OppCurve, TCurve>* oppSpan, SkIntersections* i) {
     SkIntersections thisRayI  SkDEBUGCODE((span->fDebugGlobalState));
     SkIntersections oppRayI  SkDEBUGCODE((span->fDebugGlobalState));
-    SkDLine thisLine = {{ span->fPart[0], span->fPart[TCurve::kPointLast] }};
-    SkDLine oppLine = {{ oppSpan->fPart[0], oppSpan->fPart[OppCurve::kPointLast] }};
+    SkDLine thisLine = {{ span->part()[0], span->part()[fCurve.pointLast()] }};
+    SkDLine oppLine = {{ oppSpan->part()[0], oppSpan->part()[opp->fCurve.pointLast()] }};
     int loopCount = 0;
     double bestDistSq = DBL_MAX;
     if (!thisRayI.intersectRay(opp->fCurve, thisLine)) {
@@ -1532,8 +1559,8 @@
     } while (true);
     // convergence may fail if the curves are nearly coincident
     SkTCoincident<OppCurve, TCurve> oCoinS, oCoinE;
-    oCoinS.setPerp(opp->fCurve, oppSpan->fStartT, oppSpan->fPart[0], fCurve);
-    oCoinE.setPerp(opp->fCurve, oppSpan->fEndT, oppSpan->fPart[OppCurve::kPointLast], fCurve);
+    oCoinS.setPerp(opp->fCurve, oppSpan->fStartT, oppSpan->part()[0], fCurve);
+    oCoinE.setPerp(opp->fCurve, oppSpan->fEndT, oppSpan->part()[opp->fCurve.pointLast()], fCurve);
     double tStart = oCoinS.perpT();
     double tEnd = oCoinE.perpT();
     bool swap = tStart > tEnd;
@@ -1549,21 +1576,21 @@
     SkDVector perpS, perpE;
     if (tStart == span->fStartT) {
         SkTCoincident<TCurve, OppCurve> coinS;
-        coinS.setPerp(fCurve, span->fStartT, span->fPart[0], opp->fCurve);
-        perpS = span->fPart[0] - coinS.perpPt();
+        coinS.setPerp(fCurve, span->fStartT, span->part()[0], opp->fCurve);
+        perpS = span->part()[0] - coinS.perpPt();
     } else if (swap) {
-        perpS = oCoinE.perpPt() - oppSpan->fPart[OppCurve::kPointLast];
+        perpS = oCoinE.perpPt() - oppSpan->part()[opp->fCurve.pointLast()];
     } else {
-        perpS = oCoinS.perpPt() - oppSpan->fPart[0];
+        perpS = oCoinS.perpPt() - oppSpan->part()[0];
     }
     if (tEnd == span->fEndT) {
         SkTCoincident<TCurve, OppCurve> coinE;
-        coinE.setPerp(fCurve, span->fEndT, span->fPart[TCurve::kPointLast], opp->fCurve);
-        perpE = span->fPart[TCurve::kPointLast] - coinE.perpPt();
+        coinE.setPerp(fCurve, span->fEndT, span->part()[fCurve.pointLast()], opp->fCurve);
+        perpE = span->part()[fCurve.pointLast()] - coinE.perpPt();
     } else if (swap) {
-        perpE = oCoinS.perpPt() - oppSpan->fPart[0];
+        perpE = oCoinS.perpPt() - oppSpan->part()[0];
     } else {
-        perpE = oCoinE.perpPt() - oppSpan->fPart[OppCurve::kPointLast];
+        perpE = oCoinE.perpPt() - oppSpan->part()[opp->fCurve.pointLast()];
     }
     if (perpS.dot(perpE) >= 0) {
         return 0;
@@ -1753,8 +1780,8 @@
         if (test->fCoinStart.perpT() < 0 || test->fCoinEnd.perpT() < 0) {
             continue;
         }
-        SkDVector startV = test->fCoinStart.perpPt() - test->fPart[0];
-        SkDVector endV = test->fCoinEnd.perpPt() - test->fPart[TCurve::kPointLast];
+        SkDVector startV = test->fCoinStart.perpPt() - test->part()[0];
+        SkDVector endV = test->fCoinEnd.perpPt() - test->part()[fCurve.pointLast()];
 #if DEBUG_T_SECT
         SkDebugf("%s startV=(%1.9g,%1.9g) endV=(%1.9g,%1.9g) dot=%1.9g\n", __FUNCTION__,
                 startV.fX, startV.fY, endV.fX, endV.fY, startV.dot(endV));
@@ -2002,17 +2029,17 @@
         zeroOneSet |= kZeroS1Set | kZeroS2Set;
         intersections->insert(0, 0, sect1->fCurve[0]);
     }
-    if (sect1->fCurve[0] == sect2->fCurve[OppCurve::kPointLast]) {
+    if (sect1->fCurve[0] == sect2->fCurve[sect2->fCurve.pointLast()]) {
         zeroOneSet |= kZeroS1Set | kOneS2Set;
         intersections->insert(0, 1, sect1->fCurve[0]);
     }
-    if (sect1->fCurve[TCurve::kPointLast] == sect2->fCurve[0]) {
+    if (sect1->fCurve[sect1->fCurve.pointLast()] == sect2->fCurve[0]) {
         zeroOneSet |= kOneS1Set | kZeroS2Set;
-        intersections->insert(1, 0, sect1->fCurve[TCurve::kPointLast]);
+        intersections->insert(1, 0, sect1->fCurve[sect1->fCurve.pointLast()]);
     }
-    if (sect1->fCurve[TCurve::kPointLast] == sect2->fCurve[OppCurve::kPointLast]) {
+    if (sect1->fCurve[sect1->fCurve.pointLast()] == sect2->fCurve[sect2->fCurve.pointLast()]) {
         zeroOneSet |= kOneS1Set | kOneS2Set;
-            intersections->insert(1, 1, sect1->fCurve[TCurve::kPointLast]);
+            intersections->insert(1, 1, sect1->fCurve[sect1->fCurve.pointLast()]);
     }
     // check for zero
     if (!(zeroOneSet & (kZeroS1Set | kZeroS2Set))
@@ -2021,22 +2048,22 @@
         intersections->insertNear(0, 0, sect1->fCurve[0], sect2->fCurve[0]);
     }
     if (!(zeroOneSet & (kZeroS1Set | kOneS2Set))
-            && sect1->fCurve[0].approximatelyEqual(sect2->fCurve[OppCurve::kPointLast])) {
+            && sect1->fCurve[0].approximatelyEqual(sect2->fCurve[sect2->fCurve.pointLast()])) {
         zeroOneSet |= kZeroS1Set | kOneS2Set;
-        intersections->insertNear(0, 1, sect1->fCurve[0], sect2->fCurve[OppCurve::kPointLast]);
+        intersections->insertNear(0, 1, sect1->fCurve[0], sect2->fCurve[sect2->fCurve.pointLast()]);
     }
     // check for one
     if (!(zeroOneSet & (kOneS1Set | kZeroS2Set))
-            && sect1->fCurve[TCurve::kPointLast].approximatelyEqual(sect2->fCurve[0])) {
+            && sect1->fCurve[sect1->fCurve.pointLast()].approximatelyEqual(sect2->fCurve[0])) {
         zeroOneSet |= kOneS1Set | kZeroS2Set;
-        intersections->insertNear(1, 0, sect1->fCurve[TCurve::kPointLast], sect2->fCurve[0]);
+        intersections->insertNear(1, 0, sect1->fCurve[sect1->fCurve.pointLast()], sect2->fCurve[0]);
     }
     if (!(zeroOneSet & (kOneS1Set | kOneS2Set))
-            && sect1->fCurve[TCurve::kPointLast].approximatelyEqual(sect2->fCurve[
-            OppCurve::kPointLast])) {
+            && sect1->fCurve[sect1->fCurve.pointLast()].approximatelyEqual(sect2->fCurve[
+            sect2->fCurve.pointLast()])) {
         zeroOneSet |= kOneS1Set | kOneS2Set;
-        intersections->insertNear(1, 1, sect1->fCurve[TCurve::kPointLast],
-                sect2->fCurve[OppCurve::kPointLast]);
+        intersections->insertNear(1, 1, sect1->fCurve[sect1->fCurve.pointLast()],
+                sect2->fCurve[sect2->fCurve.pointLast()]);
     }
     return zeroOneSet;
 }
@@ -2131,9 +2158,9 @@
             SkDEBUGPARAMS(SkIntersections* i)) {
         SkClosestRecord<TCurve, OppCurve>* record = &fClosest[fUsed];
         record->findEnd(span1, span2, 0, 0);
-        record->findEnd(span1, span2, 0, OppCurve::kPointLast);
-        record->findEnd(span1, span2, TCurve::kPointLast, 0);
-        record->findEnd(span1, span2, TCurve::kPointLast, OppCurve::kPointLast);
+        record->findEnd(span1, span2, 0, span2->part().pointLast());
+        record->findEnd(span1, span2, span1->part().pointLast(), 0);
+        record->findEnd(span1, span2, span1->part().pointLast(), span2->part().pointLast());
         if (record->fClosest == FLT_MAX) {
             return false;
         }
@@ -2154,7 +2181,7 @@
     }
 
     void finish(SkIntersections* intersections) const {
-        SkSTArray<TCurve::kMaxIntersections * 3,
+        SkSTArray<SkDCubic::kMaxIntersections * 3,
                 const SkClosestRecord<TCurve, OppCurve>*, true> closestPtrs;
         for (int index = 0; index < fUsed; ++index) {
             closestPtrs.push_back(&fClosest[index]);
@@ -2168,7 +2195,7 @@
     }
 
     // this is oversized so that an extra records can merge into final one
-    SkSTArray<TCurve::kMaxIntersections * 2, SkClosestRecord<TCurve, OppCurve>, true> fClosest;
+    SkSTArray<SkDCubic::kMaxIntersections * 2, SkClosestRecord<TCurve, OppCurve>, true> fClosest;
     int fUsed;
 };
 
@@ -2182,7 +2209,7 @@
     SkDEBUGCODE(sect1->fOppSect = sect2);
     SkDEBUGCODE(sect2->fOppSect = sect1);
     intersections->reset();
-    intersections->setMax(TCurve::kMaxIntersections + 4);  // give extra for slop
+    intersections->setMax(sect1->fCurve.maxIntersections() + 4);  // give extra for slop
     SkTSpan<TCurve, OppCurve>* span1 = sect1->fHead;
     SkTSpan<OppCurve, TCurve>* span2 = sect2->fHead;
     int oppSect, sect = sect1->intersects(span1, sect2, span2, &oppSect);
@@ -2305,7 +2332,7 @@
 #if DEBUG_T_SECT_LOOP_COUNT
             intersections->debugBumpLoopCount(SkIntersections::kComputePerp_DebugLoop);
 #endif
-            if (sect1->collapsed() > TCurve::kMaxIntersections) {
+            if (sect1->collapsed() > sect1->fCurve.maxIntersections()) {
                 break;
             }
         }
@@ -2339,10 +2366,10 @@
                 return;
             }
             int index = intersections->insertCoincident(coincident->fStartT,
-                    perpT, coincident->fPart[0]);
+                    perpT, coincident->part()[0]);
             if ((intersections->insertCoincident(coincident->fEndT,
                     coincident->fCoinEnd.perpT(),
-                    coincident->fPart[TCurve::kPointLast]) < 0) && index >= 0) {
+                    coincident->part()[coincident->part().pointLast()]) < 0) && index >= 0) {
                 intersections->clearCoincidence(index);
             }
         } while ((coincident = coincident->fNext));
@@ -2359,7 +2386,7 @@
         }
         if (sect1->fRemovedEndT && !(zeroOneSet & kOneS1Set)) {
             SkTCoincident<TCurve, OppCurve> perp;
-            perp.setPerp(sect1->fCurve, 1, sect1->fCurve[TCurve::kPointLast], sect2->fCurve);
+            perp.setPerp(sect1->fCurve, 1, sect1->fCurve[sect1->fCurve.pointLast()], sect2->fCurve);
             if (perp.isMatch()) {
                 intersections->insert(1, perp.perpT(), perp.perpPt());
             }
@@ -2373,7 +2400,7 @@
         }
         if (sect2->fRemovedEndT && !(zeroOneSet & kOneS2Set)) {
             SkTCoincident<OppCurve, TCurve> perp;
-            perp.setPerp(sect2->fCurve, 1, sect2->fCurve[OppCurve::kPointLast], sect1->fCurve);
+            perp.setPerp(sect2->fCurve, 1, sect2->fCurve[sect2->fCurve.pointLast()], sect1->fCurve);
             if (perp.isMatch()) {
                 intersections->insert(perp.perpT(), 1, perp.perpPt());
             }
@@ -2408,7 +2435,7 @@
     }
     const SkTSpan<TCurve, OppCurve>* tail1 = sect1->tail();
     if (!(zeroOneSet & kOneS1Set) && approximately_greater_than_one(tail1->fEndT)) {
-        const SkDPoint& end1 = sect1->fCurve[TCurve::kPointLast];
+        const SkDPoint& end1 = sect1->fCurve[sect1->fCurve.pointLast()];
         if (tail1->isBounded()) {
             double t = tail1->closestBoundedT(end1);
             if (sect2->fCurve.ptAtT(t).approximatelyEqual(end1)) {
@@ -2418,7 +2445,7 @@
     }
     const SkTSpan<OppCurve, TCurve>* tail2 = sect2->tail();
     if (!(zeroOneSet & kOneS2Set) && approximately_greater_than_one(tail2->fEndT)) {
-        const SkDPoint& end2 = sect2->fCurve[OppCurve::kPointLast];
+        const SkDPoint& end2 = sect2->fCurve[sect2->fCurve.pointLast()];
         if (tail2->isBounded()) {
             double t = tail2->closestBoundedT(end2);
             if (sect1->fCurve.ptAtT(t).approximatelyEqual(end2)) {
@@ -2469,7 +2496,7 @@
         }
         intersections->setCoincident(index);
     }
-    SkOPOBJASSERT(intersections, intersections->used() <= TCurve::kMaxIntersections);
+    SkOPOBJASSERT(intersections, intersections->used() <= sect1->fCurve.maxIntersections());
 }
 
 #endif
diff --git a/src/pathops/SkPathOpsTypes.h b/src/pathops/SkPathOpsTypes.h
index 2fef826..7e4be6f 100644
--- a/src/pathops/SkPathOpsTypes.h
+++ b/src/pathops/SkPathOpsTypes.h
@@ -16,6 +16,8 @@
 #include "SkSafe_math.h"  // for fabs, sqrt
 #include "SkScalar.h"
 
+#define PATH_OP_COMPILE_FOR_SIZE 1
+
 enum SkPathOpsMask {
     kWinding_PathOpsMask = -1,
     kNo_PathOpsMask = 0,
diff --git a/tests/PathOpsDebug.cpp b/tests/PathOpsDebug.cpp
index 41f912e..9535f3c 100644
--- a/tests/PathOpsDebug.cpp
+++ b/tests/PathOpsDebug.cpp
@@ -423,6 +423,7 @@
 
 void DontCallDebugSpan(int id);
 void DontCallDebugSpan(int id) {  // exists to instantiate the templates
+#if !PATH_OP_COMPILE_FOR_SIZE
     SkDQuad quad;
     SkDConic conic;
     SkDCubic cubic;
@@ -444,6 +445,7 @@
     DebugSpan(&c1q2, id);
     DebugSpan(&c1k2, id);
     DebugSpan(&c1c2, id);
+#endif
 }
 
 template <typename TCurve, typename OppCurve>
@@ -453,6 +455,7 @@
 
 void DontCallDebugT(double t);
 void DontCallDebugT(double t) {  // exists to instantiate the templates
+#if !PATH_OP_COMPILE_FOR_SIZE
     SkDQuad quad;
     SkDConic conic;
     SkDCubic cubic;
@@ -474,6 +477,7 @@
     DebugT(&c1q2, t);
     DebugT(&c1k2, t);
     DebugT(&c1c2, t);
+#endif
 }
 
 template <typename TCurve, typename OppCurve>
@@ -483,6 +487,7 @@
 
 void DontCallDumpTSect();
 void DontCallDumpTSect() {  // exists to instantiate the templates
+#if !PATH_OP_COMPILE_FOR_SIZE
     SkDQuad quad;
     SkDConic conic;
     SkDCubic cubic;
@@ -504,6 +509,7 @@
     Dump(&c1q2);
     Dump(&c1k2);
     Dump(&c1c2);
+#endif
 }
 
 template <typename TCurve, typename OppCurve>
@@ -513,6 +519,7 @@
 
 void DontCallDumpBoth();
 void DontCallDumpBoth() {  // exists to instantiate the templates
+#if !PATH_OP_COMPILE_FOR_SIZE
     SkDQuad quad;
     SkDConic conic;
     SkDCubic cubic;
@@ -534,6 +541,7 @@
     DumpBoth(&c1q2, &q1c2);
     DumpBoth(&c1k2, &k1c2);
     DumpBoth(&c1c2, &c1c2);
+#endif
 }
 
 template <typename TCurve, typename OppCurve>
@@ -543,6 +551,7 @@
 
 void DontCallDumpBounded();
 void DontCallDumpBounded() {
+#if !PATH_OP_COMPILE_FOR_SIZE
     SkDQuad quad;
     SkDConic conic;
     SkDCubic cubic;
@@ -564,6 +573,7 @@
     DumpBounded(&c1q2, 0);
     DumpBounded(&c1k2, 0);
     DumpBounded(&c1c2, 0);
+#endif
 }
 
 template <typename TCurve, typename OppCurve>
@@ -573,6 +583,7 @@
 
 void DontCallDumpBounds();
 void DontCallDumpBounds() {
+#if !PATH_OP_COMPILE_FOR_SIZE
     SkDQuad quad;
     SkDConic conic;
     SkDCubic cubic;
@@ -594,6 +605,7 @@
     DumpBounds(&c1q2);
     DumpBounds(&c1k2);
     DumpBounds(&c1c2);
+#endif
 }
 
 template <typename TCurve, typename OppCurve>
@@ -603,6 +615,7 @@
 
 void DontCallDumpCoin();
 void DontCallDumpCoin() {  // exists to instantiate the templates
+#if !PATH_OP_COMPILE_FOR_SIZE
     SkDQuad quad;
     SkDConic conic;
     SkDCubic cubic;
@@ -624,6 +637,7 @@
     DumpCoin(&c1q2);
     DumpCoin(&c1k2);
     DumpCoin(&c1c2);
+#endif
 }
 
 template <typename TCurve, typename OppCurve>
@@ -633,6 +647,7 @@
 
 void DontCallDumpCoinCurves();
 void DontCallDumpCoinCurves() {  // exists to instantiate the templates
+#if !PATH_OP_COMPILE_FOR_SIZE
     SkDQuad quad;
     SkDConic conic;
     SkDCubic cubic;
@@ -654,6 +669,7 @@
     DumpCoinCurves(&c1q2);
     DumpCoinCurves(&c1k2);
     DumpCoinCurves(&c1c2);
+#endif
 }
 
 template <typename TCurve, typename OppCurve>
@@ -663,6 +679,7 @@
 
 void DontCallDumpCurves();
 void DontCallDumpCurves() {  // exists to instantiate the templates
+#if !PATH_OP_COMPILE_FOR_SIZE
     SkDQuad quad;
     SkDConic conic;
     SkDCubic cubic;
@@ -684,6 +701,7 @@
     DumpCurves(&c1q2);
     DumpCurves(&c1k2);
     DumpCurves(&c1c2);
+#endif
 }
 
 template <typename TCurve, typename OppCurve>
@@ -693,15 +711,20 @@
 
 void DontCallDumpTSpan();
 void DontCallDumpTSpan() {  // exists to instantiate the templates
-    SkTSpan<SkDQuad, SkDQuad> q1q2; q1q2.debugInit();
-    SkTSpan<SkDQuad, SkDConic> q1k2; q1k2.debugInit();
-    SkTSpan<SkDQuad, SkDCubic> q1c2; q1c2.debugInit();
-    SkTSpan<SkDConic, SkDQuad> k1q2; k1q2.debugInit();
-    SkTSpan<SkDConic, SkDConic> k1k2; k1k2.debugInit();
-    SkTSpan<SkDConic, SkDCubic> k1c2; k1c2.debugInit();
-    SkTSpan<SkDCubic, SkDQuad> c1q2; c1q2.debugInit();
-    SkTSpan<SkDCubic, SkDConic> c1k2; c1k2.debugInit();
-    SkTSpan<SkDCubic, SkDCubic> c1c2; c1c2.debugInit();
+#if !PATH_OP_COMPILE_FOR_SIZE
+    SkArenaAlloc heap(0);
+    SkDQuad quad;
+    SkTSpan<SkDQuad, SkDQuad> q1q2(quad, heap); q1q2.debugInit();
+    SkTSpan<SkDQuad, SkDConic> q1k2(quad, heap); q1k2.debugInit();
+    SkTSpan<SkDQuad, SkDCubic> q1c2(quad, heap); q1c2.debugInit();
+    SkDConic conic;
+    SkTSpan<SkDConic, SkDQuad> k1q2(conic, heap); k1q2.debugInit();
+    SkTSpan<SkDConic, SkDConic> k1k2(conic, heap); k1k2.debugInit();
+    SkTSpan<SkDConic, SkDCubic> k1c2(conic, heap); k1c2.debugInit();
+    SkDCubic cubic;
+    SkTSpan<SkDCubic, SkDQuad> c1q2(cubic, heap); c1q2.debugInit();
+    SkTSpan<SkDCubic, SkDConic> c1k2(cubic, heap); c1k2.debugInit();
+    SkTSpan<SkDCubic, SkDCubic> c1c2(cubic, heap); c1c2.debugInit();
     Dump(&q1q2);
     Dump(&q1k2);
     Dump(&q1c2);
@@ -711,6 +734,7 @@
     Dump(&c1q2);
     Dump(&c1k2);
     Dump(&c1c2);
+#endif
 }
 
 template <typename TCurve, typename OppCurve>
@@ -720,15 +744,20 @@
 
 void DontCallDumpSpanAll();
 void DontCallDumpSpanAll() {  // exists to instantiate the templates
-    SkTSpan<SkDQuad, SkDQuad> q1q2; q1q2.debugInit();
-    SkTSpan<SkDQuad, SkDConic> q1k2; q1k2.debugInit();
-    SkTSpan<SkDQuad, SkDCubic> q1c2; q1c2.debugInit();
-    SkTSpan<SkDConic, SkDQuad> k1q2; k1q2.debugInit();
-    SkTSpan<SkDConic, SkDConic> k1k2; k1k2.debugInit();
-    SkTSpan<SkDConic, SkDCubic> k1c2; k1c2.debugInit();
-    SkTSpan<SkDCubic, SkDQuad> c1q2; c1q2.debugInit();
-    SkTSpan<SkDCubic, SkDConic> c1k2; c1k2.debugInit();
-    SkTSpan<SkDCubic, SkDCubic> c1c2; c1c2.debugInit();
+#if !PATH_OP_COMPILE_FOR_SIZE
+    SkArenaAlloc heap(0);
+    SkDQuad quad;
+    SkTSpan<SkDQuad, SkDQuad> q1q2(quad, heap); q1q2.debugInit();
+    SkTSpan<SkDQuad, SkDConic> q1k2(quad, heap); q1k2.debugInit();
+    SkTSpan<SkDQuad, SkDCubic> q1c2(quad, heap); q1c2.debugInit();
+    SkDConic conic;
+    SkTSpan<SkDConic, SkDQuad> k1q2(conic, heap); k1q2.debugInit();
+    SkTSpan<SkDConic, SkDConic> k1k2(conic, heap); k1k2.debugInit();
+    SkTSpan<SkDConic, SkDCubic> k1c2(conic, heap); k1c2.debugInit();
+    SkDCubic cubic;
+    SkTSpan<SkDCubic, SkDQuad> c1q2(cubic, heap); c1q2.debugInit();
+    SkTSpan<SkDCubic, SkDConic> c1k2(cubic, heap); c1k2.debugInit();
+    SkTSpan<SkDCubic, SkDCubic> c1c2(cubic, heap); c1c2.debugInit();
     DumpAll(&q1q2);
     DumpAll(&q1k2);
     DumpAll(&q1c2);
@@ -738,6 +767,7 @@
     DumpAll(&c1q2);
     DumpAll(&c1k2);
     DumpAll(&c1c2);
+#endif
 }
 
 template <typename TCurve, typename OppCurve>
@@ -747,15 +777,20 @@
 
 void DontCallDumpSpanBounded();
 void DontCallDumpSpanBounded() {  // exists to instantiate the templates
-    SkTSpan<SkDQuad, SkDQuad> q1q2; q1q2.debugInit();
-    SkTSpan<SkDQuad, SkDConic> q1k2; q1k2.debugInit();
-    SkTSpan<SkDQuad, SkDCubic> q1c2; q1c2.debugInit();
-    SkTSpan<SkDConic, SkDQuad> k1q2; k1q2.debugInit();
-    SkTSpan<SkDConic, SkDConic> k1k2; k1k2.debugInit();
-    SkTSpan<SkDConic, SkDCubic> k1c2; k1c2.debugInit();
-    SkTSpan<SkDCubic, SkDQuad> c1q2; c1q2.debugInit();
-    SkTSpan<SkDCubic, SkDConic> c1k2; c1k2.debugInit();
-    SkTSpan<SkDCubic, SkDCubic> c1c2; c1c2.debugInit();
+#if !PATH_OP_COMPILE_FOR_SIZE
+    SkArenaAlloc heap(0);
+    SkDQuad quad;
+    SkTSpan<SkDQuad, SkDQuad> q1q2(quad, heap); q1q2.debugInit();
+    SkTSpan<SkDQuad, SkDConic> q1k2(quad, heap); q1k2.debugInit();
+    SkTSpan<SkDQuad, SkDCubic> q1c2(quad, heap); q1c2.debugInit();
+    SkDConic conic;
+    SkTSpan<SkDConic, SkDQuad> k1q2(conic, heap); k1q2.debugInit();
+    SkTSpan<SkDConic, SkDConic> k1k2(conic, heap); k1k2.debugInit();
+    SkTSpan<SkDConic, SkDCubic> k1c2(conic, heap); k1c2.debugInit();
+    SkDCubic cubic;
+    SkTSpan<SkDCubic, SkDQuad> c1q2(cubic, heap); c1q2.debugInit();
+    SkTSpan<SkDCubic, SkDConic> c1k2(cubic, heap); c1k2.debugInit();
+    SkTSpan<SkDCubic, SkDCubic> c1c2(cubic, heap); c1c2.debugInit();
     DumpBounded(&q1q2);
     DumpBounded(&q1k2);
     DumpBounded(&q1c2);
@@ -765,6 +800,7 @@
     DumpBounded(&c1q2);
     DumpBounded(&c1k2);
     DumpBounded(&c1c2);
+#endif
 }
 
 template <typename TCurve, typename OppCurve>
@@ -774,15 +810,20 @@
 
 void DontCallDumpSpanCoin();
 void DontCallDumpSpanCoin() {  // exists to instantiate the templates
-    SkTSpan<SkDQuad, SkDQuad> q1q2; q1q2.debugInit();
-    SkTSpan<SkDQuad, SkDConic> q1k2; q1k2.debugInit();
-    SkTSpan<SkDQuad, SkDCubic> q1c2; q1c2.debugInit();
-    SkTSpan<SkDConic, SkDQuad> k1q2; k1q2.debugInit();
-    SkTSpan<SkDConic, SkDConic> k1k2; k1k2.debugInit();
-    SkTSpan<SkDConic, SkDCubic> k1c2; k1c2.debugInit();
-    SkTSpan<SkDCubic, SkDQuad> c1q2; c1q2.debugInit();
-    SkTSpan<SkDCubic, SkDConic> c1k2; c1k2.debugInit();
-    SkTSpan<SkDCubic, SkDCubic> c1c2; c1c2.debugInit();
+#if !PATH_OP_COMPILE_FOR_SIZE
+    SkArenaAlloc heap(0);
+    SkDQuad quad;
+    SkTSpan<SkDQuad, SkDQuad> q1q2(quad, heap); q1q2.debugInit();
+    SkTSpan<SkDQuad, SkDConic> q1k2(quad, heap); q1k2.debugInit();
+    SkTSpan<SkDQuad, SkDCubic> q1c2(quad, heap); q1c2.debugInit();
+    SkDConic conic;
+    SkTSpan<SkDConic, SkDQuad> k1q2(conic, heap); k1q2.debugInit();
+    SkTSpan<SkDConic, SkDConic> k1k2(conic, heap); k1k2.debugInit();
+    SkTSpan<SkDConic, SkDCubic> k1c2(conic, heap); k1c2.debugInit();
+    SkDCubic cubic;
+    SkTSpan<SkDCubic, SkDQuad> c1q2(cubic, heap); c1q2.debugInit();
+    SkTSpan<SkDCubic, SkDConic> c1k2(cubic, heap); c1k2.debugInit();
+    SkTSpan<SkDCubic, SkDCubic> c1c2(cubic, heap); c1c2.debugInit();
     DumpCoin(&q1q2);
     DumpCoin(&q1k2);
     DumpCoin(&q1c2);
@@ -792,6 +833,7 @@
     DumpCoin(&c1q2);
     DumpCoin(&c1k2);
     DumpCoin(&c1c2);
+#endif
 }
 
 static void dumpTestCase(const SkDQuad& quad1, const SkDQuad& quad2, int testNo) {
@@ -1706,12 +1748,14 @@
         ((const SkTSpan<SkD##a, SkD##b>& ) curve).dumpCoin();                                      \
     }
 
+#if !PATH_OP_COMPILE_FOR_SIZE
     DummyDefinitions(Quad, Quad);
     DummyDefinitions(Conic, Quad);
     DummyDefinitions(Conic, Conic);
     DummyDefinitions(Cubic, Quad);
     DummyDefinitions(Cubic, Conic);
     DummyDefinitions(Cubic, Cubic);
+#endif
 
 #undef DummyDefinitions
 }