skpbench: Support .svg files

Bug: skia:
Change-Id: I0337757f635c631870c02a65f8784fc190d1435e
Reviewed-on: https://skia-review.googlesource.com/137540
Commit-Queue: Chris Dalton <csmartdalton@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/tools/skpbench/skpbench.cpp b/tools/skpbench/skpbench.cpp
index 399bf6c..55fbc00 100644
--- a/tools/skpbench/skpbench.cpp
+++ b/tools/skpbench/skpbench.cpp
@@ -37,10 +37,17 @@
 #include "picture_utils.h"
 #include "sk_tool_utils.h"
 
+#ifdef SK_XML
+#include "SkDOM.h"
+#include "../experimental/svg/model/SkSVGDOM.h"
+#endif
+
+
 /**
- * This is a minimalist program whose sole purpose is to open an skp file, benchmark it on a single
- * config, and exit. It is intended to be used through skpbench.py rather than invoked directly.
- * Limiting the entire process to a single config/skp pair helps to keep the results repeatable.
+ * This is a minimalist program whose sole purpose is to open a .skp or .svg file, benchmark it on a
+ * single config, and exit. It is intended to be used through skpbench.py rather than invoked
+ * directly. Limiting the entire process to a single config/skp pair helps to keep the results
+ * repeatable.
  *
  * No tiling, looping, or other fanciness is used; it just draws the skp whole into a size-matched
  * render target and syncs the GPU after each draw.
@@ -57,7 +64,7 @@
 DEFINE_int32(sampleMs, 50, "minimum duration of a sample");
 DEFINE_bool(gpuClock, false, "time on the gpu clock (gpu work only)");
 DEFINE_bool(fps, false, "use fps instead of ms");
-DEFINE_string(skp, "", "path to a single .skp file, or 'warmup' for a builtin warmup run");
+DEFINE_string(src, "", "path to a single .skp or .svg file, or 'warmup' for a builtin warmup run");
 DEFINE_string(png, "", "if set, save a .png proof to disk at this file location");
 DEFINE_int32(verbosity, 4, "level of verbosity (0=none to 5=debug)");
 DEFINE_bool(suppressHeader, false, "don't print a header row before the results");
@@ -108,6 +115,7 @@
 
 static void draw_skp_and_flush(SkCanvas*, const SkPicture*);
 static sk_sp<SkPicture> create_warmup_skp();
+static sk_sp<SkPicture> create_skp_from_svg(SkStream*, const char* filename);
 static bool mkdir_p(const SkString& name);
 static SkString join(const SkCommandLineFlags::StringArray&);
 static void exitf(ExitErr, const char* format, ...);
@@ -337,36 +345,41 @@
     }
 
     // Parse the skp.
-    if (FLAGS_skp.count() != 1) {
-        exitf(ExitErr::kUsage, "invalid skp '%s': must specify a single skp file, or 'warmup'",
-                               join(FLAGS_skp).c_str());
+    if (FLAGS_src.count() != 1) {
+        exitf(ExitErr::kUsage,
+              "invalid input '%s': must specify a single .skp or .svg file, or 'warmup'",
+              join(FLAGS_src).c_str());
     }
 
     SkGraphics::Init();
 
     sk_sp<SkPicture> skp;
-    SkString skpname;
-    if (0 == strcmp(FLAGS_skp[0], "warmup")) {
+    SkString srcname;
+    if (0 == strcmp(FLAGS_src[0], "warmup")) {
         skp = create_warmup_skp();
-        skpname = "warmup";
+        srcname = "warmup";
     } else {
-        const char* skpfile = FLAGS_skp[0];
-        std::unique_ptr<SkStream> skpstream(SkStream::MakeFromFile(skpfile));
-        if (!skpstream) {
-            exitf(ExitErr::kIO, "failed to open skp file %s", skpfile);
+        SkString srcfile(FLAGS_src[0]);
+        std::unique_ptr<SkStream> srcstream(SkStream::MakeFromFile(srcfile.c_str()));
+        if (!srcstream) {
+            exitf(ExitErr::kIO, "failed to open file %s", srcfile.c_str());
         }
-        skp = SkPicture::MakeFromStream(skpstream.get());
+        if (srcfile.endsWith(".svg")) {
+            skp = create_skp_from_svg(srcstream.get(), srcfile.c_str());
+        } else {
+            skp = SkPicture::MakeFromStream(srcstream.get());
+        }
         if (!skp) {
-            exitf(ExitErr::kData, "failed to parse skp file %s", skpfile);
+            exitf(ExitErr::kData, "failed to parse file %s", srcfile.c_str());
         }
-        skpname = SkOSPath::Basename(skpfile);
+        srcname = SkOSPath::Basename(srcfile.c_str());
     }
     int width = SkTMin(SkScalarCeilToInt(skp->cullRect().width()), 2048),
         height = SkTMin(SkScalarCeilToInt(skp->cullRect().height()), 2048);
     if (FLAGS_verbosity >= 3 &&
         (width != skp->cullRect().width() || height != skp->cullRect().height())) {
         fprintf(stderr, "%s is too large (%ix%i), cropping to %ix%i.\n",
-                        skpname.c_str(), SkScalarCeilToInt(skp->cullRect().width()),
+                        srcname.c_str(), SkScalarCeilToInt(skp->cullRect().width()),
                         SkScalarCeilToInt(skp->cullRect().height()), width, height);
     }
 
@@ -448,7 +461,7 @@
         run_gpu_time_benchmark(testCtx->gpuTimer(), testCtx->fenceSync(), canvas, skp.get(),
                                &samples);
     }
-    print_result(samples, config->getTag().c_str(), skpname.c_str());
+    print_result(samples, config->getTag().c_str(), srcname.c_str());
 
     // Save a proof (if one was requested).
     if (!FLAGS_png.isEmpty()) {
@@ -499,6 +512,29 @@
     return recorder.finishRecordingAsPicture();
 }
 
+static sk_sp<SkPicture> create_skp_from_svg(SkStream* stream, const char* filename) {
+#ifdef SK_XML
+    SkDOM xml;
+    if (!xml.build(*stream)) {
+        exitf(ExitErr::kData, "failed to parse xml in file %s", filename);
+    }
+    sk_sp<SkSVGDOM> svg = SkSVGDOM::MakeFromDOM(xml);
+    if (!svg) {
+        exitf(ExitErr::kData, "failed to build svg dom from file %s", filename);
+    }
+
+    static constexpr SkRect bounds{0, 0, 1200, 1200};
+    SkPictureRecorder recorder;
+    SkCanvas* recording = recorder.beginRecording(bounds);
+
+    svg->setContainerSize(SkSize::Make(recording->getBaseLayerSize()));
+    svg->render(recording);
+
+    return recorder.finishRecordingAsPicture();
+#endif
+    exitf(ExitErr::kData, "SK_XML is disabled; cannot open svg file %s", filename);
+}
+
 bool mkdir_p(const SkString& dirname) {
     if (dirname.isEmpty()) {
         return true;