Bug 1372118 - Part3. Support image related display items. draft
authorEthan Lin <ethlin@mozilla.com>
Mon, 26 Jun 2017 22:54:34 -0700
changeset 600609 05e57b81674df475395a50f84a67a13d22a43fa0
parent 600608 3c4bbc34e7483092f68aa8df819152977b7a4a35
child 600610 a9416c994f0897bd1fff29e36738108e377c9802
push id65803
push userbmo:ethlin@mozilla.com
push dateTue, 27 Jun 2017 16:20:34 +0000
bugs1372118
milestone56.0a1
Bug 1372118 - Part3. Support image related display items. MozReview-Commit-ID: 8XJ4xdref4D
gfx/layers/wr/WebRenderLayerManager.cpp
gfx/layers/wr/WebRenderLayerManager.h
layout/generic/nsImageFrame.cpp
layout/generic/nsImageFrame.h
layout/painting/nsCSSRendering.cpp
layout/painting/nsCSSRendering.h
layout/painting/nsDisplayList.cpp
layout/painting/nsDisplayList.h
layout/painting/nsImageRenderer.cpp
layout/painting/nsImageRenderer.h
--- a/gfx/layers/wr/WebRenderLayerManager.cpp
+++ b/gfx/layers/wr/WebRenderLayerManager.cpp
@@ -245,16 +245,18 @@ WebRenderLayerManager::EndTransactionWit
   WrSize contentSize { (float)size.width, (float)size.height };
   wr::DisplayListBuilder builder(WrBridge()->GetPipeline(), contentSize);
 
   if (aDisplayList && aDisplayListBuilder) {
     StackingContextHelper sc;
     mParentCommands.Clear();
     CreateWebRenderCommandsFromDisplayList(this, aDisplayList, aDisplayListBuilder, sc, builder);
     builder.Finalize(contentSize, mBuiltDisplayList);
+
+    mLastItemData.SwapElements(mItemData);
   } else {
   }
 
   builder.PushBuiltDisplayList(mBuiltDisplayList);
 
   WrBridge()->AddWebRenderParentCommands(mParentCommands);
 
 
@@ -292,16 +294,198 @@ WebRenderLayerManager::EndTransactionWit
   mNeedsComposite = false;
 
   // this may result in Layers being deleted, which results in
   // PLayer::Send__delete__() and DeallocShmem()
   mKeepAlive.Clear();
 }
 
 void
+WebRenderLayerManager::SendAnimationData(WMAnimationData* aAnimationData,
+                                         OptionalOpacity aOpacity,
+                                         OptionalTransform aTransform)
+{
+  aAnimationData->ResolveStartTime(mAnimationReadyTime);
+  OpAddCompositorAnimations
+    anim(CompositorAnimations(aAnimationData->GetAnimations(),
+                              aAnimationData->GetCompositorAnimationsId()),
+                              aTransform,
+                              aOpacity);
+  WrBridge()->AddWebRenderParentCommand(anim);
+}
+
+Maybe<wr::ImageKey>
+WebRenderLayerManager::CreateImageKey(nsDisplayItem* aItem,
+                                      ImageContainer* aContainer,
+                                      mozilla::wr::DisplayListBuilder& aBuilder,
+                                      const StackingContextHelper& aSc,
+                                      gfx::IntSize& aSize)
+{
+  RefPtr<WMImageData> imageData = CreateOrRecycleWMData<WMImageData>(aItem);
+  MOZ_ASSERT(imageData);
+
+  imageData->mContainer = aContainer;
+
+  if (aContainer->IsAsync()) {
+    imageData->mImageClientTypeContainer = CompositableType::IMAGE_BRIDGE;
+  } else {
+    AutoLockImage autoLock(aContainer);
+    imageData->mImageClientTypeContainer = autoLock.HasImage()
+      ? CompositableType::IMAGE : CompositableType::UNKNOWN;
+  }
+
+  if (imageData->mImageClientTypeContainer == CompositableType::IMAGE && !imageData->mImageClient) {
+    imageData->mImageClient = ImageClient::CreateImageClient(CompositableType::IMAGE,
+                                                  WrBridge(),
+                                                  TextureFlags::DEFAULT);
+    if (!imageData->mImageClient) {
+      return Nothing();
+    }
+    imageData->mImageClient->Connect();
+  }
+
+  if (imageData->mImageClientTypeContainer == CompositableType::IMAGE_BRIDGE && imageData->mPipelineId.isNothing()) {
+    MOZ_ASSERT(!imageData->mImageClient);
+    // Alloc async image pipeline id.
+    imageData->mPipelineId = Some(WrBridge()->GetCompositorBridgeChild()->GetNextPipelineId());
+    WrBridge()->AddPipelineIdForAsyncCompositable(imageData->mPipelineId.ref(),
+                                                  aContainer->GetAsyncContainerHandle());
+  } else if (imageData->mImageClientTypeContainer == CompositableType::IMAGE && imageData->mExternalImageId.isNothing())  {
+    MOZ_ASSERT(imageData->mImageClient);
+    imageData->mExternalImageId = Some(WrBridge()->AllocExternalImageIdForCompositable(imageData->mImageClient));
+    MOZ_ASSERT(imageData->mExternalImageId.isSome());
+  }
+
+  if (imageData->mImageClientTypeContainer == CompositableType::IMAGE_BRIDGE) {
+    MOZ_ASSERT(!imageData->mImageClient);
+    MOZ_ASSERT(imageData->mExternalImageId.isNothing());
+
+    // Push IFrame for async image pipeline.
+    // XXX Remove this once partial display list update is supported.
+
+    //ScrollingLayersHelper scroller(this, aBuilder, aSc);
+
+    //ParentLayerRect bounds = GetLocalTransformTyped().TransformBounds(Bounds());
+
+    // We don't push a stacking context for this async image pipeline here.
+    // Instead, we do it inside the iframe that hosts the image. As a result,
+    // a bunch of the calculations normally done as part of that stacking
+    // context need to be done manually and pushed over to the parent side,
+    // where it will be done when we build the display list for the iframe.
+    // That happens in WebRenderCompositableHolder.
+
+    bool snap;
+    nsRect bounds = aItem->GetBounds(nullptr, &snap);
+    int32_t appUnitsPerDevPixel = aItem->Frame()->PresContext()->AppUnitsPerDevPixel();
+    LayoutDeviceRect rect = LayoutDeviceRect::FromAppUnits(
+                              bounds, appUnitsPerDevPixel);
+
+    aBuilder.PushIFrame(aSc.ToRelativeWrRect(rect), aSc.ToRelativeWrRect(rect), imageData->mPipelineId.ref());
+    gfx::Matrix4x4 scTransform;
+    LayerRect scBounds(0, 0, rect.width, rect.height);
+    MaybeIntSize scaleToSize;
+    //if (mScaleMode != ScaleMode::SCALE_NONE) {
+    //  NS_ASSERTION(mScaleMode == ScaleMode::STRETCH,
+    //               "No other scalemodes than stretch and none supported yet.");
+    //  scaleToSize = Some(mScaleToSize);
+    //}
+    //LayerRect scBounds = BoundsForStackingContext();
+    wr::ImageRendering filter = wr::ImageRendering::Auto; //wr::ToImageRendering(mSamplingFilter);
+    wr::MixBlendMode mixBlendMode = wr::MixBlendMode::Normal; //wr::ToWrMixBlendMode(GetMixBlendMode());
+
+    WrBridge()->AddWebRenderParentCommand(OpUpdateAsyncImagePipeline(imageData->mPipelineId.value(),
+                                                                     scBounds,
+                                                                     scTransform,
+                                                                     scaleToSize,
+                                                                     filter,
+                                                                     mixBlendMode));
+    return Nothing();
+  }
+
+  MOZ_ASSERT(imageData->mImageClientTypeContainer == CompositableType::IMAGE);
+  MOZ_ASSERT(imageData->mImageClient->AsImageClientSingle());
+
+  AutoLockImage autoLock(aContainer);
+  mozilla::layers::Image* image = autoLock.GetImage();
+  if (!image) {
+    return Nothing();
+  }
+  aSize = image->GetSize();
+  ImageClientSingle* imageClient = imageData->mImageClient->AsImageClientSingle();
+  MOZ_ASSERT(imageClient);
+  MOZ_ASSERT(aContainer);
+  uint32_t oldCounter = imageClient->GetLastUpdateGenerationCounter();
+
+  bool ret = imageClient->UpdateImage(aContainer, /* unused */0);
+  if (!ret || imageClient->IsEmpty()) {
+    // Delete old key
+    if (imageData->mKey.isSome()) {
+      AddImageKeyForDiscard(imageData->mKey.value());
+      imageData->mKey = Nothing();
+    }
+    return Nothing();
+  }
+
+  // Reuse old key if generation is not updated.
+  if (oldCounter == imageClient->GetLastUpdateGenerationCounter() && imageData->mKey.isSome()) {
+    return imageData->mKey;
+  }
+
+  // Delete old key, we are generating a new key.
+  if (imageData->mKey.isSome()) {
+    AddImageKeyForDiscard(imageData->mKey.value());
+    imageData->mKey = Nothing();
+  }
+
+  WrImageKey key;
+  key.mNamespace = WrBridge()->GetNamespace();
+  key.mHandle = WrBridge()->GetNextResourceId();
+  WrBridge()->AddWebRenderParentCommand(OpAddExternalImage(imageData->mExternalImageId.value(), key));
+  imageData->mKey = Some(key);
+
+  return imageData->mKey;
+}
+
+bool
+WebRenderLayerManager::PushImage(nsDisplayItem* aItem,
+                                 mozilla::wr::DisplayListBuilder& aBuilder,
+                                 const StackingContextHelper& aSc,
+                                 ImageContainer* aContainer,
+                                 const LayerRect& aRect)
+{
+  gfx::IntSize size;
+  Maybe<wr::ImageKey> key = CreateImageKey(aItem, aContainer, aBuilder, aSc, size);
+  if (!key) {
+    return false;
+  }
+
+  #if 0
+  if (mScaleMode != ScaleMode::SCALE_NONE) {
+    NS_ASSERTION(mScaleMode == ScaleMode::STRETCH,
+                 "No other scalemodes than stretch and none supported yet.");
+    rect = LayerRect(0, 0, mScaleToSize.width, mScaleToSize.height);
+  }
+  #endif
+
+  #if 0
+  LayoutDeviceRect clipRect(0, 0, size.width, size.height);
+  if (aItem->GetClip().HasClip()) {
+    int32_t appUnitsPerDevPixel = aItem->Frame()->PresContext()->AppUnitsPerDevPixel();
+    clipRect = LayoutDeviceRect::FromAppUnits(
+                aItem->GetClip().GetClipRect(), appUnitsPerDevPixel);
+  }
+  #endif
+
+  wr::ImageRendering filter = wr::ImageRendering::Auto;
+  aBuilder.PushImage(aSc.ToRelativeWrRect(aRect), aSc.ToRelativeWrRect(aRect), filter, key.value());
+
+  return true;
+}
+
+void
 WebRenderLayerManager::EndTransaction(DrawPaintedLayerCallback aCallback,
                                       void* aCallbackData,
                                       EndTransactionFlags aFlags)
 {
   DiscardImages();
   WrBridge()->RemoveExpiredFontKeys();
   EndTransactionInternal(aCallback, aCallbackData, aFlags);
 }
--- a/gfx/layers/wr/WebRenderLayerManager.h
+++ b/gfx/layers/wr/WebRenderLayerManager.h
@@ -6,27 +6,106 @@
 #ifndef GFX_WEBRENDERLAYERMANAGER_H
 #define GFX_WEBRENDERLAYERMANAGER_H
 
 #include "Layers.h"
 #include "mozilla/MozPromise.h"
 #include "mozilla/layers/APZTestData.h"
 #include "mozilla/layers/TransactionIdAllocator.h"
 #include "mozilla/webrender/WebRenderTypes.h"
+#include "mozilla/layers/StackingContextHelper.h"
+#include "mozilla/layers/AnimationHelper.h"
+#include "mozilla/layers/ImageClient.h"
+#include "mozilla/layers/WebRenderBridgeChild.h"
+#include "mozilla/webrender/WebRenderAPI.h"
+#include "nsDisplayList.h"
 
 class nsIWidget;
+class nsDisplayList;
 
 namespace mozilla {
 namespace layers {
 
 class CompositorBridgeChild;
 class KnowsCompositor;
 class PCompositorBridgeChild;
 class WebRenderBridgeChild;
 
+typedef Pair<nsIFrame*, uint32_t> FrameDisplayItemKey;
+
+class FrameDisplayItemKeyHashEntry : public PLDHashEntryHdr
+{
+public:
+  typedef FrameDisplayItemKey KeyType;
+  typedef const FrameDisplayItemKey* KeyTypePointer;
+
+  explicit FrameDisplayItemKeyHashEntry(KeyTypePointer aKey)
+    : mKey(*aKey) { }
+  explicit FrameDisplayItemKeyHashEntry(const FrameDisplayItemKeyHashEntry& aCopy) = default;
+
+  ~FrameDisplayItemKeyHashEntry() = default;
+
+  KeyType GetKey() const { return mKey; }
+  bool KeyEquals(KeyTypePointer aKey) const
+  {
+    return mKey.first() == aKey->first() && mKey.second() == aKey->second();
+  }
+
+  static KeyTypePointer KeyToPointer(KeyType& aKey) { return &aKey; }
+  static PLDHashNumber HashKey(KeyTypePointer aKey)
+  {
+    if (!aKey)
+      return 0;
+
+    return HashGeneric(aKey->first(), aKey->second());
+  }
+
+  enum { ALLOW_MEMMOVE = true };
+
+  FrameDisplayItemKey mKey;
+};
+
+class WMImageData;
+
+class WMData
+{
+public:
+  NS_INLINE_DECL_REFCOUNTING(WMData)
+
+  virtual WMAnimationData* AsAnimationData() { return nullptr; }
+  virtual WMImageData* AsImageData() { return nullptr; }
+  virtual WMCanvasData* AsCanvasData() { return nullptr; }
+
+  enum class TYPE {
+    ANIMATION,
+    IMAGE,
+    CANVAS
+  };
+
+  virtual TYPE GetType() = 0;
+
+protected:
+  virtual ~WMData() {}
+};
+
+class WMImageData : public WMData
+{
+public:
+  virtual WMImageData* AsImageData() override { return this; }
+  virtual TYPE GetType() override { return TYPE::IMAGE; }
+  static TYPE Type() { return TYPE::IMAGE; }
+
+  wr::MaybeExternalImageId mExternalImageId;
+  Maybe<wr::ImageKey> mKey;
+  RefPtr<ImageClient> mImageClient;
+  CompositableType mImageClientTypeContainer;
+  Maybe<wr::PipelineId> mPipelineId;
+  RefPtr<ImageContainer> mContainer;
+};
+
 class WebRenderLayerManager final : public LayerManager
 {
   typedef nsTArray<RefPtr<Layer> > LayerRefArray;
 
 public:
   explicit WebRenderLayerManager(nsIWidget* aWidget);
   void Initialize(PCompositorBridgeChild* aCBChild, wr::PipelineId aLayersId, TextureFactoryIdentifier* aTextureFactoryIdentifier);
 
@@ -40,23 +119,35 @@ public:
   WebRenderLayerManager* AsWebRenderLayerManager() override { return this; }
   virtual CompositorBridgeChild* GetCompositorBridgeChild() override;
 
   virtual int32_t GetMaxTextureSize() const override;
 
   virtual bool BeginTransactionWithTarget(gfxContext* aTarget) override;
   virtual bool BeginTransaction() override;
   virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT) override;
+  Maybe<wr::ImageKey> CreateImageKey(nsDisplayItem* aItem,
+                                     ImageContainer* aContainer,
+                                     mozilla::wr::DisplayListBuilder& aBuilder,
+                                     const StackingContextHelper& aSc,
+                                     gfx::IntSize& aSize);
+  bool PushImage(nsDisplayItem* aItem,
+                 mozilla::wr::DisplayListBuilder& aBuilder,
+                 const StackingContextHelper& aSc,
+                 ImageContainer* aContainer,
+                 const LayerRect& aRect);
+
   static void CreateWebRenderCommandsFromDisplayList(WebRenderLayerManager* aManager,
                                                      nsDisplayList* aDisplayList,
                                                      nsDisplayListBuilder* aDisplayListBuilder,
                                                      StackingContextHelper& aSc,
                                                      wr::DisplayListBuilder& aBuilder);
   void EndTransactionWithoutLayer(nsDisplayList* aDisplayList,
                                   nsDisplayListBuilder* aDisplayListBuilder);
+
   virtual void EndTransaction(DrawPaintedLayerCallback aCallback,
                               void* aCallbackData,
                               EndTransactionFlags aFlags = END_DEFAULT) override;
 
   virtual LayersBackend GetBackendType() override { return LayersBackend::LAYERS_WR; }
   virtual void GetBackendName(nsAString& name) override { name.AssignLiteral("WebRender"); }
   virtual const char* Name() const override { return "WebRender"; }
 
@@ -152,16 +243,18 @@ private:
   void MakeSnapshotIfRequired(LayoutDeviceIntSize aSize);
 
   void ClearLayer(Layer* aLayer);
 
   bool EndTransactionInternal(DrawPaintedLayerCallback aCallback,
                               void* aCallbackData,
                               EndTransactionFlags aFlags);
 
+  nsDataHashtable<FrameDisplayItemKeyHashEntry, RefPtr<WMData>> mItemData;
+  nsDataHashtable<FrameDisplayItemKeyHashEntry, RefPtr<WMData>> mLastItemData;
   wr::BuiltDisplayList mBuiltDisplayList;
   nsTArray<WebRenderParentCommand> mParentCommands;
 
 private:
   nsIWidget* MOZ_NON_OWNING_REF mWidget;
   std::vector<wr::ImageKey> mImageKeys;
   nsTArray<uint64_t> mDiscardedCompositorAnimationsIds;
 
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -76,16 +76,25 @@
 #include "nsBlockFrame.h"
 #include "nsStyleStructInlines.h"
 
 #include "mozilla/Preferences.h"
 
 #include "mozilla/dom/Link.h"
 #include "SVGImageContext.h"
 
+#include "mozilla/layers/ImageClient.h"
+#include "mozilla/layers/WebRenderLayerManager.h"
+#include "mozilla/layers/WebRenderBridgeChild.h"
+#include "mozilla/webrender/WebRenderAPI.h"
+#include "mozilla/layers/ScrollingLayersHelper.h"
+#include "mozilla/layers/StackingContextHelper.h"
+#include "mozilla/layers/CompositorBridgeChild.h"
+#include "ImageContainer.h"
+
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::gfx;
 using namespace mozilla::image;
 using namespace mozilla::layers;
 
 // sizes (pixels) for image icon, padding and border frame
 #define ICON_SIZE        (16)
@@ -1680,16 +1689,46 @@ nsDisplayImage::BuildLayer(nsDisplayList
     if (!layer)
       return nullptr;
   }
   layer->SetContainer(container);
   ConfigureLayer(layer, aParameters);
   return layer.forget();
 }
 
+bool
+nsDisplayImage::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
+                                        const StackingContextHelper& aSc,
+                                        nsTArray<WebRenderParentCommand>& aParentCommands,
+                                        WebRenderLayerManager* aManager,
+                                        nsDisplayListBuilder* aDisplayListBuilder)
+{
+  if (!CanOptimizeToImageLayer(aManager, aDisplayListBuilder)) {
+    return false;
+  }
+
+  uint32_t flags = imgIContainer::FLAG_ASYNC_NOTIFY;
+  if (aDisplayListBuilder->ShouldSyncDecodeImages()) {
+    flags |= imgIContainer::FLAG_SYNC_DECODE;
+  }
+
+  RefPtr<ImageContainer> container =
+    mImage->GetImageContainer(aManager, flags);
+  if (!container) {
+    return false;
+  }
+
+
+  const int32_t factor = mFrame->PresContext()->AppUnitsPerDevPixel();
+  const LayoutDeviceRect destRect(
+    LayoutDeviceIntRect::FromAppUnits(GetDestRect(), factor));
+  const LayerRect dest = ViewAs<LayerPixel>(destRect, PixelCastJustification::WebRenderHasUnitResolution);
+  return aManager->PushImage(this, aBuilder, aSc, container, dest);
+}
+
 DrawResult
 nsImageFrame::PaintImage(gfxContext& aRenderingContext, nsPoint aPt,
                          const nsRect& aDirtyRect, imgIContainer* aImage,
                          uint32_t aFlags)
 {
   DrawTarget* drawTarget = aRenderingContext.GetDrawTarget();
 
   // Render the image into our content area (the area inside
--- a/layout/generic/nsImageFrame.h
+++ b/layout/generic/nsImageFrame.h
@@ -455,16 +455,20 @@ public:
   }
 
   virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
                                    bool* aSnap) override;
 
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aContainerParameters) override;
-
-  NS_DISPLAY_DECL_NAME("Image", TYPE_IMAGE)
+  virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
+                                       const StackingContextHelper& aSc,
+                                       nsTArray<WebRenderParentCommand>& aParentCommands,
+                                       mozilla::layers::WebRenderLayerManager* aManager,
+                                       nsDisplayListBuilder* aDisplayListBuilder) override;
+   NS_DISPLAY_DECL_NAME("Image", TYPE_IMAGE)
 private:
   nsCOMPtr<imgIContainer> mImage;
   nsCOMPtr<imgIContainer> mPrevImage;
 };
 
 #endif /* nsImageFrame_h___ */
--- a/layout/painting/nsCSSRendering.cpp
+++ b/layout/painting/nsCSSRendering.cpp
@@ -1991,17 +1991,19 @@ nsCSSRendering::CanBuildWebRenderDisplay
   return false;
 }
 
 DrawResult
 nsCSSRendering::BuildWebRenderDisplayItemsForStyleImageLayer(const PaintBGParams& aParams,
                                                              mozilla::wr::DisplayListBuilder& aBuilder,
                                                              const mozilla::layers::StackingContextHelper& aSc,
                                                              nsTArray<WebRenderParentCommand>& aParentCommands,
-                                                             mozilla::layers::WebRenderDisplayItemLayer* aLayer)
+                                                             mozilla::layers::WebRenderDisplayItemLayer* aLayer,
+                                                             mozilla::layers::WebRenderLayerManager* aManager,
+                                                             nsDisplayItem* aItem)
 {
   NS_PRECONDITION(aParams.frame,
                   "Frame is expected to be provided to BuildWebRenderDisplayItemsForStyleImageLayer");
 
   nsStyleContext *sc;
   if (!FindBackground(aParams.frame, &sc)) {
     // We don't want to bail out if moz-appearance is set on a root
     // node. If it has a parent content node, bail because it's not
@@ -2014,18 +2016,18 @@ nsCSSRendering::BuildWebRenderDisplayIte
 
     nsIContent* content = aParams.frame->GetContent();
     if (!content || content->GetParent()) {
       return DrawResult::SUCCESS;
     }
 
     sc = aParams.frame->StyleContext();
   }
-
-  return BuildWebRenderDisplayItemsForStyleImageLayerWithSC(aParams, aBuilder, aSc, aParentCommands, aLayer,
+  return BuildWebRenderDisplayItemsForStyleImageLayerWithSC(aParams, aBuilder, aSc, aParentCommands,
+                                                            aLayer, aManager, aItem,
                                                             sc, *aParams.frame->StyleBorder());
 }
 
 static bool
 IsOpaqueBorderEdge(const nsStyleBorder& aBorder, mozilla::Side aSide)
 {
   if (aBorder.GetComputedBorder().Side(aSide) == 0)
     return true;
@@ -2738,25 +2740,21 @@ nsCSSRendering::PaintStyleImageLayerWith
 }
 
 DrawResult
 nsCSSRendering::BuildWebRenderDisplayItemsForStyleImageLayerWithSC(const PaintBGParams& aParams,
                                                                    mozilla::wr::DisplayListBuilder& aBuilder,
                                                                    const mozilla::layers::StackingContextHelper& aSc,
                                                                    nsTArray<WebRenderParentCommand>& aParentCommands,
                                                                    mozilla::layers::WebRenderDisplayItemLayer* aLayer,
+                                                                   mozilla::layers::WebRenderLayerManager* aManager,
+                                                                   nsDisplayItem* aItem,
                                                                    nsStyleContext *aBackgroundSC,
                                                                    const nsStyleBorder& aBorder)
 {
-  MOZ_ASSERT(CanBuildWebRenderDisplayItemsForStyleImageLayer(aLayer->WrManager(),
-                                                             aParams.presCtx,
-                                                             aParams.frame,
-                                                             aBackgroundSC->StyleBackground(),
-                                                             aParams.layer));
-
   MOZ_ASSERT(!(aParams.paintFlags & PAINTBG_MASK_IMAGE));
 
   nscoord appUnitsPerPixel = aParams.presCtx.AppUnitsPerDevPixel();
   ImageLayerClipState clipState;
 
   clipState.mBGClipArea = *aParams.bgClipRect;
   clipState.mCustomClip = true;
   clipState.mHasRoundedCorners = false;
@@ -2783,17 +2781,18 @@ nsCSSRendering::BuildWebRenderDisplayIte
   DrawResult result = DrawResult::SUCCESS;
   nsBackgroundLayerState state =
     PrepareImageLayer(&aParams.presCtx, aParams.frame,
                       aParams.paintFlags, paintBorderArea,
                       clipState.mBGClipArea, layer, nullptr);
   result &= state.mImageRenderer.PrepareResult();
   if (!state.mFillArea.IsEmpty()) {
     return state.mImageRenderer.BuildWebRenderDisplayItemsForLayer(&aParams.presCtx,
-                                     aBuilder, aSc, aParentCommands, aLayer,
+                                     aBuilder, aSc, aParentCommands,
+                                     aLayer, aManager, aItem,
                                      state.mDestArea, state.mFillArea,
                                      state.mAnchor + paintBorderArea.TopLeft(),
                                      clipState.mDirtyRectInAppUnits,
                                      state.mRepeatSize, aParams.opacity);
   }
 
   return result;
 }
--- a/layout/painting/nsCSSRendering.h
+++ b/layout/painting/nsCSSRendering.h
@@ -498,23 +498,27 @@ struct nsCSSRendering {
                                                               nsPresContext& aPresCtx,
                                                               nsIFrame *aFrame,
                                                               const nsStyleBackground* aBackgroundStyle,
                                                               int32_t aLayer);
   static DrawResult BuildWebRenderDisplayItemsForStyleImageLayer(const PaintBGParams& aParams,
                                                                  mozilla::wr::DisplayListBuilder& aBuilder,
                                                                  const mozilla::layers::StackingContextHelper& aSc,
                                                                  nsTArray<mozilla::layers::WebRenderParentCommand>& aParentCommands,
-                                                                 mozilla::layers::WebRenderDisplayItemLayer* aLayer);
+                                                                 mozilla::layers::WebRenderDisplayItemLayer* aLayer,
+                                                                 mozilla::layers::WebRenderLayerManager* aManager,
+                                                                 nsDisplayItem* aItem);
 
   static DrawResult BuildWebRenderDisplayItemsForStyleImageLayerWithSC(const PaintBGParams& aParams,
                                                                        mozilla::wr::DisplayListBuilder& aBuilder,
                                                                        const mozilla::layers::StackingContextHelper& aSc,
                                                                        nsTArray<mozilla::layers::WebRenderParentCommand>& aParentCommands,
                                                                        mozilla::layers::WebRenderDisplayItemLayer* aLayer,
+                                                                       mozilla::layers::WebRenderLayerManager* aManager,
+                                                                       nsDisplayItem* aItem,
                                                                        nsStyleContext *mBackgroundSC,
                                                                        const nsStyleBorder& aBorder);
 
   /**
    * Returns the rectangle covered by the given background layer image, taking
    * into account background positioning, sizing, and repetition, but not
    * clipping.
    */
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -3524,31 +3524,63 @@ nsDisplayBackgroundImage::CanBuildWebRen
   return mBackgroundStyle->mImage.mLayers[mLayer].mClip != StyleGeometryBox::Text &&
          nsCSSRendering::CanBuildWebRenderDisplayItemsForStyleImageLayer(aManager,
                                                                          *StyleFrame()->PresContext(),
                                                                          StyleFrame(),
                                                                          mBackgroundStyle,
                                                                          mLayer);
 }
 
+bool
+nsDisplayBackgroundImage::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
+                                                  const StackingContextHelper& aSc,
+                                                  nsTArray<WebRenderParentCommand>& aParentCommands,
+                                                  WebRenderLayerManager* aManager,
+                                                  nsDisplayListBuilder* aDisplayListBuilder)
+{
+  if (!CanBuildWebRenderDisplayItems(aManager)) {
+    return false;
+  }
+
+  mImageFlags = aDisplayListBuilder->GetBackgroundPaintFlags();
+  CheckForBorderItem(this, mImageFlags);
+  nsCSSRendering::PaintBGParams params =
+    nsCSSRendering::PaintBGParams::ForSingleLayer(*StyleFrame()->PresContext(),
+                                                  mVisibleRect, mBackgroundRect,
+                                                  StyleFrame(), mImageFlags, mLayer,
+                                                  CompositionOp::OP_OVER);
+  params.bgClipRect = &mBounds;
+  DrawResult result =
+    nsCSSRendering::BuildWebRenderDisplayItemsForStyleImageLayer(params, aBuilder, aSc, aParentCommands, nullptr, aManager, this);
+  nsDisplayBackgroundGeometry::UpdateDrawResult(this, result);
+
+  return true;
+}
+
 void
 nsDisplayBackgroundImage::CreateWebRenderCommands(wr::DisplayListBuilder& aBuilder,
                                                   const StackingContextHelper& aSc,
                                                   nsTArray<WebRenderParentCommand>& aParentCommands,
                                                   WebRenderDisplayItemLayer* aLayer)
 {
   nsCSSRendering::PaintBGParams params =
     nsCSSRendering::PaintBGParams::ForSingleLayer(*StyleFrame()->PresContext(),
                                                   mVisibleRect, mBackgroundRect,
                                                   StyleFrame(), mImageFlags, mLayer,
                                                   CompositionOp::OP_OVER);
   params.bgClipRect = &mBounds;
 
   DrawResult result =
-    nsCSSRendering::BuildWebRenderDisplayItemsForStyleImageLayer(params, aBuilder, aSc, aParentCommands, aLayer);
+    nsCSSRendering::BuildWebRenderDisplayItemsForStyleImageLayer(params,
+                                                                 aBuilder,
+                                                                 aSc,
+                                                                 aParentCommands,
+                                                                 aLayer,
+                                                                 aLayer->WrManager(),
+                                                                 this);
 
   nsDisplayBackgroundGeometry::UpdateDrawResult(this, result);
 }
 
 void
 nsDisplayBackgroundImage::HitTest(nsDisplayListBuilder* aBuilder,
                                   const nsRect& aRect,
                                   HitTestState* aState,
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -3124,17 +3124,21 @@ public:
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aContainerParameters) override;
 
   virtual void CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                        const StackingContextHelper& aSc,
                                        nsTArray<WebRenderParentCommand>& aParentCommands,
                                        WebRenderDisplayItemLayer* aLayer) override;
-
+  virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
+                                       const StackingContextHelper& aSc,
+                                       nsTArray<WebRenderParentCommand>& aParentCommands,
+                                       mozilla::layers::WebRenderLayerManager* aManager,
+                                       nsDisplayListBuilder* aDisplayListBuilder) override;
   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                        HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) override;
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                  nsRegion* aVisibleRegion) override;
   virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
                                    bool* aSnap) override;
   virtual mozilla::Maybe<nscolor> IsUniform(nsDisplayListBuilder* aBuilder) override;
   /**
--- a/layout/painting/nsImageRenderer.cpp
+++ b/layout/painting/nsImageRenderer.cpp
@@ -17,16 +17,17 @@
 #include "nsContentUtils.h"
 #include "nsCSSRendering.h"
 #include "nsCSSRenderingGradients.h"
 #include "nsIFrame.h"
 #include "nsStyleStructInlines.h"
 #include "nsSVGDisplayableFrame.h"
 #include "nsSVGEffects.h"
 #include "nsSVGIntegrationUtils.h"
+#include "ImageContainer.h"
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 using namespace mozilla::image;
 using namespace mozilla::layers;
 
 nsSize
 CSSSizeOrRatio::ComputeConcreteSize() const
@@ -585,16 +586,18 @@ nsImageRenderer::Draw(nsPresContext*    
 }
 
 DrawResult
 nsImageRenderer::BuildWebRenderDisplayItems(nsPresContext*       aPresContext,
                                             mozilla::wr::DisplayListBuilder&            aBuilder,
                                             const mozilla::layers::StackingContextHelper& aSc,
                                             nsTArray<WebRenderParentCommand>&           aParentCommands,
                                             mozilla::layers::WebRenderDisplayItemLayer* aLayer,
+                                            mozilla::layers::WebRenderLayerManager* aManager,
+                                            nsDisplayItem*       aItem,
                                             const nsRect&        aDirtyRect,
                                             const nsRect&        aDest,
                                             const nsRect&        aFill,
                                             const nsPoint&       aAnchor,
                                             const nsSize&        aRepeatSize,
                                             const CSSIntRect&    aSrc,
                                             float                aOpacity)
 {
@@ -619,23 +622,27 @@ nsImageRenderer::BuildWebRenderDisplayIt
     case eStyleImageType_Image:
     {
       // XXX(aosmond): We will support downscale-on-decode in bug 1368776. Until
       // then, don't pass FLAG_HIGH_QUALITY_SCALING.
       uint32_t containerFlags = imgIContainer::FLAG_NONE;
       if (mFlags & nsImageRenderer::FLAG_SYNC_DECODE_IMAGES) {
         containerFlags |= imgIContainer::FLAG_SYNC_DECODE;
       }
-      RefPtr<layers::ImageContainer> container = mImageContainer->GetImageContainer(aLayer->WrManager(),
+      RefPtr<layers::ImageContainer> container = mImageContainer->GetImageContainer(aManager,
                                                                                     containerFlags);
+      container = mImageContainer->GetImageContainer(aManager, containerFlags);
       if (!container) {
         NS_WARNING("Failed to get image container");
         return DrawResult::NOT_READY;
       }
-      Maybe<wr::ImageKey> key = aLayer->SendImageContainer(container, aParentCommands);
+
+      gfx::IntSize size;
+      Maybe<wr::ImageKey> key = aManager->CreateImageKey(aItem, container, aBuilder, aSc, size);
+
       if (key.isNothing()) {
         return DrawResult::BAD_IMAGE;
       }
 
       const int32_t appUnitsPerDevPixel = mForFrame->PresContext()->AppUnitsPerDevPixel();
       LayoutDeviceRect destRect = LayoutDeviceRect::FromAppUnits(
           aDest, appUnitsPerDevPixel);
 
@@ -725,33 +732,35 @@ nsImageRenderer::DrawLayer(nsPresContext
 }
 
 DrawResult
 nsImageRenderer::BuildWebRenderDisplayItemsForLayer(nsPresContext*       aPresContext,
                                                     mozilla::wr::DisplayListBuilder& aBuilder,
                                                     const mozilla::layers::StackingContextHelper& aSc,
                                                     nsTArray<WebRenderParentCommand>& aParentCommands,
                                                     WebRenderDisplayItemLayer*       aLayer,
+                                                    mozilla::layers::WebRenderLayerManager* aManager,
+                                                    nsDisplayItem*       aItem,
                                                     const nsRect&        aDest,
                                                     const nsRect&        aFill,
                                                     const nsPoint&       aAnchor,
                                                     const nsRect&        aDirty,
                                                     const nsSize&        aRepeatSize,
                                                     float                aOpacity)
 {
   if (!IsReady()) {
     NS_NOTREACHED("Ensure PrepareImage() has returned true before calling me");
     return mPrepareResult;
   }
   if (aDest.IsEmpty() || aFill.IsEmpty() ||
       mSize.width <= 0 || mSize.height <= 0) {
     return DrawResult::SUCCESS;
   }
-
-  return BuildWebRenderDisplayItems(aPresContext, aBuilder, aSc, aParentCommands, aLayer,
+  return BuildWebRenderDisplayItems(aPresContext, aBuilder, aSc, aParentCommands,
+                                    aLayer, aManager, aItem,
                                     aDirty, aDest, aFill, aAnchor, aRepeatSize,
                                     CSSIntRect(0, 0,
                                                nsPresContext::AppUnitsToIntCSSPixels(mSize.width),
                                                nsPresContext::AppUnitsToIntCSSPixels(mSize.height)),
                                     aOpacity);
 }
 
 /**
--- a/layout/painting/nsImageRenderer.h
+++ b/layout/painting/nsImageRenderer.h
@@ -12,16 +12,17 @@
 
 class gfxDrawable;
 namespace mozilla {
 
 namespace layers {
 class StackingContextHelper;
 class WebRenderParentCommand;
 class WebRenderDisplayItemLayer;
+class WebRenderLayerManager;
 } // namespace layers
 
 namespace wr {
 class DisplayListBuilder;
 } // namespace wr
 
 // A CSSSizeOrRatio represents a (possibly partially specified) size for use
 // in computing image sizes. Either or both of the width and height might be
@@ -207,16 +208,18 @@ public:
    * {background|mask}-specific arguments.
    * @see nsLayoutUtils::DrawImage() for parameters.
    */
   DrawResult BuildWebRenderDisplayItemsForLayer(nsPresContext*       aPresContext,
                                                 mozilla::wr::DisplayListBuilder& aBuilder,
                                                 const mozilla::layers::StackingContextHelper& aSc,
                                                 nsTArray<layers::WebRenderParentCommand>& aParentCommands,
                                                 mozilla::layers::WebRenderDisplayItemLayer* aLayer,
+                                                mozilla::layers::WebRenderLayerManager* aManager,
+                                                nsDisplayItem*       aItem,
                                                 const nsRect&        aDest,
                                                 const nsRect&        aFill,
                                                 const nsPoint&       aAnchor,
                                                 const nsRect&        aDirty,
                                                 const nsSize&        aRepeatSize,
                                                 float                aOpacity);
 
   /**
@@ -292,16 +295,18 @@ private:
    *
    * @see nsLayoutUtils::DrawImage() for other parameters.
    */
   DrawResult BuildWebRenderDisplayItems(nsPresContext*       aPresContext,
                                         mozilla::wr::DisplayListBuilder& aBuilder,
                                         const mozilla::layers::StackingContextHelper& aSc,
                                         nsTArray<layers::WebRenderParentCommand>& aParentCommands,
                                         mozilla::layers::WebRenderDisplayItemLayer* aLayer,
+                                        mozilla::layers::WebRenderLayerManager* aManager,
+                                        nsDisplayItem*       aItem,
                                         const nsRect&        aDirtyRect,
                                         const nsRect&        aDest,
                                         const nsRect&        aFill,
                                         const nsPoint&       aAnchor,
                                         const nsSize&        aRepeatSize,
                                         const mozilla::CSSIntRect& aSrc,
                                         float                aOpacity = 1.0);