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 436909 54d6ad659f11103861cf2d53259d77764dfd675e
parent 436908 79b16521982847de443b83ec0f6cf9a4ce653bad
child 436910 e65c223336d99d8e7fae360b2fd3c1b10a91d531
push id117
push userfmarier@mozilla.com
push dateTue, 28 Nov 2017 20:17:16 +0000
reviewerstnikkel
bugs1366097
milestone59.0a1
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());
 }