Make GrTriangulator immutable

Marks its methods const and lifts the breadcrumb list out into
function arguments. This is one more step toward the final vision
where GrTriangulator just has an allocator and control knobs, and
everything else is functional.

Bug: skia:10419
Change-Id: I77341c045d481da49ebfee06de5dfc7a2a8a07be
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/360956
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
diff --git a/src/gpu/GrTriangulator.cpp b/src/gpu/GrTriangulator.cpp
index 94a1eac..00f275d 100644
--- a/src/gpu/GrTriangulator.cpp
+++ b/src/gpu/GrTriangulator.cpp
@@ -204,7 +204,8 @@
     }
 }
 
-void* GrTriangulator::emitMonotonePoly(const MonotonePoly* monotonePoly, void* data) {
+void* GrTriangulator::emitMonotonePoly(const MonotonePoly* monotonePoly, void* data,
+                                       BreadcrumbTriangleList* breadcrumbList) const {
     SkASSERT(monotonePoly->fWinding != 0);
     Edge* e = monotonePoly->fFirstEdge;
     VertexList vertices;
@@ -228,14 +229,16 @@
         Vertex* curr = v;
         Vertex* next = v->fNext;
         if (count == 3) {
-            return this->emitTriangle(prev, curr, next, monotonePoly->fWinding, data);
+            return this->emitTriangle(prev, curr, next, monotonePoly->fWinding, data,
+                                      breadcrumbList);
         }
         double ax = static_cast<double>(curr->fPoint.fX) - prev->fPoint.fX;
         double ay = static_cast<double>(curr->fPoint.fY) - prev->fPoint.fY;
         double bx = static_cast<double>(next->fPoint.fX) - curr->fPoint.fX;
         double by = static_cast<double>(next->fPoint.fY) - curr->fPoint.fY;
         if (ax * by - ay * bx >= 0.0) {
-            data = this->emitTriangle(prev, curr, next, monotonePoly->fWinding, data);
+            data = this->emitTriangle(prev, curr, next, monotonePoly->fWinding, data,
+                                      breadcrumbList);
             v->fPrev->fNext = v->fNext;
             v->fNext->fPrev = v->fPrev;
             count--;
@@ -252,17 +255,17 @@
 }
 
 void* GrTriangulator::emitTriangle(Vertex* prev, Vertex* curr, Vertex* next, int winding,
-                                   void* data) const {
+                                   void* data, BreadcrumbTriangleList* breadcrumbList) const {
     if (winding > 0) {
         // Ensure our triangles always wind in the same direction as if the path had been
         // triangulated as a simple fan (a la red book).
         std::swap(prev, next);
     }
-    if (fBreadcrumbTriangles && abs(winding) > 1 &&
+    if (breadcrumbList && abs(winding) > 1 &&
         fPath.getFillType() == SkPathFillType::kWinding) {
         // The first winding count will come from the actual triangle we emit. The remaining counts
         // come from the breadcrumb triangle.
-        fBreadcrumbTriangles->push(prev->fPoint, curr->fPoint, next->fPoint, abs(winding) - 1);
+        breadcrumbList->prepend(fAlloc, prev->fPoint, curr->fPoint, next->fPoint, abs(winding) - 1);
     }
     return emit_triangle(prev, curr, next, fEmitCoverage, data);
 }
@@ -308,13 +311,14 @@
     }
     return poly;
 }
-void* GrTriangulator::emitPoly(const Poly* poly, void *data) {
+void* GrTriangulator::emitPoly(const Poly* poly, void *data,
+                               BreadcrumbTriangleList* breadcrumbList) const {
     if (poly->fCount < 3) {
         return data;
     }
     TESS_LOG("emit() %d, size %d\n", fID, fCount);
     for (MonotonePoly* m = poly->fHead; m != nullptr; m = m->fNext) {
-        data = this->emitMonotonePoly(m, data);
+        data = this->emitMonotonePoly(m, data, breadcrumbList);
     }
     return data;
 }
@@ -323,14 +327,14 @@
     return a == b;
 }
 
-Poly* GrTriangulator::makePoly(Poly** head, Vertex* v, int winding) {
+Poly* GrTriangulator::makePoly(Poly** head, Vertex* v, int winding) const {
     Poly* poly = fAlloc->make<Poly>(v, winding);
     poly->fNext = *head;
     *head = poly;
     return poly;
 }
 
-void GrTriangulator::appendPointToContour(const SkPoint& p, VertexList* contour) {
+void GrTriangulator::appendPointToContour(const SkPoint& p, VertexList* contour) const {
     Vertex* v = fAlloc->make<Vertex>(p, 255);
 #if TRIANGULATOR_LOGGING
     static float gID = 0.0f;
@@ -351,7 +355,7 @@
 }
 
 void GrTriangulator::appendQuadraticToContour(const SkPoint pts[3], SkScalar toleranceSqd,
-                                              VertexList* contour) {
+                                              VertexList* contour) const {
     SkQuadCoeff quad(pts);
     Sk2s aa = quad.fA * quad.fA;
     SkScalar denom = 2.0f * (aa[0] + aa[1]);
@@ -375,7 +379,7 @@
 
 void GrTriangulator::generateCubicPoints(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2,
                                          const SkPoint& p3, SkScalar tolSqd, VertexList* contour,
-                                         int pointsLeft) {
+                                         int pointsLeft) const {
     SkScalar d1 = SkPointPriv::DistanceToLineSegmentBetweenSqd(p1, p0, p3);
     SkScalar d2 = SkPointPriv::DistanceToLineSegmentBetweenSqd(p2, p0, p3);
     if (pointsLeft < 2 || (d1 < tolSqd && d2 < tolSqd) ||
@@ -401,7 +405,7 @@
 // Stage 1: convert the input path to a set of linear contours (linked list of Vertices).
 
 void GrTriangulator::pathToContours(float tolerance, const SkRect& clipBounds,
-                                    VertexList* contours, bool* isLinear) {
+                                    VertexList* contours, bool* isLinear) const {
     SkScalar toleranceSqd = tolerance * tolerance;
     SkPoint pts[4];
     *isLinear = true;
@@ -486,7 +490,7 @@
     }
 }
 
-bool GrTriangulator::applyFillType(int winding) {
+bool GrTriangulator::applyFillType(int winding) const {
     return apply_fill_type(fPath.getFillType(), winding);
 }
 
@@ -494,7 +498,8 @@
     return poly && apply_fill_type(fillType, poly->fWinding);
 }
 
-Edge* GrTriangulator::makeEdge(Vertex* prev, Vertex* next, EdgeType type, const Comparator& c) {
+Edge* GrTriangulator::makeEdge(Vertex* prev, Vertex* next, EdgeType type,
+                               const Comparator& c) const {
     SkASSERT(prev->fPoint != next->fPoint);
     int winding = c.sweep_lt(prev->fPoint, next->fPoint) ? 1 : -1;
     Vertex* top = winding < 0 ? next : prev;
@@ -649,35 +654,36 @@
 }
 
 void GrTriangulator::setTop(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current,
-                            const Comparator& c) {
+                            const Comparator& c, BreadcrumbTriangleList* breadcrumbList) const {
     remove_edge_below(edge);
-    if (fBreadcrumbTriangles) {
-        fBreadcrumbTriangles->push(edge->fTop->fPoint, edge->fBottom->fPoint, v->fPoint,
-                                   edge->fWinding);
+    if (breadcrumbList) {
+        breadcrumbList->prepend(fAlloc, edge->fTop->fPoint, edge->fBottom->fPoint, v->fPoint,
+                                edge->fWinding);
     }
     edge->fTop = v;
     edge->recompute();
     edge->insertBelow(v, c);
     rewind_if_necessary(edge, activeEdges, current, c);
-    this->mergeCollinearEdges(edge, activeEdges, current, c);
+    this->mergeCollinearEdges(edge, activeEdges, current, c, breadcrumbList);
 }
 
 void GrTriangulator::setBottom(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current,
-                               const Comparator& c) {
+                               const Comparator& c, BreadcrumbTriangleList* breadcrumbList) const {
     remove_edge_above(edge);
-    if (fBreadcrumbTriangles) {
-        fBreadcrumbTriangles->push(edge->fTop->fPoint, edge->fBottom->fPoint, v->fPoint,
-                                   edge->fWinding);
+    if (breadcrumbList) {
+        breadcrumbList->prepend(fAlloc, edge->fTop->fPoint, edge->fBottom->fPoint, v->fPoint,
+                                edge->fWinding);
     }
     edge->fBottom = v;
     edge->recompute();
     edge->insertAbove(v, c);
     rewind_if_necessary(edge, activeEdges, current, c);
-    this->mergeCollinearEdges(edge, activeEdges, current, c);
+    this->mergeCollinearEdges(edge, activeEdges, current, c, breadcrumbList);
 }
 
 void GrTriangulator::mergeEdgesAbove(Edge* edge, Edge* other, EdgeList* activeEdges,
-                                     Vertex** current, const Comparator& c) {
+                                     Vertex** current, const Comparator& c,
+                                     BreadcrumbTriangleList* breadcrumbList) const {
     if (coincident(edge->fTop->fPoint, other->fTop->fPoint)) {
         TESS_LOG("merging coincident above edges (%g, %g) -> (%g, %g)\n",
                  edge->fTop->fPoint.fX, edge->fTop->fPoint.fY,
@@ -689,16 +695,17 @@
     } else if (c.sweep_lt(edge->fTop->fPoint, other->fTop->fPoint)) {
         rewind(activeEdges, current, edge->fTop, c);
         other->fWinding += edge->fWinding;
-        this->setBottom(edge, other->fTop, activeEdges, current, c);
+        this->setBottom(edge, other->fTop, activeEdges, current, c, breadcrumbList);
     } else {
         rewind(activeEdges, current, other->fTop, c);
         edge->fWinding += other->fWinding;
-        this->setBottom(other, edge->fTop, activeEdges, current, c);
+        this->setBottom(other, edge->fTop, activeEdges, current, c, breadcrumbList);
     }
 }
 
 void GrTriangulator::mergeEdgesBelow(Edge* edge, Edge* other, EdgeList* activeEdges,
-                                     Vertex** current, const Comparator& c) {
+                                     Vertex** current, const Comparator& c,
+                                     BreadcrumbTriangleList* breadcrumbList) const {
     if (coincident(edge->fBottom->fPoint, other->fBottom->fPoint)) {
         TESS_LOG("merging coincident below edges (%g, %g) -> (%g, %g)\n",
                  edge->fTop->fPoint.fX, edge->fTop->fPoint.fY,
@@ -710,11 +717,11 @@
     } else if (c.sweep_lt(edge->fBottom->fPoint, other->fBottom->fPoint)) {
         rewind(activeEdges, current, other->fTop, c);
         edge->fWinding += other->fWinding;
-        this->setTop(other, edge->fBottom, activeEdges, current, c);
+        this->setTop(other, edge->fBottom, activeEdges, current, c, breadcrumbList);
     } else {
         rewind(activeEdges, current, edge->fTop, c);
         other->fWinding += edge->fWinding;
-        this->setTop(edge, other->fBottom, activeEdges, current, c);
+        this->setTop(edge, other->fBottom, activeEdges, current, c, breadcrumbList);
     }
 }
 
@@ -735,16 +742,21 @@
 }
 
 void GrTriangulator::mergeCollinearEdges(Edge* edge, EdgeList* activeEdges, Vertex** current,
-                                         const Comparator& c) {
+                                         const Comparator& c,
+                                         BreadcrumbTriangleList* breadcrumbList) const {
     for (;;) {
         if (top_collinear(edge->fPrevEdgeAbove, edge)) {
-            this->mergeEdgesAbove(edge->fPrevEdgeAbove, edge, activeEdges, current, c);
+            this->mergeEdgesAbove(edge->fPrevEdgeAbove, edge, activeEdges, current, c,
+                                  breadcrumbList);
         } else if (top_collinear(edge, edge->fNextEdgeAbove)) {
-            this->mergeEdgesAbove(edge->fNextEdgeAbove, edge, activeEdges, current, c);
+            this->mergeEdgesAbove(edge->fNextEdgeAbove, edge, activeEdges, current, c,
+                                  breadcrumbList);
         } else if (bottom_collinear(edge->fPrevEdgeBelow, edge)) {
-            this->mergeEdgesBelow(edge->fPrevEdgeBelow, edge, activeEdges, current, c);
+            this->mergeEdgesBelow(edge->fPrevEdgeBelow, edge, activeEdges, current, c,
+                                  breadcrumbList);
         } else if (bottom_collinear(edge, edge->fNextEdgeBelow)) {
-            this->mergeEdgesBelow(edge->fNextEdgeBelow, edge, activeEdges, current, c);
+            this->mergeEdgesBelow(edge->fNextEdgeBelow, edge, activeEdges, current, c,
+                                  breadcrumbList);
         } else {
             break;
         }
@@ -756,7 +768,7 @@
 }
 
 bool GrTriangulator::splitEdge(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current,
-                               const Comparator& c) {
+                               const Comparator& c, BreadcrumbTriangleList* breadcrumbList) const {
     if (!edge->fTop || !edge->fBottom || v == edge->fTop || v == edge->fBottom) {
         return false;
     }
@@ -768,25 +780,26 @@
     if (c.sweep_lt(v->fPoint, edge->fTop->fPoint)) {
         top = v;
         bottom = edge->fTop;
-        this->setTop(edge, v, activeEdges, current, c);
+        this->setTop(edge, v, activeEdges, current, c, breadcrumbList);
     } else if (c.sweep_lt(edge->fBottom->fPoint, v->fPoint)) {
         top = edge->fBottom;
         bottom = v;
-        this->setBottom(edge, v, activeEdges, current, c);
+        this->setBottom(edge, v, activeEdges, current, c, breadcrumbList);
     } else {
         top = v;
         bottom = edge->fBottom;
-        this->setBottom(edge, v, activeEdges, current, c);
+        this->setBottom(edge, v, activeEdges, current, c, breadcrumbList);
     }
     Edge* newEdge = fAlloc->make<Edge>(top, bottom, winding, edge->fType);
     newEdge->insertBelow(top, c);
     newEdge->insertAbove(bottom, c);
-    this->mergeCollinearEdges(newEdge, activeEdges, current, c);
+    this->mergeCollinearEdges(newEdge, activeEdges, current, c, breadcrumbList);
     return true;
 }
 
 bool GrTriangulator::intersectEdgePair(Edge* left, Edge* right, EdgeList* activeEdges,
-                                       Vertex** current, const Comparator& c) {
+                                       Vertex** current, const Comparator& c,
+                                       BreadcrumbTriangleList* breadcrumbList) const {
     if (!left->fTop || !left->fBottom || !right->fTop || !right->fBottom) {
         return false;
     }
@@ -796,30 +809,32 @@
     if (c.sweep_lt(left->fTop->fPoint, right->fTop->fPoint)) {
         if (!left->isLeftOf(right->fTop)) {
             rewind(activeEdges, current, right->fTop, c);
-            return this->splitEdge(left, right->fTop, activeEdges, current, c);
+            return this->splitEdge(left, right->fTop, activeEdges, current, c, breadcrumbList);
         }
     } else {
         if (!right->isRightOf(left->fTop)) {
             rewind(activeEdges, current, left->fTop, c);
-            return this->splitEdge(right, left->fTop, activeEdges, current, c);
+            return this->splitEdge(right, left->fTop, activeEdges, current, c, breadcrumbList);
         }
     }
     if (c.sweep_lt(right->fBottom->fPoint, left->fBottom->fPoint)) {
         if (!left->isLeftOf(right->fBottom)) {
             rewind(activeEdges, current, right->fBottom, c);
-            return this->splitEdge(left, right->fBottom, activeEdges, current, c);
+            return this->splitEdge(left, right->fBottom, activeEdges, current, c, breadcrumbList);
         }
     } else {
         if (!right->isRightOf(left->fBottom)) {
             rewind(activeEdges, current, left->fBottom, c);
-            return this->splitEdge(right, left->fBottom, activeEdges, current, c);
+            return this->splitEdge(right, left->fBottom, activeEdges, current, c, breadcrumbList);
         }
     }
     return false;
 }
 
 Edge* GrTriangulator::makeConnectingEdge(Vertex* prev, Vertex* next, EdgeType type,
-                                         const Comparator& c, int windingScale) {
+                                         const Comparator& c,
+                                         BreadcrumbTriangleList* breadcrumbList,
+                                         int windingScale) const {
     if (!prev || !next || prev->fPoint == next->fPoint) {
         return nullptr;
     }
@@ -827,12 +842,13 @@
     edge->insertBelow(edge->fTop, c);
     edge->insertAbove(edge->fBottom, c);
     edge->fWinding *= windingScale;
-    this->mergeCollinearEdges(edge, nullptr, nullptr, c);
+    this->mergeCollinearEdges(edge, nullptr, nullptr, c, breadcrumbList);
     return edge;
 }
 
 void GrTriangulator::mergeVertices(Vertex* src, Vertex* dst, VertexList* mesh,
-                                   const Comparator& c) {
+                                   const Comparator& c,
+                                   BreadcrumbTriangleList* breadcrumbList) const {
     TESS_LOG("found coincident verts at %g, %g; merging %g into %g\n",
              src->fPoint.fX, src->fPoint.fY, src->fID, dst->fID);
     dst->fAlpha = std::max(src->fAlpha, dst->fAlpha);
@@ -840,17 +856,17 @@
         src->fPartner->fPartner = dst;
     }
     while (Edge* edge = src->fFirstEdgeAbove) {
-        this->setBottom(edge, dst, nullptr, nullptr, c);
+        this->setBottom(edge, dst, nullptr, nullptr, c, breadcrumbList);
     }
     while (Edge* edge = src->fFirstEdgeBelow) {
-        this->setTop(edge, dst, nullptr, nullptr, c);
+        this->setTop(edge, dst, nullptr, nullptr, c, breadcrumbList);
     }
     mesh->remove(src);
     dst->fSynthetic = true;
 }
 
 Vertex* GrTriangulator::makeSortedVertex(const SkPoint& p, uint8_t alpha, VertexList* mesh,
-                                         Vertex* reference, const Comparator& c) {
+                                         Vertex* reference, const Comparator& c) const {
     Vertex* prevV = reference;
     while (prevV && c.sweep_lt(p, prevV->fPoint)) {
         prevV = prevV->fPrev;
@@ -900,7 +916,7 @@
     }
 }
 
-void GrTriangulator::computeBisector(Edge* edge1, Edge* edge2, Vertex* v) {
+void GrTriangulator::computeBisector(Edge* edge1, Edge* edge2, Vertex* v) const {
     SkASSERT(fEmitCoverage);  // Edge-AA only!
     Line line1 = edge1->fLine;
     Line line2 = edge2->fLine;
@@ -921,7 +937,8 @@
 }
 
 bool GrTriangulator::checkForIntersection(Edge* left, Edge* right, EdgeList* activeEdges,
-                                          Vertex** current, VertexList* mesh, const Comparator& c) {
+                                          Vertex** current, VertexList* mesh, const Comparator& c,
+                                          BreadcrumbTriangleList* breadcrumbList) const {
     if (!left || !right) {
         return false;
     }
@@ -959,15 +976,15 @@
             }
         }
         rewind(activeEdges, current, top ? top : v, c);
-        this->splitEdge(left, v, activeEdges, current, c);
-        this->splitEdge(right, v, activeEdges, current, c);
+        this->splitEdge(left, v, activeEdges, current, c, breadcrumbList);
+        this->splitEdge(right, v, activeEdges, current, c, breadcrumbList);
         v->fAlpha = std::max(v->fAlpha, alpha);
         return true;
     }
-    return this->intersectEdgePair(left, right, activeEdges, current, c);
+    return this->intersectEdgePair(left, right, activeEdges, current, c, breadcrumbList);
 }
 
-void GrTriangulator::sanitizeContours(VertexList* contours, int contourCnt) {
+void GrTriangulator::sanitizeContours(VertexList* contours, int contourCnt) const {
     for (VertexList* contour = contours; contourCnt > 0; --contourCnt, ++contour) {
         SkASSERT(contour->fHead);
         Vertex* prev = contour->fTail;
@@ -998,7 +1015,8 @@
     }
 }
 
-bool GrTriangulator::mergeCoincidentVertices(VertexList* mesh, const Comparator& c) {
+bool GrTriangulator::mergeCoincidentVertices(VertexList* mesh, const Comparator& c,
+                                             BreadcrumbTriangleList* breadcrumbList) const {
     if (!mesh->fHead) {
         return false;
     }
@@ -1009,7 +1027,7 @@
             v->fPoint = v->fPrev->fPoint;
         }
         if (coincident(v->fPrev->fPoint, v->fPoint)) {
-            this->mergeVertices(v, v->fPrev, mesh, c);
+            this->mergeVertices(v, v->fPrev, mesh, c, breadcrumbList);
             merged = true;
         }
         v = next;
@@ -1020,12 +1038,12 @@
 // Stage 2: convert the contours to a mesh of edges connecting the vertices.
 
 void GrTriangulator::buildEdges(VertexList* contours, int contourCnt, VertexList* mesh,
-                                const Comparator& c) {
+                                const Comparator& c, BreadcrumbTriangleList* breadcrumbList) const {
     for (VertexList* contour = contours; contourCnt > 0; --contourCnt, ++contour) {
         Vertex* prev = contour->fTail;
         for (Vertex* v = contour->fHead; v;) {
             Vertex* next = v->fNext;
-            this->makeConnectingEdge(prev, v, EdgeType::kInner, c);
+            this->makeConnectingEdge(prev, v, EdgeType::kInner, c, breadcrumbList);
             mesh->append(v);
             prev = v;
             v = next;
@@ -1098,7 +1116,7 @@
 }
 
 #if TRIANGULATOR_LOGGING
-void VertexList::dump() {
+void VertexList::dump() const {
     for (Vertex* v = fHead; v; v = v->fNext) {
         TESS_LOG("vertex %g (%g, %g) alpha %d", v->fID, v->fPoint.fX, v->fPoint.fY, v->fAlpha);
         if (Vertex* p = v->fPartner) {
@@ -1154,7 +1172,8 @@
 
 // Stage 4: Simplify the mesh by inserting new vertices at intersecting edges.
 
-GrTriangulator::SimplifyResult GrTriangulator::simplify(VertexList* mesh, const Comparator& c) {
+GrTriangulator::SimplifyResult GrTriangulator::simplify(
+        VertexList* mesh, const Comparator& c, BreadcrumbTriangleList* breadcrumbList) const {
     TESS_LOG("simplifying complex polygons\n");
     EdgeList activeEdges;
     auto result = SimplifyResult::kAlreadySimple;
@@ -1175,9 +1194,9 @@
             if (v->fFirstEdgeBelow) {
                 for (Edge* edge = v->fFirstEdgeBelow; edge; edge = edge->fNextEdgeBelow) {
                     if (this->checkForIntersection(
-                            leftEnclosingEdge, edge, &activeEdges, &v, mesh, c) ||
+                            leftEnclosingEdge, edge, &activeEdges, &v, mesh, c, breadcrumbList) ||
                         this->checkForIntersection(
-                            edge, rightEnclosingEdge, &activeEdges, &v, mesh, c)) {
+                            edge, rightEnclosingEdge, &activeEdges, &v, mesh, c, breadcrumbList)) {
                         if (fDisallowSelfIntersection) {
                             return SimplifyResult::kAbort;
                         }
@@ -1188,7 +1207,7 @@
                 }
             } else {
                 if (this->checkForIntersection(leftEnclosingEdge, rightEnclosingEdge, &activeEdges,
-                                               &v, mesh, c)) {
+                                               &v, mesh, c, breadcrumbList)) {
                     if (fDisallowSelfIntersection) {
                         return SimplifyResult::kAbort;
                     }
@@ -1216,7 +1235,7 @@
 
 // Stage 5: Tessellate the simplified mesh into monotone polygons.
 
-Poly* GrTriangulator::tessellate(const VertexList& vertices, const Comparator&) {
+Poly* GrTriangulator::tessellate(const VertexList& vertices, const Comparator&) const {
     TESS_LOG("\ntessellating simple polygons\n");
     int maxWindMagnitude = std::numeric_limits<int>::max();
     if (fDisallowSelfIntersection && !SkPathFillType_IsEvenOdd(fPath.getFillType())) {
@@ -1340,7 +1359,8 @@
 // This is a driver function that calls stages 2-5 in turn.
 
 void GrTriangulator::contoursToMesh(VertexList* contours, int contourCnt, VertexList* mesh,
-                                    const Comparator& c) {
+                                    const Comparator& c,
+                                    BreadcrumbTriangleList* breadcrumbList) const {
 #if TRIANGULATOR_LOGGING
     for (int i = 0; i < contourCnt; ++i) {
         Vertex* v = contours[i].fHead;
@@ -1352,7 +1372,7 @@
     }
 #endif
     this->sanitizeContours(contours, contourCnt);
-    this->buildEdges(contours, contourCnt, mesh, c);
+    this->buildEdges(contours, contourCnt, mesh, c, breadcrumbList);
 }
 
 void GrTriangulator::SortMesh(VertexList* vertices, const Comparator& c) {
@@ -1374,15 +1394,16 @@
 #endif
 }
 
-Poly* GrTriangulator::contoursToPolys(VertexList* contours, int contourCnt) {
+Poly* GrTriangulator::contoursToPolys(VertexList* contours, int contourCnt,
+                                      BreadcrumbTriangleList* breadcrumbList) const {
     const SkRect& pathBounds = fPath.getBounds();
     Comparator c(pathBounds.width() > pathBounds.height() ? Comparator::Direction::kHorizontal
                                                           : Comparator::Direction::kVertical);
     VertexList mesh;
-    this->contoursToMesh(contours, contourCnt, &mesh, c);
+    this->contoursToMesh(contours, contourCnt, &mesh, c, breadcrumbList);
     SortMesh(&mesh, c);
-    this->mergeCoincidentVertices(&mesh, c);
-    if (SimplifyResult::kAbort == this->simplify(&mesh, c)) {
+    this->mergeCoincidentVertices(&mesh, c, breadcrumbList);
+    if (SimplifyResult::kAbort == this->simplify(&mesh, c, breadcrumbList)) {
         return nullptr;
     }
     TESS_LOG("\nsimplified mesh:\n");
@@ -1391,10 +1412,12 @@
 }
 
 // Stage 6: Triangulate the monotone polygons into a vertex buffer.
-void* GrTriangulator::polysToTriangles(Poly* polys, void* data, SkPathFillType overrideFillType) {
+void* GrTriangulator::polysToTriangles(Poly* polys, void* data,
+                                       BreadcrumbTriangleList* breadcrumbList,
+                                       SkPathFillType overrideFillType) const {
     for (Poly* poly = polys; poly; poly = poly->fNext) {
         if (apply_fill_type(overrideFillType, poly)) {
-            data = this->emitPoly(poly, data);
+            data = this->emitPoly(poly, data, breadcrumbList);
         }
     }
     return data;
@@ -1434,7 +1457,8 @@
     return contourCnt;
 }
 
-Poly* GrTriangulator::pathToPolys(float tolerance, const SkRect& clipBounds, bool* isLinear) {
+Poly* GrTriangulator::pathToPolys(float tolerance, const SkRect& clipBounds,
+                                  BreadcrumbTriangleList* breadcrumbList, bool* isLinear) const {
     int contourCnt = get_contour_count(fPath, tolerance);
     if (contourCnt <= 0) {
         *isLinear = true;
@@ -1447,7 +1471,7 @@
     std::unique_ptr<VertexList[]> contours(new VertexList[contourCnt]);
 
     this->pathToContours(tolerance, clipBounds, contours.get(), isLinear);
-    return this->contoursToPolys(contours.get(), contourCnt);
+    return this->contoursToPolys(contours.get(), contourCnt, breadcrumbList);
 }
 
 int64_t GrTriangulator::CountPoints(Poly* polys, SkPathFillType overrideFillType) {
@@ -1462,7 +1486,8 @@
 
 // Stage 6: Triangulate the monotone polygons into a vertex buffer.
 
-int GrTriangulator::polysToTriangles(Poly* polys, GrEagerVertexAllocator* vertexAllocator) {
+int GrTriangulator::polysToTriangles(Poly* polys, GrEagerVertexAllocator* vertexAllocator,
+                                     BreadcrumbTriangleList* breadcrumbList) const {
     int64_t count64 = CountPoints(polys, fPath.getFillType());
     if (0 == count64 || count64 > SK_MaxS32) {
         return 0;
@@ -1480,7 +1505,7 @@
     }
 
     TESS_LOG("emitting %d verts\n", count);
-    void* end = this->polysToTriangles(polys, verts, fPath.getFillType());
+    void* end = this->polysToTriangles(polys, verts, breadcrumbList, fPath.getFillType());
 
     int actualCount = static_cast<int>((static_cast<uint8_t*>(end) - static_cast<uint8_t*>(verts))
                                        / vertexStride);
@@ -1494,7 +1519,7 @@
     SkArenaAlloc alloc(kArenaDefaultChunkSize);
     GrTriangulator triangulator(path, &alloc);
     bool isLinear;
-    Poly* polys = triangulator.pathToPolys(tolerance, clipBounds, &isLinear);
+    Poly* polys = triangulator.pathToPolys(tolerance, clipBounds, nullptr, &isLinear);
     int64_t count64 = CountPoints(polys, path.getFillType());
     if (0 == count64 || count64 > SK_MaxS32) {
         *verts = nullptr;
@@ -1509,7 +1534,7 @@
     for (Poly* poly = polys; poly; poly = poly->fNext) {
         if (apply_fill_type(path.getFillType(), poly)) {
             SkPoint* start = pointsEnd;
-            pointsEnd = static_cast<SkPoint*>(triangulator.emitPoly(poly, pointsEnd));
+            pointsEnd = static_cast<SkPoint*>(triangulator.emitPoly(poly, pointsEnd, nullptr));
             while (start != pointsEnd) {
                 vertsEnd->fPos = *start;
                 vertsEnd->fWinding = poly->fWinding;