use pathbuilder

Change-Id: I4b7cd6aed0c8da44e6065bb171332e25988ec8cc
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/313376
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Mike Reed <reed@google.com>
diff --git a/BUILD.gn b/BUILD.gn
index d4dc462..98f940e 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -1276,6 +1276,7 @@
     "src/core/SkOpts.cpp",
     "src/core/SkPaint.cpp",
     "src/core/SkPath.cpp",
+    "src/core/SkPathBuilder.cpp",
     "src/core/SkPathEffect.cpp",
     "src/core/SkPathMeasure.cpp",
     "src/core/SkPathRef.cpp",
diff --git a/gm/blurrect.cpp b/gm/blurrect.cpp
index 1208afa..35ef0f6 100644
--- a/gm/blurrect.cpp
+++ b/gm/blurrect.cpp
@@ -16,7 +16,7 @@
 #include "include/core/SkMaskFilter.h"
 #include "include/core/SkMatrix.h"
 #include "include/core/SkPaint.h"
-#include "include/core/SkPath.h"
+#include "include/core/SkPathBuilder.h"
 #include "include/core/SkPoint.h"
 #include "include/core/SkRect.h"
 #include "include/core/SkRefCnt.h"
@@ -44,8 +44,8 @@
 }
 
 static void draw_donut(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
-    SkRect  rect;
-    SkPath  path;
+    SkRect        rect;
+    SkPathBuilder path;
 
     rect = r;
     rect.outset(STROKE_WIDTH/2, STROKE_WIDTH/2);
@@ -56,12 +56,12 @@
     path.addRect(rect);
     path.setFillType(SkPathFillType::kEvenOdd);
 
-    canvas->drawPath(path, p);
+    canvas->drawPath(path.detach(), p);
 }
 
 static void draw_donut_skewed(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
-    SkRect  rect;
-    SkPath  path;
+    SkRect        rect;
+    SkPathBuilder path;
 
     rect = r;
     rect.outset(STROKE_WIDTH/2, STROKE_WIDTH/2);
@@ -74,7 +74,7 @@
     path.addRect(rect);
     path.setFillType(SkPathFillType::kEvenOdd);
 
-    canvas->drawPath(path, p);
+    canvas->drawPath(path.detach(), p);
 }
 
 /*
diff --git a/gm/blurs.cpp b/gm/blurs.cpp
index e6f6910..f79188f 100644
--- a/gm/blurs.cpp
+++ b/gm/blurs.cpp
@@ -12,7 +12,7 @@
 #include "include/core/SkFont.h"
 #include "include/core/SkMaskFilter.h"
 #include "include/core/SkPaint.h"
-#include "include/core/SkPath.h"
+#include "include/core/SkPathBuilder.h"
 #include "include/core/SkRect.h"
 #include "include/core/SkRefCnt.h"
 #include "include/core/SkScalar.h"
@@ -82,43 +82,43 @@
 // is translated a fractional amount.
 //
 DEF_SIMPLE_GM(blur2rects, canvas, 700, 500) {
-        SkPaint paint;
+    SkPaint paint;
 
-        paint.setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, 2.3f));
+    paint.setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, 2.3f));
 
-        SkRect outer = SkRect::MakeXYWH(10.125f, 10.125f, 100.125f, 100);
-        SkRect inner = SkRect::MakeXYWH(20.25f, 20.125f, 80, 80);
-        SkPath path;
-        path.addRect(outer, SkPathDirection::kCW);
-        path.addRect(inner, SkPathDirection::kCCW);
+    SkRect outer = SkRect::MakeXYWH(10.125f, 10.125f, 100.125f, 100);
+    SkRect inner = SkRect::MakeXYWH(20.25f, 20.125f, 80, 80);
+    SkPath path = SkPathBuilder().addRect(outer, SkPathDirection::kCW)
+                                 .addRect(inner, SkPathDirection::kCCW)
+                                 .detach();
 
-        canvas->drawPath(path, paint);
-        // important to translate by a factional amount to exercise a different "phase"
-        // of the same path w.r.t. the pixel grid
-        SkScalar dx = SkScalarRoundToScalar(path.getBounds().width()) + 14 + 0.25f;
-        canvas->translate(dx, 0);
-        canvas->drawPath(path, paint);
+    canvas->drawPath(path, paint);
+    // important to translate by a factional amount to exercise a different "phase"
+    // of the same path w.r.t. the pixel grid
+    SkScalar dx = SkScalarRoundToScalar(path.getBounds().width()) + 14 + 0.25f;
+    canvas->translate(dx, 0);
+    canvas->drawPath(path, paint);
 }
 
 DEF_SIMPLE_GM(blur2rectsnonninepatch, canvas, 700, 500) {
-        SkPaint paint;
-        paint.setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, 4.3f));
+    SkPaint paint;
+    paint.setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, 4.3f));
 
-        SkRect outer = SkRect::MakeXYWH(10, 110, 100, 100);
-        SkRect inner = SkRect::MakeXYWH(50, 150, 10, 10);
-        SkPath path;
-        path.addRect(outer, SkPathDirection::kCW);
-        path.addRect(inner, SkPathDirection::kCW);
-        canvas->drawPath(path, paint);
+    SkRect outer = SkRect::MakeXYWH(10, 110, 100, 100);
+    SkRect inner = SkRect::MakeXYWH(50, 150, 10, 10);
+    SkPath path = SkPathBuilder().addRect(outer, SkPathDirection::kCW)
+                                 .addRect(inner, SkPathDirection::kCW)
+                                 .detach();
+    canvas->drawPath(path, paint);
 
-        SkScalar dx = SkScalarRoundToScalar(path.getBounds().width()) + 40 + 0.25f;
-        canvas->translate(dx, 0);
-        canvas->drawPath(path, paint);
+    SkScalar dx = SkScalarRoundToScalar(path.getBounds().width()) + 40 + 0.25f;
+    canvas->translate(dx, 0);
+    canvas->drawPath(path, paint);
 
-        // Translate to outside of clip bounds.
-        canvas->translate(-dx, 0);
-        canvas->translate(-30, -150);
-        canvas->drawPath(path, paint);
+    // Translate to outside of clip bounds.
+    canvas->translate(-dx, 0);
+    canvas->translate(-30, -150);
+    canvas->drawPath(path, paint);
 }
 
 DEF_SIMPLE_GM(BlurDrawImage, canvas, 256, 256) {
diff --git a/gm/circulararcs.cpp b/gm/circulararcs.cpp
index 13dae6d..764fdd1 100644
--- a/gm/circulararcs.cpp
+++ b/gm/circulararcs.cpp
@@ -9,7 +9,7 @@
 #include "include/core/SkCanvas.h"
 #include "include/core/SkColor.h"
 #include "include/core/SkPaint.h"
-#include "include/core/SkPath.h"
+#include "include/core/SkPathBuilder.h"
 #include "include/core/SkPathEffect.h"
 #include "include/core/SkRect.h"
 #include "include/core/SkScalar.h"
@@ -229,7 +229,7 @@
 }
 
 DEF_SIMPLE_GM(onebadarc, canvas, 100, 100) {
-    SkPath path;
+    SkPathBuilder path;
     path.moveTo(SkBits2Float(0x41a00000), SkBits2Float(0x41a00000));  // 20, 20
     path.lineTo(SkBits2Float(0x4208918c), SkBits2Float(0x4208918c));  // 34.1421f, 34.1421f
     path.conicTo(SkBits2Float(0x41a00000), SkBits2Float(0x42412318),  // 20, 48.2843f
@@ -245,7 +245,7 @@
     p0.setStroke(true);
     p0.setAlpha(100);
     canvas->translate(20, 0);
-    canvas->drawPath(path, p0);
+    canvas->drawPath(path.detach(), p0);
 
     SkRect kRect = { 60, 0, 100, 40};
     canvas->drawArc(kRect, 45, 90, true, p0);
diff --git a/gm/dashing.cpp b/gm/dashing.cpp
index 578572c..c6b53f1 100644
--- a/gm/dashing.cpp
+++ b/gm/dashing.cpp
@@ -11,7 +11,7 @@
 #include "include/core/SkFont.h"
 #include "include/core/SkMatrix.h"
 #include "include/core/SkPaint.h"
-#include "include/core/SkPath.h"
+#include "include/core/SkPathBuilder.h"
 #include "include/core/SkPathEffect.h"
 #include "include/core/SkPoint.h"
 #include "include/core/SkRect.h"
@@ -105,36 +105,38 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-static void make_unit_star(SkPath* path, int n) {
+static SkPath make_unit_star(int n) {
     SkScalar rad = -SK_ScalarPI / 2;
     const SkScalar drad = (n >> 1) * SK_ScalarPI * 2 / n;
 
-    path->moveTo(0, -SK_Scalar1);
+    SkPathBuilder b;
+    b.moveTo(0, -SK_Scalar1);
     for (int i = 1; i < n; i++) {
         rad += drad;
-        path->lineTo(SkScalarCos(rad), SkScalarSin(rad));
+        b.lineTo(SkScalarCos(rad), SkScalarSin(rad));
     }
-    path->close();
+    return b.close().detach();
 }
 
-static void make_path_line(SkPath* path, const SkRect& bounds) {
-    path->moveTo(bounds.left(), bounds.top());
-    path->lineTo(bounds.right(), bounds.bottom());
+static SkPath make_path_line(const SkRect& bounds) {
+    return SkPathBuilder().moveTo(bounds.left(), bounds.top())
+                          .lineTo(bounds.right(), bounds.bottom())
+                          .detach();
 }
 
-static void make_path_rect(SkPath* path, const SkRect& bounds) {
-    path->addRect(bounds);
+static SkPath make_path_rect(const SkRect& bounds) {
+    return SkPath::Rect(bounds);
 }
 
-static void make_path_oval(SkPath* path, const SkRect& bounds) {
-    path->addOval(bounds);
+static SkPath make_path_oval(const SkRect& bounds) {
+    return SkPath::Oval(bounds);
 }
 
-static void make_path_star(SkPath* path, const SkRect& bounds) {
-    make_unit_star(path, 5);
+static SkPath make_path_star(const SkRect& bounds) {
+    SkPath path = make_unit_star(5);
     SkMatrix matrix;
-    matrix.setRectToRect(path->getBounds(), bounds, SkMatrix::kCenter_ScaleToFit);
-    path->transform(matrix);
+    matrix.setRectToRect(path.getBounds(), bounds, SkMatrix::kCenter_ScaleToFit);
+    return path.makeTransform(matrix);
 }
 
 class Dashing2GM : public skiagm::GM {
@@ -150,7 +152,7 @@
             2,  2, 2
         };
 
-        void (*gProc[])(SkPath*, const SkRect&) = {
+        SkPath (*gProc[])(const SkRect&) = {
             make_path_line, make_path_rect, make_path_oval, make_path_star,
         };
 
@@ -178,9 +180,7 @@
                 SkPath path;
                 SkRect r = bounds;
                 r.offset(x * dx, y * dy);
-                gProc[x](&path, r);
-
-                canvas->drawPath(path, paint);
+                canvas->drawPath(gProc[x](r), paint);
             }
         }
     }
diff --git a/gm/dstreadshuffle.cpp b/gm/dstreadshuffle.cpp
index 423588b..4bb233a 100644
--- a/gm/dstreadshuffle.cpp
+++ b/gm/dstreadshuffle.cpp
@@ -14,7 +14,7 @@
 #include "include/core/SkImageInfo.h"
 #include "include/core/SkMatrix.h"
 #include "include/core/SkPaint.h"
-#include "include/core/SkPath.h"
+#include "include/core/SkPathBuilder.h"
 #include "include/core/SkPoint.h"
 #include "include/core/SkRect.h"
 #include "include/core/SkRefCnt.h"
@@ -71,26 +71,29 @@
                 if (fConvexPath.isEmpty()) {
                     SkPoint points[4];
                     kRect.toQuad(points);
-                    fConvexPath.moveTo(points[0]);
-                    fConvexPath.quadTo(points[1], points[2]);
-                    fConvexPath.quadTo(points[3], points[0]);
+                    fConvexPath = SkPathBuilder().moveTo(points[0])
+                                                 .quadTo(points[1], points[2])
+                                                 .quadTo(points[3], points[0])
+                                                 .detach();
                     SkASSERT(fConvexPath.isConvex());
                 }
                 canvas->drawPath(fConvexPath, *paint);
                 break;
             case kConcavePath_ShapeType:
                 if (fConcavePath.isEmpty()) {
+                    SkPathBuilder b;
                     SkPoint points[5] = {{50.f, 0.f}};
                     SkMatrix rot;
                     rot.setRotate(360.f / 5, 50.f, 70.f);
                     for (int i = 1; i < 5; ++i) {
                         rot.mapPoints(points + i, points + i - 1, 1);
                     }
-                    fConcavePath.moveTo(points[0]);
+                    b.moveTo(points[0]);
                     for (int i = 0; i < 5; ++i) {
-                        fConcavePath.lineTo(points[(2 * i) % 5]);
+                        b.lineTo(points[(2 * i) % 5]);
                     }
-                    fConcavePath.setFillType(SkPathFillType::kEvenOdd);
+                    fConcavePath = b.setFillType(SkPathFillType::kEvenOdd)
+                                    .detach();
                     SkASSERT(!fConcavePath.isConvex());
                 }
                 canvas->drawPath(fConcavePath, *paint);
diff --git a/gm/filterfastbounds.cpp b/gm/filterfastbounds.cpp
index c03c25d..ef8ed58 100644
--- a/gm/filterfastbounds.cpp
+++ b/gm/filterfastbounds.cpp
@@ -65,14 +65,11 @@
 }
 
 static void draw_path(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
-    SkPath path;
-
-    path.moveTo(r.fLeft, r.fTop);
-    path.lineTo(r.fLeft, r.fBottom);
-    path.lineTo(r.fRight, r.fBottom);
-    path.close();
-
-    canvas->drawPath(path, p);
+    canvas->drawPath(SkPath::Polygon({
+        {r.fLeft, r.fTop},
+        {r.fLeft, r.fBottom},
+        {r.fRight, r.fBottom},
+    }, true), p);
 }
 
 static void draw_points(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
diff --git a/gm/hittestpath.cpp b/gm/hittestpath.cpp
index ea1d29f..34d45eb 100644
--- a/gm/hittestpath.cpp
+++ b/gm/hittestpath.cpp
@@ -9,7 +9,7 @@
 #include "include/core/SkCanvas.h"
 #include "include/core/SkColor.h"
 #include "include/core/SkPaint.h"
-#include "include/core/SkPath.h"
+#include "include/core/SkPathBuilder.h"
 #include "include/core/SkRect.h"
 #include "include/core/SkScalar.h"
 #include "include/core/SkTypes.h"
@@ -42,7 +42,7 @@
         return skiagm::DrawResult::kSkip;
     }
 
-    SkPath path;
+    SkPathBuilder b;
     SkRandom rand;
 
     int scale = 300;
@@ -52,16 +52,18 @@
         for (int index = 0; index < (int) SK_ARRAY_COUNT(randoms); ++index) {
             randoms[index] = rand.nextUScalar1();
         }
-        path.lineTo(randoms[0] * scale, randoms[1] * scale);
-        path.quadTo(randoms[2] * scale, randoms[3] * scale,
-                    randoms[4] * scale, randoms[5] * scale);
-        path.cubicTo(randoms[6] * scale, randoms[7] * scale,
-                     randoms[8] * scale, randoms[9] * scale,
-                     randoms[10] * scale, randoms[11] * scale);
+        b.lineTo(randoms[0] * scale, randoms[1] * scale)
+         .quadTo(randoms[2] * scale, randoms[3] * scale,
+                 randoms[4] * scale, randoms[5] * scale)
+         .cubicTo(randoms[6] * scale, randoms[7] * scale,
+                  randoms[8] * scale, randoms[9] * scale,
+                  randoms[10] * scale, randoms[11] * scale);
     }
 
-    path.setFillType(SkPathFillType::kEvenOdd);
-    path.offset(SkIntToScalar(20), SkIntToScalar(20));
+    b.setFillType(SkPathFillType::kEvenOdd);
+    b.offset(SkIntToScalar(20), SkIntToScalar(20));
+
+    SkPath path = b.detach();
 
     test_hittest(canvas, path);
 
diff --git a/gm/inverseclip.cpp b/gm/inverseclip.cpp
index 9d7b910..daf0479 100644
--- a/gm/inverseclip.cpp
+++ b/gm/inverseclip.cpp
@@ -7,11 +7,11 @@
 
 #include "gm/gm.h"
 #include "include/core/SkCanvas.h"
-#include "include/core/SkPath.h"
+#include "include/core/SkPathBuilder.h"
 
 // Repro case for http://skbug.com/9453
 DEF_SIMPLE_GM(inverseclip, canvas, 400, 400) {
-    SkPath clip;
+    SkPathBuilder clip;
     clip.setFillType(SkPathFillType::kInverseWinding);
     clip.moveTo(195.448f, 31);
     clip.cubicTo(97.9925f, 31, 18.99f, 105.23f, 18.99f, 196.797f);
@@ -19,7 +19,7 @@
     clip.cubicTo(292.905f, 362.595f, 371.905f, 288.365f, 371.905f, 196.797f);
     clip.cubicTo(371.905f, 105.23f, 292.905f, 31, 195.448f, 31);
     clip.close();
-    canvas->clipPath(clip, true);
+    canvas->clipPath(clip.detach(), true);
 
     SkPaint paint;
     paint.setColor(SK_ColorBLUE);
diff --git a/gm/overstroke.cpp b/gm/overstroke.cpp
index ecac1bb..f3eabfe 100644
--- a/gm/overstroke.cpp
+++ b/gm/overstroke.cpp
@@ -60,14 +60,11 @@
 }
 
 SkPath quad_path() {
-    SkPath path;
-    path.moveTo(0, 0);
-    path.lineTo(100, 0);
-    path.quadTo(50, -40,
-                0, 0);
-    path.close();
-
-    return path;
+    return SkPathBuilder().moveTo(0, 0)
+                          .lineTo(100, 0)
+                          .quadTo(50, -40, 0, 0)
+                          .close()
+                          .detach();
 }
 
 SkPath cubic_path() {
diff --git a/gm/patheffects.cpp b/gm/patheffects.cpp
index a9dde26..5964f32 100644
--- a/gm/patheffects.cpp
+++ b/gm/patheffects.cpp
@@ -9,7 +9,7 @@
 #include "include/core/SkCanvas.h"
 #include "include/core/SkMatrix.h"
 #include "include/core/SkPaint.h"
-#include "include/core/SkPath.h"
+#include "include/core/SkPathBuilder.h"
 #include "include/core/SkPathEffect.h"
 #include "include/core/SkRect.h"
 #include "include/core/SkRefCnt.h"
@@ -66,20 +66,20 @@
 4, 0, 0, -4, 8, -4, 12, 0, 8, 4, 0, 4
 };
 
-static void scale(SkPath* path, SkScalar scale) {
+static SkPath scale(const SkPath& path, SkScalar scale) {
     SkMatrix m;
     m.setScale(scale, scale);
-    path->transform(m);
+    return path.makeTransform(m);
 }
 
 static void one_d_pe(SkPaint* paint) {
-    SkPath  path;
-    path.moveTo(SkIntToScalar(gXY[0]), SkIntToScalar(gXY[1]));
-    for (unsigned i = 2; i < SK_ARRAY_COUNT(gXY); i += 2)
-        path.lineTo(SkIntToScalar(gXY[i]), SkIntToScalar(gXY[i+1]));
-    path.close();
-    path.offset(SkIntToScalar(-6), 0);
-    scale(&path, 1.5f);
+    SkPathBuilder b;
+    b.moveTo(SkIntToScalar(gXY[0]), SkIntToScalar(gXY[1]));
+    for (unsigned i = 2; i < SK_ARRAY_COUNT(gXY); i += 2) {
+        b.lineTo(SkIntToScalar(gXY[i]), SkIntToScalar(gXY[i+1]));
+    }
+    b.close().offset(SkIntToScalar(-6), 0);
+    SkPath path = scale(b.detach(), 1.5f);
 
     paint->setPathEffect(SkPath1DPathEffect::Make(path, SkIntToScalar(21), 0,
                                                   SkPath1DPathEffect::kRotate_Style));
@@ -102,10 +102,7 @@
     SkMatrix m;
     m.setScale(SkIntToScalar(12), SkIntToScalar(12));
 
-    SkPath path;
-    path.addCircle(0, 0, SkIntToScalar(5));
-
-    return SkPath2DPathEffect::Make(m, path);
+    return SkPath2DPathEffect::Make(m, SkPath::Circle(0,0,5));
 }
 
 static void tile_pe(SkPaint* paint) {
@@ -131,12 +128,13 @@
         paint.setAntiAlias(true);
         paint.setStyle(SkPaint::kStroke_Style);
 
-        SkPath path;
-        path.moveTo(20, 20);
-        path.lineTo(70, 120);
-        path.lineTo(120, 30);
-        path.lineTo(170, 80);
-        path.lineTo(240, 50);
+        SkPath path = SkPath::Polygon({
+            {20, 20},
+            {70, 120},
+            {120, 30},
+            {170, 80},
+            {240, 50},
+        }, false);
 
         canvas->save();
         for (size_t i = 0; i < SK_ARRAY_COUNT(gPE); i++) {
@@ -148,9 +146,9 @@
 
         path.reset();
         SkRect r = { 0, 0, 250, 120 };
-        path.addOval(r, SkPathDirection::kCW);
-        r.inset(50, 50);
-        path.addRect(r, SkPathDirection::kCCW);
+        path = SkPathBuilder().addOval(r, SkPathDirection::kCW)
+                              .addRect(r.makeInset(50, 50), SkPathDirection::kCCW)
+                              .detach();
 
         canvas->translate(320, 20);
         for (size_t i = 0; i < SK_ARRAY_COUNT(gPE2); i++) {
@@ -193,9 +191,10 @@
     SkISize onISize() override { return SkISize::Make(360, 630); }
 
     void onDraw(SkCanvas* canvas) override {
-        SkPath path0, path1, path2;
-        path0.addCircle(100, 100, 60);
-        path1.moveTo(20, 20); path1.cubicTo(20, 180, 140, 0, 140, 140);
+        SkPath path0 = SkPath::Circle(100, 100, 60),
+               path1 = SkPathBuilder().moveTo(20, 20)
+                                      .cubicTo(20, 180, 140, 0, 140, 140)
+                                      .detach();
 
         sk_sp<SkPathEffect> effects[] = {
             nullptr,
diff --git a/gm/picture.cpp b/gm/picture.cpp
index d7f43bb..fbf46af 100644
--- a/gm/picture.cpp
+++ b/gm/picture.cpp
@@ -24,18 +24,15 @@
 
     SkPaint paint;
     paint.setAntiAlias(true);
-    SkPath path;
 
     paint.setColor(0x800000FF);
     canvas->drawRect(SkRect::MakeWH(100, 100), paint);
 
     paint.setColor(0x80FF0000);
-    path.moveTo(0, 0); path.lineTo(100, 0); path.lineTo(100, 100);
-    canvas->drawPath(path, paint);
+    canvas->drawPath(SkPath::Polygon({{0, 0}, {100, 0}, {100, 100}}, false), paint);
 
     paint.setColor(0x8000FF00);
-    path.reset(); path.moveTo(0, 0); path.lineTo(100, 0); path.lineTo(0, 100);
-    canvas->drawPath(path, paint);
+    canvas->drawPath(SkPath::Polygon({{0, 0}, {100, 0}, {0, 100}}, false), paint);
 
     paint.setColor(0x80FFFFFF);
     paint.setBlendMode(SkBlendMode::kPlus);
diff --git a/gm/polygons.cpp b/gm/polygons.cpp
index 594d6d2..d7328a4 100644
--- a/gm/polygons.cpp
+++ b/gm/polygons.cpp
@@ -9,7 +9,7 @@
 #include "include/core/SkCanvas.h"
 #include "include/core/SkColor.h"
 #include "include/core/SkPaint.h"
-#include "include/core/SkPath.h"
+#include "include/core/SkPathBuilder.h"
 #include "include/core/SkPoint.h"
 #include "include/core/SkScalar.h"
 #include "include/core/SkSize.h"
@@ -74,13 +74,15 @@
 
         SkASSERT(SK_ARRAY_COUNT(pgs) == kNumPolygons);
         for (size_t pgIndex = 0; pgIndex < SK_ARRAY_COUNT(pgs); ++pgIndex) {
-            fPolygons.push_back().moveTo(pgs[pgIndex].fPoints[0].fX,
-                                         pgs[pgIndex].fPoints[0].fY);
+            SkPathBuilder b;
+            b.moveTo(pgs[pgIndex].fPoints[0].fX,
+                     pgs[pgIndex].fPoints[0].fY);
             for (size_t ptIndex = 1; ptIndex < pgs[pgIndex].fPointNum; ++ptIndex) {
-                fPolygons.back().lineTo(pgs[pgIndex].fPoints[ptIndex].fX,
-                                        pgs[pgIndex].fPoints[ptIndex].fY);
+                b.lineTo(pgs[pgIndex].fPoints[ptIndex].fX,
+                         pgs[pgIndex].fPoints[ptIndex].fY);
             }
-            fPolygons.back().close();
+            b.close();
+            fPolygons.push_back(b.detach());
         }
     }
 
diff --git a/gm/scaledstrokes.cpp b/gm/scaledstrokes.cpp
index 5d5b06a..1bc081b 100644
--- a/gm/scaledstrokes.cpp
+++ b/gm/scaledstrokes.cpp
@@ -8,7 +8,7 @@
 #include "gm/gm.h"
 #include "include/core/SkCanvas.h"
 #include "include/core/SkPaint.h"
-#include "include/core/SkPath.h"
+#include "include/core/SkPathBuilder.h"
 #include "include/core/SkRect.h"
 #include "include/core/SkScalar.h"
 #include "include/core/SkSize.h"
@@ -30,13 +30,13 @@
 
     static void draw_path(SkScalar size, SkCanvas* canvas, SkPaint paint) {
         SkScalar c = 0.551915024494f * size;
-        SkPath path;
+        SkPathBuilder path;
         path.moveTo(0.0f, size);
         path.cubicTo(c, size, size, c, size, 0.0f);
         path.cubicTo(size, -c, c, -size, 0.0f, -size);
         path.cubicTo(-c, -size, -size, -c, -size, 0.0f);
         path.cubicTo(-size, c, -c, size, 0.0f, size);
-        canvas->drawPath(path, paint);
+        canvas->drawPath(path.detach(), paint);
     }
 
     void onDraw(SkCanvas* canvas) override {
diff --git a/gm/shadowutils.cpp b/gm/shadowutils.cpp
index 3dc2b09..9407dd3 100644
--- a/gm/shadowutils.cpp
+++ b/gm/shadowutils.cpp
@@ -10,7 +10,7 @@
 #include "include/core/SkColor.h"
 #include "include/core/SkMatrix.h"
 #include "include/core/SkPaint.h"
-#include "include/core/SkPath.h"
+#include "include/core/SkPathBuilder.h"
 #include "include/core/SkPoint.h"
 #include "include/core/SkPoint3.h"
 #include "include/core/SkRRect.h"
@@ -47,14 +47,14 @@
 
 void draw_paths(SkCanvas* canvas, ShadowMode mode) {
     SkTArray<SkPath> paths;
-    paths.push_back().addRoundRect(SkRect::MakeWH(50, 50), 10, 10);
+    paths.push_back(SkPath::RRect(SkRect::MakeWH(50, 50), 10, 10));
     SkRRect oddRRect;
     oddRRect.setNinePatch(SkRect::MakeWH(50, 50), 9, 13, 6, 16);
-    paths.push_back().addRRect(oddRRect);
-    paths.push_back().addRect(SkRect::MakeWH(50, 50));
-    paths.push_back().addCircle(25, 25, 25);
-    paths.push_back().cubicTo(100, 50, 20, 100, 0, 0);
-    paths.push_back().addOval(SkRect::MakeWH(20, 60));
+    paths.push_back(SkPath::RRect(oddRRect));
+    paths.push_back(SkPath::Rect(SkRect::MakeWH(50, 50)));
+    paths.push_back(SkPath::Circle(25, 25, 25));
+    paths.push_back(SkPathBuilder().cubicTo(100, 50, 20, 100, 0, 0).detach());
+    paths.push_back(SkPath::Oval(SkRect::MakeWH(20, 60)));
 
     // star
     SkTArray<SkPath> concavePaths;
diff --git a/gm/smallpaths.cpp b/gm/smallpaths.cpp
index 869d7e1..5cd2748 100644
--- a/gm/smallpaths.cpp
+++ b/gm/smallpaths.cpp
@@ -8,232 +8,252 @@
 #include "gm/gm.h"
 #include "include/core/SkCanvas.h"
 #include "include/core/SkPaint.h"
-#include "include/core/SkPath.h"
+#include "include/core/SkPathBuilder.h"
 #include "include/core/SkRect.h"
 #include "include/core/SkScalar.h"
 #include "include/core/SkSize.h"
 #include "include/core/SkString.h"
 #include "include/core/SkTypes.h"
 #include "include/pathops/SkPathOps.h"
+#include <tuple>
 
-typedef SkScalar (*MakePathProc)(SkPath*);
+namespace {
+struct PathDY {
+    SkPath path;
+    SkScalar dy;
+};
+}
 
-static SkScalar make_triangle(SkPath* path) {
+typedef PathDY (*MakePathProc)();
+
+static PathDY make_triangle() {
     constexpr int gCoord[] = {
         10, 20, 15, 5, 30, 30
     };
-    path->moveTo(SkIntToScalar(gCoord[0]), SkIntToScalar(gCoord[1]));
-    path->lineTo(SkIntToScalar(gCoord[2]), SkIntToScalar(gCoord[3]));
-    path->lineTo(SkIntToScalar(gCoord[4]), SkIntToScalar(gCoord[5]));
-    path->close();
-    path->offset(SkIntToScalar(10), SkIntToScalar(0));
-    return SkIntToScalar(30);
+    return {
+        SkPathBuilder().moveTo(SkIntToScalar(gCoord[0]), SkIntToScalar(gCoord[1]))
+                       .lineTo(SkIntToScalar(gCoord[2]), SkIntToScalar(gCoord[3]))
+                       .lineTo(SkIntToScalar(gCoord[4]), SkIntToScalar(gCoord[5]))
+                       .close()
+                       .offset(10, 0)
+                       .detach(),
+        30
+    };
 }
 
-static SkScalar make_rect(SkPath* path) {
+static PathDY make_rect() {
     SkRect r = { SkIntToScalar(10), SkIntToScalar(10),
                  SkIntToScalar(30), SkIntToScalar(30) };
-    path->addRect(r);
-    path->offset(SkIntToScalar(10), SkIntToScalar(0));
-    return SkIntToScalar(30);
+    return {
+        SkPath::Rect(r.makeOffset(10, 0)),
+        30
+    };
 }
 
-static SkScalar make_oval(SkPath* path) {
+static PathDY make_oval() {
     SkRect r = { SkIntToScalar(10), SkIntToScalar(10),
                  SkIntToScalar(30), SkIntToScalar(30) };
-    path->addOval(r);
-    path->offset(SkIntToScalar(10), SkIntToScalar(0));
-    return SkIntToScalar(30);
+    return {
+        SkPath::Oval(r.makeOffset(10, 0)),
+        30
+    };
 }
 
-static SkScalar make_star(SkPath* path, int n) {
+static PathDY make_star(int n) {
     const SkScalar c = SkIntToScalar(45);
     const SkScalar r = SkIntToScalar(20);
 
     SkScalar rad = -SK_ScalarPI / 2;
     const SkScalar drad = (n >> 1) * SK_ScalarPI * 2 / n;
 
-    path->moveTo(c, c - r);
+    SkPathBuilder b;
+    b.moveTo(c, c - r);
     for (int i = 1; i < n; i++) {
         rad += drad;
-        path->lineTo(c + SkScalarCos(rad) * r, c + SkScalarSin(rad) * r);
+        b.lineTo(c + SkScalarCos(rad) * r, c + SkScalarSin(rad) * r);
     }
-    path->close();
-    return r * 2 * 6 / 5;
+    b.close();
+    return { b.detach(), r * 2 * 6 / 5 };
 }
 
-static SkScalar make_star_5(SkPath* path) { return make_star(path, 5); }
-static SkScalar make_star_13(SkPath* path) { return make_star(path, 13); }
+static PathDY make_star_5() { return make_star(5); }
+static PathDY make_star_13() { return make_star(13); }
 
-static SkScalar make_three_line(SkPath* path) {
+static PathDY make_three_line() {
     static SkScalar xOffset = 34.f;
     static SkScalar yOffset = 50.f;
-    path->moveTo(-32.5f + xOffset, 0.0f + yOffset);
-    path->lineTo(32.5f + xOffset, 0.0f + yOffset);
+    SkPathBuilder b;
+    b.moveTo(-32.5f + xOffset, 0.0f + yOffset);
+    b.lineTo(32.5f + xOffset, 0.0f + yOffset);
 
-    path->moveTo(-32.5f + xOffset, 19 + yOffset);
-    path->lineTo(32.5f + xOffset, 19 + yOffset);
+    b.moveTo(-32.5f + xOffset, 19 + yOffset);
+    b.lineTo(32.5f + xOffset, 19 + yOffset);
 
-    path->moveTo(-32.5f + xOffset, -19 + yOffset);
-    path->lineTo(32.5f + xOffset, -19 + yOffset);
-    path->lineTo(-32.5f + xOffset, -19 + yOffset);
+    b.moveTo(-32.5f + xOffset, -19 + yOffset);
+    b.lineTo(32.5f + xOffset, -19 + yOffset);
+    b.lineTo(-32.5f + xOffset, -19 + yOffset);
 
-    path->close();
+    b.close();
 
-    return SkIntToScalar(70);
+    return { b.detach(), 70 };
 }
 
-static SkScalar make_arrow(SkPath* path) {
+static PathDY make_arrow() {
     static SkScalar xOffset = 34.f;
     static SkScalar yOffset = 40.f;
-    path->moveTo(-26.f + xOffset, 0.0f + yOffset);
-    path->lineTo(26.f + xOffset, 0.0f + yOffset);
+    SkPathBuilder b;
+    b.moveTo(-26.f + xOffset, 0.0f + yOffset);
+    b.lineTo(26.f + xOffset, 0.0f + yOffset);
 
-    path->moveTo(-28.f + xOffset, -2.4748745f + yOffset);
-    path->lineTo(0 + xOffset, 25.525126f + yOffset);
+    b.moveTo(-28.f + xOffset, -2.4748745f + yOffset);
+    b.lineTo(0 + xOffset, 25.525126f + yOffset);
 
-    path->moveTo(-28.f + xOffset, 2.4748745f + yOffset);
-    path->lineTo(0 + xOffset, -25.525126f + yOffset);
-    path->lineTo(-28.f + xOffset, 2.4748745f + yOffset);
+    b.moveTo(-28.f + xOffset, 2.4748745f + yOffset);
+    b.lineTo(0 + xOffset, -25.525126f + yOffset);
+    b.lineTo(-28.f + xOffset, 2.4748745f + yOffset);
 
-    path->close();
+    b.close();
 
-    return SkIntToScalar(70);
+    return { b.detach(), 70 };
 }
 
-static SkScalar make_curve(SkPath* path) {
+static PathDY make_curve() {
     static SkScalar xOffset = -382.f;
     static SkScalar yOffset = -50.f;
-    path->moveTo(491 + xOffset, 56 + yOffset);
-    path->conicTo(435.93292f + xOffset, 56.000031f + yOffset,
+    SkPathBuilder b;
+    b.moveTo(491 + xOffset, 56 + yOffset);
+    b.conicTo(435.93292f + xOffset, 56.000031f + yOffset,
                   382.61078f + xOffset, 69.752716f + yOffset,
                   0.9920463f);
 
-    return SkIntToScalar(40);
+    return { b.detach(), 40 };
 }
 
-static SkScalar make_battery(SkPath* path) {
+static PathDY make_battery() {
     static SkScalar xOffset = 5.0f;
 
-    path->moveTo(24.67f + xOffset, 0.33000004f);
-    path->lineTo(8.3299999f + xOffset, 0.33000004f);
-    path->lineTo(8.3299999f + xOffset, 5.3299999f);
-    path->lineTo(0.33000004f + xOffset, 5.3299999f);
-    path->lineTo(0.33000004f + xOffset, 50.669998f);
-    path->lineTo(32.669998f + xOffset, 50.669998f);
-    path->lineTo(32.669998f + xOffset, 5.3299999f);
-    path->lineTo(24.67f + xOffset, 5.3299999f);
-    path->lineTo(24.67f + xOffset, 0.33000004f);
-    path->close();
+    SkPathBuilder b;
+    b.moveTo(24.67f + xOffset, 0.33000004f);
+    b.lineTo(8.3299999f + xOffset, 0.33000004f);
+    b.lineTo(8.3299999f + xOffset, 5.3299999f);
+    b.lineTo(0.33000004f + xOffset, 5.3299999f);
+    b.lineTo(0.33000004f + xOffset, 50.669998f);
+    b.lineTo(32.669998f + xOffset, 50.669998f);
+    b.lineTo(32.669998f + xOffset, 5.3299999f);
+    b.lineTo(24.67f + xOffset, 5.3299999f);
+    b.lineTo(24.67f + xOffset, 0.33000004f);
+    b.close();
 
-    path->moveTo(25.727224f + xOffset, 12.886665f);
-    path->lineTo(10.907918f + xOffset, 12.886665f);
-    path->lineTo(7.5166659f + xOffset, 28.683645f);
-    path->lineTo(14.810181f + xOffset, 28.683645f);
-    path->lineTo(7.7024879f + xOffset, 46.135998f);
-    path->lineTo(28.049999f + xOffset, 25.136419f);
-    path->lineTo(16.854223f + xOffset, 25.136419f);
-    path->lineTo(25.727224f + xOffset, 12.886665f);
-    path->close();
-    return SkIntToScalar(50);
+    b.moveTo(25.727224f + xOffset, 12.886665f);
+    b.lineTo(10.907918f + xOffset, 12.886665f);
+    b.lineTo(7.5166659f + xOffset, 28.683645f);
+    b.lineTo(14.810181f + xOffset, 28.683645f);
+    b.lineTo(7.7024879f + xOffset, 46.135998f);
+    b.lineTo(28.049999f + xOffset, 25.136419f);
+    b.lineTo(16.854223f + xOffset, 25.136419f);
+    b.lineTo(25.727224f + xOffset, 12.886665f);
+    b.close();
+    return { b.detach(), 50 };
 }
 
-static SkScalar make_battery2(SkPath* path) {
+static PathDY make_battery2() {
     static SkScalar xOffset = 225.625f;
 
-    path->moveTo(32.669998f + xOffset, 9.8640003f);
-    path->lineTo(0.33000004f + xOffset, 9.8640003f);
-    path->lineTo(0.33000004f + xOffset, 50.669998f);
-    path->lineTo(32.669998f + xOffset, 50.669998f);
-    path->lineTo(32.669998f + xOffset, 9.8640003f);
-    path->close();
+    SkPathBuilder b;
+    b.moveTo(32.669998f + xOffset, 9.8640003f);
+    b.lineTo(0.33000004f + xOffset, 9.8640003f);
+    b.lineTo(0.33000004f + xOffset, 50.669998f);
+    b.lineTo(32.669998f + xOffset, 50.669998f);
+    b.lineTo(32.669998f + xOffset, 9.8640003f);
+    b.close();
 
-    path->moveTo(10.907918f + xOffset, 12.886665f);
-    path->lineTo(25.727224f + xOffset, 12.886665f);
-    path->lineTo(16.854223f + xOffset, 25.136419f);
-    path->lineTo(28.049999f + xOffset, 25.136419f);
-    path->lineTo(7.7024879f + xOffset, 46.135998f);
-    path->lineTo(14.810181f + xOffset, 28.683645f);
-    path->lineTo(7.5166659f + xOffset, 28.683645f);
-    path->lineTo(10.907918f + xOffset, 12.886665f);
-    path->close();
+    b.moveTo(10.907918f + xOffset, 12.886665f);
+    b.lineTo(25.727224f + xOffset, 12.886665f);
+    b.lineTo(16.854223f + xOffset, 25.136419f);
+    b.lineTo(28.049999f + xOffset, 25.136419f);
+    b.lineTo(7.7024879f + xOffset, 46.135998f);
+    b.lineTo(14.810181f + xOffset, 28.683645f);
+    b.lineTo(7.5166659f + xOffset, 28.683645f);
+    b.lineTo(10.907918f + xOffset, 12.886665f);
+    b.close();
 
-    return SkIntToScalar(60);
+    return { b.detach(), 60 };
 }
 
-static SkScalar make_ring(SkPath* path) {
+static PathDY make_ring() {
     static SkScalar xOffset = 120;
     static SkScalar yOffset = -270.f;
 
-    path->setFillType(SkPathFillType::kWinding);
-    path->moveTo(xOffset + 144.859f, yOffset + 285.172f);
-    path->lineTo(xOffset + 144.859f, yOffset + 285.172f);
-    path->lineTo(xOffset + 144.859f, yOffset + 285.172f);
-    path->lineTo(xOffset + 143.132f, yOffset + 284.617f);
-    path->lineTo(xOffset + 144.859f, yOffset + 285.172f);
-    path->close();
-    path->moveTo(xOffset + 135.922f, yOffset + 286.844f);
-    path->lineTo(xOffset + 135.922f, yOffset + 286.844f);
-    path->lineTo(xOffset + 135.922f, yOffset + 286.844f);
-    path->lineTo(xOffset + 135.367f, yOffset + 288.571f);
-    path->lineTo(xOffset + 135.922f, yOffset + 286.844f);
-    path->close();
-    path->moveTo(xOffset + 135.922f, yOffset + 286.844f);
-    path->cubicTo(xOffset + 137.07f, yOffset + 287.219f, xOffset + 138.242f, yOffset + 287.086f,
-                  xOffset + 139.242f, yOffset + 286.578f);
-    path->cubicTo(xOffset + 140.234f, yOffset + 286.078f, xOffset + 141.031f, yOffset + 285.203f,
-                  xOffset + 141.406f, yOffset + 284.055f);
-    path->lineTo(xOffset + 144.859f, yOffset + 285.172f);
-    path->cubicTo(xOffset + 143.492f, yOffset + 289.375f, xOffset + 138.992f, yOffset + 291.656f,
-                  xOffset + 134.797f, yOffset + 290.297f);
-    path->lineTo(xOffset + 135.922f, yOffset + 286.844f);
-    path->close();
-    path->moveTo(xOffset + 129.68f, yOffset + 280.242f);
-    path->lineTo(xOffset + 129.68f, yOffset + 280.242f);
-    path->lineTo(xOffset + 129.68f, yOffset + 280.242f);
-    path->lineTo(xOffset + 131.407f, yOffset + 280.804f);
-    path->lineTo(xOffset + 129.68f, yOffset + 280.242f);
-    path->close();
-    path->moveTo(xOffset + 133.133f, yOffset + 281.367f);
-    path->cubicTo(xOffset + 132.758f, yOffset + 282.508f, xOffset + 132.883f, yOffset + 283.687f,
-                  xOffset + 133.391f, yOffset + 284.679f);
-    path->cubicTo(xOffset + 133.907f, yOffset + 285.679f, xOffset + 134.774f, yOffset + 286.468f,
-                  xOffset + 135.922f, yOffset + 286.843f);
-    path->lineTo(xOffset + 134.797f, yOffset + 290.296f);
-    path->cubicTo(xOffset + 130.602f, yOffset + 288.929f, xOffset + 128.313f, yOffset + 284.437f,
-                  xOffset + 129.68f, yOffset + 280.241f);
-    path->lineTo(xOffset + 133.133f, yOffset + 281.367f);
-    path->close();
-    path->moveTo(xOffset + 139.742f, yOffset + 275.117f);
-    path->lineTo(xOffset + 139.742f, yOffset + 275.117f);
-    path->lineTo(xOffset + 139.18f, yOffset + 276.844f);
-    path->lineTo(xOffset + 139.742f, yOffset + 275.117f);
-    path->close();
-    path->moveTo(xOffset + 138.609f, yOffset + 278.57f);
-    path->cubicTo(xOffset + 137.461f, yOffset + 278.203f, xOffset + 136.297f, yOffset + 278.328f,
-                  xOffset + 135.297f, yOffset + 278.836f);
-    path->cubicTo(xOffset + 134.297f, yOffset + 279.344f, xOffset + 133.508f, yOffset + 280.219f,
-                  xOffset + 133.133f, yOffset + 281.367f);
-    path->lineTo(xOffset + 129.68f, yOffset + 280.242f);
-    path->cubicTo(xOffset + 131.047f, yOffset + 276.039f, xOffset + 135.539f, yOffset + 273.758f,
-                  xOffset + 139.742f, yOffset + 275.117f);
-    path->lineTo(xOffset + 138.609f, yOffset + 278.57f);
-    path->close();
-    path->moveTo(xOffset + 141.406f, yOffset + 284.055f);
-    path->cubicTo(xOffset + 141.773f, yOffset + 282.907f, xOffset + 141.648f, yOffset + 281.735f,
-                  xOffset + 141.148f, yOffset + 280.735f);
-    path->cubicTo(xOffset + 140.625f, yOffset + 279.735f, xOffset + 139.757f, yOffset + 278.946f,
-                  xOffset + 138.609f, yOffset + 278.571f);
-    path->lineTo(xOffset + 139.742f, yOffset + 275.118f);
-    path->cubicTo(xOffset + 143.937f, yOffset + 276.493f, xOffset + 146.219f, yOffset + 280.977f,
-                  xOffset + 144.859f, yOffset + 285.173f);
-    path->lineTo(xOffset + 141.406f, yOffset + 284.055f);
-    path->close();
+    SkPathBuilder b;
+    b.setFillType(SkPathFillType::kWinding);
+    b.moveTo(xOffset + 144.859f, yOffset + 285.172f);
+    b.lineTo(xOffset + 144.859f, yOffset + 285.172f);
+    b.lineTo(xOffset + 144.859f, yOffset + 285.172f);
+    b.lineTo(xOffset + 143.132f, yOffset + 284.617f);
+    b.lineTo(xOffset + 144.859f, yOffset + 285.172f);
+    b.close();
+    b.moveTo(xOffset + 135.922f, yOffset + 286.844f);
+    b.lineTo(xOffset + 135.922f, yOffset + 286.844f);
+    b.lineTo(xOffset + 135.922f, yOffset + 286.844f);
+    b.lineTo(xOffset + 135.367f, yOffset + 288.571f);
+    b.lineTo(xOffset + 135.922f, yOffset + 286.844f);
+    b.close();
+    b.moveTo(xOffset + 135.922f, yOffset + 286.844f);
+    b.cubicTo(xOffset + 137.07f, yOffset + 287.219f, xOffset + 138.242f, yOffset + 287.086f,
+              xOffset + 139.242f, yOffset + 286.578f);
+    b.cubicTo(xOffset + 140.234f, yOffset + 286.078f, xOffset + 141.031f, yOffset + 285.203f,
+              xOffset + 141.406f, yOffset + 284.055f);
+    b.lineTo(xOffset + 144.859f, yOffset + 285.172f);
+    b.cubicTo(xOffset + 143.492f, yOffset + 289.375f, xOffset + 138.992f, yOffset + 291.656f,
+              xOffset + 134.797f, yOffset + 290.297f);
+    b.lineTo(xOffset + 135.922f, yOffset + 286.844f);
+    b.close();
+    b.moveTo(xOffset + 129.68f, yOffset + 280.242f);
+    b.lineTo(xOffset + 129.68f, yOffset + 280.242f);
+    b.lineTo(xOffset + 129.68f, yOffset + 280.242f);
+    b.lineTo(xOffset + 131.407f, yOffset + 280.804f);
+    b.lineTo(xOffset + 129.68f, yOffset + 280.242f);
+    b.close();
+    b.moveTo(xOffset + 133.133f, yOffset + 281.367f);
+    b.cubicTo(xOffset + 132.758f, yOffset + 282.508f, xOffset + 132.883f, yOffset + 283.687f,
+              xOffset + 133.391f, yOffset + 284.679f);
+    b.cubicTo(xOffset + 133.907f, yOffset + 285.679f, xOffset + 134.774f, yOffset + 286.468f,
+              xOffset + 135.922f, yOffset + 286.843f);
+    b.lineTo(xOffset + 134.797f, yOffset + 290.296f);
+    b.cubicTo(xOffset + 130.602f, yOffset + 288.929f, xOffset + 128.313f, yOffset + 284.437f,
+              xOffset + 129.68f, yOffset + 280.241f);
+    b.lineTo(xOffset + 133.133f, yOffset + 281.367f);
+    b.close();
+    b.moveTo(xOffset + 139.742f, yOffset + 275.117f);
+    b.lineTo(xOffset + 139.742f, yOffset + 275.117f);
+    b.lineTo(xOffset + 139.18f, yOffset + 276.844f);
+    b.lineTo(xOffset + 139.742f, yOffset + 275.117f);
+    b.close();
+    b.moveTo(xOffset + 138.609f, yOffset + 278.57f);
+    b.cubicTo(xOffset + 137.461f, yOffset + 278.203f, xOffset + 136.297f, yOffset + 278.328f,
+              xOffset + 135.297f, yOffset + 278.836f);
+    b.cubicTo(xOffset + 134.297f, yOffset + 279.344f, xOffset + 133.508f, yOffset + 280.219f,
+              xOffset + 133.133f, yOffset + 281.367f);
+    b.lineTo(xOffset + 129.68f, yOffset + 280.242f);
+    b.cubicTo(xOffset + 131.047f, yOffset + 276.039f, xOffset + 135.539f, yOffset + 273.758f,
+              xOffset + 139.742f, yOffset + 275.117f);
+    b.lineTo(xOffset + 138.609f, yOffset + 278.57f);
+    b.close();
+    b.moveTo(xOffset + 141.406f, yOffset + 284.055f);
+    b.cubicTo(xOffset + 141.773f, yOffset + 282.907f, xOffset + 141.648f, yOffset + 281.735f,
+              xOffset + 141.148f, yOffset + 280.735f);
+    b.cubicTo(xOffset + 140.625f, yOffset + 279.735f, xOffset + 139.757f, yOffset + 278.946f,
+              xOffset + 138.609f, yOffset + 278.571f);
+    b.lineTo(xOffset + 139.742f, yOffset + 275.118f);
+    b.cubicTo(xOffset + 143.937f, yOffset + 276.493f, xOffset + 146.219f, yOffset + 280.977f,
+              xOffset + 144.859f, yOffset + 285.173f);
+    b.lineTo(xOffset + 141.406f, yOffset + 284.055f);
+    b.close();
 
     // uncomment to reveal PathOps bug, see https://bugs.chromium.org/p/skia/issues/detail?id=9732
     // (void) Simplify(*path, path);
 
-    return SkIntToScalar(15);
+    return { b.detach(), 15 };
 }
 
 constexpr MakePathProc gProcs[] = {
@@ -307,7 +327,9 @@
 protected:
     void onOnceBeforeDraw() override {
         for (size_t i = 0; i < N; i++) {
-            fDY[i] = gProcs[i](&fPath[i]);
+            auto [path, dy] = gProcs[i]();
+            fPath[i] = path;
+            fDY[i]   = dy;
         }
     }
 
diff --git a/src/core/SkAAClip.cpp b/src/core/SkAAClip.cpp
index e33e130..a1f4e0c 100644
--- a/src/core/SkAAClip.cpp
+++ b/src/core/SkAAClip.cpp
@@ -679,9 +679,7 @@
 
     // TODO: special case this
 
-    SkPath path;
-    path.addRect(r);
-    return this->setPath(path, nullptr, doAA);
+    return this->setPath(SkPath::Rect(r), nullptr, doAA);
 }
 
 static void append_run(SkTDArray<uint8_t>& array, uint8_t value, int count) {
diff --git a/src/core/SkBitmapDevice.cpp b/src/core/SkBitmapDevice.cpp
index 303f52e..4d94571 100644
--- a/src/core/SkBitmapDevice.cpp
+++ b/src/core/SkBitmapDevice.cpp
@@ -366,21 +366,16 @@
 }
 
 void SkBitmapDevice::drawOval(const SkRect& oval, const SkPaint& paint) {
-    SkPath path;
-    path.addOval(oval);
     // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
     // required to override drawOval.
-    this->drawPath(path, paint, true);
+    this->drawPath(SkPath::Oval(oval), paint, true);
 }
 
 void SkBitmapDevice::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
 #ifdef SK_IGNORE_BLURRED_RRECT_OPT
-    SkPath  path;
-
-    path.addRRect(rrect);
     // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
     // required to override drawRRect.
-    this->drawPath(path, paint, true);
+    this->drawPath(SkPath::RRect(rrect), paint, true);
 #else
     LOOP_TILER( drawRRect(rrect, paint), Bounder(rrect.getBounds(), paint))
 #endif
diff --git a/src/core/SkBlurMF.cpp b/src/core/SkBlurMF.cpp
index 0055044..794d33b 100644
--- a/src/core/SkBlurMF.cpp
+++ b/src/core/SkBlurMF.cpp
@@ -6,6 +6,7 @@
  */
 
 #include "include/core/SkMaskFilter.h"
+#include "include/core/SkPathBuilder.h"
 #include "include/core/SkRRect.h"
 #include "include/core/SkStrokeRec.h"
 #include "include/core/SkVertices.h"
@@ -302,10 +303,10 @@
         canvas.drawRect(rects[0], paint);
     } else {
         // todo: do I need a fast way to do this?
-        SkPath path;
-        path.addRect(rects[0]);
-        path.addRect(rects[1]);
-        path.setFillType(SkPathFillType::kEvenOdd);
+        SkPath path = SkPathBuilder().addRect(rects[0])
+                                     .addRect(rects[1])
+                                     .setFillType(SkPathFillType::kEvenOdd)
+                                     .detach();
         canvas.drawPath(path, paint);
     }
     return true;
diff --git a/src/core/SkOverdrawCanvas.cpp b/src/core/SkOverdrawCanvas.cpp
index f606ac7..df5a3d0 100644
--- a/src/core/SkOverdrawCanvas.cpp
+++ b/src/core/SkOverdrawCanvas.cpp
@@ -208,9 +208,7 @@
 void SkOverdrawCanvas::onDrawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4],
                                         QuadAAFlags aa, const SkColor4f& color, SkBlendMode mode) {
     if (clip) {
-        SkPath path;
-        path.addPoly(clip, 4, true);
-        fList[0]->onDrawPath(path, fPaint);
+        fList[0]->onDrawPath(SkPath::Polygon(clip, 4, true), fPaint);
     } else {
         fList[0]->onDrawRect(rect, fPaint);
     }
@@ -227,10 +225,8 @@
             fList[0]->concat(preViewMatrices[set[i].fMatrixIndex]);
         }
         if (set[i].fHasClip) {
-            SkPath path;
-            path.addPoly(dstClips + clipIndex, 4, true);
+            fList[0]->onDrawPath(SkPath::Polygon(dstClips + clipIndex, 4, true), fPaint);
             clipIndex += 4;
-            fList[0]->onDrawPath(path, fPaint);
         } else {
             fList[0]->onDrawRect(set[i].fDstRect, fPaint);
         }
diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp
index 7f84658..055a8b3 100644
--- a/src/core/SkPath.cpp
+++ b/src/core/SkPath.cpp
@@ -3682,31 +3682,29 @@
 
 // assumes plane is pre-normalized
 // If we fail in our calculations, we return the empty path
-static void clip(const SkPath& path, const SkHalfPlane& plane, SkPath* clippedPath) {
+static SkPath clip(const SkPath& path, const SkHalfPlane& plane) {
     SkMatrix mx, inv;
     SkPoint p0 = { -plane.fA*plane.fC, -plane.fB*plane.fC };
     mx.setAll( plane.fB, plane.fA, p0.fX,
               -plane.fA, plane.fB, p0.fY,
                       0,        0,     1);
     if (!mx.invert(&inv)) {
-        clippedPath->reset();
-        return;
+        return SkPath();
     }
 
     SkPath rotated;
     path.transform(inv, &rotated);
     if (!rotated.isFinite()) {
-        clippedPath->reset();
-        return;
+        return SkPath();
     }
 
     SkScalar big = SK_ScalarMax;
     SkRect clip = {-big, 0, big, big };
 
     struct Rec {
-        SkPath* fResult;
-        SkPoint fPrev;
-    } rec = { clippedPath, {0, 0} };
+        SkPathBuilder fResult;
+        SkPoint       fPrev = {0,0};
+    } rec;
 
     SkEdgeClipper::ClipPath(rotated.view(), clip, false,
                             [](SkEdgeClipper* clipper, bool newCtr, void* ctx) {
@@ -3717,26 +3715,26 @@
         SkPath::Verb verb;
         while ((verb = clipper->next(pts)) != SkPath::kDone_Verb) {
             if (newCtr) {
-                rec->fResult->moveTo(pts[0]);
+                rec->fResult.moveTo(pts[0]);
                 rec->fPrev = pts[0];
                 newCtr = false;
             }
 
             if (addLineTo || pts[0] != rec->fPrev) {
-                rec->fResult->lineTo(pts[0]);
+                rec->fResult.lineTo(pts[0]);
             }
 
             switch (verb) {
                 case SkPath::kLine_Verb:
-                    rec->fResult->lineTo(pts[1]);
+                    rec->fResult.lineTo(pts[1]);
                     rec->fPrev = pts[1];
                     break;
                 case SkPath::kQuad_Verb:
-                    rec->fResult->quadTo(pts[1], pts[2]);
+                    rec->fResult.quadTo(pts[1], pts[2]);
                     rec->fPrev = pts[2];
                     break;
                 case SkPath::kCubic_Verb:
-                    rec->fResult->cubicTo(pts[1], pts[2], pts[3]);
+                    rec->fResult.cubicTo(pts[1], pts[2], pts[3]);
                     rec->fPrev = pts[3];
                     break;
                 default: break;
@@ -3745,11 +3743,12 @@
         }
     }, &rec);
 
-    clippedPath->setFillType(path.getFillType());
-    clippedPath->transform(mx);
-    if (!path.isFinite()) {
-        clippedPath->reset();
+    rec.fResult.setFillType(path.getFillType());
+    SkPath result = rec.fResult.detach().makeTransform(mx);
+    if (!result.isFinite()) {
+        result = SkPath();
     }
+    return result;
 }
 
 // true means we have written to clippedPath
@@ -3768,14 +3767,14 @@
             case SkHalfPlane::kAllPositive:
                 return false;
             case SkHalfPlane::kMixed: {
-                clip(path, plane, clippedPath);
+                *clippedPath = clip(path, plane);
                 return true;
             } break;
             default: break; // handled outside of the switch
         }
     }
     // clipped out (or failed)
-    clippedPath->reset();
+    *clippedPath = SkPath();
     return true;
 }
 
diff --git a/src/core/SkRasterClip.cpp b/src/core/SkRasterClip.cpp
index 34840de..57cb1e5 100644
--- a/src/core/SkRasterClip.cpp
+++ b/src/core/SkRasterClip.cpp
@@ -263,10 +263,7 @@
     SkIRect bounds(devBounds);
     this->applyClipRestriction(op, &bounds);
 
-    SkPath path;
-    path.addRRect(rrect);
-
-    return this->op(path, matrix, bounds, op, doAA);
+    return this->op(SkPath::RRect(rrect), matrix, bounds, op, doAA);
 }
 
 bool SkRasterClip::op(const SkPath& path, const SkMatrix& matrix, const SkIRect& devBounds,
diff --git a/tests/GrCCPRTest.cpp b/tests/GrCCPRTest.cpp
index 974931d..a684131 100644
--- a/tests/GrCCPRTest.cpp
+++ b/tests/GrCCPRTest.cpp
@@ -9,6 +9,7 @@
 #include "tests/Test.h"
 
 #include "include/core/SkMatrix.h"
+#include "include/core/SkPathBuilder.h"
 #include "include/core/SkRect.h"
 #include "include/gpu/GrDirectContext.h"
 #include "include/gpu/GrRecordingContext.h"
@@ -893,14 +894,14 @@
     void onRun(skiatest::Reporter* reporter, const CCPRPathDrawer& ccpr) const override {
         static constexpr int kNumBusyVerbs = 1 << 17;
         ccpr.clear();
-        SkPath busyPath;
+        SkPathBuilder busyPath;
         busyPath.moveTo(0, 0); // top left
         busyPath.lineTo(kCanvasSize, kCanvasSize); // bottom right
         for (int i = 2; i < kNumBusyVerbs; ++i) {
             float offset = i * ((float)kCanvasSize / kNumBusyVerbs);
             busyPath.lineTo(kCanvasSize - offset, kCanvasSize + offset); // offscreen
         }
-        ccpr.drawPath(busyPath);
+        ccpr.drawPath(busyPath.detach());
 
         ccpr.flush(); // If this doesn't crash, the test passed.
                       // If it does, maybe fiddle with fMaxInstancesPerDrawArraysWithoutCrashing in
diff --git a/tools/fonts/TestTypeface.cpp b/tools/fonts/TestTypeface.cpp
index f32f77a..fa4ba9d 100644
--- a/tools/fonts/TestTypeface.cpp
+++ b/tools/fonts/TestTypeface.cpp
@@ -10,7 +10,7 @@
 #include "include/core/SkFontMetrics.h"
 #include "include/core/SkImageInfo.h"
 #include "include/core/SkMatrix.h"
-#include "include/core/SkPath.h"
+#include "include/core/SkPathBuilder.h"
 #include "include/core/SkPoint.h"
 #include "include/core/SkRect.h"
 #include "include/core/SkString.h"
@@ -42,9 +42,6 @@
 }
 
 SkTestFont::~SkTestFont() {
-    for (unsigned index = 0; index < fCharCodesCount; ++index) {
-        delete fPaths[index];
-    }
     delete[] fPaths;
 }
 
@@ -58,35 +55,35 @@
 }
 
 void SkTestFont::init(const SkScalar* pts, const unsigned char* verbs) {
-    fPaths = new SkPath*[fCharCodesCount];
+    fPaths = new SkPath[fCharCodesCount];
     for (unsigned index = 0; index < fCharCodesCount; ++index) {
-        SkPath*      path = new SkPath;
+        SkPathBuilder b;
         SkPath::Verb verb;
         while ((verb = (SkPath::Verb)*verbs++) != SkPath::kDone_Verb) {
             switch (verb) {
                 case SkPath::kMove_Verb:
-                    path->moveTo(pts[0], pts[1]);
+                    b.moveTo(pts[0], pts[1]);
                     pts += 2;
                     break;
                 case SkPath::kLine_Verb:
-                    path->lineTo(pts[0], pts[1]);
+                    b.lineTo(pts[0], pts[1]);
                     pts += 2;
                     break;
                 case SkPath::kQuad_Verb:
-                    path->quadTo(pts[0], pts[1], pts[2], pts[3]);
+                    b.quadTo(pts[0], pts[1], pts[2], pts[3]);
                     pts += 4;
                     break;
                 case SkPath::kCubic_Verb:
-                    path->cubicTo(pts[0], pts[1], pts[2], pts[3], pts[4], pts[5]);
+                    b.cubicTo(pts[0], pts[1], pts[2], pts[3], pts[4], pts[5]);
                     pts += 6;
                     break;
-                case SkPath::kClose_Verb: path->close(); break;
+                case SkPath::kClose_Verb:
+                    b.close();
+                    break;
                 default: SkDEBUGFAIL("bad verb"); return;
             }
         }
-        // This should make SkPath::getBounds() queries threadsafe.
-        path->updateBoundsCache();
-        fPaths[index] = path;
+        fPaths[index] = b.detach();
     }
 }
 
@@ -104,9 +101,9 @@
 
 void TestTypeface::getFontMetrics(SkFontMetrics* metrics) { *metrics = fTestFont->fMetrics; }
 
-void TestTypeface::getPath(SkGlyphID glyphID, SkPath* path) {
+SkPath TestTypeface::getPath(SkGlyphID glyphID) {
     glyphID = glyphID < fTestFont->fCharCodesCount ? glyphID : 0;
-    *path   = *fTestFont->fPaths[glyphID];
+    return fTestFont->fPaths[glyphID];
 }
 
 void TestTypeface::onFilterRec(SkScalerContextRec* rec) const {
@@ -182,8 +179,7 @@
     void generateImage(const SkGlyph&) override { SK_ABORT("Should have generated from path."); }
 
     bool generatePath(SkGlyphID glyph, SkPath* path) override {
-        this->getTestTypeface()->getPath(glyph, path);
-        path->transform(fMatrix);
+        *path = this->getTestTypeface()->getPath(glyph).makeTransform(fMatrix);
         return true;
     }
 
diff --git a/tools/fonts/TestTypeface.h b/tools/fonts/TestTypeface.h
index fc52070..87b9fb5 100644
--- a/tools/fonts/TestTypeface.h
+++ b/tools/fonts/TestTypeface.h
@@ -57,7 +57,7 @@
     const SkFixed*       fWidths;
     const SkFontMetrics& fMetrics;
     const char*          fName;
-    SkPath**             fPaths;
+    SkPath*              fPaths;
     friend class TestTypeface;
     typedef SkRefCnt INHERITED;
 };
@@ -67,7 +67,7 @@
     TestTypeface(sk_sp<SkTestFont>, const SkFontStyle& style);
     void getAdvance(SkGlyph* glyph);
     void getFontMetrics(SkFontMetrics* metrics);
-    void getPath(SkGlyphID glyph, SkPath* path);
+    SkPath getPath(SkGlyphID glyph);
 
 protected:
     SkScalerContext* onCreateScalerContext(const SkScalerContextEffects&,