Bug 815593. Don't layerize images that exceed MaxTextureSize. r=mattwoodrow
authorRobert O'Callahan <robert@ocallahan.org>
Wed, 28 Nov 2012 15:34:45 +1300
changeset 123560 a4f64be02d63269ddbe8d930ee69f42489b42cc6
parent 123559 c94aecc61d74bef4029dd0b80746742ac22813a4
child 123561 676bf833f816e24d7c24650f13c89254e3c9f698
push id2151
push userlsblakk@mozilla.com
push dateTue, 19 Feb 2013 18:06:57 +0000
treeherdermozilla-beta@4952e88741ec [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs815593
milestone20.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 815593. Don't layerize images that exceed MaxTextureSize. r=mattwoodrow
image/public/imgIContainer.idl
image/src/RasterImage.cpp
image/src/VectorImage.cpp
layout/base/FrameLayerBuilder.cpp
layout/base/nsCSSRendering.cpp
layout/base/nsCSSRendering.h
layout/base/nsDisplayList.cpp
layout/base/nsDisplayList.h
layout/generic/nsImageFrame.cpp
layout/generic/nsImageFrame.h
layout/reftests/bugs/815593-1-ref.html
layout/reftests/bugs/815593-1.html
layout/reftests/bugs/reftest.list
layout/xul/base/src/nsImageBoxFrame.cpp
layout/xul/base/src/nsImageBoxFrame.h
--- a/image/public/imgIContainer.idl
+++ b/image/public/imgIContainer.idl
@@ -52,17 +52,17 @@ native gfxGraphicsFilter(gfxPattern::Gra
 /**
  * imgIContainer is the interface that represents an image. It allows
  * access to frames as Thebes surfaces, and permits users to extract subregions
  * as other imgIContainers. It also allows drawing of images on to Thebes
  * contexts.
  *
  * Internally, imgIContainer also manages animation of images.
  */
-[scriptable, uuid(d6c58749-ceb6-4afe-ab72-ff3086433e1f)]
+[scriptable, uuid(01e12ac9-7d9f-40d9-9ec1-70b64c53ce7a)]
 interface imgIContainer : nsISupports
 {
   /**
    * The width of the container rectangle.  In the case of any error,
    * zero is returned, and an exception will be thrown.
    */
   readonly attribute int32_t width;
 
@@ -153,17 +153,17 @@ interface imgIContainer : nsISupports
    */
   [noscript] gfxASurface getFrame(in uint32_t aWhichFrame,
                                   in uint32_t aFlags);
 
   /**
    * Attempts to create an ImageContainer (and Image) containing the current
    * frame. Only valid for RASTER type images.
    */
-  [noscript] ImageContainer getImageContainer();
+  [noscript] ImageContainer getImageContainer(in LayerManager aManager);
 
   /**
    * Create and return a new copy of the given frame that you can write to
    * and otherwise inspect the pixels of.
    *
    * @param aWhichFrame Frame specifier of the FRAME_* variety.
    * @param aFlags Flags of the FLAG_* variety
    */
--- a/image/src/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -1109,18 +1109,24 @@ RasterImage::GetCurrentImage()
   NS_ASSERTION(image->GetFormat() == cairoFormat, "Wrong format");
   static_cast<CairoImage*>(image.get())->SetData(cairoData);
 
   return image.forget();
 }
 
 
 NS_IMETHODIMP
-RasterImage::GetImageContainer(ImageContainer **_retval)
+RasterImage::GetImageContainer(LayerManager* aManager, ImageContainer **_retval)
 {
+  int32_t maxTextureSize = aManager->GetMaxTextureSize();
+  if (mSize.width > maxTextureSize || mSize.height > maxTextureSize) {
+    *_retval = nullptr;
+    return NS_OK;
+  }
+
   if (mImageContainer) {
     *_retval = mImageContainer;
     NS_ADDREF(*_retval);
     return NS_OK;
   }
 
   nsRefPtr<layers::Image> image = GetCurrentImage();
   if (!image) {
--- a/image/src/VectorImage.cpp
+++ b/image/src/VectorImage.cpp
@@ -20,16 +20,17 @@
 #include "nsSVGEffects.h" // for nsSVGRenderingObserver
 #include "gfxDrawable.h"
 #include "gfxUtils.h"
 #include "nsSVGSVGElement.h"
 
 namespace mozilla {
 
 using namespace dom;
+using namespace layers;
 
 namespace image {
 
 // Helper-class: SVGRootRenderingObserver
 class SVGRootRenderingObserver : public nsSVGRenderingObserver {
 public:
   SVGRootRenderingObserver(SVGDocumentWrapper* aDocWrapper,
                            VectorImage*        aVectorImage)
@@ -378,17 +379,18 @@ VectorImage::GetFrame(uint32_t aWhichFra
     *_retval = surface.forget().get();
   }
   return rv;
 }
 
 //******************************************************************************
 /* [noscript] ImageContainer getImageContainer(); */
 NS_IMETHODIMP
-VectorImage::GetImageContainer(mozilla::layers::ImageContainer** _retval)
+VectorImage::GetImageContainer(LayerManager* aManager,
+                               mozilla::layers::ImageContainer** _retval)
 {
   *_retval = nullptr;
   return NS_OK;
 }
 
 //******************************************************************************
 /* [noscript] gfxImageSurface copyFrame(in uint32_t aWhichFrame,
  *                                      in uint32_t aFlags); */
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -1529,17 +1529,17 @@ ContainerState::ThebesLayerData::UpdateC
 
 already_AddRefed<ImageContainer>
 ContainerState::ThebesLayerData::CanOptimizeImageLayer(nsDisplayListBuilder* aBuilder)
 {
   if (!mImage) {
     return nullptr;
   }
 
-  return mImage->GetContainer(aBuilder);
+  return mImage->GetContainer(mLayer->Manager(), aBuilder);
 }
 
 void
 ContainerState::PopThebesLayerData()
 {
   NS_ASSERTION(!mThebesLayerDataStack.IsEmpty(), "Can't pop");
 
   int32_t lastIndex = mThebesLayerDataStack.Length() - 1;
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -4691,26 +4691,27 @@ nsImageRenderer::IsRasterImage()
     return false;
   nsCOMPtr<imgIContainer> img;
   if (NS_FAILED(mImage->GetImageData()->GetImage(getter_AddRefs(img))))
     return false;
   return img->GetType() == imgIContainer::TYPE_RASTER;
 }
 
 already_AddRefed<mozilla::layers::ImageContainer>
-nsImageRenderer::GetContainer()
+nsImageRenderer::GetContainer(LayerManager* aManager)
 {
   if (mType != eStyleImageType_Image)
     return nullptr;
   nsCOMPtr<imgIContainer> img;
   nsresult rv = mImage->GetImageData()->GetImage(getter_AddRefs(img));
   if (NS_FAILED(rv))
     return nullptr;
+
   nsRefPtr<ImageContainer> container;
-  rv = img->GetImageContainer(getter_AddRefs(container));
+  rv = img->GetImageContainer(aManager, getter_AddRefs(container));
   NS_ENSURE_SUCCESS(rv, nullptr);
   return container.forget();
 }
 
 #define MAX_BLUR_RADIUS 300
 #define MAX_SPREAD_RADIUS 50
 
 static inline gfxIntSize
--- a/layout/base/nsCSSRendering.h
+++ b/layout/base/nsCSSRendering.h
@@ -24,16 +24,17 @@ class nsRenderingContext;
  * nsStyleImage image, which may internally be a real image, a sub image, or a
  * CSS gradient.
  *
  * @note Always call the member functions in the order of PrepareImage(),
  * ComputeSize(), and Draw().
  */
 class nsImageRenderer {
 public:
+  typedef mozilla::layers::LayerManager LayerManager;
   typedef mozilla::layers::ImageContainer ImageContainer;
 
   enum {
     FLAG_SYNC_DECODE_IMAGES = 0x01
   };
   nsImageRenderer(nsIFrame* aForFrame, const nsStyleImage* aImage, uint32_t aFlags);
   ~nsImageRenderer();
   /**
@@ -55,19 +56,19 @@ public:
    */
   void Draw(nsPresContext*       aPresContext,
             nsRenderingContext& aRenderingContext,
             const nsRect&        aDest,
             const nsRect&        aFill,
             const nsPoint&       aAnchor,
             const nsRect&        aDirty);
 
+  bool IsRasterImage();
+  already_AddRefed<ImageContainer> GetContainer(LayerManager* aManager);
 
-  bool IsRasterImage();
-  already_AddRefed<ImageContainer> GetContainer();
 private:
   /*
    * Compute the "unscaled" dimensions of the image in aUnscaled{Width,Height}
    * and aRatio.  Whether the image has a height and width are indicated by
    * aHaveWidth and aHaveHeight.  If the image doesn't have a ratio, aRatio will
    * be (0, 0).
    */
   void ComputeUnscaledDimensions(const nsSize& aBgPositioningArea,
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -1718,17 +1718,18 @@ nsDisplayBackgroundImage::IsSingleFixedP
 
   int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
   *aDestRect = nsLayoutUtils::RectToGfxRect(state.mFillArea, appUnitsPerDevPixel);
 
   return true;
 }
 
 bool
-nsDisplayBackgroundImage::TryOptimizeToImageLayer(nsDisplayListBuilder* aBuilder)
+nsDisplayBackgroundImage::TryOptimizeToImageLayer(LayerManager* aManager,
+                                                  nsDisplayListBuilder* aBuilder)
 {
   if (mIsThemed || !mBackgroundStyle)
     return false;
 
   nsPresContext* presContext = mFrame->PresContext();
   uint32_t flags = aBuilder->GetBackgroundPaintFlags();
   nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize());
   const nsStyleBackground::Layer &layer = mBackgroundStyle->mLayers[mLayer];
@@ -1742,17 +1743,17 @@ nsDisplayBackgroundImage::TryOptimizeToI
                                            *mBackgroundStyle,
                                            layer);
 
   nsImageRenderer* imageRenderer = &state.mImageRenderer;
   // We only care about images here, not gradients.
   if (!imageRenderer->IsRasterImage())
     return false;
 
-  nsRefPtr<ImageContainer> imageContainer = imageRenderer->GetContainer();
+  nsRefPtr<ImageContainer> imageContainer = imageRenderer->GetContainer(aManager);
   // Image is not ready to be made into a layer yet
   if (!imageContainer)
     return false;
 
   // We currently can't handle tiled or partial backgrounds.
   if (!state.mDestArea.IsEqualEdges(state.mFillArea)) {
     return false;
   }
@@ -1766,57 +1767,58 @@ nsDisplayBackgroundImage::TryOptimizeToI
   mDestRect = nsLayoutUtils::RectToGfxRect(state.mDestArea, appUnitsPerDevPixel);
   mImageContainer = imageContainer;
 
   // Ok, we can turn this into a layer if needed.
   return true;
 }
 
 already_AddRefed<ImageContainer>
-nsDisplayBackgroundImage::GetContainer(nsDisplayListBuilder *aBuilder)
+nsDisplayBackgroundImage::GetContainer(LayerManager* aManager,
+                                       nsDisplayListBuilder *aBuilder)
 {
-  if (!TryOptimizeToImageLayer(aBuilder)) {
+  if (!TryOptimizeToImageLayer(aManager, aBuilder)) {
     return nullptr;
   }
 
   nsRefPtr<ImageContainer> container = mImageContainer;
 
   return container.forget();
 }
 
 LayerState
 nsDisplayBackgroundImage::GetLayerState(nsDisplayListBuilder* aBuilder,
                                         LayerManager* aManager,
                                         const FrameLayerBuilder::ContainerParameters& aParameters)
 {
   if (!aManager->IsCompositingCheap() ||
       !nsLayoutUtils::GPUImageScalingEnabled() ||
-      !TryOptimizeToImageLayer(aBuilder)) {
+      !TryOptimizeToImageLayer(aManager, aBuilder)) {
     return LAYER_NONE;
   }
 
   gfxSize imageSize = mImageContainer->GetCurrentSize();
   NS_ASSERTION(imageSize.width != 0 && imageSize.height != 0, "Invalid image size!");
 
   gfxRect destRect = mDestRect;
 
   destRect.width *= aParameters.mXScale;
   destRect.height *= aParameters.mYScale;
 
   // Calculate the scaling factor for the frame.
   gfxSize scale = gfxSize(destRect.width / imageSize.width, destRect.height / imageSize.height);
 
   // If we are not scaling at all, no point in separating this into a layer.
   if (scale.width == 1.0f && scale.height == 1.0f) {
-    return LAYER_INACTIVE;
+    return LAYER_NONE;
   }
 
   // If the target size is pretty small, no point in using a layer.
   if (destRect.width * destRect.height < 64 * 64) {
-    return LAYER_INACTIVE;
+    return LAYER_NONE;
   }
 
   return LAYER_ACTIVE;
 }
 
 already_AddRefed<Layer>
 nsDisplayBackgroundImage::BuildLayer(nsDisplayListBuilder* aBuilder,
                                      LayerManager* aManager,
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -1555,17 +1555,18 @@ class nsDisplayImageContainer : public n
 public:
   typedef mozilla::layers::ImageContainer ImageContainer;
   typedef mozilla::layers::ImageLayer ImageLayer;
 
   nsDisplayImageContainer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
     : nsDisplayItem(aBuilder, aFrame)
   {}
 
-  virtual already_AddRefed<ImageContainer> GetContainer(nsDisplayListBuilder* aBuilder) = 0;
+  virtual already_AddRefed<ImageContainer> GetContainer(LayerManager* aManager,
+                                                        nsDisplayListBuilder* aBuilder) = 0;
   virtual void ConfigureLayer(ImageLayer* aLayer, const nsIntPoint& aOffset) = 0;
 
   virtual bool SupportsOptimizingToImage() { return true; }
 };
 
 /**
  * Use this class to implement not-very-frequently-used display items
  * that are not opaque, do not receive events, and are bounded by a frame's
@@ -1881,26 +1882,27 @@ public:
   {
     return new nsDisplayBackgroundGeometry(this, aBuilder);
   }
 
   virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                          const nsDisplayItemGeometry* aGeometry,
                                          nsRegion* aInvalidRegion) MOZ_OVERRIDE;
   
-  virtual already_AddRefed<ImageContainer> GetContainer(nsDisplayListBuilder *aBuilder) MOZ_OVERRIDE;
+  virtual already_AddRefed<ImageContainer> GetContainer(LayerManager* aManager,
+                                                        nsDisplayListBuilder *aBuilder) MOZ_OVERRIDE;
   virtual void ConfigureLayer(ImageLayer* aLayer, const nsIntPoint& aOffset) MOZ_OVERRIDE;
 
   static nsRegion GetInsideClipRegion(nsDisplayItem* aItem, nsPresContext* aPresContext, uint8_t aClip,
                                       const nsRect& aRect, bool* aSnap);
 protected:
   typedef class mozilla::layers::ImageContainer ImageContainer;
   typedef class mozilla::layers::ImageLayer ImageLayer;
 
-  bool TryOptimizeToImageLayer(nsDisplayListBuilder* aBuilder);
+  bool TryOptimizeToImageLayer(LayerManager* aManager, nsDisplayListBuilder* aBuilder);
   bool IsSingleFixedPositionImage(nsDisplayListBuilder* aBuilder,
                                   const nsRect& aClipRect,
                                   gfxRect* aDestRect);
   nsRect GetBoundsInternal();
 
   // Cache the result of nsCSSRendering::FindBackground. Always null if
   // mIsThemed is true or if FindBackground returned false.
   const nsStyleBackground* mBackgroundStyle;
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -1224,20 +1224,21 @@ nsDisplayImage::Paint(nsDisplayListBuild
   static_cast<nsImageFrame*>(mFrame)->
     PaintImage(*aCtx, ToReferenceFrame(), mVisibleRect, mImage,
                aBuilder->ShouldSyncDecodeImages()
                  ? (uint32_t) imgIContainer::FLAG_SYNC_DECODE
                  : (uint32_t) imgIContainer::FLAG_NONE);
 }
 
 already_AddRefed<ImageContainer>
-nsDisplayImage::GetContainer(nsDisplayListBuilder* aBuilder)
+nsDisplayImage::GetContainer(LayerManager* aManager,
+                             nsDisplayListBuilder* aBuilder)
 {
   nsRefPtr<ImageContainer> container;
-  nsresult rv = mImage->GetImageContainer(getter_AddRefs(container));
+  nsresult rv = mImage->GetImageContainer(aManager, getter_AddRefs(container));
   NS_ENSURE_SUCCESS(rv, nullptr);
   return container.forget();
 }
 
 gfxRect
 nsDisplayImage::GetDestRect()
 {
   int32_t factor = mFrame->PresContext()->AppUnitsPerDevPixel();
@@ -1273,34 +1274,40 @@ nsDisplayImage::GetLayerState(nsDisplayL
   destRect.width *= aParameters.mXScale;
   destRect.height *= aParameters.mYScale;
 
   // Calculate the scaling factor for the frame.
   gfxSize scale = gfxSize(destRect.width / imageWidth, destRect.height / imageHeight);
 
   // If we are not scaling at all, no point in separating this into a layer.
   if (scale.width == 1.0f && scale.height == 1.0f) {
-    return LAYER_INACTIVE;
+    return LAYER_NONE;
   }
 
   // If the target size is pretty small, no point in using a layer.
   if (destRect.width * destRect.height < 64 * 64) {
-    return LAYER_INACTIVE;
+    return LAYER_NONE;
+  }
+
+  nsRefPtr<ImageContainer> container;
+  nsresult rv = mImage->GetImageContainer(aManager, getter_AddRefs(container));
+  if (!container) {
+    return LAYER_NONE;
   }
 
   return LAYER_ACTIVE;
 }
 
 already_AddRefed<Layer>
 nsDisplayImage::BuildLayer(nsDisplayListBuilder* aBuilder,
                            LayerManager* aManager,
                            const ContainerParameters& aParameters)
 {
   nsRefPtr<ImageContainer> container;
-  nsresult rv = mImage->GetImageContainer(getter_AddRefs(container));
+  nsresult rv = mImage->GetImageContainer(aManager, getter_AddRefs(container));
   NS_ENSURE_SUCCESS(rv, nullptr);
 
   nsRefPtr<ImageLayer> layer = aManager->CreateImageLayer();
   layer->SetContainer(container);
   ConfigureLayer(layer, aParameters.mOffset);
   return layer.forget();
 }
 
--- a/layout/generic/nsImageFrame.h
+++ b/layout/generic/nsImageFrame.h
@@ -365,17 +365,18 @@ public:
   }
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      nsRenderingContext* aCtx) MOZ_OVERRIDE;
 
   /**
    * Returns an ImageContainer for this image if the image type
    * supports it (TYPE_RASTER only).
    */
-  virtual already_AddRefed<ImageContainer> GetContainer(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE;
+  virtual already_AddRefed<ImageContainer> GetContainer(LayerManager* aManager,
+                                                        nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE;
 
   gfxRect GetDestRect();
 
   virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
                                    LayerManager* aManager,
                                    const ContainerParameters& aParameters) MOZ_OVERRIDE;
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE
   {
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/815593-1-ref.html
@@ -0,0 +1,6 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+<img style="transform:translate(20px,0)" id="i" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAE4gCAYAAAA/MefJAAAJaklEQVR4nO3KQREAAAwCIPuX1ghbAI4vSZ9EURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRF8TbU+MCtlWtcNAAAAABJRU5ErkJggg==">
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/815593-1.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML>
+<html class="reftest-wait">
+<body>
+<img id="i" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAE4gCAYAAAA/MefJAAAJaklEQVR4nO3KQREAAAwCIPuX1ghbAI4vSZ9EURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRF8TbU+MCtlWtcNAAAAABJRU5ErkJggg==">
+<script>
+var i = document.getElementById("i");
+i.getBoundingClientRect();
+i.style.transform = "translate(10px,0)";
+window.addEventListener("MozReftestInvalidate", function() {
+  i.style.transform = "translate(20px,0)";
+  document.documentElement.removeAttribute("class");
+}, false);
+</script>
+</body>
+</html>
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1727,8 +1727,9 @@ fuzzy-if(true,17,5859) == 759036-2.html 
 == 787947-1.html 787947-1-ref.html
 == 796847-1.svg 796847-1-ref.svg
 fuzzy(40,800) == 797797-1.html 797797-1-ref.html # 'opacity:N' and rgba(,,,N) text don't match precisely
 fuzzy(40,800) == 797797-2.html 797797-2-ref.html # 'opacity:N' and rgba(,,,N) text don't match precisely
 == 801994-1.html 801994-1-ref.html
 == 804323-1.html 804323-1-ref.html
 == 811301-1.html 811301-1-ref.html
 == 812824-1.html 812824-1-ref.html
+== 815593-1.html 815593-1-ref.html
--- a/layout/xul/base/src/nsImageBoxFrame.cpp
+++ b/layout/xul/base/src/nsImageBoxFrame.cpp
@@ -383,37 +383,37 @@ nsDisplayXULImage::ConfigureLayer(ImageL
   transform.Scale(destRect.Width()/imageWidth,
                   destRect.Height()/imageHeight);
   aLayer->SetBaseTransform(gfx3DMatrix::From2D(transform));
 
   aLayer->SetVisibleRegion(nsIntRect(0, 0, imageWidth, imageHeight));
 }
 
 already_AddRefed<ImageContainer>
-nsDisplayXULImage::GetContainer(nsDisplayListBuilder* aBuilder)
+nsDisplayXULImage::GetContainer(LayerManager* aManager, nsDisplayListBuilder* aBuilder)
 {
-  return static_cast<nsImageBoxFrame*>(mFrame)->GetContainer();
+  return static_cast<nsImageBoxFrame*>(mFrame)->GetContainer(aManager);
 }
 
 already_AddRefed<ImageContainer>
-nsImageBoxFrame::GetContainer()
+nsImageBoxFrame::GetContainer(LayerManager* aManager)
 {
   bool hasSubRect = !mUseSrcAttr && (mSubRect.width > 0 || mSubRect.height > 0);
   if (hasSubRect || !mImageRequest) {
     return nullptr;
   }
 
   nsCOMPtr<imgIContainer> imgCon;
   mImageRequest->GetImage(getter_AddRefs(imgCon));
   if (!imgCon) {
     return nullptr;
   }
   
   nsRefPtr<ImageContainer> container;
-  nsresult rv = imgCon->GetImageContainer(getter_AddRefs(container));
+  nsresult rv = imgCon->GetImageContainer(aManager, getter_AddRefs(container));
   NS_ENSURE_SUCCESS(rv, nullptr);
   return container.forget();
 }
 
 
 //
 // DidSetStyleContext
 //
--- a/layout/xul/base/src/nsImageBoxFrame.h
+++ b/layout/xul/base/src/nsImageBoxFrame.h
@@ -30,16 +30,18 @@ public:
 
 private:
   nsImageBoxFrame *mFrame;
 };
 
 class nsImageBoxFrame : public nsLeafBoxFrame
 {
 public:
+  typedef mozilla::layers::LayerManager LayerManager;
+
   friend class nsDisplayXULImage;
   NS_DECL_FRAMEARENA_HELPERS
 
   virtual nsSize GetPrefSize(nsBoxLayoutState& aBoxLayoutState);
   virtual nsSize GetMinSize(nsBoxLayoutState& aBoxLayoutState);
   virtual nscoord GetBoxAscent(nsBoxLayoutState& aBoxLayoutState) MOZ_OVERRIDE;
   virtual void MarkIntrinsicWidthsDirty() MOZ_OVERRIDE;
 
@@ -82,17 +84,17 @@ public:
                               const nsDisplayListSet& aLists) MOZ_OVERRIDE;
 
   virtual ~nsImageBoxFrame();
 
   void  PaintImage(nsRenderingContext& aRenderingContext,
                    const nsRect& aDirtyRect,
                    nsPoint aPt, uint32_t aFlags);
 
-  already_AddRefed<mozilla::layers::ImageContainer> GetContainer();
+  already_AddRefed<mozilla::layers::ImageContainer> GetContainer(LayerManager* aManager);
 protected:
   nsImageBoxFrame(nsIPresShell* aShell, nsStyleContext* aContext);
 
   virtual void GetImageSize();
 
 private:
   nsresult OnStartContainer(imgIRequest *request, imgIContainer *image);
   nsresult OnStopDecode(imgIRequest *request);
@@ -125,17 +127,18 @@ public:
     MOZ_COUNT_CTOR(nsDisplayXULImage);
   }
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayXULImage() {
     MOZ_COUNT_DTOR(nsDisplayXULImage);
   }
 #endif
 
-  virtual already_AddRefed<ImageContainer> GetContainer(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE;
+  virtual already_AddRefed<ImageContainer> GetContainer(LayerManager* aManager,
+                                                        nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE;
   virtual void ConfigureLayer(ImageLayer* aLayer, const nsIntPoint& aOffset) MOZ_OVERRIDE;
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
   {
     *aSnap = true;
     return nsRect(ToReferenceFrame(), GetUnderlyingFrame()->GetSize());
   }
 
   // Doesn't handle HitTest because nsLeafBoxFrame already creates an