Backed out changeset 93acd240b578 (bug 929484) for reftest failures in border-separate-opacity-table-column-group.html
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Thu, 04 May 2017 17:00:20 +0200
changeset 356503 3f788935a3a4c1c6b65729298c497f06687f52ad
parent 356502 5d9cdb47c1b93d649ec3437a0c6d545d058ca672
child 356504 9499b714afc482732c2fa3da54b353f79a2322b8
push id89910
push usercbook@mozilla.com
push dateThu, 04 May 2017 15:00:30 +0000
treeherdermozilla-inbound@3f788935a3a4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs929484
milestone55.0a1
backs out93acd240b5782a90f1ce9bd4059f64907fa98137
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out changeset 93acd240b578 (bug 929484) for reftest failures in border-separate-opacity-table-column-group.html
layout/painting/nsDisplayItemTypesList.h
layout/painting/nsDisplayList.cpp
layout/painting/nsDisplayList.h
layout/tables/nsTableCellFrame.cpp
layout/tables/nsTableColFrame.cpp
layout/tables/nsTableColFrame.h
layout/tables/nsTableColGroupFrame.cpp
layout/tables/nsTableColGroupFrame.h
layout/tables/nsTableFrame.cpp
layout/tables/nsTableFrame.h
layout/tables/nsTableRowFrame.cpp
layout/tables/nsTableRowGroupFrame.cpp
layout/tables/nsTableWrapperFrame.cpp
--- a/layout/painting/nsDisplayItemTypesList.h
+++ b/layout/painting/nsDisplayItemTypesList.h
@@ -54,17 +54,16 @@ DECLARE_DISPLAY_ITEM_TYPE(FILTER)
 DECLARE_DISPLAY_ITEM_TYPE(SVG_OUTER_SVG)
 DECLARE_DISPLAY_ITEM_TYPE(SVG_GEOMETRY)
 DECLARE_DISPLAY_ITEM_TYPE(SVG_TEXT)
 DECLARE_DISPLAY_ITEM_TYPE(TABLE_CELL_BACKGROUND)
 DECLARE_DISPLAY_ITEM_TYPE(TABLE_CELL_SELECTION)
 DECLARE_DISPLAY_ITEM_TYPE(TABLE_ROW_BACKGROUND)
 DECLARE_DISPLAY_ITEM_TYPE(TABLE_ROW_GROUP_BACKGROUND)
 DECLARE_DISPLAY_ITEM_TYPE(TABLE_BORDER_BACKGROUND)
-DECLARE_DISPLAY_ITEM_TYPE(TABLE_BORDER_COLLAPSE)
 DECLARE_DISPLAY_ITEM_TYPE(TEXT)
 DECLARE_DISPLAY_ITEM_TYPE(TEXT_OVERFLOW)
 DECLARE_DISPLAY_ITEM_TYPE_FLAGS(TRANSFORM,TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE_FLAGS(PERSPECTIVE,TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE(VIDEO)
 DECLARE_DISPLAY_ITEM_TYPE(WRAP_LIST)
 DECLARE_DISPLAY_ITEM_TYPE(ZOOM)
 
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -3057,26 +3057,21 @@ SpecialCutoutRegionCase(nsDisplayListBui
 
 
 /*static*/ bool
 nsDisplayBackgroundImage::AppendBackgroundItemsToTop(nsDisplayListBuilder* aBuilder,
                                                      nsIFrame* aFrame,
                                                      const nsRect& aBackgroundRect,
                                                      nsDisplayList* aList,
                                                      bool aAllowWillPaintBorderOptimization,
-                                                     nsStyleContext* aStyleContext,
-                                                     const nsRect& aBackgroundOriginRect)
+                                                     nsStyleContext* aStyleContext)
 {
   nsStyleContext* bgSC = aStyleContext;
   const nsStyleBackground* bg = nullptr;
   nsRect bgRect = aBackgroundRect + aBuilder->ToReferenceFrame(aFrame);
-  nsRect bgOriginRect = bgRect;
-  if (!aBackgroundOriginRect.IsEmpty()) {
-    bgOriginRect = aBackgroundOriginRect + aBuilder->ToReferenceFrame(aFrame);
-  }
   nsPresContext* presContext = aFrame->PresContext();
   bool isThemed = aFrame->IsThemed();
   if (!isThemed) {
     if (!bgSC) {
       bgSC = GetBackgroundStyleContext(aFrame);
     }
     if (bgSC) {
       bg = bgSC->StyleBackground();
@@ -3175,17 +3170,17 @@ nsDisplayBackgroundImage::AppendBackgrou
     if (!aBuilder->IsForEventDelivery()) {
       const nsStyleImageLayers::Layer& layer = bg->mImage.mLayers[i];
       SetBackgroundClipRegion(clipState, aFrame, toRef,
                               layer, bgRect, willPaintBorder);
     }
 
     nsDisplayList thisItemList;
     nsDisplayBackgroundImage::InitData bgData =
-      nsDisplayBackgroundImage::GetInitData(aBuilder, aFrame, i, bgOriginRect, bg,
+      nsDisplayBackgroundImage::GetInitData(aBuilder, aFrame, i, bgRect, bg,
                                             LayerizeFixed::DO_NOT_LAYERIZE_FIXED_BACKGROUND_IF_AVOIDING_COMPONENT_ALPHA_LAYERS);
 
     if (bgData.shouldFixToViewport) {
 
       auto* displayData = aBuilder->GetCurrentFixedBackgroundDisplayData();
       nsDisplayListBuilder::AutoBuildingDisplayList
         buildingDisplayList(aBuilder, aFrame, aBuilder->GetDirtyRect(), false);
 
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -3066,18 +3066,17 @@ public:
   // aAllowWillPaintBorderOptimization should usually be left at true, unless
   // aFrame has special border drawing that causes opaque borders to not
   // actually be opaque.
   static bool AppendBackgroundItemsToTop(nsDisplayListBuilder* aBuilder,
                                          nsIFrame* aFrame,
                                          const nsRect& aBackgroundRect,
                                          nsDisplayList* aList,
                                          bool aAllowWillPaintBorderOptimization = true,
-                                         nsStyleContext* aStyleContext = nullptr,
-                                         const nsRect& aBackgroundOriginRect = nsRect());
+                                         nsStyleContext* aStyleContext = nullptr);
 
   virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
                                    LayerManager* aManager,
                                    const ContainerLayerParameters& aParameters) override;
 
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aContainerParameters) override;
--- a/layout/tables/nsTableCellFrame.cpp
+++ b/layout/tables/nsTableCellFrame.cpp
@@ -485,61 +485,81 @@ PaintTableCellSelection(nsIFrame* aFrame
 }
 
 void
 nsTableCellFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                    const nsRect&           aDirtyRect,
                                    const nsDisplayListSet& aLists)
 {
   DO_GLOBAL_REFLOW_COUNT_DSP("nsTableCellFrame");
-  nsTableFrame* tableFrame = GetTableFrame();
-  int32_t emptyCellStyle = GetContentEmpty() && !tableFrame->IsBorderCollapse() ?
-                              StyleTableBorder()->mEmptyCells
-                              : NS_STYLE_TABLE_EMPTY_CELLS_SHOW;
-  // take account of 'empty-cells'
-  if (StyleVisibility()->IsVisible() &&
-      (NS_STYLE_TABLE_EMPTY_CELLS_HIDE != emptyCellStyle)) {
-    // display outset box-shadows if we need to.
-    bool hasBoxShadow = !!StyleEffects()->mBoxShadow;
-    if (hasBoxShadow) {
-      aLists.BorderBackground()->AppendNewToTop(
-        new (aBuilder) nsDisplayBoxShadowOuter(aBuilder, this));
+  if (IsVisibleInSelection(aBuilder)) {
+    nsTableFrame* tableFrame = GetTableFrame();
+    int32_t emptyCellStyle = GetContentEmpty() && !tableFrame->IsBorderCollapse() ?
+                                StyleTableBorder()->mEmptyCells
+                                : NS_STYLE_TABLE_EMPTY_CELLS_SHOW;
+    // take account of 'empty-cells'
+    if (StyleVisibility()->IsVisible() &&
+        (NS_STYLE_TABLE_EMPTY_CELLS_HIDE != emptyCellStyle)) {
+      // display outset box-shadows if we need to.
+      bool hasBoxShadow = !!StyleEffects()->mBoxShadow;
+      if (hasBoxShadow) {
+        aLists.BorderBackground()->AppendNewToTop(
+          new (aBuilder) nsDisplayBoxShadowOuter(aBuilder, this));
+      }
+    
+      // display background if we need to.
+      if (aBuilder->IsForEventDelivery() ||
+          !StyleBackground()->IsTransparent(this) ||
+          StyleDisplay()->UsedAppearance()) {
+        if (!tableFrame->IsBorderCollapse()) {
+          nsDisplayBackgroundImage::AppendBackgroundItemsToTop(aBuilder,
+              this,
+              GetRectRelativeToSelf(),
+              aLists.BorderBackground());
+        } else if (aBuilder->IsAtRootOfPseudoStackingContext() ||
+                   aBuilder->IsForEventDelivery()) {
+          // The cell background was not painted by the nsTablePainter,
+          // so we need to do it. We have special background processing here
+          // so we need to duplicate some code from nsFrame::DisplayBorderBackgroundOutline
+          nsDisplayTableItem* item =
+            new (aBuilder) nsDisplayTableCellBackground(aBuilder, this);
+          aLists.BorderBackground()->AppendNewToTop(item);
+          item->UpdateForFrameBackground(this);
+        } else {
+          // The nsTablePainter will paint our background. Make sure it
+          // knows if we're background-attachment:fixed.
+          nsDisplayTableItem* currentItem = aBuilder->GetCurrentTableItem();
+          if (currentItem) {
+            currentItem->UpdateForFrameBackground(this);
+          }
+        }
+      }
+    
+      // display inset box-shadows if we need to.
+      if (hasBoxShadow) {
+        aLists.BorderBackground()->AppendNewToTop(
+          new (aBuilder) nsDisplayBoxShadowInner(aBuilder, this));
+      }
+    
+      // display borders if we need to
+      ProcessBorders(tableFrame, aBuilder, aLists);
+    
+      // and display the selection border if we need to
+      if (IsSelected()) {
+        aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
+          nsDisplayGeneric(aBuilder, this, ::PaintTableCellSelection,
+                           "TableCellSelection",
+                           nsDisplayItem::TYPE_TABLE_CELL_SELECTION));
+      }
     }
-
-    // display background if we need to.
-    if (aBuilder->IsForEventDelivery() ||
-        !StyleBackground()->IsTransparent(this) ||
-        StyleDisplay()->UsedAppearance()) {
-      nsDisplayBackgroundImage::AppendBackgroundItemsToTop(aBuilder,
-          this,
-          GetRectRelativeToSelf(),
-          aLists.BorderBackground());
-    }
-
-    // display inset box-shadows if we need to.
-    if (hasBoxShadow) {
-      aLists.BorderBackground()->AppendNewToTop(
-        new (aBuilder) nsDisplayBoxShadowInner(aBuilder, this));
-    }
-
-    // display borders if we need to
-    ProcessBorders(tableFrame, aBuilder, aLists);
-
-    // and display the selection border if we need to
-    if (IsSelected()) {
-      aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
-        nsDisplayGeneric(aBuilder, this, ::PaintTableCellSelection,
-                         "TableCellSelection",
-                         nsDisplayItem::TYPE_TABLE_CELL_SELECTION));
-    }
+    
+    // the 'empty-cells' property has no effect on 'outline'
+    DisplayOutline(aBuilder, aLists);
   }
 
-  // the 'empty-cells' property has no effect on 'outline'
-  DisplayOutline(aBuilder, aLists);
-
   // Push a null 'current table item' so that descendant tables can't
   // accidentally mess with our table
   nsAutoPushCurrentTableItem pushTableItem;
   pushTableItem.Push(aBuilder, nullptr);
 
   nsIFrame* kid = mFrames.FirstChild();
   NS_ASSERTION(kid && !kid->GetNextSibling(), "Table cells should have just one child");
   // The child's background will go in our BorderBackground() list.
--- a/layout/tables/nsTableColFrame.cpp
+++ b/layout/tables/nsTableColFrame.cpp
@@ -117,24 +117,16 @@ nsTableColFrame::Reflow(nsPresContext*  
   bool collapseCol = (NS_STYLE_VISIBILITY_COLLAPSE == colVis->mVisible);
   if (collapseCol) {
     GetTableFrame()->SetNeedToCollapse(true);
   }
   aStatus.Reset();
   NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
 }
 
-void
-nsTableColFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
-                                  const nsRect&           aDirtyRect,
-                                  const nsDisplayListSet& aLists)
-{
-  nsTableFrame::DisplayGenericTablePart(aBuilder, this, aDirtyRect, aLists);
-}
-
 int32_t nsTableColFrame::GetSpan()
 {
   return StyleTable()->mSpan;
 }
 
 #ifdef DEBUG
 void nsTableColFrame::Dump(int32_t aIndent)
 {
--- a/layout/tables/nsTableColFrame.h
+++ b/layout/tables/nsTableColFrame.h
@@ -48,19 +48,22 @@ public:
   /** @see nsIFrame::DidSetStyleContext */
   virtual void DidSetStyleContext(nsStyleContext* aOldStyleContext) override;
 
   virtual void Reflow(nsPresContext*           aPresContext,
                       ReflowOutput&     aDesiredSize,
                       const ReflowInput& aReflowInput,
                       nsReflowStatus&          aStatus) override;
 
+  /**
+   * Table columns never paint anything, nor receive events.
+   */
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsRect&           aDirtyRect,
-                                const nsDisplayListSet& aLists) override;
+                                const nsDisplayListSet& aLists) override {}
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override;
 #endif
 
   virtual nsSplittableType GetSplittableType() const override;
 
   nsTableColGroupFrame* GetTableColGroupFrame() const
--- a/layout/tables/nsTableColGroupFrame.cpp
+++ b/layout/tables/nsTableColGroupFrame.cpp
@@ -381,24 +381,16 @@ nsTableColGroupFrame::Reflow(nsPresConte
     FinishReflowChild(kidFrame, aPresContext, kidSize, nullptr, 0, 0, 0);
   }
 
   aDesiredSize.ClearSize();
   aStatus.Reset();
   NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
 }
 
-void
-nsTableColGroupFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
-                                       const nsRect&           aDirtyRect,
-                                       const nsDisplayListSet& aLists)
-{
-  nsTableFrame::DisplayGenericTablePart(aBuilder, this, aDirtyRect, aLists);
-}
-
 nsTableColFrame * nsTableColGroupFrame::GetFirstColumn()
 {
   return GetNextColumn(nullptr);
 }
 
 nsTableColFrame * nsTableColGroupFrame::GetNextColumn(nsIFrame *aChildFrame)
 {
   nsTableColFrame *result = nullptr;
--- a/layout/tables/nsTableColGroupFrame.h
+++ b/layout/tables/nsTableColGroupFrame.h
@@ -45,19 +45,22 @@ public:
   {
     nsIFrame* parent = GetParent();
     MOZ_ASSERT(parent && parent->IsTableFrame());
     MOZ_ASSERT(!parent->GetPrevInFlow(),
                "Col group should always be in a first-in-flow table frame");
     return static_cast<nsTableFrame*>(parent);
   }
 
+  /**
+   * ColGroups never paint anything, nor receive events.
+   */
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsRect&           aDirtyRect,
-                                const nsDisplayListSet& aLists) override;
+                                const nsDisplayListSet& aLists) override {}
 
   /** A colgroup can be caused by three things:
     * 1)	An element with table-column-group display
     * 2)	An element with a table-column display without a
 	   *    table-column-group parent
     * 3)	Cells that are not in a column (and hence get an anonymous
 	   *    column and colgroup).
     * @return colgroup type
--- a/layout/tables/nsTableFrame.cpp
+++ b/layout/tables/nsTableFrame.cpp
@@ -1233,56 +1233,16 @@ nsDisplayTableItem::ComputeInvalidationR
        geometry->ShouldInvalidateToSyncDecodeImages())) {
     bool snap;
     aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
   }
 
   nsDisplayItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
 }
 
-// A display item that draws all collapsed borders for a table.
-// At some point, we may want to find a nicer partitioning for dividing
-// border-collapse segments into their own display items.
-class nsDisplayTableBorderCollapse : public nsDisplayTableItem {
-public:
-  nsDisplayTableBorderCollapse(nsDisplayListBuilder* aBuilder,
-                               nsTableFrame* aFrame)
-    : nsDisplayTableItem(aBuilder, aFrame) {
-    MOZ_COUNT_CTOR(nsDisplayTableBorderCollapse);
-    }
-#ifdef NS_BUILD_REFCNT_LOGGING
-  virtual ~nsDisplayTableBorderCollapse() {
-    MOZ_COUNT_DTOR(nsDisplayTableBorderCollapse);
-  }
-#endif
-
-  virtual void Paint(nsDisplayListBuilder* aBuilder,
-                     nsRenderingContext* aCtx) override;
-  NS_DISPLAY_DECL_NAME("TableBorderCollapse", TYPE_TABLE_BORDER_COLLAPSE)
-};
-
-void
-nsDisplayTableBorderCollapse::Paint(nsDisplayListBuilder* aBuilder,
-                                    nsRenderingContext* aCtx)
-{
-  nsPoint pt = ToReferenceFrame();
-  DrawTarget* drawTarget = aCtx->GetDrawTarget();
-
-  gfxPoint devPixelOffset =
-    nsLayoutUtils::PointToGfxPoint(pt, mFrame->PresContext()->AppUnitsPerDevPixel());
-
-  // XXX we should probably get rid of this translation at some stage
-  // But that would mean modifying PaintBCBorders, ugh
-  AutoRestoreTransform autoRestoreTransform(drawTarget);
-  drawTarget->SetTransform(
-      drawTarget->GetTransform().PreTranslate(ToPoint(devPixelOffset)));
-
-  static_cast<nsTableFrame*>(mFrame)->PaintBCBorders(*drawTarget, mVisibleRect - pt);
-}
-
 class nsDisplayTableBorderBackground : public nsDisplayTableItem {
 public:
   nsDisplayTableBorderBackground(nsDisplayListBuilder* aBuilder,
                                  nsTableFrame* aFrame,
                                  bool aDrawsBackground) :
     nsDisplayTableItem(aBuilder, aFrame, aDrawsBackground) {
     MOZ_COUNT_CTOR(nsDisplayTableBorderBackground);
   }
@@ -1292,185 +1252,136 @@ public:
   }
 #endif
 
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      nsRenderingContext* aCtx) override;
   NS_DISPLAY_DECL_NAME("TableBorderBackground", TYPE_TABLE_BORDER_BACKGROUND)
 };
 
+#ifdef DEBUG
+static bool
+IsFrameAllowedInTable(LayoutFrameType aType)
+{
+  return IS_TABLE_CELL(aType) ||
+         LayoutFrameType::TableRow == aType ||
+         LayoutFrameType::TableRowGroup == aType ||
+         LayoutFrameType::Scroll == aType ||
+         LayoutFrameType::Table == aType ||
+         LayoutFrameType::TableCol == aType ||
+         LayoutFrameType::TableColGroup == aType;
+}
+#endif
+
 void
 nsDisplayTableBorderBackground::Paint(nsDisplayListBuilder* aBuilder,
                                       nsRenderingContext* aCtx)
 {
   DrawResult result = static_cast<nsTableFrame*>(mFrame)->
     PaintTableBorderBackground(aBuilder, *aCtx, mVisibleRect,
                                ToReferenceFrame());
 
   nsDisplayTableItemGeometry::UpdateDrawResult(this, result);
 }
 
+static int32_t
+GetTablePartRank(nsDisplayItem* aItem)
+{
+  LayoutFrameType type = aItem->Frame()->Type();
+  if (type == LayoutFrameType::Table)
+    return 0;
+  if (type == LayoutFrameType::TableRowGroup)
+    return 1;
+  if (type == LayoutFrameType::TableRow)
+    return 2;
+  return 3;
+}
+
+struct TablePartRankComparator {
+  bool operator()(nsDisplayItem* aItem1, nsDisplayItem* aItem2) const {
+    return GetTablePartRank(aItem1) < GetTablePartRank(aItem2);
+  }
+};
+
 /* static */ void
 nsTableFrame::GenericTraversal(nsDisplayListBuilder* aBuilder, nsFrame* aFrame,
                                const nsRect& aDirtyRect, const nsDisplayListSet& aLists)
 {
   // This is similar to what nsContainerFrame::BuildDisplayListForNonBlockChildren
   // does, except that we allow the children's background and borders to go
   // in our BorderBackground list. This doesn't really affect background
   // painting --- the children won't actually draw their own backgrounds
   // because the nsTableFrame already drew them, unless a child has its own
   // stacking context, in which case the child won't use its passed-in
   // BorderBackground list anyway. It does affect cell borders though; this
   // lets us get cell borders into the nsTableFrame's BorderBackground list.
-  for (nsIFrame* kid : aFrame->GetChildList(kColGroupList)) {
-    aFrame->BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists);
-  }
-
   for (nsIFrame* kid : aFrame->PrincipalChildList()) {
     aFrame->BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists);
   }
 }
 
-static void
-PaintRowBackground(nsTableRowFrame* aRow,
-                   nsIFrame* aFrame,
-                   nsDisplayListBuilder* aBuilder,
-                   const nsDisplayListSet& aLists,
-                   const nsPoint& aOffset = nsPoint())
-{
-  // Compute background rect by iterating all cell frame.
-  for (nsTableCellFrame* cell = aRow->GetFirstCell(); cell; cell = cell->GetNextCell()) {
-    auto cellRect = cell->GetRectRelativeToSelf() + cell->GetNormalPosition() + aOffset;
-    nsDisplayBackgroundImage::AppendBackgroundItemsToTop(aBuilder, aFrame, cellRect,
-                                                         aLists.BorderBackground(),
-                                                         true, nullptr,
-                                                         aFrame->GetRectRelativeToSelf());
-  }
-}
-
-static void
-PaintRowGroupBackground(nsTableRowGroupFrame* aRowGroup,
-                        nsIFrame* aFrame,
-                        nsDisplayListBuilder* aBuilder,
-                        const nsDisplayListSet& aLists)
-{
-  for (nsTableRowFrame* row = aRowGroup->GetFirstRow(); row; row = row->GetNextRow()) {
-    PaintRowBackground(row, aFrame, aBuilder, aLists, row->GetNormalPosition());
-  }
-}
-
-static void
-PaintRowGroupBackgroundByColIdx(nsTableRowGroupFrame* aRowGroup,
-                                nsIFrame* aFrame,
-                                nsDisplayListBuilder* aBuilder,
-                                const nsDisplayListSet& aLists,
-                                const nsTArray<int32_t>& aColIdx,
-                                const nsPoint& aOffset)
-{
-  for (nsTableRowFrame* row = aRowGroup->GetFirstRow(); row; row = row->GetNextRow()) {
-    for (nsTableCellFrame* cell = row->GetFirstCell(); cell; cell = cell->GetNextCell()) {
-      int32_t curColIdx;
-      cell->GetColIndex(curColIdx);
-      if (aColIdx.Contains(curColIdx)) {
-        auto cellRect = cell->GetRectRelativeToSelf() + cell->GetNormalPosition() + row->GetNormalPosition() + aOffset;
-        nsDisplayBackgroundImage::AppendBackgroundItemsToTop(aBuilder, aFrame, cellRect,
-                                                             aLists.BorderBackground(),
-                                                             true, nullptr,
-                                                             aFrame->GetRectRelativeToSelf());
-      }
-    }
-  }
-}
-
 /* static */ void
 nsTableFrame::DisplayGenericTablePart(nsDisplayListBuilder* aBuilder,
                                       nsFrame* aFrame,
                                       const nsRect& aDirtyRect,
                                       const nsDisplayListSet& aLists,
+                                      nsDisplayTableItem* aDisplayItem,
                                       DisplayGenericTablePartTraversal aTraversal)
 {
+  nsDisplayList eventsBorderBackground;
+  // If we need to sort the event backgrounds, then we'll put descendants'
+  // display items into their own set of lists.
+  bool sortEventBackgrounds = aDisplayItem && aBuilder->IsForEventDelivery();
+  nsDisplayListCollection separatedCollection;
+  const nsDisplayListSet* lists = sortEventBackgrounds ? &separatedCollection : &aLists;
+
+  nsAutoPushCurrentTableItem pushTableItem;
+  if (aDisplayItem) {
+    pushTableItem.Push(aBuilder, aDisplayItem);
+  }
+
   if (aFrame->IsVisibleForPainting(aBuilder)) {
     nsDisplayTableItem* currentItem = aBuilder->GetCurrentTableItem();
     // currentItem may be null, when none of the table parts have a
     // background or border
     if (currentItem) {
       currentItem->UpdateForFrameBackground(aFrame);
     }
 
     // Paint the outset box-shadows for the table frames
     bool hasBoxShadow = aFrame->StyleEffects()->mBoxShadow != nullptr;
     if (hasBoxShadow) {
-      aLists.BorderBackground()->AppendNewToTop(
+      lists->BorderBackground()->AppendNewToTop(
         new (aBuilder) nsDisplayBoxShadowOuter(aBuilder, aFrame));
     }
 
-    if (aFrame->IsTableRowGroupFrame()) {
-      nsTableRowGroupFrame* rowGroup = static_cast<nsTableRowGroupFrame*>(aFrame);
-      PaintRowGroupBackground(rowGroup, aFrame, aBuilder, aLists);
-    } else if (aFrame->IsTableRowFrame()) {
-      nsTableRowFrame* row = static_cast<nsTableRowFrame*>(aFrame);
-      PaintRowBackground(row, aFrame, aBuilder, aLists);
-    } else if (aFrame->IsTableColGroupFrame()) {
-      // Compute background rect by iterating all cell frame.
-      nsTableColGroupFrame* colGroup = static_cast<nsTableColGroupFrame*>(aFrame);
-      // Collecting column index.
-      AutoTArray<int32_t, 1> colIdx;
-      for (nsTableColFrame* col = colGroup->GetFirstColumn(); col; col = col->GetNextCol()) {
-        colIdx.AppendElement(col->GetColIndex());
-      }
-
-      nsTableFrame* table = colGroup->GetTableFrame();
-      RowGroupArray rowGroups;
-      table->OrderRowGroups(rowGroups);
-      for (nsTableRowGroupFrame* rowGroup : rowGroups) {
-        auto offset = rowGroup->GetNormalPosition() - colGroup->GetNormalPosition();
-        PaintRowGroupBackgroundByColIdx(rowGroup, aFrame, aBuilder, aLists, colIdx, offset);
-      }
-    } else if (aFrame->IsTableColFrame()) {
-      // Compute background rect by iterating all cell frame.
-      nsTableColFrame* col = static_cast<nsTableColFrame*>(aFrame);
-      AutoTArray<int32_t, 1> colIdx;
-      colIdx.AppendElement(col->GetColIndex());
-
-      nsTableFrame* table = col->GetTableFrame();
-      RowGroupArray rowGroups;
-      table->OrderRowGroups(rowGroups);
-      for (nsTableRowGroupFrame* rowGroup : rowGroups) {
-        auto offset = rowGroup->GetNormalPosition() -
-                      col->GetNormalPosition() -
-                      col->GetTableColGroupFrame()->GetNormalPosition();
-        PaintRowGroupBackgroundByColIdx(rowGroup, aFrame, aBuilder, aLists, colIdx, offset);
-      }
-    } else {
+    // Create dedicated background display items per-frame when we're
+    // handling events.
+    // XXX how to handle collapsed borders?
+    if (aBuilder->IsForEventDelivery()) {
       nsDisplayBackgroundImage::AppendBackgroundItemsToTop(aBuilder, aFrame,
                                                            aFrame->GetRectRelativeToSelf(),
-                                                           aLists.BorderBackground());
+                                                           lists->BorderBackground());
     }
 
     // Paint the inset box-shadows for the table frames
     if (hasBoxShadow) {
-      aLists.BorderBackground()->AppendNewToTop(
+      lists->BorderBackground()->AppendNewToTop(
         new (aBuilder) nsDisplayBoxShadowInner(aBuilder, aFrame));
     }
   }
 
-  aTraversal(aBuilder, aFrame, aDirtyRect, aLists);
-
-  if (aFrame->IsVisibleForPainting(aBuilder)) {
-    if (aFrame->IsTableFrame()) {
-      nsTableFrame* table = static_cast<nsTableFrame*>(aFrame);
-      // In the collapsed border model, overlay all collapsed borders.
-      if (table->IsBorderCollapse()) {
-        aLists.BorderBackground()->AppendNewToTop(
-          new (aBuilder) nsDisplayTableBorderCollapse(aBuilder, table));
-      } else {
-        aLists.BorderBackground()->AppendNewToTop(
-          new (aBuilder) nsDisplayBorder(aBuilder, table));
-      }
-    }
+  aTraversal(aBuilder, aFrame, aDirtyRect, *lists);
+
+  if (sortEventBackgrounds) {
+    // Ensure that the table frame event background goes before the
+    // table rowgroups event backgrounds, before the table row event backgrounds,
+    // before everything else (cells and their blocks)
+    separatedCollection.BorderBackground()->Sort<nsDisplayItem*>(TablePartRankComparator());
+    separatedCollection.MoveTo(aLists);
   }
 
   aFrame->DisplayOutline(aBuilder, aLists);
 }
 
 static inline bool FrameHasBorderOrBackground(nsTableFrame* tableFrame, nsIFrame* f)
 {
   if (!f->StyleVisibility()->IsVisible()) {
@@ -1488,26 +1399,91 @@ static inline bool FrameHasBorderOrBackg
     if (cellFrame && !tableFrame->IsBorderCollapse()) {
       return false;
     }
     return true;
   }
   return false;
 }
 
+static bool
+AnyTablePartHasBorderOrBackground(nsTableFrame* aTableFrame,
+                                  nsIFrame* aStart,
+                                  nsIFrame* aEnd)
+{
+  for (nsIFrame* f = aStart; f != aEnd; f = f->GetNextSibling()) {
+    NS_ASSERTION(IsFrameAllowedInTable(f->Type()), "unexpected frame type");
+
+    if (FrameHasBorderOrBackground(aTableFrame, f))
+      return true;
+
+    nsTableCellFrame *cellFrame = do_QueryFrame(f);
+    if (cellFrame)
+      continue;
+
+    if (AnyTablePartHasBorderOrBackground(aTableFrame,
+                                          f->PrincipalChildList().FirstChild(),
+                                          nullptr))
+      return true;
+  }
+
+  return false;
+}
+
+static void
+UpdateItemForColGroupBackgrounds(nsDisplayTableItem* item,
+                                 const nsFrameList& aFrames) {
+  for (nsFrameList::Enumerator e(aFrames); !e.AtEnd(); e.Next()) {
+    nsTableColGroupFrame* cg = static_cast<nsTableColGroupFrame*>(e.get());
+    item->UpdateForFrameBackground(cg);
+    for (nsTableColFrame* colFrame = cg->GetFirstColumn(); colFrame;
+         colFrame = colFrame->GetNextCol()) {
+      item->UpdateForFrameBackground(colFrame);
+    }
+  }
+}
+
 // table paint code is concerned primarily with borders and bg color
 // SEC: TODO: adjust the rect for captions
 void
 nsTableFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                const nsRect&           aDirtyRect,
                                const nsDisplayListSet& aLists)
 {
   DO_GLOBAL_REFLOW_COUNT_DSP_COLOR("nsTableFrame", NS_RGB(255,128,255));
 
-  DisplayGenericTablePart(aBuilder, this, aDirtyRect, aLists);
+  nsDisplayTableItem* item = nullptr;
+  if (IsVisibleInSelection(aBuilder)) {
+    nsMargin deflate = GetDeflationForBackground(PresContext());
+    if (StyleVisibility()->IsVisible()) {
+      // If 'deflate' is (0,0,0,0) then we can paint the table background
+      // in its own display item, so do that to take advantage of
+      // opacity and visibility optimizations
+      if (deflate == nsMargin(0, 0, 0, 0)) {
+        DisplayBackgroundUnconditional(aBuilder, aLists, false);
+      }
+    }
+
+    // This background is created if any of the table parts are visible,
+    // or if we're doing event handling (since DisplayGenericTablePart
+    // needs the item for the |sortEventBackgrounds|-dependent code).
+    // Specific visibility decisions are delegated to the table background
+    // painter, which handles borders and backgrounds for the table.
+    if (aBuilder->IsForEventDelivery() ||
+        AnyTablePartHasBorderOrBackground(this, this, GetNextSibling()) ||
+        AnyTablePartHasBorderOrBackground(this, mColGroups.FirstChild(), nullptr)) {
+      item = new (aBuilder) nsDisplayTableBorderBackground(aBuilder, this,
+          deflate != nsMargin(0, 0, 0, 0));
+      aLists.BorderBackground()->AppendNewToTop(item);
+    }
+  }
+  DisplayGenericTablePart(aBuilder, this, aDirtyRect, aLists, item);
+  if (item) {
+    UpdateItemForColGroupBackgrounds(item, mColGroups);
+  }
 }
 
 nsMargin
 nsTableFrame::GetDeflationForBackground(nsPresContext* aPresContext) const
 {
   if (eCompatibility_NavQuirks != aPresContext->CompatibilityMode() ||
       !IsBorderCollapse())
     return nsMargin(0,0,0,0);
--- a/layout/tables/nsTableFrame.h
+++ b/layout/tables/nsTableFrame.h
@@ -240,16 +240,17 @@ public:
    * @param aTraversal a function that gets called to traverse the table
    * part's child frames and add their display list items to a
    * display list set.
    */
   static void DisplayGenericTablePart(nsDisplayListBuilder* aBuilder,
                                       nsFrame* aFrame,
                                       const nsRect& aDirtyRect,
                                       const nsDisplayListSet& aLists,
+                                      nsDisplayTableItem* aDisplayItem,
                                       DisplayGenericTablePartTraversal aTraversal = GenericTraversal);
 
   // Return the closest sibling of aPriorChildFrame (including aPriroChildFrame)
   // of type aChildType.
   static nsIFrame* GetFrameAtOrBefore(nsIFrame* aParentFrame,
                                       nsIFrame* aPriorChildFrame,
                                       mozilla::LayoutFrameType aChildType);
   bool IsAutoBSize(mozilla::WritingMode aWM);
--- a/layout/tables/nsTableRowFrame.cpp
+++ b/layout/tables/nsTableRowFrame.cpp
@@ -616,17 +616,31 @@ nsDisplayTableRowBackground::Paint(nsDis
   nsDisplayTableItemGeometry::UpdateDrawResult(this, result);
 }
 
 void
 nsTableRowFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                   const nsRect&           aDirtyRect,
                                   const nsDisplayListSet& aLists)
 {
-  nsTableFrame::DisplayGenericTablePart(aBuilder, this, aDirtyRect, aLists);
+  nsDisplayTableItem* item = nullptr;
+  if (IsVisibleInSelection(aBuilder)) {
+    bool isRoot = aBuilder->IsAtRootOfPseudoStackingContext();
+    if (isRoot) {
+      // This background is created regardless of whether this frame is
+      // visible or not. Visibility decisions are delegated to the
+      // table background painter.
+      // We would use nsDisplayGeneric for this rare case except that we
+      // need the background to be larger than the row frame in some
+      // cases.
+      item = new (aBuilder) nsDisplayTableRowBackground(aBuilder, this);
+      aLists.BorderBackground()->AppendNewToTop(item);
+    }
+  }
+  nsTableFrame::DisplayGenericTablePart(aBuilder, this, aDirtyRect, aLists, item);
 }
 
 nsIFrame::LogicalSides
 nsTableRowFrame::GetLogicalSkipSides(const ReflowInput* aReflowInput) const
 {
   if (MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==
                      StyleBoxDecorationBreak::Clone)) {
     return LogicalSides();
--- a/layout/tables/nsTableRowGroupFrame.cpp
+++ b/layout/tables/nsTableRowGroupFrame.cpp
@@ -288,18 +288,29 @@ DisplayRows(nsDisplayListBuilder* aBuild
   }
 }
 
 void
 nsTableRowGroupFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                        const nsRect&           aDirtyRect,
                                        const nsDisplayListSet& aLists)
 {
+  nsDisplayTableItem* item = nullptr;
+  if (IsVisibleInSelection(aBuilder)) {
+    bool isRoot = aBuilder->IsAtRootOfPseudoStackingContext();
+    if (isRoot) {
+      // This background is created regardless of whether this frame is
+      // visible or not. Visibility decisions are delegated to the
+      // table background painter.
+      item = new (aBuilder) nsDisplayTableRowGroupBackground(aBuilder, this);
+      aLists.BorderBackground()->AppendNewToTop(item);
+    }
+  }
   nsTableFrame::DisplayGenericTablePart(aBuilder, this, aDirtyRect,
-                                        aLists, DisplayRows);
+                                        aLists, item, DisplayRows);
 }
 
 nsIFrame::LogicalSides
 nsTableRowGroupFrame::GetLogicalSkipSides(const ReflowInput* aReflowInput) const
 {
   if (MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==
                      StyleBoxDecorationBreak::Clone)) {
     return LogicalSides();
--- a/layout/tables/nsTableWrapperFrame.cpp
+++ b/layout/tables/nsTableWrapperFrame.cpp
@@ -185,21 +185,17 @@ nsTableWrapperFrame::BuildDisplayList(ns
   BuildDisplayListForInnerTable(aBuilder, aDirtyRect, set);
   
   nsDisplayListSet captionSet(set, set.BlockBorderBackgrounds());
   BuildDisplayListForChild(aBuilder, mCaptionFrames.FirstChild(),
                            aDirtyRect, captionSet);
 
   // Now we have to sort everything by content order, since the caption
   // may be somewhere inside the table
-  set.BlockBorderBackgrounds()->SortByContentOrder(GetContent());
-  set.Floats()->SortByContentOrder(GetContent());
-  set.Content()->SortByContentOrder(GetContent());
-  set.PositionedDescendants()->SortByContentOrder(GetContent());
-  set.Outlines()->SortByContentOrder(GetContent());
+  set.SortAllByContentOrder(GetContent());
   set.MoveTo(aLists);
 }
 
 void
 nsTableWrapperFrame::BuildDisplayListForInnerTable(nsDisplayListBuilder*   aBuilder,
                                                    const nsRect&           aDirtyRect,
                                                    const nsDisplayListSet& aLists)
 {