Bug 1446309 - Part 3. Properly handle ImgDrawResult for WebRender display list generation. r=tnikkel
authorAndrew Osmond <aosmond@mozilla.com>
Thu, 13 Sep 2018 19:48:27 -0400
changeset 436292 86b053d526320d97f3457c7796c3e4143f568b66
parent 436291 2ca405997ed545fb13d1a9618f15a1192345e828
child 436293 314994bc7f3f7de359818616dc96f6840a6e6c35
push id34633
push usernerli@mozilla.com
push dateFri, 14 Sep 2018 03:31:50 +0000
treeherdermozilla-central@82e36ec6b2bd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstnikkel
bugs1446309
milestone64.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 1446309 - Part 3. Properly handle ImgDrawResult for WebRender display list generation. r=tnikkel When generating display lists for WebRender, we were not caching the draw result via nsDisplayItemGenericImageGeometry::UpdateDrawResult (or similar) after completing CreateWebRenderCommands. This is important because reftests use this to force sync decoding for images; it may be a reason for image-related intermittent failures on *-qr builds. Additionally, we may have been requesting fallback in cases where fallback could not do anything more than WebRender could. For example, if we can't get an image container yet, there is no point in requesting fallback because it might just be we haven't started decoding yet. We should just return the actual draw result in such cases.
image/ImgDrawResult.h
image/RasterImage.cpp
image/test/gtest/TestContainers.cpp
layout/forms/nsFieldSetFrame.cpp
layout/generic/nsBulletFrame.cpp
layout/generic/nsImageFrame.cpp
layout/painting/nsCSSRendering.cpp
layout/painting/nsCSSRendering.h
layout/painting/nsCSSRenderingBorders.cpp
layout/painting/nsCSSRenderingBorders.h
layout/painting/nsDisplayList.cpp
layout/painting/nsDisplayListInvalidation.h
layout/painting/nsImageRenderer.cpp
layout/xul/nsImageBoxFrame.cpp
layout/xul/nsImageBoxFrame.h
--- a/image/ImgDrawResult.h
+++ b/image/ImgDrawResult.h
@@ -78,16 +78,21 @@ enum class MOZ_MUST_USE_TYPE ImgDrawResu
  */
 inline ImgDrawResult
 operator&(const ImgDrawResult aLeft, const ImgDrawResult aRight)
 {
   if (MOZ_LIKELY(aLeft == ImgDrawResult::SUCCESS)) {
     return aRight;
   }
 
+  if (aLeft == ImgDrawResult::NOT_SUPPORTED ||
+      aRight == ImgDrawResult::NOT_SUPPORTED) {
+    return ImgDrawResult::NOT_SUPPORTED;
+  }
+
   if ((aLeft == ImgDrawResult::BAD_IMAGE ||
        aLeft == ImgDrawResult::SUCCESS_NOT_COMPLETE) &&
       aRight != ImgDrawResult::SUCCESS &&
       aRight != ImgDrawResult::SUCCESS_NOT_COMPLETE) {
     return aRight;
   }
   return aLeft;
 }
--- a/image/RasterImage.cpp
+++ b/image/RasterImage.cpp
@@ -665,16 +665,20 @@ RasterImage::IsImageContainerAvailable(L
 
 NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
 RasterImage::GetImageContainer(LayerManager* aManager, uint32_t aFlags)
 {
   RefPtr<ImageContainer> container;
   ImgDrawResult drawResult =
     GetImageContainerImpl(aManager, mSize, Nothing(), aFlags,
                           getter_AddRefs(container));
+
+  // We silence the unused warning here because anything that needs the draw
+  // result should be using GetImageContainerAtSize, not GetImageContainer.
+  (void)drawResult;
   return container.forget();
 }
 
 NS_IMETHODIMP_(bool)
 RasterImage::IsImageContainerAvailableAtSize(LayerManager* aManager,
                                              const IntSize& aSize,
                                              uint32_t aFlags)
 {
--- a/image/test/gtest/TestContainers.cpp
+++ b/image/test/gtest/TestContainers.cpp
@@ -73,37 +73,41 @@ TEST_F(ImageContainers, RasterImageConta
   requestedSize.Scale(2, 2);
   RefPtr<layers::ImageContainer> upscaleContainer;
   drawResult = image->GetImageContainerAtSize(layerManager,
                                               requestedSize,
                                               Nothing(),
                                               imgIContainer::FLAG_SYNC_DECODE |
                                               imgIContainer::FLAG_HIGH_QUALITY_SCALING,
                                               getter_AddRefs(upscaleContainer));
+  EXPECT_EQ(drawResult, ImgDrawResult::SUCCESS);
   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;
   drawResult = image->GetImageContainerAtSize(layerManager,
                                               requestedSize,
                                               Nothing(),
                                               imgIContainer::FLAG_SYNC_DECODE |
                                               imgIContainer::FLAG_HIGH_QUALITY_SCALING,
                                               getter_AddRefs(downscaleContainer));
+  EXPECT_EQ(drawResult, ImgDrawResult::SUCCESS);
+  ASSERT_TRUE(downscaleContainer != nullptr);
   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;
   drawResult = image->GetImageContainerAtSize(layerManager,
                                               testCase.mSize,
                                               Nothing(),
                                               imgIContainer::FLAG_SYNC_DECODE,
                                               getter_AddRefs(againContainer));
+  EXPECT_EQ(drawResult, ImgDrawResult::SUCCESS);
   ASSERT_EQ(nativeContainer.get(), againContainer.get());
 }
--- a/layout/forms/nsFieldSetFrame.cpp
+++ b/layout/forms/nsFieldSetFrame.cpp
@@ -172,24 +172,31 @@ nsDisplayFieldSetBorder::CreateWebRender
     nsRect legendRect = legend->GetNormalRect() + offset;
     if (!legendRect.IsEmpty()) {
       return false;
     }
   } else {
     rect = nsRect(offset, frame->GetRect().Size());
   }
 
-  return nsCSSRendering::CreateWebRenderCommandsForBorder(this,
-                                                          mFrame,
-                                                          rect,
-                                                          aBuilder,
-                                                          aResources,
-                                                          aSc,
-                                                          aManager,
-                                                          aDisplayListBuilder);
+  ImgDrawResult drawResult =
+    nsCSSRendering::CreateWebRenderCommandsForBorder(this,
+                                                     mFrame,
+                                                     rect,
+                                                     aBuilder,
+                                                     aResources,
+                                                     aSc,
+                                                     aManager,
+                                                     aDisplayListBuilder);
+  if (drawResult == ImgDrawResult::NOT_SUPPORTED) {
+    return false;
+  }
+
+  nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, drawResult);
+  return true;
 };
 
 void
 nsFieldSetFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                   const nsDisplayListSet& aLists) {
   // Paint our background and border in a special way.
   // REVIEW: We don't really need to check frame emptiness here; if it's empty,
   // the background/border display item won't do anything, and if it isn't empty,
--- a/layout/generic/nsBulletFrame.cpp
+++ b/layout/generic/nsBulletFrame.cpp
@@ -236,17 +236,17 @@ public:
     , mText(text)
     , mFontMetrics(fm)
     , mPoint(point)
     , mListStyleType(listStyleType)
   {
     MOZ_ASSERT(IsTextType());
   }
 
-  bool
+  ImgDrawResult
   CreateWebRenderCommands(nsDisplayItem* aItem,
                           wr::DisplayListBuilder& aBuilder,
                           wr::IpcResourceUpdateQueue& aResources,
                           const layers::StackingContextHelper& aSc,
                           mozilla::layers::WebRenderLayerManager* aManager,
                           nsDisplayListBuilder* aDisplayListBuilder);
 
   ImgDrawResult
@@ -286,17 +286,17 @@ public:
   PaintTextToContext(nsIFrame* aFrame,
                      gfxContext* aCtx,
                      bool aDisableSubpixelAA);
 
   bool
   IsImageContainerAvailable(layers::LayerManager* aManager, uint32_t aFlags);
 
 private:
-  bool
+  ImgDrawResult
   CreateWebRenderCommandsForImage(nsDisplayItem* aItem,
                                   wr::DisplayListBuilder& aBuilder,
                                   wr::IpcResourceUpdateQueue& aResources,
                                   const layers::StackingContextHelper& aSc,
                                   mozilla::layers::WebRenderLayerManager* aManager,
                                   nsDisplayListBuilder* aDisplayListBuilder);
 
   bool
@@ -344,35 +344,40 @@ private:
   nsPoint mPoint;
   RefPtr<ScaledFont> mFont;
   nsTArray<layers::GlyphArray> mGlyphs;
 
   // Store the type of list-style-type.
   int32_t mListStyleType;
 };
 
-bool
+ImgDrawResult
 BulletRenderer::CreateWebRenderCommands(nsDisplayItem* aItem,
                                         wr::DisplayListBuilder& aBuilder,
                                         wr::IpcResourceUpdateQueue& aResources,
                                         const layers::StackingContextHelper& aSc,
                                         mozilla::layers::WebRenderLayerManager* aManager,
                                         nsDisplayListBuilder* aDisplayListBuilder)
 {
   if (IsImageType()) {
     return CreateWebRenderCommandsForImage(aItem, aBuilder, aResources,
                                     aSc, aManager, aDisplayListBuilder);
-  } else if (IsPathType()) {
-    return CreateWebRenderCommandsForPath(aItem, aBuilder, aResources,
-                                   aSc, aManager, aDisplayListBuilder);
+  }
+
+  bool success;
+  if (IsPathType()) {
+    success = CreateWebRenderCommandsForPath(aItem, aBuilder, aResources, aSc,
+                                             aManager, aDisplayListBuilder);
   } else {
     MOZ_ASSERT(IsTextType());
-    return CreateWebRenderCommandsForText(aItem, aBuilder, aResources, aSc,
-                                          aManager, aDisplayListBuilder);
+    success = CreateWebRenderCommandsForText(aItem, aBuilder, aResources, aSc,
+                                             aManager, aDisplayListBuilder);
   }
+
+  return success ? ImgDrawResult::SUCCESS : ImgDrawResult::NOT_SUPPORTED;
 }
 
 ImgDrawResult
 BulletRenderer::Paint(gfxContext& aRenderingContext, nsPoint aPt,
                       const nsRect& aDirtyRect, uint32_t aFlags,
                       bool aDisableSubpixelAA, nsIFrame* aFrame)
 {
   if (IsImageType()) {
@@ -449,17 +454,17 @@ BulletRenderer::PaintTextToContext(nsIFr
 bool
 BulletRenderer::IsImageContainerAvailable(layers::LayerManager* aManager, uint32_t aFlags)
 {
   MOZ_ASSERT(IsImageType());
 
   return mImage->IsImageContainerAvailable(aManager, aFlags);
 }
 
-bool
+ImgDrawResult
 BulletRenderer::CreateWebRenderCommandsForImage(nsDisplayItem* aItem,
                                                 wr::DisplayListBuilder& aBuilder,
                                                 wr::IpcResourceUpdateQueue& aResources,
                                                 const layers::StackingContextHelper& aSc,
                                                 mozilla::layers::WebRenderLayerManager* aManager,
                                                 nsDisplayListBuilder* aDisplayListBuilder)
 {
   MOZ_RELEASE_ASSERT(IsImageType());
@@ -476,37 +481,38 @@ BulletRenderer::CreateWebRenderCommandsF
   const int32_t appUnitsPerDevPixel = aItem->Frame()->PresContext()->AppUnitsPerDevPixel();
   LayoutDeviceRect destRect = LayoutDeviceRect::FromAppUnits(mDest, appUnitsPerDevPixel);
   Maybe<SVGImageContext> svgContext;
   gfx::IntSize decodeSize =
     nsLayoutUtils::ComputeImageContainerDrawingParameters(mImage, aItem->Frame(), destRect,
                                                           aSc, flags, svgContext);
 
   RefPtr<layers::ImageContainer> container;
-  mImage->GetImageContainerAtSize(aManager, decodeSize, svgContext,
-                                  flags, getter_AddRefs(container));
+  ImgDrawResult drawResult =
+    mImage->GetImageContainerAtSize(aManager, decodeSize, svgContext,
+                                    flags, getter_AddRefs(container));
   if (!container) {
-    return false;
+    return drawResult;
   }
 
   mozilla::wr::ImageRendering rendering = wr::ToImageRendering(
     nsLayoutUtils::GetSamplingFilterForFrame(aItem->Frame()));
   gfx::IntSize size;
   Maybe<wr::ImageKey> key = aManager->CommandBuilder().CreateImageKey(
     aItem, container, aBuilder, aResources, rendering, aSc, size, Nothing());
   if (key.isNothing()) {
-    return true;  // Nothing to do
+    return drawResult;
   }
 
   wr::LayoutRect dest = wr::ToRoundedLayoutRect(destRect);
 
   aBuilder.PushImage(
     dest, dest, !aItem->BackfaceIsHidden(), rendering, key.value());
 
-  return true;
+  return drawResult;
 }
 
 bool
 BulletRenderer::CreateWebRenderCommandsForPath(nsDisplayItem* aItem,
                                                wr::DisplayListBuilder& aBuilder,
                                                wr::IpcResourceUpdateQueue& aResources,
                                                const layers::StackingContextHelper& aSc,
                                                mozilla::layers::WebRenderLayerManager* aManager,
@@ -662,18 +668,25 @@ nsDisplayBullet::CreateWebRenderCommands
     gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget().get());
   Maybe<BulletRenderer> br = static_cast<nsBulletFrame*>(mFrame)->
     CreateBulletRenderer(*screenRefCtx, ToReferenceFrame());
 
   if (!br) {
     return false;
   }
 
-  return br->CreateWebRenderCommands(this, aBuilder, aResources, aSc,
-                                     aManager, aDisplayListBuilder);
+  ImgDrawResult drawResult =
+    br->CreateWebRenderCommands(this, aBuilder, aResources, aSc,
+                                aManager, aDisplayListBuilder);
+  if (drawResult == ImgDrawResult::NOT_SUPPORTED) {
+    return false;
+  }
+
+  nsDisplayBulletGeometry::UpdateDrawResult(this, drawResult);
+  return true;
 }
 
 void nsDisplayBullet::Paint(nsDisplayListBuilder* aBuilder,
                             gfxContext* aCtx)
 {
   uint32_t flags = imgIContainer::FLAG_NONE;
   if (aBuilder->ShouldSyncDecodeImages()) {
     flags |= imgIContainer::FLAG_SYNC_DECODE;
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -1837,40 +1837,42 @@ nsDisplayImage::CreateWebRenderCommands(
           container = std::move(prevContainer);
           break;
         }
 
         // Previous image was unusable; we can forget about it.
         updatePrevImage = true;
       }
       break;
+    case ImgDrawResult::NOT_SUPPORTED:
+      return false;
     default:
       updatePrevImage = mPrevImage != mImage;
       break;
   }
 
   // The previous image was not used, and is different from the current image.
   // We should forget about it. We need to update the frame as well because the
   // display item may get recreated.
   if (updatePrevImage) {
     mPrevImage = mImage;
     if (mFrame->IsImageFrame()) {
       nsImageFrame* f = static_cast<nsImageFrame*>(mFrame);
       f->mPrevImage = f->mImage;
     }
   }
 
-  if (!container) {
-    return false;
-  }
-
   // If the image container is empty, we don't want to fallback. Any other
   // failure will be due to resource constraints and fallback is unlikely to
   // help us. Hence we can ignore the return value from PushImage.
-  aManager->CommandBuilder().PushImage(this, container, aBuilder, aResources, aSc, destRect);
+  if (container) {
+    aManager->CommandBuilder().PushImage(this, container, aBuilder, aResources, aSc, destRect);
+  }
+
+  nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, drawResult);
   return true;
 }
 
 ImgDrawResult
 nsImageFrame::PaintImage(gfxContext& aRenderingContext, nsPoint aPt,
                          const nsRect& aDirtyRect, imgIContainer* aImage,
                          uint32_t aFlags)
 {
--- a/layout/painting/nsCSSRendering.cpp
+++ b/layout/painting/nsCSSRendering.cpp
@@ -754,17 +754,17 @@ nsCSSRendering::CreateBorderRenderer(nsP
                                              aDirtyRect,
                                              aBorderArea,
                                              newStyleBorder,
                                              aComputedStyle,
                                              aOutBorderIsEmpty,
                                              aSkipSides);
 }
 
-bool
+ImgDrawResult
 nsCSSRendering::CreateWebRenderCommandsForBorder(
   nsDisplayItem* aItem,
   nsIFrame* aForFrame,
   const nsRect& aBorderArea,
   mozilla::wr::DisplayListBuilder& aBuilder,
   mozilla::wr::IpcResourceUpdateQueue& aResources,
   const mozilla::layers::StackingContextHelper& aSc,
   mozilla::layers::WebRenderLayerManager* aManager,
@@ -778,48 +778,48 @@ nsCSSRendering::CreateWebRenderCommandsF
                                            nullptr,
                                            aForFrame,
                                            nsRect(),
                                            aBorderArea,
                                            aForFrame->Style(),
                                            &borderIsEmpty,
                                            aForFrame->GetSkipSides());
     if (borderIsEmpty) {
-      return true;
+      return ImgDrawResult::SUCCESS;
     }
 
     if (br) {
       br->CreateWebRenderCommands(aItem, aBuilder, aResources, aSc);
-      return true;
+      return ImgDrawResult::SUCCESS;
     }
   }
 
   // Next try to draw an image border
   const nsStyleBorder* styleBorder = aForFrame->Style()->StyleBorder();
   const nsStyleImage* image = &styleBorder->mBorderImageSource;
 
   // Filter out unsupported image/border types
   if (!image) {
-    return false;
+    return ImgDrawResult::NOT_SUPPORTED;
   }
 
   // All this code bitrotted too much (but is almost right); disabled for now.
   bool imageTypeSupported = false;
   // FIXME(1409773): fix this: image->GetType() == eStyleImageType_Image
   // FIXME(1409774): fix this: image->GetType() == eStyleImageType_Gradient;
 
   if (!imageTypeSupported) {
-    return false;
+    return ImgDrawResult::NOT_SUPPORTED;
   }
 
   if (styleBorder->mBorderImageRepeatH == StyleBorderImageRepeat::Round ||
       styleBorder->mBorderImageRepeatH == StyleBorderImageRepeat::Space ||
       styleBorder->mBorderImageRepeatV == StyleBorderImageRepeat::Round ||
       styleBorder->mBorderImageRepeatV == StyleBorderImageRepeat::Space) {
-    return false;
+    return ImgDrawResult::NOT_SUPPORTED;
   }
 
   uint32_t flags = 0;
   if (aDisplayListBuilder->ShouldSyncDecodeImages()) {
     flags |= nsImageRenderer::FLAG_SYNC_DECODE_IMAGES;
   }
 
   image::ImgDrawResult result;
@@ -830,28 +830,21 @@ nsCSSRendering::CreateWebRenderCommandsF
       aBorderArea,
       *styleBorder,
       aItem->GetPaintRect(),
       aForFrame->GetSkipSides(),
       flags,
       &result);
 
   if (!bir) {
-    return false;
+    return result;
   }
 
-  if (image->GetType() == eStyleImageType_Image &&
-      !bir->mImageRenderer.IsImageContainerAvailable(aManager, flags)) {
-    return false;
-  }
-
-  bir->CreateWebRenderCommands(
+  return bir->CreateWebRenderCommands(
     aItem, aForFrame, aBuilder, aResources, aSc, aManager, aDisplayListBuilder);
-
-  return true;
 }
 
 static nsCSSBorderRenderer
 ConstructBorderRenderer(nsPresContext* aPresContext,
                         ComputedStyle* aComputedStyle,
                         DrawTarget* aDrawTarget,
                         nsIFrame* aForFrame,
                         const nsRect& aDirtyRect,
--- a/layout/painting/nsCSSRendering.h
+++ b/layout/painting/nsCSSRendering.h
@@ -228,17 +228,17 @@ struct nsCSSRendering
   static mozilla::Maybe<nsCSSBorderRenderer> CreateBorderRendererForOutline(
     nsPresContext* aPresContext,
     gfxContext* aRenderingContext,
     nsIFrame* aForFrame,
     const nsRect& aDirtyRect,
     const nsRect& aBorderArea,
     mozilla::ComputedStyle* aComputedStyle);
 
-  static bool CreateWebRenderCommandsForBorder(
+  static ImgDrawResult CreateWebRenderCommandsForBorder(
     nsDisplayItem* aItem,
     nsIFrame* aForFrame,
     const nsRect& aBorderArea,
     mozilla::wr::DisplayListBuilder& aBuilder,
     mozilla::wr::IpcResourceUpdateQueue& aResources,
     const mozilla::layers::StackingContextHelper& aSc,
     mozilla::layers::WebRenderLayerManager* aManager,
     nsDisplayListBuilder* aDisplayListBuilder);
--- a/layout/painting/nsCSSRenderingBorders.cpp
+++ b/layout/painting/nsCSSRenderingBorders.cpp
@@ -3796,28 +3796,28 @@ nsCSSBorderImageRenderer::DrawBorderImag
         svgViewportSize,
         hasIntrinsicRatio);
     }
   }
 
   return result;
 }
 
-void
+ImgDrawResult
 nsCSSBorderImageRenderer::CreateWebRenderCommands(
   nsDisplayItem* aItem,
   nsIFrame* aForFrame,
   mozilla::wr::DisplayListBuilder& aBuilder,
   mozilla::wr::IpcResourceUpdateQueue& aResources,
   const mozilla::layers::StackingContextHelper& aSc,
   mozilla::layers::WebRenderLayerManager* aManager,
   nsDisplayListBuilder* aDisplayListBuilder)
 {
   if (!mImageRenderer.IsReady()) {
-    return;
+    return ImgDrawResult::NOT_READY;
   }
 
   float widths[4];
   float slice[4];
   float outset[4];
   const int32_t appUnitsPerDevPixel =
     aForFrame->PresContext()->AppUnitsPerDevPixel();
   NS_FOR_CSS_SIDES(i)
@@ -3833,16 +3833,17 @@ nsCSSBorderImageRenderer::CreateWebRende
 
   wr::LayoutRect clip = dest;
   if (!mClip.IsEmpty()) {
     LayoutDeviceRect clipRect =
       LayoutDeviceRect::FromAppUnits(mClip, appUnitsPerDevPixel);
     clip = wr::ToRoundedLayoutRect(clipRect);
   }
 
+  ImgDrawResult drawResult = ImgDrawResult::SUCCESS;
   switch (mImageRenderer.GetType()) {
     case eStyleImageType_Image: {
       uint32_t flags = imgIContainer::FLAG_ASYNC_NOTIFY;
       if (aDisplayListBuilder->IsPaintingToWindow()) {
         flags |= imgIContainer::FLAG_HIGH_QUALITY_SCALING;
       }
       if (aDisplayListBuilder->ShouldSyncDecodeImages()) {
         flags |= imgIContainer::FLAG_SYNC_DECODE;
@@ -3850,36 +3851,36 @@ nsCSSBorderImageRenderer::CreateWebRende
 
       RefPtr<imgIContainer> img = mImageRenderer.GetImage();
       Maybe<SVGImageContext> svgContext;
       gfx::IntSize decodeSize =
         nsLayoutUtils::ComputeImageContainerDrawingParameters(
           img, aForFrame, destRect, aSc, flags, svgContext);
 
       RefPtr<layers::ImageContainer> container;
-      img->GetImageContainerAtSize(aManager, decodeSize, svgContext,
-                                   flags, getter_AddRefs(container));
+      drawResult = img->GetImageContainerAtSize(aManager, decodeSize, svgContext,
+                                                flags, getter_AddRefs(container));
       if (!container) {
-        return;
+        break;
       }
 
       mozilla::wr::ImageRendering rendering = wr::ToImageRendering(
         nsLayoutUtils::GetSamplingFilterForFrame(aItem->Frame()));
       gfx::IntSize size;
       Maybe<wr::ImageKey> key =
         aManager->CommandBuilder().CreateImageKey(aItem,
                                                   container,
                                                   aBuilder,
                                                   aResources,
                                                   rendering,
                                                   aSc,
                                                   size,
                                                   Nothing());
       if (key.isNothing()) {
-        return;
+        break;
       }
 
       aBuilder.PushBorderImage(
         dest,
         clip,
         !aItem->BackfaceIsHidden(),
         wr::ToBorderWidths(widths[0], widths[1], widths[2], widths[3]),
         key.value(),
@@ -3934,17 +3935,20 @@ nsCSSBorderImageRenderer::CreateWebRende
           stops,
           extendMode,
           wr::ToSideOffsets2D_f32(outset[0], outset[1], outset[2], outset[3]));
       }
       break;
     }
     default:
       MOZ_ASSERT_UNREACHABLE("Unsupport border image type");
+      drawResult = ImgDrawResult::NOT_SUPPORTED;
   }
+
+  return drawResult;
 }
 
 nsCSSBorderImageRenderer::nsCSSBorderImageRenderer(
   const nsCSSBorderImageRenderer& aRhs)
   : mImageRenderer(aRhs.mImageRenderer)
   , mImageSize(aRhs.mImageSize)
   , mSlice(aRhs.mSlice)
   , mWidths(aRhs.mWidths)
--- a/layout/painting/nsCSSRenderingBorders.h
+++ b/layout/painting/nsCSSRenderingBorders.h
@@ -286,17 +286,17 @@ public:
     nsIFrame::Sides aSkipSides,
     uint32_t aFlags,
     mozilla::image::ImgDrawResult* aDrawResult);
 
   mozilla::image::ImgDrawResult DrawBorderImage(nsPresContext* aPresContext,
                                                 gfxContext& aRenderingContext,
                                                 nsIFrame* aForFrame,
                                                 const nsRect& aDirtyRect);
-  void CreateWebRenderCommands(
+  mozilla::image::ImgDrawResult CreateWebRenderCommands(
     nsDisplayItem* aItem,
     nsIFrame* aForFrame,
     mozilla::wr::DisplayListBuilder& aBuilder,
     mozilla::wr::IpcResourceUpdateQueue& aResources,
     const mozilla::layers::StackingContextHelper& aSc,
     mozilla::layers::WebRenderLayerManager* aManager,
     nsDisplayListBuilder* aDisplayListBuilder);
 
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -4293,18 +4293,21 @@ nsDisplayBackgroundImage::CreateWebRende
                                                   StyleFrame(),
                                                   mImageFlags,
                                                   mLayer,
                                                   CompositionOp::OP_OVER);
   params.bgClipRect = &mBounds;
   ImgDrawResult result =
     nsCSSRendering::BuildWebRenderDisplayItemsForStyleImageLayer(
       params, aBuilder, aResources, aSc, aManager, this);
+  if (result == ImgDrawResult::NOT_SUPPORTED) {
+    return false;
+  }
+
   nsDisplayBackgroundGeometry::UpdateDrawResult(this, result);
-
   return true;
 }
 
 void
 nsDisplayBackgroundImage::HitTest(nsDisplayListBuilder* aBuilder,
                                   const nsRect& aRect,
                                   HitTestState* aState,
                                   nsTArray<nsIFrame*>* aOutFrames)
@@ -5532,24 +5535,32 @@ nsDisplayBorder::CreateWebRenderCommands
   mozilla::wr::DisplayListBuilder& aBuilder,
   mozilla::wr::IpcResourceUpdateQueue& aResources,
   const StackingContextHelper& aSc,
   mozilla::layers::WebRenderLayerManager* aManager,
   nsDisplayListBuilder* aDisplayListBuilder)
 {
   nsRect rect = nsRect(ToReferenceFrame(), mFrame->GetSize());
 
-  return nsCSSRendering::CreateWebRenderCommandsForBorder(this,
-                                                          mFrame,
-                                                          rect,
-                                                          aBuilder,
-                                                          aResources,
-                                                          aSc,
-                                                          aManager,
-                                                          aDisplayListBuilder);
+  ImgDrawResult drawResult =
+    nsCSSRendering::CreateWebRenderCommandsForBorder(this,
+                                                     mFrame,
+                                                     rect,
+                                                     aBuilder,
+                                                     aResources,
+                                                     aSc,
+                                                     aManager,
+                                                     aDisplayListBuilder);
+
+  if (drawResult == ImgDrawResult::NOT_SUPPORTED) {
+    return false;
+  }
+
+  nsDisplayBorderGeometry::UpdateDrawResult(this, drawResult);
+  return true;
 };
 
 void
 nsDisplayBorder::Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx)
 {
   nsPoint offset = ToReferenceFrame();
 
   PaintBorderFlags flags = aBuilder->ShouldSyncDecodeImages()
--- a/layout/painting/nsDisplayListInvalidation.h
+++ b/layout/painting/nsDisplayListInvalidation.h
@@ -120,16 +120,19 @@ public:
         ShouldInvalidateToSyncDecodeImages()) {
       mWaitingForPaint = true;
     }
   }
 
   static void UpdateDrawResult(nsDisplayItem* aItem,
                                mozilla::image::ImgDrawResult aResult)
   {
+    MOZ_ASSERT(aResult != mozilla::image::ImgDrawResult::NOT_SUPPORTED,
+               "ImgDrawResult::NOT_SUPPORTED should be handled already!");
+
     auto lastGeometry =
       static_cast<T*>(mozilla::FrameLayerBuilder::GetMostRecentGeometry(aItem));
     if (lastGeometry) {
       lastGeometry->mLastDrawResult = aResult;
       lastGeometry->mWaitingForPaint = false;
     }
   }
 
--- a/layout/painting/nsImageRenderer.cpp
+++ b/layout/painting/nsImageRenderer.cpp
@@ -597,16 +597,17 @@ nsImageRenderer::BuildWebRenderDisplayIt
     return ImgDrawResult::NOT_READY;
   }
 
   if (aDest.IsEmpty() || aFill.IsEmpty() || mSize.width <= 0 ||
       mSize.height <= 0) {
     return ImgDrawResult::SUCCESS;
   }
 
+  ImgDrawResult drawResult = ImgDrawResult::SUCCESS;
   switch (mType) {
     case eStyleImageType_Gradient: {
       nsCSSGradientRenderer renderer = nsCSSGradientRenderer::Create(
         aPresContext, mForFrame->Style(), mGradientData, mSize);
 
       renderer.BuildWebRenderDisplayItems(aBuilder,
                                           aSc,
                                           aDest,
@@ -638,38 +639,38 @@ nsImageRenderer::BuildWebRenderDisplayIt
         nsLayoutUtils::ComputeImageContainerDrawingParameters(mImageContainer,
                                                               mForFrame,
                                                               destRect,
                                                               aSc,
                                                               containerFlags,
                                                               svgContext);
 
       RefPtr<layers::ImageContainer> container;
-      mImageContainer->GetImageContainerAtSize(aManager, decodeSize, svgContext,
-                                               containerFlags, getter_AddRefs(container));
+      drawResult = mImageContainer->GetImageContainerAtSize(aManager, decodeSize, svgContext,
+                                                            containerFlags, getter_AddRefs(container));
       if (!container) {
         NS_WARNING("Failed to get image container");
-        return ImgDrawResult::NOT_READY;
+        break;
       }
 
       mozilla::wr::ImageRendering rendering = wr::ToImageRendering(
         nsLayoutUtils::GetSamplingFilterForFrame(aItem->Frame()));
       gfx::IntSize size;
       Maybe<wr::ImageKey> key =
         aManager->CommandBuilder().CreateImageKey(aItem,
                                                   container,
                                                   aBuilder,
                                                   aResources,
                                                   rendering,
                                                   aSc,
                                                   size,
                                                   Nothing());
 
       if (key.isNothing()) {
-        return ImgDrawResult::NOT_READY;
+        break;
       }
 
       nsPoint firstTilePos = nsLayoutUtils::GetBackgroundFirstTilePos(
         aDest.TopLeft(), aFill.TopLeft(), aRepeatSize);
       LayoutDeviceRect fillRect =
         LayoutDeviceRect::FromAppUnits(nsRect(firstTilePos.x,
                                               firstTilePos.y,
                                               aFill.XMost() - firstTilePos.x,
@@ -717,18 +718,20 @@ nsImageRenderer::BuildWebRenderDisplayIt
                          rendering,
                          key.value());
       break;
     }
     default:
       break;
   }
 
-  return mImage->IsComplete() ? ImgDrawResult::SUCCESS
-                              : ImgDrawResult::SUCCESS_NOT_COMPLETE;
+  if (!mImage->IsComplete() && drawResult == ImgDrawResult::SUCCESS) {
+    return ImgDrawResult::SUCCESS_NOT_COMPLETE;
+  }
+  return drawResult;
 }
 
 already_AddRefed<gfxDrawable>
 nsImageRenderer::DrawableForElement(const nsRect& aImageRect,
                                     gfxContext& aContext)
 {
   NS_ASSERTION(mType == eStyleImageType_Element,
                "DrawableForElement only makes sense if backed by an element");
--- a/layout/xul/nsImageBoxFrame.cpp
+++ b/layout/xul/nsImageBoxFrame.cpp
@@ -413,33 +413,33 @@ nsImageBoxFrame::PaintImage(gfxContext& 
            PresContext(), imgCon,
            nsLayoutUtils::GetSamplingFilterForFrame(this),
            dest, dirty,
            svgContext, aFlags,
            anchorPoint.ptrOr(nullptr),
            hasSubRect ? &mSubRect : nullptr);
 }
 
-Maybe<ImgDrawResult>
+ImgDrawResult
 nsImageBoxFrame::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                          mozilla::wr::IpcResourceUpdateQueue& aResources,
                                          const StackingContextHelper& aSc,
                                          mozilla::layers::WebRenderLayerManager* aManager,
                                          nsDisplayItem* aItem,
                                          nsPoint aPt,
                                          uint32_t aFlags)
 {
   ImgDrawResult result;
   Maybe<nsPoint> anchorPoint;
   nsRect dest;
   nsCOMPtr<imgIContainer> imgCon = GetImageContainerForPainting(aPt, result,
                                                                 anchorPoint,
                                                                 dest);
   if (!imgCon) {
-    return Nothing();
+    return result;
   }
 
   uint32_t containerFlags = imgIContainer::FLAG_ASYNC_NOTIFY;
   if (aFlags & nsImageRenderer::FLAG_PAINTING_TO_WINDOW) {
     containerFlags |= imgIContainer::FLAG_HIGH_QUALITY_SCALING;
   }
   if (aFlags & nsImageRenderer::FLAG_SYNC_DECODE_IMAGES) {
     containerFlags |= imgIContainer::FLAG_SYNC_DECODE;
@@ -449,43 +449,43 @@ nsImageBoxFrame::CreateWebRenderCommands
   LayoutDeviceRect fillRect = LayoutDeviceRect::FromAppUnits(dest,
                                                              appUnitsPerDevPixel);
   Maybe<SVGImageContext> svgContext;
   gfx::IntSize decodeSize =
     nsLayoutUtils::ComputeImageContainerDrawingParameters(imgCon, aItem->Frame(), fillRect,
                                                           aSc, containerFlags, svgContext);
 
   RefPtr<layers::ImageContainer> container;
-  imgCon->GetImageContainerAtSize(aManager, decodeSize, svgContext,
-                                  containerFlags, getter_AddRefs(container));
+  result = imgCon->GetImageContainerAtSize(aManager, decodeSize, svgContext,
+                                           containerFlags, getter_AddRefs(container));
   if (!container) {
     NS_WARNING("Failed to get image container");
-    return Nothing();
+    return result;
   }
 
   mozilla::wr::ImageRendering rendering = wr::ToImageRendering(
     nsLayoutUtils::GetSamplingFilterForFrame(aItem->Frame()));
   gfx::IntSize size;
   Maybe<wr::ImageKey> key = aManager->CommandBuilder().CreateImageKey(
     aItem, container, aBuilder, aResources, rendering, aSc, size, Nothing());
   if (key.isNothing()) {
-    return Some(ImgDrawResult::NOT_READY);
+    return result;
   }
   wr::LayoutRect fill = wr::ToRoundedLayoutRect(fillRect);
 
   LayoutDeviceSize gapSize(0, 0);
   aBuilder.PushImage(fill,
                      fill,
                      !BackfaceIsHidden(),
                      wr::ToLayoutSize(fillRect.Size()),
                      wr::ToLayoutSize(gapSize),
                      rendering,
                      key.value());
 
-  return Some(ImgDrawResult::SUCCESS);
+  return result;
 }
 
 nsRect
 nsImageBoxFrame::GetDestRect(const nsPoint& aOffset, Maybe<nsPoint>& aAnchorPoint)
 {
   nsCOMPtr<imgIContainer> imgCon;
   mImageRequest->GetImage(getter_AddRefs(imgCon));
   MOZ_ASSERT(imgCon);
@@ -566,23 +566,23 @@ nsDisplayXULImage::CreateWebRenderComman
   uint32_t flags = imgIContainer::FLAG_SYNC_DECODE_IF_FAST;
   if (aDisplayListBuilder->ShouldSyncDecodeImages()) {
     flags |= imgIContainer::FLAG_SYNC_DECODE;
   }
   if (aDisplayListBuilder->IsPaintingToWindow()) {
     flags |= imgIContainer::FLAG_HIGH_QUALITY_SCALING;
   }
 
-  Maybe<ImgDrawResult> result = imageFrame->
+  ImgDrawResult result = imageFrame->
     CreateWebRenderCommands(aBuilder, aResources, aSc, aManager, this, ToReferenceFrame(), flags);
-  if (!result) {
+  if (result == ImgDrawResult::NOT_SUPPORTED) {
     return false;
   }
 
-  nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, *result);
+  nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, result);
   return true;
 }
 
 nsDisplayItemGeometry*
 nsDisplayXULImage::AllocateGeometry(nsDisplayListBuilder* aBuilder)
 {
   return new nsDisplayItemGenericImageGeometry(this, aBuilder);
 }
--- a/layout/xul/nsImageBoxFrame.h
+++ b/layout/xul/nsImageBoxFrame.h
@@ -91,23 +91,23 @@ public:
                                                                ImgDrawResult& aDrawResult,
                                                                Maybe<nsPoint>& aAnchorPoint,
                                                                nsRect& aDest);
 
   ImgDrawResult PaintImage(gfxContext& aRenderingContext,
                         const nsRect& aDirtyRect,
                         nsPoint aPt, uint32_t aFlags);
 
-  Maybe<ImgDrawResult> CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
-                                               mozilla::wr::IpcResourceUpdateQueue& aResources,
-                                               const mozilla::layers::StackingContextHelper& aSc,
-                                               mozilla::layers::WebRenderLayerManager* aManager,
-                                               nsDisplayItem* aItem,
-                                               nsPoint aPt,
-                                               uint32_t aFlags);
+  ImgDrawResult CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
+                                        mozilla::wr::IpcResourceUpdateQueue& aResources,
+                                        const mozilla::layers::StackingContextHelper& aSc,
+                                        mozilla::layers::WebRenderLayerManager* aManager,
+                                        nsDisplayItem* aItem,
+                                        nsPoint aPt,
+                                        uint32_t aFlags);
 
   bool CanOptimizeToImageLayer();
 
   nsRect GetDestRect(const nsPoint& aOffset, Maybe<nsPoint>& aAnchorPoint);
 
 protected:
   explicit nsImageBoxFrame(ComputedStyle* aStyle);