[SVGDom] Expose intrinsic size info

  * expose intrinsic size info on <svg> nodes.

  * tweak the SkSVGDOM constructor to no longer take an container size
    param, but instead default to intrinsic size
  * update clients to call SkSVGDOM::setContainerSize() explicitly, when
    needed

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

Review-Url: https://codereview.chromium.org/2345533002
diff --git a/bench/nanobench.cpp b/bench/nanobench.cpp
index ef22dee..ca403f5 100644
--- a/bench/nanobench.cpp
+++ b/bench/nanobench.cpp
@@ -651,16 +651,21 @@
             return nullptr;
         }
 
-        // TODO: use intrinsic size? make tunable via flag?
-        static const SkSize kContainerSize = SkSize::Make(128, 128);
-        sk_sp<SkSVGDOM> svgDom = SkSVGDOM::MakeFromStream(stream, kContainerSize);
+        sk_sp<SkSVGDOM> svgDom = SkSVGDOM::MakeFromStream(stream);
         if (!svgDom) {
             SkDebugf("Could not parse %s.\n", path);
             return nullptr;
         }
 
+        // Use the intrinsic SVG size if available, otherwise fall back to a default value.
+        static const SkSize kDefaultContainerSize = SkSize::Make(128, 128);
+        if (svgDom->containerSize().isEmpty()) {
+            svgDom->setContainerSize(kDefaultContainerSize);
+        }
+
         SkPictureRecorder recorder;
-        svgDom->render(recorder.beginRecording(kContainerSize.width(), kContainerSize.height()));
+        svgDom->render(recorder.beginRecording(svgDom->containerSize().width(),
+                                               svgDom->containerSize().height()));
         return recorder.finishRecordingAsPicture();
     }
 
diff --git a/dm/DMSrcSink.cpp b/dm/DMSrcSink.cpp
index 0c7de85..0cdb70e 100644
--- a/dm/DMSrcSink.cpp
+++ b/dm/DMSrcSink.cpp
@@ -1043,11 +1043,12 @@
         return SkStringPrintf("Unable to open file: %s", fPath.c_str());
     }
 
-    sk_sp<SkSVGDOM> dom = SkSVGDOM::MakeFromStream(stream, kSVGSize);
+    sk_sp<SkSVGDOM> dom = SkSVGDOM::MakeFromStream(stream);
     if (!dom) {
         return SkStringPrintf("Unable to parse file: %s", fPath.c_str());
     }
 
+    dom->setContainerSize(kSVGSize);
     dom->render(canvas);
 
     return "";
diff --git a/experimental/svg/model/SkSVGDOM.cpp b/experimental/svg/model/SkSVGDOM.cpp
index f467c5e..c9745f1 100644
--- a/experimental/svg/model/SkSVGDOM.cpp
+++ b/experimental/svg/model/SkSVGDOM.cpp
@@ -384,26 +384,29 @@
 
 } // anonymous namespace
 
-SkSVGDOM::SkSVGDOM(const SkSize& containerSize)
-    : fContainerSize(containerSize) {
+SkSVGDOM::SkSVGDOM()
+    : fContainerSize(SkSize::Make(0, 0)) {
 }
 
-sk_sp<SkSVGDOM> SkSVGDOM::MakeFromDOM(const SkDOM& xmlDom, const SkSize& containerSize) {
-    sk_sp<SkSVGDOM> dom = sk_make_sp<SkSVGDOM>(containerSize);
+sk_sp<SkSVGDOM> SkSVGDOM::MakeFromDOM(const SkDOM& xmlDom) {
+    sk_sp<SkSVGDOM> dom = sk_make_sp<SkSVGDOM>();
 
     ConstructionContext ctx(&dom->fIDMapper);
     dom->fRoot = construct_svg_node(xmlDom, ctx, xmlDom.getRootNode());
 
+    // Reset the default container size to match the intrinsic SVG size.
+    dom->setContainerSize(dom->intrinsicSize());
+
     return dom;
 }
 
-sk_sp<SkSVGDOM> SkSVGDOM::MakeFromStream(SkStream& svgStream, const SkSize& containerSize) {
+sk_sp<SkSVGDOM> SkSVGDOM::MakeFromStream(SkStream& svgStream) {
     SkDOM xmlDom;
     if (!xmlDom.build(svgStream)) {
         return nullptr;
     }
 
-    return MakeFromDOM(xmlDom, containerSize);
+    return MakeFromDOM(xmlDom);
 }
 
 void SkSVGDOM::render(SkCanvas* canvas) const {
@@ -416,6 +419,20 @@
     }
 }
 
+SkSize SkSVGDOM::intrinsicSize() const {
+    if (!fRoot || fRoot->tag() != SkSVGTag::kSvg) {
+        return SkSize::Make(0, 0);
+    }
+
+    // Intrinsic sizes are never relative, so the viewport size is irrelevant.
+    const SkSVGLengthContext lctx(SkSize::Make(0, 0));
+    return static_cast<const SkSVGSVG*>(fRoot.get())->intrinsicSize(lctx);
+}
+
+const SkSize& SkSVGDOM::containerSize() const {
+    return fContainerSize;
+}
+
 void SkSVGDOM::setContainerSize(const SkSize& containerSize) {
     // TODO: inval
     fContainerSize = containerSize;
diff --git a/experimental/svg/model/SkSVGDOM.h b/experimental/svg/model/SkSVGDOM.h
index 9c59b7c..8904c17 100644
--- a/experimental/svg/model/SkSVGDOM.h
+++ b/experimental/svg/model/SkSVGDOM.h
@@ -20,18 +20,22 @@
 
 class SkSVGDOM : public SkRefCnt {
 public:
-    SkSVGDOM(const SkSize& containerSize);
+    SkSVGDOM();
     ~SkSVGDOM() = default;
 
-    static sk_sp<SkSVGDOM> MakeFromDOM(const SkDOM&, const SkSize& containerSize);
-    static sk_sp<SkSVGDOM> MakeFromStream(SkStream&, const SkSize& containerSize);
+    static sk_sp<SkSVGDOM> MakeFromDOM(const SkDOM&);
+    static sk_sp<SkSVGDOM> MakeFromStream(SkStream&);
 
+    const SkSize& containerSize() const;
     void setContainerSize(const SkSize&);
+
     void setRoot(sk_sp<SkSVGNode>);
 
     void render(SkCanvas*) const;
 
 private:
+    SkSize intrinsicSize() const;
+
     SkSize           fContainerSize;
     sk_sp<SkSVGNode> fRoot;
     SkSVGIDMapper    fIDMapper;
diff --git a/experimental/svg/model/SkSVGSVG.cpp b/experimental/svg/model/SkSVGSVG.cpp
index 13f1804..5929927 100644
--- a/experimental/svg/model/SkSVGSVG.cpp
+++ b/experimental/svg/model/SkSVGSVG.cpp
@@ -95,3 +95,15 @@
         this->INHERITED::onSetAttribute(attr, v);
     }
 }
+
+// https://www.w3.org/TR/SVG/coords.html#IntrinsicSizing
+SkSize SkSVGSVG::intrinsicSize(const SkSVGLengthContext& lctx) const {
+    // Percentage values do not provide an intrinsic size.
+    if (fWidth.unit() == SkSVGLength::Unit::kPercentage ||
+        fHeight.unit() == SkSVGLength::Unit::kPercentage) {
+        return SkSize::Make(0, 0);
+    }
+
+    return SkSize::Make(lctx.resolve(fWidth, SkSVGLengthContext::LengthType::kHorizontal),
+                        lctx.resolve(fHeight, SkSVGLengthContext::LengthType::kVertical));
+}
diff --git a/experimental/svg/model/SkSVGSVG.h b/experimental/svg/model/SkSVGSVG.h
index ae4787c..675c833 100644
--- a/experimental/svg/model/SkSVGSVG.h
+++ b/experimental/svg/model/SkSVGSVG.h
@@ -12,6 +12,8 @@
 #include "SkSVGTypes.h"
 #include "SkTLazy.h"
 
+class SkSVGLengthContext;
+
 class SkSVGSVG : public SkSVGContainer {
 public:
     virtual ~SkSVGSVG() = default;
@@ -24,6 +26,8 @@
     void setHeight(const SkSVGLength&);
     void setViewBox(const SkSVGViewBoxType&);
 
+    SkSize intrinsicSize(const SkSVGLengthContext&) const;
+
 protected:
     bool onPrepareToRender(SkSVGRenderContext*) const override;
 
diff --git a/samplecode/SampleSVGFile.cpp b/samplecode/SampleSVGFile.cpp
index a4b5b34..61a6be7 100644
--- a/samplecode/SampleSVGFile.cpp
+++ b/samplecode/SampleSVGFile.cpp
@@ -35,7 +35,10 @@
             return;
         }
 
-        fDom = SkSVGDOM::MakeFromDOM(xmlDom, SkSize::Make(this->width(), this->height()));
+        fDom = SkSVGDOM::MakeFromDOM(xmlDom);
+        if (fDom) {
+            fDom->setContainerSize(SkSize::Make(this->width(), this->height()));
+        }
     }
 
     void onDrawContent(SkCanvas* canvas) override {
diff --git a/samplecode/SampleSVGPong.cpp b/samplecode/SampleSVGPong.cpp
index be107b6..590ec18 100644
--- a/samplecode/SampleSVGPong.cpp
+++ b/samplecode/SampleSVGPong.cpp
@@ -136,7 +136,8 @@
         // Handle everything in a normalized 1x1 space.
         root->setViewBox(SkSVGViewBoxType(SkRect::MakeWH(1, 1)));
 
-        fDom = sk_sp<SkSVGDOM>(new SkSVGDOM(SkSize::Make(this->width(), this->height())));
+        fDom = sk_sp<SkSVGDOM>(new SkSVGDOM());
+        fDom->setContainerSize(SkSize::Make(this->width(), this->height()));
         fDom->setRoot(std::move(root));
 
         // Off we go.