Bug 539356 - Make the table code use rect invalidation to avoid over invalidation. r=roc
authorMatt Woodrow <mwoodrow@mozilla.com>
Wed, 29 Aug 2012 17:48:45 +1200
changeset 108288 a55f82f0fecaee28f0391cf83cfe7a94ae4abc3d
parent 108287 daa0868b05bf010268e075d33c6cbae0ab7c4b91
child 108289 bcd22436baf4ddd3010ac9bb1517b134fd6e42eb
push id23552
push userryanvm@gmail.com
push dateFri, 28 Sep 2012 03:05:08 +0000
treeherdermozilla-central@2d96ee8d9dd4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs539356
milestone18.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 539356 - Make the table code use rect invalidation to avoid over invalidation. r=roc
layout/base/nsFrameManager.cpp
layout/generic/nsFrame.cpp
layout/generic/nsIFrame.h
layout/tables/nsTableCellFrame.cpp
layout/tables/nsTableCellFrame.h
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/nsTableOuterFrame.cpp
layout/tables/nsTableRowFrame.cpp
layout/tables/nsTableRowFrame.h
layout/tables/nsTableRowGroupFrame.cpp
layout/tables/nsTableRowGroupFrame.h
--- a/layout/base/nsFrameManager.cpp
+++ b/layout/base/nsFrameManager.cpp
@@ -467,16 +467,24 @@ nsFrameManager::InsertFrames(nsIFrame*  
 
 nsresult
 nsFrameManager::RemoveFrame(ChildListID     aListID,
                             nsIFrame*       aOldFrame)
 {
   bool wasDestroyingFrames = mIsDestroyingFrames;
   mIsDestroyingFrames = true;
 
+  // In case the reflow doesn't invalidate anything since it just leaves
+  // a gap where the old frame was, we invalidate it here.  (This is
+  // reasonably likely to happen when removing a last child in a way
+  // that doesn't change the size of the parent.)
+  // This has to sure to invalidate the entire overflow rect; this
+  // is important in the presence of absolute positioning
+  aOldFrame->InvalidateFrameForRemoval();
+
   NS_ASSERTION(!aOldFrame->GetPrevContinuation() ||
                // exception for nsCSSFrameConstructor::RemoveFloatingFirstLetterFrames
                aOldFrame->GetType() == nsGkAtoms::textFrame,
                "Must remove first continuation.");
   NS_ASSERTION(!(aOldFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW &&
                  GetPlaceholderFrameFor(aOldFrame)),
                "Must call RemoveFrame on placeholder for out-of-flows.");
   nsresult rv = NS_OK;
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -4789,40 +4789,45 @@ nsIFrame::ClearInvalidationStateBits()
     }
   }
 
   RemoveStateBits(NS_FRAME_NEEDS_PAINT | 
                   NS_FRAME_DESCENDANT_NEEDS_PAINT | 
                   NS_FRAME_ALL_DESCENDANTS_NEED_PAINT);
 }
 
-void
-nsIFrame::InvalidateFrame()
-{
-  AddStateBits(NS_FRAME_NEEDS_PAINT);
-  nsIFrame *parent = nsLayoutUtils::GetCrossDocParentFrame(this);
+static void InvalidateFrameInternal(nsIFrame *aFrame)
+{
+  aFrame->AddStateBits(NS_FRAME_NEEDS_PAINT);
+  nsIFrame *parent = nsLayoutUtils::GetCrossDocParentFrame(aFrame);
   while (parent && !parent->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT)) {
     parent->AddStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT);
     parent = nsLayoutUtils::GetCrossDocParentFrame(parent);
   }
   if (!parent) {
-    SchedulePaint();
-  }
-  if (HasAnyStateBits(NS_FRAME_HAS_INVALID_RECT)) {
-    Properties().Delete(InvalidationRect());
-    RemoveStateBits(NS_FRAME_HAS_INVALID_RECT);
-  }
+    aFrame->SchedulePaint();
+  }
+  if (aFrame->HasAnyStateBits(NS_FRAME_HAS_INVALID_RECT)) {
+    aFrame->Properties().Delete(nsIFrame::InvalidationRect());
+    aFrame->RemoveStateBits(NS_FRAME_HAS_INVALID_RECT);
+  }
+}
+
+void
+nsIFrame::InvalidateFrame()
+{
+  InvalidateFrameInternal(this);
 }
 
 void
 nsIFrame::InvalidateFrameWithRect(const nsRect& aRect)
 {
   bool alreadyInvalid = false;
   if (!HasAnyStateBits(NS_FRAME_NEEDS_PAINT)) {
-    InvalidateFrame();
+    InvalidateFrameInternal(this);
   } else {
     alreadyInvalid = true;
   } 
 
   nsRect *rect = static_cast<nsRect*>(Properties().Get(InvalidationRect()));
   if (!rect) {
     if (alreadyInvalid) {
       return;
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -2198,16 +2198,22 @@ public:
   /**
    * Calls InvalidateFrame() on all frames descendant frames (including
    * this one).
    * 
    * This function doesn't walk through placeholder frames to invalidate
    * the out-of-flow frames.
    */
   void InvalidateFrameSubtree();
+
+  /**
+   * Called when a frame is about to be removed and needs to be invalidated.
+   * Normally does nothing since DLBI handles removed frames.
+   */
+  virtual void InvalidateFrameForRemoval() {}
   
   /**
    * Checks if a frame has had InvalidateFrame() called on it since the
    * last paint.
    *
    * If true, then the invalid rect is returned in aRect, with an
    * empty rect meaning all pixels drawn by this frame should be
    * invalidated.
--- a/layout/tables/nsTableCellFrame.cpp
+++ b/layout/tables/nsTableCellFrame.cpp
@@ -23,16 +23,17 @@
 #include "nsAccessibilityService.h"
 #endif
 #include "nsIServiceManager.h"
 #include "nsIDOMNode.h"
 #include "nsINameSpaceManager.h"
 #include "nsDisplayList.h"
 #include "nsLayoutUtils.h"
 #include "nsTextFrame.h"
+#include "FrameLayerBuilder.h"
 
 //TABLECELL SELECTION
 #include "nsFrameSelection.h"
 #include "mozilla/LookAndFeel.h"
 
 using namespace mozilla;
 
 
@@ -391,16 +392,31 @@ nsRect
 nsDisplayTableCellBackground::GetBounds(nsDisplayListBuilder* aBuilder,
                                         bool* aSnap)
 {
   // revert from nsDisplayTableItem's implementation ... cell backgrounds
   // don't overflow the cell
   return nsDisplayItem::GetBounds(aBuilder, aSnap);
 }
 
+void nsTableCellFrame::InvalidateFrame(uint32_t aDisplayItemKey)
+{
+  nsIFrame::InvalidateFrame(aDisplayItemKey);
+  GetParent()->InvalidateFrameWithRect(GetVisualOverflowRect() + GetPosition(), aDisplayItemKey);
+}
+
+void nsTableCellFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey)
+{
+  nsIFrame::InvalidateFrameWithRect(aRect, aDisplayItemKey);
+  // If we have filters applied that would affects our bounds, then
+  // we get an inactive layer created and this is computed
+  // within FrameLayerBuilder
+  GetParent()->InvalidateFrameWithRect(aRect + GetPosition(), aDisplayItemKey);
+}
+
 static void
 PaintTableCellSelection(nsIFrame* aFrame, nsRenderingContext* aCtx,
                         const nsRect& aRect, nsPoint aPt)
 {
   static_cast<nsTableCellFrame*>(aFrame)->DecorateForSelection(*aCtx, aPt);
 }
 
 NS_IMETHODIMP
@@ -556,30 +572,38 @@ void nsTableCellFrame::VerticallyAlignCh
     default:
     case NS_STYLE_VERTICAL_ALIGN_MIDDLE:
       // Align the middle of the child frame with the middle of the content area,
       kidYTop = (height - childHeight - bottomInset + topInset) / 2;
   }
   // if the content is larger than the cell height align from top
   kidYTop = NS_MAX(0, kidYTop);
 
+  if (kidYTop != kidRect.y) {
+    // Invalidate at the old position first
+    firstKid->InvalidateFrameSubtree();
+  }
+
   firstKid->SetPosition(nsPoint(kidRect.x, kidYTop));
   nsHTMLReflowMetrics desiredSize;
   desiredSize.width = mRect.width;
   desiredSize.height = mRect.height;
 
   nsRect overflow(nsPoint(0,0), GetSize());
   overflow.Inflate(GetBorderOverflow());
   desiredSize.mOverflowAreas.SetAllTo(overflow);
   ConsiderChildOverflow(desiredSize.mOverflowAreas, firstKid);
   FinishAndStoreOverflow(&desiredSize);
   if (kidYTop != kidRect.y) {
     // Make sure any child views are correctly positioned. We know the inner table
     // cell won't have a view
     nsContainerFrame::PositionChildViews(firstKid);
+
+    // Invalidate new overflow rect
+    firstKid->InvalidateFrameSubtree();
   }
   if (HasView()) {
     nsContainerFrame::SyncFrameViewAfterReflow(PresContext(), this,
                                                GetView(),
                                                desiredSize.VisualOverflow(), 0);
   }
 }
 
@@ -860,26 +884,34 @@ NS_METHOD nsTableCellFrame::Reflow(nsPre
       (GetFirstInFlow()->GetStateBits() & NS_TABLE_CELL_HAD_SPECIAL_REFLOW)) {
     // We need to force the kid to have mVResize set if we've had a
     // special reflow in the past, since the non-special reflow needs to
     // resize back to what it was without the special height reflow.
     kidReflowState.mFlags.mVResize = true;
   }
 
   nsPoint kidOrigin(leftInset, topInset);
+  nsRect origRect = firstKid->GetRect();
+  nsRect origVisualOverflow = firstKid->GetVisualOverflowRect();
+  bool firstReflow = (firstKid->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0;
 
   ReflowChild(firstKid, aPresContext, kidSize, kidReflowState,
               kidOrigin.x, kidOrigin.y, NS_FRAME_INVALIDATE_ON_MOVE, aStatus);
   if (NS_FRAME_OVERFLOW_IS_INCOMPLETE(aStatus)) {
     // Don't pass OVERFLOW_INCOMPLETE through tables until they can actually handle it
     //XXX should paginate overflow as overflow, but not in this patch (bug 379349)
     NS_FRAME_SET_INCOMPLETE(aStatus);
     printf("Set table cell incomplete %p\n", static_cast<void*>(this));
   }
 
+  // XXXbz is this invalidate actually needed, really?
+  if (GetStateBits() & NS_FRAME_IS_DIRTY) {
+    InvalidateFrameSubtree();
+  }
+
 #ifdef DEBUG
   DebugCheckChildSize(firstKid, kidSize, availSize);
 #endif
 
   // 0 dimensioned cells need to be treated specially in Standard/NavQuirks mode
   // see testcase "emptyCells.html"
   nsIFrame* prevInFlow = GetPrevInFlow();
   bool isEmpty;
@@ -889,16 +921,19 @@ NS_METHOD nsTableCellFrame::Reflow(nsPre
     isEmpty = !CellHasVisibleContent(kidSize.height, tableFrame, firstKid);
   }
   SetContentEmpty(isEmpty);
 
   // Place the child
   FinishReflowChild(firstKid, aPresContext, &kidReflowState, kidSize,
                     kidOrigin.x, kidOrigin.y, 0);
 
+  nsTableFrame::InvalidateTableFrame(firstKid, origRect, origVisualOverflow,
+                                     firstReflow);
+
   // first, compute the height which can be set w/o being restricted by aMaxSize.height
   nscoord cellHeight = kidSize.height;
 
   if (NS_UNCONSTRAINEDSIZE != cellHeight) {
     cellHeight += topInset + bottomInset;
   }
 
   // next determine the cell's width
@@ -921,16 +956,23 @@ NS_METHOD nsTableCellFrame::Reflow(nsPre
       // the height that they could honor in the pass 2 reflow
       SetHasPctOverHeight(true);
     }
     if (NS_UNCONSTRAINEDSIZE == aReflowState.availableHeight) {
       aDesiredSize.height = mRect.height;
     }
   }
 
+  // If our parent is in initial reflow, it'll handle invalidating our
+  // entire overflow rect.
+  if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW) &&
+      nsSize(aDesiredSize.width, aDesiredSize.height) != mRect.Size()) {
+    InvalidateFrame();
+  }
+
   // remember the desired size for this reflow
   SetDesiredSize(aDesiredSize);
 
   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
   return NS_OK;
 }
 
 /* ----- global methods ----- */
--- a/layout/tables/nsTableCellFrame.h
+++ b/layout/tables/nsTableCellFrame.h
@@ -206,22 +206,19 @@ public:
                                nsPoint              aPt,
                                uint32_t             aFlags);
 
   void DecorateForSelection(nsRenderingContext& aRenderingContext,
                             nsPoint              aPt);
 
   virtual bool UpdateOverflow();
   
-  virtual void InvalidateFrame()
-  {
-    nsIFrame::InvalidateFrame();
-    nsTableFrame *tableFrame = nsTableFrame::GetTableFrame(this);
-    tableFrame->InvalidateFrame();
-  }
+  virtual void InvalidateFrame(uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE;
+  virtual void InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE;
+  virtual void InvalidateFrameForRemoval() MOZ_OVERRIDE { InvalidateFrameSubtree(); }
 
 protected:
   /** implement abstract method on nsContainerFrame */
   virtual int GetSkipSides() const;
 
   /**
    * GetBorderOverflow says how far the cell's own borders extend
    * outside its own bounds.  In the separated borders model this should
--- a/layout/tables/nsTableColFrame.cpp
+++ b/layout/tables/nsTableColFrame.cpp
@@ -186,15 +186,25 @@ nsTableColFrame::GetFrameName(nsAString&
 
 nsSplittableType
 nsTableColFrame::GetSplittableType() const
 {
   return NS_FRAME_NOT_SPLITTABLE;
 }
 
 void
-nsTableColFrame::InvalidateFrame()
+nsTableColFrame::InvalidateFrame(uint32_t aDisplayItemKey)
 {
-  nsIFrame::InvalidateFrame();
-  nsTableFrame *tableFrame = nsTableFrame::GetTableFrame(this);
-  tableFrame->InvalidateFrame();
+  nsIFrame::InvalidateFrame(aDisplayItemKey);
+  GetParent()->InvalidateFrameWithRect(GetVisualOverflowRect() + GetPosition(), aDisplayItemKey);
 }
 
+void
+nsTableColFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey)
+{
+  nsIFrame::InvalidateFrameWithRect(aRect, aDisplayItemKey);
+
+  // If we have filters applied that would affects our bounds, then
+  // we get an inactive layer created and this is computed
+  // within FrameLayerBuilder
+  GetParent()->InvalidateFrameWithRect(aRect + GetPosition(), aDisplayItemKey);
+}
+
--- a/layout/tables/nsTableColFrame.h
+++ b/layout/tables/nsTableColFrame.h
@@ -259,17 +259,19 @@ public:
   }
   void SetFinalWidth(nscoord aFinalWidth) {
     mFinalWidth = aFinalWidth;
   }
   nscoord GetFinalWidth() {
     return mFinalWidth;
   }
   
-  virtual void InvalidateFrame();
+  virtual void InvalidateFrame(uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE;
+  virtual void InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE;
+  virtual void InvalidateFrameForRemoval() MOZ_OVERRIDE { InvalidateFrameSubtree(); }
 
 protected:
 
   nsTableColFrame(nsStyleContext* aContext);
   ~nsTableColFrame();
 
   nscoord mMinCoord;
   nscoord mPrefCoord;
--- a/layout/tables/nsTableColGroupFrame.cpp
+++ b/layout/tables/nsTableColGroupFrame.cpp
@@ -460,21 +460,30 @@ NS_IMPL_FRAMEARENA_HELPERS(nsTableColGro
 
 nsIAtom*
 nsTableColGroupFrame::GetType() const
 {
   return nsGkAtoms::tableColGroupFrame;
 }
   
 void 
-nsTableColGroupFrame::InvalidateFrame()
+nsTableColGroupFrame::InvalidateFrame(uint32_t aDisplayItemKey)
 {
-  nsIFrame::InvalidateFrame();
-  nsTableFrame *tableFrame = nsTableFrame::GetTableFrame(this);
-  tableFrame->InvalidateFrame();
+  nsIFrame::InvalidateFrame(aDisplayItemKey);
+  GetParent()->InvalidateFrameWithRect(GetVisualOverflowRect() + GetPosition(), aDisplayItemKey);
+}
+
+void 
+nsTableColGroupFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey)
+{
+  nsIFrame::InvalidateFrameWithRect(aRect, aDisplayItemKey);
+  // If we have filters applied that would affects our bounds, then
+  // we get an inactive layer created and this is computed
+  // within FrameLayerBuilder
+  GetParent()->InvalidateFrameWithRect(aRect + GetPosition(), aDisplayItemKey);
 }
 
 #ifdef DEBUG
 NS_IMETHODIMP
 nsTableColGroupFrame::GetFrameName(nsAString& aResult) const
 {
   return MakeFrameName(NS_LITERAL_STRING("TableColGroup"), aResult);
 }
--- a/layout/tables/nsTableColGroupFrame.h
+++ b/layout/tables/nsTableColGroupFrame.h
@@ -192,17 +192,19 @@ public:
   void GetContinuousBCBorderWidth(nsMargin& aBorder);
   /**
    * Set full border widths before collapsing with cell borders
    * @param aForSide - side to set; only accepts top and bottom
    */
   void SetContinuousBCBorderWidth(uint8_t     aForSide,
                                   BCPixelSize aPixelValue);
   
-  virtual void InvalidateFrame();
+  virtual void InvalidateFrame(uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE;
+  virtual void InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE;
+  virtual void InvalidateFrameForRemoval() MOZ_OVERRIDE { InvalidateFrameSubtree(); }
 
 protected:
   nsTableColGroupFrame(nsStyleContext* aContext);
 
   void InsertColsReflow(int32_t                   aColIndex,
                         const nsFrameList::Slice& aCols);
 
   /** implement abstract method on nsContainerFrame */
--- a/layout/tables/nsTableFrame.cpp
+++ b/layout/tables/nsTableFrame.cpp
@@ -1386,17 +1386,17 @@ nsTableFrame::ProcessRowInserted(nscoord
     nsIFrame* childFrame = rgFrame->GetFirstPrincipalChild();
     // find the row that was inserted first
     while (childFrame) {
       nsTableRowFrame *rowFrame = do_QueryFrame(childFrame);
       if (rowFrame) {
         if (rowFrame->IsFirstInserted()) {
           rowFrame->SetFirstInserted(false);
           // damage the table from the 1st row inserted to the end of the table
-          InvalidateFrame();
+          nsIFrame::InvalidateFrame();
           // XXXbz didn't we do this up front?  Why do we need to do it again?
           SetRowInserted(false);
           return; // found it, so leave
         }
       }
       childFrame = childFrame->GetNextSibling();
     }
   }
@@ -1801,16 +1801,21 @@ NS_METHOD nsTableFrame::Reflow(nsPresCon
 
   if (!ApplyOverflowClipping(this, aReflowState.mStyleDisplay)) {
     // collapsed border may leak out
     nsMargin bcMargin = GetExcludedOuterBCBorder();
     tableRect.Inflate(bcMargin);
   }
   aDesiredSize.mOverflowAreas.UnionAllWith(tableRect);
 
+  if ((GetStateBits() & NS_FRAME_FIRST_REFLOW) ||
+      nsSize(aDesiredSize.width, aDesiredSize.height) != mRect.Size()) {
+      nsIFrame::InvalidateFrame();
+  }
+
   FinishAndStoreOverflow(&aDesiredSize);
   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
   return rv;
 }
 
 bool
 nsTableFrame::UpdateOverflow()
 {
@@ -2486,20 +2491,26 @@ nsTableFrame::InitChildReflowState(nsHTM
 // Position and size aKidFrame and update our reflow state. The origin of
 // aKidRect is relative to the upper-left origin of our frame
 void nsTableFrame::PlaceChild(nsTableReflowState&  aReflowState,
                               nsIFrame*            aKidFrame,
                               nsHTMLReflowMetrics& aKidDesiredSize,
                               const nsRect&        aOriginalKidRect,
                               const nsRect&        aOriginalKidVisualOverflow)
 {
+  bool isFirstReflow =
+    (aKidFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0;
+
   // Place and size the child
   FinishReflowChild(aKidFrame, PresContext(), nullptr, aKidDesiredSize,
                     aReflowState.x, aReflowState.y, 0);
 
+  InvalidateTableFrame(aKidFrame, aOriginalKidRect, aOriginalKidVisualOverflow,
+                       isFirstReflow);
+
   // Adjust the running y-offset
   aReflowState.y += aKidDesiredSize.height;
 
   // If our height is constrained, then update the available height
   if (NS_UNCONSTRAINEDSIZE != aReflowState.availSize.height) {
     aReflowState.availSize.height -= aKidDesiredSize.height;
   }
 }
@@ -2924,19 +2935,23 @@ nsTableFrame::ReflowChildren(nsTableRefl
         }
         break;
       }
     }
     else { // it isn't being reflowed
       aReflowState.y += cellSpacingY;
       nsRect kidRect = kidFrame->GetRect();
       if (kidRect.y != aReflowState.y) {
+        // invalidate the old position
+        kidFrame->InvalidateFrameSubtree();
         kidRect.y = aReflowState.y;
         kidFrame->SetRect(kidRect);        // move to the new position
         RePositionViews(kidFrame);
+        // invalidate the new position
+        kidFrame->InvalidateFrameSubtree();
       }
       aReflowState.y += kidRect.height;
 
       // If our height is constrained then update the available height.
       if (NS_UNCONSTRAINEDSIZE != aReflowState.availSize.height) {
         aReflowState.availSize.height -= cellSpacingY + kidRect.height;
       }
     }
@@ -3100,42 +3115,57 @@ nsTableFrame::DistributeHeightToRows(con
             // XXXbz we don't need to change rowRect.y to be yOriginRow?
             rowFrame->SetRect(rowRect);
             yOriginRow += rowRect.height + cellSpacingY;
             yEndRG += rowRect.height + cellSpacingY;
             amountUsed += amountForRow;
             amountUsedByRG += amountForRow;
             //rowFrame->DidResize();
             nsTableFrame::RePositionViews(rowFrame);
+
+            rgFrame->InvalidateFrameWithRect(oldRowRect);
+            rgFrame->InvalidateFrame();
           }
         }
         else {
           if (amountUsed > 0 && yOriginRow != rowRect.y &&
               !(GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
+            rowFrame->InvalidateFrameSubtree();
             rowFrame->SetPosition(nsPoint(rowRect.x, yOriginRow));
             nsTableFrame::RePositionViews(rowFrame);
+            rowFrame->InvalidateFrameSubtree();
           }
           yOriginRow += rowRect.height + cellSpacingY;
           yEndRG += rowRect.height + cellSpacingY;
         }
         rowFrame = rowFrame->GetNextRow();
       }
       if (amountUsed > 0) {
+        if (rgRect.y != yOriginRG) {
+          rgFrame->InvalidateFrameSubtree();
+        }
+
         nsRect origRgRect = rgRect;
+        nsRect origRgVisualOverflow = rgFrame->GetVisualOverflowRect();
 
         rgRect.y = yOriginRG;
         rgRect.height += amountUsedByRG;
 
         rgFrame->SetRect(rgRect);
+
+        nsTableFrame::InvalidateTableFrame(rgFrame, origRgRect,
+                                           origRgVisualOverflow, false);
       }
     }
     else if (amountUsed > 0 && yOriginRG != rgRect.y) {
+      rgFrame->InvalidateFrameSubtree();
       rgFrame->SetPosition(nsPoint(rgRect.x, yOriginRG));
       // Make sure child views are properly positioned
       nsTableFrame::RePositionViews(rgFrame);
+      rgFrame->InvalidateFrameSubtree();
     }
     yOriginRG = yEndRG;
   }
 
   if (amountUsed >= aAmount) {
     ResizeCells(*this);
     return;
   }
@@ -3233,50 +3263,68 @@ nsTableFrame::DistributeHeightToRows(con
             ratio = 1.0f / float(divisor);
           }
           // give rows their additional space, except for the last row which
           // gets the remainder
           nscoord amountForRow = (rowFrame == lastEligibleRow)
                                  ? aAmount - amountUsed : NSToCoordRound(((float)(heightToDistribute)) * ratio);
           amountForRow = NS_MIN(amountForRow, aAmount - amountUsed);
 
+          if (yOriginRow != rowRect.y) {
+            rowFrame->InvalidateFrameSubtree();
+          }
+
           // update the row height
           nsRect newRowRect(rowRect.x, yOriginRow, rowRect.width,
                             rowRect.height + amountForRow);
           rowFrame->SetRect(newRowRect);
 
           yOriginRow += newRowRect.height + cellSpacingY;
           yEndRG += newRowRect.height + cellSpacingY;
 
           amountUsed += amountForRow;
           amountUsedByRG += amountForRow;
           NS_ASSERTION((amountUsed <= aAmount), "invalid row allocation");
           //rowFrame->DidResize();
           nsTableFrame::RePositionViews(rowFrame);
+
+          nsTableFrame::InvalidateTableFrame(rowFrame, rowRect, rowVisualOverflow,
+                                             false);
         }
         else {
           if (amountUsed > 0 && yOriginRow != rowRect.y) {
+            rowFrame->InvalidateFrameSubtree();
             rowFrame->SetPosition(nsPoint(rowRect.x, yOriginRow));
             nsTableFrame::RePositionViews(rowFrame);
+            rowFrame->InvalidateFrameSubtree();
           }
           yOriginRow += rowRect.height + cellSpacingY;
           yEndRG += rowRect.height + cellSpacingY;
         }
         rowFrame = rowFrame->GetNextRow();
       }
       if (amountUsed > 0) {
+        if (rgRect.y != yOriginRG) {
+          rgFrame->InvalidateFrameSubtree();
+        }
+
         rgFrame->SetRect(nsRect(rgRect.x, yOriginRG, rgRect.width,
                                 rgRect.height + amountUsedByRG));
+
+        nsTableFrame::InvalidateTableFrame(rgFrame, rgRect, rgVisualOverflow,
+                                           false);
       }
       // Make sure child views are properly positioned
     }
     else if (amountUsed > 0 && yOriginRG != rgRect.y) {
+      rgFrame->InvalidateFrameSubtree();
       rgFrame->SetPosition(nsPoint(rgRect.x, yOriginRG));
       // Make sure child views are properly positioned
       nsTableFrame::RePositionViews(rgFrame);
+      rgFrame->InvalidateFrameSubtree();
     }
     yOriginRG = yEndRG;
   }
 
   ResizeCells(*this);
 }
 
 int32_t nsTableFrame::GetColumnWidth(int32_t aColIndex)
@@ -7178,8 +7226,50 @@ bool nsTableFrame::RowIsSpannedInto(int3
   bool result = false;
   nsTableCellMap* cellMap = GetCellMap();
   NS_PRECONDITION (cellMap, "bad call, cellMap not yet allocated.");
   if (cellMap) {
     result = cellMap->RowIsSpannedInto(aRowIndex, aNumEffCols);
   }
   return result;
 }
+
+/* static */
+void
+nsTableFrame::InvalidateTableFrame(nsIFrame* aFrame,
+                                   const nsRect& aOrigRect,
+                                   const nsRect& aOrigVisualOverflow,
+                                   bool aIsFirstReflow)
+{
+  nsIFrame* parent = aFrame->GetParent();
+  NS_ASSERTION(parent, "What happened here?");
+
+  if (parent->GetStateBits() & NS_FRAME_FIRST_REFLOW) {
+    // Don't bother; we'll invalidate the parent's overflow rect when
+    // we finish reflowing it.
+    return;
+  }
+
+  // The part that looks at both the rect and the overflow rect is a
+  // bit of a hack.  See nsBlockFrame::ReflowLine for an eloquent
+  // description of its hackishness.
+  //
+  // This doesn't really make sense now that we have DLBI.
+  // This code can probably be simplified a fair bit.
+  nsRect visualOverflow = aFrame->GetVisualOverflowRect();
+  if (aIsFirstReflow ||
+      aOrigRect.TopLeft() != aFrame->GetPosition() ||
+      aOrigVisualOverflow.TopLeft() != visualOverflow.TopLeft()) {
+    // Invalidate the old and new overflow rects.  Note that if the
+    // frame moved, we can't just use aOrigVisualOverflow, since it's in
+    // coordinates relative to the old position.  So invalidate via
+    // aFrame's parent, and reposition that overflow rect to the right
+    // place.
+    // XXXbz this doesn't handle outlines, does it?
+    aFrame->InvalidateFrame();
+    parent->InvalidateFrameWithRect(aOrigVisualOverflow + aOrigRect.TopLeft());
+  } else {
+    aFrame->InvalidateFrameWithRect(aOrigVisualOverflow);;
+    aFrame->InvalidateFrame();
+    parent->InvalidateFrameWithRect(aOrigRect);;
+    parent->InvalidateFrame();
+  }
+}
--- a/layout/tables/nsTableFrame.h
+++ b/layout/tables/nsTableFrame.h
@@ -459,16 +459,33 @@ public:
   bool ColumnHasCellSpacingBefore(int32_t aColIndex) const;
 
   bool HasPctCol() const;
   void SetHasPctCol(bool aValue);
 
   bool HasCellSpanningPctCol() const;
   void SetHasCellSpanningPctCol(bool aValue);
 
+  /**
+   * To be called on a frame by its parent after setting its size/position and
+   * calling DidReflow (possibly via FinishReflowChild()).  This can also be
+   * used for child frames which are not being reflowed but did have their size
+   * or position changed.
+   *
+   * @param aFrame The frame to invalidate
+   * @param aOrigRect The original rect of aFrame (before the change).
+   * @param aOrigVisualOverflow The original overflow rect of aFrame.
+   * @param aIsFirstReflow True if the size/position change is due to the
+   *                       first reflow of aFrame.
+   */
+  static void InvalidateTableFrame(nsIFrame* aFrame,
+                                   const nsRect& aOrigRect,
+                                   const nsRect& aOrigVisualOverflow,
+                                   bool aIsFirstReflow);
+
   virtual bool UpdateOverflow();
 
 protected:
 
   /** protected constructor. 
     * @see NewFrame
     */
   nsTableFrame(nsStyleContext* aContext);
--- a/layout/tables/nsTableOuterFrame.cpp
+++ b/layout/tables/nsTableOuterFrame.cpp
@@ -911,16 +911,31 @@ NS_METHOD nsTableOuterFrame::Reflow(nsPr
     ((sizeof(nsHTMLReflowState) + sizeof(long) - 1) / sizeof(long))
   long captionRSSpace[LONGS_IN_HTMLRS];
   nsHTMLReflowState *captionRS =
     static_cast<nsHTMLReflowState*>((void*)captionRSSpace);
   long innerRSSpace[LONGS_IN_HTMLRS];
   nsHTMLReflowState *innerRS =
     static_cast<nsHTMLReflowState*>((void*) innerRSSpace);
 
+  nsRect origInnerRect = InnerTableFrame()->GetRect();
+  nsRect origInnerVisualOverflow = InnerTableFrame()->GetVisualOverflowRect();
+  bool innerFirstReflow =
+    (InnerTableFrame()->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0;
+  nsRect origCaptionRect;
+  nsRect origCaptionVisualOverflow;
+  bool captionFirstReflow;
+  if (mCaptionFrames.NotEmpty()) {
+    origCaptionRect = mCaptionFrames.FirstChild()->GetRect();
+    origCaptionVisualOverflow =
+      mCaptionFrames.FirstChild()->GetVisualOverflowRect();
+    captionFirstReflow =
+      (mCaptionFrames.FirstChild()->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0;
+  }
+  
   // ComputeAutoSize has to match this logic.
   if (captionSide == NO_SIDE) {
     // We don't have a caption.
     OuterBeginReflowChild(aPresContext, InnerTableFrame(), aOuterRS,
                           innerRSSpace, aOuterRS.ComputedWidth());
   } else if (captionSide == NS_STYLE_CAPTION_SIDE_LEFT ||
              captionSide == NS_STYLE_CAPTION_SIDE_RIGHT) {
     // nsTableCaptionFrame::ComputeAutoSize takes care of making side
@@ -1032,16 +1047,24 @@ NS_METHOD nsTableOuterFrame::Reflow(nsPr
 
   nsPoint innerOrigin;
   GetInnerOrigin(captionSide, containSize, captionSize, 
                  captionMargin, innerSize, innerMargin, innerOrigin);
   FinishReflowChild(InnerTableFrame(), aPresContext, innerRS, innerMet,
                     innerOrigin.x, innerOrigin.y, 0);
   innerRS->~nsHTMLReflowState();
 
+  nsTableFrame::InvalidateTableFrame(InnerTableFrame(), origInnerRect,
+                                     origInnerVisualOverflow, innerFirstReflow);
+  if (mCaptionFrames.NotEmpty()) {
+    nsTableFrame::InvalidateTableFrame(mCaptionFrames.FirstChild(), origCaptionRect,
+                                       origCaptionVisualOverflow,
+                                       captionFirstReflow);
+  }
+
   UpdateReflowMetrics(captionSide, aDesiredSize, innerMargin, captionMargin);
   FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aOuterRS, aStatus);
 
   // Return our desired rect
 
   NS_FRAME_SET_TRUNCATION(aStatus, aOuterRS, aDesiredSize);
   return rv;
 }
--- a/layout/tables/nsTableRowFrame.cpp
+++ b/layout/tables/nsTableRowFrame.cpp
@@ -330,19 +330,23 @@ nsTableRowFrame::DidResize()
 
   while (childFrame) {
     nsTableCellFrame *cellFrame = do_QueryFrame(childFrame);
     if (cellFrame) {
       nscoord cellHeight = mRect.height + GetHeightOfRowsSpannedBelowFirst(*cellFrame, *tableFrame);
 
       // resize the cell's height
       nsRect cellRect = cellFrame->GetRect();
+      nsRect cellVisualOverflow = cellFrame->GetVisualOverflowRect();
       if (cellRect.height != cellHeight)
       {
         cellFrame->SetSize(nsSize(cellRect.width, cellHeight));
+        nsTableFrame::InvalidateTableFrame(cellFrame, cellRect,
+                                           cellVisualOverflow,
+                                           false);
       }
 
       // realign cell content based on the new height.  We might be able to
       // skip this if the height didn't change... maybe.  Hard to tell.
       cellFrame->VerticallyAlignChild(mMaxCellAscent);
       
       // Always store the overflow, even if the height didn't change, since
       // we'll lose part of our overflow area otherwise.
@@ -829,16 +833,19 @@ nsTableRowFrame::ReflowChildren(nsPresCo
                            cellSpacingX, iter.IsLeftToRight(), false);
     }
 
     // remember the rightmost (ltr) or leftmost (rtl) column this cell spans into
     prevColIndex = (iter.IsLeftToRight()) ? cellColIndex + (cellColSpan - 1) : cellColIndex;
 
     // Reflow the child frame
     nsRect kidRect = kidFrame->GetRect();
+    nsRect kidVisualOverflow = kidFrame->GetVisualOverflowRect();
+    bool firstReflow =
+      (kidFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0;
 
     if (doReflowChild) {
       // Calculate the available width for the table cell using the known column widths
       nscoord availCellWidth =
         CalcAvailWidth(aTableFrame, *cellFrame, cellSpacingX);
 
       nsHTMLReflowMetrics desiredSize;
 
@@ -918,16 +925,19 @@ nsTableRowFrame::ReflowChildren(nsPresCo
         }
       }
 
       // Place the child
       desiredSize.width = availCellWidth;
 
       FinishReflowChild(kidFrame, aPresContext, nullptr, desiredSize, x, 0, 0);
 
+      nsTableFrame::InvalidateTableFrame(kidFrame, kidRect, kidVisualOverflow,
+                                         firstReflow);
+      
       x += desiredSize.width;  
     }
     else {
       if (kidRect.x != x) {
         // Invalidate the old position
         kidFrame->InvalidateFrameSubtree();
         // move to the new position
         kidFrame->SetPosition(nsPoint(x, kidRect.y));
@@ -1011,16 +1021,23 @@ nsTableRowFrame::Reflow(nsPresContext*  
   InitHasCellWithStyleHeight(tableFrame);
 
   rv = ReflowChildren(aPresContext, aDesiredSize, aReflowState, *tableFrame,
                       aStatus);
 
   // just set our width to what was available. The table will calculate the width and not use our value.
   aDesiredSize.width = aReflowState.availableWidth;
 
+  // If our parent is in initial reflow, it'll handle invalidating our
+  // entire overflow rect.
+  if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW) &&
+      nsSize(aDesiredSize.width, aDesiredSize.height) != mRect.Size()) {
+    InvalidateFrame();
+  }
+
   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
   return rv;
 }
 
 /**
  * This function is called by the row group frame's SplitRowGroup() code when
  * pushing a row frame that has cell frames that span into it. The cell frame
  * should be reflowed with the specified height
@@ -1057,16 +1074,21 @@ nsTableRowFrame::ReflowCellFrame(nsPresC
 
   // Note: VerticallyAlignChild can affect the overflow rect.
   // XXX What happens if this cell has 'vertical-align: baseline' ?
   // XXX Why is it assumed that the cell's ascent hasn't changed ?
   if (fullyComplete) {
     aCellFrame->VerticallyAlignChild(mMaxCellAscent);
   }
   
+  nsTableFrame::InvalidateTableFrame(aCellFrame, cellRect,
+                                     cellVisualOverflow,
+                                     (aCellFrame->GetStateBits() &
+                                      NS_FRAME_FIRST_REFLOW) != 0);
+  
   aCellFrame->DidReflow(aPresContext, nullptr, NS_FRAME_REFLOW_FINISHED);
 
   return desiredSize.height;
 }
 
 nscoord
 nsTableRowFrame::CollapseRowIfNecessary(nscoord aRowOffset,
                                         nscoord aWidth,
@@ -1082,16 +1104,18 @@ nsTableRowFrame::CollapseRowIfNecessary(
   }
 
   if (aRowOffset != 0) {
     // We're moving, so invalidate our old position
     InvalidateFrameSubtree();
   }
   
   nsRect rowRect = GetRect();
+  nsRect oldRect = rowRect;
+  nsRect oldVisualOverflow = GetVisualOverflowRect();
   
   rowRect.y -= aRowOffset;
   rowRect.width  = aWidth;
   nsOverflowAreas overflow;
   nscoord shift = 0;
   nscoord cellSpacingX = tableFrame->GetCellSpacingX();
   nscoord cellSpacingY = tableFrame->GetCellSpacingY();
 
@@ -1210,26 +1234,33 @@ nsTableRowFrame::CollapseRowIfNecessary(
         // XXXbz This looks completely bogus in the cases when we didn't
         // collapse the cell!
         nsRect cellBounds(0, 0, cRect.width, cRect.height);
         nsOverflowAreas cellOverflow(cellBounds, cellBounds);
         cellFrame->FinishAndStoreOverflow(cellOverflow,
                                           nsSize(cRect.width, cRect.height));
         nsTableFrame::RePositionViews(cellFrame);
         ConsiderChildOverflow(overflow, cellFrame);
+                
+        if (aRowOffset == 0) {
+          nsTableFrame::InvalidateTableFrame(cellFrame, oldCellRect,
+                                             oldCellVisualOverflow,
+                                             false);
+        }
       }
       kidFrame = iter.Next(); // Get the next child
     }
   }
 
   SetRect(rowRect);
   overflow.UnionAllWith(nsRect(0,0,rowRect.width, rowRect.height));
   FinishAndStoreOverflow(overflow, nsSize(rowRect.width, rowRect.height));
 
   nsTableFrame::RePositionViews(this);
+  nsTableFrame::InvalidateTableFrame(this, oldRect, oldVisualOverflow, false);
   return shift;
 }
 
 /*
  * The following method is called by the row group frame's SplitRowGroup()
  * when it creates a continuing cell frame and wants to insert it into the
  * row's child list.
  */
@@ -1347,21 +1378,30 @@ void nsTableRowFrame::InitHasCellWithSty
       AddStateBits(NS_ROW_HAS_CELL_WITH_STYLE_HEIGHT);
       return;
     }
   }
   RemoveStateBits(NS_ROW_HAS_CELL_WITH_STYLE_HEIGHT);
 }
   
 void 
-nsTableRowFrame::InvalidateFrame()
+nsTableRowFrame::InvalidateFrame(uint32_t aDisplayItemKey)
 {
-  nsIFrame::InvalidateFrame();
-  nsTableFrame *tableFrame = nsTableFrame::GetTableFrame(this);
-  tableFrame->InvalidateFrame();
+  nsIFrame::InvalidateFrame(aDisplayItemKey);
+  GetParent()->InvalidateFrameWithRect(GetVisualOverflowRect() + GetPosition(), aDisplayItemKey);
+}
+
+void
+nsTableRowFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey)
+{
+  nsIFrame::InvalidateFrameWithRect(aRect, aDisplayItemKey);
+  // If we have filters applied that would affects our bounds, then
+  // we get an inactive layer created and this is computed
+  // within FrameLayerBuilder
+  GetParent()->InvalidateFrameWithRect(aRect + GetPosition(), aDisplayItemKey);
 }
 
 /* ----- global methods ----- */
 
 nsIFrame* 
 NS_NewTableRowFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) nsTableRowFrame(aContext);
--- a/layout/tables/nsTableRowFrame.h
+++ b/layout/tables/nsTableRowFrame.h
@@ -219,17 +219,19 @@ public:
   nscoord GetOuterTopContBCBorderWidth();
   /**
    * Sets full border widths before collapsing with cell borders
    * @param aForSide - side to set; only accepts right, left, and top
    */
   void SetContinuousBCBorderWidth(uint8_t     aForSide,
                                   BCPixelSize aPixelValue);
 
-  virtual void InvalidateFrame();
+  virtual void InvalidateFrame(uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE;
+  virtual void InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE;
+  virtual void InvalidateFrameForRemoval() MOZ_OVERRIDE { InvalidateFrameSubtree(); }
 
 #ifdef ACCESSIBILITY
   virtual already_AddRefed<Accessible> CreateAccessible() MOZ_OVERRIDE;
 #endif
 
 protected:
 
   /** protected constructor.
--- a/layout/tables/nsTableRowGroupFrame.cpp
+++ b/layout/tables/nsTableRowGroupFrame.cpp
@@ -249,20 +249,26 @@ nsTableRowGroupFrame::GetSkipSides() con
 void 
 nsTableRowGroupFrame::PlaceChild(nsPresContext*         aPresContext,
                                  nsRowGroupReflowState& aReflowState,
                                  nsIFrame*              aKidFrame,
                                  nsHTMLReflowMetrics&   aDesiredSize,
                                  const nsRect&          aOriginalKidRect,
                                  const nsRect&          aOriginalKidVisualOverflow)
 {
+  bool isFirstReflow =
+    (aKidFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0;
+
   // Place and size the child
   FinishReflowChild(aKidFrame, aPresContext, nullptr, aDesiredSize, 0,
                     aReflowState.y, 0);
 
+  nsTableFrame::InvalidateTableFrame(aKidFrame, aOriginalKidRect,
+                                     aOriginalKidVisualOverflow, isFirstReflow);
+
   // Adjust the running y-offset
   aReflowState.y += aDesiredSize.height;
 
   // If our height is constrained then update the available height
   if (NS_UNCONSTRAINEDSIZE != aReflowState.availSize.height) {
     aReflowState.availSize.height -= aDesiredSize.height;
   }
 }
@@ -738,28 +744,32 @@ nsTableRowGroupFrame::CalculateRowHeight
     }
     rowGroupHeight = aReflowState.ComputedHeight();
   }
 
   nscoord yOrigin = startRowGroupHeight;
   // update the rows with their (potentially) new heights
   for (rowFrame = startRowFrame, rowIndex = 0; rowFrame; rowFrame = rowFrame->GetNextRow(), rowIndex++) {
     nsRect rowBounds = rowFrame->GetRect();
+    nsRect rowVisualOverflow = rowFrame->GetVisualOverflowRect();
 
     bool movedFrame = (rowBounds.y != yOrigin);  
     nscoord rowHeight = (rowInfo[rowIndex].height > 0) ? rowInfo[rowIndex].height : 0;
     
     if (movedFrame || (rowHeight != rowBounds.height)) {
       // Resize/move the row to its final size and position
       if (movedFrame) {
         rowFrame->InvalidateFrameSubtree();
       }
       
       rowFrame->SetRect(nsRect(rowBounds.x, yOrigin, rowBounds.width,
                                rowHeight));
+
+      nsTableFrame::InvalidateTableFrame(rowFrame, rowBounds, rowVisualOverflow,
+                                         false);
     }
     if (movedFrame) {
       nsTableFrame::RePositionViews(rowFrame);
       // XXXbz we don't need to update our overflow area?
     }
     yOrigin += rowHeight + cellSpacingY;
   }
 
@@ -793,16 +803,18 @@ nsTableRowGroupFrame::CollapseRowGroupIf
     yGroupOffset += rowFrame->CollapseRowIfNecessary(yGroupOffset,
                                                      aWidth, collapseGroup,
                                                      didCollapse);
     ConsiderChildOverflow(overflow, rowFrame);
     rowFrame = rowFrame->GetNextRow();
   }
 
   nsRect groupRect = GetRect();
+  nsRect oldGroupRect = groupRect;
+  nsRect oldGroupVisualOverflow = GetVisualOverflowRect();
   
   groupRect.height -= yGroupOffset;
   if (didCollapse) {
     // add back the cellspacing between rowgroups
     groupRect.height += tableFrame->GetCellSpacingY();
   }
 
   groupRect.y -= aYTotalOffset;
@@ -811,16 +823,19 @@ nsTableRowGroupFrame::CollapseRowGroupIf
   if (aYTotalOffset != 0) {
     InvalidateFrameSubtree();
   }
   
   SetRect(groupRect);
   overflow.UnionAllWith(nsRect(0, 0, groupRect.width, groupRect.height));
   FinishAndStoreOverflow(overflow, nsSize(groupRect.width, groupRect.height));
   nsTableFrame::RePositionViews(this);
+  nsTableFrame::InvalidateTableFrame(this, oldGroupRect, oldGroupVisualOverflow,
+                                     false);
+
   return yGroupOffset;
 }
 
 // Move a child that was skipped during a reflow.
 void
 nsTableRowGroupFrame::SlideChild(nsRowGroupReflowState& aReflowState,
                                  nsIFrame*              aKidFrame)
 {
@@ -1047,25 +1062,33 @@ nsTableRowGroupFrame::SplitRowGroup(nsPr
         nsHTMLReflowState rowReflowState(aPresContext, aReflowState,
                                          rowFrame, availSize,
                                          -1, -1, false);
                                          
         InitChildReflowState(*aPresContext, borderCollapse, rowReflowState);
         rowReflowState.mFlags.mIsTopOfPage = isTopOfPage; // set top of page
         nsHTMLReflowMetrics rowMetrics;
 
+        // Get the old size before we reflow.
+        nsRect oldRowRect = rowFrame->GetRect();
+        nsRect oldRowVisualOverflow = rowFrame->GetVisualOverflowRect();
+
         // Reflow the cell with the constrained height. A cell with rowspan >1 will get this
         // reflow later during SplitSpanningCells.
         rv = ReflowChild(rowFrame, aPresContext, rowMetrics, rowReflowState,
                          0, 0, NS_FRAME_NO_MOVE_FRAME, aStatus);
         if (NS_FAILED(rv)) return rv;
         rowFrame->SetSize(nsSize(rowMetrics.width, rowMetrics.height));
         rowFrame->DidReflow(aPresContext, nullptr, NS_FRAME_REFLOW_FINISHED);
         rowFrame->DidResize();
 
+        nsTableFrame::InvalidateTableFrame(rowFrame, oldRowRect,
+                                           oldRowVisualOverflow,
+                                           false);
+
         if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) {
           // The row frame is incomplete and all of the rowspan 1 cells' block frames split
           if ((rowMetrics.height <= rowReflowState.availableHeight) || isTopOfPage) {
             // The row stays on this page because either it split ok or we're on the top of page.
             // If top of page and the height exceeded the avail height, then there will be data loss
             NS_ASSERTION(rowMetrics.height <= rowReflowState.availableHeight, 
                          "data loss - incomplete row needed more height than available, on top of page");
             CreateContinuingRowFrame(*aPresContext, *rowFrame, (nsIFrame**)&contRow);
@@ -1283,16 +1306,23 @@ nsTableRowGroupFrame::Reflow(nsPresConte
   SetHasStyleHeight((NS_UNCONSTRAINEDSIZE != aReflowState.ComputedHeight()) &&
                     (aReflowState.ComputedHeight() > 0)); 
   
   // just set our width to what was available. The table will calculate the width and not use our value.
   aDesiredSize.width = aReflowState.availableWidth;
 
   aDesiredSize.UnionOverflowAreasWithDesiredBounds();
 
+  // If our parent is in initial reflow, it'll handle invalidating our
+  // entire overflow rect.
+  if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW) &&
+      nsSize(aDesiredSize.width, aDesiredSize.height) != mRect.Size()) {
+    InvalidateFrame();
+  }
+  
   FinishAndStoreOverflow(&aDesiredSize);
   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
   return rv;
 }
 
 /* virtual */ void
 nsTableRowGroupFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
 {
@@ -1838,14 +1868,23 @@ nsTableRowGroupFrame::FrameCursorData::A
   nscoord overflowAbove = -overflowRect.y;
   nscoord overflowBelow = overflowRect.YMost() - aFrame->GetSize().height;
   mOverflowAbove = NS_MAX(mOverflowAbove, overflowAbove);
   mOverflowBelow = NS_MAX(mOverflowBelow, overflowBelow);
   return mFrames.AppendElement(aFrame) != nullptr;
 }
   
 void 
-nsTableRowGroupFrame::InvalidateFrame()
+nsTableRowGroupFrame::InvalidateFrame(uint32_t aDisplayItemKey)
 {
-  nsIFrame::InvalidateFrame();
-  nsTableFrame *tableFrame = nsTableFrame::GetTableFrame(this);
-  tableFrame->InvalidateFrame();
+  nsIFrame::InvalidateFrame(aDisplayItemKey);
+  GetParent()->InvalidateFrameWithRect(GetVisualOverflowRect() + GetPosition(), aDisplayItemKey);
 }
+
+void 
+nsTableRowGroupFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey)
+{
+  nsIFrame::InvalidateFrameWithRect(aRect, aDisplayItemKey);
+  // If we have filters applied that would affects our bounds, then
+  // we get an inactive layer created and this is computed
+  // within FrameLayerBuilder
+  GetParent()->InvalidateFrameWithRect(aRect + GetPosition(), aDisplayItemKey);
+}
--- a/layout/tables/nsTableRowGroupFrame.h
+++ b/layout/tables/nsTableRowGroupFrame.h
@@ -320,17 +320,19 @@ public:
    * form non-decreasing sequences (should always be true for table rows);
    * if this is violated, call ClearRowCursor(). If we return nullptr, then we
    * decided not to use a cursor or we already have one set up.
    */
   FrameCursorData* SetupRowCursor();
 
   virtual nsILineIterator* GetLineIterator() { return this; }
 
-  virtual void InvalidateFrame();
+  virtual void InvalidateFrame(uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE;
+  virtual void InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE;
+  virtual void InvalidateFrameForRemoval() MOZ_OVERRIDE { InvalidateFrameSubtree(); }
 
 protected:
   nsTableRowGroupFrame(nsStyleContext* aContext);
 
   void InitChildReflowState(nsPresContext&     aPresContext, 
                             bool               aBorderCollapse,
                             nsHTMLReflowState& aReflowState);