convert pathops to use SkSTArray where possible.

Replace SkTDArray with SkTArray and use SkSTArray when
the probable array size is known.

In a couple of places (spans, chases) the arrays are
constructed using insert() so SkTArrays can't be used for
now.

Also, add an optimization to cubic subdivide if either end
is zero or one.

BUG=

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

git-svn-id: http://skia.googlecode.com/svn/trunk@9635 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/pathops/SkAddIntersections.cpp b/src/pathops/SkAddIntersections.cpp
index 1884d4e..0d65446 100644
--- a/src/pathops/SkAddIntersections.cpp
+++ b/src/pathops/SkAddIntersections.cpp
@@ -413,7 +413,7 @@
 
 // resolve any coincident pairs found while intersecting, and
 // see if coincidence is formed by clipping non-concident segments
-void CoincidenceCheck(SkTDArray<SkOpContour*>* contourList, int total) {
+void CoincidenceCheck(SkTArray<SkOpContour*, true>* contourList, int total) {
     int contourCount = (*contourList).count();
     for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
         SkOpContour* contour = (*contourList)[cIndex];
diff --git a/src/pathops/SkAddIntersections.h b/src/pathops/SkAddIntersections.h
index b5727a4..94ea436 100644
--- a/src/pathops/SkAddIntersections.h
+++ b/src/pathops/SkAddIntersections.h
@@ -9,10 +9,10 @@
 
 #include "SkIntersectionHelper.h"
 #include "SkIntersections.h"
-#include "SkTDArray.h"
+#include "SkTArray.h"
 
 bool AddIntersectTs(SkOpContour* test, SkOpContour* next);
 void AddSelfIntersectTs(SkOpContour* test);
-void CoincidenceCheck(SkTDArray<SkOpContour*>* contourList, int total);
+void CoincidenceCheck(SkTArray<SkOpContour*, true>* contourList, int total);
 
 #endif
diff --git a/src/pathops/SkDCubicIntersection.cpp b/src/pathops/SkDCubicIntersection.cpp
index 5106bbb..511879c 100644
--- a/src/pathops/SkDCubicIntersection.cpp
+++ b/src/pathops/SkDCubicIntersection.cpp
@@ -12,7 +12,6 @@
 #include "SkPathOpsQuad.h"
 #include "SkPathOpsRect.h"
 #include "SkReduceOrder.h"
-#include "SkTDArray.h"
 #include "SkTSort.h"
 
 #if ONE_OFF_DEBUG
@@ -23,6 +22,8 @@
 #define DEBUG_QUAD_PART 0
 #define SWAP_TOP_DEBUG 0
 
+static const int kCubicToQuadSubdivisionDepth = 8; // slots reserved for cubic to quads subdivision
+
 static int quadPart(const SkDCubic& cubic, double tStart, double tEnd, SkReduceOrder* reducer) {
     SkDCubic part = cubic.subDivide(tStart, tEnd);
     SkDQuad quad = part.toQuad();
@@ -74,10 +75,10 @@
     i.upDepth();
     SkDCubic c1 = cubic1.subDivide(t1s, t1e);
     SkDCubic c2 = cubic2.subDivide(t2s, t2e);
-    SkTDArray<double> ts1;
+    SkSTArray<kCubicToQuadSubdivisionDepth, double, true> ts1;
     // OPTIMIZE: if c1 == c2, call once (happens when detecting self-intersection)
     c1.toQuadraticTs(c1.calcPrecision() * precisionScale, &ts1);
-    SkTDArray<double> ts2;
+    SkSTArray<kCubicToQuadSubdivisionDepth, double, true> ts2;
     c2.toQuadraticTs(c2.calcPrecision() * precisionScale, &ts2);
     double t1Start = t1s;
     int ts1Count = ts1.count();
@@ -264,10 +265,12 @@
     int t1Index = start ? 0 : 3;
     // don't bother if the two cubics are connnected
 #if 1
-    SkTDArray<double> tVals;  // OPTIMIZE: replace with hard-sized array
+    static const int kPointsInCubic = 4; // FIXME: move to DCubic, replace '4' with this
+    static const int kMaxLineCubicIntersections = 3;
+    SkSTArray<(kMaxLineCubicIntersections - 1) * kMaxLineCubicIntersections, double, true> tVals;
     line[0] = cubic1[t1Index];
     // this variant looks for intersections with the end point and lines parallel to other points
-    for (int index = 0; index < 4; ++index) {
+    for (int index = 0; index < kPointsInCubic; ++index) {
         if (index == t1Index) {
             continue;
         }
@@ -296,7 +299,7 @@
                     i.insert(start ? 0 : 1, foundT, line[0]);
                 }
             } else {
-                *tVals.append() = foundT;
+                tVals.push_back(foundT);
             }
         }
     }
diff --git a/src/pathops/SkDCubicToQuads.cpp b/src/pathops/SkDCubicToQuads.cpp
index b950535..571f1d9 100644
--- a/src/pathops/SkDCubicToQuads.cpp
+++ b/src/pathops/SkDCubicToQuads.cpp
@@ -49,7 +49,7 @@
 #include "SkPathOpsLine.h"
 #include "SkPathOpsQuad.h"
 #include "SkReduceOrder.h"
-#include "SkTDArray.h"
+#include "SkTArray.h"
 #include "SkTSort.h"
 
 #define USE_CUBIC_END_POINTS 1
@@ -88,26 +88,26 @@
     return quad;
 }
 
-static bool add_simple_ts(const SkDCubic& cubic, double precision, SkTDArray<double>* ts) {
+static bool add_simple_ts(const SkDCubic& cubic, double precision, SkTArray<double, true>* ts) {
     double tDiv = calc_t_div(cubic, precision, 0);
     if (tDiv >= 1) {
         return true;
     }
     if (tDiv >= 0.5) {
-        *ts->append() = 0.5;
+        ts->push_back(0.5);
         return true;
     }
     return false;
 }
 
 static void addTs(const SkDCubic& cubic, double precision, double start, double end,
-        SkTDArray<double>* ts) {
+        SkTArray<double, true>* ts) {
     double tDiv = calc_t_div(cubic, precision, 0);
     double parts = ceil(1.0 / tDiv);
     for (double index = 0; index < parts; ++index) {
         double newT = start + (index / parts) * (end - start);
         if (newT > 0 && newT < 1) {
-            *ts->append() = newT;
+            ts->push_back(newT);
         }
     }
 }
@@ -116,7 +116,7 @@
 // FIXME: when called from recursive intersect 2, this could take the original cubic
 // and do a more precise job when calling chop at and sub divide by computing the fractional ts.
 // it would still take the prechopped cubic for reduce order and find cubic inflections
-void SkDCubic::toQuadraticTs(double precision, SkTDArray<double>* ts) const {
+void SkDCubic::toQuadraticTs(double precision, SkTArray<double, true>* ts) const {
     SkReduceOrder reducer;
     int order = reducer.reduce(*this, SkReduceOrder::kAllow_Quadratics, SkReduceOrder::kFill_Style);
     if (order < 3) {
diff --git a/src/pathops/SkDQuadIntersection.cpp b/src/pathops/SkDQuadIntersection.cpp
index b6a1761..8b222f7 100644
--- a/src/pathops/SkDQuadIntersection.cpp
+++ b/src/pathops/SkDQuadIntersection.cpp
@@ -9,7 +9,7 @@
 #include "SkIntersections.h"
 #include "SkPathOpsLine.h"
 #include "SkQuarticRoot.h"
-#include "SkTDArray.h"
+#include "SkTArray.h"
 #include "SkTSort.h"
 
 /* given the implicit form 0 = Ax^2 + Bxy + Cy^2 + Dx + Ey + F
@@ -150,9 +150,9 @@
     SkDQuad hull = q1.subDivide(t1s, t1e);
     SkDLine line = {{hull[2], hull[0]}};
     const SkDLine* testLines[] = { &line, (const SkDLine*) &hull[0], (const SkDLine*) &hull[1] };
-    size_t testCount = SK_ARRAY_COUNT(testLines);
-    SkTDArray<double> tsFound;
-    for (size_t index = 0; index < testCount; ++index) {
+    const size_t kTestCount = SK_ARRAY_COUNT(testLines);
+    SkSTArray<kTestCount * 2, double, true> tsFound;
+    for (size_t index = 0; index < kTestCount; ++index) {
         SkIntersections rootTs;
         int roots = rootTs.intersect(q2, *testLines[index]);
         for (int idx2 = 0; idx2 < roots; ++idx2) {
@@ -165,7 +165,7 @@
             if (approximately_negative(t - t2s) || approximately_positive(t - t2e)) {
                 continue;
             }
-            *tsFound.append() = rootTs[0][idx2];
+            tsFound.push_back(rootTs[0][idx2]);
         }
     }
     int tCount = tsFound.count();
diff --git a/src/pathops/SkOpAngle.h b/src/pathops/SkOpAngle.h
index 2800ff0..e7e5e1f 100644
--- a/src/pathops/SkOpAngle.h
+++ b/src/pathops/SkOpAngle.h
@@ -17,6 +17,8 @@
 // given angles of {dx dy ddx ddy dddx dddy} sort them
 class SkOpAngle {
 public:
+    enum { kStackBasedCount = 8 }; // FIXME: determine what this should be
+
     bool operator<(const SkOpAngle& rh) const;
 
     bool calcSlop(double x, double y, double rx, double ry, bool* result) const;
diff --git a/src/pathops/SkOpContour.cpp b/src/pathops/SkOpContour.cpp
index 6266c65..f3861a1 100644
--- a/src/pathops/SkOpContour.cpp
+++ b/src/pathops/SkOpContour.cpp
@@ -11,7 +11,7 @@
 
 void SkOpContour::addCoincident(int index, SkOpContour* other, int otherIndex,
         const SkIntersections& ts, bool swap) {
-    SkCoincidence& coincidence = *fCoincidences.append();
+    SkCoincidence& coincidence = fCoincidences.push_back();
     coincidence.fContours[0] = this;  // FIXME: no need to store
     coincidence.fContours[1] = other;
     coincidence.fSegments[0] = index;
@@ -152,9 +152,9 @@
 
 void SkOpContour::sortSegments() {
     int segmentCount = fSegments.count();
-    fSortedSegments.setReserve(segmentCount);
+    fSortedSegments.push_back_n(segmentCount);
     for (int test = 0; test < segmentCount; ++test) {
-        *fSortedSegments.append() = &fSegments[test];
+        fSortedSegments[test] = &fSegments[test];
     }
     SkTQSort<SkOpSegment>(fSortedSegments.begin(), fSortedSegments.end() - 1);
     fFirstSorted = 0;
@@ -229,7 +229,7 @@
     return sum;
 }
 
-static void SkOpContour::debugShowWindingValues(const SkTDArray<SkOpContour*>& contourList) {
+static void SkOpContour::debugShowWindingValues(const SkTArray<SkOpContour*, true>& contourList) {
 //     int ofInterest = 1 << 1 | 1 << 5 | 1 << 9 | 1 << 13;
 //    int ofInterest = 1 << 4 | 1 << 8 | 1 << 12 | 1 << 16;
     int ofInterest = 1 << 5 | 1 << 8;
diff --git a/src/pathops/SkOpContour.h b/src/pathops/SkOpContour.h
index c57fbac..84f0eb1 100644
--- a/src/pathops/SkOpContour.h
+++ b/src/pathops/SkOpContour.h
@@ -46,7 +46,7 @@
             SkASSERT(fCrosses[index] != crosser);
         }
 #endif
-        *fCrosses.append() = crosser;
+        fCrosses.push_back(crosser);
     }
 
     void addCubic(const SkPoint pts[4]) {
@@ -214,17 +214,17 @@
 
 #if DEBUG_SHOW_WINDING
     int debugShowWindingValues(int totalSegments, int ofInterest);
-    static void debugShowWindingValues(const SkTDArray<SkOpContour*>& contourList);
+    static void debugShowWindingValues(const SkTArray<SkOpContour*, true>& contourList);
 #endif
 
 private:
     void setBounds();
 
     SkTArray<SkOpSegment> fSegments;
-    SkTDArray<SkOpSegment*> fSortedSegments;
+    SkTArray<SkOpSegment*, true> fSortedSegments;
     int fFirstSorted;
-    SkTDArray<SkCoincidence> fCoincidences;
-    SkTDArray<const SkOpContour*> fCrosses;
+    SkTArray<SkCoincidence, true> fCoincidences;
+    SkTArray<const SkOpContour*, true> fCrosses;
     SkPathOpsBounds fBounds;
     bool fContainsIntercepts;  // FIXME: is this used by anybody?
     bool fContainsCubics;
diff --git a/src/pathops/SkOpEdgeBuilder.cpp b/src/pathops/SkOpEdgeBuilder.cpp
index 5803afa..d7f5275 100644
--- a/src/pathops/SkOpEdgeBuilder.cpp
+++ b/src/pathops/SkOpEdgeBuilder.cpp
@@ -22,7 +22,7 @@
 
 void SkOpEdgeBuilder::addOperand(const SkPath& path) {
     SkASSERT(fPathVerbs.count() > 0 && fPathVerbs.end()[-1] == SkPath::kDone_Verb);
-    fPathVerbs.pop();
+    fPathVerbs.pop_back();
     fPath = &path;
     fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_PathOpsMask
             : kWinding_PathOpsMask;
@@ -72,11 +72,11 @@
     SkPath::Verb verb;
     do {
         verb = iter.next(pts);
-        *fPathVerbs.append() = verb;
+        fPathVerbs.push_back(verb);
         if (verb == SkPath::kMove_Verb) {
-            *fPathPts.append() = pts[0];
+            fPathPts.push_back(pts[0]);
         } else if (verb >= SkPath::kLine_Verb && verb <= SkPath::kCubic_Verb) {
-            fPathPts.append(SkPathOpsVerbToPoints(verb), &pts[1]);
+            fPathPts.push_back_n(SkPathOpsVerbToPoints(verb), &pts[1]);
         }
     } while (verb != SkPath::kDone_Verb);
     return fPathVerbs.count() - 1;
@@ -84,10 +84,10 @@
 
 bool SkOpEdgeBuilder::close() {
     if (fFinalCurveStart && fFinalCurveEnd && *fFinalCurveStart != *fFinalCurveEnd) {
-        *fReducePts.append() = *fFinalCurveStart;
-        *fReducePts.append() = *fFinalCurveEnd;
+        fReducePts.push_back(*fFinalCurveStart);
+        fReducePts.push_back(*fFinalCurveEnd);
         const SkPoint* lineStart = fReducePts.end() - 2;
-        *fExtra.append() = fCurrentContour->addLine(lineStart);
+        fExtra.push_back(fCurrentContour->addLine(lineStart));
     }
     complete();
     return true;
@@ -119,7 +119,7 @@
                     fCurrentContour = fContours.push_back_n(1);
                     fCurrentContour->setOperand(fOperand);
                     fCurrentContour->setXor(fXorMask[fOperand] == kEvenOdd_PathOpsMask);
-                    *fExtra.append() = -1;  // start new contour
+                    fExtra.push_back(-1);  // start new contour
                 }
                 fFinalCurveEnd = pointsPtr++;
                 continue;
@@ -139,7 +139,7 @@
                 }
                 if (reducedVerb == SkPath::kLine_Verb) {
                     const SkPoint* lineStart = fReducePts.end() - 2;
-                   *fExtra.append() = fCurrentContour->addLine(lineStart);
+                    fExtra.push_back(fCurrentContour->addLine(lineStart));
                     break;
                 }
                 fCurrentContour->addQuad(quadStart);
@@ -152,12 +152,12 @@
                 }
                 if (reducedVerb == SkPath::kLine_Verb) {
                     const SkPoint* lineStart = fReducePts.end() - 2;
-                    *fExtra.append() = fCurrentContour->addLine(lineStart);
+                    fExtra.push_back(fCurrentContour->addLine(lineStart));
                     break;
                 }
                 if (reducedVerb == SkPath::kQuad_Verb) {
                     const SkPoint* quadStart = fReducePts.end() - 3;
-                    *fExtra.append() = fCurrentContour->addQuad(quadStart);
+                    fExtra.push_back(fCurrentContour->addQuad(quadStart));
                     break;
                 }
                 fCurrentContour->addCubic(cubicStart);
diff --git a/src/pathops/SkOpEdgeBuilder.h b/src/pathops/SkOpEdgeBuilder.h
index b827a2a..2a2bf03 100644
--- a/src/pathops/SkOpEdgeBuilder.h
+++ b/src/pathops/SkOpEdgeBuilder.h
@@ -10,7 +10,6 @@
 #include "SkOpContour.h"
 #include "SkPathWriter.h"
 #include "SkTArray.h"
-#include "SkTDArray.h"
 
 class SkOpEdgeBuilder {
 public:
@@ -49,12 +48,12 @@
     bool walk();
 
     const SkPath* fPath;
-    SkTDArray<SkPoint> fPathPts;
-    SkTDArray<uint8_t> fPathVerbs;
+    SkTArray<SkPoint, true> fPathPts;
+    SkTArray<uint8_t, true> fPathVerbs;
     SkOpContour* fCurrentContour;
     SkTArray<SkOpContour>& fContours;
-    SkTDArray<SkPoint> fReducePts;  // segments created on the fly
-    SkTDArray<int> fExtra;  // -1 marks new contour, > 0 offsets into contour
+    SkTArray<SkPoint, true> fReducePts;  // segments created on the fly
+    SkTArray<int, true> fExtra;  // -1 marks new contour, > 0 offsets into contour
     SkPathOpsMask fXorMask[2];
     const SkPoint* fFinalCurveStart;
     const SkPoint* fFinalCurveEnd;
diff --git a/src/pathops/SkOpSegment.cpp b/src/pathops/SkOpSegment.cpp
index a9e20fd..08f4f7e 100644
--- a/src/pathops/SkOpSegment.cpp
+++ b/src/pathops/SkOpSegment.cpp
@@ -32,6 +32,8 @@
 #undef F
 #undef T
 
+enum { kOutsideTrackedTCount = 16 }; // FIXME: determine what this should be
+
 // OPTIMIZATION: does the following also work, and is it any faster?
 // return outerWinding * innerWinding > 0
 //      || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
@@ -44,7 +46,7 @@
     return result;
 }
 
-bool SkOpSegment::activeAngle(int index, int* done, SkTDArray<SkOpAngle>* angles) {
+bool SkOpSegment::activeAngle(int index, int* done, SkTArray<SkOpAngle, true>* angles) {
     if (activeAngleInner(index, done, angles)) {
         return true;
     }
@@ -63,14 +65,14 @@
     return false;
 }
 
-bool SkOpSegment::activeAngleOther(int index, int* done, SkTDArray<SkOpAngle>* angles) {
+bool SkOpSegment::activeAngleOther(int index, int* done, SkTArray<SkOpAngle, true>* angles) {
     SkOpSpan* span = &fTs[index];
     SkOpSegment* other = span->fOther;
     int oIndex = span->fOtherIndex;
     return other->activeAngleInner(oIndex, done, angles);
 }
 
-bool SkOpSegment::activeAngleInner(int index, int* done, SkTDArray<SkOpAngle>* angles) {
+bool SkOpSegment::activeAngleInner(int index, int* done, SkTArray<SkOpAngle, true>* angles) {
     int next = nextExactSpan(index, 1);
     if (next > 0) {
         SkOpSpan& upSpan = fTs[index];
@@ -204,11 +206,11 @@
     return result;
 }
 
-void SkOpSegment::addAngle(SkTDArray<SkOpAngle>* anglesPtr, int start, int end) const {
+void SkOpSegment::addAngle(SkTArray<SkOpAngle, true>* anglesPtr, int start, int end) const {
     SkASSERT(start != end);
-    SkOpAngle* angle = anglesPtr->append();
+    SkOpAngle& angle = anglesPtr->push_back();
 #if DEBUG_ANGLE
-    SkTDArray<SkOpAngle>& angles = *anglesPtr;
+    SkTArray<SkOpAngle, true>& angles = *anglesPtr;
     if (angles.count() > 1) {
         const SkOpSegment* aSeg = angles[0].segment();
         int aStart = angles[0].start();
@@ -224,7 +226,7 @@
         }
     }
 #endif
-    angle->set(this, start, end);
+    angle.set(this, start, end);
 }
 
 void SkOpSegment::addCancelOutsides(double tStart, double oStart, SkOpSegment* other, double oEnd) {
@@ -299,7 +301,7 @@
     }
 }
 
-void SkOpSegment::addCoinOutsides(const SkTDArray<double>& outsideTs, SkOpSegment* other,
+void SkOpSegment::addCoinOutsides(const SkTArray<double, true>& outsideTs, SkOpSegment* other,
                                   double oEnd) {
     // walk this to outsideTs[0]
     // walk other to outsideTs[1]
@@ -566,8 +568,8 @@
     double tRatio = (oEndT - oStartT) / (endT - startT);
     SkOpSpan* test = &fTs[index];
     SkOpSpan* oTest = &other->fTs[oIndex];
-    SkTDArray<double> outsideTs;
-    SkTDArray<double> oOutsideTs;
+    SkSTArray<kOutsideTrackedTCount, double, true> outsideTs;
+    SkSTArray<kOutsideTrackedTCount, double, true> oOutsideTs;
     do {
         bool decrement = test->fWindValue && oTest->fWindValue;
         bool track = test->fWindValue || oTest->fWindValue;
@@ -658,7 +660,7 @@
 }
 
 int SkOpSegment::bumpCoincidentThis(const SkOpSpan& oTest, bool opp, int index,
-        SkTDArray<double>* outsideTs) {
+        SkTArray<double, true>* outsideTs) {
     int oWindValue = oTest.fWindValue;
     int oOppValue = oTest.fOppValue;
     if (opp) {
@@ -681,7 +683,7 @@
 // intermediate T values (using this as the master, other as the follower)
 // and walk other conditionally -- hoping that it catches up in the end
 int SkOpSegment::bumpCoincidentOther(const SkOpSpan& test, double oEndT, int& oIndex,
-        SkTDArray<double>* oOutsideTs) {
+        SkTArray<double, true>* oOutsideTs) {
     SkOpSpan* const oTest = &fTs[oIndex];
     SkOpSpan* oEnd = oTest;
     const double startT = test.fT;
@@ -719,8 +721,8 @@
     }
     SkOpSpan* test = &fTs[index];
     SkOpSpan* oTest = &other->fTs[oIndex];
-    SkTDArray<double> outsideTs;
-    SkTDArray<double> oOutsideTs;
+    SkSTArray<kOutsideTrackedTCount, double, true> outsideTs;
+    SkSTArray<kOutsideTrackedTCount, double, true> oOutsideTs;
     do {
         // if either span has an opposite value and the operands don't match, resolve first
  //       SkASSERT(!test->fDone || !oTest->fDone);
@@ -775,7 +777,7 @@
     other->matchWindingValue(otherInsertedAt, otherT, borrowWind);
 }
 
-void SkOpSegment::addTwoAngles(int start, int end, SkTDArray<SkOpAngle>* angles) const {
+void SkOpSegment::addTwoAngles(int start, int end, SkTArray<SkOpAngle, true>* angles) const {
     // add edge leading into junction
     int min = SkMin32(end, start);
     if (fTs[min].fWindValue > 0 || fTs[min].fOppValue != 0) {
@@ -817,7 +819,7 @@
     return approximately_between(fTs[lesser].fT, testT, fTs[greater].fT);
 }
 
-void SkOpSegment::buildAngles(int index, SkTDArray<SkOpAngle>* angles, bool includeOpp) const {
+void SkOpSegment::buildAngles(int index, SkTArray<SkOpAngle, true>* angles, bool includeOpp) const {
     double referenceT = fTs[index].fT;
     int lesser = index;
     while (--lesser >= 0 && (includeOpp || fTs[lesser].fOther->fOperand == fOperand)
@@ -830,7 +832,7 @@
             && precisely_negative(fTs[index].fT - referenceT));
 }
 
-void SkOpSegment::buildAnglesInner(int index, SkTDArray<SkOpAngle>* angles) const {
+void SkOpSegment::buildAnglesInner(int index, SkTArray<SkOpAngle, true>* angles) const {
     const SkOpSpan* span = &fTs[index];
     SkOpSegment* other = span->fOther;
 // if there is only one live crossing, and no coincidence, continue
@@ -850,12 +852,12 @@
 }
 
 int SkOpSegment::computeSum(int startIndex, int endIndex, bool binary) {
-    SkTDArray<SkOpAngle> angles;
+    SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles;
     addTwoAngles(startIndex, endIndex, &angles);
     buildAngles(endIndex, &angles, false);
     // OPTIMIZATION: check all angles to see if any have computed wind sum
     // before sorting (early exit if none)
-    SkTDArray<SkOpAngle*> sorted;
+    SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted;
     // FIXME?: Not sure if this sort must be ordered or if the relaxed ordering is OK ...
     bool sortable = SortAngles(angles, &sorted, SkOpSegment::kMustBeOrdered_SortAngleKind);
 #if DEBUG_SORT
@@ -1137,12 +1139,12 @@
         return other;
     }
     // more than one viable candidate -- measure angles to find best
-    SkTDArray<SkOpAngle> angles;
+    SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles;
     SkASSERT(startIndex - endIndex != 0);
     SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
     addTwoAngles(startIndex, end, &angles);
     buildAngles(end, &angles, true);
-    SkTDArray<SkOpAngle*> sorted;
+    SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted;
     bool sortable = SortAngles(angles, &sorted, SkOpSegment::kMustBeOrdered_SortAngleKind);
     int angleCount = angles.count();
     int firstIndex = findStartingEdge(sorted, startIndex, end);
@@ -1259,12 +1261,12 @@
         return other;
     }
     // more than one viable candidate -- measure angles to find best
-    SkTDArray<SkOpAngle> angles;
+    SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles;
     SkASSERT(startIndex - endIndex != 0);
     SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
     addTwoAngles(startIndex, end, &angles);
     buildAngles(end, &angles, true);
-    SkTDArray<SkOpAngle*> sorted;
+    SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted;
     bool sortable = SortAngles(angles, &sorted, SkOpSegment::kMustBeOrdered_SortAngleKind);
     int angleCount = angles.count();
     int firstIndex = findStartingEdge(sorted, startIndex, end);
@@ -1388,12 +1390,12 @@
         SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count());
         return other;
     }
-    SkTDArray<SkOpAngle> angles;
+    SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles;
     SkASSERT(startIndex - endIndex != 0);
     SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
     addTwoAngles(startIndex, end, &angles);
     buildAngles(end, &angles, false);
-    SkTDArray<SkOpAngle*> sorted;
+    SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted;
     bool sortable = SortAngles(angles, &sorted, SkOpSegment::kMustBeOrdered_SortAngleKind);
     if (!sortable) {
         *unsortable = true;
@@ -1449,7 +1451,7 @@
     return nextSegment;
 }
 
-int SkOpSegment::findStartingEdge(const SkTDArray<SkOpAngle*>& sorted, int start, int end) {
+int SkOpSegment::findStartingEdge(const SkTArray<SkOpAngle*, true>& sorted, int start, int end) {
     int angleCount = sorted.count();
     int firstIndex = -1;
     for (int angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
@@ -1631,11 +1633,11 @@
     }
     // 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<SkOpAngle> angles;
+    SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles;
     SkASSERT(firstT - end != 0);
     addTwoAngles(end, firstT, &angles);
     buildAngles(firstT, &angles, true);
-    SkTDArray<SkOpAngle*> sorted;
+    SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted;
     bool sortable = SortAngles(angles, &sorted, SkOpSegment::kMayBeUnordered_SortAngleKind);
     int first = SK_MaxS32;
     SkScalar top = SK_ScalarMax;
@@ -2343,15 +2345,17 @@
 // exclusion in find top and others. This could be optimized to only mark
 // adjacent spans that unsortable. However, this makes it difficult to later
 // determine starting points for edge detection in find top and the like.
-bool SkOpSegment::SortAngles(const SkTDArray<SkOpAngle>& angles, SkTDArray<SkOpAngle*>* angleList,
+bool SkOpSegment::SortAngles(const SkTArray<SkOpAngle, true>& angles,
+                             SkTArray<SkOpAngle*, true>* angleList,
                              SortAngleKind orderKind) {
     bool sortable = true;
     int angleCount = angles.count();
     int angleIndex;
-    angleList->setReserve(angleCount);
+// FIXME: caller needs to use SkTArray constructor with reserve count
+//    angleList->setReserve(angleCount);
     for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) {
         const SkOpAngle& angle = angles[angleIndex];
-        *angleList->append() = const_cast<SkOpAngle*>(&angle);
+        angleList->push_back(const_cast<SkOpAngle*>(&angle));
 #if DEBUG_ANGLE
         (*(angleList->end() - 1))->setID(angleIndex);
 #endif
@@ -2470,11 +2474,11 @@
     return fTs[index].fTiny;
 }
 
-void SkOpSegment::TrackOutside(SkTDArray<double>* outsideTs, double end, double start) {
+void SkOpSegment::TrackOutside(SkTArray<double, true>* outsideTs, double end, double start) {
     int outCount = outsideTs->count();
     if (outCount == 0 || !approximately_negative(end - (*outsideTs)[outCount - 2])) {
-        *outsideTs->append() = end;
-        *outsideTs->append() = start;
+        outsideTs->push_back(end);
+        outsideTs->push_back(start);
     }
 }
 
@@ -2763,8 +2767,9 @@
 #endif
 
 #if DEBUG_SORT || DEBUG_SWAP_TOP
-void SkOpSegment::debugShowSort(const char* fun, const SkTDArray<SkOpAngle*>& angles, int first,
-        const int contourWinding, const int oppContourWinding) const {
+void SkOpSegment::debugShowSort(const char* fun, const SkTArray<SkOpAngle*, true>& angles,
+                                int first, const int contourWinding,
+                                const int oppContourWinding) const {
     if (--gDebugSortCount < 0) {
         return;
     }
@@ -2872,7 +2877,8 @@
     } while (index != first);
 }
 
-void SkOpSegment::debugShowSort(const char* fun, const SkTDArray<SkOpAngle*>& angles, int first) {
+void SkOpSegment::debugShowSort(const char* fun, const SkTArray<SkOpAngle*, true>& angles,
+                                int first) {
     const SkOpAngle* firstAngle = angles[first];
     const SkOpSegment* segment = firstAngle->segment();
     int winding = segment->updateWinding(firstAngle);
@@ -2888,8 +2894,7 @@
         return 0;
     }
     int sum = 0;
-    SkTDArray<char> slots;
-    slots.setCount(slotCount * 2);
+    SkTArray<char, true> slots(slotCount * 2);
     memset(slots.begin(), ' ', slotCount * 2);
     for (int i = 0; i < fTs.count(); ++i) {
    //     if (!(1 << fTs[i].fOther->fID & ofInterest)) {
diff --git a/src/pathops/SkOpSegment.h b/src/pathops/SkOpSegment.h
index b26bad1..94efcb5 100644
--- a/src/pathops/SkOpSegment.h
+++ b/src/pathops/SkOpSegment.h
@@ -11,6 +11,7 @@
 #include "SkOpSpan.h"
 #include "SkPathOpsBounds.h"
 #include "SkPathOpsCurve.h"
+#include "SkTArray.h"
 #include "SkTDArray.h"
 
 class SkPathWriter;
@@ -230,7 +231,7 @@
         return xyAtT(span).fY;
     }
 
-    bool activeAngle(int index, int* done, SkTDArray<SkOpAngle>* angles);
+    bool activeAngle(int index, int* done, SkTArray<SkOpAngle, true>* angles);
     SkPoint activeLeftTop(bool onlySortable, int* firstT) const;
     bool activeOp(int index, int endIndex, int xorMiMask, int xorSuMask, SkPathOp op);
     bool activeOp(int xorMiMask, int xorSuMask, int index, int endIndex, SkPathOp op,
@@ -294,7 +295,8 @@
         kMustBeOrdered_SortAngleKind, // required for winding calc
         kMayBeUnordered_SortAngleKind // ok for find top
     };
-    static bool SortAngles(const SkTDArray<SkOpAngle>& angles, SkTDArray<SkOpAngle*>* angleList,
+    static bool SortAngles(const SkTArray<SkOpAngle, true>& angles,
+                           SkTArray<SkOpAngle*, true>* angleList,
                            SortAngleKind );
     bool subDivide(int start, int end, SkPoint edge[4]) const;
     bool subDivide(int start, int end, SkDCubic* result) const;
@@ -315,9 +317,9 @@
     void debugShowActiveSpans() const;
 #endif
 #if DEBUG_SORT || DEBUG_SWAP_TOP
-    void debugShowSort(const char* fun, const SkTDArray<SkOpAngle*>& angles, int first,
+    void debugShowSort(const char* fun, const SkTArray<SkOpAngle*, true>& angles, int first,
             const int contourWinding, const int oppContourWinding) const;
-    void debugShowSort(const char* fun, const SkTDArray<SkOpAngle*>& angles, int first);
+    void debugShowSort(const char* fun, const SkTArray<SkOpAngle*, true>& angles, int first);
 #endif
 #if DEBUG_CONCIDENT
     void debugShowTs() const;
@@ -327,25 +329,25 @@
 #endif
 
 private:
-    bool activeAngleOther(int index, int* done, SkTDArray<SkOpAngle>* angles);
-    bool activeAngleInner(int index, int* done, SkTDArray<SkOpAngle>* angles);
-    void addAngle(SkTDArray<SkOpAngle>* angles, int start, int end) const;
+    bool activeAngleOther(int index, int* done, SkTArray<SkOpAngle, true>* angles);
+    bool activeAngleInner(int index, int* done, SkTArray<SkOpAngle, true>* angles);
+    void addAngle(SkTArray<SkOpAngle, true>* angles, int start, int end) const;
     void addCancelOutsides(double tStart, double oStart, SkOpSegment* other, double oEnd);
-    void addCoinOutsides(const SkTDArray<double>& outsideTs, SkOpSegment* other, double oEnd);
-    void addTwoAngles(int start, int end, SkTDArray<SkOpAngle>* angles) const;
+    void addCoinOutsides(const SkTArray<double, true>& outsideTs, SkOpSegment* other, double oEnd);
+    void addTwoAngles(int start, int end, SkTArray<SkOpAngle, true>* angles) const;
     int advanceCoincidentOther(const SkOpSpan* test, double oEndT, int oIndex);
     int advanceCoincidentThis(const SkOpSpan* oTest, bool opp, int index);
-    void buildAngles(int index, SkTDArray<SkOpAngle>* angles, bool includeOpp) const;
-    void buildAnglesInner(int index, SkTDArray<SkOpAngle>* angles) const;
+    void buildAngles(int index, SkTArray<SkOpAngle, true>* angles, bool includeOpp) const;
+    void buildAnglesInner(int index, SkTArray<SkOpAngle, true>* angles) const;
     int bumpCoincidentThis(const SkOpSpan& oTest, bool opp, int index,
-                           SkTDArray<double>* outsideTs);
+                           SkTArray<double, true>* outsideTs);
     int bumpCoincidentOther(const SkOpSpan& test, double oEndT, int& oIndex,
-                            SkTDArray<double>* oOutsideTs);
+                            SkTArray<double, true>* oOutsideTs);
     bool bumpSpan(SkOpSpan* span, int windDelta, int oppDelta);
     bool clockwise(int tStart, int tEnd) const;
     void decrementSpan(SkOpSpan* span);
     bool equalPoints(int greaterTIndex, int lesserTIndex);
-    int findStartingEdge(const SkTDArray<SkOpAngle*>& sorted, int start, int end);
+    int findStartingEdge(const SkTArray<SkOpAngle*, true>& sorted, int start, int end);
     void init(const SkPoint pts[], SkPath::Verb verb, bool operand, bool evenOdd);
     void matchWindingValue(int tIndex, double t, bool borrowWind);
     SkOpSpan* markAndChaseDone(int index, int endIndex, int winding);
@@ -365,7 +367,7 @@
     SkOpSegment* nextChase(int* index, const int step, int* min, SkOpSpan** last);
     bool serpentine(int tStart, int tEnd) const;
     void subDivideBounds(int start, int end, SkPathOpsBounds* bounds) const;
-    static void TrackOutside(SkTDArray<double>* outsideTs, double end, double start);
+    static void TrackOutside(SkTArray<double, true>* outsideTs, double end, double start);
     int updateOppWinding(int index, int endIndex) const;
     int updateOppWinding(const SkOpAngle* angle) const;
     int updateWinding(int index, int endIndex) const;
@@ -393,6 +395,7 @@
 
     const SkPoint* fPts;
     SkPathOpsBounds fBounds;
+    // FIXME: can't convert to SkTArray because it uses insert
     SkTDArray<SkOpSpan> fTs;  // two or more (always includes t=0 t=1)
     // OPTIMIZATION: could pack donespans, verb, operand, xor into 1 int-sized value
     int fDoneSpans;  // quick check that segment is finished
diff --git a/src/pathops/SkPathOpsCommon.cpp b/src/pathops/SkPathOpsCommon.cpp
index 9215cbc..0fa5ce0 100644
--- a/src/pathops/SkPathOpsCommon.cpp
+++ b/src/pathops/SkPathOpsCommon.cpp
@@ -9,7 +9,7 @@
 #include "SkPathWriter.h"
 #include "SkTSort.h"
 
-static int contourRangeCheckY(const SkTDArray<SkOpContour*>& contourList, SkOpSegment** currentPtr,
+static int contourRangeCheckY(const SkTArray<SkOpContour*, true>& contourList, SkOpSegment** currentPtr,
                               int* indexPtr, int* endIndexPtr, double* bestHit, SkScalar* bestDx,
                               bool* tryAgain, double* midPtr, bool opp) {
     const int index = *indexPtr;
@@ -97,7 +97,7 @@
     return result;
 }
 
-SkOpSegment* FindUndone(SkTDArray<SkOpContour*>& contourList, int* start, int* end) {
+SkOpSegment* FindUndone(SkTArray<SkOpContour*, true>& contourList, int* start, int* end) {
     int contourCount = contourList.count();
     SkOpSegment* result;
     for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
@@ -117,7 +117,7 @@
         const SkOpSpan& backPtr = span->fOther->span(span->fOtherIndex);
         SkOpSegment* segment = backPtr.fOther;
         tIndex = backPtr.fOtherIndex;
-        SkTDArray<SkOpAngle> angles;
+        SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles;
         int done = 0;
         if (segment->activeAngle(tIndex, &done, &angles)) {
             SkOpAngle* last = angles.end() - 1;
@@ -133,7 +133,7 @@
         if (done == angles.count()) {
             continue;
         }
-        SkTDArray<SkOpAngle*> sorted;
+        SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted;
         bool sortable = SkOpSegment::SortAngles(angles, &sorted,
                 SkOpSegment::kMayBeUnordered_SortAngleKind);
         int angleCount = sorted.count();
@@ -208,7 +208,7 @@
 }
 
 #if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY
-void DebugShowActiveSpans(SkTDArray<SkOpContour*>& contourList) {
+void DebugShowActiveSpans(SkTArray<SkOpContour*, true>& contourList) {
     int index;
     for (index = 0; index < contourList.count(); ++ index) {
         contourList[index]->debugShowActiveSpans();
@@ -216,7 +216,7 @@
 }
 #endif
 
-static SkOpSegment* findSortableTop(const SkTDArray<SkOpContour*>& contourList,
+static SkOpSegment* findSortableTop(const SkTArray<SkOpContour*, true>& contourList,
                                     int* index, int* endIndex, SkPoint* topLeft, bool* unsortable,
                                     bool* done, bool onlySortable) {
     SkOpSegment* result;
@@ -253,7 +253,7 @@
     return result;
 }
 
-static int rightAngleWinding(const SkTDArray<SkOpContour*>& contourList,
+static int rightAngleWinding(const SkTArray<SkOpContour*, true>& contourList,
                              SkOpSegment** current, int* index, int* endIndex, double* tHit,
                              SkScalar* hitDx, bool* tryAgain, bool opp) {
     double test = 0.9;
@@ -270,7 +270,7 @@
     return contourWinding;
 }
 
-static void skipVertical(const SkTDArray<SkOpContour*>& contourList,
+static void skipVertical(const SkTArray<SkOpContour*, true>& contourList,
         SkOpSegment** current, int* index, int* endIndex) {
     if (!(*current)->isVertical(*index, *endIndex)) {
         return;
@@ -288,7 +288,7 @@
     }
 }
 
-SkOpSegment* FindSortableTop(const SkTDArray<SkOpContour*>& contourList, bool* firstContour,
+SkOpSegment* FindSortableTop(const SkTArray<SkOpContour*, true>& contourList, bool* firstContour,
                              int* indexPtr, int* endIndexPtr, SkPoint* topLeft, bool* unsortable,
                              bool* done,  bool binary) {
     SkOpSegment* current = findSortableTop(contourList, indexPtr, endIndexPtr, topLeft, unsortable,
@@ -344,7 +344,7 @@
     return current;
 }
 
-void FixOtherTIndex(SkTDArray<SkOpContour*>* contourList) {
+void FixOtherTIndex(SkTArray<SkOpContour*, true>* contourList) {
     int contourCount = (*contourList).count();
     for (int cTest = 0; cTest < contourCount; ++cTest) {
         SkOpContour* contour = (*contourList)[cTest];
@@ -352,7 +352,7 @@
     }
 }
 
-void SortSegments(SkTDArray<SkOpContour*>* contourList) {
+void SortSegments(SkTArray<SkOpContour*, true>* contourList) {
     int contourCount = (*contourList).count();
     for (int cTest = 0; cTest < contourCount; ++cTest) {
         SkOpContour* contour = (*contourList)[cTest];
@@ -360,7 +360,7 @@
     }
 }
 
-void MakeContourList(SkTArray<SkOpContour>& contours, SkTDArray<SkOpContour*>& list,
+void MakeContourList(SkTArray<SkOpContour>& contours, SkTArray<SkOpContour*, true>& list,
                      bool evenOdd, bool oppEvenOdd) {
     int count = contours.count();
     if (count == 0) {
@@ -369,7 +369,7 @@
     for (int index = 0; index < count; ++index) {
         SkOpContour& contour = contours[index];
         contour.setOppXor(contour.operand() ? evenOdd : oppEvenOdd);
-        *list.append() = &contour;
+        list.push_back(&contour);
     }
     SkTQSort<SkOpContour>(list.begin(), list.end() - 1);
 }
@@ -403,7 +403,7 @@
     builder.finish();
     int count = contours.count();
     int outer;
-    SkTDArray<int> runs;  // indices of partial contours
+    SkTArray<int, true> runs(count);  // indices of partial contours
     for (outer = 0; outer < count; ++outer) {
         const SkOpContour& eContour = contours[outer];
         const SkPoint& eStart = eContour.start();
@@ -422,23 +422,23 @@
             eContour.toPath(simple);
             continue;
         }
-        *runs.append() = outer;
+        runs.push_back(outer);
     }
     count = runs.count();
     if (count == 0) {
         return;
     }
-    SkTDArray<int> sLink, eLink;
-    sLink.setCount(count);
-    eLink.setCount(count);
+    SkTArray<int, true> sLink, eLink;
+    sLink.push_back_n(count);
+    eLink.push_back_n(count);
     int rIndex, iIndex;
     for (rIndex = 0; rIndex < count; ++rIndex) {
         sLink[rIndex] = eLink[rIndex] = SK_MaxS32;
     }
-    SkTDArray<double> distances;
     const int ends = count * 2;  // all starts and ends
     const int entries = (ends - 1) * count;  // folded triangle : n * (n - 1) / 2
-    distances.setCount(entries);
+    SkTArray<double, true> distances;
+    distances.push_back_n(entries);
     for (rIndex = 0; rIndex < ends - 1; ++rIndex) {
         outer = runs[rIndex >> 1];
         const SkOpContour& oContour = contours[outer];
@@ -455,8 +455,8 @@
             distances[row + iIndex] = dist;  // oStart distance from iStart
         }
     }
-    SkTDArray<int> sortedDist;
-    sortedDist.setCount(entries);
+    SkTArray<int, true> sortedDist;
+    sortedDist.push_back_n(entries);
     for (rIndex = 0; rIndex < entries; ++rIndex) {
         sortedDist[rIndex] = rIndex;
     }
diff --git a/src/pathops/SkPathOpsCommon.h b/src/pathops/SkPathOpsCommon.h
index 8bbe232..569edb7 100644
--- a/src/pathops/SkPathOpsCommon.h
+++ b/src/pathops/SkPathOpsCommon.h
@@ -8,22 +8,24 @@
 #define SkPathOpsCommon_DEFINED
 
 #include "SkOpContour.h"
+#include "SkTDArray.h"
 
 class SkPathWriter;
 
 void Assemble(const SkPathWriter& path, SkPathWriter* simple);
+// FIXME: find chase uses insert, so it can't be converted to SkTArray yet
 SkOpSegment* FindChase(SkTDArray<SkOpSpan*>& chase, int& tIndex, int& endIndex);
-SkOpSegment* FindSortableTop(const SkTDArray<SkOpContour*>& contourList, bool* firstContour,
+SkOpSegment* FindSortableTop(const SkTArray<SkOpContour*, true>& contourList, bool* firstContour,
                              int* index, int* endIndex, SkPoint* topLeft, bool* unsortable,
                              bool* done, bool binary);
-SkOpSegment* FindUndone(SkTDArray<SkOpContour*>& contourList, int* start, int* end);
-void FixOtherTIndex(SkTDArray<SkOpContour*>* contourList);
-void MakeContourList(SkTArray<SkOpContour>& contours, SkTDArray<SkOpContour*>& list,
+SkOpSegment* FindUndone(SkTArray<SkOpContour*, true>& contourList, int* start, int* end);
+void FixOtherTIndex(SkTArray<SkOpContour*, true>* contourList);
+void MakeContourList(SkTArray<SkOpContour>& contours, SkTArray<SkOpContour*, true>& list,
                      bool evenOdd, bool oppEvenOdd);
-void SortSegments(SkTDArray<SkOpContour*>* contourList);
+void SortSegments(SkTArray<SkOpContour*, true>* contourList);
 
 #if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY
-void DebugShowActiveSpans(SkTDArray<SkOpContour*>& contourList);
+void DebugShowActiveSpans(SkTArray<SkOpContour*, true>& contourList);
 #endif
 
 #endif
diff --git a/src/pathops/SkPathOpsCubic.cpp b/src/pathops/SkPathOpsCubic.cpp
index 5d77e5a..60dca44 100644
--- a/src/pathops/SkPathOpsCubic.cpp
+++ b/src/pathops/SkPathOpsCubic.cpp
@@ -383,8 +383,13 @@
 }
 
 SkDCubic SkDCubic::subDivide(double t1, double t2) const {
-    if (t1 == 0 && t2 == 1) {
-        return *this;
+    if (t1 == 0 || t2 == 1) {
+        if (t1 == 0 && t2 == 1) {
+            return *this;
+        }
+        SkDCubicPair pair = chopAt(t1 == 0 ? t2 : t1);
+        SkDCubic dst = t1 == 0 ? pair.first() : pair.second();
+        return dst;
     }
     SkDCubic dst;
     double ax = dst[0].fX = interp_cubic_coords(&fPts[0].fX, t1);
diff --git a/src/pathops/SkPathOpsCubic.h b/src/pathops/SkPathOpsCubic.h
index 7be6142..f07af80 100644
--- a/src/pathops/SkPathOpsCubic.h
+++ b/src/pathops/SkPathOpsCubic.h
@@ -10,7 +10,7 @@
 
 #include "SkPath.h"
 #include "SkPathOpsPoint.h"
-#include "SkTDArray.h"
+#include "SkTArray.h"
 
 struct SkDCubicPair {
     const SkDCubic& first() const { return (const SkDCubic&) pts[0]; }
@@ -74,7 +74,7 @@
     }
 
     SkDPoint top(double startT, double endT) const;
-    void toQuadraticTs(double precision, SkTDArray<double>* ts) const;
+    void toQuadraticTs(double precision, SkTArray<double, true>* ts) const;
     SkDQuad toQuad() const;
     SkDPoint xyAtT(double t) const;
 };
diff --git a/src/pathops/SkPathOpsOp.cpp b/src/pathops/SkPathOpsOp.cpp
index f030765..7e1c772 100644
--- a/src/pathops/SkPathOpsOp.cpp
+++ b/src/pathops/SkPathOpsOp.cpp
@@ -20,7 +20,7 @@
         const SkOpSpan& backPtr = span->fOther->span(span->fOtherIndex);
         SkOpSegment* segment = backPtr.fOther;
         nextStart = backPtr.fOtherIndex;
-        SkTDArray<SkOpAngle> angles;
+        SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles;
         int done = 0;
         if (segment->activeAngle(nextStart, &done, &angles)) {
             SkOpAngle* last = angles.end() - 1;
@@ -36,7 +36,7 @@
         if (done == angles.count()) {
             continue;
         }
-        SkTDArray<SkOpAngle*> sorted;
+        SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted;
         bool sortable = SkOpSegment::SortAngles(angles, &sorted,
                 SkOpSegment::kMayBeUnordered_SortAngleKind);
         int angleCount = sorted.count();
@@ -126,7 +126,7 @@
 }
 */
 
-static bool bridgeOp(SkTDArray<SkOpContour*>& contourList, const SkPathOp op,
+static bool bridgeOp(SkTArray<SkOpContour*, true>& contourList, const SkPathOp op,
         const int xorMask, const int xorOpMask, SkPathWriter* simple) {
     bool firstContour = true;
     bool unsortable = false;
@@ -263,7 +263,7 @@
     result->reset();
     result->setFillType(fillType);
     const int xorOpMask = builder.xorMask();
-    SkTDArray<SkOpContour*> contourList;
+    SkTArray<SkOpContour*, true> contourList;
     MakeContourList(contours, contourList, xorMask == kEvenOdd_PathOpsMask,
             xorOpMask == kEvenOdd_PathOpsMask);
     SkOpContour** currentPtr = contourList.begin();
diff --git a/src/pathops/SkPathOpsSimplify.cpp b/src/pathops/SkPathOpsSimplify.cpp
index 9a319e0..f89c4af 100644
--- a/src/pathops/SkPathOpsSimplify.cpp
+++ b/src/pathops/SkPathOpsSimplify.cpp
@@ -9,7 +9,7 @@
 #include "SkPathOpsCommon.h"
 #include "SkPathWriter.h"
 
-static bool bridgeWinding(SkTDArray<SkOpContour*>& contourList, SkPathWriter* simple) {
+static bool bridgeWinding(SkTArray<SkOpContour*, true>& contourList, SkPathWriter* simple) {
     bool firstContour = true;
     bool unsortable = false;
     bool topUnsortable = false;
@@ -94,7 +94,7 @@
 }
 
 // returns true if all edges were processed
-static bool bridgeXor(SkTDArray<SkOpContour*>& contourList, SkPathWriter* simple) {
+static bool bridgeXor(SkTArray<SkOpContour*, true>& contourList, SkPathWriter* simple) {
     SkOpSegment* current;
     int start, end;
     bool unsortable = false;
@@ -161,7 +161,7 @@
     if (!builder.finish()) {
         return false;
     }
-    SkTDArray<SkOpContour*> contourList;
+    SkTArray<SkOpContour*, true> contourList;
     MakeContourList(contours, contourList, false, false);
     SkOpContour** currentPtr = contourList.begin();
     result->setFillType(fillType);
diff --git a/src/pathops/SkReduceOrder.cpp b/src/pathops/SkReduceOrder.cpp
index 6d2339c..ab85f3d 100644
--- a/src/pathops/SkReduceOrder.cpp
+++ b/src/pathops/SkReduceOrder.cpp
@@ -425,31 +425,31 @@
     return 4;
 }
 
-SkPath::Verb SkReduceOrder::Quad(const SkPoint a[3], SkTDArray<SkPoint>* reducePts) {
+SkPath::Verb SkReduceOrder::Quad(const SkPoint a[3], SkTArray<SkPoint, true>* reducePts) {
     SkDQuad quad;
     quad.set(a);
     SkReduceOrder reducer;
     int order = reducer.reduce(quad, kFill_Style);
     if (order == 2) {  // quad became line
         for (int index = 0; index < order; ++index) {
-            SkPoint* pt = reducePts->append();
-            pt->fX = SkDoubleToScalar(reducer.fLine[index].fX);
-            pt->fY = SkDoubleToScalar(reducer.fLine[index].fY);
+            SkPoint& pt = reducePts->push_back();
+            pt.fX = SkDoubleToScalar(reducer.fLine[index].fX);
+            pt.fY = SkDoubleToScalar(reducer.fLine[index].fY);
         }
     }
     return SkPathOpsPointsToVerb(order - 1);
 }
 
-SkPath::Verb SkReduceOrder::Cubic(const SkPoint a[4], SkTDArray<SkPoint>* reducePts) {
+SkPath::Verb SkReduceOrder::Cubic(const SkPoint a[4], SkTArray<SkPoint, true>* reducePts) {
     SkDCubic cubic;
     cubic.set(a);
     SkReduceOrder reducer;
     int order = reducer.reduce(cubic, kAllow_Quadratics, kFill_Style);
     if (order == 2 || order == 3) {  // cubic became line or quad
         for (int index = 0; index < order; ++index) {
-            SkPoint* pt = reducePts->append();
-            pt->fX = SkDoubleToScalar(reducer.fQuad[index].fX);
-            pt->fY = SkDoubleToScalar(reducer.fQuad[index].fY);
+            SkPoint& pt = reducePts->push_back();
+            pt.fX = SkDoubleToScalar(reducer.fQuad[index].fX);
+            pt.fY = SkDoubleToScalar(reducer.fQuad[index].fY);
         }
     }
     return SkPathOpsPointsToVerb(order - 1);
diff --git a/src/pathops/SkReduceOrder.h b/src/pathops/SkReduceOrder.h
index 62b4af9..82f8ffb 100644
--- a/src/pathops/SkReduceOrder.h
+++ b/src/pathops/SkReduceOrder.h
@@ -11,7 +11,7 @@
 #include "SkPathOpsCubic.h"
 #include "SkPathOpsLine.h"
 #include "SkPathOpsQuad.h"
-#include "SkTDArray.h"
+#include "SkTArray.h"
 
 union SkReduceOrder {
     enum Quadratics {
@@ -27,8 +27,8 @@
     int reduce(const SkDLine& line);
     int reduce(const SkDQuad& quad, Style);
 
-    static SkPath::Verb Cubic(const SkPoint pts[4], SkTDArray<SkPoint>* reducePts);
-    static SkPath::Verb Quad(const SkPoint pts[3], SkTDArray<SkPoint>* reducePts);
+    static SkPath::Verb Cubic(const SkPoint pts[4], SkTArray<SkPoint, true>* reducePts);
+    static SkPath::Verb Quad(const SkPoint pts[3], SkTArray<SkPoint, true>* reducePts);
 
     SkDLine fLine;
     SkDQuad fQuad;