Backed out 10 changesets (bug 1132427, bug 1130707, bug 1128769) for Linux32 debug bustage.
authorRyan VanderMeulen <ryanvm@gmail.com>
Sat, 21 Feb 2015 12:13:59 -0500
changeset 251597 0d2ff42498171c5c9d5df3f4499f208c03ab1c45
parent 251596 306766d9ecff2a9f36b72687ac170241f204f21b
child 251598 c011ebd0e2c1e4a48709972453f76166442f80fc
push id698
push userjlund@mozilla.com
push dateMon, 23 Mar 2015 22:08:11 +0000
treeherdermozilla-release@b0c0ae7b02a3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1132427, 1130707, 1128769
milestone37.0a2
backs outf23746928e841079b106a708f6ec1f6d1c084eae
4a8edebbc3cebe1a6659bcfcc9b8fb89f4759071
4abf28db48d53964d502c9f6ff93d46c2b784f30
77af082895db0ba23a53bcf4fac30c456ee9ee06
da8d29b51b28f728bc3fbb379d97fb3aec86bf11
25345c8d57715a508e76bbc1940273e9fd4b0a7f
20fe191ffa445f93e3c363eaf858d8a0405f1db5
c581cb43428d6cc8406876c1a5728ed8aba6b785
cfc0c8037827795f5dace033f864f8b7fd39cb9b
907ae07461e43688bfda477a1b17c31ae75a78e7
Backed out 10 changesets (bug 1132427, bug 1130707, bug 1128769) for Linux32 debug bustage. Backed out changeset f23746928e84 (bug 1132427) Backed out changeset 4a8edebbc3ce (bug 1132427) Backed out changeset 4abf28db48d5 (bug 1130707) Backed out changeset 77af082895db (bug 1130707) Backed out changeset da8d29b51b28 (bug 1128769) Backed out changeset 25345c8d5771 (bug 1128769) Backed out changeset 20fe191ffa44 (bug 1128769) Backed out changeset c581cb43428d (bug 1128769) Backed out changeset cfc0c8037827 (bug 1128769) Backed out changeset 907ae07461e4 (bug 1128769)
image/public/imgIContainer.idl
image/src/DynamicImage.cpp
image/src/ImageWrapper.cpp
image/src/RasterImage.cpp
image/src/RasterImage.h
image/src/VectorImage.cpp
image/test/mochitest/bug1132427.gif
image/test/mochitest/bug1132427.html
image/test/mochitest/chrome.ini
image/test/mochitest/test_bug1132427.html
layout/base/nsCSSRendering.cpp
layout/base/nsCSSRendering.h
layout/base/nsDisplayList.cpp
layout/base/nsDisplayList.h
layout/base/nsDisplayListInvalidation.cpp
layout/base/nsDisplayListInvalidation.h
layout/forms/nsButtonFrameRenderer.cpp
layout/forms/nsButtonFrameRenderer.h
layout/forms/nsFieldSetFrame.cpp
layout/forms/nsFieldSetFrame.h
layout/generic/nsBulletFrame.cpp
layout/generic/nsImageFrame.cpp
layout/mathml/nsMathMLChar.cpp
layout/tables/nsTableCellFrame.cpp
layout/tables/nsTableCellFrame.h
layout/tables/nsTableFrame.cpp
layout/tables/nsTableFrame.h
layout/tables/nsTablePainter.cpp
layout/tables/nsTablePainter.h
layout/tables/nsTableRowFrame.cpp
layout/tables/nsTableRowGroupFrame.cpp
layout/xul/nsImageBoxFrame.cpp
--- a/image/public/imgIContainer.idl
+++ b/image/public/imgIContainer.idl
@@ -111,17 +111,17 @@ native nsIntSizeByVal(nsIntSize);
 
 /**
  * imgIContainer is the interface that represents an image. It allows
  * access to frames as Thebes surfaces. It also allows drawing of images
  * onto Thebes contexts.
  *
  * Internally, imgIContainer also manages animation of images.
  */
-[scriptable, builtinclass, uuid(9a43298b-bf49-44fc-9abe-9ff702f1bd25)]
+[scriptable, builtinclass, uuid(4e7d0b17-cb57-4d68-860f-59b303a86dbd)]
 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;
 
@@ -420,16 +420,24 @@ interface imgIContainer : nsISupports
    *               (FLAG_DECODE_*) and FLAG_SYNC_DECODE (which will
    *               synchronously decode images that can be decoded "quickly",
    *               just like startDecoding() does) are accepted; others will be
    *               ignored.
    */
   [noscript] void requestDecodeForSize([const] in nsIntSize aSize,
                                        in uint32_t aFlags);
 
+  /*
+   * Returns true if no more decoding can be performed on this image. Images
+   * with errors return true since they cannot be decoded any further. Note that
+   * because decoded images may be discarded, isDecoded() may return false even
+   * if it has returned true in the past.
+   */
+  [noscript, notxpcom, nostdcall] bool isDecoded();
+
   /**
     * Increments the lock count on the image. An image will not be discarded
     * as long as the lock count is nonzero. Note that it is still possible for
     * the image to be undecoded if decode-on-draw is enabled and the image
     * was never drawn.
     *
     * Upon instantiation images have a lock count of zero.
     */
--- a/image/src/DynamicImage.cpp
+++ b/image/src/DynamicImage.cpp
@@ -255,16 +255,22 @@ DynamicImage::StartDecoding()
 }
 
 NS_IMETHODIMP
 DynamicImage::RequestDecodeForSize(const nsIntSize& aSize, uint32_t aFlags)
 {
   return NS_OK;
 }
 
+bool
+DynamicImage::IsDecoded()
+{
+  return true;
+}
+
 NS_IMETHODIMP
 DynamicImage::LockImage()
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
 DynamicImage::UnlockImage()
--- a/image/src/ImageWrapper.cpp
+++ b/image/src/ImageWrapper.cpp
@@ -225,16 +225,22 @@ ImageWrapper::StartDecoding()
 }
 
 NS_IMETHODIMP
 ImageWrapper::RequestDecodeForSize(const nsIntSize& aSize, uint32_t aFlags)
 {
   return mInnerImage->RequestDecodeForSize(aSize, aFlags);
 }
 
+bool
+ImageWrapper::IsDecoded()
+{
+  return mInnerImage->IsDecoded();
+}
+
 NS_IMETHODIMP
 ImageWrapper::LockImage()
 {
   MOZ_ASSERT(NS_IsMainThread(),
              "Main thread to encourage serialization with UnlockImage");
   return mInnerImage->LockImage();
 }
 
--- a/image/src/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -257,16 +257,17 @@ RasterImage::RasterImage(ProgressTracker
   mDecodeCount(0),
   mRequestedSampleSize(0),
 #ifdef DEBUG
   mFramesNotified(0),
 #endif
   mSourceBuffer(new SourceBuffer()),
   mFrameCount(0),
   mHasSize(false),
+  mBlockedOnload(false),
   mDecodeOnDraw(false),
   mTransient(false),
   mDiscardable(false),
   mHasSourceData(false),
   mHasBeenDecoded(false),
   mPendingAnimation(false),
   mAnimationFinished(false),
   mWantFullDecode(false)
@@ -930,19 +931,20 @@ RasterImage::OnAddedFrame(uint32_t aNewF
       // mid-decode, and thus we're decoding out of the source buffer. Since we're
       // going to fix this anyway later, and since we didn't kill the source data
       // in the old world either, locking is acceptable for the moment.
       LockImage();
 
       if (mPendingAnimation && ShouldAnimate()) {
         StartAnimation();
       }
-    }
-    if (aNewFrameCount > 1) {
-      mAnim->UnionFirstFrameRefreshArea(aNewRefreshArea);
+
+      if (aNewFrameCount > 1) {
+        mAnim->UnionFirstFrameRefreshArea(aNewRefreshArea);
+      }
     }
   }
 }
 
 nsresult
 RasterImage::SetSize(int32_t aWidth, int32_t aHeight, Orientation aOrientation)
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -1152,61 +1154,59 @@ RasterImage::OnImageDataComplete(nsIRequ
 
   MOZ_ASSERT(mHasSize || mError, "Need to know size before firing load event");
   MOZ_ASSERT(!mHasSize ||
              (mProgressTracker->GetProgress() & FLAG_SIZE_AVAILABLE),
              "Should have notified that the size is available if we have it");
 
   Progress loadProgress = LoadCompleteProgress(aLastPart, mError, finalStatus);
 
-  if (mDecodeOnDraw) {
+  if (mBlockedOnload) {
     // For decode-on-draw images, we want to send notifications as if we've
     // already finished decoding. Otherwise some observers will never even try
-    // to draw. (We may have already sent some of these notifications from
-    // NotifyForDecodeOnDrawOnly(), but ProgressTracker will ensure no duplicate
-    // notifications get sent.)
-    loadProgress |= FLAG_ONLOAD_BLOCKED |
-                    FLAG_DECODE_STARTED |
-                    FLAG_FRAME_COMPLETE |
+    // to draw.
+    MOZ_ASSERT(mDecodeOnDraw, "Blocked onload but not decode-on-draw");
+    loadProgress |= FLAG_FRAME_COMPLETE |
                     FLAG_DECODE_COMPLETE |
                     FLAG_ONLOAD_UNBLOCKED;
   }
 
   // Notify our listeners, which will fire this image's load event.
   NotifyProgress(loadProgress);
 
   return finalStatus;
 }
 
 void
-RasterImage::NotifyForDecodeOnDrawOnly()
+RasterImage::BlockOnloadForDecodeOnDraw()
 {
-  if (!NS_IsMainThread()) {
-    nsCOMPtr<nsIRunnable> runnable =
-      NS_NewRunnableMethod(this, &RasterImage::NotifyForDecodeOnDrawOnly);
-    NS_DispatchToMainThread(runnable);
+  if (mHasSourceData) {
+    // OnImageDataComplete got called before we got to run. No point in blocking
+    // onload now.
     return;
   }
 
+  // Block onload. We'll unblock it in OnImageDataComplete.
+  mBlockedOnload = true;
   NotifyProgress(FLAG_DECODE_STARTED | FLAG_ONLOAD_BLOCKED);
 }
 
 nsresult
 RasterImage::OnImageDataAvailable(nsIRequest*,
                                   nsISupports*,
                                   nsIInputStream* aInStr,
                                   uint64_t aOffset,
                                   uint32_t aCount)
 {
   nsresult rv;
 
   if (MOZ_UNLIKELY(mDecodeOnDraw && aOffset == 0)) {
-    // If we're a decode-on-draw image, send notifications as if we've just
-    // started decoding.
-    NotifyForDecodeOnDrawOnly();
+    nsCOMPtr<nsIRunnable> runnable =
+      NS_NewRunnableMethod(this, &RasterImage::BlockOnloadForDecodeOnDraw);
+    NS_DispatchToMainThread(runnable);
   }
 
   // WriteToSourceBuffer always consumes everything it gets if it doesn't run
   // out of memory.
   uint32_t bytesRead;
   rv = aInStr->ReadSegments(WriteToSourceBuffer, this, aCount, &bytesRead);
 
   NS_ABORT_IF_FALSE(bytesRead == aCount || HasError() || NS_FAILED(rv),
@@ -1464,16 +1464,23 @@ RasterImage::RequestDecodeForSize(const 
 
   // Look up the first frame of the image, which will implicitly start decoding
   // if it's not available right now.
   LookupFrame(0, targetSize, flags);
 
   return NS_OK;
 }
 
+bool
+RasterImage::IsDecoded()
+{
+  // XXX(seth): We need to get rid of this; it's not reliable.
+  return mHasBeenDecoded || mError || (mDecodeOnDraw && mHasSourceData);
+}
+
 NS_IMETHODIMP
 RasterImage::Decode(const Maybe<nsIntSize>& aSize, uint32_t aFlags)
 {
   MOZ_ASSERT(!aSize || NS_IsMainThread());
 
   if (mError) {
     return NS_ERROR_FAILURE;
   }
--- a/image/src/RasterImage.h
+++ b/image/src/RasterImage.h
@@ -243,17 +243,17 @@ public:
                                         nsIInputStream* aInStr,
                                         uint64_t aSourceOffset,
                                         uint32_t aCount) MOZ_OVERRIDE;
   virtual nsresult OnImageDataComplete(nsIRequest* aRequest,
                                        nsISupports* aContext,
                                        nsresult aStatus,
                                        bool aLastPart) MOZ_OVERRIDE;
 
-  void NotifyForDecodeOnDrawOnly();
+  void BlockOnloadForDecodeOnDraw();
 
   /**
    * A hint of the number of bytes of source data that the image contains. If
    * called early on, this can help reduce copying and reallocations by
    * appropriately preallocating the source data buffer.
    *
    * We take this approach rather than having the source data management code do
    * something more complicated (like chunklisting) because HTTP is by far the
@@ -389,16 +389,17 @@ private: // data
   // The source data for this image.
   nsRefPtr<SourceBuffer>     mSourceBuffer;
 
   // The number of frames this image has.
   uint32_t                   mFrameCount;
 
   // Boolean flags (clustered together to conserve space):
   bool                       mHasSize:1;       // Has SetSize() been called?
+  bool                       mBlockedOnload:1; // Did send BLOCK_ONLOAD?
   bool                       mDecodeOnDraw:1;  // Decoding on draw?
   bool                       mTransient:1;     // Is the image short-lived?
   bool                       mDiscardable:1;   // Is container discardable?
   bool                       mHasSourceData:1; // Do we have source data?
   bool                       mHasBeenDecoded:1; // Decoded at least once?
   bool                       mDownscaleDuringDecode:1;
 
   // Whether we're waiting to start animation. If we get a StartAnimation() call
--- a/image/src/VectorImage.cpp
+++ b/image/src/VectorImage.cpp
@@ -926,16 +926,22 @@ NS_IMETHODIMP
 VectorImage::RequestDecodeForSize(const nsIntSize& aSize, uint32_t aFlags)
 {
   // Nothing to do for SVG images, though in theory we could rasterize to the
   // provided size ahead of time if we supported off-main-thread SVG
   // rasterization...
   return NS_OK;
 }
 
+bool
+VectorImage::IsDecoded()
+{
+  return mIsFullyLoaded || mError;
+}
+
 //******************************************************************************
 /* void lockImage() */
 NS_IMETHODIMP
 VectorImage::LockImage()
 {
   // This method is for image-discarding, which only applies to RasterImages.
   return NS_OK;
 }
deleted file mode 100644
index 39f49689a0ab5ce727666a278e69e946ed4f4776..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
--- a/image/test/mochitest/bug1132427.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<html>
-<body onload="opener.doTest();">
-  <img id="left" style="width: 201px; height: 201px;" src="bug1132427.gif">
-  <img id="right" src="bug1132427.gif">
-</body>
-</html>
--- a/image/test/mochitest/chrome.ini
+++ b/image/test/mochitest/chrome.ini
@@ -23,18 +23,16 @@ support-files =
   opaque.bmp
   purple.gif
   red.gif
   red.png
   ref-iframe.html
   rillybad.jpg
   transparent.gif
   transparent.png
-  bug1132427.html
-  bug1132427.gif
 
 [test_animSVGImage.html]
 [test_animSVGImage2.html]
 [test_animation.html]
 disabled = bug 1100497
 [test_animation2.html]
 disabled = bug 1101415
 [test_background_image_anim.html]
@@ -47,9 +45,8 @@ disabled = bug 1101415
 [test_removal_onload.html]
 [test_staticClone.html]
 [test_svg_animatedGIF.html]
 [test_svg_filter_animation.html]
 [test_synchronized_animation.html]
 [test_undisplayed_iframe.html]
 disabled = bug 1060869
 [test_xultree_animation.xhtml]
-[test_bug1132427.html]
deleted file mode 100644
--- a/image/test/mochitest/test_bug1132427.html
+++ /dev/null
@@ -1,96 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-  <title>Test for scrolling selection into view</title>
-  <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
-  <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/WindowSnapshot.js"></script>
-  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
-</head>
-<body>
-
-<pre id="test">
-<script class="testbody" type="text/javascript">
-
-// We open a window which contains two copies of the same gif. One at a scaled size, one at the
-// natural image size. We rely on the bug only showing up in the scaled image. The gif has three
-// frames and a delay of 100ms. The first is all white. The second has a very small update area
-// in the upper left, it changes the pixels to slightly off white. The third changes all the
-// pixels to blue. When the bug appears we only update the upper left pixels when looping around
-// from the last frame to the first frame. We compare a middle pixel of the two images to make
-// sure that they are the same at 100ms for a second. If the bug appears then the middle pixel
-// on the scaled image will always be blue and so should not match the middle pixel on the
-// unscaled image which should be white two thirds of the time. If the timers fire at bad times
-// and only fire when both frames are displaying blue we won't be able to detect this bug and the
-// test will pass without testing anything important, but that's not a big deal. That should be
-// rare enough, and the next time the test is run will should do proper testing.
-
-SimpleTest.waitForExplicitFinish();
-addLoadEvent(openWindow);
-
-var win = null;
-
-function openWindow() {
-  win = window.open("bug1132427.html",
-                "", "scrollbars=yes,toolbar,menubar,width=600,height=800");
-  win.addEventListener("load", doTest, false);
-  win.focus();
-}
-
-function doTest() {
-  setTimeout(continueTest, 1000);
-}
-
-function checkPixel(canvas, context, x1, y1, x2, y2) {
-  var pix = context.getImageData(0, 0, canvas.width, canvas.height).data;
-  for (var i = 0; i < 4; i++) {
-    is(pix[4 * (y1 * canvas.width + x1) + i], pix[4 * (y2 * canvas.width + x2) + i], "pixels should match");
-  }
-}
-
-var iterationsLeft = 10;
-
-function continueTest() {
-  // we need to drawWindow the chrome window so we can get a dump of the retained widget layers
-  // if we have to repaint to fulfill this drawWindow request then it will be impossible to
-  // observe the bug
-  var chromewin = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
-                     .getInterface(Components.interfaces.nsIWebNavigation)
-                     .QueryInterface(Components.interfaces.nsIDocShellTreeItem)
-                     .rootTreeItem
-                     .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
-                     .getInterface(Components.interfaces.nsIDOMWindow);
-
-  var el = window.document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
-  el.width = chromewin.innerWidth;
-  el.height = chromewin.innerHeight;
-  var ctx = el.getContext("2d");
-  // pass the correct flags so we don't have to flush the retained layers
-  ctx.drawWindow(chromewin, 0, 0, chromewin.innerWidth, chromewin.innerHeight, "rgba(0,0,0,0)",
-    ctx.DRAWWINDOW_USE_WIDGET_LAYERS | ctx.DRAWWINDOW_DRAW_VIEW | ctx.DRAWWINDOW_DRAW_CARET);
-
-  var leftbox = win.document.getElementById("left").getBoundingClientRect();
-  var rightbox = win.document.getElementById("right").getBoundingClientRect();
-  // this is actually chrome on left and right, but in practice we have none so it doesn't matter
-  var chromeleft = win.outerWidth - win.innerWidth;
-  // this is actually chrome on top and bottom, but bottom chrome is usually small to none and we have
-  // 100px to spare in hitting the middle of the image elements (they are 200x200)
-  var chrometop = win.outerHeight - win.innerHeight;
-
-  // compare the middle of the two image elements
-  checkPixel(el, ctx, chromeleft + leftbox.left + Math.floor(leftbox.width/2), chrometop + leftbox.top + Math.floor(leftbox.height/2),
-                      chromeleft + rightbox.left + Math.floor(rightbox.width/2), chrometop + rightbox.top + Math.floor(rightbox.height/2));
-
-  iterationsLeft--;
-  if (iterationsLeft > 0) {
-    // now test 100ms later, we should have the next frame of the gif then
-    setTimeout(continueTest, 100);
-  } else {
-    win.close();
-    SimpleTest.finish();
-  }
-}
-</script>
-</pre>
-</body>
-
-</html>
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -57,17 +57,17 @@
 #include "gfxColor.h"
 #include "gfxGradientCache.h"
 #include "GraphicsFilter.h"
 #include <algorithm>
 
 using namespace mozilla;
 using namespace mozilla::css;
 using namespace mozilla::gfx;
-using namespace mozilla::image;
+using mozilla::image::ImageOps;
 using mozilla::CSSSizeOrRatio;
 
 static int gFrameTreeLockCount = 0;
 
 // To avoid storing this data on nsInlineFrame (bloat) and to avoid
 // recalculating this for each frame in a continuation (perf), hold
 // a cache of various coordinate information that we need in order
 // to paint inline backgrounds.
@@ -1613,17 +1613,17 @@ nsCSSRendering::PaintBoxShadowInner(nsPr
     shadowContext->Fill();
     shadowContext->NewPath();
 
     blurringArea.DoPaint();
     renderContext->Restore();
   }
 }
 
-DrawResult
+void
 nsCSSRendering::PaintBackground(nsPresContext* aPresContext,
                                 nsRenderingContext& aRenderingContext,
                                 nsIFrame* aForFrame,
                                 const nsRect& aDirtyRect,
                                 const nsRect& aBorderArea,
                                 uint32_t aFlags,
                                 nsRect* aBGClipRect,
                                 int32_t aLayer)
@@ -1637,31 +1637,31 @@ nsCSSRendering::PaintBackground(nsPresCo
   nsStyleContext *sc;
   if (!FindBackground(aForFrame, &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
     // a root, otherwise keep going in order to let the theme stuff
     // draw the background. The canvas really should be drawing the
     // bg, but there's no way to hook that up via css.
     if (!aForFrame->StyleDisplay()->mAppearance) {
-      return DrawResult::SUCCESS;
+      return;
     }
 
     nsIContent* content = aForFrame->GetContent();
     if (!content || content->GetParent()) {
-      return DrawResult::SUCCESS;
+      return;
     }
 
     sc = aForFrame->StyleContext();
   }
 
-  return PaintBackgroundWithSC(aPresContext, aRenderingContext, aForFrame,
-                               aDirtyRect, aBorderArea, sc,
-                               *aForFrame->StyleBorder(), aFlags,
-                               aBGClipRect, aLayer);
+  PaintBackgroundWithSC(aPresContext, aRenderingContext, aForFrame,
+                        aDirtyRect, aBorderArea, sc,
+                        *aForFrame->StyleBorder(), aFlags,
+                        aBGClipRect, aLayer);
 }
 
 static bool
 IsOpaqueBorderEdge(const nsStyleBorder& aBorder, mozilla::css::Side aSide)
 {
   if (aBorder.GetComputedBorder().Side(aSide) == 0)
     return true;
   switch (aBorder.GetBorderStyle(aSide)) {
@@ -2812,52 +2812,47 @@ nsCSSRendering::PaintGradient(nsPresCont
         ctx->SetPattern(gradientPattern);
       }
       ctx->Fill();
       ctx->SetMatrix(ctm);
     }
   }
 }
 
-DrawResult
+void
 nsCSSRendering::PaintBackgroundWithSC(nsPresContext* aPresContext,
                                       nsRenderingContext& aRenderingContext,
                                       nsIFrame* aForFrame,
                                       const nsRect& aDirtyRect,
                                       const nsRect& aBorderArea,
                                       nsStyleContext* aBackgroundSC,
                                       const nsStyleBorder& aBorder,
                                       uint32_t aFlags,
                                       nsRect* aBGClipRect,
                                       int32_t aLayer)
 {
   NS_PRECONDITION(aForFrame,
                   "Frame is expected to be provided to PaintBackground");
 
-  // Initialize our result to success. We update it only if its value is
-  // currently DrawResult::SUCCESS, which means that as soon as we hit our first
-  // non-successful draw, we stop updating and will return that value.
-  DrawResult result = DrawResult::SUCCESS;
-
   // Check to see if we have an appearance defined.  If so, we let the theme
   // renderer draw the background and bail out.
   // XXXzw this ignores aBGClipRect.
   const nsStyleDisplay* displayData = aForFrame->StyleDisplay();
   if (displayData->mAppearance) {
     nsITheme *theme = aPresContext->GetTheme();
     if (theme && theme->ThemeSupportsWidget(aPresContext, aForFrame,
                                             displayData->mAppearance)) {
       nsRect drawing(aBorderArea);
       theme->GetWidgetOverflow(aPresContext->DeviceContext(),
                                aForFrame, displayData->mAppearance, &drawing);
       drawing.IntersectRect(drawing, aDirtyRect);
       theme->DrawWidgetBackground(&aRenderingContext, aForFrame,
                                   displayData->mAppearance, aBorderArea,
                                   drawing);
-      return DrawResult::SUCCESS;
+      return;
     }
   }
 
   // For canvas frames (in the CSS sense) we draw the background color using
   // a solid color item that gets added in nsLayoutUtils::PaintFrame,
   // or nsSubDocumentFrame::BuildDisplayList (bug 488242). (The solid
   // color may be moved into nsDisplayCanvasBackground by
   // nsPresShell::AddCanvasBackgroundColorItem, and painted by
@@ -2882,17 +2877,17 @@ nsCSSRendering::PaintBackgroundWithSC(ns
   if (drawBackgroundColor && aLayer >= 0) {
     drawBackgroundColor = false;
   }
 
   // At this point, drawBackgroundImage and drawBackgroundColor are
   // true if and only if we are actually supposed to paint an image or
   // color into aDirtyRect, respectively.
   if (!drawBackgroundImage && !drawBackgroundColor)
-    return DrawResult::SUCCESS;
+    return;
 
   // Compute the outermost boundary of the area that might be painted.
   // Same coordinate space as aBorderArea & aBGClipRect.
   Sides skipSides = aForFrame->GetSkipSides();
   nsRect paintBorderArea =
     ::BoxDecorationRectForBackground(aForFrame, aBorderArea, skipSides, &aBorder);
   nsRect clipBorderArea =
     ::BoxDecorationRectForBorder(aForFrame, aBorderArea, skipSides, &aBorder);
@@ -2929,23 +2924,23 @@ nsCSSRendering::PaintBackgroundWithSC(ns
 
   // If there is no background image, draw a color.  (If there is
   // neither a background image nor a color, we wouldn't have gotten
   // this far.)
   if (!drawBackgroundImage) {
     if (!isCanvasFrame) {
       DrawBackgroundColor(clipState, ctx, appUnitsPerPixel);
     }
-    return DrawResult::SUCCESS;
+    return;
   }
 
   if (bg->mImageCount < 1) {
     // Return if there are no background layers, all work from this point
     // onwards happens iteratively on these.
-    return DrawResult::SUCCESS;
+    return;
   }
 
   // Validate the layer range before we start iterating.
   int32_t startLayer = aLayer;
   int32_t nLayers = 1;
   if (startLayer < 0) {
     startLayer = (int32_t)bg->mImageCount - 1;
     nLayers = bg->mImageCount;
@@ -3004,36 +2999,27 @@ nsCSSRendering::PaintBackgroundWithSC(ns
         nsBackgroundLayerState state = PrepareBackgroundLayer(aPresContext, aForFrame,
             aFlags, paintBorderArea, clipState.mBGClipArea, layer);
         if (!state.mFillArea.IsEmpty()) {
           if (state.mCompositingOp != gfxContext::OPERATOR_OVER) {
             NS_ASSERTION(ctx->CurrentOperator() == gfxContext::OPERATOR_OVER,
                          "It is assumed the initial operator is OPERATOR_OVER, when it is restored later");
             ctx->SetOperator(state.mCompositingOp);
           }
-
-          DrawResult resultForLayer =
-            state.mImageRenderer.DrawBackground(aPresContext, aRenderingContext,
-                                                state.mDestArea, state.mFillArea,
-                                                state.mAnchor + paintBorderArea.TopLeft(),
-                                                clipState.mDirtyRect);
-
-          if (result == DrawResult::SUCCESS) {
-            result = resultForLayer;
-          }
-
+          state.mImageRenderer.DrawBackground(aPresContext, aRenderingContext,
+                                              state.mDestArea, state.mFillArea,
+                                              state.mAnchor + paintBorderArea.TopLeft(),
+                                              clipState.mDirtyRect);
           if (state.mCompositingOp != gfxContext::OPERATOR_OVER) {
             ctx->SetOperator(gfxContext::OPERATOR_OVER);
           }
         }
       }
     }
   }
-
-  return result;
 }
 
 static inline bool
 IsTransformed(nsIFrame* aForFrame, nsIFrame* aTopFrame)
 {
   for (nsIFrame* f = aForFrame; f != aTopFrame; f = f->GetParent()) {
     if (f->IsTransformed()) {
       return true;
@@ -3342,16 +3328,44 @@ nsCSSRendering::GetBackgroundLayerRect(n
   nsRect borderArea =
     ::BoxDecorationRectForBackground(aForFrame, aBorderArea, skipSides);
   nsBackgroundLayerState state =
       PrepareBackgroundLayer(aPresContext, aForFrame, aFlags, borderArea,
                              aClipRect, aLayer);
   return state.mFillArea;
 }
 
+/* static */ bool
+nsCSSRendering::IsBackgroundImageDecodedForStyleContextAndLayer(
+  const nsStyleBackground *aBackground, uint32_t aLayer)
+{
+  const nsStyleImage* image = &aBackground->mLayers[aLayer].mImage;
+  if (image->GetType() == eStyleImageType_Image) {
+    nsCOMPtr<imgIContainer> img;
+    if (NS_SUCCEEDED(image->GetImageData()->GetImage(getter_AddRefs(img)))) {
+      if (!img->IsDecoded()) {
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+/* static */ bool
+nsCSSRendering::AreAllBackgroundImagesDecodedForFrame(nsIFrame* aFrame)
+{
+  const nsStyleBackground *bg = aFrame->StyleContext()->StyleBackground();
+  NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, bg) {
+    if (!IsBackgroundImageDecodedForStyleContextAndLayer(bg, i)) {
+      return false;
+    }
+  }
+  return true;
+}
+
 static void
 DrawBorderImage(nsPresContext*       aPresContext,
                 nsRenderingContext&  aRenderingContext,
                 nsIFrame*            aForFrame,
                 const nsRect&        aBorderArea,
                 const nsStyleBorder& aStyleBorder,
                 const nsRect&        aDirtyRect,
                 Sides                aSkipSides)
@@ -4890,62 +4904,62 @@ ConvertImageRendererToDrawFlags(uint32_t
     drawFlags |= imgIContainer::FLAG_SYNC_DECODE;
   }
   if (aImageRendererFlags & nsImageRenderer::FLAG_PAINTING_TO_WINDOW) {
     drawFlags |= imgIContainer::FLAG_HIGH_QUALITY_SCALING;
   }
   return drawFlags;
 }
 
-DrawResult
+void
 nsImageRenderer::Draw(nsPresContext*       aPresContext,
                       nsRenderingContext&  aRenderingContext,
                       const nsRect&        aDirtyRect,
                       const nsRect&        aDest,
                       const nsRect&        aFill,
                       const nsPoint&       aAnchor,
                       const CSSIntRect&    aSrc)
 {
   if (!mIsReady) {
     NS_NOTREACHED("Ensure PrepareImage() has returned true before calling me");
-    return DrawResult::TEMPORARY_ERROR;
+    return;
   }
   if (aDest.IsEmpty() || aFill.IsEmpty() ||
       mSize.width <= 0 || mSize.height <= 0) {
-    return DrawResult::SUCCESS;
+    return;
   }
 
   GraphicsFilter filter = nsLayoutUtils::GetGraphicsFilterForFrame(mForFrame);
 
   switch (mType) {
     case eStyleImageType_Image:
     {
       nsIntSize imageSize(nsPresContext::AppUnitsToIntCSSPixels(mSize.width),
                           nsPresContext::AppUnitsToIntCSSPixels(mSize.height));
-      return
-        nsLayoutUtils::DrawBackgroundImage(*aRenderingContext.ThebesContext(),
-                                           aPresContext,
-                                           mImageContainer, imageSize, filter,
-                                           aDest, aFill, aAnchor, aDirtyRect,
-                                           ConvertImageRendererToDrawFlags(mFlags));
+      nsLayoutUtils::DrawBackgroundImage(*aRenderingContext.ThebesContext(),
+                                         aPresContext,
+                                         mImageContainer, imageSize, filter,
+                                         aDest, aFill, aAnchor, aDirtyRect,
+                                         ConvertImageRendererToDrawFlags(mFlags));
+      return;
     }
     case eStyleImageType_Gradient:
     {
       nsCSSRendering::PaintGradient(aPresContext, aRenderingContext,
                                     mGradientData, aDirtyRect,
                                     aDest, aFill, aSrc, mSize);
-      return DrawResult::SUCCESS;
+      return;
     }
     case eStyleImageType_Element:
     {
       nsRefPtr<gfxDrawable> drawable = DrawableForElement(aDest,
                                                           aRenderingContext);
       if (!drawable) {
         NS_WARNING("Could not create drawable for element");
-        return DrawResult::TEMPORARY_ERROR;
+        return;
       }
 
       gfxContext* ctx = aRenderingContext.ThebesContext();
       gfxContext::GraphicsOperator op = ctx->CurrentOperator();
       if (op != gfxContext::OPERATOR_OVER) {
         ctx->PushGroup(gfxContentType::COLOR_ALPHA);
         ctx->SetOperator(gfxContext::OPERATOR_OVER);
       }
@@ -4956,21 +4970,21 @@ nsImageRenderer::Draw(nsPresContext*    
                                filter, aDest, aFill, aAnchor, aDirtyRect,
                                ConvertImageRendererToDrawFlags(mFlags));
 
       if (op != gfxContext::OPERATOR_OVER) {
         ctx->PopGroupToSource();
         ctx->Paint();
       }
 
-      return DrawResult::SUCCESS;
+      return;
     }
     case eStyleImageType_Null:
     default:
-      return DrawResult::SUCCESS;
+      return;
   }
 }
 
 already_AddRefed<gfxDrawable>
 nsImageRenderer::DrawableForElement(const nsRect& aImageRect,
                                     nsRenderingContext&  aRenderingContext)
 {
   NS_ASSERTION(mType == eStyleImageType_Element,
@@ -4993,38 +5007,38 @@ nsImageRenderer::DrawableForElement(cons
   }
   NS_ASSERTION(mImageElementSurface.mSourceSurface, "Surface should be ready.");
   nsRefPtr<gfxDrawable> drawable = new gfxSurfaceDrawable(
                                 mImageElementSurface.mSourceSurface,
                                 mImageElementSurface.mSize);
   return drawable.forget();
 }
 
-DrawResult
+void
 nsImageRenderer::DrawBackground(nsPresContext*       aPresContext,
                                 nsRenderingContext&  aRenderingContext,
                                 const nsRect&        aDest,
                                 const nsRect&        aFill,
                                 const nsPoint&       aAnchor,
                                 const nsRect&        aDirty)
 {
   if (!mIsReady) {
     NS_NOTREACHED("Ensure PrepareImage() has returned true before calling me");
-    return DrawResult::TEMPORARY_ERROR;
+    return;
   }
   if (aDest.IsEmpty() || aFill.IsEmpty() ||
       mSize.width <= 0 || mSize.height <= 0) {
-    return DrawResult::SUCCESS;
+    return;
   }
 
-  return Draw(aPresContext, aRenderingContext,
-              aDirty, aDest, aFill, aAnchor,
-              CSSIntRect(0, 0,
-                         nsPresContext::AppUnitsToIntCSSPixels(mSize.width),
-                         nsPresContext::AppUnitsToIntCSSPixels(mSize.height)));
+  Draw(aPresContext, aRenderingContext,
+       aDirty, aDest, aFill, aAnchor,
+       CSSIntRect(0, 0,
+                  nsPresContext::AppUnitsToIntCSSPixels(mSize.width),
+                  nsPresContext::AppUnitsToIntCSSPixels(mSize.height)));
 }
 
 /**
  * Compute the size and position of the master copy of the image. I.e., a single
  * tile used to fill the dest rect.
  * aFill The destination rect to be filled
  * aHFill and aVFill are the repeat patterns for the component -
  * NS_STYLE_BORDER_IMAGE_REPEAT_* - i.e., how a tiling unit is used to fill aFill
--- a/layout/base/nsCSSRendering.h
+++ b/layout/base/nsCSSRendering.h
@@ -5,17 +5,16 @@
 
 /* utility functions for drawing borders and backgrounds */
 
 #ifndef nsCSSRendering_h___
 #define nsCSSRendering_h___
 
 #include "gfxBlur.h"
 #include "gfxContext.h"
-#include "imgIContainer.h"
 #include "mozilla/gfx/PathHelpers.h"
 #include "mozilla/gfx/Rect.h"
 #include "nsLayoutUtils.h"
 #include "nsStyleStruct.h"
 #include "nsIFrame.h"
 
 class gfxDrawable;
 class nsStyleContext;
@@ -105,17 +104,16 @@ struct CSSSizeOrRatio
  * 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(),
  * SetSize(), and Draw*().
  */
 class nsImageRenderer {
 public:
-  typedef mozilla::image::DrawResult DrawResult;
   typedef mozilla::layers::LayerManager LayerManager;
   typedef mozilla::layers::ImageContainer ImageContainer;
 
   enum {
     FLAG_SYNC_DECODE_IMAGES = 0x01,
     FLAG_PAINTING_TO_WINDOW = 0x02
   };
   enum FitType
@@ -199,22 +197,22 @@ public:
   void SetPreferredSize(const mozilla::CSSSizeOrRatio& aIntrinsicSize,
                         const nsSize& aDefaultSize);
 
   /**
    * Draws the image to the target rendering context using background-specific
    * arguments.
    * @see nsLayoutUtils::DrawImage() for parameters.
    */
-  DrawResult DrawBackground(nsPresContext*       aPresContext,
-                            nsRenderingContext&  aRenderingContext,
-                            const nsRect&        aDest,
-                            const nsRect&        aFill,
-                            const nsPoint&       aAnchor,
-                            const nsRect&        aDirty);
+  void DrawBackground(nsPresContext*       aPresContext,
+                      nsRenderingContext&  aRenderingContext,
+                      const nsRect&        aDest,
+                      const nsRect&        aFill,
+                      const nsPoint&       aAnchor,
+                      const nsRect&        aDirty);
 
   /**
    * Draw the image to a single component of a border-image style rendering.
    * aFill The destination rect to be drawn into
    * aSrc is the part of the image to be rendered into a tile (aUnitSize in
    * aFill), if aSrc and the dest tile are different sizes, the image will be
    * scaled to map aSrc onto the dest tile.
    * aHFill and aVFill are the repeat patterns for the component -
@@ -244,23 +242,23 @@ public:
 private:
   /**
    * Draws the image to the target rendering context.
    * aSrc is a rect on the source image which will be mapped to aDest; it's
    * currently only used for gradients.
    *
    * @see nsLayoutUtils::DrawImage() for other parameters.
    */
-  DrawResult Draw(nsPresContext*       aPresContext,
-                  nsRenderingContext&  aRenderingContext,
-                  const nsRect&        aDirtyRect,
-                  const nsRect&        aDest,
-                  const nsRect&        aFill,
-                  const nsPoint&       aAnchor,
-                  const mozilla::CSSIntRect& aSrc);
+  void Draw(nsPresContext*       aPresContext,
+            nsRenderingContext&  aRenderingContext,
+            const nsRect&        aDirtyRect,
+            const nsRect&        aDest,
+            const nsRect&        aFill,
+            const nsPoint&       aAnchor,
+            const mozilla::CSSIntRect& aSrc);
 
   /**
    * Helper method for creating a gfxDrawable from mPaintServerFrame or 
    * mImageElementSurface.
    * Requires mType is eStyleImageType_Element.
    * Returns null if we cannot create the drawable.
    */
   already_AddRefed<gfxDrawable> DrawableForElement(const nsRect& aImageRect,
@@ -318,17 +316,16 @@ struct nsBackgroundLayerState {
   gfxContext::GraphicsOperator mCompositingOp;
 };
 
 struct nsCSSRendering {
   typedef mozilla::gfx::DrawTarget DrawTarget;
   typedef mozilla::gfx::Float Float;
   typedef mozilla::gfx::Rect Rect;
   typedef mozilla::gfx::RectCornerRadii RectCornerRadii;
-  typedef mozilla::image::DrawResult DrawResult;
   typedef nsIFrame::Sides Sides;
 
   /**
    * Initialize any static variables used by nsCSSRendering.
    */
   static void Init();
   
   /**
@@ -552,58 +549,70 @@ struct nsCSSRendering {
      */
     PAINTBG_SYNC_DECODE_IMAGES = 0x02,
     /**
      * When this flag is passed, painting will go to the screen so we can
      * take advantage of the fact that it will be clipped to the viewport.
      */
     PAINTBG_TO_WINDOW = 0x04
   };
-  static DrawResult PaintBackground(nsPresContext* aPresContext,
-                                    nsRenderingContext& aRenderingContext,
-                                    nsIFrame* aForFrame,
-                                    const nsRect& aDirtyRect,
-                                    const nsRect& aBorderArea,
-                                    uint32_t aFlags,
-                                    nsRect* aBGClipRect = nullptr,
-                                    int32_t aLayer = -1);
+  static void PaintBackground(nsPresContext* aPresContext,
+                              nsRenderingContext& aRenderingContext,
+                              nsIFrame* aForFrame,
+                              const nsRect& aDirtyRect,
+                              const nsRect& aBorderArea,
+                              uint32_t aFlags,
+                              nsRect* aBGClipRect = nullptr,
+                              int32_t aLayer = -1);
 
   /**
    * Same as |PaintBackground|, except using the provided style structs.
    * This short-circuits the code that ensures that the root element's
    * background is drawn on the canvas.
    * The aLayer parameter allows you to paint a single layer of the background.
    * The default value for aLayer, -1, means that all layers will be painted.
    * The background color will only be painted if the back-most layer is also
    * being painted.
    */
-  static DrawResult PaintBackgroundWithSC(nsPresContext* aPresContext,
-                                          nsRenderingContext& aRenderingContext,
-                                          nsIFrame* aForFrame,
-                                          const nsRect& aDirtyRect,
-                                          const nsRect& aBorderArea,
-                                          nsStyleContext *aStyleContext,
-                                          const nsStyleBorder& aBorder,
-                                          uint32_t aFlags,
-                                          nsRect* aBGClipRect = nullptr,
-                                          int32_t aLayer = -1);
+  static void PaintBackgroundWithSC(nsPresContext* aPresContext,
+                                    nsRenderingContext& aRenderingContext,
+                                    nsIFrame* aForFrame,
+                                    const nsRect& aDirtyRect,
+                                    const nsRect& aBorderArea,
+                                    nsStyleContext *aStyleContext,
+                                    const nsStyleBorder& aBorder,
+                                    uint32_t aFlags,
+                                    nsRect* aBGClipRect = nullptr,
+                                    int32_t aLayer = -1);
 
   /**
    * Returns the rectangle covered by the given background layer image, taking
    * into account background positioning, sizing, and repetition, but not
    * clipping.
    */
   static nsRect GetBackgroundLayerRect(nsPresContext* aPresContext,
                                        nsIFrame* aForFrame,
                                        const nsRect& aBorderArea,
                                        const nsRect& aClipRect,
                                        const nsStyleBackground::Layer& aLayer,
                                        uint32_t aFlags);
 
   /**
+   * Checks if image in layer aLayer of aBackground is currently decoded.
+   */
+  static bool IsBackgroundImageDecodedForStyleContextAndLayer(
+    const nsStyleBackground *aBackground, uint32_t aLayer);
+
+  /**
+   * Checks if all images that are part of the background for aFrame are
+   * currently decoded.
+   */
+  static bool AreAllBackgroundImagesDecodedForFrame(nsIFrame* aFrame);
+
+  /**
    * Called when we start creating a display list. The frame tree will not
    * change until a matching EndFrameTreeLocked is called.
    */
   static void BeginFrameTreesLocked();
   /**
    * Called when we've finished using a display list. When all
    * BeginFrameTreeLocked calls have been balanced by an EndFrameTreeLocked,
    * the frame tree may start changing again.
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -1967,16 +1967,30 @@ nsDisplayItem::nsDisplayItem(nsDisplayLi
   NS_ASSERTION(aBuilder->GetDirtyRect().width >= 0 ||
                !aBuilder->IsForPainting(), "dirty rect not set");
   // The dirty rect is for mCurrentFrame, so we have to use
   // mCurrentOffsetToReferenceFrame
   mVisibleRect = aBuilder->GetDirtyRect() +
       aBuilder->GetCurrentFrameOffsetToReferenceFrame();
 }
 
+void
+nsDisplayItem::AddInvalidRegionForSyncDecodeBackgroundImages(
+  nsDisplayListBuilder* aBuilder,
+  const nsDisplayItemGeometry* aGeometry,
+  nsRegion* aInvalidRegion)
+{
+  if (aBuilder->ShouldSyncDecodeImages()) {
+    if (!nsCSSRendering::AreAllBackgroundImagesDecodedForFrame(mFrame)) {
+      bool snap;
+      aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
+    }
+  }
+}
+
 /* static */ bool
 nsDisplayItem::ForceActiveLayers()
 {
   static bool sForce = false;
   static bool sForceCached = false;
 
   if (!sForceCached) {
     Preferences::AddBoolVarCache(&sForce, "layers.force-active", false);
@@ -2489,21 +2503,16 @@ nsDisplayBackgroundImage::BuildLayer(nsD
 
 void
 nsDisplayBackgroundImage::ConfigureLayer(ImageLayer* aLayer, const nsIntPoint& aOffset)
 {
   aLayer->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(mFrame));
 
   mozilla::gfx::IntSize imageSize = mImageContainer->GetCurrentSize();
   NS_ASSERTION(imageSize.width != 0 && imageSize.height != 0, "Invalid image size!");
-  if (imageSize.width > 0 && imageSize.height > 0) {
-    // We're actually using the ImageContainer. Let our frame know that it
-    // should consider itself to have painted successfully.
-    nsDisplayBackgroundGeometry::UpdateDrawResult(this, DrawResult::SUCCESS);
-  }
 
   gfxPoint p = mDestRect.TopLeft() + aOffset;
   Matrix transform = Matrix::Translation(p.x, p.y);
   transform.PreScale(mDestRect.width / imageSize.width,
                      mDestRect.height / imageSize.height);
   aLayer->SetBaseTransform(gfx::Matrix4x4::From2D(transform));
 }
 
@@ -2663,23 +2672,21 @@ nsDisplayBackgroundImage::Paint(nsDispla
 void
 nsDisplayBackgroundImage::PaintInternal(nsDisplayListBuilder* aBuilder,
                                         nsRenderingContext* aCtx, const nsRect& aBounds,
                                         nsRect* aClipRect) {
   nsPoint offset = ToReferenceFrame();
   uint32_t flags = aBuilder->GetBackgroundPaintFlags();
   CheckForBorderItem(this, flags);
 
-  DrawResult result =
-    nsCSSRendering::PaintBackground(mFrame->PresContext(), *aCtx, mFrame,
-                                    aBounds,
-                                    nsRect(offset, mFrame->GetSize()),
-                                    flags, aClipRect, mLayer);
-
-  nsDisplayBackgroundGeometry::UpdateDrawResult(this, result);
+  nsCSSRendering::PaintBackground(mFrame->PresContext(), *aCtx, mFrame,
+                                  aBounds,
+                                  nsRect(offset, mFrame->GetSize()),
+                                  flags, aClipRect, mLayer);
+
 }
 
 void nsDisplayBackgroundImage::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                                          const nsDisplayItemGeometry* aGeometry,
                                                          nsRegion* aInvalidRegion)
 {
   if (!mBackgroundStyle) {
     return;
@@ -2698,19 +2705,18 @@ void nsDisplayBackgroundImage::ComputeIn
     aInvalidRegion->Or(bounds, geometry->mBounds);
 
     if (positioningArea.Size() != geometry->mPositioningArea.Size()) {
       NotifyRenderingChanged();
     }
     return;
   }
   if (aBuilder->ShouldSyncDecodeImages()) {
-    const nsStyleImage& image = mBackgroundStyle->mLayers[mLayer].mImage;
-    if (image.GetType() == eStyleImageType_Image &&
-        geometry->ShouldInvalidateToSyncDecodeImages()) {
+    if (mBackgroundStyle &&
+        !nsCSSRendering::IsBackgroundImageDecodedForStyleContextAndLayer(mBackgroundStyle, mLayer)) {
       aInvalidRegion->Or(*aInvalidRegion, bounds);
 
       NotifyRenderingChanged();
     }
   }
   if (!bounds.IsEqualInterior(geometry->mBounds)) {
     // Positioning area is unchanged, so invalidate just the change in the
     // painting area.
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -1141,16 +1141,26 @@ public:
         aInvalidRegion->Or(aGeometry->mBounds, bounds);
       } else {
         aInvalidRegion->Xor(aGeometry->mBounds, bounds);
       }
     }
   }
 
   /**
+   * For display items types that just draw a background we use this function
+   * to do any invalidation that might be needed if we are asked to sync decode
+   * images.
+   */
+  void AddInvalidRegionForSyncDecodeBackgroundImages(
+    nsDisplayListBuilder* aBuilder,
+    const nsDisplayItemGeometry* aGeometry,
+    nsRegion* aInvalidRegion);
+
+  /**
    * Called when the area rendered by this display item has changed (been
    * invalidated or changed geometry) since the last paint. This includes
    * when the display item was not rendered at all in the last paint.
    * It does NOT get called when a display item was being rendered and no
    * longer is, because generally that means there is no display item to
    * call this method on.
    */
   virtual void NotifyRenderingChanged() {}
--- a/layout/base/nsDisplayListInvalidation.cpp
+++ b/layout/base/nsDisplayListInvalidation.cpp
@@ -19,22 +19,16 @@ nsDisplayItemGeometry::~nsDisplayItemGeo
   MOZ_COUNT_DTOR(nsDisplayItemGeometry);
 }
 
 nsDisplayItemGenericGeometry::nsDisplayItemGenericGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder)
   : nsDisplayItemGeometry(aItem, aBuilder)
   , mBorderRect(aItem->GetBorderRect())
 {}
 
-bool
-ShouldSyncDecodeImages(nsDisplayListBuilder* aBuilder)
-{
-  return aBuilder->ShouldSyncDecodeImages();
-}
-
 void
 nsDisplayItemGenericGeometry::MoveBy(const nsPoint& aOffset)
 {
   nsDisplayItemGeometry::MoveBy(aOffset);
   mBorderRect.MoveBy(aOffset);
 }
 
 nsDisplayItemBoundsGeometry::nsDisplayItemBoundsGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder)
@@ -54,17 +48,16 @@ nsDisplayBorderGeometry::MoveBy(const ns
 {
   nsDisplayItemGeometry::MoveBy(aOffset);
   mContentRect.MoveBy(aOffset);
 }
 
 nsDisplayBackgroundGeometry::nsDisplayBackgroundGeometry(nsDisplayBackgroundImage* aItem,
                                                          nsDisplayListBuilder* aBuilder)
   : nsDisplayItemGeometry(aItem, aBuilder)
-  , nsImageGeometryMixin(aItem, aBuilder)
   , mPositioningArea(aItem->GetPositioningArea())
 {}
 
 void
 nsDisplayBackgroundGeometry::MoveBy(const nsPoint& aOffset)
 {
   nsDisplayItemGeometry::MoveBy(aOffset);
   mPositioningArea.MoveBy(aOffset);
--- a/layout/base/nsDisplayListInvalidation.h
+++ b/layout/base/nsDisplayListInvalidation.h
@@ -68,101 +68,70 @@ class nsDisplayItemGenericGeometry : pub
 public:
   nsDisplayItemGenericGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder);
 
   virtual void MoveBy(const nsPoint& aOffset) MOZ_OVERRIDE;
 
   nsRect mBorderRect;
 };
 
-bool ShouldSyncDecodeImages(nsDisplayListBuilder* aBuilder);
-
 /**
  * nsImageGeometryMixin is a mixin for geometry items that draw images. Geometry
  * items that include this mixin can track drawing results and use that
  * information to inform invalidation decisions.
  *
  * This mixin uses CRTP; its template parameter should be the type of the class
  * that is inheriting from it. See nsDisplayItemGenericImageGeometry for an
  * example.
  */
 template <typename T>
 class nsImageGeometryMixin
 {
 public:
-  nsImageGeometryMixin(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder)
+  explicit nsImageGeometryMixin(nsDisplayItem* aItem)
     : mLastDrawResult(mozilla::image::DrawResult::NOT_READY)
-    , mWaitingForPaint(false)
   {
-    // Transfer state from the previous version of this geometry item.
     auto lastGeometry =
       static_cast<T*>(mozilla::FrameLayerBuilder::GetMostRecentGeometry(aItem));
     if (lastGeometry) {
-      mLastDrawResult = lastGeometry->mLastDrawResult;
-      mWaitingForPaint = lastGeometry->mWaitingForPaint;
-    }
-
-    // If our display item is going to invalidate to trigger sync decoding of
-    // images, mark ourselves as waiting for a paint. If we actually get
-    // painted, UpdateDrawResult will get called, and we'll clear the flag.
-    if (ShouldSyncDecodeImages(aBuilder) &&
-        ShouldInvalidateToSyncDecodeImages()) {
-      mWaitingForPaint = true;
+      mLastDrawResult = lastGeometry->LastDrawResult();
     }
   }
 
   static void UpdateDrawResult(nsDisplayItem* aItem,
                                mozilla::image::DrawResult aResult)
   {
     auto lastGeometry =
       static_cast<T*>(mozilla::FrameLayerBuilder::GetMostRecentGeometry(aItem));
     if (lastGeometry) {
       lastGeometry->mLastDrawResult = aResult;
-      lastGeometry->mWaitingForPaint = false;
     }
   }
 
-  bool ShouldInvalidateToSyncDecodeImages() const
-  {
-    if (mWaitingForPaint) {
-      // We previously invalidated for sync decoding and haven't gotten painted
-      // since them. This suggests that our display item is completely occluded
-      // and there's no point in invalidating again - and because the reftest
-      // harness takes a new snapshot every time we invalidate, doing so might
-      // lead to an invalidation loop if we're in a reftest.
-      return false;
-    }
-
-    if (mLastDrawResult == mozilla::image::DrawResult::SUCCESS) {
-      return false;
-    }
-
-    return true;
-  }
+  mozilla::image::DrawResult LastDrawResult() const { return mLastDrawResult; }
 
 private:
   mozilla::image::DrawResult mLastDrawResult;
-  bool mWaitingForPaint;
 };
 
 /**
  * nsDisplayItemGenericImageGeometry is a generic geometry item class that
  * includes nsImageGeometryMixin.
  *
  * This should be sufficient for most display items that draw images.
  */
 class nsDisplayItemGenericImageGeometry
   : public nsDisplayItemGenericGeometry
   , public nsImageGeometryMixin<nsDisplayItemGenericImageGeometry>
 {
 public:
   nsDisplayItemGenericImageGeometry(nsDisplayItem* aItem,
                                     nsDisplayListBuilder* aBuilder)
     : nsDisplayItemGenericGeometry(aItem, aBuilder)
-    , nsImageGeometryMixin(aItem, aBuilder)
+    , nsImageGeometryMixin(aItem)
   { }
 };
 
 class nsDisplayItemBoundsGeometry : public nsDisplayItemGeometry
 {
 public:
   nsDisplayItemBoundsGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder);
 
@@ -174,19 +143,17 @@ class nsDisplayBorderGeometry : public n
 public:
   nsDisplayBorderGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder);
 
   virtual void MoveBy(const nsPoint& aOffset) MOZ_OVERRIDE;
 
   nsRect mContentRect;
 };
 
-class nsDisplayBackgroundGeometry
-  : public nsDisplayItemGeometry
-  , public nsImageGeometryMixin<nsDisplayBackgroundGeometry>
+class nsDisplayBackgroundGeometry : public nsDisplayItemGeometry
 {
 public:
   nsDisplayBackgroundGeometry(nsDisplayBackgroundImage* aItem, nsDisplayListBuilder* aBuilder);
 
   virtual void MoveBy(const nsPoint& aOffset) MOZ_OVERRIDE;
 
   nsRect mPositioningArea;
 };
--- a/layout/forms/nsButtonFrameRenderer.cpp
+++ b/layout/forms/nsButtonFrameRenderer.cpp
@@ -14,18 +14,16 @@
 #include "nsFrame.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/dom/Element.h"
 
 #define ACTIVE   "active"
 #define HOVER    "hover"
 #define FOCUS    "focus"
 
-using namespace mozilla::image;
-
 nsButtonFrameRenderer::nsButtonFrameRenderer()
 {
   MOZ_COUNT_CTOR(nsButtonFrameRenderer);
 }
 
 nsButtonFrameRenderer::~nsButtonFrameRenderer()
 {
   MOZ_COUNT_DTOR(nsButtonFrameRenderer);
@@ -127,17 +125,16 @@ public:
                        HitTestState* aState,
                        nsTArray<nsIFrame*> *aOutFrames) MOZ_OVERRIDE {
     aOutFrames->AppendElement(mFrame);
   }
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      nsRenderingContext* aCtx) MOZ_OVERRIDE;
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
                            bool* aSnap) MOZ_OVERRIDE;
-  virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE;
   virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                          const nsDisplayItemGeometry* aGeometry,
                                          nsRegion *aInvalidRegion) MOZ_OVERRIDE;
   NS_DISPLAY_DECL_NAME("ButtonBorderBackground", TYPE_BUTTON_BORDER_BACKGROUND)
 private:
   nsButtonFrameRenderer* mBFR;
 };
 
@@ -163,52 +160,36 @@ public:
 
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      nsRenderingContext* aCtx) MOZ_OVERRIDE;
   NS_DISPLAY_DECL_NAME("ButtonForeground", TYPE_BUTTON_FOREGROUND)
 private:
   nsButtonFrameRenderer* mBFR;
 };
 
-nsDisplayItemGeometry*
-nsDisplayButtonBorderBackground::AllocateGeometry(nsDisplayListBuilder* aBuilder)
-{
-  return new nsDisplayItemGenericImageGeometry(this, aBuilder);
-}
-
 void
 nsDisplayButtonBorderBackground::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                                            const nsDisplayItemGeometry* aGeometry,
                                                            nsRegion *aInvalidRegion)
 {
-  auto geometry =
-    static_cast<const nsDisplayItemGenericImageGeometry*>(aGeometry);
-
-  if (aBuilder->ShouldSyncDecodeImages() &&
-      geometry->ShouldInvalidateToSyncDecodeImages()) {
-    bool snap;
-    aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
-  }
+  AddInvalidRegionForSyncDecodeBackgroundImages(aBuilder, aGeometry, aInvalidRegion);
 
   nsDisplayItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
 }
 
 void nsDisplayButtonBorderBackground::Paint(nsDisplayListBuilder* aBuilder,
                                             nsRenderingContext* aCtx)
 {
   NS_ASSERTION(mFrame, "No frame?");
   nsPresContext* pc = mFrame->PresContext();
   nsRect r = nsRect(ToReferenceFrame(), mFrame->GetSize());
   
   // draw the border and background inside the focus and outline borders
-  DrawResult result =
-    mBFR->PaintBorderAndBackground(pc, *aCtx, mVisibleRect, r,
-                                   aBuilder->GetBackgroundPaintFlags());
-
-  nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, result);
+  mBFR->PaintBorderAndBackground(pc, *aCtx, mVisibleRect, r,
+                                 aBuilder->GetBackgroundPaintFlags());
 }
 
 void nsDisplayButtonForeground::Paint(nsDisplayListBuilder* aBuilder,
                                       nsRenderingContext* aCtx)
 {
   nsPresContext *presContext = mFrame->PresContext();
   const nsStyleDisplay *disp = mFrame->StyleDisplay();
   if (!mFrame->IsThemed(disp) ||
@@ -274,39 +255,36 @@ nsButtonFrameRenderer::PaintOutlineAndFo
     GetButtonInnerFocusRect(aRect, rect);
 
     nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, mFrame,
                                 aDirtyRect, rect, mInnerFocusStyle);
   }
 }
 
 
-DrawResult
+void
 nsButtonFrameRenderer::PaintBorderAndBackground(nsPresContext* aPresContext,
           nsRenderingContext& aRenderingContext,
           const nsRect& aDirtyRect,
           const nsRect& aRect,
           uint32_t aBGFlags)
 
 {
   // get the button rect this is inside the focus and outline rects
   nsRect buttonRect;
   GetButtonRect(aRect, buttonRect);
 
   nsStyleContext* context = mFrame->StyleContext();
 
-  DrawResult result =
-    nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, mFrame,
-                                    aDirtyRect, buttonRect, aBGFlags);
+  nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, mFrame,
+                                  aDirtyRect, buttonRect, aBGFlags);
   nsCSSRendering::PaintBoxShadowInner(aPresContext, aRenderingContext,
                                       mFrame, buttonRect, aDirtyRect);
   nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, mFrame,
                               aDirtyRect, buttonRect, context);
-
-  return result;
 }
 
 
 void
 nsButtonFrameRenderer::GetButtonOuterFocusRect(const nsRect& aRect, nsRect& focusRect)
 {
   focusRect = aRect;
 }
--- a/layout/forms/nsButtonFrameRenderer.h
+++ b/layout/forms/nsButtonFrameRenderer.h
@@ -1,17 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsButtonFrameRenderer_h___
 #define nsButtonFrameRenderer_h___
 
-#include "imgIContainer.h"
 #include "nsAutoPtr.h"
 #include "nsMargin.h"
 
 class nsIFrame;
 class nsFrame;
 class nsDisplayList;
 class nsDisplayListBuilder;
 class nsPresContext;
@@ -20,18 +19,16 @@ struct nsRect;
 class nsStyleContext;
 
 
 #define NS_BUTTON_RENDERER_FOCUS_INNER_CONTEXT_INDEX  0
 #define NS_BUTTON_RENDERER_FOCUS_OUTER_CONTEXT_INDEX  1
 #define NS_BUTTON_RENDERER_LAST_CONTEXT_INDEX   NS_BUTTON_RENDERER_FOCUS_OUTER_CONTEXT_INDEX
 
 class nsButtonFrameRenderer {
-  typedef mozilla::image::DrawResult DrawResult;
-
 public:
 
   nsButtonFrameRenderer();
   ~nsButtonFrameRenderer();
 
   /**
    * Create display list items for the button
    */
@@ -39,21 +36,21 @@ public:
                          nsDisplayList* aBackground, nsDisplayList* aForeground);
 
 
   void PaintOutlineAndFocusBorders(nsPresContext* aPresContext,
                                    nsRenderingContext& aRenderingContext,
                                    const nsRect& aDirtyRect,
                                    const nsRect& aRect);
 
-  DrawResult PaintBorderAndBackground(nsPresContext* aPresContext,
-                                      nsRenderingContext& aRenderingContext,
-                                      const nsRect& aDirtyRect,
-                                      const nsRect& aRect,
-                                      uint32_t aBGFlags);
+  void PaintBorderAndBackground(nsPresContext* aPresContext,
+                                nsRenderingContext& aRenderingContext,
+                                const nsRect& aDirtyRect,
+                                const nsRect& aRect,
+                                uint32_t aBGFlags);
 
   void SetFrame(nsFrame* aFrame, nsPresContext* aPresContext);
  
   void SetDisabled(bool aDisabled, bool notify);
 
   bool isActive();
   bool isDisabled();
 
--- a/layout/forms/nsFieldSetFrame.cpp
+++ b/layout/forms/nsFieldSetFrame.cpp
@@ -19,17 +19,16 @@
 #include "nsDisplayList.h"
 #include "nsRenderingContext.h"
 #include "nsIScrollableFrame.h"
 #include "mozilla/Likely.h"
 #include "mozilla/Maybe.h"
 
 using namespace mozilla;
 using namespace mozilla::gfx;
-using namespace mozilla::image;
 using namespace mozilla::layout;
 
 nsContainerFrame*
 NS_NewFieldSetFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) nsFieldSetFrame(aContext);
 }
 
@@ -98,17 +97,16 @@ public:
   }
 #endif
 
   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                        HitTestState* aState,
                        nsTArray<nsIFrame*> *aOutFrames) MOZ_OVERRIDE;
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      nsRenderingContext* aCtx) MOZ_OVERRIDE;
-  virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE;
   virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                          const nsDisplayItemGeometry* aGeometry,
                                          nsRegion *aInvalidRegion) MOZ_OVERRIDE;
   NS_DISPLAY_DECL_NAME("FieldSetBorderBackground", TYPE_FIELDSET_BORDER_BACKGROUND)
 };
 
 void nsDisplayFieldSetBorderBackground::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                                                 HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames)
@@ -118,42 +116,27 @@ void nsDisplayFieldSetBorderBackground::
   // It's not clear whether this is correct.
   aOutFrames->AppendElement(mFrame);
 }
 
 void
 nsDisplayFieldSetBorderBackground::Paint(nsDisplayListBuilder* aBuilder,
                                          nsRenderingContext* aCtx)
 {
-  DrawResult result = static_cast<nsFieldSetFrame*>(mFrame)->
+  static_cast<nsFieldSetFrame*>(mFrame)->
     PaintBorderBackground(*aCtx, ToReferenceFrame(),
                           mVisibleRect, aBuilder->GetBackgroundPaintFlags());
-
-  nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, result);
-}
-
-nsDisplayItemGeometry*
-nsDisplayFieldSetBorderBackground::AllocateGeometry(nsDisplayListBuilder* aBuilder)
-{
-  return new nsDisplayItemGenericImageGeometry(this, aBuilder);
 }
 
 void
 nsDisplayFieldSetBorderBackground::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                                              const nsDisplayItemGeometry* aGeometry,
                                                              nsRegion *aInvalidRegion)
 {
-  auto geometry =
-    static_cast<const nsDisplayItemGenericImageGeometry*>(aGeometry);
-
-  if (aBuilder->ShouldSyncDecodeImages() &&
-      geometry->ShouldInvalidateToSyncDecodeImages()) {
-    bool snap;
-    aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
-  }
+  AddInvalidRegionForSyncDecodeBackgroundImages(aBuilder, aGeometry, aInvalidRegion);
 
   nsDisplayItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
 }
 
 void
 nsFieldSetFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                   const nsRect&           aDirtyRect,
                                   const nsDisplayListSet& aLists) {
@@ -200,32 +183,31 @@ nsFieldSetFrame::BuildDisplayList(nsDisp
   }
   // Put the inner frame's display items on the master list. Note that this
   // moves its border/background display items to our BorderBackground() list,
   // which isn't really correct, but it's OK because the inner frame is
   // anonymous and can't have its own border and background.
   contentDisplayItems.MoveTo(aLists);
 }
 
-DrawResult
+void
 nsFieldSetFrame::PaintBorderBackground(nsRenderingContext& aRenderingContext,
     nsPoint aPt, const nsRect& aDirtyRect, uint32_t aBGFlags)
 {
   // if the border is smaller than the legend. Move the border down
   // to be centered on the legend. 
   // FIXME: This means border-radius clamping is incorrect; we should
   // override nsIFrame::GetBorderRadii.
   nsRect rect = VisualBorderRectRelativeToSelf();
   nscoord yoff = rect.y;
   rect += aPt;
   nsPresContext* presContext = PresContext();
 
-  DrawResult result =
-    nsCSSRendering::PaintBackground(presContext, aRenderingContext, this,
-                                    aDirtyRect, rect, aBGFlags);
+  nsCSSRendering::PaintBackground(presContext, aRenderingContext, this,
+                                  aDirtyRect, rect, aBGFlags);
 
   nsCSSRendering::PaintBoxShadowInner(presContext, aRenderingContext,
                                       this, rect, aDirtyRect);
 
    if (nsIFrame* legend = GetLegend()) {
      nscoord topBorder = StyleBorder()->GetComputedBorderWidth(NS_SIDE_TOP);
 
     // Use the rect of the legend frame, not mLegendRect, so we draw our
@@ -276,18 +258,16 @@ nsFieldSetFrame::PaintBorderBackground(n
     gfx->Restore();
   } else {
 
     nsCSSRendering::PaintBorder(presContext, aRenderingContext, this,
                                 aDirtyRect,
                                 nsRect(aPt, mRect.Size()),
                                 mStyleContext);
   }
-
-  return result;
 }
 
 nscoord
 nsFieldSetFrame::GetIntrinsicISize(nsRenderingContext* aRenderingContext,
                                    nsLayoutUtils::IntrinsicISizeType aType)
 {
   nscoord legendWidth = 0;
   nscoord contentWidth = 0;
--- a/layout/forms/nsFieldSetFrame.h
+++ b/layout/forms/nsFieldSetFrame.h
@@ -2,23 +2,20 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsFieldSetFrame_h___
 #define nsFieldSetFrame_h___
 
 #include "mozilla/Attributes.h"
-#include "imgIContainer.h"
 #include "nsContainerFrame.h"
 
 class nsFieldSetFrame MOZ_FINAL : public nsContainerFrame
 {
-  typedef mozilla::image::DrawResult DrawResult;
-
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
   explicit nsFieldSetFrame(nsStyleContext* aContext);
 
   nscoord
     GetIntrinsicISize(nsRenderingContext* aRenderingContext,
                       nsLayoutUtils::IntrinsicISizeType);
@@ -45,19 +42,18 @@ public:
                       nsHTMLReflowMetrics&     aDesiredSize,
                       const nsHTMLReflowState& aReflowState,
                       nsReflowStatus&          aStatus) MOZ_OVERRIDE;
                                
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsRect&           aDirtyRect,
                                 const nsDisplayListSet& aLists) MOZ_OVERRIDE;
 
-  DrawResult PaintBorderBackground(nsRenderingContext& aRenderingContext,
-                                   nsPoint aPt, const nsRect& aDirtyRect,
-                                   uint32_t aBGFlags);
+  void PaintBorderBackground(nsRenderingContext& aRenderingContext,
+    nsPoint aPt, const nsRect& aDirtyRect, uint32_t aBGFlags);
 
 #ifdef DEBUG
   virtual void SetInitialChildList(ChildListID    aListID,
                                    nsFrameList&   aChildList) MOZ_OVERRIDE;
   virtual void AppendFrames(ChildListID    aListID,
                             nsFrameList&   aFrameList) MOZ_OVERRIDE;
   virtual void InsertFrames(ChildListID    aListID,
                             nsIFrame*      aPrevFrame,
--- a/layout/generic/nsBulletFrame.cpp
+++ b/layout/generic/nsBulletFrame.cpp
@@ -172,17 +172,17 @@ nsBulletFrame::DidSetStyleContext(nsStyl
 
 class nsDisplayBulletGeometry
   : public nsDisplayItemGenericGeometry
   , public nsImageGeometryMixin<nsDisplayBulletGeometry>
 {
 public:
   nsDisplayBulletGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder)
     : nsDisplayItemGenericGeometry(aItem, aBuilder)
-    , nsImageGeometryMixin(aItem, aBuilder)
+    , nsImageGeometryMixin(aItem)
   {
     nsBulletFrame* f = static_cast<nsBulletFrame*>(aItem->Frame());
     mOrdinal = f->GetOrdinal();
   }
 
   int32_t mOrdinal;
 };
 
@@ -234,17 +234,17 @@ public:
     if (f->GetOrdinal() != geometry->mOrdinal) {
       bool snap;
       aInvalidRegion->Or(geometry->mBounds, GetBounds(aBuilder, &snap));
       return;
     }
 
     nsCOMPtr<imgIContainer> image = f->GetImage();
     if (aBuilder->ShouldSyncDecodeImages() && image &&
-        geometry->ShouldInvalidateToSyncDecodeImages()) {
+        geometry->LastDrawResult() != DrawResult::SUCCESS) {
       bool snap;
       aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
     }
 
     return nsDisplayItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
   }
 };
 
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -1377,17 +1377,17 @@ void
 nsDisplayImage::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                           const nsDisplayItemGeometry* aGeometry,
                                           nsRegion* aInvalidRegion)
 {
   auto geometry =
     static_cast<const nsDisplayItemGenericImageGeometry*>(aGeometry);
 
   if (aBuilder->ShouldSyncDecodeImages() &&
-      geometry->ShouldInvalidateToSyncDecodeImages()) {
+      geometry->LastDrawResult() != DrawResult::SUCCESS) {
     bool snap;
     aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
   }
 
   nsDisplayImageContainer::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
 }
 
 already_AddRefed<ImageContainer>
--- a/layout/mathml/nsMathMLChar.cpp
+++ b/layout/mathml/nsMathMLChar.cpp
@@ -36,17 +36,16 @@
 #include "nsMathMLOperators.h"
 #include <algorithm>
 
 #include "gfxMathTable.h"
 #include "nsUnicodeScriptCodes.h"
 
 using namespace mozilla;
 using namespace mozilla::gfx;
-using namespace mozilla::image;
 
 //#define NOISY_SEARCH 1
 
 // BUG 848725 Drawing failure with stretchy horizontal parenthesis when no fonts
 // are installed. "kMaxScaleFactor" is required to limit the scale for the
 // vertical and horizontal stretchy operators.
 static const float kMaxScaleFactor = 20.0;
 static const float kLargeOpFactor = float(M_SQRT2);
@@ -1881,64 +1880,46 @@ public:
     MOZ_COUNT_CTOR(nsDisplayMathMLCharBackground);
   }
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayMathMLCharBackground() {
     MOZ_COUNT_DTOR(nsDisplayMathMLCharBackground);
   }
 #endif
 
-  virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE;
   virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                          const nsDisplayItemGeometry* aGeometry,
                                          nsRegion *aInvalidRegion) MOZ_OVERRIDE;
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      nsRenderingContext* aCtx) MOZ_OVERRIDE;
   NS_DISPLAY_DECL_NAME("MathMLCharBackground", TYPE_MATHML_CHAR_BACKGROUND)
 private:
   nsStyleContext* mStyleContext;
   nsRect          mRect;
 };
 
-nsDisplayItemGeometry*
-nsDisplayMathMLCharBackground::AllocateGeometry(nsDisplayListBuilder* aBuilder)
-{
-  return new nsDisplayItemGenericImageGeometry(this, aBuilder);
-}
-
 void
 nsDisplayMathMLCharBackground::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                                          const nsDisplayItemGeometry* aGeometry,
                                                          nsRegion *aInvalidRegion)
 {
-  auto geometry =
-    static_cast<const nsDisplayItemGenericImageGeometry*>(aGeometry);
-
-  if (aBuilder->ShouldSyncDecodeImages() &&
-      geometry->ShouldInvalidateToSyncDecodeImages()) {
-    bool snap;
-    aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
-  }
+  AddInvalidRegionForSyncDecodeBackgroundImages(aBuilder, aGeometry, aInvalidRegion);
 
   nsDisplayItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
 }
 
 void nsDisplayMathMLCharBackground::Paint(nsDisplayListBuilder* aBuilder,
                                           nsRenderingContext* aCtx)
 {
   const nsStyleBorder* border = mStyleContext->StyleBorder();
   nsRect rect(mRect + ToReferenceFrame());
-
-  DrawResult result =
-    nsCSSRendering::PaintBackgroundWithSC(mFrame->PresContext(), *aCtx, mFrame,
-                                          mVisibleRect, rect,
-                                          mStyleContext, *border,
-                                          aBuilder->GetBackgroundPaintFlags());
-
-  nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, result);
+  nsCSSRendering::PaintBackgroundWithSC(mFrame->PresContext(), *aCtx, mFrame,
+                                        mVisibleRect, rect,
+                                        mStyleContext, *border,
+                                        aBuilder->GetBackgroundPaintFlags());
 }
 
 class nsDisplayMathMLCharForeground : public nsDisplayItem {
 public:
   nsDisplayMathMLCharForeground(nsDisplayListBuilder* aBuilder,
                                 nsIFrame* aFrame, nsMathMLChar* aChar,
 				                uint32_t aIndex, bool aIsSelected)
     : nsDisplayItem(aBuilder, aFrame), mChar(aChar), 
--- a/layout/tables/nsTableCellFrame.cpp
+++ b/layout/tables/nsTableCellFrame.cpp
@@ -35,17 +35,16 @@
 #include <algorithm>
 
 //TABLECELL SELECTION
 #include "nsFrameSelection.h"
 #include "mozilla/LookAndFeel.h"
 
 using namespace mozilla;
 using namespace mozilla::gfx;
-using namespace mozilla::image;
 
 nsTableCellFrame::nsTableCellFrame(nsStyleContext* aContext) :
   nsContainerFrame(aContext)
   , mDesiredSize(GetWritingMode())
 {
   mColIndex = 0;
   mPriorAvailWidth = 0;
 
@@ -359,38 +358,37 @@ nsTableCellFrame::DecorateForSelection(n
         StrokeLineWithSnapping(nsPoint(mRect.width - (2*onePixel), 2*onePixel),
                                nsPoint(mRect.width - (2*onePixel), mRect.height-onePixel),
                                appUnitsPerDevPixel, *drawTarget, color);
       }
     }
   }
 }
 
-DrawResult
+void
 nsTableCellFrame::PaintBackground(nsRenderingContext& aRenderingContext,
                                   const nsRect&        aDirtyRect,
                                   nsPoint              aPt,
                                   uint32_t             aFlags)
 {
   nsRect rect(aPt, GetSize());
-  return nsCSSRendering::PaintBackground(PresContext(), aRenderingContext, this,
-                                         aDirtyRect, rect, aFlags);
+  nsCSSRendering::PaintBackground(PresContext(), aRenderingContext, this,
+                                  aDirtyRect, rect, aFlags);
 }
 
 // Called by nsTablePainter
-DrawResult
+void
 nsTableCellFrame::PaintCellBackground(nsRenderingContext& aRenderingContext,
                                       const nsRect& aDirtyRect, nsPoint aPt,
                                       uint32_t aFlags)
 {
-  if (!StyleVisibility()->IsVisible()) {
-    return DrawResult::SUCCESS;
-  }
+  if (!StyleVisibility()->IsVisible())
+    return;
 
-  return PaintBackground(aRenderingContext, aDirtyRect, aPt, aFlags);
+  PaintBackground(aRenderingContext, aDirtyRect, aPt, aFlags);
 }
 
 nsresult
 nsTableCellFrame::ProcessBorders(nsTableFrame* aFrame,
                                  nsDisplayListBuilder* aBuilder,
                                  const nsDisplayListSet& aLists)
 {
   const nsStyleBorder* borderStyle = StyleBorder();
@@ -423,61 +421,50 @@ public:
                        HitTestState* aState,
                        nsTArray<nsIFrame*> *aOutFrames) MOZ_OVERRIDE {
     aOutFrames->AppendElement(mFrame);
   }
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      nsRenderingContext* aCtx) MOZ_OVERRIDE;
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
                            bool* aSnap) MOZ_OVERRIDE;
-  virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE;
   virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                          const nsDisplayItemGeometry* aGeometry,
                                          nsRegion *aInvalidRegion) MOZ_OVERRIDE;
 
   NS_DISPLAY_DECL_NAME("TableCellBackground", TYPE_TABLE_CELL_BACKGROUND)
 };
 
 void nsDisplayTableCellBackground::Paint(nsDisplayListBuilder* aBuilder,
                                          nsRenderingContext* aCtx)
 {
-  DrawResult result = static_cast<nsTableCellFrame*>(mFrame)->
+  static_cast<nsTableCellFrame*>(mFrame)->
     PaintBackground(*aCtx, mVisibleRect, ToReferenceFrame(),
                     aBuilder->GetBackgroundPaintFlags());
-
-  nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, result);
 }
 
 nsRect
 nsDisplayTableCellBackground::GetBounds(nsDisplayListBuilder* aBuilder,
                                         bool* aSnap)
 {
   // revert from nsDisplayTableItem's implementation ... cell backgrounds
   // don't overflow the cell
   return nsDisplayItem::GetBounds(aBuilder, aSnap);
 }
 
-nsDisplayItemGeometry*
-nsDisplayTableCellBackground::AllocateGeometry(nsDisplayListBuilder* aBuilder)
-{
-  return new nsDisplayItemGenericImageGeometry(this, aBuilder);
-}
-
 void
 nsDisplayTableCellBackground::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                                         const nsDisplayItemGeometry* aGeometry,
                                                         nsRegion *aInvalidRegion)
 {
-  auto geometry =
-    static_cast<const nsDisplayItemGenericImageGeometry*>(aGeometry);
-
-  if (aBuilder->ShouldSyncDecodeImages() &&
-      geometry->ShouldInvalidateToSyncDecodeImages()) {
-    bool snap;
-    aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
+  if (aBuilder->ShouldSyncDecodeImages()) {
+    if (!nsCSSRendering::AreAllBackgroundImagesDecodedForFrame(mFrame)) {
+      bool snap;
+      aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
+    }
   }
 
   nsDisplayTableItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
 }
 
 void nsTableCellFrame::InvalidateFrame(uint32_t aDisplayItemKey)
 {
   nsIFrame::InvalidateFrame(aDisplayItemKey);
@@ -1227,17 +1214,17 @@ nsBCTableCellFrame::GetBorderOverflow()
   halfBorder.top = BC_BORDER_TOP_HALF_COORD(p2t, mTopBorder);
   halfBorder.right = BC_BORDER_RIGHT_HALF_COORD(p2t, mRightBorder);
   halfBorder.bottom = BC_BORDER_BOTTOM_HALF_COORD(p2t, mBottomBorder);
   halfBorder.left = BC_BORDER_LEFT_HALF_COORD(p2t, mLeftBorder);
   return halfBorder;
 }
 
 
-DrawResult
+void
 nsBCTableCellFrame::PaintBackground(nsRenderingContext& aRenderingContext,
                                     const nsRect&        aDirtyRect,
                                     nsPoint              aPt,
                                     uint32_t             aFlags)
 {
   // make border-width reflect the half of the border-collapse
   // assigned border that's inside the cell
   nsMargin borderWidth;
@@ -1247,13 +1234,13 @@ nsBCTableCellFrame::PaintBackground(nsRe
 
   NS_FOR_CSS_SIDES(side) {
     myBorder.SetBorderWidth(side, borderWidth.Side(side));
   }
 
   nsRect rect(aPt, GetSize());
   // bypassing nsCSSRendering::PaintBackground is safe because this kind
   // of frame cannot be used for the root element
-  return nsCSSRendering::PaintBackgroundWithSC(PresContext(), aRenderingContext,
-                                               this, aDirtyRect, rect,
-                                               StyleContext(), myBorder,
-                                               aFlags, nullptr);
+  nsCSSRendering::PaintBackgroundWithSC(PresContext(), aRenderingContext, this,
+                                        aDirtyRect, rect,
+                                        StyleContext(), myBorder,
+                                        aFlags, nullptr);
 }
--- a/layout/tables/nsTableCellFrame.h
+++ b/layout/tables/nsTableCellFrame.h
@@ -2,17 +2,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #ifndef nsTableCellFrame_h__
 #define nsTableCellFrame_h__
 
 #include "mozilla/Attributes.h"
 #include "celldata.h"
-#include "imgIContainer.h"
 #include "nsITableCellLayout.h"
 #include "nscore.h"
 #include "nsContainerFrame.h"
 #include "nsStyleContext.h"
 #include "nsIPercentHeightObserver.h"
 #include "nsGkAtoms.h"
 #include "nsLayoutUtils.h"
 #include "nsTArray.h"
@@ -29,18 +28,16 @@ class nsTableFrame;
  * no actual support is under the hood.
  *
  * @author  sclark
  */
 class nsTableCellFrame : public nsContainerFrame,
                          public nsITableCellLayout,
                          public nsIPercentHeightObserver
 {
-  typedef mozilla::image::DrawResult DrawResult;
-
 public:
   NS_DECL_QUERYFRAME_TARGET(nsTableCellFrame)
   NS_DECL_QUERYFRAME
   NS_DECL_FRAMEARENA_HELPERS
 
   // default constructor supplied by the compiler
 
   explicit nsTableCellFrame(nsStyleContext* aContext);
@@ -91,19 +88,19 @@ public:
     * @return           the frame that was created
     */
   friend nsIFrame* NS_NewTableCellFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsRect&           aDirtyRect,
                                 const nsDisplayListSet& aLists) MOZ_OVERRIDE;
 
-  DrawResult PaintCellBackground(nsRenderingContext& aRenderingContext,
-                                 const nsRect& aDirtyRect, nsPoint aPt,
-                                 uint32_t aFlags);
+  void PaintCellBackground(nsRenderingContext& aRenderingContext,
+                           const nsRect& aDirtyRect, nsPoint aPt,
+                           uint32_t aFlags);
 
  
   virtual nsresult ProcessBorders(nsTableFrame* aFrame,
                                   nsDisplayListBuilder* aBuilder,
                                   const nsDisplayListSet& aLists);
 
   virtual nscoord GetMinISize(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE;
   virtual nscoord GetPrefISize(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE;
@@ -200,20 +197,20 @@ public:
 
   bool HasPctOverHeight();
   void SetHasPctOverHeight(bool aValue);
 
   nsTableCellFrame* GetNextCell() const;
 
   virtual nsMargin* GetBorderWidth(nsMargin& aBorder) const;
 
-  virtual DrawResult PaintBackground(nsRenderingContext& aRenderingContext,
-                                     const nsRect&        aDirtyRect,
-                                     nsPoint              aPt,
-                                     uint32_t             aFlags);
+  virtual void PaintBackground(nsRenderingContext& aRenderingContext,
+                               const nsRect&        aDirtyRect,
+                               nsPoint              aPt,
+                               uint32_t             aFlags);
 
   void DecorateForSelection(nsRenderingContext& aRenderingContext,
                             nsPoint              aPt);
 
   virtual bool UpdateOverflow() MOZ_OVERRIDE;
 
   virtual bool IsFrameOfType(uint32_t aFlags) const MOZ_OVERRIDE
   {
@@ -287,17 +284,16 @@ inline void nsTableCellFrame::SetHasPctO
   } else {
     mState &= ~NS_TABLE_CELL_HAS_PCT_OVER_HEIGHT;
   }
 }
 
 // nsBCTableCellFrame
 class nsBCTableCellFrame MOZ_FINAL : public nsTableCellFrame
 {
-  typedef mozilla::image::DrawResult DrawResult;
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
   explicit nsBCTableCellFrame(nsStyleContext* aContext);
 
   ~nsBCTableCellFrame();
 
   virtual nsIAtom* GetType() const MOZ_OVERRIDE;
@@ -318,20 +314,20 @@ public:
   void SetBorderWidth(mozilla::css::Side aSide, BCPixelSize aPixelValue);
 
   virtual nsMargin GetBorderOverflow() MOZ_OVERRIDE;
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE;
 #endif
 
-  virtual DrawResult PaintBackground(nsRenderingContext& aRenderingContext,
-                                     const nsRect&        aDirtyRect,
-                                     nsPoint              aPt,
-                                     uint32_t             aFlags) MOZ_OVERRIDE;
+  virtual void PaintBackground(nsRenderingContext& aRenderingContext,
+                               const nsRect&        aDirtyRect,
+                               nsPoint              aPt,
+                               uint32_t             aFlags) MOZ_OVERRIDE;
 
 private:
 
   // These are the entire width of the border (the cell edge contains only
   // the inner half, per the macros in nsTablePainter.h).
   BCPixelSize mTopBorder;
   BCPixelSize mRightBorder;
   BCPixelSize mBottomBorder;
--- a/layout/tables/nsTableFrame.cpp
+++ b/layout/tables/nsTableFrame.cpp
@@ -42,17 +42,16 @@
 #include "nsStyleSet.h"
 #include "nsDisplayList.h"
 #include "nsIScrollableFrame.h"
 #include "nsCSSProps.h"
 #include "RestyleTracker.h"
 #include <algorithm>
 
 using namespace mozilla;
-using namespace mozilla::image;
 using namespace mozilla::layout;
 
 /********************************************************************************
  ** nsTableReflowState                                                         **
  ********************************************************************************/
 
 struct nsTableReflowState {
 
@@ -1110,17 +1109,16 @@ public:
     MOZ_COUNT_CTOR(nsDisplayTableBorderBackground);
   }
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayTableBorderBackground() {
     MOZ_COUNT_DTOR(nsDisplayTableBorderBackground);
   }
 #endif
 
-  virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE;
   virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                          const nsDisplayItemGeometry* aGeometry,
                                          nsRegion *aInvalidRegion) MOZ_OVERRIDE;
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      nsRenderingContext* aCtx) MOZ_OVERRIDE;
   NS_DISPLAY_DECL_NAME("TableBorderBackground", TYPE_TABLE_BORDER_BACKGROUND)
 };
 
@@ -1133,49 +1131,62 @@ IsFrameAllowedInTable(nsIAtom* aType)
          nsGkAtoms::tableRowGroupFrame == aType ||
          nsGkAtoms::scrollFrame == aType ||
          nsGkAtoms::tableFrame == aType ||
          nsGkAtoms::tableColFrame == aType ||
          nsGkAtoms::tableColGroupFrame == aType;
 }
 #endif
 
-nsDisplayItemGeometry*
-nsDisplayTableBorderBackground::AllocateGeometry(nsDisplayListBuilder* aBuilder)
-{
-  return new nsDisplayItemGenericImageGeometry(this, aBuilder);
+/* static */ bool
+nsTableFrame::AnyTablePartHasUndecodedBackgroundImage(nsIFrame* aStart,
+                                                      nsIFrame* aEnd)
+{
+  for (nsIFrame* f = aStart; f != aEnd; f = f->GetNextSibling()) {
+    NS_ASSERTION(IsFrameAllowedInTable(f->GetType()), "unexpected frame type");
+
+    if (!nsCSSRendering::AreAllBackgroundImagesDecodedForFrame(f))
+      return true;
+
+    nsTableCellFrame *cellFrame = do_QueryFrame(f);
+    if (cellFrame)
+      continue;
+
+    if (AnyTablePartHasUndecodedBackgroundImage(f->PrincipalChildList().FirstChild(), nullptr))
+      return true;
+  }
+  
+  return false;
 }
 
 void
 nsDisplayTableBorderBackground::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                                           const nsDisplayItemGeometry* aGeometry,
                                                           nsRegion *aInvalidRegion)
 {
-  auto geometry =
-    static_cast<const nsDisplayItemGenericImageGeometry*>(aGeometry);
-
-  if (aBuilder->ShouldSyncDecodeImages() &&
-      geometry->ShouldInvalidateToSyncDecodeImages()) {
-    bool snap;
-    aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
+  if (aBuilder->ShouldSyncDecodeImages()) {
+    if (nsTableFrame::AnyTablePartHasUndecodedBackgroundImage(mFrame, mFrame->GetNextSibling()) ||
+        nsTableFrame::AnyTablePartHasUndecodedBackgroundImage(
+          mFrame->GetChildList(nsIFrame::kColGroupList).FirstChild(), nullptr)) {
+      bool snap;
+      aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
+    }
   }
 
   nsDisplayTableItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
 }
 
 void
 nsDisplayTableBorderBackground::Paint(nsDisplayListBuilder* aBuilder,
                                       nsRenderingContext* aCtx)
 {
-  DrawResult result = static_cast<nsTableFrame*>(mFrame)->
+  static_cast<nsTableFrame*>(mFrame)->
     PaintTableBorderBackground(*aCtx, mVisibleRect,
                                ToReferenceFrame(),
                                aBuilder->GetBackgroundPaintFlags());
-
-  nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, result);
 }
 
 static int32_t GetTablePartRank(nsDisplayItem* aItem)
 {
   nsIAtom* type = aItem->Frame()->GetType();
   if (type == nsGkAtoms::tableFrame)
     return 0;
   if (type == nsGkAtoms::tableRowGroupFrame)
@@ -1336,31 +1347,31 @@ nsTableFrame::GetDeflationForBackground(
       !IsBorderCollapse())
     return nsMargin(0,0,0,0);
 
   return GetOuterBCBorder();
 }
 
 // XXX We don't put the borders and backgrounds in tree order like we should.
 // That requires some major surgery which we aren't going to do right now.
-DrawResult
+void
 nsTableFrame::PaintTableBorderBackground(nsRenderingContext& aRenderingContext,
                                          const nsRect& aDirtyRect,
                                          nsPoint aPt, uint32_t aBGPaintFlags)
 {
   nsPresContext* presContext = PresContext();
 
   TableBackgroundPainter painter(this, TableBackgroundPainter::eOrigin_Table,
                                  presContext, aRenderingContext,
                                  aDirtyRect, aPt, aBGPaintFlags);
   nsMargin deflate = GetDeflationForBackground(presContext);
   // If 'deflate' is (0,0,0,0) then we'll paint the table background
   // in a separate display item, so don't do it here.
-  DrawResult result =
-    painter.PaintTable(this, deflate, deflate != nsMargin(0, 0, 0, 0));
+  nsresult rv = painter.PaintTable(this, deflate, deflate != nsMargin(0, 0, 0, 0));
+  if (NS_FAILED(rv)) return;
 
   if (StyleVisibility()->IsVisible()) {
     if (!IsBorderCollapse()) {
       Sides skipSides = GetSkipSides();
       nsRect rect(aPt, mRect.Size());
       nsCSSRendering::PaintBorder(presContext, aRenderingContext, this,
                                   aDirtyRect, rect, mStyleContext, skipSides);
     }
@@ -1374,18 +1385,16 @@ nsTableFrame::PaintTableBorderBackground
       // XXX we should probably get rid of this translation at some stage
       // But that would mean modifying PaintBCBorders, ugh
       gfxContextMatrixAutoSaveRestore autoSR(ctx);
       ctx->SetMatrix(ctx->CurrentMatrix().Translate(devPixelOffset));
 
       PaintBCBorders(aRenderingContext, aDirtyRect - aPt);
     }
   }
-
-  return result;
 }
 
 nsIFrame::LogicalSides
 nsTableFrame::GetLogicalSkipSides(const nsHTMLReflowState* aReflowState) const
 {
   if (MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==
                      NS_STYLE_BOX_DECORATION_BREAK_CLONE)) {
     return LogicalSides();
--- a/layout/tables/nsTableFrame.h
+++ b/layout/tables/nsTableFrame.h
@@ -2,17 +2,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #ifndef nsTableFrame_h__
 #define nsTableFrame_h__
 
 #include "mozilla/Attributes.h"
 #include "celldata.h"
-#include "imgIContainer.h"
 #include "nscore.h"
 #include "nsContainerFrame.h"
 #include "nsStyleCoord.h"
 #include "nsStyleConsts.h"
 #include "nsTableColFrame.h"
 #include "nsTableColGroupFrame.h"
 #include "nsCellMap.h"
 #include "nsGkAtoms.h"
@@ -102,18 +101,16 @@ private:
   * Used as a pseudo-frame within nsTableOuterFrame, it may also be used
   * stand-alone as the top-level frame.
   *
   * The principal child list contains row group frames. There is also an
   * additional child list, kColGroupList, which contains the col group frames.
   */
 class nsTableFrame : public nsContainerFrame
 {
-  typedef mozilla::image::DrawResult DrawResult;
-
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
   static void DestroyPositionedTablePartArray(void* aPropertyValue);
   NS_DECLARE_FRAME_PROPERTY(PositionedTablePartArray, DestroyPositionedTablePartArray)
 
   /** nsTableOuterFrame has intimate knowledge of the inner table frame */
   friend class nsTableOuterFrame;
@@ -244,19 +241,26 @@ public:
                                 const nsRect&           aDirtyRect,
                                 const nsDisplayListSet& aLists) MOZ_OVERRIDE;
 
   /**
    * Paint the background of the table and its parts (column groups,
    * columns, row groups, rows, and cells), and the table border, and all
    * internal borders if border-collapse is on.
    */
-  DrawResult PaintTableBorderBackground(nsRenderingContext& aRenderingContext,
-                                        const nsRect& aDirtyRect,
-                                        nsPoint aPt, uint32_t aBGPaintFlags);
+  void PaintTableBorderBackground(nsRenderingContext& aRenderingContext,
+                                  const nsRect& aDirtyRect,
+                                  nsPoint aPt, uint32_t aBGPaintFlags);
+
+  /**
+   * Determines if any table part has a background image that is currently not
+   * decoded. Does not look into cell contents (ie only table parts).
+   */
+  static bool AnyTablePartHasUndecodedBackgroundImage(nsIFrame* aStart,
+                                                      nsIFrame* aEnd);
 
   /** Get the outer half (i.e., the part outside the height and width of
    *  the table) of the largest segment (?) of border-collapsed border on
    *  the table on each side, or 0 for non border-collapsed tables.
    */
   nsMargin GetOuterBCBorder() const;
 
   /** Same as above, but only if it's included from the border-box width
--- a/layout/tables/nsTablePainter.cpp
+++ b/layout/tables/nsTablePainter.cpp
@@ -92,18 +92,16 @@
    Elements with stacking contexts set up their own painter to finish the
    painting process, since they were skipped. They call the appropriate
    sub-part of the loop (e.g. PaintRow) which will paint the frame and
    descendants.
    
    XXX views are going 
  */
 
-using namespace mozilla::image;
-
 TableBackgroundPainter::TableBackgroundData::TableBackgroundData()
   : mFrame(nullptr),
     mVisible(false),
     mBorder(nullptr),
     mSynthBorder(nullptr)
 {
   MOZ_COUNT_CTOR(TableBackgroundData);
 }
@@ -170,31 +168,33 @@ TableBackgroundPainter::TableBackgroundD
   const nsStyleBackground *bg = mFrame->StyleBackground();
   NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, bg) {
     if (!bg->mLayers[i].mImage.IsEmpty())
       return true;
   }
   return false;
 }
 
-void
+nsresult
 TableBackgroundPainter::TableBackgroundData::SetBCBorder(nsMargin& aBorder,
                                                          TableBackgroundPainter* aPainter)
 {
-  MOZ_ASSERT(aPainter);
+  NS_PRECONDITION(aPainter, "null painter");
   if (!mSynthBorder) {
     mSynthBorder = new (aPainter->mPresContext)
                         nsStyleBorder(aPainter->mZeroBorder);
+    if (!mSynthBorder) return NS_ERROR_OUT_OF_MEMORY;
   }
 
   NS_FOR_CSS_SIDES(side) {
     mSynthBorder->SetBorderWidth(side, aBorder.Side(side));
   }
   
   mBorder = mSynthBorder;
+  return NS_OK;
 }
 
 TableBackgroundPainter::TableBackgroundPainter(nsTableFrame*        aTableFrame,
                                                Origin               aOrigin,
                                                nsPresContext*       aPresContext,
                                                nsRenderingContext& aRenderingContext,
                                                const nsRect&        aDirtyRect,
                                                const nsPoint&       aRenderPt,
@@ -240,33 +240,23 @@ TableBackgroundPainter::~TableBackground
     }
     delete [] mCols;
   }
   mRowGroup.Destroy(mPresContext);
   mRow.Destroy(mPresContext);
   MOZ_COUNT_DTOR(TableBackgroundPainter);
 }
 
-static void UpdateDrawResult(DrawResult* aCurrentResult,
-                             DrawResult aNewResult)
-{
-  MOZ_ASSERT(aCurrentResult);
-  if (*aCurrentResult == DrawResult::SUCCESS) {
-    *aCurrentResult = aNewResult;
-  }
-}
-
-DrawResult
+nsresult
 TableBackgroundPainter::PaintTableFrame(nsTableFrame*         aTableFrame,
                                         nsTableRowGroupFrame* aFirstRowGroup,
                                         nsTableRowGroupFrame* aLastRowGroup,
                                         const nsMargin&       aDeflate)
 {
-  MOZ_ASSERT(aTableFrame);
-
+  NS_PRECONDITION(aTableFrame, "null frame");
   TableBackgroundData tableData;
   tableData.SetFull(aTableFrame);
   tableData.mRect.MoveTo(0,0); //using table's coords
   tableData.mRect.Deflate(aDeflate);
   if (mIsBorderCollapse && tableData.ShouldSetBCBorder()) {
     if (aFirstRowGroup && aLastRowGroup && mNumCols > 0) {
       //only handle non-degenerate tables; we need a more robust BC model
       //to make degenerate tables' borders reasonable to deal with
@@ -283,35 +273,33 @@ TableBackgroundPainter::PaintTableFrame(
       nsTableRowFrame* rowFrame = aFirstRowGroup->GetFirstRow();
       if (rowFrame) {
         rowFrame->GetContinuousBCBorderWidth(tempBorder);
         border.top = tempBorder.top;
       }
 
       border.left = aTableFrame->GetContinuousLeftBCBorderWidth();
 
-      tableData.SetBCBorder(border, this);
+      nsresult rv = tableData.SetBCBorder(border, this);
+      if (NS_FAILED(rv)) {
+        tableData.Destroy(mPresContext);
+        return rv;
+      }
     }
   }
-
-  DrawResult result = DrawResult::SUCCESS;
-
   if (tableData.IsVisible()) {
-    result =
-      nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
-                                            tableData.mFrame, mDirtyRect,
-                                            tableData.mRect + mRenderPt,
-                                            tableData.mFrame->StyleContext(),
-                                            *tableData.mBorder,
-                                            mBGPaintFlags);
+    nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
+                                          tableData.mFrame, mDirtyRect,
+                                          tableData.mRect + mRenderPt,
+                                          tableData.mFrame->StyleContext(),
+                                          *tableData.mBorder,
+                                          mBGPaintFlags);
   }
-
   tableData.Destroy(mPresContext);
-
-  return result;
+  return NS_OK;
 }
 
 void
 TableBackgroundPainter::TranslateContext(nscoord aDX,
                                          nscoord aDY)
 {
   mRenderPt += nsPoint(aDX, aDY);
   if (mCols) {
@@ -325,47 +313,46 @@ TableBackgroundPainter::TranslateContext
           return;
         mCols[i].mColGroup->mRect.MoveBy(-aDX, -aDY);
         lastColGroup = mCols[i].mColGroup;
       }
     }
   }
 }
 
-DrawResult
+nsresult
 TableBackgroundPainter::PaintTable(nsTableFrame*   aTableFrame,
                                    const nsMargin& aDeflate,
                                    bool            aPaintTableBackground)
 {
   NS_PRECONDITION(aTableFrame, "null table frame");
 
   nsTableFrame::RowGroupArray rowGroups;
   aTableFrame->OrderRowGroups(rowGroups);
 
-  DrawResult result = DrawResult::SUCCESS;
-
   if (rowGroups.Length() < 1) { //degenerate case
     if (aPaintTableBackground) {
       PaintTableFrame(aTableFrame, nullptr, nullptr, nsMargin(0,0,0,0));
     }
     /* No cells; nothing else to paint */
-    return result;
+    return NS_OK;
   }
 
   if (aPaintTableBackground) {
     PaintTableFrame(aTableFrame, rowGroups[0], rowGroups[rowGroups.Length() - 1],
                     aDeflate);
   }
 
   /*Set up column background/border data*/
   if (mNumCols > 0) {
     nsFrameList& colGroupList = aTableFrame->GetColGroups();
     NS_ASSERTION(colGroupList.FirstChild(), "table should have at least one colgroup");
 
     mCols = new ColData[mNumCols];
+    if (!mCols) return NS_ERROR_OUT_OF_MEMORY;
 
     TableBackgroundData* cgData = nullptr;
     nsMargin border;
     /* BC left borders aren't stored on cols, but the previous column's
        right border is the next one's left border.*/
     //Start with table's left border.
     nscoord lastLeftBorder = aTableFrame->GetContinuousLeftBCBorderWidth();
     for (nsTableColGroupFrame* cgFrame = static_cast<nsTableColGroupFrame*>(colGroupList.FirstChild());
@@ -373,21 +360,27 @@ TableBackgroundPainter::PaintTable(nsTab
 
       if (cgFrame->GetColCount() < 1) {
         //No columns, no cells, so no need for data
         continue;
       }
 
       /*Create data struct for column group*/
       cgData = new TableBackgroundData;
+      if (!cgData) return NS_ERROR_OUT_OF_MEMORY;
       cgData->SetFull(cgFrame);
       if (mIsBorderCollapse && cgData->ShouldSetBCBorder()) {
         border.left = lastLeftBorder;
         cgFrame->GetContinuousBCBorderWidth(border);
-        cgData->SetBCBorder(border, this);
+        nsresult rv = cgData->SetBCBorder(border, this);
+        if (NS_FAILED(rv)) {
+          cgData->Destroy(mPresContext);
+          delete cgData;
+          return rv;
+        }
       }
 
       // Boolean that indicates whether mCols took ownership of cgData
       bool cgDataOwnershipTaken = false;
       
       /*Loop over columns in this colgroup*/
       for (nsTableColFrame* col = cgFrame->GetFirstColumn(); col;
            col = static_cast<nsTableColFrame*>(col->GetNextSibling())) {
@@ -401,17 +394,18 @@ TableBackgroundPainter::PaintTable(nsTab
         mCols[colIndex].mCol.mRect.MoveBy(cgData->mRect.x, cgData->mRect.y);
         //link to parent colgroup's data
         mCols[colIndex].mColGroup = cgData;
         cgDataOwnershipTaken = true;
         if (mIsBorderCollapse) {
           border.left = lastLeftBorder;
           lastLeftBorder = col->GetContinuousBCBorderWidth(border);
           if (mCols[colIndex].mCol.ShouldSetBCBorder()) {
-            mCols[colIndex].mCol.SetBCBorder(border, this);
+            nsresult rv = mCols[colIndex].mCol.SetBCBorder(border, this);
+            if (NS_FAILED(rv)) return rv;
           }
         }
       }
 
       if (!cgDataOwnershipTaken) {
         cgData->Destroy(mPresContext);
         delete cgData;
       }
@@ -428,30 +422,28 @@ TableBackgroundPainter::PaintTable(nsTab
     // We have to draw backgrounds not only within the overflow region of this
     // row group, but also possibly (in the case of column / column group
     // backgrounds) at its pre-relative-positioning location.
     nsRect rgVisualOverflow = rg->GetVisualOverflowRectRelativeToSelf();
     nsRect rgOverflowRect = rgVisualOverflow + rg->GetPosition();
     nsRect rgNormalRect = rgVisualOverflow + rg->GetNormalPosition();
 
     if (rgOverflowRect.Union(rgNormalRect).Intersects(mDirtyRect - mRenderPt)) {
-      DrawResult rowGroupResult =
-        PaintRowGroup(rg, rg->IsPseudoStackingContextFromStyle());
-      UpdateDrawResult(&result, rowGroupResult);
+      nsresult rv = PaintRowGroup(rg, rg->IsPseudoStackingContextFromStyle());
+      if (NS_FAILED(rv)) return rv;
     }
   }
-
-  return result;
+  return NS_OK;
 }
 
-DrawResult
+nsresult
 TableBackgroundPainter::PaintRowGroup(nsTableRowGroupFrame* aFrame,
                                       bool                  aPassThrough)
 {
-  MOZ_ASSERT(aFrame);
+  NS_PRECONDITION(aFrame, "null frame");
 
   if (!mRowGroup.mFrame) {
     mRowGroup.SetFrame(aFrame);
   }
 
   nsTableRowFrame* firstRow = aFrame->GetFirstRow();
 
   /* Load row group data */
@@ -461,17 +453,20 @@ TableBackgroundPainter::PaintRowGroup(ns
       nsMargin border;
       if (firstRow) {
         //pick up first row's top border (= rg top border)
         firstRow->GetContinuousBCBorderWidth(border);
         /* (row group doesn't store its top border) */
       }
       //overwrite sides+bottom borders with rg's own
       aFrame->GetContinuousBCBorderWidth(border);
-      mRowGroup.SetBCBorder(border, this);
+      nsresult res = mRowGroup.SetBCBorder(border, this);
+      if (!NS_SUCCEEDED(res)) {
+        return res;
+      }
     }
     aPassThrough = !mRowGroup.IsVisible();
   }
 
   /* translate everything into row group coord system*/
   if (eOrigin_TableRowGroup != mOrigin) {
     TranslateContext(mRowGroup.mRect.x, mRowGroup.mRect.y);
   }
@@ -496,55 +491,51 @@ TableBackgroundPainter::PaintRowGroup(ns
   nsTableRowFrame* row = static_cast<nsTableRowFrame*>(cursor);  
   if (!row) {
     // No useful cursor; just start at the top.  Don't bother to set up a
     // cursor; if we've gotten this far then we've already built the display
     // list for the rowgroup, so not having a cursor means that there's some
     // good reason we don't have a cursor and we shouldn't create one here.
     row = firstRow;
   }
-
-  DrawResult result = DrawResult::SUCCESS;
   
   /* Finally paint */
   for (; row; row = row->GetNextRow()) {
     mRow.SetFrame(row);
     // Be sure to consider our positions both pre- and post-relative
     // positioning, since we potentially need to paint at both places.
     nscoord rowY = std::min(mRow.mRect.y, row->GetNormalPosition().y);
 
     // Intersect wouldn't handle rowspans.
     if (cursor &&
         (mDirtyRect.YMost() - mRenderPt.y) <= (rowY - overflowAbove)) {
       // All done; cells originating in later rows can't intersect mDirtyRect.
       break;
     }
     
-    DrawResult rowResult =
-      PaintRow(row, aPassThrough || row->IsPseudoStackingContextFromStyle());
-
-    UpdateDrawResult(&result, rowResult);
+    nsresult rv = PaintRow(row, aPassThrough || row->IsPseudoStackingContextFromStyle());
+    if (NS_FAILED(rv)) return rv;
   }
 
   /* translate back into table coord system */
   if (eOrigin_TableRowGroup != mOrigin) {
     TranslateContext(-rgRect.x, -rgRect.y);
   }
   
   /* unload rg data */
   mRowGroup.Clear();
 
-  return result;
+  return NS_OK;
 }
 
-DrawResult
+nsresult
 TableBackgroundPainter::PaintRow(nsTableRowFrame* aFrame,
                                  bool             aPassThrough)
 {
-  MOZ_ASSERT(aFrame);
+  NS_PRECONDITION(aFrame, "null frame");
 
   if (!mRow.mFrame) {
     mRow.SetFrame(aFrame);
   }
 
   /* Load row data */
   if (!aPassThrough) {
     mRow.SetData();
@@ -556,138 +547,125 @@ TableBackgroundPainter::PaintRow(nsTable
       }
       else { //acquire rg's bottom border
         nsTableRowGroupFrame* rowGroup = static_cast<nsTableRowGroupFrame*>(aFrame->GetParent());
         rowGroup->GetContinuousBCBorderWidth(border);
       }
       //get the rest of the borders; will overwrite all but bottom
       aFrame->GetContinuousBCBorderWidth(border);
 
-      mRow.SetBCBorder(border, this);
+      nsresult res = mRow.SetBCBorder(border, this);
+      if (!NS_SUCCEEDED(res)) {
+        return res;
+      }
     }
     aPassThrough = !mRow.IsVisible();
   }
 
   /* Translate */
   if (eOrigin_TableRow == mOrigin) {
     /* If we originate from the row, then make the row the origin. */
     mRow.mRect.MoveTo(0, 0);
   }
   //else: Use row group's coord system -> no translation necessary
 
-  DrawResult result = DrawResult::SUCCESS;
-
   for (nsTableCellFrame* cell = aFrame->GetFirstCell(); cell; cell = cell->GetNextCell()) {
     nsRect cellBGRect, rowBGRect, rowGroupBGRect, colBGRect;
     ComputeCellBackgrounds(cell, cellBGRect, rowBGRect,
                            rowGroupBGRect, colBGRect);
 
     // Find the union of all the cell background layers.
     nsRect combinedRect(cellBGRect);
     combinedRect.UnionRect(combinedRect, rowBGRect);
     combinedRect.UnionRect(combinedRect, rowGroupBGRect);
     combinedRect.UnionRect(combinedRect, colBGRect);
 
     if (combinedRect.Intersects(mDirtyRect)) {
       bool passCell = aPassThrough || cell->IsPseudoStackingContextFromStyle();
-      DrawResult cellResult = PaintCell(cell, cellBGRect, rowBGRect,
-                                        rowGroupBGRect, colBGRect, passCell);
-      UpdateDrawResult(&result, cellResult);
+      nsresult rv = PaintCell(cell, cellBGRect, rowBGRect, rowGroupBGRect,
+                              colBGRect, passCell);
+      if (NS_FAILED(rv)) return rv;
     }
   }
 
   /* Unload row data */
   mRow.Clear();
-
-  return result;
+  return NS_OK;
 }
 
-DrawResult
+nsresult
 TableBackgroundPainter::PaintCell(nsTableCellFrame* aCell,
                                   nsRect&           aCellBGRect,
                                   nsRect&           aRowBGRect,
                                   nsRect&           aRowGroupBGRect,
                                   nsRect&           aColBGRect,
                                   bool              aPassSelf)
 {
-  MOZ_ASSERT(aCell);
+  NS_PRECONDITION(aCell, "null frame");
 
   const nsStyleTableBorder* cellTableStyle;
   cellTableStyle = aCell->StyleTableBorder();
   if (NS_STYLE_TABLE_EMPTY_CELLS_SHOW != cellTableStyle->mEmptyCells &&
       aCell->GetContentEmpty() && !mIsBorderCollapse) {
-    return DrawResult::SUCCESS;
+    return NS_OK;
   }
 
   int32_t colIndex;
   aCell->GetColIndex(colIndex);
   NS_ASSERTION(colIndex < int32_t(mNumCols), "prevent array boundary violation");
-  if (int32_t(mNumCols) <= colIndex) {
-    return DrawResult::SUCCESS;
-  }
-
-  DrawResult result = DrawResult::SUCCESS;
+  if (int32_t(mNumCols) <= colIndex)
+    return NS_OK;
 
   //Paint column group background
   if (mCols && mCols[colIndex].mColGroup && mCols[colIndex].mColGroup->IsVisible()) {
-    DrawResult colGroupResult = 
-      nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
-                                            mCols[colIndex].mColGroup->mFrame, mDirtyRect,
-                                            mCols[colIndex].mColGroup->mRect + mRenderPt,
-                                            mCols[colIndex].mColGroup->mFrame->StyleContext(),
-                                            *mCols[colIndex].mColGroup->mBorder,
-                                            mBGPaintFlags, &aColBGRect);
-    UpdateDrawResult(&result, colGroupResult);
+    nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
+                                          mCols[colIndex].mColGroup->mFrame, mDirtyRect,
+                                          mCols[colIndex].mColGroup->mRect + mRenderPt,
+                                          mCols[colIndex].mColGroup->mFrame->StyleContext(),
+                                          *mCols[colIndex].mColGroup->mBorder,
+                                          mBGPaintFlags, &aColBGRect);
   }
 
   //Paint column background
   if (mCols && mCols[colIndex].mCol.IsVisible()) {
-    DrawResult colResult =
-      nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
-                                            mCols[colIndex].mCol.mFrame, mDirtyRect,
-                                            mCols[colIndex].mCol.mRect + mRenderPt,
-                                            mCols[colIndex].mCol.mFrame->StyleContext(),
-                                            *mCols[colIndex].mCol.mBorder,
-                                            mBGPaintFlags, &aColBGRect);
-    UpdateDrawResult(&result, colResult);
+    nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
+                                          mCols[colIndex].mCol.mFrame, mDirtyRect,
+                                          mCols[colIndex].mCol.mRect + mRenderPt,
+                                          mCols[colIndex].mCol.mFrame->StyleContext(),
+                                          *mCols[colIndex].mCol.mBorder,
+                                          mBGPaintFlags, &aColBGRect);
   }
 
   //Paint row group background
   if (mRowGroup.IsVisible()) {
-    DrawResult rowGroupResult =
-      nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
-                                            mRowGroup.mFrame, mDirtyRect,
-                                            mRowGroup.mRect + mRenderPt,
-                                            mRowGroup.mFrame->StyleContext(),
-                                            *mRowGroup.mBorder,
-                                            mBGPaintFlags, &aRowGroupBGRect);
-    UpdateDrawResult(&result, rowGroupResult);
+    nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
+                                          mRowGroup.mFrame, mDirtyRect,
+                                          mRowGroup.mRect + mRenderPt,
+                                          mRowGroup.mFrame->StyleContext(),
+                                          *mRowGroup.mBorder,
+                                          mBGPaintFlags, &aRowGroupBGRect);
   }
 
   //Paint row background
   if (mRow.IsVisible()) {
-    DrawResult rowResult =
-      nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
-                                            mRow.mFrame, mDirtyRect,
-                                            mRow.mRect + mRenderPt,
-                                            mRow.mFrame->StyleContext(),
-                                            *mRow.mBorder,
-                                            mBGPaintFlags, &aRowBGRect);
-    UpdateDrawResult(&result, rowResult);
+    nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
+                                          mRow.mFrame, mDirtyRect,
+                                          mRow.mRect + mRenderPt,
+                                          mRow.mFrame->StyleContext(),
+                                          *mRow.mBorder,
+                                          mBGPaintFlags, &aRowBGRect);
   }
 
   //Paint cell background in border-collapse unless we're just passing
   if (mIsBorderCollapse && !aPassSelf) {
-    DrawResult cellResult =
-      aCell->PaintCellBackground(mRenderingContext, mDirtyRect,
-                                 aCellBGRect.TopLeft(), mBGPaintFlags);
-    UpdateDrawResult(&result, cellResult);
+    aCell->PaintCellBackground(mRenderingContext, mDirtyRect,
+                               aCellBGRect.TopLeft(), mBGPaintFlags);
   }
 
-  return result;
+  return NS_OK;
 }
 
 void
 TableBackgroundPainter::ComputeCellBackgrounds(nsTableCellFrame* aCell,
                                                nsRect&           aCellBGRect,
                                                nsRect&           aRowBGRect,
                                                nsRect&           aRowGroupBGRect,
                                                nsRect&           aColBGRect)
--- a/layout/tables/nsTablePainter.h
+++ b/layout/tables/nsTablePainter.h
@@ -1,18 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsTablePainter_h__
 #define nsTablePainter_h__
 
-#include "imgIContainer.h"
-
 #include "celldata.h"
 
 // flags for Paint, PaintChild, PaintChildren are currently only used by tables.
 //Table-based paint call; not a direct call as with views
 #define NS_PAINT_FLAG_TABLE_BG_PAINT      0x00000001
 //Cells should paint their backgrounds only, no children
 #define NS_PAINT_FLAG_TABLE_CELL_BG_PASS  0x00000002
 
@@ -24,18 +22,16 @@ class nsTableCellFrame;
 
 class TableBackgroundPainter
 {
   /*
    * Helper class for painting table backgrounds
    *
    */
 
-  typedef mozilla::image::DrawResult DrawResult;
-
   public:
 
     enum Origin { eOrigin_Table, eOrigin_TableRowGroup, eOrigin_TableRow };
 
     /** Public constructor
       * @param aTableFrame       - the table's table frame
       * @param aOrigin           - what type of table frame is creating this instance
       * @param aPresContext      - the presentation context
@@ -79,89 +75,80 @@ class TableBackgroundPainter
       * (Cells themselves will only be painted in border collapse)
       * Table must do a flagged TABLE_BG_PAINT ::Paint call on its
       * children afterwards
       * @param aTableFrame - the table frame
       * @param aDeflate    - deflation needed to bring table's mRect
       *                      to the outer grid lines in border-collapse
       * @param aPaintTableBackground - if true, the table background
       * is included, otherwise it isn't
-      * @returns DrawResult::SUCCESS if all painting was successful. If some
-      *          painting failed or an improved result could be achieved by sync
-      *          decoding images, returns another value.
       */
-    DrawResult PaintTable(nsTableFrame* aTableFrame, const nsMargin& aDeflate,
-                          bool aPaintTableBackground);
+    nsresult PaintTable(nsTableFrame* aTableFrame, const nsMargin& aDeflate,
+                        bool aPaintTableBackground);
 
     /** Paint background for the row group and its children down through cells
       * (Cells themselves will only be painted in border collapse)
       * Standards mode only
       * Table Row Group must do a flagged TABLE_BG_PAINT ::Paint call on its
       * children afterwards
       * @param aFrame - the table row group frame
-      * @returns DrawResult::SUCCESS if all painting was successful. If some
-      *          painting failed or an improved result could be achieved by sync
-      *          decoding images, returns another value.
       */
-    DrawResult PaintRowGroup(nsTableRowGroupFrame* aFrame)
+    nsresult PaintRowGroup(nsTableRowGroupFrame* aFrame)
     { return PaintRowGroup(aFrame, false); }
 
     /** Paint background for the row and its children down through cells
       * (Cells themselves will only be painted in border collapse)
       * Standards mode only
       * Table Row must do a flagged TABLE_BG_PAINT ::Paint call on its
       * children afterwards
       * @param aFrame - the table row frame
-      * @returns DrawResult::SUCCESS if all painting was successful. If some
-      *          painting failed or an improved result could be achieved by sync
-      *          decoding images, returns another value.
       */
-    DrawResult PaintRow(nsTableRowFrame* aFrame)
+    nsresult PaintRow(nsTableRowFrame* aFrame)
     { return PaintRow(aFrame, false); }
 
   private:
 
     /** Paint table frame's background
       * @param aTableFrame     - the table frame
       * @param aFirstRowGroup  - the first (in layout order) row group
       *                          may be null
       * @param aLastRowGroup   - the last (in layout order) row group
       *                          may be null
       * @param aDeflate        - adjustment to frame's rect (used for quirks BC)
       *                          may be null
       */
-    DrawResult PaintTableFrame(nsTableFrame*         aTableFrame,
-                               nsTableRowGroupFrame* aFirstRowGroup,
-                               nsTableRowGroupFrame* aLastRowGroup,
-                               const nsMargin&       aDeflate);
+    nsresult PaintTableFrame(nsTableFrame*         aTableFrame,
+                             nsTableRowGroupFrame* aFirstRowGroup,
+                             nsTableRowGroupFrame* aLastRowGroup,
+                             const nsMargin&       aDeflate);
 
     /* aPassThrough params indicate whether to paint the element or to just
      * pass through and paint underlying layers only
      * See Public versions for function descriptions
      */
-    DrawResult PaintRowGroup(nsTableRowGroupFrame* aFrame,
-                             bool                  aPassThrough);
-    DrawResult PaintRow(nsTableRowFrame* aFrame,
-                        bool             aPassThrough);
+    nsresult PaintRowGroup(nsTableRowGroupFrame* aFrame,
+                           bool                  aPassThrough);
+    nsresult PaintRow(nsTableRowFrame* aFrame,
+                      bool             aPassThrough);
 
     /** Paint table background layers for this cell space
       * Also paints cell's own background in border-collapse mode
       * @param aCell           - the cell
       * @param aCellBGRect     - background rect for the cell
       * @param aRowBGRect      - background rect for the row
       * @param aRowGroupBGRect - background rect for the row group
       * @param aColBGRect      - background rect for the column and column group
       * @param aPassSelf       - pass this cell; i.e. paint only underlying layers
       */
-    DrawResult PaintCell(nsTableCellFrame* aCell,
-                         nsRect&           aCellBGRect,
-                         nsRect&           aRowBGRect,
-                         nsRect&           aRowGroupBGRect,
-                         nsRect&           aColBGRect,
-                         bool              aPassSelf);
+    nsresult PaintCell(nsTableCellFrame* aCell,
+                       nsRect&           aCellBGRect,
+                       nsRect&           aRowBGRect,
+                       nsRect&           aRowGroupBGRect,
+                       nsRect&           aColBGRect,
+                       bool              aPassSelf);
 
     /** Compute table background layer positions for this cell space
       * @param aCell              - the cell
       * @param aCellBGRectOut     - outparam: background rect for the cell
       * @param aRowBGRectOut      - outparam: background rect for the row
       * @param aRowGroupBGRectOut - outparam: background rect for the row group
       * @param aColBGRectOut      - outparam: background rect for the column
                                     and column group
@@ -213,18 +200,18 @@ class TableBackgroundPainter
 
       /** Calculate the style data for mFrame */
       void SetData();
 
       /** True if need to set border-collapse border; must call SetFull beforehand */
       bool ShouldSetBCBorder();
 
       /** Set border-collapse border with aBorderWidth as widths */
-      void SetBCBorder(nsMargin&               aBorderWidth,
-                       TableBackgroundPainter* aPainter);
+      nsresult SetBCBorder(nsMargin&               aBorderWidth,
+                           TableBackgroundPainter* aPainter);
 
       private:
       nsStyleBorder* mSynthBorder;
     };
 
     struct ColData;
     friend struct ColData;
     struct ColData {
--- a/layout/tables/nsTableRowFrame.cpp
+++ b/layout/tables/nsTableRowFrame.cpp
@@ -530,63 +530,50 @@ public:
     MOZ_COUNT_CTOR(nsDisplayTableRowBackground);
   }
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayTableRowBackground() {
     MOZ_COUNT_DTOR(nsDisplayTableRowBackground);
   }
 #endif
 
-  virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE;
   virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                          const nsDisplayItemGeometry* aGeometry,
                                          nsRegion *aInvalidRegion) MOZ_OVERRIDE;
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      nsRenderingContext* aCtx) MOZ_OVERRIDE;
   NS_DISPLAY_DECL_NAME("TableRowBackground", TYPE_TABLE_ROW_BACKGROUND)
 };
 
-nsDisplayItemGeometry*
-nsDisplayTableRowBackground::AllocateGeometry(nsDisplayListBuilder* aBuilder)
-{
-  return new nsDisplayItemGenericImageGeometry(this, aBuilder);
-}
-
 void
 nsDisplayTableRowBackground::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                                        const nsDisplayItemGeometry* aGeometry,
                                                        nsRegion *aInvalidRegion)
 {
-  auto geometry =
-    static_cast<const nsDisplayItemGenericImageGeometry*>(aGeometry);
-
-  if (aBuilder->ShouldSyncDecodeImages() &&
-      geometry->ShouldInvalidateToSyncDecodeImages()) {
-    bool snap;
-    aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
+  if (aBuilder->ShouldSyncDecodeImages()) {
+    if (nsTableFrame::AnyTablePartHasUndecodedBackgroundImage(mFrame, mFrame->GetNextSibling())) {
+      bool snap;
+      aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
+    }
   }
 
   nsDisplayTableItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
 }
 
 void
 nsDisplayTableRowBackground::Paint(nsDisplayListBuilder* aBuilder,
                                    nsRenderingContext* aCtx)
 {
   nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(mFrame);
   TableBackgroundPainter painter(tableFrame,
                                  TableBackgroundPainter::eOrigin_TableRow,
                                  mFrame->PresContext(), *aCtx,
                                  mVisibleRect, ToReferenceFrame(),
                                  aBuilder->GetBackgroundPaintFlags());
-
-  DrawResult result =
-    painter.PaintRow(static_cast<nsTableRowFrame*>(mFrame));
-
-  nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, result);
+  painter.PaintRow(static_cast<nsTableRowFrame*>(mFrame));
 }
 
 void
 nsTableRowFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                   const nsRect&           aDirtyRect,
                                   const nsDisplayListSet& aLists)
 {
   nsDisplayTableItem* item = nullptr;
--- a/layout/tables/nsTableRowGroupFrame.cpp
+++ b/layout/tables/nsTableRowGroupFrame.cpp
@@ -142,64 +142,51 @@ public:
     MOZ_COUNT_CTOR(nsDisplayTableRowGroupBackground);
   }
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayTableRowGroupBackground() {
     MOZ_COUNT_DTOR(nsDisplayTableRowGroupBackground);
   }
 #endif
 
-  virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE;
   virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                          const nsDisplayItemGeometry* aGeometry,
                                          nsRegion *aInvalidRegion) MOZ_OVERRIDE;
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      nsRenderingContext* aCtx) MOZ_OVERRIDE;
 
   NS_DISPLAY_DECL_NAME("TableRowGroupBackground", TYPE_TABLE_ROW_GROUP_BACKGROUND)
 };
 
-nsDisplayItemGeometry*
-nsDisplayTableRowGroupBackground::AllocateGeometry(nsDisplayListBuilder* aBuilder)
-{
-  return new nsDisplayItemGenericImageGeometry(this, aBuilder);
-}
-
 void
 nsDisplayTableRowGroupBackground::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                                             const nsDisplayItemGeometry* aGeometry,
                                                             nsRegion *aInvalidRegion)
 {
-  auto geometry =
-    static_cast<const nsDisplayItemGenericImageGeometry*>(aGeometry);
-
-  if (aBuilder->ShouldSyncDecodeImages() &&
-      geometry->ShouldInvalidateToSyncDecodeImages()) {
-    bool snap;
-    aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
+  if (aBuilder->ShouldSyncDecodeImages()) {
+    if (nsTableFrame::AnyTablePartHasUndecodedBackgroundImage(mFrame, mFrame->GetNextSibling())) {
+      bool snap;
+      aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
+    }
   }
 
   nsDisplayTableItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
 }
 
 void
 nsDisplayTableRowGroupBackground::Paint(nsDisplayListBuilder* aBuilder,
                                         nsRenderingContext* aCtx)
 {
   nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(mFrame);
   TableBackgroundPainter painter(tableFrame,
                                  TableBackgroundPainter::eOrigin_TableRowGroup,
                                  mFrame->PresContext(), *aCtx,
                                  mVisibleRect, ToReferenceFrame(),
                                  aBuilder->GetBackgroundPaintFlags());
-
-  DrawResult result =
-    painter.PaintRowGroup(static_cast<nsTableRowGroupFrame*>(mFrame));
-
-  nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, result);
+  painter.PaintRowGroup(static_cast<nsTableRowGroupFrame*>(mFrame));
 }
 
 // Handle the child-traversal part of DisplayGenericTablePart
 static void
 DisplayRows(nsDisplayListBuilder* aBuilder, nsFrame* aFrame,
             const nsRect& aDirtyRect, const nsDisplayListSet& aLists)
 {
   nscoord overflowAbove;
--- a/layout/xul/nsImageBoxFrame.cpp
+++ b/layout/xul/nsImageBoxFrame.cpp
@@ -383,17 +383,17 @@ nsDisplayXULImage::ComputeInvalidationRe
                                              nsRegion* aInvalidRegion)
 {
   auto boxFrame = static_cast<nsImageBoxFrame*>(mFrame);
   auto geometry =
     static_cast<const nsDisplayItemGenericImageGeometry*>(aGeometry);
 
   if (aBuilder->ShouldSyncDecodeImages() &&
       boxFrame->mImageRequest &&
-      geometry->ShouldInvalidateToSyncDecodeImages()) {
+      geometry->LastDrawResult() != DrawResult::SUCCESS) {
       bool snap;
       aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
   }
 
   nsDisplayImageContainer::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
 }
 
 void