[svg] Text asPath() support

Enables use of text as a clip path.

Bug: skia:10840
Change-Id: I9de40e23696083e8cdd7e0b82221da3f3c36ac8b
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/358533
Reviewed-by: Tyler Denniston <tdenniston@google.com>
Commit-Queue: Florin Malita <fmalita@google.com>
diff --git a/modules/svg/src/SkSVGText.cpp b/modules/svg/src/SkSVGText.cpp
index a5f1609..c571c30 100644
--- a/modules/svg/src/SkSVGText.cpp
+++ b/modules/svg/src/SkSVGText.cpp
@@ -14,6 +14,7 @@
 #include "include/core/SkFont.h"
 #include "include/core/SkFontMgr.h"
 #include "include/core/SkFontStyle.h"
+#include "include/core/SkPathBuilder.h"
 #include "include/core/SkRSXform.h"
 #include "include/core/SkString.h"
 #include "modules/skshaper/include/SkShaper.h"
@@ -594,6 +595,53 @@
     return bounds;
 }
 
+SkPath SkSVGText::onAsPath(const SkSVGRenderContext& ctx) const {
+    SkPathBuilder builder;
+
+    const SkSVGTextContext::ShapedTextCallback as_path =
+        [&builder](const SkSVGRenderContext& ctx, const sk_sp<SkTextBlob>& blob, const SkPaint*,
+                   const SkPaint*) {
+            if (!blob) {
+                return;
+            }
+
+            SkTextBlobRunIterator it(blob.get());
+            for (SkTextBlobRunIterator it(blob.get()); !it.done(); it.next()) {
+                struct GetPathsCtx {
+                    SkPathBuilder&   builder;
+                    const SkRSXform* xform;
+                } get_paths_ctx {builder, it.xforms()};
+
+                it.font().getPaths(it.glyphs(), it.glyphCount(), [](const SkPath* path,
+                                                                    const SkMatrix& matrix,
+                                                                    void* raw_ctx) {
+                    auto* get_paths_ctx = static_cast<GetPathsCtx*>(raw_ctx);
+                    const auto& glyph_rsx = *get_paths_ctx->xform++;
+
+                    if (!path) {
+                        return;
+                    }
+
+                    SkMatrix glyph_matrix;
+                    glyph_matrix.setRSXform(glyph_rsx);
+                    glyph_matrix.preConcat(matrix);
+
+                    get_paths_ctx->builder.addPath(path->makeTransform(glyph_matrix));
+                }, &get_paths_ctx);
+            }
+        };
+
+    {
+        SkSVGTextContext tctx(ctx, as_path);
+        this->onShapeText(ctx, &tctx, this->getXmlSpace());
+    }
+
+    auto path = builder.detach();
+    this->mapToParent(&path);
+
+    return path;
+}
+
 void SkSVGTextPath::onShapeText(const SkSVGRenderContext& ctx, SkSVGTextContext* parent_tctx,
                                  SkSVGXmlSpace xs) const {
     SkASSERT(parent_tctx);