Bug 1128769 (Part 4) - Record the last draw result when drawing CSS tables and use it to decide whether to sync decode. r=tn
authorSeth Fowler <seth@mozilla.com>
Thu, 05 Feb 2015 20:45:56 -0800
changeset 241885 a72dc404ea1ff83b8c53129b6b9af773a7b53375
parent 241884 d6c37a5ec39cc1d7891728369de0b55e465f4306
child 241886 e2239d5fcb1e9c2b9d17dc65e734b5ce81069426
push id625
push userdburns@mozilla.com
push dateTue, 10 Feb 2015 14:14:40 +0000
reviewerstn
bugs1128769
milestone38.0a1
Bug 1128769 (Part 4) - Record the last draw result when drawing CSS tables and use it to decide whether to sync decode. r=tn
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 {
 
@@ -1102,16 +1103,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)
 };
 
@@ -1124,62 +1126,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)
@@ -1340,30 +1329,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.
-  painter.PaintTable(this, deflate, deflate != nsMargin(0, 0, 0, 0));
+  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);
     }
@@ -1377,16 +1367,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
 
   NS_DECLARE_FRAME_PROPERTY(PositionedTablePartArray,
                             DeleteValue<nsTArray<nsIFrame*>>)
 
   /** 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
@@ -90,16 +90,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)
   , mUsesSynthBorder(false)
 {
 }
 
 TableBackgroundPainter::TableBackgroundData::TableBackgroundData(nsIFrame* aFrame)
@@ -180,17 +182,26 @@ TableBackgroundPainter::TableBackgroundP
   mNumCols = aTableFrame->GetColCount();
 }
 
 TableBackgroundPainter::~TableBackgroundPainter()
 {
   MOZ_COUNT_DTOR(TableBackgroundPainter);
 }
 
-void
+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)
 {
   MOZ_ASSERT(aTableFrame, "null frame");
   TableBackgroundData tableData(aTableFrame);
   tableData.mRect.MoveTo(0,0); //using table's coords
@@ -215,24 +226,30 @@ TableBackgroundPainter::PaintTableFrame(
         border.top = tempBorder.top;
       }
 
       border.left = aTableFrame->GetContinuousLeftBCBorderWidth();
 
       tableData.SetBCBorder(border);
     }
   }
+
+  DrawResult result = DrawResult::SUCCESS;
+
   if (tableData.IsVisible()) {
-    nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
-                                          tableData.mFrame, mDirtyRect,
-                                          tableData.mRect + mRenderPt,
-                                          tableData.mFrame->StyleContext(),
-                                          tableData.StyleBorder(mZeroBorder),
-                                          mBGPaintFlags);
+    result =
+      nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
+                                            tableData.mFrame, mDirtyRect,
+                                            tableData.mRect + mRenderPt,
+                                            tableData.mFrame->StyleContext(),
+                                            tableData.StyleBorder(mZeroBorder),
+                                            mBGPaintFlags);
   }
+
+  return result;
 }
 
 void
 TableBackgroundPainter::TranslateContext(nscoord aDX,
                                          nscoord aDY)
 {
   mRenderPt += nsPoint(aDX, aDY);
   for (auto& col : mCols) {
@@ -244,32 +261,34 @@ TableBackgroundPainter::TranslateContext
 }
 
 TableBackgroundPainter::ColData::ColData(nsIFrame* aFrame, TableBackgroundData& aColGroupBGData)
   : mCol(aFrame)
   , mColGroup(aColGroupBGData)
 {
 }
 
-void
+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;
+    return result;
   }
 
   if (aPaintTableBackground) {
     PaintTableFrame(aTableFrame, rowGroups[0], rowGroups[rowGroups.Length() - 1],
                     aDeflate);
   }
 
   /*Set up column background/border data*/
@@ -338,28 +357,32 @@ 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)) {
-      PaintRowGroup(rg, rowGroupBGData, rg->IsPseudoStackingContextFromStyle());
+      DrawResult rowGroupResult =
+        PaintRowGroup(rg, rowGroupBGData, rg->IsPseudoStackingContextFromStyle());
+      UpdateDrawResult(&result, rowGroupResult);
     }
   }
+
+  return result;
 }
 
-void
+DrawResult
 TableBackgroundPainter::PaintRowGroup(nsTableRowGroupFrame* aFrame)
 {
-  PaintRowGroup(aFrame, TableBackgroundData(aFrame), false);
+  return PaintRowGroup(aFrame, TableBackgroundData(aFrame), false);
 }
 
-void
+DrawResult
 TableBackgroundPainter::PaintRowGroup(nsTableRowGroupFrame* aFrame,
                                       TableBackgroundData   aRowGroupBGData,
                                       bool                  aPassThrough)
 {
   MOZ_ASSERT(aFrame, "null frame");
 
   nsTableRowFrame* firstRow = aFrame->GetFirstRow();
 
@@ -407,48 +430,55 @@ TableBackgroundPainter::PaintRowGroup(ns
   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()) {
     TableBackgroundData rowBackgroundData(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(rowBackgroundData.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;
     }
     
-    PaintRow(row, aRowGroupBGData, rowBackgroundData,
-             aPassThrough || row->IsPseudoStackingContextFromStyle());
+    DrawResult rowResult =
+      PaintRow(row, aRowGroupBGData, rowBackgroundData,
+               aPassThrough || row->IsPseudoStackingContextFromStyle());
+
+    UpdateDrawResult(&result, rowResult);
   }
 
   /* translate back into table coord system */
   if (eOrigin_TableRowGroup != mOrigin) {
     TranslateContext(-rgRect.x, -rgRect.y);
   }
+
+  return result;
 }
 
-void
+DrawResult
 TableBackgroundPainter::PaintRow(nsTableRowFrame* aFrame)
 {
   return PaintRow(aFrame, TableBackgroundData(), TableBackgroundData(aFrame), false);
 }
 
-void
+DrawResult
 TableBackgroundPainter::PaintRow(nsTableRowFrame* aFrame,
                                  const TableBackgroundData& aRowGroupBGData,
                                  TableBackgroundData aRowBGData,
                                  bool             aPassThrough)
 {
   MOZ_ASSERT(aFrame, "null frame");
 
   /* Load row data */
@@ -475,112 +505,134 @@ TableBackgroundPainter::PaintRow(nsTable
 
   /* Translate */
   if (eOrigin_TableRow == mOrigin) {
     /* If we originate from the row, then make the row the origin. */
     aRowBGData.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, aRowGroupBGData, aRowBGData,
                            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();
-      PaintCell(cell, aRowGroupBGData, aRowBGData,
-                cellBGRect, rowBGRect, rowGroupBGRect, colBGRect, passCell);
+      DrawResult cellResult =
+        PaintCell(cell, aRowGroupBGData, aRowBGData,
+                  cellBGRect, rowBGRect, rowGroupBGRect, colBGRect, passCell);
+
+      UpdateDrawResult(&result, cellResult);
     }
   }
+
+  return result;
 }
 
-void
+DrawResult
 TableBackgroundPainter::PaintCell(nsTableCellFrame* aCell,
                                   const TableBackgroundData& aRowGroupBGData,
                                   const TableBackgroundData& aRowBGData,
                                   nsRect&           aCellBGRect,
                                   nsRect&           aRowBGRect,
                                   nsRect&           aRowGroupBGRect,
                                   nsRect&           aColBGRect,
                                   bool              aPassSelf)
 {
   MOZ_ASSERT(aCell, "null frame");
 
   const nsStyleTableBorder* cellTableStyle;
   cellTableStyle = aCell->StyleTableBorder();
   if (NS_STYLE_TABLE_EMPTY_CELLS_SHOW != cellTableStyle->mEmptyCells &&
       aCell->GetContentEmpty() && !mIsBorderCollapse) {
-    return;
+    return DrawResult::SUCCESS;
   }
 
   int32_t colIndex;
   aCell->GetColIndex(colIndex);
   // We're checking mNumCols instead of mCols.Length() here because mCols can
   // be empty even if mNumCols > 0.
   NS_ASSERTION(size_t(colIndex) < mNumCols, "out-of-bounds column index");
-  if (size_t(colIndex) >= mNumCols)
-    return;
+  if (size_t(colIndex) >= mNumCols) {
+    return DrawResult::SUCCESS;
+  }
 
   // If callers call PaintRowGroup or PaintRow directly, we haven't processed
   // our columns. Ignore column / col group backgrounds in that case.
   bool haveColumns = !mCols.IsEmpty();
 
+  DrawResult result = DrawResult::SUCCESS;
+
   //Paint column group background
   if (haveColumns && 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.StyleBorder(mZeroBorder),
-                                          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.StyleBorder(mZeroBorder),
+                                            mBGPaintFlags, &aColBGRect);
+    UpdateDrawResult(&result, colGroupResult);
   }
 
   //Paint column background
   if (haveColumns && 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.StyleBorder(mZeroBorder),
-                                          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.StyleBorder(mZeroBorder),
+                                            mBGPaintFlags, &aColBGRect);
+    UpdateDrawResult(&result, colResult);
   }
 
   //Paint row group background
   if (aRowGroupBGData.IsVisible()) {
-    nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
-                                          aRowGroupBGData.mFrame, mDirtyRect,
-                                          aRowGroupBGData.mRect + mRenderPt,
-                                          aRowGroupBGData.mFrame->StyleContext(),
-                                          aRowGroupBGData.StyleBorder(mZeroBorder),
-                                          mBGPaintFlags, &aRowGroupBGRect);
+    DrawResult rowGroupResult =
+      nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
+                                            aRowGroupBGData.mFrame, mDirtyRect,
+                                            aRowGroupBGData.mRect + mRenderPt,
+                                            aRowGroupBGData.mFrame->StyleContext(),
+                                            aRowGroupBGData.StyleBorder(mZeroBorder),
+                                            mBGPaintFlags, &aRowGroupBGRect);
+    UpdateDrawResult(&result, rowGroupResult);
   }
 
   //Paint row background
   if (aRowBGData.IsVisible()) {
-    nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
-                                          aRowBGData.mFrame, mDirtyRect,
-                                          aRowBGData.mRect + mRenderPt,
-                                          aRowBGData.mFrame->StyleContext(),
-                                          aRowBGData.StyleBorder(mZeroBorder),
-                                          mBGPaintFlags, &aRowBGRect);
+    DrawResult rowResult =
+      nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
+                                            aRowBGData.mFrame, mDirtyRect,
+                                            aRowBGData.mRect + mRenderPt,
+                                            aRowBGData.mFrame->StyleContext(),
+                                            aRowBGData.StyleBorder(mZeroBorder),
+                                            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 result;
 }
 
 void
 TableBackgroundPainter::ComputeCellBackgrounds(nsTableCellFrame* aCell,
                                                const TableBackgroundData& aRowGroupBGData,
                                                const TableBackgroundData& aRowBGData,
                                                nsRect&           aCellBGRect,
                                                nsRect&           aRowBGRect,
--- 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,89 +79,98 @@ 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.
       */
-    void 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.
       */
-    void PaintRowGroup(nsTableRowGroupFrame* aFrame);
+    DrawResult PaintRowGroup(nsTableRowGroupFrame* aFrame);
 
     /** 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.
       */
-    void PaintRow(nsTableRowFrame* aFrame);
+    DrawResult PaintRow(nsTableRowFrame* aFrame);
 
   private:
     struct TableBackgroundData;
 
     /** 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
       */
-    void 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.
      * aRowGroupBGData is not a const reference because the function modifies
      * its copy. Same for aRowBGData in PaintRow.
      * See Public versions for function descriptions
      */
-    void PaintRowGroup(nsTableRowGroupFrame* aFrame,
-                       TableBackgroundData   aRowGroupBGData,
-                       bool                  aPassThrough);
+    DrawResult PaintRowGroup(nsTableRowGroupFrame* aFrame,
+                             TableBackgroundData   aRowGroupBGData,
+                             bool                  aPassThrough);
 
-    void PaintRow(nsTableRowFrame* aFrame,
-                  const TableBackgroundData& aRowGroupBGData,
-                  TableBackgroundData aRowBGData,
-                  bool             aPassThrough);
+    DrawResult PaintRow(nsTableRowFrame* aFrame,
+                        const TableBackgroundData& aRowGroupBGData,
+                        TableBackgroundData aRowBGData,
+                        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 aRowGroupBGData - background drawing info for the row group
       * @param aRowBGData      - background drawing info for the row
       * @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
       */
-    void PaintCell(nsTableCellFrame* aCell,
-                   const TableBackgroundData& aRowGroupBGData,
-                   const TableBackgroundData& aRowBGData,
-                   nsRect&           aCellBGRect,
-                   nsRect&           aRowBGRect,
-                   nsRect&           aRowGroupBGRect,
-                   nsRect&           aColBGRect,
-                   bool              aPassSelf);
+    DrawResult PaintCell(nsTableCellFrame* aCell,
+                         const TableBackgroundData& aRowGroupBGData,
+                         const TableBackgroundData& aRowBGData,
+                         nsRect&           aCellBGRect,
+                         nsRect&           aRowBGRect,
+                         nsRect&           aRowGroupBGRect,
+                         nsRect&           aColBGRect,
+                         bool              aPassSelf);
 
     /** Compute table background layer positions for this cell space
       * @param aCell              - the cell
       * @param aRowGroupBGData    - background drawing info for the row group
       * @param aRowBGData         - background drawing info for the row
       * @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
--- a/layout/tables/nsTableRowFrame.cpp
+++ b/layout/tables/nsTableRowFrame.cpp
@@ -530,50 +530,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
@@ -142,51 +142,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;