use pathbuilder

Change-Id: Icb4d3f98440b53ba38270cc1f43fc43e6724d36b
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/315736
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Mike Reed <reed@google.com>
diff --git a/gm/complexclip.cpp b/gm/complexclip.cpp
index 4a7e0ec..368e3ea 100644
--- a/gm/complexclip.cpp
+++ b/gm/complexclip.cpp
@@ -12,7 +12,7 @@
 #include "include/core/SkFont.h"
 #include "include/core/SkFontTypes.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"
@@ -54,21 +54,22 @@
     SkISize onISize() override { return SkISize::Make(388, 780); }
 
     void onDraw(SkCanvas* canvas) override {
-        SkPath path;
-        path.moveTo(0,   50)
-            .quadTo(0,   0,   50,  0)
-            .lineTo(175, 0)
-            .quadTo(200, 0,   200, 25)
-            .lineTo(200, 150)
-            .quadTo(200, 200, 150, 200)
-            .lineTo(0,   200)
-            .close()
-            .moveTo(50,  50)
-            .lineTo(150, 50)
-            .lineTo(150, 125)
-            .quadTo(150, 150, 125, 150)
-            .lineTo(50,  150)
-            .close();
+        SkPath path = SkPathBuilder()
+                        .moveTo(0,   50)
+                        .quadTo(0,   0,   50,  0)
+                        .lineTo(175, 0)
+                        .quadTo(200, 0,   200, 25)
+                        .lineTo(200, 150)
+                        .quadTo(200, 200, 150, 200)
+                        .lineTo(0,   200)
+                        .close()
+                        .moveTo(50,  50)
+                        .lineTo(150, 50)
+                        .lineTo(150, 125)
+                        .quadTo(150, 150, 125, 150)
+                        .lineTo(50,  150)
+                        .close()
+                        .detach();
         if (fInvertDraw) {
             path.setFillType(SkPathFillType::kInverseEvenOdd);
         } else {
@@ -78,11 +79,9 @@
         pathPaint.setAntiAlias(true);
         pathPaint.setColor(gPathColor);
 
-        SkPath clipA;
-        clipA.addPoly({{10,  20}, {165, 22}, {70,  105}, {165, 177}, {-5,  180}}, false).close();
+        SkPath clipA = SkPath::Polygon({{10,  20}, {165, 22}, {70,  105}, {165, 177}, {-5,  180}}, true);
 
-        SkPath clipB;
-        clipB.addPoly({{40,  10}, {190, 15}, {195, 190}, {40,  185}, {155, 100}}, false).close();
+        SkPath clipB = SkPath::Polygon({{40,  10}, {190, 15}, {195, 190}, {40,  185}, {155, 100}}, true);
 
         SkFont font(ToolUtils::create_portable_typeface(), 20);
 
diff --git a/gm/convexpolyclip.cpp b/gm/convexpolyclip.cpp
index 3e78054..0953ee7 100644
--- a/gm/convexpolyclip.cpp
+++ b/gm/convexpolyclip.cpp
@@ -207,8 +207,7 @@
                         canvas->save();
                     }
                     canvas->translate(x, y);
-                    SkPath closedClipPath;
-                    clip->asClosedPath(&closedClipPath);
+                    SkPath closedClipPath = clip->asClosedPath();
                     canvas->drawPath(closedClipPath, clipOutlinePaint);
                     clip->setOnCanvas(canvas, kIntersect_SkClipOp, SkToBool(aa));
                     canvas->scale(1.f, 1.8f);
@@ -240,7 +239,7 @@
         void setOnCanvas(SkCanvas* canvas, SkClipOp op, bool aa) const {
             switch (fClipType) {
                 case kPath_ClipType:
-                    canvas->clipPath(fPath, op, aa);
+                    canvas->clipPath(fPathBuilder.snapshot(), op, aa);
                     break;
                 case kRect_ClipType:
                     canvas->clipRect(fRect, op, aa);
@@ -251,31 +250,29 @@
             }
         }
 
-        void asClosedPath(SkPath* path) const {
+        SkPath asClosedPath() const {
             switch (fClipType) {
                 case kPath_ClipType:
-                    *path = fPath;
-                    path->close();
+                    return SkPathBuilder(fPathBuilder).close().detach();
                     break;
                 case kRect_ClipType:
-                    path->reset();
-                    path->addRect(fRect);
-                    break;
+                    return SkPath::Rect(fRect);
                 case kNone_ClipType:
                     SkDEBUGFAIL("Uninitialized Clip.");
                     break;
             }
+            return SkPath();
         }
 
         void setPath(const SkPath& path) {
             fClipType = kPath_ClipType;
-            fPath = path;
+            fPathBuilder = path;
         }
 
         void setRect(const SkRect& rect) {
             fClipType = kRect_ClipType;
             fRect = rect;
-            fPath.reset();
+            fPathBuilder.reset();
         }
 
         ClipType getType() const { return fClipType; }
@@ -283,7 +280,7 @@
         void getBounds(SkRect* bounds) const {
             switch (fClipType) {
                 case kPath_ClipType:
-                    *bounds = fPath.getBounds();
+                    *bounds = fPathBuilder.computeBounds();
                     break;
                 case kRect_ClipType:
                     *bounds = fRect;
@@ -296,7 +293,7 @@
 
     private:
         ClipType fClipType;
-        SkPath fPath;
+        SkPathBuilder fPathBuilder;
         SkRect fRect;
     };
 
diff --git a/include/core/SkPathBuilder.h b/include/core/SkPathBuilder.h
index 79941957..0cda81d 100644
--- a/include/core/SkPathBuilder.h
+++ b/include/core/SkPathBuilder.h
@@ -16,9 +16,18 @@
 class SK_API SkPathBuilder {
 public:
     SkPathBuilder();
+    SkPathBuilder(SkPathFillType);
+    SkPathBuilder(const SkPath&);
+    SkPathBuilder(const SkPathBuilder&) = default;
     ~SkPathBuilder();
 
-    SkPath snapshot();  // the builder is unchanged after returning this path
+    SkPathBuilder& operator=(const SkPath&);
+    SkPathBuilder& operator=(const SkPathBuilder&) = default;
+
+    SkPathFillType fillType() const { return fFillType; }
+    SkRect computeBounds() const;
+
+    SkPath snapshot() const;  // the builder is unchanged after returning this path
     SkPath detach();    // the builder is reset to empty after returning this path
 
     SkPathBuilder& setFillType(SkPathFillType ft) { fFillType = ft; return *this; }
diff --git a/src/core/SkPathBuilder.cpp b/src/core/SkPathBuilder.cpp
index 9d442db..6a300ea 100644
--- a/src/core/SkPathBuilder.cpp
+++ b/src/core/SkPathBuilder.cpp
@@ -18,6 +18,10 @@
     this->reset();
 }
 
+SkPathBuilder::SkPathBuilder(const SkPath& src) {
+    *this = src;
+}
+
 SkPathBuilder::~SkPathBuilder() {
 }
 
@@ -40,11 +44,33 @@
     return *this;
 }
 
+SkPathBuilder& SkPathBuilder::operator=(const SkPath& src) {
+    this->reset().setFillType(src.getFillType());
+
+    for (auto [verb, pts, w] : SkPathPriv::Iterate(src)) {
+        switch (verb) {
+            case SkPathVerb::kMove:  this->moveTo(pts[0]); break;
+            case SkPathVerb::kLine:  this->lineTo(pts[1]); break;
+            case SkPathVerb::kQuad:  this->quadTo(pts[1], pts[2]); break;
+            case SkPathVerb::kConic: this->conicTo(pts[1], pts[2], w[0]); break;
+            case SkPathVerb::kCubic: this->cubicTo(pts[1], pts[2], pts[3]); break;
+            case SkPathVerb::kClose: this->close(); break;
+        }
+    }
+    return *this;
+}
+
 void SkPathBuilder::incReserve(int extraPtCount, int extraVbCount) {
     fPts.setReserve(  Sk32_sat_add(fPts.count(),   extraPtCount));
     fVerbs.setReserve(Sk32_sat_add(fVerbs.count(), extraVbCount));
 }
 
+SkRect SkPathBuilder::computeBounds() const {
+    SkRect bounds;
+    bounds.setBounds(fPts.begin(), fPts.count());
+    return bounds;
+}
+
 /*
  *  Some old behavior in SkPath -- should we keep it?
  *
@@ -178,7 +204,7 @@
     return SkPath(std::move(pr), fFillType, fIsVolatile, convexity, dir);
 }
 
-SkPath SkPathBuilder::snapshot() {
+SkPath SkPathBuilder::snapshot() const {
     return this->make(sk_sp<SkPathRef>(new SkPathRef(fPts,
                                                      fVerbs,
                                                      fConicWeights,
diff --git a/src/gpu/GrReducedClip.cpp b/src/gpu/GrReducedClip.cpp
index 5049523..30c8fec 100644
--- a/src/gpu/GrReducedClip.cpp
+++ b/src/gpu/GrReducedClip.cpp
@@ -675,10 +675,10 @@
         return ClipResult::kClipped;
     }
 
-    SkPath deviceSpacePath;
+    SkPathBuilder deviceSpacePath;
     deviceSpacePath.setIsVolatile(true);
     deviceSpacePath.addRRect(deviceSpaceRRect);
-    return this->addAnalyticPath(deviceSpacePath, invert, aa);
+    return this->addAnalyticPath(deviceSpacePath.detach(), invert, aa);
 }
 
 GrReducedClip::ClipResult GrReducedClip::addAnalyticPath(const SkPath& deviceSpacePath,
diff --git a/src/gpu/GrTestUtils.cpp b/src/gpu/GrTestUtils.cpp
index d60a358..5b51215 100644
--- a/src/gpu/GrTestUtils.cpp
+++ b/src/gpu/GrTestUtils.cpp
@@ -8,7 +8,7 @@
 #include "src/gpu/GrTestUtils.h"
 
 #include "include/core/SkMatrix.h"
-#include "include/core/SkPath.h"
+#include "include/core/SkPathBuilder.h"
 #include "include/core/SkRRect.h"
 #include "src/core/SkRectPriv.h"
 #include "src/gpu/GrColorInfo.h"
@@ -168,36 +168,43 @@
     if (!gOnce) {
         gOnce = true;
         // line
-        gPath[0].moveTo(0.f, 0.f);
-        gPath[0].lineTo(10.f, 10.f);
+        gPath[0] = SkPathBuilder().moveTo(0.f, 0.f)
+                                  .lineTo(10.f, 10.f)
+                                  .detach();
         // quad
-        gPath[1].moveTo(0.f, 0.f);
-        gPath[1].quadTo(10.f, 10.f, 20.f, 20.f);
+        gPath[1] = SkPathBuilder().moveTo(0.f, 0.f)
+                                  .quadTo(10.f, 10.f, 20.f, 20.f)
+                                  .detach();
         // conic
-        gPath[2].moveTo(0.f, 0.f);
-        gPath[2].conicTo(10.f, 10.f, 20.f, 20.f, 1.f);
+        gPath[2] = SkPathBuilder().moveTo(0.f, 0.f)
+                                  .conicTo(10.f, 10.f, 20.f, 20.f, 1.f)
+                                  .detach();
         // cubic
-        gPath[3].moveTo(0.f, 0.f);
-        gPath[3].cubicTo(10.f, 10.f, 20.f, 20.f, 30.f, 30.f);
+        gPath[3] = SkPathBuilder().moveTo(0.f, 0.f)
+                                  .cubicTo(10.f, 10.f, 20.f, 20.f, 30.f, 30.f)
+                                  .detach();
         // all three
-        gPath[4].moveTo(0.f, 0.f);
-        gPath[4].lineTo(10.f, 10.f);
-        gPath[4].quadTo(10.f, 10.f, 20.f, 20.f);
-        gPath[4].conicTo(10.f, 10.f, 20.f, 20.f, 1.f);
-        gPath[4].cubicTo(10.f, 10.f, 20.f, 20.f, 30.f, 30.f);
+        gPath[4] = SkPathBuilder().moveTo(0.f, 0.f)
+                                  .lineTo(10.f, 10.f)
+                                  .quadTo(10.f, 10.f, 20.f, 20.f)
+                                  .conicTo(10.f, 10.f, 20.f, 20.f, 1.f)
+                                  .cubicTo(10.f, 10.f, 20.f, 20.f, 30.f, 30.f)
+                                  .detach();
         // convex
-        gPath[5].moveTo(0.0f, 0.0f);
-        gPath[5].lineTo(10.0f, 0.0f);
-        gPath[5].lineTo(10.0f, 10.0f);
-        gPath[5].lineTo(0.0f, 10.0f);
-        gPath[5].close();
+        gPath[5] = SkPathBuilder().moveTo(0.0f, 0.0f)
+                                  .lineTo(10.0f, 0.0f)
+                                  .lineTo(10.0f, 10.0f)
+                                  .lineTo(0.0f, 10.0f)
+                                  .close()
+                                  .detach();
         // concave
-        gPath[6].moveTo(0.0f, 0.0f);
-        gPath[6].lineTo(5.0f, 5.0f);
-        gPath[6].lineTo(10.0f, 0.0f);
-        gPath[6].lineTo(10.0f, 10.0f);
-        gPath[6].lineTo(0.0f, 10.0f);
-        gPath[6].close();
+        gPath[6] = SkPathBuilder().moveTo(0.0f, 0.0f)
+                                  .lineTo(5.0f, 5.0f)
+                                  .lineTo(10.0f, 0.0f)
+                                  .lineTo(10.0f, 10.0f)
+                                  .lineTo(0.0f, 10.0f)
+                                  .close()
+                                  .detach();
     }
 
     return gPath[random->nextULessThan(static_cast<uint32_t>(SK_ARRAY_COUNT(gPath)))];
@@ -209,25 +216,25 @@
     if (!gOnce) {
         gOnce = true;
         // narrow rect
-        gPath[0].moveTo(-1.5f, -50.0f);
-        gPath[0].lineTo(-1.5f, -50.0f);
-        gPath[0].lineTo( 1.5f, -50.0f);
-        gPath[0].lineTo( 1.5f,  50.0f);
-        gPath[0].lineTo(-1.5f,  50.0f);
+        gPath[0] = SkPath::Polygon({{-1.5f, -50.0f},
+                                    {-1.5f, -50.0f},
+                                    { 1.5f, -50.0f},
+                                    { 1.5f,  50.0f},
+                                    {-1.5f,  50.0f}}, false);
         // degenerate
-        gPath[1].moveTo(-0.025f, -0.025f);
-        gPath[1].lineTo(-0.025f, -0.025f);
-        gPath[1].lineTo( 0.025f, -0.025f);
-        gPath[1].lineTo( 0.025f,  0.025f);
-        gPath[1].lineTo(-0.025f,  0.025f);
+        gPath[1] = SkPath::Polygon({{-0.025f, -0.025f},
+                                    {-0.025f, -0.025f},
+                                    { 0.025f, -0.025f},
+                                    { 0.025f,  0.025f},
+                                    {-0.025f,  0.025f}}, false);
         // clipped triangle
-        gPath[2].moveTo(-10.0f, -50.0f);
-        gPath[2].lineTo(-10.0f, -50.0f);
-        gPath[2].lineTo( 10.0f, -50.0f);
-        gPath[2].lineTo( 50.0f,  31.0f);
-        gPath[2].lineTo( 40.0f,  50.0f);
-        gPath[2].lineTo(-40.0f,  50.0f);
-        gPath[2].lineTo(-50.0f,  31.0f);
+        gPath[2] = SkPath::Polygon({{-10.0f, -50.0f},
+                                    {-10.0f, -50.0f},
+                                    { 10.0f, -50.0f},
+                                    { 50.0f,  31.0f},
+                                    { 40.0f,  50.0f},
+                                    {-40.0f,  50.0f},
+                                    {-50.0f,  31.0f}}, false);
 
         for (size_t i = 0; i < SK_ARRAY_COUNT(gPath); i++) {
             SkASSERT(gPath[i].isConvex());
diff --git a/src/utils/SkLua.cpp b/src/utils/SkLua.cpp
index bba28f9..958e645 100644
--- a/src/utils/SkLua.cpp
+++ b/src/utils/SkLua.cpp
@@ -20,7 +20,7 @@
 #include "include/core/SkImage.h"
 #include "include/core/SkMatrix.h"
 #include "include/core/SkPaint.h"
-#include "include/core/SkPath.h"
+#include "include/core/SkPathBuilder.h"
 #include "include/core/SkPictureRecorder.h"
 #include "include/core/SkRRect.h"
 #include "include/core/SkString.h"
@@ -62,6 +62,7 @@
 DEF_MTNAME(SkRRect)
 DEF_MTNAME(SkPath)
 DEF_MTNAME(SkPaint)
+DEF_MTNAME(SkPathBuilder)
 DEF_MTNAME(SkPathEffect)
 DEF_MTNAME(SkPicture)
 DEF_MTNAME(SkPictureRecorder)
@@ -530,7 +531,7 @@
 }
 
 static int lcanvas_drawPath(lua_State* L) {
-    get_ref<SkCanvas>(L, 1)->drawPath(*get_obj<SkPath>(L, 2),
+    get_ref<SkCanvas>(L, 1)->drawPath(get_obj<SkPathBuilder>(L, 2)->snapshot(),
                                       *get_obj<SkPaint>(L, 3));
     return 0;
 }
@@ -879,19 +880,6 @@
     return 0;
 }
 
-static int lpaint_getFillPath(lua_State* L) {
-    const SkPaint* paint = get_obj<SkPaint>(L, 1);
-    const SkPath* path = get_obj<SkPath>(L, 2);
-
-    SkPath fillpath;
-    paint->getFillPath(*path, &fillpath);
-
-    SkLua lua(L);
-    lua.pushPath(fillpath);
-
-    return 1;
-}
-
 static int lpaint_gc(lua_State* L) {
     get_obj<SkPaint>(L, 1)->~SkPaint();
     return 0;
@@ -923,7 +911,6 @@
     { "getShader", lpaint_getShader },
     { "setShader", lpaint_setShader },
     { "getPathEffect", lpaint_getPathEffect },
-    { "getFillPath", lpaint_getFillPath },
     { "__gc", lpaint_gc },
     { nullptr, nullptr }
 };
@@ -1243,7 +1230,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 static int lpath_getBounds(lua_State* L) {
-    SkLua(L).pushRect(get_obj<SkPath>(L, 1)->getBounds());
+    SkLua(L).pushRect(get_obj<SkPathBuilder>(L, 1)->computeBounds());
     return 1;
 }
 
@@ -1262,7 +1249,7 @@
 }
 
 static int lpath_getFillType(lua_State* L) {
-    SkPathFillType fill = get_obj<SkPath>(L, 1)->getFillType();
+    SkPathFillType fill = get_obj<SkPathBuilder>(L, 1)->fillType();
     SkLua(L).pushString(fill_type_to_str(fill));
     return 1;
 }
@@ -1303,25 +1290,25 @@
 }
 
 static int lpath_getSegmentTypes(lua_State* L) {
-    uint32_t segMasks = get_obj<SkPath>(L, 1)->getSegmentMasks();
+    uint32_t segMasks = get_obj<SkPathBuilder>(L, 1)->snapshot().getSegmentMasks();
     SkLua(L).pushString(segment_masks_to_str(segMasks));
     return 1;
 }
 
 static int lpath_isConvex(lua_State* L) {
-    bool isConvex = get_obj<SkPath>(L, 1)->isConvex();
+    bool isConvex = get_obj<SkPathBuilder>(L, 1)->snapshot().isConvex();
     SkLua(L).pushBool(isConvex);
     return 1;
 }
 
 static int lpath_isEmpty(lua_State* L) {
-    lua_pushboolean(L, get_obj<SkPath>(L, 1)->isEmpty());
+    lua_pushboolean(L, get_obj<SkPathBuilder>(L, 1)->snapshot().isEmpty());
     return 1;
 }
 
 static int lpath_isRect(lua_State* L) {
     SkRect r;
-    bool pred = get_obj<SkPath>(L, 1)->isRect(&r);
+    bool pred = get_obj<SkPathBuilder>(L, 1)->snapshot().isRect(&r);
     int ret_count = 1;
     lua_pushboolean(L, pred);
     if (pred) {
@@ -1332,13 +1319,13 @@
 }
 
 static int lpath_countPoints(lua_State* L) {
-    lua_pushinteger(L, get_obj<SkPath>(L, 1)->countPoints());
+    lua_pushinteger(L, get_obj<SkPathBuilder>(L, 1)->snapshot().countPoints());
     return 1;
 }
 
 static int lpath_getVerbs(lua_State* L) {
-    const SkPath* path = get_obj<SkPath>(L, 1);
-    SkPath::Iter iter(*path, false);
+    SkPath path = get_obj<SkPathBuilder>(L, 1)->snapshot();
+    SkPath::Iter iter(path, false);
     SkPoint pts[4];
 
     lua_newtable(L);
@@ -1376,40 +1363,40 @@
 }
 
 static int lpath_reset(lua_State* L) {
-    get_obj<SkPath>(L, 1)->reset();
+    get_obj<SkPathBuilder>(L, 1)->reset();
     return 0;
 }
 
 static int lpath_moveTo(lua_State* L) {
-    get_obj<SkPath>(L, 1)->moveTo(lua2scalar(L, 2), lua2scalar(L, 3));
+    get_obj<SkPathBuilder>(L, 1)->moveTo(lua2scalar(L, 2), lua2scalar(L, 3));
     return 0;
 }
 
 static int lpath_lineTo(lua_State* L) {
-    get_obj<SkPath>(L, 1)->lineTo(lua2scalar(L, 2), lua2scalar(L, 3));
+    get_obj<SkPathBuilder>(L, 1)->lineTo(lua2scalar(L, 2), lua2scalar(L, 3));
     return 0;
 }
 
 static int lpath_quadTo(lua_State* L) {
-    get_obj<SkPath>(L, 1)->quadTo(lua2scalar(L, 2), lua2scalar(L, 3),
+    get_obj<SkPathBuilder>(L, 1)->quadTo(lua2scalar(L, 2), lua2scalar(L, 3),
                                   lua2scalar(L, 4), lua2scalar(L, 5));
     return 0;
 }
 
 static int lpath_cubicTo(lua_State* L) {
-    get_obj<SkPath>(L, 1)->cubicTo(lua2scalar(L, 2), lua2scalar(L, 3),
+    get_obj<SkPathBuilder>(L, 1)->cubicTo(lua2scalar(L, 2), lua2scalar(L, 3),
                                    lua2scalar(L, 4), lua2scalar(L, 5),
                                    lua2scalar(L, 6), lua2scalar(L, 7));
     return 0;
 }
 
 static int lpath_close(lua_State* L) {
-    get_obj<SkPath>(L, 1)->close();
+    get_obj<SkPathBuilder>(L, 1)->close();
     return 0;
 }
 
 static int lpath_gc(lua_State* L) {
-    get_obj<SkPath>(L, 1)->~SkPath();
+    get_obj<SkPathBuilder>(L, 1)->~SkPathBuilder();
     return 0;
 }
 
@@ -1824,7 +1811,7 @@
 }
 
 static int lsk_newPath(lua_State* L) {
-    push_new<SkPath>(L);
+    push_new<SkPathBuilder>(L);
     return 1;
 }