Bug 1128769 (Part 4) - Record the last draw result when drawing CSS tables and use it to decide whether to sync decode. r=tn a=lmandel
authorSeth Fowler <seth@mozilla.com>
Thu, 05 Feb 2015 20:45:56 -0800
changeset 250152 782bd163aeed
parent 250151 d80f4050e348
child 250153 498290d95f1c
push id4514
push usermfowler@mozilla.com
push date2015-03-02 22:11 +0000
treeherdermozilla-beta@7b3c7ba30dfe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstn, lmandel
bugs1128769
milestone37.0
Bug 1128769 (Part 4) - Record the last draw result when drawing CSS tables and use it to decide whether to sync decode. r=tn a=lmandel
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
--- a/layout/tables/nsTableCellFrame.cpp
+++ b/layout/tables/nsTableCellFrame.cpp
@@ -35,16 +35,17 @@
 #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;
 
@@ -358,37 +359,38 @@ nsTableCellFrame::DecorateForSelection(n
         StrokeLineWithSnapping(nsPoint(mRect.width - (2*onePixel), 2*onePixel),
                                nsPoint(mRect.width - (2*onePixel), mRect.height-onePixel),
                                appUnitsPerDevPixel, *drawTarget, color);
       }
     }
   }
 }
 
-void
+DrawResult
 nsTableCellFrame::PaintBackground(nsRenderingContext& aRenderingContext,
                                   const nsRect&        aDirtyRect,
                                   nsPoint              aPt,
                                   uint32_t             aFlags)
 {
   nsRect rect(aPt, GetSize());
-  nsCSSRendering::PaintBackground(PresContext(), aRenderingContext, this,
-                                  aDirtyRect, rect, aFlags);
+  return nsCSSRendering::PaintBackground(PresContext(), aRenderingContext, this,
+                                         aDirtyRect, rect, aFlags);
 }
 
 // Called by nsTablePainter
-void
+DrawResult
 nsTableCellFrame::PaintCellBackground(nsRenderingContext& aRenderingContext,
                                       const nsRect& aDirtyRect, nsPoint aPt,
                                       uint32_t aFlags)
 {
-  if (!StyleVisibility()->IsVisible())
-    return;
+  if (!StyleVisibility()->IsVisible()) {
+    return DrawResult::SUCCESS;
+  }
 
-  PaintBackground(aRenderingContext, aDirtyRect, aPt, aFlags);
+  return PaintBackground(aRenderingContext, aDirtyRect, aPt, aFlags);
 }
 
 nsresult
 nsTableCellFrame::ProcessBorders(nsTableFrame* aFrame,
                                  nsDisplayListBuilder* aBuilder,
                                  const nsDisplayListSet& aLists)
 {
   const nsStyleBorder* borderStyle = StyleBorder();
@@ -421,50 +423,61 @@ 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)
 {
-  static_cast<nsTableCellFrame*>(mFrame)->
+  DrawResult result = 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)
 {
-  if (aBuilder->ShouldSyncDecodeImages()) {
-    if (!nsCSSRendering::AreAllBackgroundImagesDecodedForFrame(mFrame)) {
-      bool snap;
-      aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
-    }
+  auto geometry =
+    static_cast<const nsDisplayItemGenericImageGeometry*>(aGeometry);
+
+  if (aBuilder->ShouldSyncDecodeImages() &&
+      geometry->ShouldInvalidateToSyncDecodeImages()) {
+    bool snap;
+    aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
   }
 
   nsDisplayTableItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
 }
 
 void nsTableCellFrame::InvalidateFrame(uint32_t aDisplayItemKey)
 {
   nsIFrame::InvalidateFrame(aDisplayItemKey);
@@ -1214,17 +1227,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;
 }
 
 
-void
+DrawResult
 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;
@@ -1234,13 +1247,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
-  nsCSSRendering::PaintBackgroundWithSC(PresContext(), aRenderingContext, this,
-                                        aDirtyRect, rect,
-                                        StyleContext(), myBorder,
-                                        aFlags, nullptr);
+  return nsCSSRendering::PaintBackgroundWithSC(PresContext(), aRenderingContext,
+                                               this, aDirtyRect, rect,
+                                               StyleContext(), myBorder,
+                                               aFlags, nullptr);
 }
--- a/layout/tables/nsTableCellFrame.h
+++ b/layout/tables/nsTableCellFrame.h
@@ -2,16 +2,17 @@
 /* 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"
@@ -28,16 +29,18 @@ 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);
@@ -88,19 +91,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;
 
-  void PaintCellBackground(nsRenderingContext& aRenderingContext,
-                           const nsRect& aDirtyRect, nsPoint aPt,
-                           uint32_t aFlags);
+  DrawResult 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;
@@ -197,20 +200,20 @@ public:
 
   bool HasPctOverHeight();
   void SetHasPctOverHeight(bool aValue);
 
   nsTableCellFrame* GetNextCell() const;
 
   virtual nsMargin* GetBorderWidth(nsMargin& aBorder) const;
 
-  virtual void PaintBackground(nsRenderingContext& aRenderingContext,
-                               const nsRect&        aDirtyRect,
-                               nsPoint              aPt,
-                               uint32_t             aFlags);
+  virtual DrawResult 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
   {
@@ -284,16 +287,17 @@ 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;
@@ -314,20 +318,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 void PaintBackground(nsRenderingContext& aRenderingContext,
-                               const nsRect&        aDirtyRect,
-                               nsPoint              aPt,
-                               uint32_t             aFlags) MOZ_OVERRIDE;
+  virtual DrawResult 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,16 +42,17 @@
 #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 {
 
@@ -1109,16 +1110,17 @@ 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)
 };
 
@@ -1131,62 +1133,49 @@ IsFrameAllowedInTable(nsIAtom* aType)
          nsGkAtoms::tableRowGroupFrame == aType ||
          nsGkAtoms::scrollFrame == aType ||
          nsGkAtoms::tableFrame == aType ||
          nsGkAtoms::tableColFrame == aType ||
          nsGkAtoms::tableColGroupFrame == aType;
 }
 #endif
 
-/* 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;
+nsDisplayItemGeometry*
+nsDisplayTableBorderBackground::AllocateGeometry(nsDisplayListBuilder* aBuilder)
+{
+  return new nsDisplayItemGenericImageGeometry(this, aBuilder);
 }
 
 void
 nsDisplayTableBorderBackground::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                                           const nsDisplayItemGeometry* aGeometry,
                                                           nsRegion *aInvalidRegion)
 {
-  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));
-    }
+  auto geometry =
+    static_cast<const nsDisplayItemGenericImageGeometry*>(aGeometry);
+
+  if (aBuilder->ShouldSyncDecodeImages() &&
+      geometry->ShouldInvalidateToSyncDecodeImages()) {
+    bool snap;
+    aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
   }
 
   nsDisplayTableItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
 }
 
 void
 nsDisplayTableBorderBackground::Paint(nsDisplayListBuilder* aBuilder,
                                       nsRenderingContext* aCtx)
 {
-  static_cast<nsTableFrame*>(mFrame)->
+  DrawResult result = 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)
@@ -1347,31 +1336,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.
-void
+DrawResult
 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.
-  nsresult rv = painter.PaintTable(this, deflate, deflate != nsMargin(0, 0, 0, 0));
-  if (NS_FAILED(rv)) return;
+  DrawResult result =
+    painter.PaintTable(this, deflate, deflate != nsMargin(0, 0, 0, 0));
 
   if (StyleVisibility()->IsVisible()) {
     if (!IsBorderCollapse()) {
       Sides skipSides = GetSkipSides();
       nsRect rect(aPt, mRect.Size());
       nsCSSRendering::PaintBorder(presContext, aRenderingContext, this,
                                   aDirtyRect, rect, mStyleContext, skipSides);
     }
@@ -1385,16 +1374,18 @@ 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,16 +2,17 @@
 /* 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"
@@ -101,16 +102,18 @@ 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;
@@ -241,26 +244,19 @@ 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.
    */
-  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);
+  DrawResult PaintTableBorderBackground(nsRenderingContext& aRenderingContext,
+                                        const nsRect& aDirtyRect,
+                                        nsPoint aPt, uint32_t aBGPaintFlags);
 
   /** 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,16 +92,18 @@
    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);
 }
@@ -168,33 +170,31 @@ 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;
 }
 
-nsresult
+void
 TableBackgroundPainter::TableBackgroundData::SetBCBorder(nsMargin& aBorder,
                                                          TableBackgroundPainter* aPainter)
 {
-  NS_PRECONDITION(aPainter, "null painter");
+  MOZ_ASSERT(aPainter);
   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,23 +240,33 @@ TableBackgroundPainter::~TableBackground
     }
     delete [] mCols;
   }
   mRowGroup.Destroy(mPresContext);
   mRow.Destroy(mPresContext);
   MOZ_COUNT_DTOR(TableBackgroundPainter);
 }
 
-nsresult
+static void UpdateDrawResult(DrawResult* aCurrentResult,
+                             DrawResult aNewResult)
+{
+  MOZ_ASSERT(aCurrentResult);
+  if (*aCurrentResult == DrawResult::SUCCESS) {
+    *aCurrentResult = aNewResult;
+  }
+}
+
+DrawResult
 TableBackgroundPainter::PaintTableFrame(nsTableFrame*         aTableFrame,
                                         nsTableRowGroupFrame* aFirstRowGroup,
                                         nsTableRowGroupFrame* aLastRowGroup,
                                         const nsMargin&       aDeflate)
 {
-  NS_PRECONDITION(aTableFrame, "null frame");
+  MOZ_ASSERT(aTableFrame);
+
   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
@@ -273,33 +283,35 @@ TableBackgroundPainter::PaintTableFrame(
       nsTableRowFrame* rowFrame = aFirstRowGroup->GetFirstRow();
       if (rowFrame) {
         rowFrame->GetContinuousBCBorderWidth(tempBorder);
         border.top = tempBorder.top;
       }
 
       border.left = aTableFrame->GetContinuousLeftBCBorderWidth();
 
-      nsresult rv = tableData.SetBCBorder(border, this);
-      if (NS_FAILED(rv)) {
-        tableData.Destroy(mPresContext);
-        return rv;
-      }
+      tableData.SetBCBorder(border, this);
     }
   }
+
+  DrawResult result = DrawResult::SUCCESS;
+
   if (tableData.IsVisible()) {
-    nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
-                                          tableData.mFrame, mDirtyRect,
-                                          tableData.mRect + mRenderPt,
-                                          tableData.mFrame->StyleContext(),
-                                          *tableData.mBorder,
-                                          mBGPaintFlags);
+    result =
+      nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
+                                            tableData.mFrame, mDirtyRect,
+                                            tableData.mRect + mRenderPt,
+                                            tableData.mFrame->StyleContext(),
+                                            *tableData.mBorder,
+                                            mBGPaintFlags);
   }
+
   tableData.Destroy(mPresContext);
-  return NS_OK;
+
+  return result;
 }
 
 void
 TableBackgroundPainter::TranslateContext(nscoord aDX,
                                          nscoord aDY)
 {
   mRenderPt += nsPoint(aDX, aDY);
   if (mCols) {
@@ -313,46 +325,47 @@ TableBackgroundPainter::TranslateContext
           return;
         mCols[i].mColGroup->mRect.MoveBy(-aDX, -aDY);
         lastColGroup = mCols[i].mColGroup;
       }
     }
   }
 }
 
-nsresult
+DrawResult
 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 NS_OK;
+    return result;
   }
 
   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());
@@ -360,27 +373,21 @@ 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);
-        nsresult rv = cgData->SetBCBorder(border, this);
-        if (NS_FAILED(rv)) {
-          cgData->Destroy(mPresContext);
-          delete cgData;
-          return rv;
-        }
+        cgData->SetBCBorder(border, this);
       }
 
       // 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())) {
@@ -394,18 +401,17 @@ 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()) {
-            nsresult rv = mCols[colIndex].mCol.SetBCBorder(border, this);
-            if (NS_FAILED(rv)) return rv;
+            mCols[colIndex].mCol.SetBCBorder(border, this);
           }
         }
       }
 
       if (!cgDataOwnershipTaken) {
         cgData->Destroy(mPresContext);
         delete cgData;
       }
@@ -422,28 +428,30 @@ 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)) {
-      nsresult rv = PaintRowGroup(rg, rg->IsPseudoStackingContextFromStyle());
-      if (NS_FAILED(rv)) return rv;
+      DrawResult rowGroupResult =
+        PaintRowGroup(rg, rg->IsPseudoStackingContextFromStyle());
+      UpdateDrawResult(&result, rowGroupResult);
     }
   }
-  return NS_OK;
+
+  return result;
 }
 
-nsresult
+DrawResult
 TableBackgroundPainter::PaintRowGroup(nsTableRowGroupFrame* aFrame,
                                       bool                  aPassThrough)
 {
-  NS_PRECONDITION(aFrame, "null frame");
+  MOZ_ASSERT(aFrame);
 
   if (!mRowGroup.mFrame) {
     mRowGroup.SetFrame(aFrame);
   }
 
   nsTableRowFrame* firstRow = aFrame->GetFirstRow();
 
   /* Load row group data */
@@ -453,20 +461,17 @@ 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);
-      nsresult res = mRowGroup.SetBCBorder(border, this);
-      if (!NS_SUCCEEDED(res)) {
-        return res;
-      }
+      mRowGroup.SetBCBorder(border, this);
     }
     aPassThrough = !mRowGroup.IsVisible();
   }
 
   /* translate everything into row group coord system*/
   if (eOrigin_TableRowGroup != mOrigin) {
     TranslateContext(mRowGroup.mRect.x, mRowGroup.mRect.y);
   }
@@ -491,51 +496,55 @@ 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;
     }
     
-    nsresult rv = PaintRow(row, aPassThrough || row->IsPseudoStackingContextFromStyle());
-    if (NS_FAILED(rv)) return rv;
+    DrawResult rowResult =
+      PaintRow(row, aPassThrough || row->IsPseudoStackingContextFromStyle());
+
+    UpdateDrawResult(&result, rowResult);
   }
 
   /* translate back into table coord system */
   if (eOrigin_TableRowGroup != mOrigin) {
     TranslateContext(-rgRect.x, -rgRect.y);
   }
   
   /* unload rg data */
   mRowGroup.Clear();
 
-  return NS_OK;
+  return result;
 }
 
-nsresult
+DrawResult
 TableBackgroundPainter::PaintRow(nsTableRowFrame* aFrame,
                                  bool             aPassThrough)
 {
-  NS_PRECONDITION(aFrame, "null frame");
+  MOZ_ASSERT(aFrame);
 
   if (!mRow.mFrame) {
     mRow.SetFrame(aFrame);
   }
 
   /* Load row data */
   if (!aPassThrough) {
     mRow.SetData();
@@ -547,125 +556,138 @@ 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);
 
-      nsresult res = mRow.SetBCBorder(border, this);
-      if (!NS_SUCCEEDED(res)) {
-        return res;
-      }
+      mRow.SetBCBorder(border, this);
     }
     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();
-      nsresult rv = PaintCell(cell, cellBGRect, rowBGRect, rowGroupBGRect,
-                              colBGRect, passCell);
-      if (NS_FAILED(rv)) return rv;
+      DrawResult cellResult = PaintCell(cell, cellBGRect, rowBGRect,
+                                        rowGroupBGRect, colBGRect, passCell);
+      UpdateDrawResult(&result, cellResult);
     }
   }
 
   /* Unload row data */
   mRow.Clear();
-  return NS_OK;
+
+  return result;
 }
 
-nsresult
+DrawResult
 TableBackgroundPainter::PaintCell(nsTableCellFrame* aCell,
                                   nsRect&           aCellBGRect,
                                   nsRect&           aRowBGRect,
                                   nsRect&           aRowGroupBGRect,
                                   nsRect&           aColBGRect,
                                   bool              aPassSelf)
 {
-  NS_PRECONDITION(aCell, "null frame");
+  MOZ_ASSERT(aCell);
 
   const nsStyleTableBorder* cellTableStyle;
   cellTableStyle = aCell->StyleTableBorder();
   if (NS_STYLE_TABLE_EMPTY_CELLS_SHOW != cellTableStyle->mEmptyCells &&
       aCell->GetContentEmpty() && !mIsBorderCollapse) {
-    return NS_OK;
+    return DrawResult::SUCCESS;
   }
 
   int32_t colIndex;
   aCell->GetColIndex(colIndex);
   NS_ASSERTION(colIndex < int32_t(mNumCols), "prevent array boundary violation");
-  if (int32_t(mNumCols) <= colIndex)
-    return NS_OK;
+  if (int32_t(mNumCols) <= colIndex) {
+    return DrawResult::SUCCESS;
+  }
+
+  DrawResult result = DrawResult::SUCCESS;
 
   //Paint column group background
   if (mCols && mCols[colIndex].mColGroup && mCols[colIndex].mColGroup->IsVisible()) {
-    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);
+    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);
   }
 
   //Paint column background
   if (mCols && mCols[colIndex].mCol.IsVisible()) {
-    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);
+    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);
   }
 
   //Paint row group background
   if (mRowGroup.IsVisible()) {
-    nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
-                                          mRowGroup.mFrame, mDirtyRect,
-                                          mRowGroup.mRect + mRenderPt,
-                                          mRowGroup.mFrame->StyleContext(),
-                                          *mRowGroup.mBorder,
-                                          mBGPaintFlags, &aRowGroupBGRect);
+    DrawResult rowGroupResult =
+      nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
+                                            mRowGroup.mFrame, mDirtyRect,
+                                            mRowGroup.mRect + mRenderPt,
+                                            mRowGroup.mFrame->StyleContext(),
+                                            *mRowGroup.mBorder,
+                                            mBGPaintFlags, &aRowGroupBGRect);
+    UpdateDrawResult(&result, rowGroupResult);
   }
 
   //Paint row background
   if (mRow.IsVisible()) {
-    nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
-                                          mRow.mFrame, mDirtyRect,
-                                          mRow.mRect + mRenderPt,
-                                          mRow.mFrame->StyleContext(),
-                                          *mRow.mBorder,
-                                          mBGPaintFlags, &aRowBGRect);
+    DrawResult rowResult =
+      nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
+                                            mRow.mFrame, mDirtyRect,
+                                            mRow.mRect + mRenderPt,
+                                            mRow.mFrame->StyleContext(),
+                                            *mRow.mBorder,
+                                            mBGPaintFlags, &aRowBGRect);
+    UpdateDrawResult(&result, rowResult);
   }
 
   //Paint cell background in border-collapse unless we're just passing
   if (mIsBorderCollapse && !aPassSelf) {
-    aCell->PaintCellBackground(mRenderingContext, mDirtyRect,
-                               aCellBGRect.TopLeft(), mBGPaintFlags);
+    DrawResult cellResult =
+      aCell->PaintCellBackground(mRenderingContext, mDirtyRect,
+                                 aCellBGRect.TopLeft(), mBGPaintFlags);
+    UpdateDrawResult(&result, cellResult);
   }
 
-  return NS_OK;
+  return result;
 }
 
 void
 TableBackgroundPainter::ComputeCellBackgrounds(nsTableCellFrame* aCell,
                                                nsRect&           aCellBGRect,
                                                nsRect&           aRowBGRect,
                                                nsRect&           aRowGroupBGRect,
                                                nsRect&           aColBGRect)
--- a/layout/tables/nsTablePainter.h
+++ b/layout/tables/nsTablePainter.h
@@ -1,16 +1,18 @@
 /* -*- 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
 
@@ -22,16 +24,18 @@ 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
@@ -75,80 +79,89 @@ 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.
       */
-    nsresult PaintTable(nsTableFrame* aTableFrame, const nsMargin& aDeflate,
-                        bool aPaintTableBackground);
+    DrawResult 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.
       */
-    nsresult PaintRowGroup(nsTableRowGroupFrame* aFrame)
+    DrawResult 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.
       */
-    nsresult PaintRow(nsTableRowFrame* aFrame)
+    DrawResult 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
       */
-    nsresult PaintTableFrame(nsTableFrame*         aTableFrame,
-                             nsTableRowGroupFrame* aFirstRowGroup,
-                             nsTableRowGroupFrame* aLastRowGroup,
-                             const nsMargin&       aDeflate);
+    DrawResult 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
      */
-    nsresult PaintRowGroup(nsTableRowGroupFrame* aFrame,
-                           bool                  aPassThrough);
-    nsresult PaintRow(nsTableRowFrame* aFrame,
-                      bool             aPassThrough);
+    DrawResult PaintRowGroup(nsTableRowGroupFrame* aFrame,
+                             bool                  aPassThrough);
+    DrawResult 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
       */
-    nsresult PaintCell(nsTableCellFrame* aCell,
-                       nsRect&           aCellBGRect,
-                       nsRect&           aRowBGRect,
-                       nsRect&           aRowGroupBGRect,
-                       nsRect&           aColBGRect,
-                       bool              aPassSelf);
+    DrawResult 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
@@ -200,18 +213,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 */
-      nsresult SetBCBorder(nsMargin&               aBorderWidth,
-                           TableBackgroundPainter* aPainter);
+      void 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
@@ -20,16 +20,17 @@
 #include "nsTableColGroupFrame.h"
 #include "nsTableColFrame.h"
 #include "nsCOMPtr.h"
 #include "nsDisplayList.h"
 #include "nsIFrameInlines.h"
 #include <algorithm>
 
 using namespace mozilla;
+using namespace mozilla::image;
 
 struct nsTableCellReflowState : public nsHTMLReflowState
 {
   nsTableCellReflowState(nsPresContext*           aPresContext,
                          const nsHTMLReflowState& aParentReflowState,
                          nsIFrame*                aFrame,
                          const LogicalSize&       aAvailableSpace,
                          uint32_t                 aFlags = 0)
@@ -530,50 +531,63 @@ 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)
 {
-  if (aBuilder->ShouldSyncDecodeImages()) {
-    if (nsTableFrame::AnyTablePartHasUndecodedBackgroundImage(mFrame, mFrame->GetNextSibling())) {
-      bool snap;
-      aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
-    }
+  auto geometry =
+    static_cast<const nsDisplayItemGenericImageGeometry*>(aGeometry);
+
+  if (aBuilder->ShouldSyncDecodeImages() &&
+      geometry->ShouldInvalidateToSyncDecodeImages()) {
+    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());
-  painter.PaintRow(static_cast<nsTableRowFrame*>(mFrame));
+
+  DrawResult result =
+    painter.PaintRow(static_cast<nsTableRowFrame*>(mFrame));
+
+  nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, result);
 }
 
 void
 nsTableRowFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                   const nsRect&           aDirtyRect,
                                   const nsDisplayListSet& aLists)
 {
   nsDisplayTableItem* item = nullptr;
--- a/layout/tables/nsTableRowGroupFrame.cpp
+++ b/layout/tables/nsTableRowGroupFrame.cpp
@@ -17,16 +17,17 @@
 #include "nsHTMLParts.h"
 #include "nsCSSFrameConstructor.h"
 #include "nsDisplayList.h"
 
 #include "nsCellMap.h"//table cell navigation
 #include <algorithm>
 
 using namespace mozilla;
+using namespace mozilla::image;
 using namespace mozilla::layout;
 
 nsTableRowGroupFrame::nsTableRowGroupFrame(nsStyleContext* aContext):
   nsContainerFrame(aContext)
 {
   SetRepeatable(false);
 }
 
@@ -142,51 +143,64 @@ 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)
 {
-  if (aBuilder->ShouldSyncDecodeImages()) {
-    if (nsTableFrame::AnyTablePartHasUndecodedBackgroundImage(mFrame, mFrame->GetNextSibling())) {
-      bool snap;
-      aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
-    }
+  auto geometry =
+    static_cast<const nsDisplayItemGenericImageGeometry*>(aGeometry);
+
+  if (aBuilder->ShouldSyncDecodeImages() &&
+      geometry->ShouldInvalidateToSyncDecodeImages()) {
+    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());
-  painter.PaintRowGroup(static_cast<nsTableRowGroupFrame*>(mFrame));
+
+  DrawResult result =
+    painter.PaintRowGroup(static_cast<nsTableRowGroupFrame*>(mFrame));
+
+  nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, result);
 }
 
 // Handle the child-traversal part of DisplayGenericTablePart
 static void
 DisplayRows(nsDisplayListBuilder* aBuilder, nsFrame* aFrame,
             const nsRect& aDirtyRect, const nsDisplayListSet& aLists)
 {
   nscoord overflowAbove;