[svg] Add support for preserveAspectRatio

This fixes the aspect ratio for pretty much all tests.

Since we're going to rebaseline everything, also have dm use a white
background (to match other user agents).

Bug: skia:10842
Change-Id: Iab2afd61560af540539c216d1c3673f19fe0fe51
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/328982
Commit-Queue: Florin Malita <fmalita@chromium.org>
Commit-Queue: Florin Malita <fmalita@google.com>
Reviewed-by: Tyler Denniston <tdenniston@google.com>
diff --git a/dm/DMSrcSink.cpp b/dm/DMSrcSink.cpp
index eb2ff11..4d850a3 100644
--- a/dm/DMSrcSink.cpp
+++ b/dm/DMSrcSink.cpp
@@ -1326,6 +1326,7 @@
 
     SkAutoCanvasRestore acr(canvas, true);
     canvas->scale(fScale, fScale);
+    canvas->drawColor(SK_ColorWHITE);
     fDom->render(canvas);
 
     return Result::Ok();
diff --git a/modules/svg/include/SkSVGAttribute.h b/modules/svg/include/SkSVGAttribute.h
index bd8204a..22a2262 100644
--- a/modules/svg/include/SkSVGAttribute.h
+++ b/modules/svg/include/SkSVGAttribute.h
@@ -37,6 +37,7 @@
     kOpacity,
     kPatternTransform,
     kPoints,
+    kPreserveAspectRatio,
     kR,  // <circle>, <radialGradient>: radius
     kRx, // <ellipse>,<rect>: horizontal (corner) radius
     kRy, // <ellipse>,<rect>: vertical (corner) radius
diff --git a/modules/svg/include/SkSVGAttributeParser.h b/modules/svg/include/SkSVGAttributeParser.h
index 1876dea..2e5f11c 100644
--- a/modules/svg/include/SkSVGAttributeParser.h
+++ b/modules/svg/include/SkSVGAttributeParser.h
@@ -32,6 +32,7 @@
     bool parseGradientUnits(SkSVGGradientUnits*);
     bool parseVisibility(SkSVGVisibility*);
     bool parseDashArray(SkSVGDashArray*);
+    bool parsePreserveAspectRatio(SkSVGPreserveAspectRatio*);
 
     bool parseFontFamily(SkSVGFontFamily*);
     bool parseFontSize(SkSVGFontSize*);
diff --git a/modules/svg/include/SkSVGNode.h b/modules/svg/include/SkSVGNode.h
index 8f493d2..a2991f1 100644
--- a/modules/svg/include/SkSVGNode.h
+++ b/modules/svg/include/SkSVGNode.h
@@ -128,4 +128,14 @@
     using INHERITED = SkRefCnt;
 };
 
+#undef SVG_PRES_ATTR // presentation attributes are only defined for the base class
+
+#define SVG_ATTR(attr_name, attr_type, attr_default)                      \
+    private:                                                              \
+        attr_type f##attr_name = attr_default;                            \
+    public:                                                               \
+        const attr_type& get##attr_name() const { return f##attr_name; }  \
+        void set##attr_name(const attr_type& a) { f##attr_name = a; }     \
+        void set##attr_name(attr_type&& a) { f##attr_name = std::move(a); }
+
 #endif // SkSVGNode_DEFINED
diff --git a/modules/svg/include/SkSVGSVG.h b/modules/svg/include/SkSVGSVG.h
index 7494d78..46ecfc9 100644
--- a/modules/svg/include/SkSVGSVG.h
+++ b/modules/svg/include/SkSVGSVG.h
@@ -20,10 +20,13 @@
 
     static sk_sp<SkSVGSVG> Make() { return sk_sp<SkSVGSVG>(new SkSVGSVG()); }
 
-    void setX(const SkSVGLength&);
-    void setY(const SkSVGLength&);
-    void setWidth(const SkSVGLength&);
-    void setHeight(const SkSVGLength&);
+    SVG_ATTR(X                  , SkSVGLength, SkSVGLength(0))
+    SVG_ATTR(Y                  , SkSVGLength, SkSVGLength(0))
+    SVG_ATTR(Width              , SkSVGLength, SkSVGLength(100, SkSVGLength::Unit::kPercentage))
+    SVG_ATTR(Height             , SkSVGLength, SkSVGLength(100, SkSVGLength::Unit::kPercentage))
+    SVG_ATTR(PreserveAspectRatio, SkSVGPreserveAspectRatio, SkSVGPreserveAspectRatio())
+
+    // TODO: SVG_ATTR is not smart enough to handle SkTLazy<T>
     void setViewBox(const SkSVGViewBoxType&);
 
     SkSize intrinsicSize(const SkSVGLengthContext&) const;
@@ -36,11 +39,6 @@
 private:
     SkSVGSVG();
 
-    SkSVGLength fX      = SkSVGLength(0);
-    SkSVGLength fY      = SkSVGLength(0);
-    SkSVGLength fWidth  = SkSVGLength(100, SkSVGLength::Unit::kPercentage);
-    SkSVGLength fHeight = SkSVGLength(100, SkSVGLength::Unit::kPercentage);
-
     SkTLazy<SkSVGViewBoxType> fViewBox;
 
     using INHERITED = SkSVGContainer;
diff --git a/modules/svg/include/SkSVGTypes.h b/modules/svg/include/SkSVGTypes.h
index 5f535de..6e84f85 100644
--- a/modules/svg/include/SkSVGTypes.h
+++ b/modules/svg/include/SkSVGTypes.h
@@ -437,4 +437,30 @@
     Type fType;
 };
 
+struct SkSVGPreserveAspectRatio {
+    enum Align : uint8_t {
+        // These values are chosen such that bits [0,1] encode X alignment, and
+        // bits [2,3] encode Y alignment.
+        kXMinYMin = 0x00,
+        kXMidYMin = 0x01,
+        kXMaxYMin = 0x02,
+        kXMinYMid = 0x04,
+        kXMidYMid = 0x05,
+        kXMaxYMid = 0x06,
+        kXMinYMax = 0x08,
+        kXMidYMax = 0x09,
+        kXMaxYMax = 0x0a,
+
+        kNone     = 0x10,
+    };
+
+    enum Scale {
+        kMeet,
+        kSlice,
+    };
+
+    Align fAlign = kXMidYMid;
+    Scale fScale = kMeet;
+};
+
 #endif // SkSVGTypes_DEFINED
diff --git a/modules/svg/include/SkSVGValue.h b/modules/svg/include/SkSVGValue.h
index 9c9f251..b9ea659 100644
--- a/modules/svg/include/SkSVGValue.h
+++ b/modules/svg/include/SkSVGValue.h
@@ -34,6 +34,7 @@
         kPaint,
         kPath,
         kPoints,
+        kPreserveAspectRatio,
         kSpreadMethod,
         kStopColor,
         kString,
@@ -106,4 +107,7 @@
 using SkSVGFontStyleValue    = SkSVGWrapperValue<SkSVGFontStyle    , SkSVGValue::Type::kFontStyle >;
 using SkSVGFontWeightValue   = SkSVGWrapperValue<SkSVGFontWeight   , SkSVGValue::Type::kFontWeight>;
 
+using SkSVGPreserveAspectRatioValue = SkSVGWrapperValue<SkSVGPreserveAspectRatio,
+                                                        SkSVGValue::Type::kPreserveAspectRatio>;
+
 #endif // SkSVGValue_DEFINED
diff --git a/modules/svg/src/SkSVGAttributeParser.cpp b/modules/svg/src/SkSVGAttributeParser.cpp
index 8cfc6c3..a56e8e7 100644
--- a/modules/svg/src/SkSVGAttributeParser.cpp
+++ b/modules/svg/src/SkSVGAttributeParser.cpp
@@ -821,3 +821,41 @@
 
     return parsedValue && this->parseEOSToken();
 }
+
+// https://www.w3.org/TR/SVG11/coords.html#PreserveAspectRatioAttribute
+bool SkSVGAttributeParser::parsePreserveAspectRatio(SkSVGPreserveAspectRatio* par) {
+    static constexpr std::tuple<const char*, SkSVGPreserveAspectRatio::Align> gAlignMap[] = {
+        { "none"    , SkSVGPreserveAspectRatio::kNone     },
+        { "xMinYMin", SkSVGPreserveAspectRatio::kXMinYMin },
+        { "xMidYMin", SkSVGPreserveAspectRatio::kXMidYMin },
+        { "xMaxYMin", SkSVGPreserveAspectRatio::kXMaxYMin },
+        { "xMinYMid", SkSVGPreserveAspectRatio::kXMinYMid },
+        { "xMidYMid", SkSVGPreserveAspectRatio::kXMidYMid },
+        { "xMaxYMid", SkSVGPreserveAspectRatio::kXMaxYMid },
+        { "xMinYMax", SkSVGPreserveAspectRatio::kXMinYMax },
+        { "xMidYMax", SkSVGPreserveAspectRatio::kXMidYMax },
+        { "xMaxYMax", SkSVGPreserveAspectRatio::kXMaxYMax },
+    };
+
+    static constexpr std::tuple<const char*, SkSVGPreserveAspectRatio::Scale> gScaleMap[] = {
+        { "meet" , SkSVGPreserveAspectRatio::kMeet  },
+        { "slice", SkSVGPreserveAspectRatio::kSlice },
+    };
+
+    bool parsedValue = false;
+
+    // ignoring optional 'defer'
+    this->parseExpectedStringToken("defer");
+    this->parseWSToken();
+
+    if (this->parseEnumMap(gAlignMap, &par->fAlign)) {
+        parsedValue = true;
+
+        // optional scaling selector
+        this->parseWSToken();
+        this->parseEnumMap(gScaleMap, &par->fScale);
+    }
+
+    return parsedValue && this->parseEOSToken();
+}
+
diff --git a/modules/svg/src/SkSVGDOM.cpp b/modules/svg/src/SkSVGDOM.cpp
index 58f1ef0..27e2540 100644
--- a/modules/svg/src/SkSVGDOM.cpp
+++ b/modules/svg/src/SkSVGDOM.cpp
@@ -308,6 +308,18 @@
     return true;
 }
 
+bool SetPreserveAspectRatioAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
+                                     const char* stringValue) {
+    SkSVGPreserveAspectRatio par;
+    SkSVGAttributeParser parser(stringValue);
+    if (!parser.parsePreserveAspectRatio(&par)) {
+        return false;
+    }
+
+    node->setAttribute(attr, SkSVGPreserveAspectRatioValue(par));
+    return true;
+}
+
 SkString TrimmedString(const char* first, const char* last) {
     SkASSERT(first);
     SkASSERT(last);
@@ -386,57 +398,59 @@
 };
 
 SortedDictionaryEntry<AttrParseInfo> gAttributeParseInfo[] = {
-    { "clip-path"        , { SkSVGAttribute::kClipPath         , SetClipPathAttribute     }},
-    { "clip-rule"        , { SkSVGAttribute::kClipRule         , SetFillRuleAttribute     }},
-    { "color"            , { SkSVGAttribute::kColor            , SetColorAttribute        }},
-    { "cx"               , { SkSVGAttribute::kCx               , SetLengthAttribute       }},
-    { "cy"               , { SkSVGAttribute::kCy               , SetLengthAttribute       }},
-    { "d"                , { SkSVGAttribute::kD                , SetPathDataAttribute     }},
-    { "fill"             , { SkSVGAttribute::kFill             , SetPaintAttribute        }},
-    { "fill-opacity"     , { SkSVGAttribute::kFillOpacity      , SetNumberAttribute       }},
-    { "fill-rule"        , { SkSVGAttribute::kFillRule         , SetFillRuleAttribute     }},
-    { "font-family"      , { SkSVGAttribute::kFontFamily       , SetFontFamilyAttribute   }},
-    { "font-size"        , { SkSVGAttribute::kFontSize         , SetFontSizeAttribute     }},
-    { "font-style"       , { SkSVGAttribute::kFontStyle        , SetFontStyleAttribute    }},
-    { "font-weight"      , { SkSVGAttribute::kFontWeight       , SetFontWeightAttribute   }},
+    { "clip-path"          , { SkSVGAttribute::kClipPath         , SetClipPathAttribute     }},
+    { "clip-rule"          , { SkSVGAttribute::kClipRule         , SetFillRuleAttribute     }},
+    { "color"              , { SkSVGAttribute::kColor            , SetColorAttribute        }},
+    { "cx"                 , { SkSVGAttribute::kCx               , SetLengthAttribute       }},
+    { "cy"                 , { SkSVGAttribute::kCy               , SetLengthAttribute       }},
+    { "d"                  , { SkSVGAttribute::kD                , SetPathDataAttribute     }},
+    { "fill"               , { SkSVGAttribute::kFill             , SetPaintAttribute        }},
+    { "fill-opacity"       , { SkSVGAttribute::kFillOpacity      , SetNumberAttribute       }},
+    { "fill-rule"          , { SkSVGAttribute::kFillRule         , SetFillRuleAttribute     }},
+    { "font-family"        , { SkSVGAttribute::kFontFamily       , SetFontFamilyAttribute   }},
+    { "font-size"          , { SkSVGAttribute::kFontSize         , SetFontSizeAttribute     }},
+    { "font-style"         , { SkSVGAttribute::kFontStyle        , SetFontStyleAttribute    }},
+    { "font-weight"        , { SkSVGAttribute::kFontWeight       , SetFontWeightAttribute   }},
     // focal point x & y
-    { "fx"               , { SkSVGAttribute::kFx               , SetLengthAttribute       }},
-    { "fy"               , { SkSVGAttribute::kFy               , SetLengthAttribute       }},
-    { "gradientTransform", { SkSVGAttribute::kGradientTransform, SetTransformAttribute    }},
-    { "gradientUnits"    , { SkSVGAttribute::kGradientUnits    , SetGradientUnitsAttribute}},
-    { "height"           , { SkSVGAttribute::kHeight           , SetLengthAttribute       }},
-    { "offset"           , { SkSVGAttribute::kOffset           , SetLengthAttribute       }},
-    { "opacity"          , { SkSVGAttribute::kOpacity          , SetNumberAttribute       }},
-    { "patternTransform" , { SkSVGAttribute::kPatternTransform , SetTransformAttribute    }},
-    { "points"           , { SkSVGAttribute::kPoints           , SetPointsAttribute       }},
-    { "r"                , { SkSVGAttribute::kR                , SetLengthAttribute       }},
-    { "rx"               , { SkSVGAttribute::kRx               , SetLengthAttribute       }},
-    { "ry"               , { SkSVGAttribute::kRy               , SetLengthAttribute       }},
-    { "spreadMethod"     , { SkSVGAttribute::kSpreadMethod     , SetSpreadMethodAttribute }},
-    { "stop-color"       , { SkSVGAttribute::kStopColor        , SetStopColorAttribute    }},
-    { "stop-opacity"     , { SkSVGAttribute::kStopOpacity      , SetNumberAttribute       }},
-    { "stroke"           , { SkSVGAttribute::kStroke           , SetPaintAttribute        }},
-    { "stroke-dasharray" , { SkSVGAttribute::kStrokeDashArray  , SetDashArrayAttribute    }},
-    { "stroke-dashoffset", { SkSVGAttribute::kStrokeDashOffset , SetLengthAttribute       }},
-    { "stroke-linecap"   , { SkSVGAttribute::kStrokeLineCap    , SetLineCapAttribute      }},
-    { "stroke-linejoin"  , { SkSVGAttribute::kStrokeLineJoin   , SetLineJoinAttribute     }},
-    { "stroke-miterlimit", { SkSVGAttribute::kStrokeMiterLimit , SetNumberAttribute       }},
-    { "stroke-opacity"   , { SkSVGAttribute::kStrokeOpacity    , SetNumberAttribute       }},
-    { "stroke-width"     , { SkSVGAttribute::kStrokeWidth      , SetLengthAttribute       }},
-    { "style"            , { SkSVGAttribute::kUnknown          , SetStyleAttributes       }},
-    { "text"             , { SkSVGAttribute::kText             , SetStringAttribute       }},
-    { "text-anchor"      , { SkSVGAttribute::kTextAnchor       , SetStringAttribute       }},
-    { "transform"        , { SkSVGAttribute::kTransform        , SetTransformAttribute    }},
-    { "viewBox"          , { SkSVGAttribute::kViewBox          , SetViewBoxAttribute      }},
-    { "visibility"       , { SkSVGAttribute::kVisibility       , SetVisibilityAttribute   }},
-    { "width"            , { SkSVGAttribute::kWidth            , SetLengthAttribute       }},
-    { "x"                , { SkSVGAttribute::kX                , SetLengthAttribute       }},
-    { "x1"               , { SkSVGAttribute::kX1               , SetLengthAttribute       }},
-    { "x2"               , { SkSVGAttribute::kX2               , SetLengthAttribute       }},
-    { "xlink:href"       , { SkSVGAttribute::kHref             , SetIRIAttribute          }},
-    { "y"                , { SkSVGAttribute::kY                , SetLengthAttribute       }},
-    { "y1"               , { SkSVGAttribute::kY1               , SetLengthAttribute       }},
-    { "y2"               , { SkSVGAttribute::kY2               , SetLengthAttribute       }},
+    { "fx"                 , { SkSVGAttribute::kFx               , SetLengthAttribute       }},
+    { "fy"                 , { SkSVGAttribute::kFy               , SetLengthAttribute       }},
+    { "gradientTransform"  , { SkSVGAttribute::kGradientTransform, SetTransformAttribute    }},
+    { "gradientUnits"      , { SkSVGAttribute::kGradientUnits    , SetGradientUnitsAttribute}},
+    { "height"             , { SkSVGAttribute::kHeight           , SetLengthAttribute       }},
+    { "offset"             , { SkSVGAttribute::kOffset           , SetLengthAttribute       }},
+    { "opacity"            , { SkSVGAttribute::kOpacity          , SetNumberAttribute       }},
+    { "patternTransform"   , { SkSVGAttribute::kPatternTransform , SetTransformAttribute    }},
+    { "points"             , { SkSVGAttribute::kPoints           , SetPointsAttribute       }},
+    { "preserveAspectRatio", { SkSVGAttribute::kPreserveAspectRatio,
+                               SetPreserveAspectRatioAttribute }},
+    { "r"                  , { SkSVGAttribute::kR                , SetLengthAttribute       }},
+    { "rx"                 , { SkSVGAttribute::kRx               , SetLengthAttribute       }},
+    { "ry"                 , { SkSVGAttribute::kRy               , SetLengthAttribute       }},
+    { "spreadMethod"       , { SkSVGAttribute::kSpreadMethod     , SetSpreadMethodAttribute }},
+    { "stop-color"         , { SkSVGAttribute::kStopColor        , SetStopColorAttribute    }},
+    { "stop-opacity"       , { SkSVGAttribute::kStopOpacity      , SetNumberAttribute       }},
+    { "stroke"             , { SkSVGAttribute::kStroke           , SetPaintAttribute        }},
+    { "stroke-dasharray"   , { SkSVGAttribute::kStrokeDashArray  , SetDashArrayAttribute    }},
+    { "stroke-dashoffset"  , { SkSVGAttribute::kStrokeDashOffset , SetLengthAttribute       }},
+    { "stroke-linecap"     , { SkSVGAttribute::kStrokeLineCap    , SetLineCapAttribute      }},
+    { "stroke-linejoin"    , { SkSVGAttribute::kStrokeLineJoin   , SetLineJoinAttribute     }},
+    { "stroke-miterlimit"  , { SkSVGAttribute::kStrokeMiterLimit , SetNumberAttribute       }},
+    { "stroke-opacity"     , { SkSVGAttribute::kStrokeOpacity    , SetNumberAttribute       }},
+    { "stroke-width"       , { SkSVGAttribute::kStrokeWidth      , SetLengthAttribute       }},
+    { "style"              , { SkSVGAttribute::kUnknown          , SetStyleAttributes       }},
+    { "text"               , { SkSVGAttribute::kText             , SetStringAttribute       }},
+    { "text-anchor"        , { SkSVGAttribute::kTextAnchor       , SetStringAttribute       }},
+    { "transform"          , { SkSVGAttribute::kTransform        , SetTransformAttribute    }},
+    { "viewBox"            , { SkSVGAttribute::kViewBox          , SetViewBoxAttribute      }},
+    { "visibility"         , { SkSVGAttribute::kVisibility       , SetVisibilityAttribute   }},
+    { "width"              , { SkSVGAttribute::kWidth            , SetLengthAttribute       }},
+    { "x"                  , { SkSVGAttribute::kX                , SetLengthAttribute       }},
+    { "x1"                 , { SkSVGAttribute::kX1               , SetLengthAttribute       }},
+    { "x2"                 , { SkSVGAttribute::kX2               , SetLengthAttribute       }},
+    { "xlink:href"         , { SkSVGAttribute::kHref             , SetIRIAttribute          }},
+    { "y"                  , { SkSVGAttribute::kY                , SetLengthAttribute       }},
+    { "y1"                 , { SkSVGAttribute::kY1               , SetLengthAttribute       }},
+    { "y2"                 , { SkSVGAttribute::kY2               , SetLengthAttribute       }},
 };
 
 SortedDictionaryEntry<sk_sp<SkSVGNode>(*)()> gTagFactories[] = {
diff --git a/modules/svg/src/SkSVGSVG.cpp b/modules/svg/src/SkSVGSVG.cpp
index 2542d2b..4f2d573 100644
--- a/modules/svg/src/SkSVGSVG.cpp
+++ b/modules/svg/src/SkSVGSVG.cpp
@@ -12,6 +12,58 @@
 
 SkSVGSVG::SkSVGSVG() : INHERITED(SkSVGTag::kSvg) { }
 
+static SkMatrix ViewboxMatrix(const SkRect& view_box, const SkRect& view_port,
+                              const SkSVGPreserveAspectRatio& par) {
+    SkASSERT(!view_box.isEmpty());
+    SkASSERT(!view_port.isEmpty());
+
+    auto compute_scale = [&]() -> SkV2 {
+        const auto sx = view_port.width()  / view_box.width(),
+                   sy = view_port.height() / view_box.height();
+
+        if (par.fAlign == SkSVGPreserveAspectRatio::kNone) {
+            // none -> anisotropic scaling, regardless of fScale
+            return {sx,sy};
+        }
+
+        // isotropic scaling
+        const auto s = par.fScale == SkSVGPreserveAspectRatio::kMeet
+                            ? std::min(sx, sy)
+                            : std::max(sx, sy);
+        return {s,s};
+    };
+
+    auto compute_trans = [&](const SkV2& scale) -> SkV2 {
+        static constexpr float gAlignCoeffs[] = {
+            0.0f, // Min
+            0.5f, // Mid
+            1.0f  // Max
+        };
+
+        const size_t x_coeff = par.fAlign>>0 & 0x03,
+                     y_coeff = par.fAlign>>2 & 0x03;
+
+        SkASSERT(x_coeff < SK_ARRAY_COUNT(gAlignCoeffs) &&
+                 y_coeff < SK_ARRAY_COUNT(gAlignCoeffs));
+
+        const auto tx = -view_box.x() * scale.x,
+                   ty = -view_box.y() * scale.y,
+                   dx = view_port.width()  - view_box.width() * scale.x,
+                   dy = view_port.height() - view_box.height()* scale.y;
+
+        return {
+            tx + dx * gAlignCoeffs[x_coeff],
+            ty + dy * gAlignCoeffs[y_coeff]
+        };
+    };
+
+    const auto s = compute_scale(),
+               t = compute_trans(s);
+
+    return SkMatrix::Translate(t.x, t.y) *
+           SkMatrix::Scale(s.x, s.y);
+}
+
 bool SkSVGSVG::onPrepareToRender(SkSVGRenderContext* ctx) const {
     auto viewPortRect  = ctx->lengthContext().resolveRect(fX, fY, fWidth, fHeight);
     auto contentMatrix = SkMatrix::Translate(viewPortRect.x(), viewPortRect.y());
@@ -28,8 +80,7 @@
         // A viewBox overrides the intrinsic viewport.
         viewPort = SkSize::Make(viewBox.width(), viewBox.height());
 
-        contentMatrix.preConcat(
-            SkMatrix::MakeRectToRect(viewBox, viewPortRect, SkMatrix::kFill_ScaleToFit));
+        contentMatrix.preConcat(ViewboxMatrix(viewBox, viewPortRect, fPreserveAspectRatio));
     }
 
     if (!contentMatrix.isIdentity()) {
@@ -44,22 +95,6 @@
     return this->INHERITED::onPrepareToRender(ctx);
 }
 
-void SkSVGSVG::setX(const SkSVGLength& x) {
-    fX = x;
-}
-
-void SkSVGSVG::setY(const SkSVGLength& y) {
-    fY = y;
-}
-
-void SkSVGSVG::setWidth(const SkSVGLength& w) {
-    fWidth = w;
-}
-
-void SkSVGSVG::setHeight(const SkSVGLength& h) {
-    fHeight = h;
-}
-
 void SkSVGSVG::setViewBox(const SkSVGViewBoxType& vb) {
     fViewBox.set(vb);
 }
@@ -91,6 +126,11 @@
             this->setViewBox(*vb);
         }
         break;
+    case SkSVGAttribute::kPreserveAspectRatio:
+        if (const auto* par = v.as<SkSVGPreserveAspectRatioValue>()) {
+            this->setPreserveAspectRatio(*par);
+        }
+        break;
     default:
         this->INHERITED::onSetAttribute(attr, v);
     }