Invalidate tables a little harder. Bug 421632, r+sr=roc
authorbzbarsky@mit.edu
Sun, 16 Mar 2008 13:32:48 -0700
changeset 13144 bf1e867422cf43e36ec352b377861f1ab9452d4b
parent 13143 56b3af45a98cc703416b4aa252dd458dbdb0c21e
child 13145 73ae680263103a433b0ca78f3b1dc861435c69a9
push idunknown
push userunknown
push dateunknown
bugs421632
milestone1.9b5pre
Invalidate tables a little harder. Bug 421632, r+sr=roc
layout/generic/nsBlockFrame.cpp
layout/tables/nsTableCellFrame.cpp
layout/tables/nsTableFrame.cpp
layout/tables/nsTableFrame.h
layout/tables/nsTableRowFrame.cpp
layout/tables/nsTableRowGroupFrame.cpp
layout/tables/nsTableRowGroupFrame.h
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -2237,16 +2237,17 @@ nsBlockFrame::ReflowLine(nsBlockReflowSt
     // We expect blocks to damage any area inside their bounds that is
     // dirty; however, if the frame changes size or position then we
     // need to do some repainting.
     // XXX roc --- the above statement is ambiguous about whether 'bounds'
     // means the frame's bounds or overflowArea, and in fact this is a source
     // of much confusion and bugs. Thus the following hack considers *both*
     // overflowArea and bounds. This should be considered a temporary hack
     // until we decide how it's really supposed to work.
+    // Note that we have a similar hack in nsTableFrame::InvalidateFrame.
     nsRect lineCombinedArea(aLine->GetCombinedArea());
     if (oldCombinedArea.TopLeft() != lineCombinedArea.TopLeft() ||
         oldBounds.TopLeft() != newBounds.TopLeft()) {
       // The block has moved, and so to be safe we need to repaint
       // XXX We need to improve on this...
       nsRect  dirtyRect;
       dirtyRect.UnionRect(oldCombinedArea, lineCombinedArea);
 #ifdef NOISY_BLOCK_INVALIDATE
--- a/layout/tables/nsTableCellFrame.cpp
+++ b/layout/tables/nsTableCellFrame.cpp
@@ -865,16 +865,17 @@ NS_METHOD nsTableCellFrame::Reflow(nsPre
     // 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 = PR_TRUE;
   }
 
   nsPoint kidOrigin(leftInset, topInset);
   nsRect origRect = firstKid->GetRect();
+  nsRect origOverflowRect = firstKid->GetOverflowRect();
   PRBool 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);
@@ -893,17 +894,18 @@ NS_METHOD nsTableCellFrame::Reflow(nsPre
   // 0 dimensioned cells need to be treated specially in Standard/NavQuirks mode 
   // see testcase "emptyCells.html"
   SetContentEmpty(0 == kidSize.height);
 
   // Place the child
   FinishReflowChild(firstKid, aPresContext, &kidReflowState, kidSize,
                     kidOrigin.x, kidOrigin.y, 0);
 
-  nsTableFrame::InvalidateFrame(firstKid, origRect, firstReflow);
+  nsTableFrame::InvalidateFrame(firstKid, origRect, origOverflowRect,
+                                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;
   }
 
--- a/layout/tables/nsTableFrame.cpp
+++ b/layout/tables/nsTableFrame.cpp
@@ -1953,16 +1953,18 @@ NS_METHOD nsTableFrame::Reflow(nsPresCon
     // use the old overflow area
      aDesiredSize.mOverflowArea.UnionRect(aDesiredSize.mOverflowArea,
                                           GetOverflowRect());
   }
 
   if (GetStateBits() & NS_FRAME_FIRST_REFLOW) {
     // Fulfill the promise InvalidateFrame makes.
     Invalidate(aDesiredSize.mOverflowArea);
+  } else {
+    CheckInvalidateSizeChange(aPresContext, aDesiredSize, aReflowState);
   }
 
   FinishAndStoreOverflow(&aDesiredSize);
   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
   return rv;
 }
 
 nsresult 
@@ -2577,26 +2579,28 @@ 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&        aOriginalKidRect,
+                              const nsRect&        aOriginalKidOverflowRect)
 {
   PRBool isFirstReflow =
     (aKidFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0;
   
   // Place and size the child
   FinishReflowChild(aKidFrame, PresContext(), nsnull, aKidDesiredSize,
                     aReflowState.x, aReflowState.y, 0);
 
-  InvalidateFrame(aKidFrame, aOriginalKidRect, isFirstReflow);
+  InvalidateFrame(aKidFrame, aOriginalKidRect, aOriginalKidOverflowRect,
+                  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;
   }
@@ -2910,16 +2914,17 @@ nsTableFrame::ReflowChildren(nsTableRefl
           if (footerHeight + cellSpacingY < kidAvailSize.height) {
             allowRepeatedFooter = PR_TRUE;
             kidAvailSize.height -= footerHeight + cellSpacingY;
           }
         }
       }
 
       nsRect oldKidRect = kidFrame->GetRect();
+      nsRect oldKidOverflowRect = kidFrame->GetOverflowRect();
 
       nsHTMLReflowMetrics desiredSize;
       desiredSize.width = desiredSize.height = 0;
   
       // Reflow the child into the available space
       nsHTMLReflowState kidReflowState(presContext, aReflowState.reflowState,
                                        kidFrame, kidAvailSize,
                                        -1, -1, PR_FALSE);
@@ -2961,17 +2966,18 @@ nsTableFrame::ReflowChildren(nsTableRefl
       if (NS_FRAME_IS_COMPLETE(aStatus) && isPaginated &&
           (NS_UNCONSTRAINEDSIZE != kidReflowState.availableHeight) &&
           kidReflowState.availableHeight < desiredSize.height) {
         // if we are on top of the page place with dataloss
         if (kidReflowState.mFlags.mIsTopOfPage) {
           if (childX+1 < rowGroups.Length()) {
             nsIFrame* nextRowGroupFrame = rowGroups[childX + 1];
             if (nextRowGroupFrame) {
-              PlaceChild(aReflowState, kidFrame, desiredSize, oldKidRect);
+              PlaceChild(aReflowState, kidFrame, desiredSize, oldKidRect,
+                         oldKidOverflowRect);
               aStatus = NS_FRAME_NOT_COMPLETE;
               PushChildren(rowGroups, childX + 1);
               aLastChildReflowed = kidFrame;
               break;
             }
           }
         }
         else { // we are not on top, push this rowgroup onto the next page
@@ -2992,17 +2998,18 @@ nsTableFrame::ReflowChildren(nsTableRefl
       if (NS_FRAME_IS_COMPLETE(aStatus) && isPaginated && 
           (NS_UNCONSTRAINEDSIZE != kidReflowState.availableHeight)) {
         nsIFrame* nextKid =
           (childX + 1 < numRowGroups) ? rowGroups[childX + 1] : nsnull;
         pageBreak = PageBreakAfter(*kidFrame, nextKid);
       }
 
       // Place the child
-      PlaceChild(aReflowState, kidFrame, desiredSize, oldKidRect);
+      PlaceChild(aReflowState, kidFrame, desiredSize, oldKidRect,
+                 oldKidOverflowRect);
 
       // Remember where we just were in case we end up pushing children
       prevKidFrame = kidFrame;
 
       // Special handling for incomplete children
       if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) {         
         kidNextInFlow = kidFrame->GetNextInFlow();
         if (!kidNextInFlow) {
@@ -3042,22 +3049,24 @@ nsTableFrame::ReflowChildren(nsTableRefl
           nsHTMLReflowState footerReflowState(presContext,
                                               aReflowState.reflowState,
                                               tfoot, kidAvailSize,
                                               -1, -1, PR_FALSE);
           InitChildReflowState(footerReflowState);
           aReflowState.y += cellSpacingY;
 
           nsRect origTfootRect = tfoot->GetRect();
+          nsRect origTfootOverflowRect = tfoot->GetOverflowRect();
           
           nsReflowStatus footerStatus;
           rv = ReflowChild(tfoot, presContext, desiredSize, footerReflowState,
                            aReflowState.x, aReflowState.y,
                            NS_FRAME_INVALIDATE_ON_MOVE, footerStatus);
-          PlaceChild(aReflowState, tfoot, desiredSize, origTfootRect);
+          PlaceChild(aReflowState, tfoot, desiredSize, origTfootRect,
+                     origTfootOverflowRect);
         }
         break;
       }
     }
     else { // it isn't being reflowed
       aReflowState.y += cellSpacingY;
       nsRect kidRect = kidFrame->GetRect();
       if (kidRect.y != aReflowState.y) {
@@ -3269,23 +3278,25 @@ nsTableFrame::DistributeHeightToRows(con
         rowFrame = rowFrame->GetNextRow();
       }
       if (amountUsed > 0) {
         if (rgRect.y != yOriginRG) {
           rgFrame->InvalidateOverflowRect();
         }
 
         nsRect origRgRect = rgRect;
+        nsRect origRgOverflowRect = rgFrame->GetOverflowRect();
         
         rgRect.y = yOriginRG;
         rgRect.height += amountUsedByRG;
         
         rgFrame->SetRect(rgRect);
 
-        nsTableFrame::InvalidateFrame(rgFrame, origRgRect, PR_FALSE);
+        nsTableFrame::InvalidateFrame(rgFrame, origRgRect, origRgOverflowRect,
+                                      PR_FALSE);
       }
     }
     else if (amountUsed > 0 && yOriginRG != rgFrame->GetPosition().y) {
       NS_ASSERTION(rgFrame->GetPosition().x == 0, "Unexpected position");
       rgFrame->InvalidateOverflowRect();
       rgFrame->SetPosition(nsPoint(0, yOriginRG));
       // Make sure child views are properly positioned
       nsTableFrame::RePositionViews(rgFrame);
@@ -3362,21 +3373,23 @@ nsTableFrame::DistributeHeightToRows(con
   nscoord heightToDistribute = aAmount - amountUsed;
   yOriginRG = borderPadding.top + cellSpacingY;
   yEndRG = yOriginRG;
   for (rgX = 0; rgX < rowGroups.Length(); rgX++) {
     nsTableRowGroupFrame* rgFrame = rowGroups[rgX];
     nscoord amountUsedByRG = 0;
     nscoord yOriginRow = 0;
     nsRect rgRect = rgFrame->GetRect();
+    nsRect rgOverflowRect = rgFrame->GetOverflowRect();
     // see if there is an eligible row group or we distribute to all rows
     if (!firstUnStyledRG || !rgFrame->HasStyleHeight() || !eligibleRows) {
       nsTableRowFrame* rowFrame = rgFrame->GetFirstRow();
       while (rowFrame) {
         nsRect rowRect = rowFrame->GetRect();
+        nsRect rowOverflowRect = rowFrame->GetOverflowRect();
         // see if there is an eligible row or we distribute to all rows
         if (!firstUnStyledRow || !rowFrame->HasStyleHeight() || !eligibleRows) {          
           float ratio;
           if (eligibleRows) {
             if (!expandEmptyRows) {
               // The amount of additional space each row gets is proportional to
               // its height
               ratio = float(rowRect.height) / float(divisor);
@@ -3408,17 +3421,18 @@ nsTableFrame::DistributeHeightToRows(con
           yEndRG += newRowRect.height + cellSpacingY;
 
           amountUsed += amountForRow;
           amountUsedByRG += amountForRow;
           NS_ASSERTION((amountUsed <= aAmount), "invalid row allocation");
           //rowFrame->DidResize();        
           nsTableFrame::RePositionViews(rowFrame);
 
-          nsTableFrame::InvalidateFrame(rowFrame, rowRect, PR_FALSE);
+          nsTableFrame::InvalidateFrame(rowFrame, rowRect, rowOverflowRect,
+                                        PR_FALSE);
         }
         else {
           if (amountUsed > 0 && yOriginRow != rowRect.y) {
             rowFrame->InvalidateOverflowRect();
             rowFrame->SetPosition(nsPoint(rowRect.x, yOriginRow));
             nsTableFrame::RePositionViews(rowFrame);
             rowFrame->InvalidateOverflowRect();
           }
@@ -3430,17 +3444,18 @@ nsTableFrame::DistributeHeightToRows(con
       if (amountUsed > 0) {
         if (rgRect.y != yOriginRG) {
           rgFrame->InvalidateOverflowRect();
         }
         
         rgFrame->SetRect(nsRect(rgRect.x, yOriginRG, rgRect.width,
                                 rgRect.height + amountUsedByRG));
 
-        nsTableFrame::InvalidateFrame(rgFrame, rgRect, PR_FALSE);
+        nsTableFrame::InvalidateFrame(rgFrame, rgRect, rgOverflowRect,
+                                      PR_FALSE);
       }
       // Make sure child views are properly positioned
       // XXX what happens if childFrame is a scroll frame and this gets skipped? see also below
     }
     else if (amountUsed > 0 && yOriginRG != rgFrame->GetPosition().y) {
       NS_ASSERTION(rgFrame->GetPosition().x == 0, "Unexpected position");
       rgFrame->InvalidateOverflowRect();
       rgFrame->SetPosition(nsPoint(0, yOriginRG));
@@ -6768,31 +6783,40 @@ nsTableFrame::GetProperty(nsIFrame*     
     }
     return value;
   }
   return nsnull;
 }
 
 /* static */
 void
-nsTableFrame::InvalidateFrame(nsIFrame* aFrame, const nsRect& aOrigRect,
+nsTableFrame::InvalidateFrame(nsIFrame* aFrame,
+                              const nsRect& aOrigRect,
+                              const nsRect& aOrigOverflowRect,
                               PRBool 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;
   }
-  
-  if (aIsFirstReflow || aOrigRect.TopLeft() != aFrame->GetPosition()) {
+
+  // The part that looks at both the rect and the overflow rect is a
+  // bit of a hack.  See nsBlockFrame::ReflowLine for an eloquent
+  // descriptiong of its hackishness.
+  nsRect overflowRect = aFrame->GetOverflowRect();
+  if (aIsFirstReflow ||
+      aOrigRect.TopLeft() != aFrame->GetPosition() ||
+      aOrigOverflowRect.TopLeft() != overflowRect.TopLeft()) {
     aFrame->InvalidateOverflowRect();
   } else {
+    aFrame->InvalidateRectDifference(aOrigOverflowRect, overflowRect);
     parent->InvalidateRectDifference(aOrigRect, aFrame->GetRect());
   }    
 }
 
 #ifdef DEBUG
 #define MAX_SIZE  128
 #define MIN_INDENT 30
 
--- a/layout/tables/nsTableFrame.h
+++ b/layout/tables/nsTableFrame.h
@@ -483,20 +483,23 @@ public:
   /**
    * 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 reflown 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 aOrigOverflowRect The original overflow rect of aFrame.
    * @param aIsFirstReflow True if the size/position change is due to the
    *                       first reflow of aFrame.
    */
-  static void InvalidateFrame(nsIFrame* aFrame, const nsRect& aOrigRect,
+  static void InvalidateFrame(nsIFrame* aFrame,
+                              const nsRect& aOrigRect,
+                              const nsRect& aOrigOverflowRect,
                               PRBool aIsFirstReflow);
 
 protected:
 
   /** protected constructor. 
     * @see NewFrame
     */
   nsTableFrame(nsStyleContext* aContext);
@@ -577,17 +580,18 @@ protected:
   // The following is a helper for CalcDesiredHeight 
  
   void DistributeHeightToRows(const nsHTMLReflowState& aReflowState,
                               nscoord                  aAmount);
 
   void PlaceChild(nsTableReflowState&  aReflowState,
                   nsIFrame*            aKidFrame,
                   nsHTMLReflowMetrics& aKidDesiredSize,
-                  const nsRect&        aOriginalKidRect);
+                  const nsRect&        aOriginalKidRect,
+                  const nsRect&        aOriginalKidOverflowRect);
 
   nsIFrame* GetFirstBodyRowGroupFrame();
   PRBool MoveOverflowToChildList(nsPresContext* aPresContext);
   /**
    * Push all our child frames from the aFrames array, in order, starting from the
    * frame at aPushFrom to the end of the array. The frames are put on our overflow
    * list or moved directly to our next-in-flow if one exists.
    */
--- a/layout/tables/nsTableRowFrame.cpp
+++ b/layout/tables/nsTableRowFrame.cpp
@@ -349,20 +349,22 @@ nsTableRowFrame::DidResize()
 
   while (childFrame) {
     if (IS_TABLE_CELL(childFrame->GetType())) {
       nsTableCellFrame* cellFrame = (nsTableCellFrame*)childFrame;
       nscoord cellHeight = mRect.height + GetHeightOfRowsSpannedBelowFirst(*cellFrame, *tableFrame);
 
       // resize the cell's height
       nsRect cellRect = cellFrame->GetRect();
+      nsRect cellOverflowRect = cellFrame->GetOverflowRect();
       if (cellRect.height != cellHeight)
       {
         cellFrame->SetSize(nsSize(cellRect.width, cellHeight));
-        nsTableFrame::InvalidateFrame(cellFrame, cellRect, PR_FALSE);
+        nsTableFrame::InvalidateFrame(cellFrame, cellRect, cellOverflowRect,
+                                      PR_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.
@@ -859,16 +861,17 @@ nsTableRowFrame::ReflowChildren(nsPresCo
                            cellSpacingX, iter.IsLeftToRight(), PR_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 kidOverflowRect = kidFrame->GetOverflowRect();
     PRBool firstReflow =
       (kidFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0;
 
     if (doReflowChild) {
       // Calculate the available width for the table cell using the known column widths
       nscoord availColWidth, availCellWidth;
       CalcAvailWidth(aTableFrame, *cellFrame, cellSpacingX,
                      availColWidth, availCellWidth);
@@ -959,17 +962,18 @@ nsTableRowFrame::ReflowChildren(nsPresCo
 
       // Place the child
       if (NS_UNCONSTRAINEDSIZE != availColWidth) {
         desiredSize.width = PR_MAX(availCellWidth, availColWidth);
       }
 
       FinishReflowChild(kidFrame, aPresContext, nsnull, desiredSize, x, 0, 0);
 
-      nsTableFrame::InvalidateFrame(kidFrame, kidRect, firstReflow);
+      nsTableFrame::InvalidateFrame(kidFrame, kidRect, kidOverflowRect,
+                                    firstReflow);
       
       x += desiredSize.width;  
     }
     else {
       if (kidRect.x != x) {
         // Invalidate the old position
         kidFrame->InvalidateOverflowRect();
         // move to the new position
@@ -1056,16 +1060,22 @@ 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) {
+    CheckInvalidateSizeChange(aPresContext, aDesiredSize, aReflowState);
+  }
+
   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
@@ -1079,16 +1089,17 @@ nsTableRowFrame::ReflowCellFrame(nsPresC
                                  nsReflowStatus&          aStatus)
 {
   nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
   if (!tableFrame)
     ABORT1(NS_ERROR_NULL_POINTER);
 
   // Reflow the cell frame with the specified height. Use the existing width
   nsRect cellRect = aCellFrame->GetRect();
+  nsRect cellOverflowRect = aCellFrame->GetOverflowRect();
   
   nsSize  availSize(cellRect.width, aAvailableHeight);
   PRBool borderCollapse = ((nsTableFrame*)tableFrame->GetFirstInFlow())->IsBorderCollapse();
   nsTableCellReflowState cellReflowState(aPresContext, aReflowState,
                                          aCellFrame, availSize, PR_FALSE);
   InitChildReflowState(*aPresContext, availSize, borderCollapse, cellReflowState);
   cellReflowState.mFlags.mIsTopOfPage = aIsTopOfPage;
 
@@ -1097,25 +1108,28 @@ nsTableRowFrame::ReflowCellFrame(nsPresC
   ReflowChild(aCellFrame, aPresContext, desiredSize, cellReflowState,
               0, 0, NS_FRAME_NO_MOVE_FRAME, aStatus);
   PRBool fullyComplete = NS_FRAME_IS_COMPLETE(aStatus) && !NS_FRAME_IS_TRUNCATED(aStatus);
   if (fullyComplete) {
     desiredSize.height = aAvailableHeight;
   }
   aCellFrame->SetSize(nsSize(cellRect.width, desiredSize.height));
 
-  nsTableFrame::InvalidateFrame(aCellFrame, cellRect,
-                                (aCellFrame->GetStateBits() &
-                                   NS_FRAME_FIRST_REFLOW) != 0);
-  
+  // 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::InvalidateFrame(aCellFrame, cellRect,
+                                cellOverflowRect,
+                                (aCellFrame->GetStateBits() &
+                                   NS_FRAME_FIRST_REFLOW) != 0);
+  
   aCellFrame->DidReflow(aPresContext, nsnull, NS_FRAME_REFLOW_FINISHED);
 
   return desiredSize.height;
 }
 
 nscoord
 nsTableRowFrame::CollapseRowIfNecessary(nscoord aRowOffset,
                                         nscoord aWidth,
@@ -1133,16 +1147,17 @@ nsTableRowFrame::CollapseRowIfNecessary(
 
   if (aRowOffset != 0) {
     // We're moving, so invalidate our old position
     InvalidateOverflowRect();
   }
   
   nsRect rowRect = GetRect();
   nsRect oldRect = rowRect;
+  nsRect oldOverflowRect = GetOverflowRect();
   
   rowRect.y -= aRowOffset;
   rowRect.width  = aWidth;
   nsRect overflowArea(0, 0, 0, 0);
   nscoord shift = 0;
   nscoord cellSpacingX = tableFrame->GetCellSpacingX();
   nscoord cellSpacingY = tableFrame->GetCellSpacingY();
 
@@ -1248,16 +1263,17 @@ nsTableRowFrame::CollapseRowIfNecessary(
           if (!collapseNextRow) {
             nsRect nextRect = rowFrame->GetRect();
             cRect.height += nextRect.height + cellSpacingY;
           }
           rowFrame = rowFrame->GetNextRow();
         }
 
         nsRect oldCellRect = cellFrame->GetRect();
+        nsRect oldCellOverflowRect = cellFrame->GetOverflowRect();
 
         if (aRowOffset == 0 && cRect.TopLeft() != oldCellRect.TopLeft()) {
           // We're moving the cell.  Invalidate the old overflow area
           cellFrame->InvalidateOverflowRect();
         }
         
         cellFrame->SetRect(cRect);
 
@@ -1265,31 +1281,32 @@ nsTableRowFrame::CollapseRowIfNecessary(
         // collapse the cell!
         nsRect cellOverflow = nsRect(0, 0, cRect.width, cRect.height);
         cellFrame->FinishAndStoreOverflow(&cellOverflow, nsSize(cRect.width,
                                               cRect.height));
         nsTableFrame::RePositionViews(cellFrame);
         ConsiderChildOverflow(overflowArea, cellFrame);
                 
         if (aRowOffset == 0) {
-          nsTableFrame::InvalidateFrame(cellFrame, oldCellRect, PR_FALSE);
+          nsTableFrame::InvalidateFrame(cellFrame, oldCellRect,
+                                        oldCellOverflowRect, PR_FALSE);
         }
       }
       kidFrame = iter.Next(); // Get the next child
     }
   }
 
   SetRect(rowRect);
   overflowArea.UnionRect(nsRect(0,0,rowRect.width, rowRect.height),
                          overflowArea);
   FinishAndStoreOverflow(&overflowArea, nsSize(rowRect.width,
                                               rowRect.height));
 
   nsTableFrame::RePositionViews(this);
-  nsTableFrame::InvalidateFrame(this, oldRect, PR_FALSE);
+  nsTableFrame::InvalidateFrame(this, oldRect, oldOverflowRect, PR_FALSE);
   return shift;
 }
 
 
 /**
  * These 3 functions are called by the row group frame's SplitRowGroup() code when
  * it creates a continuing cell frame and wants to insert it into the row's child list
  */
--- a/layout/tables/nsTableRowGroupFrame.cpp
+++ b/layout/tables/nsTableRowGroupFrame.cpp
@@ -290,26 +290,28 @@ nsTableRowGroupFrame::GetSkipSides() con
 
 // Position and size aKidFrame and update our reflow state. The origin of
 // aKidRect is relative to the upper-left origin of our frame
 void 
 nsTableRowGroupFrame::PlaceChild(nsPresContext*        aPresContext,
                                  nsRowGroupReflowState& aReflowState,
                                  nsIFrame*              aKidFrame,
                                  nsHTMLReflowMetrics&   aDesiredSize,
-                                 const nsRect&          aOriginalKidRect)
+                                 const nsRect&          aOriginalKidRect,
+                                 const nsRect&          aOriginalKidOverflowRect)
 {
   PRBool isFirstReflow =
     (aKidFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0;
 
   // Place and size the child
   FinishReflowChild(aKidFrame, aPresContext, nsnull, aDesiredSize, 0,
                     aReflowState.y, 0);
 
-  nsTableFrame::InvalidateFrame(aKidFrame, aOriginalKidRect, isFirstReflow);
+  nsTableFrame::InvalidateFrame(aKidFrame, aOriginalKidRect,
+                                aOriginalKidOverflowRect, 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;
   }
@@ -387,16 +389,17 @@ nsTableRowGroupFrame::ReflowChildren(nsP
 
     // Reflow the row frame
     if (reflowAllKids ||
         NS_SUBTREE_DIRTY(kidFrame) ||
         (aReflowState.reflowState.mFlags.mSpecialHeightReflow &&
          (isPaginated || (kidFrame->GetStateBits() &
                           NS_FRAME_CONTAINS_RELATIVE_HEIGHT)))) {
       nsRect oldKidRect = kidFrame->GetRect();
+      nsRect oldKidOverflowRect = kidFrame->GetOverflowRect();
 
       // XXXldb We used to only pass aDesiredSize.mFlags through for the
       // incremental reflow codepath.
       nsHTMLReflowMetrics desiredSize(aDesiredSize.mFlags);
       desiredSize.width = desiredSize.height = 0;
   
       // Reflow the child into the available space, giving it as much height as
       // it wants. We'll deal with splitting later after we've computed the row
@@ -417,17 +420,17 @@ nsTableRowGroupFrame::ReflowChildren(nsP
       }
 
       rv = ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState,
                        0, aReflowState.y, NS_FRAME_INVALIDATE_ON_MOVE,
                        aStatus);
 
       // Place the child
       PlaceChild(aPresContext, aReflowState, kidFrame, desiredSize,
-                 oldKidRect);
+                 oldKidRect, oldKidOverflowRect);
       aReflowState.y += cellSpacingY;
 
       if (!reflowAllKids) {
         if (IsSimpleRowFrame(aReflowState.tableFrame, kidFrame)) {
           // Inform the row of its new height.
           ((nsTableRowFrame*)kidFrame)->DidResize();
           // the overflow area may have changed inflate the overflow area
           if (aReflowState.tableFrame->IsAutoHeight()) {
@@ -796,31 +799,33 @@ 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 rowBounds = rowFrame->GetRect();
+    nsRect rowOverflowRect = rowFrame->GetOverflowRect();
 
     PRBool 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->InvalidateOverflowRect();
       }
       
       rowFrame->SetRect(nsRect(rowBounds.x, yOrigin, rowBounds.width,
                                rowHeight));
 
-      nsTableFrame::InvalidateFrame(rowFrame, rowBounds, PR_FALSE);
+      nsTableFrame::InvalidateFrame(rowFrame, rowBounds, rowOverflowRect,
+                                    PR_FALSE);
     }
     if (movedFrame) {
       nsTableFrame::RePositionViews(rowFrame);
       // XXXbz we don't need to update our overflow area?
     }
     yOrigin += rowHeight + cellSpacingY;
   }
 
@@ -856,16 +861,17 @@ nsTableRowGroupFrame::CollapseRowGroupIf
                                                      aWidth, collapseGroup,
                                                      didCollapse);
     ConsiderChildOverflow(overflowArea, rowFrame);
     rowFrame = rowFrame->GetNextRow();
   }
 
   nsRect groupRect = GetRect();
   nsRect oldGroupRect = groupRect;
+  nsRect oldGroupOverflowRect = GetOverflowRect();
   
   groupRect.height -= yGroupOffset;
   if (didCollapse) {
     // add back the cellspacing between rowgroups
     groupRect.height += tableFrame->GetCellSpacingY();
   }
 
   groupRect.y -= aYTotalOffset;
@@ -876,17 +882,18 @@ nsTableRowGroupFrame::CollapseRowGroupIf
   }
   
   SetRect(groupRect);
   overflowArea.UnionRect(nsRect(0, 0, groupRect.width, groupRect.height),
                          overflowArea);
   FinishAndStoreOverflow(&overflowArea, nsSize(groupRect.width,
                                               groupRect.height));
   nsTableFrame::RePositionViews(this);
-  nsTableFrame::InvalidateFrame(this, oldGroupRect, PR_FALSE);
+  nsTableFrame::InvalidateFrame(this, oldGroupRect, oldGroupOverflowRect,
+                                PR_FALSE);
 
   return yGroupOffset;
 }
 
 // Move a child that was skipped during an incremental reflow.
 // This function is not used for paginated mode so we don't need to deal
 // with continuing frames, and it's only called if aKidFrame has no
 // cells that span into it and no cells that span across it. That way
@@ -1102,27 +1109,29 @@ nsTableRowGroupFrame::SplitRowGroup(nsPr
                                          -1, -1, PR_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 oldRowOverflowRect = rowFrame->GetOverflowRect();
 
         // 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, nsnull, NS_FRAME_REFLOW_FINISHED);
         rowFrame->DidResize();
 
-        nsTableFrame::InvalidateFrame(rowFrame, oldRowRect, PR_FALSE);
+        nsTableFrame::InvalidateFrame(rowFrame, oldRowRect, oldRowOverflowRect,
+                                      PR_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");
@@ -1340,17 +1349,24 @@ 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.mOverflowArea.UnionRect(aDesiredSize.mOverflowArea, nsRect(0, 0, aDesiredSize.width,
-	                                                                      aDesiredSize.height)); 
+	                                                                      aDesiredSize.height));
+
+  // If our parent is in initial reflow, it'll handle invalidating our
+  // entire overflow rect.
+  if (!GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW) {
+    CheckInvalidateSizeChange(aPresContext, aDesiredSize, aReflowState);
+  }
+  
   FinishAndStoreOverflow(&aDesiredSize);
   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
   return rv;
 }
 
 NS_IMETHODIMP
 nsTableRowGroupFrame::AppendFrames(nsIAtom*        aListName,
                                    nsIFrame*       aFrameList)
--- a/layout/tables/nsTableRowGroupFrame.h
+++ b/layout/tables/nsTableRowGroupFrame.h
@@ -370,17 +370,18 @@ protected:
   
   /** implement abstract method on nsHTMLContainerFrame */
   virtual PRIntn GetSkipSides() const;
 
   void PlaceChild(nsPresContext*        aPresContext,
                   nsRowGroupReflowState& aReflowState,
                   nsIFrame*              aKidFrame,
                   nsHTMLReflowMetrics&   aDesiredSize,
-                  const nsRect&          aOriginalKidRect);
+                  const nsRect&          aOriginalKidRect,
+                  const nsRect&          aOriginalKidOverflowRect);
 
   void CalculateRowHeights(nsPresContext*          aPresContext, 
                            nsHTMLReflowMetrics&     aDesiredSize,
                            const nsHTMLReflowState& aReflowState);
 
   void DidResizeRows(nsHTMLReflowMetrics& aDesiredSize);
 
   void SlideChild(nsRowGroupReflowState& aReflowState,