Initial SVG model

A minimal subset needed to render tiger.svg: <svg>, <g>, <path>, 'd', 'fill'/'stroke' (color-only), 'transform'.

R=reed@google.com,robertphillips@google.com
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2164193002

Review-Url: https://codereview.chromium.org/2164193002
diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp
index 0747fcf..64d460f 100644
--- a/samplecode/SampleApp.cpp
+++ b/samplecode/SampleApp.cpp
@@ -80,6 +80,17 @@
     }
 };
 
+extern SampleView* CreateSampleSVGFileView(const char filename[]);
+
+class SVGFileFactory : public SkViewFactory {
+    SkString fFilename;
+public:
+    SVGFileFactory(const SkString& filename) : fFilename(filename) {}
+    SkView* operator() () const override {
+        return CreateSampleSVGFileView(fFilename.c_str());
+    }
+};
+
 #ifdef SAMPLE_PDF_FILE_VIEWER
 extern SampleView* CreateSamplePdfFileViewer(const char filename[]);
 
@@ -678,6 +689,8 @@
 DEFINE_bool(deepColor, false, "Request deep color (10-bit/channel or more) display buffer.");
 DEFINE_string(pictureDir, "", "Read pictures from here.");
 DEFINE_string(picture, "", "Path to single picture.");
+DEFINE_string(svg, "", "Path to single SVG file.");
+DEFINE_string(svgDir, "", "Read SVGs from here.");
 DEFINE_string(sequence, "", "Path to file containing the desired samples/gms to show.");
 DEFINE_bool(sort, false, "Sort samples by title.");
 DEFINE_bool(list, false, "List samples?");
@@ -711,6 +724,19 @@
         fCurrIndex = fSamples.count();
         *fSamples.append() = new PictFileFactory(path);
     }
+    if (!FLAGS_svg.isEmpty()) {
+        SkString path(FLAGS_svg[0]);
+        fCurrIndex = fSamples.count();
+        *fSamples.append() = new SVGFileFactory(path);
+    }
+    if (!FLAGS_svgDir.isEmpty()) {
+        SkOSFile::Iter iter(FLAGS_svgDir[0], "svg");
+        SkString filename;
+        while (iter.next(&filename)) {
+            *fSamples.append() = new SVGFileFactory(
+                SkOSPath::Join(FLAGS_svgDir[0], filename.c_str()));
+        }
+    }
 #ifdef SAMPLE_PDF_FILE_VIEWER
     if (!FLAGS_pdfPath.isEmpty()) {
         SkOSFile::Iter iter(FLAGS_pdfPath[0], "pdf");
diff --git a/samplecode/SampleSVGFile.cpp b/samplecode/SampleSVGFile.cpp
new file mode 100644
index 0000000..01a1958
--- /dev/null
+++ b/samplecode/SampleSVGFile.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SampleCode.h"
+#include "SkCanvas.h"
+#include "SkDOM.h"
+#include "SkStream.h"
+#include "SkSVGDOM.h"
+#include "SkView.h"
+
+namespace {
+
+class SVGFileView : public SampleView {
+public:
+    SVGFileView(const char path[]) {
+        SkFILEStream svgStream(path);
+        if (!svgStream.isValid()) {
+            SkDebugf("file not found: \"path\"\n", path);
+            return;
+        }
+
+        SkDOM xmlDom;
+        if (!xmlDom.build(svgStream)) {
+            SkDebugf("XML parsing failed: \"path\"\n", path);
+            return;
+        }
+
+        fDom = SkSVGDOM::MakeFromDOM(xmlDom, SkSize::Make(this->width(), this->height()));
+    }
+
+    virtual ~SVGFileView() = default;
+
+protected:
+    void onDrawContent(SkCanvas* canvas) override {
+        if (fDom) {
+            fDom->render(canvas);
+        }
+    }
+
+    void onSizeChange() override {
+        if (fDom) {
+            fDom->setContainerSize(SkSize::Make(this->width(), this->height()));
+        }
+
+        this->INHERITED::onSizeChange();
+    }
+
+private:
+    sk_sp<SkSVGDOM> fDom;
+
+    typedef SampleView INHERITED;
+};
+
+} // anonymous namespace
+
+SampleView* CreateSampleSVGFileView(const char filename[]);
+SampleView* CreateSampleSVGFileView(const char filename[]) {
+    return new SVGFileView(filename);
+}