Bug 1383650 - Support geometry property for SVG image element r=longsonr
authorviolet <violet.bugreport@gmail.com>
Fri, 24 May 2019 12:40:12 +0000
changeset 475377 b0a0359fdadb1c7dcd39656c449f3a072f49d66d
parent 475376 a398387437aee799483ac38ed2e7eb72312841f7
child 475378 f712de0c8a7ca23a3a1bde2ecae29d900dee8b0c
push id36060
push usercbrindusan@mozilla.com
push dateFri, 24 May 2019 21:47:21 +0000
treeherdermozilla-central@ac95bdf3c0b3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslongsonr
bugs1383650
milestone69.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1383650 - Support geometry property for SVG image element r=longsonr The only different part is to resolve intrinsic image size. This patch implements explicit requirements of the spec, but an edge case is tricky. It's not clear per spec what the intrinsic image size is for an SVG without explicit width/height, something like: <svg> <image href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'><rect width='40' height='90' fill='red' /></svg>"/> </svg> Chrome treats the intrinsic size of the href svg as the default size of a replaced element (300x150), our image/VectorImage.cpp doesn't resolve size in this case. We can handle this particular case in some seperate bug if necessary, I think. Differential Revision: https://phabricator.services.mozilla.com/D32415
dom/svg/SVGGeometryProperty.cpp
dom/svg/SVGGeometryProperty.h
dom/svg/SVGImageElement.cpp
dom/svg/SVGImageElement.h
layout/reftests/svg/geometry-properties-in-css-ref.html
layout/reftests/svg/geometry-properties-in-css.html
layout/svg/nsSVGImageFrame.cpp
layout/svg/nsSVGImageFrame.h
testing/web-platform/meta/svg/geometry/svg-image-intrinsic-size-with-cssstyle-auto-dynamic-image-change.html.ini
testing/web-platform/meta/svg/geometry/svg-image-intrinsic-size-with-cssstyle-auto.html.ini
--- a/dom/svg/SVGGeometryProperty.cpp
+++ b/dom/svg/SVGGeometryProperty.cpp
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "SVGGeometryProperty.h"
 #include "SVGCircleElement.h"
 #include "SVGEllipseElement.h"
 #include "SVGForeignObjectElement.h"
+#include "SVGImageElement.h"
 #include "SVGRectElement.h"
 
 namespace mozilla {
 namespace dom {
 namespace SVGGeometryProperty {
 
 nsCSSUnit SpecifiedUnitTypeToCSSUnit(uint8_t aSpecifiedUnit) {
   switch (aSpecifiedUnit) {
@@ -58,30 +59,34 @@ nsCSSPropertyID AttrEnumToCSSPropId(cons
     return SVGRectElement::GetCSSPropertyIdForAttrEnum(aAttrEnum);
   }
   if (aElement->IsSVGElement(nsGkAtoms::circle)) {
     return SVGCircleElement::GetCSSPropertyIdForAttrEnum(aAttrEnum);
   }
   if (aElement->IsSVGElement(nsGkAtoms::ellipse)) {
     return SVGEllipseElement::GetCSSPropertyIdForAttrEnum(aAttrEnum);
   }
+  if (aElement->IsSVGElement(nsGkAtoms::image)) {
+    return SVGImageElement::GetCSSPropertyIdForAttrEnum(aAttrEnum);
+  }
   if (aElement->IsSVGElement(nsGkAtoms::foreignObject)) {
     return SVGForeignObjectElement::GetCSSPropertyIdForAttrEnum(aAttrEnum);
   }
   return eCSSProperty_UNKNOWN;
 }
 
 bool IsNonNegativeGeometryProperty(nsCSSPropertyID aProp) {
   return aProp == eCSSProperty_r || aProp == eCSSProperty_rx ||
          aProp == eCSSProperty_ry || aProp == eCSSProperty_width ||
          aProp == eCSSProperty_height;
 }
 
 bool ElementMapsLengthsToStyle(SVGElement const* aElement) {
   return aElement->IsSVGElement(nsGkAtoms::rect) ||
          aElement->IsSVGElement(nsGkAtoms::circle) ||
          aElement->IsSVGElement(nsGkAtoms::ellipse) ||
+         aElement->IsSVGElement(nsGkAtoms::image) ||
          aElement->IsSVGElement(nsGkAtoms::foreignObject);
 }
 
 }  // namespace SVGGeometryProperty
 }  // namespace dom
 }  // namespace mozilla
--- a/dom/svg/SVGGeometryProperty.h
+++ b/dom/svg/SVGGeometryProperty.h
@@ -3,19 +3,21 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_SVGGeometryProperty_SVGGeometryProperty_h
 #define mozilla_dom_SVGGeometryProperty_SVGGeometryProperty_h
 
 #include "mozilla/dom/SVGElement.h"
+#include "ComputedStyle.h"
 #include "SVGAnimatedLength.h"
-#include "ComputedStyle.h"
+#include "nsGkAtoms.h"
 #include "nsIFrame.h"
+#include "nsSVGImageFrame.h"
 #include <type_traits>
 
 namespace mozilla {
 namespace dom {
 
 namespace SVGGeometryProperty {
 namespace ResolverTypes {
 struct LengthPercentNoAuto {};
@@ -33,23 +35,35 @@ namespace Tags {
     constexpr static auto Getter = &styleStruct::m##tagName;          \
   }
 
 SVGGEOMETRYPROPERTY_GENERATETAG(X, LengthPercentNoAuto, X, nsStyleSVGReset);
 SVGGEOMETRYPROPERTY_GENERATETAG(Y, LengthPercentNoAuto, Y, nsStyleSVGReset);
 SVGGEOMETRYPROPERTY_GENERATETAG(Cx, LengthPercentNoAuto, X, nsStyleSVGReset);
 SVGGEOMETRYPROPERTY_GENERATETAG(Cy, LengthPercentNoAuto, Y, nsStyleSVGReset);
 SVGGEOMETRYPROPERTY_GENERATETAG(R, LengthPercentNoAuto, XY, nsStyleSVGReset);
-SVGGEOMETRYPROPERTY_GENERATETAG(Width, LengthPercentWidthHeight, X,
-                                nsStylePosition);
-SVGGEOMETRYPROPERTY_GENERATETAG(Height, LengthPercentWidthHeight, Y,
-                                nsStylePosition);
 
 #undef SVGGEOMETRYPROPERTY_GENERATETAG
 
+struct Height;
+struct Width {
+  using ResolverType = ResolverTypes::LengthPercentWidthHeight;
+  constexpr static auto CtxDirection = SVGContentUtils::X;
+  constexpr static auto Getter = &nsStylePosition::mWidth;
+  constexpr static auto SizeGetter = &gfx::Size::width;
+  using CounterPart = Height;
+};
+struct Height {
+  using ResolverType = ResolverTypes::LengthPercentWidthHeight;
+  constexpr static auto CtxDirection = SVGContentUtils::Y;
+  constexpr static auto Getter = &nsStylePosition::mHeight;
+  constexpr static auto SizeGetter = &gfx::Size::height;
+  using CounterPart = Width;
+};
+
 struct Ry;
 struct Rx {
   using ResolverType = ResolverTypes::LengthPercentRXY;
   constexpr static auto CtxDirection = SVGContentUtils::X;
   constexpr static auto Getter = &nsStyleSVGReset::mRx;
   using CounterPart = Ry;
 };
 struct Ry {
@@ -89,17 +103,56 @@ float ResolveImpl(ComputedStyle const& a
       "Wrong tag");
 
   auto const& value = aStyle.StylePosition()->*Tag::Getter;
   if (value.IsLengthPercentage()) {
     return ResolvePureLengthPercentage<Tag::CtxDirection>(
         aElement, value.AsLengthPercentage());
   }
 
-  // |auto| and |max-content| etc. are treated as 0.
+  if (aElement->IsSVGElement(nsGkAtoms::image)) {
+    // It's not clear per SVG2 spec what should be done for values other
+    // than |auto| (e.g. |max-content|). We treat them as nonsense, thus
+    // using the initial value behavior, i.e. |auto|.
+
+    auto* f = aElement->GetPrimaryFrame();
+    MOZ_ASSERT(f && f->IsSVGImageFrame());
+    auto* imgf = static_cast<nsSVGImageFrame const*>(f);
+
+    using Other = typename Tag::CounterPart;
+    auto const& valueOther = aStyle.StylePosition()->*Other::Getter;
+
+    gfx::Size intrinsicImageSize;
+    if (!imgf->GetIntrinsicImageSize(intrinsicImageSize)) {
+      // Cannot get intrinsic image size, just return 0.
+      return 0.f;
+    }
+
+    if (valueOther.IsLengthPercentage()) {
+      // We are |auto|, but the other side has specifed length. Then
+      // we need to preserve aspect ratio.
+
+      float intrinsicLengthOther = intrinsicImageSize.*Other::SizeGetter;
+      if (!intrinsicLengthOther) {
+        // Avoid dividing by 0.
+        return 0.f;
+      }
+
+      float intrinsicLength = intrinsicImageSize.*Tag::SizeGetter,
+            lengthOther = ResolvePureLengthPercentage<Other::CtxDirection>(
+                aElement, valueOther.AsLengthPercentage());
+
+      return intrinsicLength * lengthOther / intrinsicLengthOther;
+    }
+
+    // So |width| and |height| are both |auto|, just use intrinsic size.
+    return intrinsicImageSize.*Tag::SizeGetter;
+  }
+
+  // For other elements, |auto| and |max-content| etc. are treated as 0.
   return 0.f;
 }
 
 template <class Tag>
 float ResolveImpl(ComputedStyle const& aStyle, SVGElement* aElement,
                   ResolverTypes::LengthPercentRXY) {
   static_assert(std::is_same<Tag, Tags::Rx>{} || std::is_same<Tag, Tags::Ry>{},
                 "Wrong tag");
--- a/dom/svg/SVGImageElement.cpp
+++ b/dom/svg/SVGImageElement.cpp
@@ -12,16 +12,17 @@
 #include "mozilla/gfx/2D.h"
 #include "nsCOMPtr.h"
 #include "nsIURI.h"
 #include "nsNetUtil.h"
 #include "imgINotificationObserver.h"
 #include "mozilla/dom/SVGImageElementBinding.h"
 #include "mozilla/dom/SVGLengthBinding.h"
 #include "nsContentUtils.h"
+#include "SVGGeometryProperty.h"
 
 NS_IMPL_NS_NEW_SVG_ELEMENT(Image)
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace dom {
 
@@ -49,25 +50,43 @@ SVGElement::StringInfo SVGImageElement::
 // nsISupports methods
 
 NS_IMPL_ISUPPORTS_INHERITED(SVGImageElement, SVGImageElementBase,
                             imgINotificationObserver, nsIImageLoadingContent)
 
 //----------------------------------------------------------------------
 // Implementation
 
+namespace SVGT = SVGGeometryProperty::Tags;
+
 SVGImageElement::SVGImageElement(
     already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
     : SVGImageElementBase(std::move(aNodeInfo)) {
   // We start out broken
   AddStatesSilently(NS_EVENT_STATE_BROKEN);
 }
 
 SVGImageElement::~SVGImageElement() { DestroyImageLoadingContent(); }
 
+nsCSSPropertyID SVGImageElement::GetCSSPropertyIdForAttrEnum(
+    uint8_t aAttrEnum) {
+  switch (aAttrEnum) {
+    case ATTR_X:
+      return eCSSProperty_x;
+    case ATTR_Y:
+      return eCSSProperty_y;
+    case ATTR_WIDTH:
+      return eCSSProperty_width;
+    case ATTR_HEIGHT:
+      return eCSSProperty_height;
+    default:
+      MOZ_ASSERT_UNREACHABLE("Unknown attr enum");
+      return eCSSProperty_UNKNOWN;
+  }
+}
 //----------------------------------------------------------------------
 // nsINode methods
 
 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGImageElement)
 
 //----------------------------------------------------------------------
 
 already_AddRefed<DOMSVGAnimatedLength> SVGImageElement::X() {
@@ -227,33 +246,38 @@ SVGImageElement::IsAttributeMapped(const
 // SVGGeometryElement methods
 
 /* For the purposes of the update/invalidation logic pretend to
    be a rectangle. */
 bool SVGImageElement::GetGeometryBounds(
     Rect* aBounds, const StrokeOptions& aStrokeOptions,
     const Matrix& aToBoundsSpace, const Matrix* aToNonScalingStrokeSpace) {
   Rect rect;
-  GetAnimatedLengthValues(&rect.x, &rect.y, &rect.width, &rect.height, nullptr);
+
+  MOZ_ASSERT(GetPrimaryFrame());
+  SVGGeometryProperty::ResolveAll<SVGT::X, SVGT::Y, SVGT::Width, SVGT::Height>(
+      this, &rect.x, &rect.y, &rect.width, &rect.height);
 
   if (rect.IsEmpty()) {
     // Rendering of the element disabled
     rect.SetEmpty();  // Make sure width/height are zero and not negative
   }
 
   *aBounds = aToBoundsSpace.TransformBounds(rect);
   return true;
 }
 
 already_AddRefed<Path> SVGImageElement::BuildPath(PathBuilder* aBuilder) {
   // We get called in order to get bounds for this element, and for
   // hit-testing against it. For that we just pretend to be a rectangle.
 
   float x, y, width, height;
-  GetAnimatedLengthValues(&x, &y, &width, &height, nullptr);
+  MOZ_ASSERT(GetPrimaryFrame());
+  SVGGeometryProperty::ResolveAll<SVGT::X, SVGT::Y, SVGT::Width, SVGT::Height>(
+      this, &x, &y, &width, &height);
 
   if (width <= 0 || height <= 0) {
     return nullptr;
   }
 
   Rect r(x, y, width, height);
   aBuilder->MoveTo(r.TopLeft());
   aBuilder->LineTo(r.TopRight());
@@ -264,20 +288,23 @@ already_AddRefed<Path> SVGImageElement::
   return aBuilder->Finish();
 }
 
 //----------------------------------------------------------------------
 // SVGElement methods
 
 /* virtual */
 bool SVGImageElement::HasValidDimensions() const {
-  return mLengthAttributes[ATTR_WIDTH].IsExplicitlySet() &&
-         mLengthAttributes[ATTR_WIDTH].GetAnimValInSpecifiedUnits() > 0 &&
-         mLengthAttributes[ATTR_HEIGHT].IsExplicitlySet() &&
-         mLengthAttributes[ATTR_HEIGHT].GetAnimValInSpecifiedUnits() > 0;
+  float width, height;
+
+  MOZ_ASSERT(GetPrimaryFrame());
+  SVGGeometryProperty::ResolveAll<SVGT::Width, SVGT::Height>(this, &width,
+                                                             &height);
+
+  return width > 0 && height > 0;
 }
 
 SVGElement::LengthAttributesInfo SVGImageElement::GetLengthInfo() {
   return LengthAttributesInfo(mLengthAttributes, sLengthInfo,
                               ArrayLength(sLengthInfo));
 }
 
 SVGAnimatedPreserveAspectRatio*
--- a/dom/svg/SVGImageElement.h
+++ b/dom/svg/SVGImageElement.h
@@ -90,16 +90,18 @@ class SVGImageElement : public SVGImageE
 
   void SetDecoding(const nsAString& aDecoding, ErrorResult& aError) {
     SetAttr(nsGkAtoms::decoding, aDecoding, aError);
   }
   void GetDecoding(nsAString& aValue);
 
   already_AddRefed<Promise> Decode(ErrorResult& aRv);
 
+  static nsCSSPropertyID GetCSSPropertyIdForAttrEnum(uint8_t aAttrEnum);
+
  protected:
   nsresult LoadSVGImage(bool aForce, bool aNotify);
 
   virtual LengthAttributesInfo GetLengthInfo() override;
   virtual SVGAnimatedPreserveAspectRatio* GetAnimatedPreserveAspectRatio()
       override;
   virtual StringAttributesInfo GetStringInfo() override;
 
--- a/layout/reftests/svg/geometry-properties-in-css-ref.html
+++ b/layout/reftests/svg/geometry-properties-in-css-ref.html
@@ -12,9 +12,10 @@
     <ellipse cx="30" cy="100" rx="20" ry="40" fill="cyan" />
     <ellipse cx="80" cy="50" rx="20" ry="40" fill="navy" />
   </svg>
   <foreignObject x="450" y="200" width="80" height="130">
     <svg>
       <rect width="50" height="50" rx="4" ry="4" fill="brown" />
     </svg>
   </foreignObject>
+  <rect x="300" y="260" width="50" height="50" fill="red" />
 </svg>
--- a/layout/reftests/svg/geometry-properties-in-css.html
+++ b/layout/reftests/svg/geometry-properties-in-css.html
@@ -48,16 +48,21 @@
     y: 200px;
     width: 80px;
     height: 130px;
   }
   #r2 {
     width: 50px;
     height:50px;
   }
+  svg image {
+    x: 300px;
+    y: 260px;
+    height: 50px;
+  }
 </style>
 <svg>
   <g>
     <rect x="0" y="-10" width="30px" height="10px" rx="-5px" ry="auto" fill="purple" />
     <rect x=" 40px /* some nonsense */ " y="150" width="30" height="20em" rx="20px" ry="20px" fill="magenta" />
   </g>
   <circle cx="/* more nonsense */ 170" cy="340" r="-5px" fill="pink" />
   <g transform="translate(150,0)">
@@ -67,9 +72,10 @@
     <ellipse fill="cyan" />
     <ellipse fill="navy" />
   </svg>
   <foreignObject>
     <svg>
       <rect id="r2" style="x:0;y:0" fill="brown" />
     </svg>
   </foreignObject>
+  <image href="data:image/svg+xml,<svg width='10' height='10' xmlns='http://www.w3.org/2000/svg'><rect width='100%' height='100%' fill='red' /></svg>" />
 </svg>
--- a/layout/svg/nsSVGImageFrame.cpp
+++ b/layout/svg/nsSVGImageFrame.cpp
@@ -10,31 +10,33 @@
 #include "gfxContext.h"
 #include "gfxPlatform.h"
 #include "mozilla/gfx/2D.h"
 #include "imgIContainer.h"
 #include "nsContainerFrame.h"
 #include "nsIImageLoadingContent.h"
 #include "nsLayoutUtils.h"
 #include "imgINotificationObserver.h"
+#include "SVGGeometryProperty.h"
 #include "SVGObserverUtils.h"
 #include "nsSVGUtils.h"
 #include "SVGContentUtils.h"
 #include "SVGGeometryFrame.h"
 #include "SVGImageContext.h"
 #include "mozilla/PresShell.h"
 #include "mozilla/dom/MutationEventBinding.h"
 #include "mozilla/dom/SVGImageElement.h"
 #include "nsIReflowCallback.h"
 #include "mozilla/Unused.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::gfx;
 using namespace mozilla::image;
+namespace SVGT = SVGGeometryProperty::Tags;
 
 // ---------------------------------------------------------------------
 // nsQueryFrame methods
 NS_QUERYFRAME_HEAD(nsSVGImageFrame)
   NS_QUERYFRAME_ENTRY(nsSVGImageFrame)
 NS_QUERYFRAME_TAIL_INHERITING(SVGGeometryFrame)
 
 nsIFrame* NS_NewSVGImageFrame(PresShell* aPresShell, ComputedStyle* aStyle) {
@@ -172,37 +174,59 @@ void nsSVGImageFrame::OnVisibilityChange
 
   SVGGeometryFrame::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
 }
 
 gfx::Matrix nsSVGImageFrame::GetRasterImageTransform(int32_t aNativeWidth,
                                                      int32_t aNativeHeight) {
   float x, y, width, height;
   SVGImageElement* element = static_cast<SVGImageElement*>(GetContent());
-  element->GetAnimatedLengthValues(&x, &y, &width, &height, nullptr);
+  SVGGeometryProperty::ResolveAll<SVGT::X, SVGT::Y, SVGT::Width, SVGT::Height>(
+      element, &x, &y, &width, &height);
 
   Matrix viewBoxTM = SVGContentUtils::GetViewBoxTransform(
       width, height, 0, 0, aNativeWidth, aNativeHeight,
       element->mPreserveAspectRatio);
 
   return viewBoxTM * gfx::Matrix::Translation(x, y);
 }
 
 gfx::Matrix nsSVGImageFrame::GetVectorImageTransform() {
   float x, y, width, height;
   SVGImageElement* element = static_cast<SVGImageElement*>(GetContent());
-  element->GetAnimatedLengthValues(&x, &y, &width, &height, nullptr);
+  SVGGeometryProperty::ResolveAll<SVGT::X, SVGT::Y, SVGT::Width, SVGT::Height>(
+      element, &x, &y, &width, &height);
 
   // No viewBoxTM needed here -- our height/width overrides any concept of
   // "native size" that the SVG image has, and it will handle viewBox and
   // preserveAspectRatio on its own once we give it a region to draw into.
 
   return gfx::Matrix::Translation(x, y);
 }
 
+bool nsSVGImageFrame::GetIntrinsicImageSize(
+    mozilla::gfx::Size& aIntrinsicSize) const {
+  if (!mImageContainer) {
+    return false;
+  }
+
+  int32_t width, height;
+  if (NS_FAILED(mImageContainer->GetWidth(&width))) {
+    return false;
+  }
+
+  if (NS_FAILED(mImageContainer->GetHeight(&height))) {
+    return false;
+  }
+
+  aIntrinsicSize = {float(width), float(height)};
+
+  return true;
+}
+
 bool nsSVGImageFrame::TransformContextForPainting(gfxContext* aGfxContext,
                                                   const gfxMatrix& aTransform) {
   gfx::Matrix imageTransform;
   if (mImageContainer->GetType() == imgIContainer::TYPE_VECTOR) {
     imageTransform = GetVectorImageTransform() * ToMatrix(aTransform);
   } else {
     int32_t nativeWidth, nativeHeight;
     if (NS_FAILED(mImageContainer->GetWidth(&nativeWidth)) ||
@@ -236,17 +260,18 @@ void nsSVGImageFrame::PaintSVG(gfxContex
                                imgDrawingParams& aImgParams,
                                const nsIntRect* aDirtyRect) {
   if (!StyleVisibility()->IsVisible()) {
     return;
   }
 
   float x, y, width, height;
   SVGImageElement* imgElem = static_cast<SVGImageElement*>(GetContent());
-  imgElem->GetAnimatedLengthValues(&x, &y, &width, &height, nullptr);
+  SVGGeometryProperty::ResolveAll<SVGT::X, SVGT::Y, SVGT::Width, SVGT::Height>(
+      imgElem, &x, &y, &width, &height);
   NS_ASSERTION(width > 0 && height > 0,
                "Should only be painting things with valid width/height");
 
   if (!mImageContainer) {
     nsCOMPtr<imgIRequest> currentRequest;
     nsCOMPtr<nsIImageLoadingContent> imageLoader =
         do_QueryInterface(GetContent());
     if (imageLoader)
@@ -342,18 +367,18 @@ void nsSVGImageFrame::PaintSVG(gfxContex
 
 nsIFrame* nsSVGImageFrame::GetFrameForPoint(const gfxPoint& aPoint) {
   if (!(GetStateBits() & NS_STATE_SVG_CLIPPATH_CHILD) && !GetHitTestFlags()) {
     return nullptr;
   }
 
   Rect rect;
   SVGImageElement* element = static_cast<SVGImageElement*>(GetContent());
-  element->GetAnimatedLengthValues(&rect.x, &rect.y, &rect.width, &rect.height,
-                                   nullptr);
+  SVGGeometryProperty::ResolveAll<SVGT::X, SVGT::Y, SVGT::Width, SVGT::Height>(
+      element, &rect.x, &rect.y, &rect.width, &rect.height);
 
   if (!rect.Contains(ToPoint(aPoint))) {
     return nullptr;
   }
 
   // Special case for raster images -- we only want to accept points that fall
   // in the underlying image's (scaled to fit) native bounds.  That region
   // doesn't necessarily map to our <image> element's [x,y,width,height] if the
@@ -397,17 +422,18 @@ void nsSVGImageFrame::ReflowSVG() {
              "ReflowSVG mechanism not designed for this");
 
   if (!nsSVGUtils::NeedsReflowSVG(this)) {
     return;
   }
 
   float x, y, width, height;
   SVGImageElement* element = static_cast<SVGImageElement*>(GetContent());
-  element->GetAnimatedLengthValues(&x, &y, &width, &height, nullptr);
+  SVGGeometryProperty::ResolveAll<SVGT::X, SVGT::Y, SVGT::Width, SVGT::Height>(
+      element, &x, &y, &width, &height);
 
   Rect extent(x, y, width, height);
 
   if (!extent.IsEmpty()) {
     mRect = nsLayoutUtils::RoundGfxRectToAppRect(extent, AppUnitsPerCSSPixel());
   } else {
     mRect.SetEmpty();
   }
--- a/layout/svg/nsSVGImageFrame.h
+++ b/layout/svg/nsSVGImageFrame.h
@@ -83,16 +83,18 @@ class nsSVGImageFrame final : public moz
       Visibility aNewVisibility,
       const Maybe<OnNonvisible>& aNonvisibleAction = Nothing()) override;
 
   virtual void Init(nsIContent* aContent, nsContainerFrame* aParent,
                     nsIFrame* aPrevInFlow) override;
   virtual void DestroyFrom(nsIFrame* aDestructRoot,
                            PostDestroyData& aPostDestroyData) override;
 
+  bool GetIntrinsicImageSize(mozilla::gfx::Size& aIntrinsicSize) const;
+
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override {
     return MakeFrameName(NS_LITERAL_STRING("SVGImage"), aResult);
   }
 #endif
 
   // nsIReflowCallback
   virtual bool ReflowFinished() override;
deleted file mode 100644
--- a/testing/web-platform/meta/svg/geometry/svg-image-intrinsic-size-with-cssstyle-auto-dynamic-image-change.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[svg-image-intrinsic-size-with-cssstyle-auto-dynamic-image-change.html]
-  [Test <svg:image>'s sizing with css size as auto, with dynamic image change]
-    expected: FAIL
-
--- a/testing/web-platform/meta/svg/geometry/svg-image-intrinsic-size-with-cssstyle-auto.html.ini
+++ b/testing/web-platform/meta/svg/geometry/svg-image-intrinsic-size-with-cssstyle-auto.html.ini
@@ -1,73 +1,40 @@
 [svg-image-intrinsic-size-with-cssstyle-auto.html]
-  [<svg:image> 'auto' sizing with 200x100 svg image viewBox='0 0 400 100', attributes width='60' height='60' and CSS 'height:auto']
-    expected: FAIL
-
   [<svg:image> 'auto' sizing with default sized svg image viewBox='0 0 400 100', attributes width='60' height='60' and CSS 'width:auto']
     expected: FAIL
 
   [<svg:image> 'auto' sizing with default sized svg image, attributes width='200' and CSS 'width:auto; height:auto']
     expected: FAIL
 
-  [<svg:image> 'auto' sizing with 200x100 svg image, attributes width='50' height='50' and CSS 'width:auto; height:auto']
-    expected: FAIL
-
-  [<svg:image> 'auto' sizing with 256x256 png image, attributes width='64' height='128' and CSS 'height:auto']
-    expected: FAIL
-
   [<svg:image> 'auto' sizing with default sized svg image, without attributes width and height, no css width/height specified]
     expected: FAIL
 
-  [<svg:image> 'auto' sizing with 200x100 svg image, without attributes width and height and CSS 'width:auto']
-    expected: FAIL
-
   [<svg:image> 'auto' sizing with svg image height='100' viewBox='0 0 400 100', attributes width='60' height='60' and CSS 'height:auto']
     expected: FAIL
 
   [<svg:image> 'auto' sizing with svg image width='200' viewBox='0 0 400 100', attributes width='60' height='60' and CSS 'width:auto; height:auto']
     expected: FAIL
 
   [<svg:image> 'auto' sizing with svg image height='100' viewBox='0 0 400 100', attributes width='60' height='60' and CSS 'width:auto; height:auto']
     expected: FAIL
 
-  [<svg:image> 'auto' sizing with 256x256 png image, attributes width='64' height='64' and CSS 'width:auto; height:auto']
-    expected: FAIL
-
-  [<svg:image> 'auto' sizing with 200x100 svg image viewBox='0 0 400 100', attributes width='60' height='60' and CSS 'width:auto; height:auto']
-    expected: FAIL
-
   [<svg:image> 'auto' sizing with default sized svg image, attributes height='200' and CSS 'width:auto; height:auto']
     expected: FAIL
 
   [<svg:image> 'auto' sizing with svg image width='200' viewBox='0 0 400 100', attributes width='60' height='60' and CSS 'width:auto']
     expected: FAIL
 
   [<svg:image> 'auto' sizing with svg image width='200' viewBox='0 0 400 100', attributes width='60' height='60' and CSS 'height:auto']
     expected: FAIL
 
-  [<svg:image> 'auto' sizing with 200x100 svg image, attributes width='50' height='50' and CSS 'width:auto']
-    expected: FAIL
-
   [<svg:image> 'auto' sizing with svg image height='100' viewBox='0 0 400 100', attributes width='60' height='60' and CSS 'width:auto']
     expected: FAIL
 
   [<svg:image> 'auto' sizing with default sized svg image, attributes width='200' height='200' and CSS 'width:auto; height:auto']
     expected: FAIL
 
-  [<svg:image> 'auto' sizing with 200x100 svg image viewBox='0 0 400 100', attributes width='60' height='60' and CSS 'width:auto']
-    expected: FAIL
-
   [<svg:image> 'auto' sizing with default sized svg image viewBox='0 0 400 100', attributes width='60' height='60' and CSS 'height:auto']
     expected: FAIL
 
-  [<svg:image> 'auto' sizing with 200x100 svg image, attributes width='50' and CSS height:auto]
-    expected: FAIL
-
-  [<svg:image> 'auto' sizing with 256x256 png image, attributes width='128' height='64' and CSS 'width:auto']
-    expected: FAIL
-
-  [<svg:image> 'auto' sizing with 200x100 svg image, attributes height='50' and 'width:auto']
-    expected: FAIL
-
   [<svg:image> 'auto' sizing with default sized svg image viewBox='0 0 400 100', attributes width='60' height='60' and CSS 'width:auto; height:auto']
     expected: FAIL