bug 460637 - the group cellmaps need to set the damageArea relative to the entire table, patch by Mats Palmgren, Randell Jesup and Bernd, r=mats, bernd
authorBernd <bmlk@gmx.de>
Thu, 27 Oct 2011 09:58:44 -0400
changeset 81640 0b39e1a64c2b19221274c6a62dfae556902161b6
parent 81639 bc7ff681a4ae19830c39329bcf855e1f85b9a03f
child 81641 215ba0c3d5b767b38949f4ef73dc7ab2b0c0f30b
push id628
push userclegnitto@mozilla.com
push dateWed, 21 Dec 2011 14:41:57 +0000
treeherdermozilla-aurora@24a61ad789e8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmats, bernd
bugs460637
milestone11.0a1
bug 460637 - the group cellmaps need to set the damageArea relative to the entire table, patch by Mats Palmgren, Randell Jesup and Bernd, r=mats, bernd
layout/reftests/bugs/reftest.list
layout/tables/crashtests/460637-1.xhtml
layout/tables/crashtests/460637-2.xhtml
layout/tables/crashtests/460637-3.xhtml
layout/tables/crashtests/crashtests.list
layout/tables/nsCellMap.cpp
layout/tables/nsCellMap.h
layout/tables/nsTableCellFrame.cpp
layout/tables/nsTableColFrame.cpp
layout/tables/nsTableColGroupFrame.cpp
layout/tables/nsTableFrame.cpp
layout/tables/nsTableFrame.h
layout/tables/nsTableRowFrame.cpp
layout/tables/nsTableRowGroupFrame.cpp
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -296,17 +296,17 @@ fails-if(Android) != 192767-17.xul 19276
 == 280708-1b.html 280708-1-ref.html
 == 281241-1.html 281241-1-ref.html
 == 281241-2.xhtml 281241-1-ref.html
 == 283686-1.html about:blank
 == 283686-2.html 283686-2-ref.html
 == 283686-3.html about:blank
 == 289384-1.xhtml 289384-ref.xhtml
 fails-if(Android) random-if(d2d) HTTP == 289480.html#top 289480-ref.html # basically-verbatim acid2 test, HTTP for a 404 page -- bug 578114 for the d2d failures
-asserts(1) == 290129-1.html 290129-1-ref.html # bug 315549/460637
+== 290129-1.html 290129-1-ref.html
 == 291078-1.html 291078-1-ref.html
 == 291078-2.html 291078-2-ref.html
 == 291262-1.html 291262-1-ref.html
 == 294306-1.html 294306-1a-ref.html
 != 294306-1.html 294306-1b-ref.html
 == 296361-1.html 296361-ref.html
 == 296904-1.html 296904-1-ref.html
 == 299136-1.html 299136-1-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/tables/crashtests/460637-1.xhtml
@@ -0,0 +1,41 @@
+<html xmlns="http://www.w3.org/1999/xhtml" class="reftest-wait">
+<head><script type="text/javascript">
+<![CDATA[
+
+  function boom() {
+    var HTML_NS = "http://www.w3.org/1999/xhtml";
+    var r = document.documentElement; while(r.firstChild) { r.removeChild(r.firstChild); }
+    var table = document.createElementNS(HTML_NS, "table");
+    table.setAttribute("border", "1");
+    var text = document.createTextNode("\n ");
+    table.appendChild(text);
+    var tr1 = document.createElementNS(HTML_NS, "tr");
+    table.appendChild(tr1);
+    var tr2 = document.createElementNS(HTML_NS, "tr");
+    var input = document.createElementNS(HTML_NS, "input");
+    tr2.appendChild(input);
+    table.appendChild(tr2);
+    document.documentElement.appendChild(table);
+    var tr3 = document.createElementNS(HTML_NS, 'tr');
+    table.insertBefore(tr3, text);
+    var td = document.createElementNS(HTML_NS, 'td');
+    td.setAttribute('rowspan', 0);
+    tr3.insertBefore(td, null);
+    table.removeAttribute('border');
+    var caption = document.createElementNS(HTML_NS, 'caption');
+    table.insertBefore(caption, tr2);
+    document.documentElement.removeAttribute("class");
+  }
+
+  function ol(e) {
+    window.removeEventListener("load", ol, false);
+    setTimeout(boom, 400);
+  }
+  
+  window.addEventListener("load", ol, false);
+
+]]></script>
+</head>
+
+<body></body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/tables/crashtests/460637-2.xhtml
@@ -0,0 +1,24 @@
+<html xmlns="http://www.w3.org/1999/xhtml" class="reftest-wait">
+<head><script type="text/javascript">
+<![CDATA[
+
+  function boom() {
+    var tr = document.getElementById('tr');
+    th = document.createElementNS("http://www.w3.org/1999/xhtml", 'th');
+    th.setAttribute('rowspan', 9);
+    tr.appendChild(th);
+    document.documentElement.removeAttribute("class");
+  }
+
+
+  function ol(e) {
+    window.removeEventListener("load", ol, false);
+    setTimeout(boom, 400);
+  }
+  
+  window.addEventListener("load", ol, false);
+
+]]></script>
+</head>
+<body><table style="border-collapse: collapse;"><tbody><tr id="tr"></tr></tbody></table></body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/tables/crashtests/460637-3.xhtml
@@ -0,0 +1,26 @@
+<html xmlns="http://www.w3.org/1999/xhtml" class="reftest-wait">
+<head><script type="text/javascript">
+<![CDATA[
+
+  function boom() {
+    const HTML_NS = "http://www.w3.org/1999/xhtml";
+    var tr4 = document.createElementNS(HTML_NS, 'tr');
+    document.getElementById('tbody1').appendChild(tr4);
+    var span1 = document.createElementNS(HTML_NS, 'td');
+    tr4.insertBefore(span1, null);
+    document.documentElement.removeAttribute("class");
+  }
+
+  function ol(e) {
+    window.removeEventListener("load", ol, false);
+    setTimeout(boom, 400);
+  }
+
+  window.addEventListener("load", ol, false);
+
+]]>
+</script>
+</head>
+
+<body><table><tbody id="tbody1"><tr><td rowspan="0"></td></tr></tbody></table></body>
+</html>
--- a/layout/tables/crashtests/crashtests.list
+++ b/layout/tables/crashtests/crashtests.list
@@ -91,16 +91,19 @@ load 416845-3.html
 asserts(12) load 420654-1.xhtml # Bug 575011
 load 423514-1.xhtml
 load 430374.html
 load 444431-1.html
 load 448988-1.xhtml
 load 450311-1.html
 load 456041.html
 load 457115.html
+load 460637-1.xhtml
+load 460637-2.xhtml
+load 460637-3.xhtml
 load 467141-1.html
 load 488388-1.html
 load 512749-1.html
 load 513732-1.html
 asserts(0-1) load 533380-1.xhtml # Bug 614457
 load 534716-1.html
 load 573354-1.xhtml
 load 576890-1.html
--- a/layout/tables/nsCellMap.cpp
+++ b/layout/tables/nsCellMap.cpp
@@ -36,16 +36,34 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsTArray.h"
 #include "nsCellMap.h"
 #include "nsTableFrame.h"
 #include "nsTableCellFrame.h"
 #include "nsTableRowGroupFrame.h"
 
+
+static void
+SetDamageArea(PRInt32 aXOrigin,
+              PRInt32 aYOrigin,
+              PRInt32 aWidth,
+              PRInt32 aHeight,
+              nsRect& aDamageArea)
+{
+  NS_ASSERTION(aXOrigin >= 0, "negative col index");
+  NS_ASSERTION(aYOrigin >= 0, "negative row index");
+  NS_ASSERTION(aWidth >= 0, "negative horizontal damage");
+  NS_ASSERTION(aHeight >= 0, "negative vertical damage");
+  aDamageArea.x      = aXOrigin;
+  aDamageArea.y      = aYOrigin;
+  aDamageArea.width  = aWidth;
+  aDamageArea.height = aHeight;
+}
+ 
 // Empty static array used for SafeElementAt() calls on mRows.
 static nsCellMap::CellDataArray * sEmptyRow;
 
 // CellData
 
 CellData::CellData(nsTableCellFrame* aOrigCell)
 {
   MOZ_COUNT_CTOR(CellData);
@@ -474,23 +492,23 @@ nsTableCellMap::InsertRows(nsTableRowGro
                            PRInt32                     aFirstRowIndex,
                            bool                        aConsiderSpans,
                            nsRect&                     aDamageArea)
 {
   PRInt32 numNewRows = aRows.Length();
   if ((numNewRows <= 0) || (aFirstRowIndex < 0)) ABORT0();
 
   PRInt32 rowIndex = aFirstRowIndex;
+  PRInt32 rgStartRowIndex = 0;
   nsCellMap* cellMap = mFirstMap;
   while (cellMap) {
     nsTableRowGroupFrame* rg = cellMap->GetRowGroup();
     if (rg == aParent) {
-      cellMap->InsertRows(*this, aRows, rowIndex, aConsiderSpans, aDamageArea);
-      aDamageArea.y = NS_MIN(aFirstRowIndex, aDamageArea.y);
-      aDamageArea.height = NS_MAX(0, GetRowCount() - aDamageArea.y);
+      cellMap->InsertRows(*this, aRows, rowIndex, aConsiderSpans,
+                          rgStartRowIndex, aDamageArea);
 #ifdef DEBUG_TABLE_CELLMAP
       Dump("after InsertRows");
 #endif
       if (mBCInfo) {
         PRInt32 count = mBCInfo->mRightBorders.Length();
         if (aFirstRowIndex < count) {
           for (PRInt32 rowX = aFirstRowIndex; rowX < aFirstRowIndex + numNewRows; rowX++) {
             if (!mBCInfo->mRightBorders.InsertElementAt(rowX))
@@ -502,47 +520,50 @@ nsTableCellMap::InsertRows(nsTableRowGro
           for (PRInt32 rowX = aFirstRowIndex + 1; rowX < aFirstRowIndex + numNewRows; rowX++) {
             if (!mBCInfo->mRightBorders.AppendElement())
               ABORT0();
           }
         }
       }
       return;
     }
-    rowIndex -= cellMap->GetRowCount();
+    PRInt32 rowCount = cellMap->GetRowCount();
+    rgStartRowIndex += rowCount;
+    rowIndex -= rowCount;
     cellMap = cellMap->GetNextSibling();
   }
 
   NS_ERROR("Attempt to insert row into wrong map.");
 }
 
 void
 nsTableCellMap::RemoveRows(PRInt32         aFirstRowIndex,
                            PRInt32         aNumRowsToRemove,
                            bool            aConsiderSpans,
                            nsRect&         aDamageArea)
 {
   PRInt32 rowIndex = aFirstRowIndex;
+  PRInt32 rgStartRowIndex = 0;
   nsCellMap* cellMap = mFirstMap;
   while (cellMap) {
-    if (cellMap->GetRowCount() > rowIndex) {
-      cellMap->RemoveRows(*this, rowIndex, aNumRowsToRemove, aConsiderSpans, aDamageArea);
-      nsTableRowGroupFrame* rg = cellMap->GetRowGroup();
-      aDamageArea.y += (rg) ? rg->GetStartRowIndex() : 0;
-      aDamageArea.height = NS_MAX(0, GetRowCount() - aFirstRowIndex);
+    PRInt32 rowCount = cellMap->GetRowCount();
+    if (rowCount > rowIndex) {
+      cellMap->RemoveRows(*this, rowIndex, aNumRowsToRemove, aConsiderSpans,
+                          rgStartRowIndex, aDamageArea);
       if (mBCInfo) {
         for (PRInt32 rowX = aFirstRowIndex + aNumRowsToRemove - 1; rowX >= aFirstRowIndex; rowX--) {
           if (PRUint32(rowX) < mBCInfo->mRightBorders.Length()) {
             mBCInfo->mRightBorders.RemoveElementAt(rowX);
           }
         }
       }
       break;
     }
-    rowIndex -= cellMap->GetRowCount();
+    rgStartRowIndex += rowCount;
+    rowIndex -= rowCount;
     cellMap = cellMap->GetNextSibling();
   }
 #ifdef DEBUG_TABLE_CELLMAP
   Dump("after RemoveRows");
 #endif
 }
 
 
@@ -556,51 +577,55 @@ nsTableCellMap::AppendCell(nsTableCellFr
   NS_ASSERTION(&aCellFrame == aCellFrame.GetFirstInFlow(), "invalid call on continuing frame");
   nsIFrame* rgFrame = aCellFrame.GetParent(); // get the row
   if (!rgFrame) return 0;
   rgFrame = rgFrame->GetParent();   // get the row group
   if (!rgFrame) return 0;
 
   CellData* result = nsnull;
   PRInt32 rowIndex = aRowIndex;
+  PRInt32 rgStartRowIndex = 0;
   nsCellMap* cellMap = mFirstMap;
   while (cellMap) {
     if (cellMap->GetRowGroup() == rgFrame) {
-      result = cellMap->AppendCell(*this, &aCellFrame, rowIndex, aRebuildIfNecessary, aDamageArea);
-      nsTableRowGroupFrame* rg = cellMap->GetRowGroup();
-      aDamageArea.y += (rg) ? rg->GetStartRowIndex() : 0;
+      result = cellMap->AppendCell(*this, &aCellFrame, rowIndex,
+                                   aRebuildIfNecessary, rgStartRowIndex,
+                                   aDamageArea);
       break;
     }
-    rowIndex -= cellMap->GetRowCount();
+    PRInt32 rowCount = cellMap->GetRowCount();
+    rgStartRowIndex += rowCount;
+    rowIndex -= rowCount;
     cellMap = cellMap->GetNextSibling();
   }
 #ifdef DEBUG_TABLE_CELLMAP
   Dump("after AppendCell");
 #endif
   return result;
 }
 
 
 void
 nsTableCellMap::InsertCells(nsTArray<nsTableCellFrame*>& aCellFrames,
                             PRInt32                      aRowIndex,
                             PRInt32                      aColIndexBefore,
                             nsRect&                      aDamageArea)
 {
   PRInt32 rowIndex = aRowIndex;
+  PRInt32 rgStartRowIndex = 0;
   nsCellMap* cellMap = mFirstMap;
   while (cellMap) {
-    if (cellMap->GetRowCount() > rowIndex) {
-      cellMap->InsertCells(*this, aCellFrames, rowIndex, aColIndexBefore, aDamageArea);
-      nsTableRowGroupFrame* rg = cellMap->GetRowGroup();
-      aDamageArea.y += (rg) ? rg->GetStartRowIndex() : 0;
-      aDamageArea.width = NS_MAX(0, GetColCount() - aColIndexBefore - 1);
+    PRInt32 rowCount = cellMap->GetRowCount();
+    if (rowCount > rowIndex) {
+      cellMap->InsertCells(*this, aCellFrames, rowIndex, aColIndexBefore,
+                           rgStartRowIndex, aDamageArea);
       break;
     }
-    rowIndex -= cellMap->GetRowCount();
+    rgStartRowIndex += rowCount;
+    rowIndex -= rowCount;
     cellMap = cellMap->GetNextSibling();
   }
 #ifdef DEBUG_TABLE_CELLMAP
   Dump("after InsertCells");
 #endif
 }
 
 
@@ -608,72 +633,59 @@ void
 nsTableCellMap::RemoveCell(nsTableCellFrame* aCellFrame,
                            PRInt32           aRowIndex,
                            nsRect&           aDamageArea)
 {
   if (!aCellFrame) ABORT0();
   NS_ASSERTION(aCellFrame == (nsTableCellFrame *)aCellFrame->GetFirstInFlow(),
                "invalid call on continuing frame");
   PRInt32 rowIndex = aRowIndex;
+  PRInt32 rgStartRowIndex = 0;
   nsCellMap* cellMap = mFirstMap;
   while (cellMap) {
-    if (cellMap->GetRowCount() > rowIndex) {
-      cellMap->RemoveCell(*this, aCellFrame, rowIndex, aDamageArea);
-      nsTableRowGroupFrame* rg = cellMap->GetRowGroup();
-      aDamageArea.y += (rg) ? rg->GetStartRowIndex() : 0;
-      PRInt32 colIndex;
-      aCellFrame->GetColIndex(colIndex);
-      aDamageArea.width = NS_MAX(0, GetColCount() - colIndex - 1);
+    PRInt32 rowCount = cellMap->GetRowCount();
+    if (rowCount > rowIndex) {
+      cellMap->RemoveCell(*this, aCellFrame, rowIndex, rgStartRowIndex,
+                          aDamageArea);
 #ifdef DEBUG_TABLE_CELLMAP
       Dump("after RemoveCell");
 #endif
       return;
     }
-    rowIndex -= cellMap->GetRowCount();
+    rgStartRowIndex += rowCount;
+    rowIndex -= rowCount;
     cellMap = cellMap->GetNextSibling();
   }
   // if we reach this point - the cell did not get removed, the caller of this routine
   // will delete the cell and the cellmap will probably hold a reference to
   // the deleted cell which will cause a subsequent crash when this cell is
   // referenced later
   NS_ERROR("nsTableCellMap::RemoveCell - could not remove cell");
 }
 
 void
-SetDamageArea(PRInt32 aXOrigin,
-              PRInt32 aYOrigin,
-              PRInt32 aWidth,
-              PRInt32 aHeight,
-              nsRect& aDamageArea)
-{
-  aDamageArea.x      = aXOrigin;
-  aDamageArea.y      = aYOrigin;
-  aDamageArea.width  = NS_MAX(1, aWidth);
-  aDamageArea.height = NS_MAX(1, aHeight);
-}
-
-void
 nsTableCellMap::RebuildConsideringCells(nsCellMap*                   aCellMap,
                                         nsTArray<nsTableCellFrame*>* aCellFrames,
                                         PRInt32                      aRowIndex,
                                         PRInt32                      aColIndex,
                                         bool                         aInsert,
                                         nsRect&                      aDamageArea)
 {
   PRInt32 numOrigCols = GetColCount();
   ClearCols();
   nsCellMap* cellMap = mFirstMap;
   PRInt32 rowCount = 0;
   while (cellMap) {
     if (cellMap == aCellMap) {
-      cellMap->RebuildConsideringCells(*this, numOrigCols, aCellFrames, aRowIndex, aColIndex, aInsert, aDamageArea);
-
+      cellMap->RebuildConsideringCells(*this, numOrigCols, aCellFrames,
+                                       aRowIndex, aColIndex, aInsert);
     }
     else {
-      cellMap->RebuildConsideringCells(*this, numOrigCols, nsnull, -1, 0, false, aDamageArea);
+      cellMap->RebuildConsideringCells(*this, numOrigCols, nsnull, -1, 0,
+                                       false);
     }
     rowCount += cellMap->GetRowCount();
     cellMap = cellMap->GetNextSibling();
   }
   SetDamageArea(0, 0, GetColCount(), rowCount, aDamageArea);
 }
 
 void
@@ -687,20 +699,22 @@ nsTableCellMap::RebuildConsideringRows(n
                   "Can't handle both removing and inserting rows at once");
 
   PRInt32 numOrigCols = GetColCount();
   ClearCols();
   nsCellMap* cellMap = mFirstMap;
   PRInt32 rowCount = 0;
   while (cellMap) {
     if (cellMap == aCellMap) {
-      cellMap->RebuildConsideringRows(*this, aStartRowIndex, aRowsToInsert, aNumRowsToRemove, aDamageArea);
+      cellMap->RebuildConsideringRows(*this, aStartRowIndex, aRowsToInsert,
+                                      aNumRowsToRemove);
     }
     else {
-      cellMap->RebuildConsideringCells(*this, numOrigCols, nsnull, -1, 0, false, aDamageArea);
+      cellMap->RebuildConsideringCells(*this, numOrigCols, nsnull, -1, 0,
+                                       false);
     }
     rowCount += cellMap->GetRowCount();
     cellMap = cellMap->GetNextSibling();
   }
   SetDamageArea(0, 0, GetColCount(), rowCount, aDamageArea);
 }
 
 PRInt32
@@ -1010,30 +1024,34 @@ nsTableCellMap::SetBCBorderEdge(mozilla:
     for (xIndex = xPos; xIndex <= lastIndex; xIndex++) {
       changed = aChanged && (xIndex == xPos);
       BCData* bcData = nsnull;
       cellData = (BCCellData*)aCellMap.GetDataAt(rgYPos, xIndex);
       if (!cellData) {
         PRInt32 numRgRows = aCellMap.GetRowCount();
         if (yPos < numRgRows) { // add a dead cell data
           nsRect damageArea;
-          cellData = (BCCellData*)aCellMap.AppendCell(*this, nsnull, rgYPos, false, damageArea); if (!cellData) ABORT0();
+          cellData = (BCCellData*)aCellMap.AppendCell(*this, nsnull, rgYPos,
+                                                       false, 0, damageArea);
+          if (!cellData) ABORT0();
         }
         else {
           NS_ASSERTION(aSide == NS_SIDE_BOTTOM, "program error");
           // try the next non empty row group
           nsCellMap* cellMap = aCellMap.GetNextSibling();
           while (cellMap && (0 == cellMap->GetRowCount())) {
             cellMap = cellMap->GetNextSibling();
           }
           if (cellMap) {
             cellData = (BCCellData*)cellMap->GetDataAt(0, xIndex);
             if (!cellData) { // add a dead cell
               nsRect damageArea;
-              cellData = (BCCellData*)cellMap->AppendCell(*this, nsnull, 0, false, damageArea);
+              cellData = (BCCellData*)cellMap->AppendCell(*this, nsnull, 0,
+                                                           false, 0,
+                                                           damageArea);
             }
           }
           else { // must be at the end of the table
             bcData = GetBottomMostBorder(xIndex);
           }
         }
       }
       if (!bcData && cellData) {
@@ -1116,29 +1134,31 @@ nsTableCellMap::SetBCBorderCorner(Corner
     bcData = GetRightMostBorder(yPos);
   }
   else {
     cellData = (BCCellData*)aCellMap.GetDataAt(rgYPos, xPos);
     if (!cellData) {
       PRInt32 numRgRows = aCellMap.GetRowCount();
       if (yPos < numRgRows) { // add a dead cell data
         nsRect damageArea;
-        cellData = (BCCellData*)aCellMap.AppendCell(*this, nsnull, rgYPos, false, damageArea);
+        cellData = (BCCellData*)aCellMap.AppendCell(*this, nsnull, rgYPos,
+                                                     false, 0, damageArea);
       }
       else {
         // try the next non empty row group
         nsCellMap* cellMap = aCellMap.GetNextSibling();
         while (cellMap && (0 == cellMap->GetRowCount())) {
           cellMap = cellMap->GetNextSibling();
         }
         if (cellMap) {
           cellData = (BCCellData*)cellMap->GetDataAt(0, xPos);
           if (!cellData) { // add a dead cell
             nsRect damageArea;
-            cellData = (BCCellData*)cellMap->AppendCell(*this, nsnull, 0, false, damageArea);
+            cellData = (BCCellData*)cellMap->AppendCell(*this, nsnull, 0,
+                                                         false, 0, damageArea);
           }
         }
         else { // must be at the bottom of the table
           bcData = GetBottomMostBorder(xPos);
         }
       }
     }
   }
@@ -1332,101 +1352,105 @@ void nsCellMap::GrowRow(CellDataArray& a
   aRow.InsertElementsAt(aRow.Length(), aNumCols, (CellData*)nsnull);
 }
 
 void
 nsCellMap::InsertRows(nsTableCellMap&             aMap,
                       nsTArray<nsTableRowFrame*>& aRows,
                       PRInt32                     aFirstRowIndex,
                       bool                        aConsiderSpans,
+                      PRInt32                     aRgFirstRowIndex,
                       nsRect&                     aDamageArea)
 {
   PRInt32 numCols = aMap.GetColCount();
   NS_ASSERTION(aFirstRowIndex >= 0, "nsCellMap::InsertRows called with negative rowIndex");
   if (PRUint32(aFirstRowIndex) > mRows.Length()) {
     // create (aFirstRowIndex - mRows.Length()) empty rows up to aFirstRowIndex
     PRInt32 numEmptyRows = aFirstRowIndex - mRows.Length();
     if (!Grow(aMap, numEmptyRows)) {
       return;
     }
   }
 
   if (!aConsiderSpans) {
     // update mContentRowCount, since non-empty rows will be added
     mContentRowCount = NS_MAX(aFirstRowIndex, mContentRowCount);
-    ExpandWithRows(aMap, aRows, aFirstRowIndex, aDamageArea);
+    ExpandWithRows(aMap, aRows, aFirstRowIndex, aRgFirstRowIndex, aDamageArea);
     return;
   }
 
   // if any cells span into or out of the row being inserted, then rebuild
   bool spansCauseRebuild = CellsSpanInOrOut(aFirstRowIndex,
                                               aFirstRowIndex, 0, numCols - 1);
 
   // update mContentRowCount, since non-empty rows will be added
   mContentRowCount = NS_MAX(aFirstRowIndex, mContentRowCount);
 
   // if any of the new cells span out of the new rows being added, then rebuild
   // XXX it would be better to only rebuild the portion of the map that follows the new rows
   if (!spansCauseRebuild && (PRUint32(aFirstRowIndex) < mRows.Length())) {
     spansCauseRebuild = CellsSpanOut(aRows);
   }
-
   if (spansCauseRebuild) {
     aMap.RebuildConsideringRows(this, aFirstRowIndex, &aRows, 0, aDamageArea);
   }
   else {
-    ExpandWithRows(aMap, aRows, aFirstRowIndex, aDamageArea);
+    ExpandWithRows(aMap, aRows, aFirstRowIndex, aRgFirstRowIndex, aDamageArea);
   }
 }
 
 void
 nsCellMap::RemoveRows(nsTableCellMap& aMap,
                       PRInt32         aFirstRowIndex,
                       PRInt32         aNumRowsToRemove,
                       bool            aConsiderSpans,
+                      PRInt32         aRgFirstRowIndex,
                       nsRect&         aDamageArea)
 {
   PRInt32 numRows = mRows.Length();
   PRInt32 numCols = aMap.GetColCount();
 
   if (aFirstRowIndex >= numRows) {
     // reduce the content based row count based on the function arguments
     // as they are known to be real rows even if the cell map did not create
     // rows for them before.
     mContentRowCount -= aNumRowsToRemove;
     return;
   }
   if (!aConsiderSpans) {
-    ShrinkWithoutRows(aMap, aFirstRowIndex, aNumRowsToRemove, aDamageArea);
+    ShrinkWithoutRows(aMap, aFirstRowIndex, aNumRowsToRemove, aRgFirstRowIndex,
+                      aDamageArea);
     return;
   }
   PRInt32 endRowIndex = aFirstRowIndex + aNumRowsToRemove - 1;
   if (endRowIndex >= numRows) {
     NS_ERROR("nsCellMap::RemoveRows tried to remove too many rows");
     endRowIndex = numRows - 1;
   }
   bool spansCauseRebuild = CellsSpanInOrOut(aFirstRowIndex, endRowIndex,
                                               0, numCols - 1);
-
   if (spansCauseRebuild) {
-    aMap.RebuildConsideringRows(this, aFirstRowIndex, nsnull, aNumRowsToRemove, aDamageArea);
+    aMap.RebuildConsideringRows(this, aFirstRowIndex, nsnull, aNumRowsToRemove,
+                                aDamageArea);
   }
   else {
-    ShrinkWithoutRows(aMap, aFirstRowIndex, aNumRowsToRemove, aDamageArea);
+    ShrinkWithoutRows(aMap, aFirstRowIndex, aNumRowsToRemove, aRgFirstRowIndex,
+                      aDamageArea);
   }
 }
 
 
 
 
 CellData*
 nsCellMap::AppendCell(nsTableCellMap&   aMap,
                       nsTableCellFrame* aCellFrame,
                       PRInt32           aRowIndex,
                       bool              aRebuildIfNecessary,
+                      PRInt32           aRgFirstRowIndex,
                       nsRect&           aDamageArea,
                       PRInt32*          aColToBeginSearch)
 {
   NS_ASSERTION(!!aMap.mBCInfo == mIsBC, "BC state mismatch");
   PRInt32 origNumMapRows = mRows.Length();
   PRInt32 origNumCols = aMap.GetColCount();
   bool    zeroRowSpan = false;
   PRInt32 rowSpan = (aCellFrame) ? GetRowSpanForNewCell(aCellFrame, aRowIndex,
@@ -1509,17 +1533,25 @@ nsCellMap::AppendCell(nsTableCellMap&   
     }
   }
   else {
     origData = AllocCellData(aCellFrame);
     if (!origData) ABORT1(origData);
     SetDataAt(aMap, *origData, aRowIndex, startColIndex);
   }
 
-  SetDamageArea(startColIndex, aRowIndex, 1 + endColIndex - startColIndex, 1 + endRowIndex - aRowIndex, aDamageArea);
+  if (aRebuildIfNecessary) {
+    //the caller depends on the damageArea
+    // The special case for zeroRowSpan is to adjust for the '2' in
+    // GetRowSpanForNewCell.
+    PRUint32 height = zeroRowSpan ? endRowIndex - aRowIndex  :
+                                    1 + endRowIndex - aRowIndex;
+    SetDamageArea(startColIndex, aRgFirstRowIndex + aRowIndex,
+                  1 + endColIndex - startColIndex, height, aDamageArea);
+  }
 
   if (!aCellFrame) {
     return origData;
   }
 
   // initialize the cell frame
   aCellFrame->SetColIndex(startColIndex);
 
@@ -1718,16 +1750,17 @@ bool nsCellMap::CellsSpanInOrOut(PRInt32
   }
   return false;
 }
 
 void nsCellMap::InsertCells(nsTableCellMap&              aMap,
                             nsTArray<nsTableCellFrame*>& aCellFrames,
                             PRInt32                      aRowIndex,
                             PRInt32                      aColIndexBefore,
+                            PRInt32                      aRgFirstRowIndex,
                             nsRect&                      aDamageArea)
 {
   if (aCellFrames.Length() == 0) return;
   NS_ASSERTION(aColIndexBefore >= -1, "index out of range");
   PRInt32 numCols = aMap.GetColCount();
   if (aColIndexBefore >= numCols) {
     NS_ERROR("Inserting instead of appending cells indicates a serious cellmap error");
     aColIndexBefore = numCols - 1;
@@ -1774,29 +1807,31 @@ void nsCellMap::InsertCells(nsTableCellM
       spansCauseRebuild = true;
     }
   }
 
   if (!spansCauseRebuild) {
     spansCauseRebuild = CellsSpanInOrOut(aRowIndex, aRowIndex + rowSpan - 1,
                                          startColIndex, numCols - 1);
   }
-
   if (spansCauseRebuild) {
-    aMap.RebuildConsideringCells(this, &aCellFrames, aRowIndex, startColIndex, true, aDamageArea);
+    aMap.RebuildConsideringCells(this, &aCellFrames, aRowIndex, startColIndex,
+                                 true, aDamageArea);
   }
   else {
-    ExpandWithCells(aMap, aCellFrames, aRowIndex, startColIndex, rowSpan, zeroRowSpan, aDamageArea);
+    ExpandWithCells(aMap, aCellFrames, aRowIndex, startColIndex, rowSpan,
+                    zeroRowSpan, aRgFirstRowIndex, aDamageArea);
   }
 }
 
 void
 nsCellMap::ExpandWithRows(nsTableCellMap&             aMap,
                           nsTArray<nsTableRowFrame*>& aRowFrames,
                           PRInt32                     aStartRowIndexIn,
+                          PRInt32                     aRgFirstRowIndex,
                           nsRect&                     aDamageArea)
 {
   PRInt32 startRowIndex = (aStartRowIndexIn >= 0) ? aStartRowIndexIn : 0;
   NS_ASSERTION(PRUint32(startRowIndex) <= mRows.Length(), "caller should have grown cellmap before");
 
   PRInt32 numNewRows  = aRowFrames.Length();
   mContentRowCount += numNewRows;
 
@@ -1813,32 +1848,34 @@ nsCellMap::ExpandWithRows(nsTableCellMap
   for (PRInt32 rowX = startRowIndex; rowX <= endRowIndex; rowX++) {
     nsTableRowFrame* rFrame = aRowFrames.ElementAt(newRowIndex);
     // append cells
     nsIFrame* cFrame = rFrame->GetFirstPrincipalChild();
     PRInt32 colIndex = 0;
     while (cFrame) {
       nsTableCellFrame *cellFrame = do_QueryFrame(cFrame);
       if (cellFrame) {
-        AppendCell(aMap, cellFrame, rowX, false, aDamageArea, &colIndex);
+        AppendCell(aMap, cellFrame, rowX, false, aRgFirstRowIndex, aDamageArea,
+                   &colIndex);
       }
       cFrame = cFrame->GetNextSibling();
     }
     newRowIndex++;
   }
-
-  SetDamageArea(0, startRowIndex, aMap.GetColCount(), 1 + endRowIndex - startRowIndex, aDamageArea);
+  SetDamageArea(0, aRgFirstRowIndex + startRowIndex, aMap.GetColCount(),
+                1 + endRowIndex - startRowIndex, aDamageArea);
 }
 
 void nsCellMap::ExpandWithCells(nsTableCellMap&              aMap,
                                 nsTArray<nsTableCellFrame*>& aCellFrames,
                                 PRInt32                      aRowIndex,
                                 PRInt32                      aColIndex,
                                 PRInt32                      aRowSpan, // same for all cells
                                 bool                         aRowSpanIsZero,
+                                PRInt32                      aRgFirstRowIndex,
                                 nsRect&                      aDamageArea)
 {
   NS_ASSERTION(!!aMap.mBCInfo == mIsBC, "BC state mismatch");
   PRInt32 endRowIndex = aRowIndex + aRowSpan - 1;
   PRInt32 startColIndex = aColIndex;
   PRInt32 endColIndex = aColIndex;
   PRInt32 numCells = aCellFrames.Length();
   PRInt32 totalColSpan = 0;
@@ -1903,18 +1940,20 @@ void nsCellMap::ExpandWithCells(nsTableC
             }
           }
         }
         SetDataAt(aMap, *data, rowX, colX);
       }
     }
     cellFrame->SetColIndex(startColIndex);
   }
-  PRInt32 damageHeight = NS_MIN(GetRowGroup()->GetRowCount() - aRowIndex, aRowSpan);
-  SetDamageArea(aColIndex, aRowIndex, 1 + endColIndex - aColIndex, damageHeight, aDamageArea);
+  PRInt32 damageHeight = NS_MIN(GetRowGroup()->GetRowCount() - aRowIndex,
+                                aRowSpan);
+  SetDamageArea(aColIndex, aRgFirstRowIndex + aRowIndex,
+                1 + endColIndex - aColIndex, damageHeight, aDamageArea);
 
   PRInt32 rowX;
 
   // update the row and col info due to shifting
   for (rowX = aRowIndex; rowX <= endRowIndex; rowX++) {
     CellDataArray& row = mRows[rowX];
     PRUint32 numCols = row.Length();
     PRUint32 colX;
@@ -1946,16 +1985,17 @@ void nsCellMap::ExpandWithCells(nsTableC
       }
     }
   }
 }
 
 void nsCellMap::ShrinkWithoutRows(nsTableCellMap& aMap,
                                   PRInt32         aStartRowIndex,
                                   PRInt32         aNumRowsToRemove,
+                                  PRInt32         aRgFirstRowIndex,
                                   nsRect&         aDamageArea)
 {
   NS_ASSERTION(!!aMap.mBCInfo == mIsBC, "BC state mismatch");
   PRInt32 endRowIndex = aStartRowIndex + aNumRowsToRemove - 1;
   PRUint32 colCount = aMap.GetColCount();
   for (PRInt32 rowX = endRowIndex; rowX >= aStartRowIndex; --rowX) {
     CellDataArray& row = mRows[rowX];
     PRUint32 colX;
@@ -1983,18 +2023,18 @@ void nsCellMap::ShrinkWithoutRows(nsTabl
     }
 
     mRows.RemoveElementAt(rowX);
 
     // Decrement our row and next available index counts.
     mContentRowCount--;
   }
   aMap.RemoveColsAtEnd();
-
-  SetDamageArea(0, aStartRowIndex, aMap.GetColCount(), 0, aDamageArea);
+  SetDamageArea(0, aRgFirstRowIndex + aStartRowIndex, aMap.GetColCount(), 0,
+                aDamageArea);
 }
 
 PRInt32 nsCellMap::GetColSpanForNewCell(nsTableCellFrame& aCellFrameToAdd,
                                         bool&           aIsZeroColSpan) const
 {
   aIsZeroColSpan = false;
   PRInt32 colSpan = aCellFrameToAdd.GetColSpan();
   if (0 == colSpan) {
@@ -2122,30 +2162,32 @@ PRInt32 nsCellMap::GetRowSpan(PRInt32  a
   }
   return rowSpan;
 }
 
 void nsCellMap::ShrinkWithoutCell(nsTableCellMap&   aMap,
                                   nsTableCellFrame& aCellFrame,
                                   PRInt32           aRowIndex,
                                   PRInt32           aColIndex,
+                                  PRInt32           aRgFirstRowIndex,
                                   nsRect&           aDamageArea)
 {
   NS_ASSERTION(!!aMap.mBCInfo == mIsBC, "BC state mismatch");
   PRUint32 colX, rowX;
 
   // get the rowspan and colspan from the cell map since the content may have changed
   bool zeroColSpan;
   PRUint32 numCols = aMap.GetColCount();
   PRInt32 rowSpan = GetRowSpan(aRowIndex, aColIndex, false);
   PRUint32 colSpan = GetEffectiveColSpan(aMap, aRowIndex, aColIndex, zeroColSpan);
   PRUint32 endRowIndex = aRowIndex + rowSpan - 1;
   PRUint32 endColIndex = aColIndex + colSpan - 1;
-
-  SetDamageArea(aColIndex, aRowIndex, 1 + endColIndex - aColIndex, 1 + endRowIndex - aRowIndex, aDamageArea);
+  SetDamageArea(aColIndex, aRgFirstRowIndex + aRowIndex,
+                NS_MAX(0, aMap.GetColCount() - aColIndex - 1),
+                1 + endRowIndex - aRowIndex, aDamageArea);
 
   if (aMap.mTableFrame.HasZeroColSpans()) {
     aMap.mTableFrame.SetNeedColSpanExpansion(true);
   }
 
   // adjust the col counts due to the deleted cell before removing it
   for (colX = aColIndex; colX <= endColIndex; colX++) {
     nsColInfo* colInfo = aMap.GetColInfoAt(colX);
@@ -2212,18 +2254,17 @@ void nsCellMap::ShrinkWithoutCell(nsTabl
   }
   aMap.RemoveColsAtEnd();
 }
 
 void
 nsCellMap::RebuildConsideringRows(nsTableCellMap&             aMap,
                                   PRInt32                     aStartRowIndex,
                                   nsTArray<nsTableRowFrame*>* aRowsToInsert,
-                                  PRInt32                     aNumRowsToRemove,
-                                  nsRect&                     aDamageArea)
+                                  PRInt32                     aNumRowsToRemove)
 {
   NS_ASSERTION(!!aMap.mBCInfo == mIsBC, "BC state mismatch");
   // copy the old cell map into a new array
   PRUint32 numOrigRows = mRows.Length();
   nsTArray<CellDataArray> origRows;
   mRows.SwapElements(origRows);
 
   PRInt32 rowNumberChange;
@@ -2247,45 +2288,45 @@ nsCellMap::RebuildConsideringRows(nsTabl
 
   // aStartRowIndex might be after all existing rows so we should limit the
   // copy to the amount of exisiting rows
   PRUint32 copyEndRowIndex = NS_MIN(numOrigRows, PRUint32(aStartRowIndex));
 
   // rowX keeps track of where we are in mRows while setting up the
   // new cellmap.
   PRUint32 rowX = 0;
-
+  nsRect damageArea;
   // put back the rows before the affected ones just as before.  Note that we
   // can't just copy the old rows in bit-for-bit, because they might be
   // spanning out into the rows we're adding/removing.
   for ( ; rowX < copyEndRowIndex; rowX++) {
     const CellDataArray& row = origRows[rowX];
     PRUint32 numCols = row.Length();
     for (PRUint32 colX = 0; colX < numCols; colX++) {
       // put in the original cell from the cell map
       const CellData* data = row.ElementAt(colX);
       if (data && data->IsOrig()) {
-        AppendCell(aMap, data->GetCellFrame(), rowX, false, aDamageArea);
+        AppendCell(aMap, data->GetCellFrame(), rowX, false, 0, damageArea);
       }
     }
   }
 
   // Now handle the new rows being inserted, if any.
   PRUint32 copyStartRowIndex;
   rowX = aStartRowIndex;
   if (aRowsToInsert) {
     // add in the new cells and create rows if necessary
     PRInt32 numNewRows = aRowsToInsert->Length();
     for (PRInt32 newRowX = 0; newRowX < numNewRows; newRowX++) {
       nsTableRowFrame* rFrame = aRowsToInsert->ElementAt(newRowX);
       nsIFrame* cFrame = rFrame->GetFirstPrincipalChild();
       while (cFrame) {
         nsTableCellFrame *cellFrame = do_QueryFrame(cFrame);
         if (cellFrame) {
-          AppendCell(aMap, cellFrame, rowX, false, aDamageArea);
+          AppendCell(aMap, cellFrame, rowX, false, 0, damageArea);
         }
         cFrame = cFrame->GetNextSibling();
       }
       rowX++;
     }
     copyStartRowIndex = aStartRowIndex;
   }
   else {
@@ -2298,87 +2339,85 @@ nsCellMap::RebuildConsideringRows(nsTabl
   for (PRUint32 copyRowX = copyStartRowIndex; copyRowX < numOrigRows;
        copyRowX++) {
     const CellDataArray& row = origRows[copyRowX];
     PRUint32 numCols = row.Length();
     for (PRUint32 colX = 0; colX < numCols; colX++) {
       // put in the original cell from the cell map
       CellData* data = row.ElementAt(colX);
       if (data && data->IsOrig()) {
-        AppendCell(aMap, data->GetCellFrame(), rowX, false, aDamageArea);
+        AppendCell(aMap, data->GetCellFrame(), rowX, false, 0, damageArea);
       }
     }
     rowX++;
   }
 
   // delete the old cell map.  Now rowX no longer has anything to do with mRows
   for (rowX = 0; rowX < numOrigRows; rowX++) {
     CellDataArray& row = origRows[rowX];
     PRUint32 len = row.Length();
     for (PRUint32 colX = 0; colX < len; colX++) {
       DestroyCellData(row[colX]);
     }
   }
-
-  SetDamageArea(0, 0, aMap.GetColCount(), GetRowCount(), aDamageArea);
 }
 
 void
 nsCellMap::RebuildConsideringCells(nsTableCellMap&              aMap,
                                    PRInt32                      aNumOrigCols,
                                    nsTArray<nsTableCellFrame*>* aCellFrames,
                                    PRInt32                      aRowIndex,
                                    PRInt32                      aColIndex,
-                                   bool                         aInsert,
-                                   nsRect&                      aDamageArea)
+                                   bool                         aInsert)
 {
   NS_ASSERTION(!!aMap.mBCInfo == mIsBC, "BC state mismatch");
   // copy the old cell map into a new array
   PRInt32 numOrigRows  = mRows.Length();
   nsTArray<CellDataArray> origRows;
   mRows.SwapElements(origRows);
 
   PRInt32 numNewCells = (aCellFrames) ? aCellFrames->Length() : 0;
 
   // the new cells might extend the previous column number
   NS_ASSERTION(aNumOrigCols >= aColIndex, "Appending cells far beyond cellmap data?!");
   PRInt32 numCols = aInsert ? NS_MAX(aNumOrigCols, aColIndex + 1) : aNumOrigCols;
 
   // build the new cell map.  Hard to say what, if anything, we can preallocate
   // here...  Should come back to that sometime, perhaps.
   PRInt32 rowX;
+  nsRect damageArea;
   for (rowX = 0; rowX < numOrigRows; rowX++) {
     const CellDataArray& row = origRows[rowX];
     for (PRInt32 colX = 0; colX < numCols; colX++) {
       if ((rowX == aRowIndex) && (colX == aColIndex)) {
         if (aInsert) { // put in the new cells
           for (PRInt32 cellX = 0; cellX < numNewCells; cellX++) {
             nsTableCellFrame* cell = aCellFrames->ElementAt(cellX);
             if (cell) {
-              AppendCell(aMap, cell, rowX, false, aDamageArea);
+              AppendCell(aMap, cell, rowX, false, 0, damageArea);
             }
           }
         }
         else {
           continue; // do not put the deleted cell back
         }
       }
       // put in the original cell from the cell map
       CellData* data = row.SafeElementAt(colX);
       if (data && data->IsOrig()) {
-        AppendCell(aMap, data->GetCellFrame(), rowX, false, aDamageArea);
+        AppendCell(aMap, data->GetCellFrame(), rowX, false, 0, damageArea);
       }
     }
   }
   if (aInsert && numOrigRows <= aRowIndex) { // append the new cells below the last original row
     NS_ASSERTION (numOrigRows == aRowIndex, "Appending cells far beyond the last row");
     for (PRInt32 cellX = 0; cellX < numNewCells; cellX++) {
       nsTableCellFrame* cell = aCellFrames->ElementAt(cellX);
       if (cell) {
-        AppendCell(aMap, cell, aRowIndex, false, aDamageArea);
+        AppendCell(aMap, cell, aRowIndex, false, 0, damageArea);
       }
     }
   }
 
   // delete the old cell map
   for (rowX = 0; rowX < numOrigRows; rowX++) {
     CellDataArray& row = origRows[rowX];
     PRUint32 len = row.Length();
@@ -2391,16 +2430,17 @@ nsCellMap::RebuildConsideringCells(nsTab
     Grow(aMap, mContentRowCount - mRows.Length());
   }
 
 }
 
 void nsCellMap::RemoveCell(nsTableCellMap&   aMap,
                            nsTableCellFrame* aCellFrame,
                            PRInt32           aRowIndex,
+                           PRInt32           aRgFirstRowIndex,
                            nsRect&           aDamageArea)
 {
   PRUint32 numRows = mRows.Length();
   if (PRUint32(aRowIndex) >= numRows) {
     NS_ERROR("bad arg in nsCellMap::RemoveCell");
     return;
   }
   PRInt32 numCols = aMap.GetColCount();
@@ -2424,20 +2464,22 @@ void nsCellMap::RemoveCell(nsTableCellMa
                                               startColIndex, numCols - 1);
   // XXX if the cell has a col span to the end of the map, and the end has no originating
   // cells, we need to assume that this the only such cell, and rebuild so that there are
   // no extraneous cols at the end. The same is true for removing rows.
   if (!aCellFrame->GetRowSpan() || !aCellFrame->GetColSpan())
     spansCauseRebuild = true;
 
   if (spansCauseRebuild) {
-    aMap.RebuildConsideringCells(this, nsnull, aRowIndex, startColIndex, false, aDamageArea);
+    aMap.RebuildConsideringCells(this, nsnull, aRowIndex, startColIndex, false,
+                                 aDamageArea);
   }
   else {
-    ShrinkWithoutCell(aMap, *aCellFrame, aRowIndex, startColIndex, aDamageArea);
+    ShrinkWithoutCell(aMap, *aCellFrame, aRowIndex, startColIndex,
+                      aRgFirstRowIndex, aDamageArea);
   }
 }
 
 void nsCellMap::ExpandZeroColSpans(nsTableCellMap& aMap)
 {
   NS_ASSERTION(!!aMap.mBCInfo == mIsBC, "BC state mismatch");
   PRUint32 numRows = mRows.Length();
   PRUint32 numCols = aMap.GetColCount();
--- a/layout/tables/nsCellMap.h
+++ b/layout/tables/nsCellMap.h
@@ -373,16 +373,17 @@ public:
     *                             row should start
     * @return                   - a pointer to the celldata entry inserted into
     *                             the cellmap
     */
   CellData* AppendCell(nsTableCellMap&   aMap,
                        nsTableCellFrame* aCellFrame,
                        PRInt32           aRowIndex,
                        bool              aRebuildIfNecessary,
+                       PRInt32           aRgFirstRowIndex,
                        nsRect&           aDamageArea,
                        PRInt32*          aBeginSearchAtCol = nsnull);
 
   /** Function to be called when a cell is added at a location which is spanned
     * to by a zero colspan.  We handle this situation by collapsing the zero
     * colspan, since there is really no good way to deal with it (trying to
     * increase the number of columns to hold the new cell would just mean the
     * zero colspan needs to expand).
@@ -396,33 +397,37 @@ public:
                            CellData*       aOrigData,
                            PRInt32         aRowIndex,
                            PRInt32         aColIndex);
 
   void InsertCells(nsTableCellMap&              aMap,
                    nsTArray<nsTableCellFrame*>& aCellFrames,
                    PRInt32                      aRowIndex,
                    PRInt32                      aColIndexBefore,
+                   PRInt32                      aRgFirstRowIndex,
                    nsRect&                      aDamageArea);
 
   void RemoveCell(nsTableCellMap&   aMap,
                   nsTableCellFrame* aCellFrame,
                   PRInt32           aRowIndex,
+                  PRInt32           aRgFirstRowIndex,
                   nsRect&           aDamageArea);
 
   void InsertRows(nsTableCellMap&             aMap,
                   nsTArray<nsTableRowFrame*>& aRows,
                   PRInt32                     aFirstRowIndex,
                   bool                        aConsiderSpans,
+                  PRInt32                     aRgFirstRowIndex,
                   nsRect&                     aDamageArea);
 
   void RemoveRows(nsTableCellMap& aMap,
                   PRInt32         aFirstRowIndex,
                   PRInt32         aNumRowsToRemove,
                   bool            aConsiderSpans,
+                  PRInt32         aRgFirstRowIndex,
                   nsRect&         aDamageArea);
 
   PRInt32 GetNumCellsOriginatingInRow(PRInt32 aRowIndex) const;
   PRInt32 GetNumCellsOriginatingInCol(PRInt32 aColIndex) const;
 
   /** return the number of rows in the table represented by this CellMap */
   PRInt32 GetRowCount(bool aConsiderDeadRowSpanRows = false) const;
 
@@ -494,58 +499,60 @@ protected:
   CellData* GetDataAt(PRInt32         aMapRowIndex,
                       PRInt32         aColIndex) const;
 
   PRInt32 GetNumCellsIn(PRInt32 aColIndex) const;
 
   void ExpandWithRows(nsTableCellMap&             aMap,
                       nsTArray<nsTableRowFrame*>& aRowFrames,
                       PRInt32                     aStartRowIndex,
+                      PRInt32                     aRgFirstRowIndex,
                       nsRect&                     aDamageArea);
 
   void ExpandWithCells(nsTableCellMap&              aMap,
                        nsTArray<nsTableCellFrame*>& aCellFrames,
                        PRInt32                      aRowIndex,
                        PRInt32                      aColIndex,
                        PRInt32                      aRowSpan,
                        bool                         aRowSpanIsZero,
+                       PRInt32                      aRgFirstRowIndex,
                        nsRect&                      aDamageArea);
 
   void ShrinkWithoutRows(nsTableCellMap& aMap,
                          PRInt32         aFirstRowIndex,
                          PRInt32         aNumRowsToRemove,
+                         PRInt32         aRgFirstRowIndex,
                          nsRect&         aDamageArea);
 
   void ShrinkWithoutCell(nsTableCellMap&   aMap,
                          nsTableCellFrame& aCellFrame,
                          PRInt32           aRowIndex,
                          PRInt32           aColIndex,
+                         PRInt32           aRgFirstRowIndex,
                          nsRect&           aDamageArea);
 
   /**
    * Rebuild due to rows being inserted or deleted with cells spanning
    * into or out of the rows.  This function can only handle insertion
    * or deletion but NOT both.  So either aRowsToInsert must be null
    * or aNumRowsToRemove must be 0.
    *
    * // XXXbz are both allowed to happen?  That'd be a no-op...
    */
   void RebuildConsideringRows(nsTableCellMap&             aMap,
                               PRInt32                     aStartRowIndex,
                               nsTArray<nsTableRowFrame*>* aRowsToInsert,
-                              PRInt32                     aNumRowsToRemove,
-                              nsRect&                     aDamageArea);
+                              PRInt32                     aNumRowsToRemove);
 
   void RebuildConsideringCells(nsTableCellMap&              aMap,
                                PRInt32                      aNumOrigCols,
                                nsTArray<nsTableCellFrame*>* aCellFrames,
                                PRInt32                      aRowIndex,
                                PRInt32                      aColIndex,
-                               bool                         aInsert,
-                               nsRect&                      aDamageArea);
+                               bool                         aInsert);
 
   bool CellsSpanOut(nsTArray<nsTableRowFrame*>& aNewRows) const;
 
   /** If a cell spans out of the area defined by aStartRowIndex, aEndRowIndex
     * and aStartColIndex, aEndColIndex the cellmap changes are more severe so
     * the corresponding routines needs to be called. This is also necessary if
     * cells outside spans into this region.
     * @aStartRowIndex       - y start index
--- a/layout/tables/nsTableCellFrame.cpp
+++ b/layout/tables/nsTableCellFrame.cpp
@@ -251,17 +251,17 @@ nsTableCellFrame::DidSetStyleContext(nsS
   nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
 
   if (tableFrame->IsBorderCollapse() &&
       tableFrame->BCRecalcNeeded(aOldStyleContext, GetStyleContext())) {
     PRInt32 colIndex, rowIndex;
     GetColIndex(colIndex);
     GetRowIndex(rowIndex);
     nsRect damageArea(colIndex, rowIndex, GetColSpan(), GetRowSpan());
-    tableFrame->SetBCDamageArea(damageArea);
+    tableFrame->AddBCDamageArea(damageArea);
   }
 }
 
 
 NS_IMETHODIMP
 nsTableCellFrame::AppendFrames(ChildListID     aListID,
                                nsFrameList&    aFrameList)
 {
--- a/layout/tables/nsTableColFrame.cpp
+++ b/layout/tables/nsTableColFrame.cpp
@@ -89,17 +89,17 @@ nsTableColFrame::DidSetStyleContext(nsSt
   if (!aOldStyleContext) //avoid this on init
     return;
      
   nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
     
   if (tableFrame->IsBorderCollapse() &&
       tableFrame->BCRecalcNeeded(aOldStyleContext, GetStyleContext())) {
     nsRect damageArea = nsRect(GetColIndex(), 0, 1, tableFrame->GetRowCount());
-    tableFrame->SetBCDamageArea(damageArea);
+    tableFrame->AddBCDamageArea(damageArea);
   }
   return;
 }
 
 void nsTableColFrame::SetContinuousBCBorderWidth(PRUint8     aForSide,
                                                  BCPixelSize aPixelValue)
 {
   switch (aForSide) {
--- a/layout/tables/nsTableColGroupFrame.cpp
+++ b/layout/tables/nsTableColGroupFrame.cpp
@@ -200,17 +200,17 @@ nsTableColGroupFrame::DidSetStyleContext
 
   if (tableFrame->IsBorderCollapse() &&
       tableFrame->BCRecalcNeeded(aOldStyleContext, GetStyleContext())) {
     PRInt32 colCount = GetColCount();
     if (!colCount)
       return; // this is a degenerated colgroup 
     nsRect damageArea(GetFirstColumn()->GetColIndex(), 0, colCount,
                       tableFrame->GetRowCount());
-    tableFrame->SetBCDamageArea(damageArea);
+    tableFrame->AddBCDamageArea(damageArea);
   }
   return;
 }
 
 NS_IMETHODIMP
 nsTableColGroupFrame::AppendFrames(ChildListID     aListID,
                                    nsFrameList&    aFrameList)
 {
--- a/layout/tables/nsTableFrame.cpp
+++ b/layout/tables/nsTableFrame.cpp
@@ -143,21 +143,20 @@ struct nsTableReflowState {
 };
 
 /********************************************************************************
  ** nsTableFrame                                                               **
  ********************************************************************************/
 
 struct BCPropertyData
 {
-  BCPropertyData() { mDamageArea.x = mDamageArea.y = mDamageArea.width =
-                     mDamageArea.height = mTopBorderWidth = mRightBorderWidth =
-                     mBottomBorderWidth = mLeftBorderWidth =
-                     mLeftCellBorderWidth = mRightCellBorderWidth = 0; }
-  nsRect  mDamageArea;
+  BCPropertyData() : mTopBorderWidth(0), mRightBorderWidth(0),
+                     mBottomBorderWidth(0), mLeftBorderWidth(0),
+                     mLeftCellBorderWidth(0), mRightCellBorderWidth(0) {}
+  nsRect mDamageArea;
   BCPixelSize mTopBorderWidth;
   BCPixelSize mRightBorderWidth;
   BCPixelSize mBottomBorderWidth;
   BCPixelSize mLeftBorderWidth;
   BCPixelSize mLeftCellBorderWidth;
   BCPixelSize mRightCellBorderWidth;
 };
 
@@ -346,18 +345,17 @@ nsTableFrame::SetInitialChildList(ChildL
   // so don't treat this like an append
   if (!GetPrevInFlow()) {
     // process col groups first so that real cols get constructed before
     // anonymous ones due to cells in rows.
     InsertColGroups(0, mColGroups);
     InsertRowGroups(mFrames);
     // calc collapsing borders
     if (IsBorderCollapse()) {
-      nsRect damageArea(0, 0, GetColCount(), GetRowCount());
-      SetBCDamageArea(damageArea);
+      SetFullBCDamageArea();
     }
   }
 
   return NS_OK;
 }
 
 void nsTableFrame::AttributeChangedFor(nsIFrame*       aFrame,
                                        nsIContent*     aContent,
@@ -599,18 +597,18 @@ void nsTableFrame::InsertCol(nsTableColF
       }
       if (!removedFromCache) {
         cellMap->AddColsAtEnd(1);
       }
     }
   }
   // for now, just bail and recalc all of the collapsing borders
   if (IsBorderCollapse()) {
-    nsRect damageArea(0, 0, NS_MAX(1, GetColCount()), NS_MAX(1, GetRowCount()));
-    SetBCDamageArea(damageArea);
+    nsRect damageArea(aColIndex, 0, 1, GetRowCount());
+    AddBCDamageArea(damageArea);
   }
 }
 
 void nsTableFrame::RemoveCol(nsTableColGroupFrame* aColGroupFrame,
                              PRInt32               aColIndex,
                              bool                  aRemoveFromCache,
                              bool                  aRemoveFromCellMap)
 {
@@ -621,17 +619,17 @@ void nsTableFrame::RemoveCol(nsTableColG
     nsTableCellMap* cellMap = GetCellMap();
     if (cellMap) {
       AppendAnonymousColFrames(1);
     }
   }
   // for now, just bail and recalc all of the collapsing borders
   if (IsBorderCollapse()) {
     nsRect damageArea(0, 0, GetColCount(), GetRowCount());
-    SetBCDamageArea(damageArea);
+    AddBCDamageArea(damageArea);
   }
 }
 
 /** Get the cell map for this table frame.  It is not always mCellMap.
   * Only the firstInFlow has a legit cell map
   */
 nsTableCellMap* nsTableFrame::GetCellMap() const
 {
@@ -794,32 +792,32 @@ nsTableFrame::AppendCell(nsTableCellFram
                          PRInt32           aRowIndex)
 {
   nsTableCellMap* cellMap = GetCellMap();
   if (cellMap) {
     nsRect damageArea(0,0,0,0);
     cellMap->AppendCell(aCellFrame, aRowIndex, true, damageArea);
     MatchCellMapToColCache(cellMap);
     if (IsBorderCollapse()) {
-      SetBCDamageArea(damageArea);
+      AddBCDamageArea(damageArea);
     }
   }
 }
 
 void nsTableFrame::InsertCells(nsTArray<nsTableCellFrame*>& aCellFrames,
                                PRInt32                      aRowIndex,
                                PRInt32                      aColIndexBefore)
 {
   nsTableCellMap* cellMap = GetCellMap();
   if (cellMap) {
     nsRect damageArea(0,0,0,0);
     cellMap->InsertCells(aCellFrames, aRowIndex, aColIndexBefore, damageArea);
     MatchCellMapToColCache(cellMap);
     if (IsBorderCollapse()) {
-      SetBCDamageArea(damageArea);
+      AddBCDamageArea(damageArea);
     }
   }
 }
 
 // this removes the frames from the col group and table, but not the cell map
 PRInt32
 nsTableFrame::DestroyAnonymousColFrames(PRInt32 aNumFrames)
 {
@@ -849,17 +847,17 @@ void nsTableFrame::RemoveCell(nsTableCel
                               PRInt32           aRowIndex)
 {
   nsTableCellMap* cellMap = GetCellMap();
   if (cellMap) {
     nsRect damageArea(0,0,0,0);
     cellMap->RemoveCell(aCellFrame, aRowIndex, damageArea);
     MatchCellMapToColCache(cellMap);
     if (IsBorderCollapse()) {
-      SetBCDamageArea(damageArea);
+      AddBCDamageArea(damageArea);
     }
   }
 }
 
 PRInt32
 nsTableFrame::GetStartRowIndex(nsTableRowGroupFrame* aRowGroupFrame)
 {
   RowGroupArray orderedRowGroups;
@@ -914,17 +912,17 @@ nsTableFrame::InsertRows(nsTableRowGroup
     }
     // assign the correct row indices to the new rows. If they were adjusted above
     // it may not have been done correctly because each row is constructed with index 0
     for (PRInt32 rowY = 0; rowY < numNewRows; rowY++) {
       nsTableRowFrame* rowFrame = aRowFrames.ElementAt(rowY);
       rowFrame->SetRowIndex(aRowIndex + rowY);
     }
     if (IsBorderCollapse()) {
-      SetBCDamageArea(damageArea);
+      AddBCDamageArea(damageArea);
     }
   }
 #ifdef DEBUG_TABLE_CELLMAP
   printf("=== insertRowsAfter \n");
   Dump(true, false, true);
 #endif
 
   return numColsToAdd;
@@ -957,17 +955,17 @@ void nsTableFrame::RemoveRows(nsTableRow
   Dump(true, false, true);
 #endif
   nsTableCellMap* cellMap = GetCellMap();
   if (cellMap) {
     nsRect damageArea(0,0,0,0);
     cellMap->RemoveRows(firstRowIndex, aNumRowsToRemove, aConsiderSpans, damageArea);
     MatchCellMapToColCache(cellMap);
     if (IsBorderCollapse()) {
-      SetBCDamageArea(damageArea);
+      AddBCDamageArea(damageArea);
     }
   }
   AdjustRowIndices(firstRowIndex, -aNumRowsToRemove);
 #ifdef DEBUG_TABLE_CELLMAP
   printf("=== removeRowsAfter\n");
   Dump(true, true, true);
 #endif
 }
@@ -2044,18 +2042,17 @@ nsTableFrame::GetCollapsedWidth(nsMargin
 /* virtual */ void
 nsTableFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
 {
    if (!aOldStyleContext) //avoid this on init
      return;
 
    if (IsBorderCollapse() &&
        BCRecalcNeeded(aOldStyleContext, GetStyleContext())) {
-     nsRect damageArea(0, 0, GetColCount(), GetRowCount());
-     SetBCDamageArea(damageArea);
+     SetFullBCDamageArea();
    }
 
    //avoid this on init or nextinflow
    if (!mTableLayoutStrategy || GetPrevInFlow())
      return;
 
    bool isAuto = IsAutoLayout();
    if (isAuto != (LayoutStrategy()->GetType() == nsITableLayoutStrategy::Auto)) {
@@ -2304,18 +2301,17 @@ nsTableFrame::RemoveFrame(ChildListID   
       cellMap->RebuildConsideringCells(nsnull, nsnull, 0, 0, false, damageArea);
 
       MatchCellMapToColCache(cellMap);
     }
   }
   // for now, just bail and recalc all of the collapsing borders
   // as the cellmap changes we need to recalc
   if (IsBorderCollapse()) {
-    nsRect damageArea(0, 0, NS_MAX(1, GetColCount()), NS_MAX(1, GetRowCount()));
-    SetBCDamageArea(damageArea);
+    SetFullBCDamageArea();
   }
   PresContext()->PresShell()->FrameNeedsReflow(this, nsIPresShell::eTreeChange,
                                                NS_FRAME_HAS_DIRTY_CHILDREN);
   SetGeometryDirty();
 #ifdef DEBUG_TABLE_CELLMAP
   printf("=== TableFrame::RemoveFrame\n");
   Dump(true, true, true);
 #endif
@@ -2352,16 +2348,30 @@ nsTableFrame::GetUsedMargin() const
 static void
 DestroyBCProperty(void* aPropertyValue)
 {
   delete static_cast<BCPropertyData*>(aPropertyValue);
 }
 
 NS_DECLARE_FRAME_PROPERTY(TableBCProperty, DestroyBCProperty)
 
+BCPropertyData*
+nsTableFrame::GetBCProperty(bool aCreateIfNecessary) const
+{
+  FrameProperties props = Properties();
+  BCPropertyData* value = static_cast<BCPropertyData*>
+                          (props.Get(TableBCProperty()));
+  if (!value && aCreateIfNecessary) {
+    value = new BCPropertyData();
+    props.Set(TableBCProperty(), value);
+  }
+
+  return value;
+}
+
 static void
 DivideBCBorderSize(BCPixelSize  aPixelSize,
                    BCPixelSize& aSmallHalf,
                    BCPixelSize& aLargeHalf)
 {
   aSmallHalf = aPixelSize / 2;
   aLargeHalf = aPixelSize - aSmallHalf;
 }
@@ -2369,18 +2379,17 @@ DivideBCBorderSize(BCPixelSize  aPixelSi
 nsMargin
 nsTableFrame::GetOuterBCBorder() const
 {
   if (NeedToCalcBCBorders())
     const_cast<nsTableFrame*>(this)->CalcBCBorders();
 
   nsMargin border(0, 0, 0, 0);
   PRInt32 p2t = nsPresContext::AppUnitsPerCSSPixel();
-  BCPropertyData* propData = static_cast<BCPropertyData*>
-    (Properties().Get(TableBCProperty()));
+  BCPropertyData* propData = GetBCProperty();
   if (propData) {
     border.top    = BC_BORDER_TOP_HALF_COORD(p2t, propData->mTopBorderWidth);
     border.right  = BC_BORDER_RIGHT_HALF_COORD(p2t, propData->mRightBorderWidth);
     border.bottom = BC_BORDER_BOTTOM_HALF_COORD(p2t, propData->mBottomBorderWidth);
     border.left   = BC_BORDER_LEFT_HALF_COORD(p2t, propData->mLeftBorderWidth);
   }
   return border;
 }
@@ -2388,18 +2397,17 @@ nsTableFrame::GetOuterBCBorder() const
 nsMargin
 nsTableFrame::GetIncludedOuterBCBorder() const
 {
   if (NeedToCalcBCBorders())
     const_cast<nsTableFrame*>(this)->CalcBCBorders();
 
   nsMargin border(0, 0, 0, 0);
   PRInt32 p2t = nsPresContext::AppUnitsPerCSSPixel();
-  BCPropertyData* propData = static_cast<BCPropertyData*>
-    (Properties().Get(TableBCProperty()));
+  BCPropertyData* propData = GetBCProperty();
   if (propData) {
     border.top += BC_BORDER_TOP_HALF_COORD(p2t, propData->mTopBorderWidth);
     border.right += BC_BORDER_RIGHT_HALF_COORD(p2t, propData->mRightCellBorderWidth);
     border.bottom += BC_BORDER_BOTTOM_HALF_COORD(p2t, propData->mBottomBorderWidth);
     border.left += BC_BORDER_LEFT_HALF_COORD(p2t, propData->mLeftCellBorderWidth);
   }
   return border;
 }
@@ -3762,69 +3770,99 @@ nsTableFrame::ColumnHasCellSpacingBefore
   if (aColIndex == 0)
     return true;
   nsTableCellMap* cellMap = GetCellMap();
   if (!cellMap)
     return false;
   return cellMap->GetNumCellsOriginatingInCol(aColIndex) > 0;
 }
 
-static void
-CheckFixDamageArea(PRInt32 aNumRows,
-                   PRInt32 aNumCols,
-                   nsRect& aDamageArea)
-{
-  if (((aDamageArea.XMost() > aNumCols) && (aDamageArea.width  != 1) && (aNumCols != 0)) ||
-      ((aDamageArea.YMost() > aNumRows) && (aDamageArea.height != 1) && (aNumRows != 0))) {
-    // the damage area was set incorrectly, just be safe and make it the entire table
-    NS_ASSERTION(false, "invalid BC damage area");
-    aDamageArea.x      = 0;
-    aDamageArea.y      = 0;
-    aDamageArea.width  = aNumCols;
-    aDamageArea.height = aNumRows;
-  }
-}
-
 /********************************************************************************
  * Collapsing Borders
  *
  *  The CSS spec says to resolve border conflicts in this order:
  *  1) any border with the style HIDDEN wins
  *  2) the widest border with a style that is not NONE wins
  *  3) the border styles are ranked in this order, highest to lowest precedence:
  *     double, solid, dashed, dotted, ridge, outset, groove, inset
  *  4) borders that are of equal width and style (differ only in color) have this precedence:
  *     cell, row, rowgroup, col, colgroup, table
  *  5) if all border styles are NONE, then that's the computed border style.
  *******************************************************************************/
 
+#ifdef DEBUG
+#define VerifyNonNegativeDamageRect(r)                                  \
+  NS_ASSERTION((r).x >= 0, "negative col index");                       \
+  NS_ASSERTION((r).y >= 0, "negative row index");                       \
+  NS_ASSERTION((r).width >= 0, "negative horizontal damage");           \
+  NS_ASSERTION((r).height >= 0, "negative vertical damage");
+#define VerifyDamageRect(r)                                             \
+  VerifyNonNegativeDamageRect(r);                                       \
+  NS_ASSERTION((r).XMost() <= GetColCount(),                            \
+               "horizontal damage extends outside table");              \
+  NS_ASSERTION((r).YMost() <= GetRowCount(),                            \
+               "vertical damage extends outside table");
+#endif
+
 void
-nsTableFrame::SetBCDamageArea(const nsRect& aValue)
-{
-  nsRect newRect(aValue);
-  newRect.width  = NS_MAX(1, newRect.width);
-  newRect.height = NS_MAX(1, newRect.height);
-
-  if (!IsBorderCollapse()) {
-    NS_ASSERTION(false, "invalid call - not border collapse model");
-    return;
-  }
+nsTableFrame::AddBCDamageArea(const nsRect& aValue)
+{
+  NS_ASSERTION(IsBorderCollapse(), "invalid AddBCDamageArea call");
+#ifdef DEBUG
+  VerifyDamageRect(aValue);
+#endif
+
   SetNeedToCalcBCBorders(true);
   // Get the property
-  FrameProperties props = Properties();
-  BCPropertyData* value = static_cast<BCPropertyData*>
-    (props.Get(TableBCProperty()));
-  if (!value) {
-    value = new BCPropertyData();
-    props.Set(TableBCProperty(), value);
-  }
-  // for now just construct a union of the new and old damage areas
-  value->mDamageArea.UnionRect(value->mDamageArea, newRect);
-  CheckFixDamageArea(GetRowCount(), GetColCount(), value->mDamageArea);
-}
+  BCPropertyData* value = GetBCProperty(true);
+  if (value) {
+#ifdef DEBUG
+    VerifyNonNegativeDamageRect(value->mDamageArea);
+#endif
+    // Clamp the old damage area to the current table area in case it shrunk.
+    PRInt32 cols = GetColCount();
+    if (value->mDamageArea.XMost() > cols) {
+      if (value->mDamageArea.x > cols) {
+        value->mDamageArea.x = cols;
+        value->mDamageArea.width = 0;
+      }
+      else {
+        value->mDamageArea.width = cols - value->mDamageArea.x;
+      }
+    }
+    PRInt32 rows = GetRowCount();
+    if (value->mDamageArea.YMost() > rows) {
+      if (value->mDamageArea.y > rows) {
+        value->mDamageArea.y = rows;
+        value->mDamageArea.height = 0;
+      }
+      else {
+        value->mDamageArea.height = rows - value->mDamageArea.y;
+      }
+    }
+
+    // Construct a union of the new and old damage areas.
+    value->mDamageArea.UnionRect(value->mDamageArea, aValue);
+  }
+}
+
+
+void
+nsTableFrame::SetFullBCDamageArea()
+{
+  NS_ASSERTION(IsBorderCollapse(), "invalid SetFullBCDamageArea call");
+
+  SetNeedToCalcBCBorders(true);
+
+  BCPropertyData* value = GetBCProperty(true);
+  if (value) {
+    value->mDamageArea = nsRect(0, 0, GetColCount(), GetRowCount());
+  }
+}
+
 
 /* BCCellBorder represents a border segment which can be either a horizontal
  * or a vertical segment. For each segment we need to know the color, width,
  * style, who owns it and how long it is in cellmap coordinates.
  * Ownership of these segments is important to calculate which corners should
  * be bevelled. This structure has dual use, its used first to compute the
  * dominant border for horizontal and vertical segments and to store the
  * preliminary computed border results in the BCCellBorders structure.
@@ -4211,17 +4249,19 @@ BCMapCellIterator::SetNewRow(nsTableRowF
     if (PRUint32(rgRowIndex) >= mCellMap->mRows.Length())
       ABORT1(false);
     const nsCellMap::CellDataArray& row = mCellMap->mRows[rgRowIndex];
 
     for (mColIndex = mAreaStart.x; mColIndex <= mAreaEnd.x; mColIndex++) {
       CellData* cellData = row.SafeElementAt(mColIndex);
       if (!cellData) { // add a dead cell data
         nsRect damageArea;
-        cellData = mCellMap->AppendCell(*mTableCellMap, nsnull, rgRowIndex, false, damageArea); if (!cellData) ABORT1(false);
+        cellData = mCellMap->AppendCell(*mTableCellMap, nsnull, rgRowIndex,
+                                        false, 0, damageArea);
+        if (!cellData) ABORT1(false);
       }
       if (cellData && (cellData->IsOrig() || cellData->IsDead())) {
         break;
       }
     }
     mIsNewRow = true;
     mAtEnd    = false;
   }
@@ -4307,17 +4347,17 @@ BCMapCellIterator::Next(BCMapCellInfo& a
     for (; mColIndex <= mAreaEnd.x; mColIndex++) {
       PRInt32 rgRowIndex = mRowIndex - mRowGroupStart;
       BCCellData* cellData =
          static_cast<BCCellData*>(mCellMap->GetDataAt(rgRowIndex, mColIndex));
       if (!cellData) { // add a dead cell data
         nsRect damageArea;
         cellData =
           static_cast<BCCellData*>(mCellMap->AppendCell(*mTableCellMap, nsnull,
-                                                         rgRowIndex, false,
+                                                         rgRowIndex, false, 0,
                                                          damageArea));
         if (!cellData) ABORT0();
       }
       if (cellData && (cellData->IsOrig() || cellData->IsDead())) {
         aMapInfo.SetInfo(mRow, mColIndex, cellData, this);
         return;
       }
     }
@@ -4342,17 +4382,17 @@ BCMapCellIterator::PeekRight(BCMapCellIn
 
   BCCellData* cellData =
     static_cast<BCCellData*>(mCellMap->GetDataAt(rgRowIndex, colIndex));
   if (!cellData) { // add a dead cell data
     NS_ASSERTION(colIndex < mTableCellMap->GetColCount(), "program error");
     nsRect damageArea;
     cellData =
       static_cast<BCCellData*>(mCellMap->AppendCell(*mTableCellMap, nsnull,
-                                                     rgRowIndex, false,
+                                                     rgRowIndex, false, 0,
                                                      damageArea));
     if (!cellData) ABORT0();
   }
   nsTableRowFrame* row = nsnull;
   if (cellData->IsRowSpan()) {
     rgRowIndex -= cellData->GetRowSpanOffset();
     cellData =
       static_cast<BCCellData*>(mCellMap->GetDataAt(rgRowIndex, colIndex));
@@ -4400,17 +4440,17 @@ BCMapCellIterator::PeekBottom(BCMapCellI
 
   BCCellData* cellData =
     static_cast<BCCellData*>(cellMap->GetDataAt(rgRowIndex, aColIndex));
   if (!cellData) { // add a dead cell data
     NS_ASSERTION(rgRowIndex < cellMap->GetRowCount(), "program error");
     nsRect damageArea;
     cellData =
       static_cast<BCCellData*>(cellMap->AppendCell(*mTableCellMap, nsnull,
-                                                    rgRowIndex, false,
+                                                    rgRowIndex, false, 0,
                                                     damageArea));
     if (!cellData) ABORT0();
   }
   if (cellData->IsColSpan()) {
     aColIndex -= cellData->GetColSpanOffset();
     cellData =
       static_cast<BCCellData*>(cellMap->GetDataAt(rgRowIndex, aColIndex));
   }
@@ -5464,23 +5504,21 @@ nsTableFrame::CalcBCBorders()
                "calling CalcBCBorders on separated-border table");
   nsTableCellMap* tableCellMap = GetCellMap(); if (!tableCellMap) ABORT0();
   PRInt32 numRows = GetRowCount();
   PRInt32 numCols = GetColCount();
   if (!numRows || !numCols)
     return; // nothing to do
 
   // Get the property holding the table damage area and border widths
-  BCPropertyData* propData = static_cast<BCPropertyData*>
-    (Properties().Get(TableBCProperty()));
+  BCPropertyData* propData = GetBCProperty();
   if (!propData) ABORT0();
 
 
 
-  CheckFixDamageArea(numRows, numCols, propData->mDamageArea);
   // calculate an expanded damage area
   nsRect damageArea(propData->mDamageArea);
   ExpandBCDamageArea(damageArea);
 
   // segments that are on the table border edges need
   // to be initialized only once
   bool tableBorderReset[4];
   for (PRUint32 sideX = NS_SIDE_TOP; sideX <= NS_SIDE_LEFT; sideX++) {
--- a/layout/tables/nsTableFrame.h
+++ b/layout/tables/nsTableFrame.h
@@ -53,16 +53,17 @@ class nsTableColFrame;
 class nsTableRowGroupFrame;
 class nsTableRowFrame;
 class nsTableColGroupFrame;
 class nsITableLayoutStrategy;
 class nsStyleContext;
 
 struct nsTableReflowState;
 struct nsStylePosition;
+struct BCPropertyData;
 
 static inline bool IS_TABLE_CELL(nsIAtom* frameType) {
   return nsGkAtoms::tableCellFrame == frameType ||
     nsGkAtoms::bcTableCellFrame == frameType;
 }
 
 class nsDisplayTableItem : public nsDisplayItem
 {
@@ -286,17 +287,17 @@ public:
    *  continue along the length of the whole left side.
    *  see nsTablePainter about continuous borders
    */
   nscoord GetContinuousLeftBCBorderWidth() const;
   void SetContinuousLeftBCBorderWidth(nscoord aValue);
 
   friend class nsDelayedCalcBCBorders;
   
-  void SetBCDamageArea(const nsRect& aValue);
+  void AddBCDamageArea(const nsRect& aValue);
   bool BCRecalcNeeded(nsStyleContext* aOldStyleContext,
                         nsStyleContext* aNewStyleContext);
   void PaintBCBorders(nsRenderingContext& aRenderingContext,
                       const nsRect&        aDirtyRect);
 
   virtual void MarkIntrinsicWidthsDirty();
   // For border-collapse tables, the caller must not add padding and
   // border to the results of these functions.
@@ -683,20 +684,23 @@ public:
     * reordering but are not yet inserted into the cellmap
     * @param aRowGroupsToExclude - an iterator that will produce the row groups
     *                              to exclude.
     */
   void ResetRowIndices(const nsFrameList::Slice& aRowGroupsToExclude);
 
   nsTArray<nsTableColFrame*>& GetColCache();
 
+
 protected:
 
   void SetBorderCollapse(bool aValue);
 
+  BCPropertyData* GetBCProperty(bool aCreateIfNecessary = false) const;
+  void SetFullBCDamageArea();
   void CalcBCBorders();
 
   void ExpandBCDamageArea(nsRect& aRect) const;
 
   void SetColumnDimensions(nscoord         aHeight,
                            const nsMargin& aReflowState);
 
   PRInt32 CollectRows(nsIFrame*                   aFrame,
--- a/layout/tables/nsTableRowFrame.cpp
+++ b/layout/tables/nsTableRowFrame.cpp
@@ -190,17 +190,17 @@ nsTableRowFrame::DidSetStyleContext(nsSt
   if (!aOldStyleContext) //avoid this on init
     return;
      
   nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
     
   if (tableFrame->IsBorderCollapse() &&
       tableFrame->BCRecalcNeeded(aOldStyleContext, GetStyleContext())) {
     nsRect damageArea(0, GetRowIndex(), tableFrame->GetColCount(), 1);
-    tableFrame->SetBCDamageArea(damageArea);
+    tableFrame->AddBCDamageArea(damageArea);
   }
   return;
 }
 
 NS_IMETHODIMP
 nsTableRowFrame::AppendFrames(ChildListID     aListID,
                               nsFrameList&    aFrameList)
 {
--- a/layout/tables/nsTableRowGroupFrame.cpp
+++ b/layout/tables/nsTableRowGroupFrame.cpp
@@ -1384,17 +1384,17 @@ nsTableRowGroupFrame::DidSetStyleContext
     return;
      
   nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
     
   if (tableFrame->IsBorderCollapse() &&
       tableFrame->BCRecalcNeeded(aOldStyleContext, GetStyleContext())) {
     nsRect damageArea(0, GetStartRowIndex(), tableFrame->GetColCount(),
                       GetRowCount());
-    tableFrame->SetBCDamageArea(damageArea);
+    tableFrame->AddBCDamageArea(damageArea);
   }
   return;
 }
 
 NS_IMETHODIMP
 nsTableRowGroupFrame::AppendFrames(ChildListID     aListID,
                                    nsFrameList&    aFrameList)
 {