Bug 1366097 - Part 5. Add an SVGImageContext parameter to imgIContainer::GetImageContainerAtSize. r=tnikkel
authorAndrew Osmond <aosmond@mozilla.com>
Fri, 17 Nov 2017 14:08:52 -0500
changeset 392504 54d6ad659f11103861cf2d53259d77764dfd675e
parent 392503 79b16521982847de443b83ec0f6cf9a4ce653bad
child 392505 e65c223336d99d8e7fae360b2fd3c1b10a91d531
push id32921
push usernerli@mozilla.com
push dateFri, 17 Nov 2017 22:02:18 +0000
treeherdermozilla-central@daa0dcd1616c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstnikkel
bugs1366097
milestone59.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 1366097 - Part 5. Add an SVGImageContext parameter to imgIContainer::GetImageContainerAtSize. r=tnikkel
image/ClippedImage.cpp
image/ClippedImage.h
image/DynamicImage.cpp
image/FrozenImage.cpp
image/FrozenImage.h
image/Image.cpp
image/Image.h
image/ImageWrapper.cpp
image/OrientedImage.cpp
image/OrientedImage.h
image/RasterImage.cpp
image/RasterImage.h
image/VectorImage.cpp
image/VectorImage.h
image/imgIContainer.idl
image/test/gtest/TestContainers.cpp
--- a/image/ClippedImage.cpp
+++ b/image/ClippedImage.cpp
@@ -365,26 +365,28 @@ ClippedImage::IsImageContainerAvailableA
     return InnerImage()->IsImageContainerAvailableAtSize(aManager, aSize, aFlags);
   }
   return false;
 }
 
 NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
 ClippedImage::GetImageContainerAtSize(LayerManager* aManager,
                                       const IntSize& aSize,
+                                      const Maybe<SVGImageContext>& aSVGContext,
                                       uint32_t aFlags)
 {
   // XXX(seth): We currently don't have a way of clipping the result of
   // GetImageContainer. We work around this by always returning null, but if it
   // ever turns out that ClippedImage is widely used on codepaths that can
   // actually benefit from GetImageContainer, it would be a good idea to fix
   // that method for performance reasons.
 
   if (!ShouldClip()) {
-    return InnerImage()->GetImageContainerAtSize(aManager, aSize, aFlags);
+    return InnerImage()->GetImageContainerAtSize(aManager, aSize,
+                                                 aSVGContext, aFlags);
   }
 
   return nullptr;
 }
 
 static bool
 MustCreateSurface(gfxContext* aContext,
                   const nsIntSize& aSize,
--- a/image/ClippedImage.h
+++ b/image/ClippedImage.h
@@ -49,16 +49,17 @@ public:
                       uint32_t aFlags) override;
   NS_IMETHOD_(bool)
     IsImageContainerAvailableAtSize(layers::LayerManager* aManager,
                                     const gfx::IntSize& aSize,
                                     uint32_t aFlags) override;
   NS_IMETHOD_(already_AddRefed<layers::ImageContainer>)
     GetImageContainerAtSize(layers::LayerManager* aManager,
                             const gfx::IntSize& aSize,
+                            const Maybe<SVGImageContext>& aSVGContext,
                             uint32_t aFlags) override;
   NS_IMETHOD_(DrawResult) Draw(gfxContext* aContext,
                                const nsIntSize& aSize,
                                const ImageRegion& aRegion,
                                uint32_t aWhichFrame,
                                gfx::SamplingFilter aSamplingFilter,
                                const Maybe<SVGImageContext>& aSVGContext,
                                uint32_t aFlags,
--- a/image/DynamicImage.cpp
+++ b/image/DynamicImage.cpp
@@ -232,16 +232,17 @@ DynamicImage::IsImageContainerAvailableA
                                               uint32_t aFlags)
 {
   return false;
 }
 
 NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
 DynamicImage::GetImageContainerAtSize(LayerManager* aManager,
                                       const IntSize& aSize,
+                                      const Maybe<SVGImageContext>& aSVGContext,
                                       uint32_t aFlags)
 {
   return nullptr;
 }
 
 NS_IMETHODIMP_(DrawResult)
 DynamicImage::Draw(gfxContext* aContext,
                    const nsIntSize& aSize,
--- a/image/FrozenImage.cpp
+++ b/image/FrozenImage.cpp
@@ -77,16 +77,17 @@ FrozenImage::IsImageContainerAvailableAt
                                              uint32_t aFlags)
 {
   return false;
 }
 
 NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
 FrozenImage::GetImageContainerAtSize(layers::LayerManager* aManager,
                                      const IntSize& aSize,
+                                     const Maybe<SVGImageContext>& aSVGContext,
                                      uint32_t aFlags)
 {
   // XXX(seth): GetImageContainer does not currently support anything but the
   // current frame. We work around this by always returning null, but if it ever
   // turns out that FrozenImage is widely used on codepaths that can actually
   // benefit from GetImageContainer, it would be a good idea to fix that method
   // for performance reasons.
   return nullptr;
--- a/image/FrozenImage.h
+++ b/image/FrozenImage.h
@@ -48,16 +48,17 @@ public:
                       uint32_t aFlags) override;
   NS_IMETHOD_(bool)
     IsImageContainerAvailableAtSize(layers::LayerManager* aManager,
                                     const gfx::IntSize& aSize,
                                     uint32_t aFlags) override;
   NS_IMETHOD_(already_AddRefed<layers::ImageContainer>)
     GetImageContainerAtSize(layers::LayerManager* aManager,
                             const gfx::IntSize& aSize,
+                            const Maybe<SVGImageContext>& aSVGContext,
                             uint32_t aFlags) override;
   NS_IMETHOD_(DrawResult) Draw(gfxContext* aContext,
                                const nsIntSize& aSize,
                                const ImageRegion& aRegion,
                                uint32_t aWhichFrame,
                                gfx::SamplingFilter aSamplingFilter,
                                const Maybe<SVGImageContext>& aSVGContext,
                                uint32_t aFlags,
--- a/image/Image.cpp
+++ b/image/Image.cpp
@@ -86,16 +86,17 @@ ImageResource::SetCurrentImage(ImageCont
   } else {
     aContainer->SetCurrentImages(imageList);
   }
 }
 
 already_AddRefed<ImageContainer>
 ImageResource::GetImageContainerImpl(LayerManager* aManager,
                                      const IntSize& aSize,
+                                     const Maybe<SVGImageContext>& aSVGContext,
                                      uint32_t aFlags)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aManager);
   MOZ_ASSERT((aFlags & ~(FLAG_SYNC_DECODE |
                          FLAG_SYNC_DECODE_IF_FAST |
                          FLAG_ASYNC_NOTIFY |
                          FLAG_HIGH_QUALITY_SCALING))
@@ -114,17 +115,18 @@ ImageResource::GetImageContainerImpl(Lay
   uint32_t flags = (aFlags & ~(FLAG_SYNC_DECODE |
                                FLAG_SYNC_DECODE_IF_FAST)) | FLAG_ASYNC_NOTIFY;
   RefPtr<layers::ImageContainer> container;
   ImageContainerEntry* entry = nullptr;
   int i = mImageContainers.Length() - 1;
   for (; i >= 0; --i) {
     entry = &mImageContainers[i];
     container = entry->mContainer.get();
-    if (size == entry->mSize && flags == entry->mFlags) {
+    if (size == entry->mSize && flags == entry->mFlags &&
+        aSVGContext == entry->mSVGContext) {
       // Lack of a container is handled below.
       break;
     } else if (!container) {
       // Stop tracking if our weak pointer to the image container was freed.
       mImageContainers.RemoveElementAt(i);
     } else {
       // It isn't a match, but still valid. Forget the container so we don't
       // try to reuse it below.
@@ -154,17 +156,18 @@ ImageResource::GetImageContainerImpl(Lay
 #ifdef DEBUG
   NotifyDrawingObservers();
 #endif
 
   DrawResult drawResult;
   IntSize bestSize;
   RefPtr<SourceSurface> surface;
   Tie(drawResult, bestSize, surface) =
-    GetFrameInternal(size, FRAME_CURRENT, aFlags | FLAG_ASYNC_NOTIFY);
+    GetFrameInternal(size, aSVGContext, FRAME_CURRENT,
+                     aFlags | FLAG_ASYNC_NOTIFY);
 
   // The requested size might be refused by the surface cache (i.e. due to
   // factor-of-2 mode). In that case we don't want to create an entry for this
   // specific size, but rather re-use the entry for the substituted size.
   if (bestSize != size) {
     MOZ_ASSERT(!bestSize.IsEmpty());
 
     // We can only remove the entry if we no longer have a container, because if
@@ -180,17 +183,18 @@ ImageResource::GetImageContainerImpl(Lay
     container = nullptr;
 
     // We need to do the entry search again for the new size. We skip pruning
     // because we did this above once already, but ImageContainer is threadsafe,
     // so there is a remote possibility it got freed.
     i = mImageContainers.Length() - 1;
     for (; i >= 0; --i) {
       entry = &mImageContainers[i];
-      if (bestSize == entry->mSize && flags == entry->mFlags) {
+      if (bestSize == entry->mSize && flags == entry->mFlags &&
+          aSVGContext == entry->mSVGContext) {
         container = entry->mContainer.get();
         if (container) {
           switch (entry->mLastDrawResult) {
             case DrawResult::SUCCESS:
             case DrawResult::BAD_IMAGE:
             case DrawResult::BAD_ARGS:
               return container.forget();
             case DrawResult::NOT_READY:
@@ -214,17 +218,17 @@ ImageResource::GetImageContainerImpl(Lay
   if (!container) {
     // We need a new ImageContainer, so create one.
     container = LayerManager::CreateImageContainer();
 
     if (i >= 0) {
       entry->mContainer = container;
     } else {
       entry = mImageContainers.AppendElement(
-        ImageContainerEntry(bestSize, container.get(), flags));
+        ImageContainerEntry(bestSize, aSVGContext, container.get(), flags));
     }
   }
 
   SetCurrentImage(container, surface, true);
   entry->mLastDrawResult = drawResult;
   return container.forget();
 }
 
@@ -235,17 +239,18 @@ ImageResource::UpdateImageContainer()
 
   for (int i = mImageContainers.Length() - 1; i >= 0; --i) {
     ImageContainerEntry& entry = mImageContainers[i];
     RefPtr<ImageContainer> container = entry.mContainer.get();
     if (container) {
       IntSize bestSize;
       RefPtr<SourceSurface> surface;
       Tie(entry.mLastDrawResult, bestSize, surface) =
-        GetFrameInternal(entry.mSize, FRAME_CURRENT, entry.mFlags);
+        GetFrameInternal(entry.mSize, entry.mSVGContext,
+                         FRAME_CURRENT, entry.mFlags);
 
       // It is possible that this is a factor-of-2 substitution. Since we
       // managed to convert the weak reference into a strong reference, that
       // means that an imagelib user still is holding onto the container. thus
       // we cannot consolidate and must keep updating the duplicate container.
       SetCurrentImage(container, surface, false);
     } else {
       // Stop tracking if our weak pointer to the image container was freed.
--- a/image/Image.h
+++ b/image/Image.h
@@ -334,16 +334,17 @@ protected:
   uint32_t                      mAnimationConsumers;
   uint16_t                      mAnimationMode; // Enum values in imgIContainer
   bool                          mInitialized:1; // Have we been initalized?
   bool                          mAnimating:1;   // Are we currently animating?
   bool                          mError:1;       // Error handling
 
   virtual Tuple<DrawResult, gfx::IntSize, RefPtr<gfx::SourceSurface>>
     GetFrameInternal(const gfx::IntSize& aSize,
+                     const Maybe<SVGImageContext>& aSVGContext,
                      uint32_t aWhichFrame,
                      uint32_t aFlags)
   {
     return MakeTuple(DrawResult::BAD_IMAGE, aSize,
                      RefPtr<gfx::SourceSurface>());
   }
 
   /**
@@ -357,38 +358,42 @@ protected:
                                              uint32_t aFlags)
   {
     return gfx::IntSize(0, 0);
   }
 
   already_AddRefed<layers::ImageContainer>
     GetImageContainerImpl(layers::LayerManager* aManager,
                           const gfx::IntSize& aSize,
+                          const Maybe<SVGImageContext>& aSVGContext,
                           uint32_t aFlags);
 
   void UpdateImageContainer();
 
   void ReleaseImageContainer();
 
 private:
   void SetCurrentImage(layers::ImageContainer* aContainer,
                        gfx::SourceSurface* aSurface,
                        bool aInTransaction);
 
   struct ImageContainerEntry {
     ImageContainerEntry(const gfx::IntSize& aSize,
+                        const Maybe<SVGImageContext>& aSVGContext,
                         layers::ImageContainer* aContainer,
                         uint32_t aFlags)
       : mSize(aSize)
+      , mSVGContext(aSVGContext)
       , mContainer(aContainer)
       , mLastDrawResult(DrawResult::NOT_READY)
       , mFlags(aFlags)
     { }
 
     gfx::IntSize                        mSize;
+    Maybe<SVGImageContext>              mSVGContext;
     // A weak pointer to our ImageContainer, which stays alive only as long as
     // the layer system needs it.
     WeakPtr<layers::ImageContainer>     mContainer;
     // If mContainer is non-null, this contains the DrawResult we obtained
     // the last time we updated it.
     DrawResult                          mLastDrawResult;
     // Cached flags to use for decoding. FLAG_ASYNC_NOTIFY should always be set
     // but FLAG_HIGH_QUALITY_SCALING may vary.
--- a/image/ImageWrapper.cpp
+++ b/image/ImageWrapper.cpp
@@ -220,19 +220,21 @@ ImageWrapper::IsImageContainerAvailableA
                                               uint32_t aFlags)
 {
   return mInnerImage->IsImageContainerAvailableAtSize(aManager, aSize, aFlags);
 }
 
 NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
 ImageWrapper::GetImageContainerAtSize(LayerManager* aManager,
                                       const IntSize& aSize,
+                                      const Maybe<SVGImageContext>& aSVGContext,
                                       uint32_t aFlags)
 {
-  return mInnerImage->GetImageContainerAtSize(aManager, aSize, aFlags);
+  return mInnerImage->GetImageContainerAtSize(aManager, aSize,
+                                              aSVGContext, aFlags);
 }
 
 NS_IMETHODIMP_(DrawResult)
 ImageWrapper::Draw(gfxContext* aContext,
                    const nsIntSize& aSize,
                    const ImageRegion& aRegion,
                    uint32_t aWhichFrame,
                    SamplingFilter aSamplingFilter,
--- a/image/OrientedImage.cpp
+++ b/image/OrientedImage.cpp
@@ -182,26 +182,28 @@ OrientedImage::IsImageContainerAvailable
     return InnerImage()->IsImageContainerAvailableAtSize(aManager, aSize, aFlags);
   }
   return false;
 }
 
 NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
 OrientedImage::GetImageContainerAtSize(LayerManager* aManager,
                                        const IntSize& aSize,
+                                       const Maybe<SVGImageContext>& aSVGContext,
                                        uint32_t aFlags)
 {
   // XXX(seth): We currently don't have a way of orienting the result of
   // GetImageContainer. We work around this by always returning null, but if it
   // ever turns out that OrientedImage is widely used on codepaths that can
   // actually benefit from GetImageContainer, it would be a good idea to fix
   // that method for performance reasons.
 
   if (mOrientation.IsIdentity()) {
-    return InnerImage()->GetImageContainerAtSize(aManager, aSize, aFlags);
+    return InnerImage()->GetImageContainerAtSize(aManager, aSize,
+                                                 aSVGContext, aFlags);
   }
 
   return nullptr;
 }
 
 struct MatrixBuilder
 {
   explicit MatrixBuilder(bool aInvert) : mInvert(aInvert) { }
--- a/image/OrientedImage.h
+++ b/image/OrientedImage.h
@@ -46,16 +46,17 @@ public:
                       uint32_t aFlags) override;
   NS_IMETHOD_(bool)
     IsImageContainerAvailableAtSize(layers::LayerManager* aManager,
                                     const gfx::IntSize& aSize,
                                     uint32_t aFlags) override;
   NS_IMETHOD_(already_AddRefed<layers::ImageContainer>)
     GetImageContainerAtSize(layers::LayerManager* aManager,
                             const gfx::IntSize& aSize,
+                            const Maybe<SVGImageContext>& aSVGContext,
                             uint32_t aFlags) override;
   NS_IMETHOD_(DrawResult) Draw(gfxContext* aContext,
                                const nsIntSize& aSize,
                                const ImageRegion& aRegion,
                                uint32_t aWhichFrame,
                                gfx::SamplingFilter aSamplingFilter,
                                const Maybe<SVGImageContext>& aSVGContext,
                                uint32_t aFlags,
--- a/image/RasterImage.cpp
+++ b/image/RasterImage.cpp
@@ -571,27 +571,28 @@ NS_IMETHODIMP_(already_AddRefed<SourceSu
 RasterImage::GetFrameAtSize(const IntSize& aSize,
                             uint32_t aWhichFrame,
                             uint32_t aFlags)
 {
 #ifdef DEBUG
   NotifyDrawingObservers();
 #endif
 
-  auto result = GetFrameInternal(aSize, aWhichFrame, aFlags);
+  auto result = GetFrameInternal(aSize, Nothing(), aWhichFrame, aFlags);
   RefPtr<SourceSurface> surf = mozilla::Get<2>(result).forget();
 
   // If we are here, it suggests the image is embedded in a canvas or some
   // other path besides layers, and we won't need the file handle.
   MarkSurfaceShared(surf);
   return surf.forget();
 }
 
 Tuple<DrawResult, IntSize, RefPtr<SourceSurface>>
 RasterImage::GetFrameInternal(const IntSize& aSize,
+                              const Maybe<SVGImageContext>& aSVGContext,
                               uint32_t aWhichFrame,
                               uint32_t aFlags)
 {
   MOZ_ASSERT(aWhichFrame <= FRAME_MAX_VALUE);
 
   if (aSize.IsEmpty() || aWhichFrame > FRAME_MAX_VALUE) {
     return MakeTuple(DrawResult::BAD_ARGS, aSize,
                      RefPtr<SourceSurface>());
@@ -650,17 +651,17 @@ NS_IMETHODIMP_(bool)
 RasterImage::IsImageContainerAvailable(LayerManager* aManager, uint32_t aFlags)
 {
   return IsImageContainerAvailableAtSize(aManager, mSize, aFlags);
 }
 
 NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
 RasterImage::GetImageContainer(LayerManager* aManager, uint32_t aFlags)
 {
-  return GetImageContainerImpl(aManager, mSize, aFlags);
+  return GetImageContainerImpl(aManager, mSize, Nothing(), aFlags);
 }
 
 NS_IMETHODIMP_(bool)
 RasterImage::IsImageContainerAvailableAtSize(LayerManager* aManager,
                                              const IntSize& aSize,
                                              uint32_t aFlags)
 {
   // We check the minimum size because while we support downscaling, we do not
@@ -675,19 +676,20 @@ RasterImage::IsImageContainerAvailableAt
   }
 
   return true;
 }
 
 NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
 RasterImage::GetImageContainerAtSize(LayerManager* aManager,
                                      const IntSize& aSize,
+                                     const Maybe<SVGImageContext>& aSVGContext,
                                      uint32_t aFlags)
 {
-  return GetImageContainerImpl(aManager, aSize, aFlags);
+  return GetImageContainerImpl(aManager, aSize, aSVGContext, aFlags);
 }
 
 size_t
 RasterImage::SizeOfSourceWithComputedFallback(SizeOfState& aState) const
 {
   return mSourceBuffer->SizeOfIncludingThisWithComputedFallback(
     aState.mMallocSizeOf);
 }
--- a/image/RasterImage.h
+++ b/image/RasterImage.h
@@ -304,16 +304,17 @@ private:
                           const nsIntSize& aSize,
                           const ImageRegion& aRegion,
                           gfx::SamplingFilter aSamplingFilter,
                           uint32_t aFlags,
                           float aOpacity);
 
   Tuple<DrawResult, gfx::IntSize, RefPtr<gfx::SourceSurface>>
     GetFrameInternal(const gfx::IntSize& aSize,
+                     const Maybe<SVGImageContext>& aSVGContext,
                      uint32_t aWhichFrame,
                      uint32_t aFlags) override;
 
   gfx::IntSize GetImageContainerSize(layers::LayerManager* aManager,
                                      const gfx::IntSize& aSize,
                                      uint32_t aFlags) override;
 
   //////////////////////////////////////////////////////////////////////////////
--- a/image/VectorImage.cpp
+++ b/image/VectorImage.cpp
@@ -736,27 +736,28 @@ VectorImage::GetFrame(uint32_t aWhichFra
   return GetFrameAtSize(imageIntSize, aWhichFrame, aFlags);
 }
 
 NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
 VectorImage::GetFrameAtSize(const IntSize& aSize,
                             uint32_t aWhichFrame,
                             uint32_t aFlags)
 {
-  auto result = GetFrameInternal(aSize, aWhichFrame, aFlags);
+  auto result = GetFrameInternal(aSize, Nothing(), aWhichFrame, aFlags);
   RefPtr<SourceSurface> surf = Get<2>(result).forget();
 
   // If we are here, it suggests the image is embedded in a canvas or some
   // other path besides layers, and we won't need the file handle.
   MarkSurfaceShared(surf);
   return surf.forget();
 }
 
 Tuple<DrawResult, IntSize, RefPtr<SourceSurface>>
 VectorImage::GetFrameInternal(const IntSize& aSize,
+                              const Maybe<SVGImageContext>& aSVGContext,
                               uint32_t aWhichFrame,
                               uint32_t aFlags)
 {
   MOZ_ASSERT(aWhichFrame <= FRAME_MAX_VALUE);
 
   if (aSize.IsEmpty() || aWhichFrame > FRAME_MAX_VALUE) {
     return MakeTuple(DrawResult::BAD_ARGS, aSize,
                      RefPtr<SourceSurface>());
@@ -768,17 +769,17 @@ VectorImage::GetFrameInternal(const IntS
   }
 
   if (!mIsFullyLoaded) {
     return MakeTuple(DrawResult::NOT_READY, aSize,
                      RefPtr<SourceSurface>());
   }
 
   RefPtr<SourceSurface> sourceSurface =
-    LookupCachedSurface(aSize, Nothing(), aFlags);
+    LookupCachedSurface(aSize, aSVGContext, aFlags);
   if (sourceSurface) {
     return MakeTuple(DrawResult::SUCCESS, aSize, Move(sourceSurface));
   }
 
   if (mIsDrawing) {
     NS_WARNING("Refusing to make re-entrant call to VectorImage::Draw");
     return MakeTuple(DrawResult::TEMPORARY_ERROR, aSize,
                      RefPtr<SourceSurface>());
@@ -792,19 +793,18 @@ VectorImage::GetFrameInternal(const IntS
     NS_ERROR("Could not create a DrawTarget");
     return MakeTuple(DrawResult::TEMPORARY_ERROR, aSize,
                      RefPtr<SourceSurface>());
   }
 
   RefPtr<gfxContext> context = gfxContext::CreateOrNull(dt);
   MOZ_ASSERT(context); // already checked the draw target above
 
-  Maybe<SVGImageContext> svgContext;
   SVGDrawingParameters params(context, aSize, ImageRegion::Create(aSize),
-                              SamplingFilter::POINT, svgContext,
+                              SamplingFilter::POINT, aSVGContext,
                               mSVGDocumentWrapper->GetCurrentTime(),
                               aFlags, 1.0);
 
   // DrawInternal may return a surface which is stored in the cache. It is
   // important to prefer this result over the snapshot because it may be a
   // different surface type (e.g. SourceSurfaceSharedData for WebRender). If
   // we did not put anything in the cache, we will need to fallback to the
   // snapshot surface.
@@ -857,22 +857,23 @@ VectorImage::IsImageContainerAvailableAt
   return aSize.width <= maxTextureSize &&
          aSize.height <= maxTextureSize;
 }
 
 //******************************************************************************
 NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
 VectorImage::GetImageContainerAtSize(LayerManager* aManager,
                                      const IntSize& aSize,
+                                     const Maybe<SVGImageContext>& aSVGContext,
                                      uint32_t aFlags)
 {
   // Since we do not support high quality scaling with SVG, we mask it off so
   // that container requests with and without it map to the same container.
   uint32_t flags = aFlags & ~FLAG_HIGH_QUALITY_SCALING;
-  return GetImageContainerImpl(aManager, aSize, aFlags);
+  return GetImageContainerImpl(aManager, aSize, aSVGContext, flags);
 }
 
 //******************************************************************************
 NS_IMETHODIMP_(DrawResult)
 VectorImage::Draw(gfxContext* aContext,
                   const nsIntSize& aSize,
                   const ImageRegion& aRegion,
                   uint32_t aWhichFrame,
--- a/image/VectorImage.h
+++ b/image/VectorImage.h
@@ -78,16 +78,17 @@ protected:
 
   virtual nsresult StartAnimation() override;
   virtual nsresult StopAnimation() override;
   virtual bool     ShouldAnimate() override;
 
 private:
   Tuple<DrawResult, IntSize, RefPtr<SourceSurface>>
     GetFrameInternal(const IntSize& aSize,
+                     const Maybe<SVGImageContext>& aSVGContext,
                      uint32_t aWhichFrame,
                      uint32_t aFlags) override;
 
   IntSize GetImageContainerSize(layers::LayerManager* aManager,
                                 const IntSize& aSize,
                                 uint32_t aFlags) override;
 
   /// Attempt to find a matching cached surface in the SurfaceCache.
--- a/image/imgIContainer.idl
+++ b/image/imgIContainer.idl
@@ -310,25 +310,29 @@ interface imgIContainer : nsISupports
    * not guaranteed that the surface you get will be a perfect match. (Some
    * reasons you may get a surface of a different size include: if you
    * requested upscaling, or if downscale-during-decode is disabled.)
    *
    * Avoid calling this unless you're actually going to layerize this image.
    *
    * @param aManager The LayerManager which will be used to create the
    *                 ImageContainer.
-   * @param aSize  The size to decode the frame at.
+   * @param aSVGContext If specified, SVG-related rendering context, such as
+   *                    overridden attributes on the image document's root <svg>
+   *                    node, and the size of the viewport that the full image
+   *                    would occupy. Ignored for raster images.
    * @param aFlags Decoding / drawing flags (in other words, FLAG_* flags).
    *               Currently only FLAG_SYNC_DECODE and FLAG_SYNC_DECODE_IF_FAST
    *               are supported.
    * @return An ImageContainer for the current frame, or nullptr if one could
    *         not be created.
    */
   [noscript, notxpcom] TempRefImageContainer getImageContainerAtSize(in LayerManager aManager,
                                                                      [const] in nsIntSize aSize,
+                                                                     [const] in MaybeSVGImageContext aSVGContext,
                                                                      in uint32_t aFlags);
 
   /**
    * Draw the requested frame of this image onto the context specified.
    *
    * Drawing an image involves scaling it to a certain size (which may be
    * implemented as a "smart" scale by substituting an HQ-scaled frame or
    * rendering at a high DPI), and then selecting a region of that image to
--- a/image/test/gtest/TestContainers.cpp
+++ b/image/test/gtest/TestContainers.cpp
@@ -68,35 +68,38 @@ TEST_F(ImageContainers, RasterImageConta
   EXPECT_EQ(testCase.mSize.height, containerSize.height);
 
   // Upscaling should give the native size.
   IntSize requestedSize = testCase.mSize;
   requestedSize.Scale(2, 2);
   RefPtr<layers::ImageContainer> upscaleContainer =
     image->GetImageContainerAtSize(layerManager,
                                    requestedSize,
+                                   Nothing(),
                                    imgIContainer::FLAG_SYNC_DECODE |
                                    imgIContainer::FLAG_HIGH_QUALITY_SCALING);
   ASSERT_TRUE(upscaleContainer != nullptr);
   containerSize = upscaleContainer->GetCurrentSize();
   EXPECT_EQ(testCase.mSize.width, containerSize.width);
   EXPECT_EQ(testCase.mSize.height, containerSize.height);
 
   // Downscaling should give the downscaled size.
   requestedSize = testCase.mSize;
   requestedSize.width /= 2;
   requestedSize.height /= 2;
   RefPtr<layers::ImageContainer> downscaleContainer =
     image->GetImageContainerAtSize(layerManager,
                                    requestedSize,
+                                   Nothing(),
                                    imgIContainer::FLAG_SYNC_DECODE |
                                    imgIContainer::FLAG_HIGH_QUALITY_SCALING);
   containerSize = downscaleContainer->GetCurrentSize();
   EXPECT_EQ(requestedSize.width, containerSize.width);
   EXPECT_EQ(requestedSize.height, containerSize.height);
 
   // Get at native size again. Should give same container.
   RefPtr<layers::ImageContainer> againContainer =
     image->GetImageContainerAtSize(layerManager,
                                    testCase.mSize,
+                                   Nothing(),
                                    imgIContainer::FLAG_SYNC_DECODE);
   ASSERT_EQ(nativeContainer.get(), againContainer.get());
 }