LCOV - code coverage report
Current view: directory - layout/tables - nsCellMap.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 1486 8 0.5 %
Date: 2012-06-02 Functions: 87 2 2.3 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is mozilla.org code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *
      24                 :  * Alternatively, the contents of this file may be used under the terms of
      25                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      26                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      28                 :  * of those above. If you wish to allow use of your version of this file only
      29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      30                 :  * use your version of this file under the terms of the MPL, indicate your
      31                 :  * decision by deleting the provisions above and replace them with the notice
      32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      33                 :  * the provisions above, a recipient may use your version of this file under
      34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      35                 :  *
      36                 :  * ***** END LICENSE BLOCK ***** */
      37                 : 
      38                 : #include "nsTArray.h"
      39                 : #include "nsCellMap.h"
      40                 : #include "nsTableFrame.h"
      41                 : #include "nsTableCellFrame.h"
      42                 : #include "nsTableRowGroupFrame.h"
      43                 : 
      44                 : 
      45                 : static void
      46               0 : SetDamageArea(PRInt32 aXOrigin,
      47                 :               PRInt32 aYOrigin,
      48                 :               PRInt32 aWidth,
      49                 :               PRInt32 aHeight,
      50                 :               nsIntRect& aDamageArea)
      51                 : {
      52               0 :   NS_ASSERTION(aXOrigin >= 0, "negative col index");
      53               0 :   NS_ASSERTION(aYOrigin >= 0, "negative row index");
      54               0 :   NS_ASSERTION(aWidth >= 0, "negative horizontal damage");
      55               0 :   NS_ASSERTION(aHeight >= 0, "negative vertical damage");
      56               0 :   aDamageArea.x      = aXOrigin;
      57               0 :   aDamageArea.y      = aYOrigin;
      58               0 :   aDamageArea.width  = aWidth;
      59               0 :   aDamageArea.height = aHeight;
      60               0 : }
      61                 :  
      62                 : // Empty static array used for SafeElementAt() calls on mRows.
      63                 : static nsCellMap::CellDataArray * sEmptyRow;
      64                 : 
      65                 : // CellData
      66                 : 
      67               0 : CellData::CellData(nsTableCellFrame* aOrigCell)
      68                 : {
      69               0 :   MOZ_COUNT_CTOR(CellData);
      70               0 :   mOrigCell = aOrigCell;
      71               0 : }
      72                 : 
      73               0 : CellData::~CellData()
      74                 : {
      75               0 :   MOZ_COUNT_DTOR(CellData);
      76               0 : }
      77                 : 
      78               0 : BCCellData::BCCellData(nsTableCellFrame* aOrigCell)
      79               0 : :CellData(aOrigCell)
      80                 : {
      81               0 :   MOZ_COUNT_CTOR(BCCellData);
      82               0 : }
      83                 : 
      84               0 : BCCellData::~BCCellData()
      85                 : {
      86               0 :   MOZ_COUNT_DTOR(BCCellData);
      87               0 : }
      88                 : 
      89                 : // nsTableCellMap
      90                 : 
      91               0 : nsTableCellMap::nsTableCellMap(nsTableFrame&   aTableFrame,
      92                 :                                bool            aBorderCollapse)
      93               0 : :mTableFrame(aTableFrame), mFirstMap(nsnull), mBCInfo(nsnull)
      94                 : {
      95               0 :   MOZ_COUNT_CTOR(nsTableCellMap);
      96                 : 
      97               0 :   nsTableFrame::RowGroupArray orderedRowGroups;
      98               0 :   aTableFrame.OrderRowGroups(orderedRowGroups);
      99                 : 
     100               0 :   nsTableRowGroupFrame* prior = nsnull;
     101               0 :   for (PRUint32 rgX = 0; rgX < orderedRowGroups.Length(); rgX++) {
     102               0 :     nsTableRowGroupFrame* rgFrame = orderedRowGroups[rgX];
     103               0 :     InsertGroupCellMap(rgFrame, prior);
     104               0 :     prior = rgFrame;
     105                 :   }
     106               0 :   if (aBorderCollapse) {
     107               0 :     mBCInfo = new BCInfo();
     108                 :   }
     109               0 : }
     110                 : 
     111               0 : nsTableCellMap::~nsTableCellMap()
     112                 : {
     113               0 :   MOZ_COUNT_DTOR(nsTableCellMap);
     114                 : 
     115               0 :   nsCellMap* cellMap = mFirstMap;
     116               0 :   while (cellMap) {
     117               0 :     nsCellMap* next = cellMap->GetNextSibling();
     118               0 :     delete cellMap;
     119               0 :     cellMap = next;
     120                 :   }
     121                 : 
     122               0 :   if (mBCInfo) {
     123               0 :     DeleteRightBottomBorders();
     124               0 :     delete mBCInfo;
     125                 :   }
     126               0 : }
     127                 : 
     128                 : // Get the bcData holding the border segments of the right edge of the table
     129                 : BCData*
     130               0 : nsTableCellMap::GetRightMostBorder(PRInt32 aRowIndex)
     131                 : {
     132               0 :   if (!mBCInfo) ABORT1(nsnull);
     133                 : 
     134               0 :   PRInt32 numRows = mBCInfo->mRightBorders.Length();
     135               0 :   if (aRowIndex < numRows) {
     136               0 :     return &mBCInfo->mRightBorders.ElementAt(aRowIndex);
     137                 :   }
     138                 : 
     139               0 :   if (!mBCInfo->mRightBorders.SetLength(aRowIndex+1))
     140               0 :     ABORT1(nsnull);
     141               0 :   return &mBCInfo->mRightBorders.ElementAt(aRowIndex);
     142                 : }
     143                 : 
     144                 : // Get the bcData holding the border segments of the bottom edge of the table
     145                 : BCData*
     146               0 : nsTableCellMap::GetBottomMostBorder(PRInt32 aColIndex)
     147                 : {
     148               0 :   if (!mBCInfo) ABORT1(nsnull);
     149                 : 
     150               0 :   PRInt32 numCols = mBCInfo->mBottomBorders.Length();
     151               0 :   if (aColIndex < numCols) {
     152               0 :     return &mBCInfo->mBottomBorders.ElementAt(aColIndex);
     153                 :   }
     154                 : 
     155               0 :   if (!mBCInfo->mBottomBorders.SetLength(aColIndex+1))
     156               0 :     ABORT1(nsnull);
     157               0 :   return &mBCInfo->mBottomBorders.ElementAt(aColIndex);
     158                 : }
     159                 : 
     160                 : // delete the borders corresponding to the right and bottom edges of the table
     161                 : void
     162               0 : nsTableCellMap::DeleteRightBottomBorders()
     163                 : {
     164               0 :   if (mBCInfo) {
     165               0 :     mBCInfo->mBottomBorders.Clear();
     166               0 :     mBCInfo->mRightBorders.Clear();
     167                 :   }
     168               0 : }
     169                 : 
     170                 : void
     171               0 : nsTableCellMap::InsertGroupCellMap(nsCellMap* aPrevMap,
     172                 :                                    nsCellMap& aNewMap)
     173                 : {
     174                 :   nsCellMap* next;
     175               0 :   if (aPrevMap) {
     176               0 :     next = aPrevMap->GetNextSibling();
     177               0 :     aPrevMap->SetNextSibling(&aNewMap);
     178                 :   }
     179                 :   else {
     180               0 :     next = mFirstMap;
     181               0 :     mFirstMap = &aNewMap;
     182                 :   }
     183               0 :   aNewMap.SetNextSibling(next);
     184               0 : }
     185                 : 
     186               0 : void nsTableCellMap::InsertGroupCellMap(nsTableRowGroupFrame*  aNewGroup,
     187                 :                                         nsTableRowGroupFrame*& aPrevGroup)
     188                 : {
     189               0 :   nsCellMap* newMap = new nsCellMap(aNewGroup, mBCInfo != nsnull);
     190               0 :   nsCellMap* prevMap = nsnull;
     191               0 :   nsCellMap* lastMap = mFirstMap;
     192               0 :   if (aPrevGroup) {
     193               0 :     nsCellMap* map = mFirstMap;
     194               0 :     while (map) {
     195               0 :       lastMap = map;
     196               0 :       if (map->GetRowGroup() == aPrevGroup) {
     197               0 :         prevMap = map;
     198               0 :         break;
     199                 :       }
     200               0 :       map = map->GetNextSibling();
     201                 :     }
     202                 :   }
     203               0 :   if (!prevMap) {
     204               0 :     if (aPrevGroup) {
     205               0 :       prevMap = lastMap;
     206               0 :       aPrevGroup = (prevMap) ? prevMap->GetRowGroup() : nsnull;
     207                 :     }
     208                 :     else {
     209               0 :       aPrevGroup = nsnull;
     210                 :     }
     211                 :   }
     212               0 :   InsertGroupCellMap(prevMap, *newMap);
     213               0 : }
     214                 : 
     215               0 : void nsTableCellMap::RemoveGroupCellMap(nsTableRowGroupFrame* aGroup)
     216                 : {
     217               0 :   nsCellMap* map = mFirstMap;
     218               0 :   nsCellMap* prior = nsnull;
     219               0 :   while (map) {
     220               0 :     if (map->GetRowGroup() == aGroup) {
     221               0 :       nsCellMap* next = map->GetNextSibling();
     222               0 :       if (mFirstMap == map) {
     223               0 :         mFirstMap = next;
     224                 :       }
     225                 :       else {
     226               0 :         prior->SetNextSibling(next);
     227                 :       }
     228               0 :       delete map;
     229               0 :       break;
     230                 :     }
     231               0 :     prior = map;
     232               0 :     map = map->GetNextSibling();
     233                 :   }
     234               0 : }
     235                 : 
     236                 : static nsCellMap*
     237               0 : FindMapFor(const nsTableRowGroupFrame* aRowGroup,
     238                 :            nsCellMap* aStart,
     239                 :            const nsCellMap* aEnd)
     240                 : {
     241               0 :   for (nsCellMap* map = aStart; map != aEnd; map = map->GetNextSibling()) {
     242               0 :     if (aRowGroup == map->GetRowGroup()) {
     243               0 :       return map;
     244                 :     }
     245                 :   }
     246                 : 
     247               0 :   return nsnull;
     248                 : }
     249                 : 
     250                 : nsCellMap*
     251               0 : nsTableCellMap::GetMapFor(const nsTableRowGroupFrame* aRowGroup,
     252                 :                           nsCellMap* aStartHint) const
     253                 : {
     254               0 :   NS_PRECONDITION(aRowGroup, "Must have a rowgroup");
     255               0 :   NS_ASSERTION(!aRowGroup->GetPrevInFlow(), "GetMapFor called with continuation");
     256               0 :   if (aStartHint) {
     257               0 :     nsCellMap* map = FindMapFor(aRowGroup, aStartHint, nsnull);
     258               0 :     if (map) {
     259               0 :       return map;
     260                 :     }
     261                 :   }
     262                 : 
     263               0 :   nsCellMap* map = FindMapFor(aRowGroup, mFirstMap, aStartHint);
     264               0 :   if (map) {
     265               0 :     return map;
     266                 :   }
     267                 : 
     268                 :   // if aRowGroup is a repeated header or footer find the header or footer it was repeated from
     269               0 :   if (aRowGroup->IsRepeatable()) {
     270               0 :     nsTableFrame* fifTable = static_cast<nsTableFrame*>(mTableFrame.GetFirstInFlow());
     271                 : 
     272               0 :     const nsStyleDisplay* display = aRowGroup->GetStyleDisplay();
     273                 :     nsTableRowGroupFrame* rgOrig =
     274                 :       (NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == display->mDisplay) ?
     275               0 :       fifTable->GetTHead() : fifTable->GetTFoot();
     276                 :     // find the row group cell map using the original header/footer
     277               0 :     if (rgOrig && rgOrig != aRowGroup) {
     278               0 :       return GetMapFor(rgOrig, aStartHint);
     279                 :     }
     280                 :   }
     281                 : 
     282               0 :   return nsnull;
     283                 : }
     284                 : 
     285                 : void
     286               0 : nsTableCellMap::Synchronize(nsTableFrame* aTableFrame)
     287                 : {
     288               0 :   nsTableFrame::RowGroupArray orderedRowGroups;
     289               0 :   nsAutoTArray<nsCellMap*, 8> maps;
     290                 : 
     291               0 :   aTableFrame->OrderRowGroups(orderedRowGroups);
     292               0 :   if (!orderedRowGroups.Length()) {
     293                 :     return;
     294                 :   }
     295                 : 
     296                 :   // XXXbz this fails if orderedRowGroups is missing some row groups
     297                 :   // (due to OOM when appending to the array, e.g. -- we leak maps in
     298                 :   // that case).
     299                 : 
     300                 :   // Scope |map| outside the loop so we can use it as a hint.
     301               0 :   nsCellMap* map = nsnull;
     302               0 :   for (PRUint32 rgX = 0; rgX < orderedRowGroups.Length(); rgX++) {
     303               0 :     nsTableRowGroupFrame* rgFrame = orderedRowGroups[rgX];
     304               0 :     map = GetMapFor((nsTableRowGroupFrame*)rgFrame->GetFirstInFlow(), map);
     305               0 :     if (map) {
     306               0 :       if (!maps.AppendElement(map)) {
     307               0 :         delete map;
     308               0 :         map = nsnull;
     309               0 :         NS_WARNING("Could not AppendElement");
     310               0 :         break;
     311                 :       }
     312                 :     }
     313                 :   }
     314                 : 
     315               0 :   PRInt32 mapIndex = maps.Length() - 1;  // Might end up -1
     316               0 :   nsCellMap* nextMap = maps.ElementAt(mapIndex);
     317               0 :   nextMap->SetNextSibling(nsnull);
     318               0 :   for (mapIndex-- ; mapIndex >= 0; mapIndex--) {
     319               0 :     nsCellMap* map = maps.ElementAt(mapIndex);
     320               0 :     map->SetNextSibling(nextMap);
     321               0 :     nextMap = map;
     322                 :   }
     323               0 :   mFirstMap = nextMap;
     324                 : }
     325                 : 
     326                 : bool
     327               0 : nsTableCellMap::HasMoreThanOneCell(PRInt32 aRowIndex) const
     328                 : {
     329               0 :   PRInt32 rowIndex = aRowIndex;
     330               0 :   nsCellMap* map = mFirstMap;
     331               0 :   while (map) {
     332               0 :     if (map->GetRowCount() > rowIndex) {
     333               0 :       return map->HasMoreThanOneCell(rowIndex);
     334                 :     }
     335               0 :     rowIndex -= map->GetRowCount();
     336               0 :     map = map->GetNextSibling();
     337                 :   }
     338               0 :   return false;
     339                 : }
     340                 : 
     341                 : PRInt32
     342               0 : nsTableCellMap::GetNumCellsOriginatingInRow(PRInt32 aRowIndex) const
     343                 : {
     344               0 :   PRInt32 rowIndex = aRowIndex;
     345               0 :   nsCellMap* map = mFirstMap;
     346               0 :   while (map) {
     347               0 :     if (map->GetRowCount() > rowIndex) {
     348               0 :       return map->GetNumCellsOriginatingInRow(rowIndex);
     349                 :     }
     350               0 :     rowIndex -= map->GetRowCount();
     351               0 :     map = map->GetNextSibling();
     352                 :   }
     353               0 :   return 0;
     354                 : }
     355                 : PRInt32
     356               0 : nsTableCellMap::GetEffectiveRowSpan(PRInt32 aRowIndex,
     357                 :                                     PRInt32 aColIndex) const
     358                 : {
     359               0 :   PRInt32 rowIndex = aRowIndex;
     360               0 :   nsCellMap* map = mFirstMap;
     361               0 :   while (map) {
     362               0 :     if (map->GetRowCount() > rowIndex) {
     363               0 :       return map->GetRowSpan(rowIndex, aColIndex, true);
     364                 :     }
     365               0 :     rowIndex -= map->GetRowCount();
     366               0 :     map = map->GetNextSibling();
     367                 :   }
     368               0 :   NS_NOTREACHED("Bogus row index?");
     369               0 :   return 0;
     370                 : }
     371                 : 
     372                 : PRInt32
     373               0 : nsTableCellMap::GetEffectiveColSpan(PRInt32 aRowIndex,
     374                 :                                     PRInt32 aColIndex) const
     375                 : {
     376               0 :   PRInt32 rowIndex = aRowIndex;
     377               0 :   nsCellMap* map = mFirstMap;
     378               0 :   while (map) {
     379               0 :     if (map->GetRowCount() > rowIndex) {
     380                 :       bool zeroColSpan;
     381               0 :       return map->GetEffectiveColSpan(*this, rowIndex, aColIndex, zeroColSpan);
     382                 :     }
     383               0 :     rowIndex -= map->GetRowCount();
     384               0 :     map = map->GetNextSibling();
     385                 :   }
     386               0 :   NS_NOTREACHED("Bogus row index?");
     387               0 :   return 0;
     388                 : }
     389                 : 
     390                 : nsTableCellFrame*
     391               0 : nsTableCellMap::GetCellFrame(PRInt32   aRowIndex,
     392                 :                              PRInt32   aColIndex,
     393                 :                              CellData& aData,
     394                 :                              bool      aUseRowIfOverlap) const
     395                 : {
     396               0 :   PRInt32 rowIndex = aRowIndex;
     397               0 :   nsCellMap* map = mFirstMap;
     398               0 :   while (map) {
     399               0 :     if (map->GetRowCount() > rowIndex) {
     400               0 :       return map->GetCellFrame(rowIndex, aColIndex, aData, aUseRowIfOverlap);
     401                 :     }
     402               0 :     rowIndex -= map->GetRowCount();
     403               0 :     map = map->GetNextSibling();
     404                 :   }
     405               0 :   return nsnull;
     406                 : }
     407                 : 
     408                 : nsColInfo*
     409               0 : nsTableCellMap::GetColInfoAt(PRInt32 aColIndex)
     410                 : {
     411               0 :   PRInt32 numColsToAdd = aColIndex + 1 - mCols.Length();
     412               0 :   if (numColsToAdd > 0) {
     413               0 :     AddColsAtEnd(numColsToAdd);  // XXX this could fail to add cols in theory
     414                 :   }
     415               0 :   return &mCols.ElementAt(aColIndex);
     416                 : }
     417                 : 
     418                 : PRInt32
     419               0 : nsTableCellMap::GetRowCount() const
     420                 : {
     421               0 :   PRInt32 numRows = 0;
     422               0 :   nsCellMap* map = mFirstMap;
     423               0 :   while (map) {
     424               0 :     numRows += map->GetRowCount();
     425               0 :     map = map->GetNextSibling();
     426                 :   }
     427               0 :   return numRows;
     428                 : }
     429                 : 
     430                 : CellData*
     431               0 : nsTableCellMap::GetDataAt(PRInt32 aRowIndex,
     432                 :                           PRInt32 aColIndex) const
     433                 : {
     434               0 :   PRInt32 rowIndex = aRowIndex;
     435               0 :   nsCellMap* map = mFirstMap;
     436               0 :   while (map) {
     437               0 :     if (map->GetRowCount() > rowIndex) {
     438               0 :       return map->GetDataAt(rowIndex, aColIndex);
     439                 :     }
     440               0 :     rowIndex -= map->GetRowCount();
     441               0 :     map = map->GetNextSibling();
     442                 :   }
     443               0 :   return nsnull;
     444                 : }
     445                 : 
     446                 : void
     447               0 : nsTableCellMap::AddColsAtEnd(PRUint32 aNumCols)
     448                 : {
     449               0 :   if (!mCols.AppendElements(aNumCols)) {
     450               0 :     NS_WARNING("Could not AppendElement");
     451                 :   }
     452               0 :   if (mBCInfo) {
     453               0 :     if (!mBCInfo->mBottomBorders.AppendElements(aNumCols)) {
     454               0 :       NS_WARNING("Could not AppendElement");
     455                 :     }
     456                 :   }
     457               0 : }
     458                 : 
     459                 : void
     460               0 : nsTableCellMap::RemoveColsAtEnd()
     461                 : {
     462                 :   // Remove the cols at the end which don't have originating cells or cells spanning
     463                 :   // into them. Only do this if the col was created as eColAnonymousCell
     464               0 :   PRInt32 numCols = GetColCount();
     465               0 :   PRInt32 lastGoodColIndex = mTableFrame.GetIndexOfLastRealCol();
     466               0 :   for (PRInt32 colX = numCols - 1; (colX >= 0) && (colX > lastGoodColIndex); colX--) {
     467               0 :     nsColInfo& colInfo = mCols.ElementAt(colX);
     468               0 :     if ((colInfo.mNumCellsOrig <= 0) && (colInfo.mNumCellsSpan <= 0))  {
     469               0 :       mCols.RemoveElementAt(colX);
     470                 : 
     471               0 :       if (mBCInfo) {
     472               0 :         PRInt32 count = mBCInfo->mBottomBorders.Length();
     473               0 :         if (colX < count) {
     474               0 :           mBCInfo->mBottomBorders.RemoveElementAt(colX);
     475                 :         }
     476                 :       }
     477                 :     }
     478               0 :     else break; // only remove until we encounter the 1st valid one
     479                 :   }
     480               0 : }
     481                 : 
     482                 : void
     483               0 : nsTableCellMap::ClearCols()
     484                 : {
     485               0 :   mCols.Clear();
     486               0 :   if (mBCInfo)
     487               0 :     mBCInfo->mBottomBorders.Clear();
     488               0 : }
     489                 : void
     490               0 : nsTableCellMap::InsertRows(nsTableRowGroupFrame*       aParent,
     491                 :                            nsTArray<nsTableRowFrame*>& aRows,
     492                 :                            PRInt32                     aFirstRowIndex,
     493                 :                            bool                        aConsiderSpans,
     494                 :                            nsIntRect&                  aDamageArea)
     495                 : {
     496               0 :   PRInt32 numNewRows = aRows.Length();
     497               0 :   if ((numNewRows <= 0) || (aFirstRowIndex < 0)) ABORT0();
     498                 : 
     499               0 :   PRInt32 rowIndex = aFirstRowIndex;
     500               0 :   PRInt32 rgStartRowIndex = 0;
     501               0 :   nsCellMap* cellMap = mFirstMap;
     502               0 :   while (cellMap) {
     503               0 :     nsTableRowGroupFrame* rg = cellMap->GetRowGroup();
     504               0 :     if (rg == aParent) {
     505                 :       cellMap->InsertRows(*this, aRows, rowIndex, aConsiderSpans,
     506               0 :                           rgStartRowIndex, aDamageArea);
     507                 : #ifdef DEBUG_TABLE_CELLMAP
     508                 :       Dump("after InsertRows");
     509                 : #endif
     510               0 :       if (mBCInfo) {
     511               0 :         PRInt32 count = mBCInfo->mRightBorders.Length();
     512               0 :         if (aFirstRowIndex < count) {
     513               0 :           for (PRInt32 rowX = aFirstRowIndex; rowX < aFirstRowIndex + numNewRows; rowX++) {
     514               0 :             if (!mBCInfo->mRightBorders.InsertElementAt(rowX))
     515               0 :               ABORT0();
     516                 :           }
     517                 :         }
     518                 :         else {
     519               0 :           GetRightMostBorder(aFirstRowIndex); // this will create missing entries
     520               0 :           for (PRInt32 rowX = aFirstRowIndex + 1; rowX < aFirstRowIndex + numNewRows; rowX++) {
     521               0 :             if (!mBCInfo->mRightBorders.AppendElement())
     522               0 :               ABORT0();
     523                 :           }
     524                 :         }
     525                 :       }
     526               0 :       return;
     527                 :     }
     528               0 :     PRInt32 rowCount = cellMap->GetRowCount();
     529               0 :     rgStartRowIndex += rowCount;
     530               0 :     rowIndex -= rowCount;
     531               0 :     cellMap = cellMap->GetNextSibling();
     532                 :   }
     533                 : 
     534               0 :   NS_ERROR("Attempt to insert row into wrong map.");
     535                 : }
     536                 : 
     537                 : void
     538               0 : nsTableCellMap::RemoveRows(PRInt32         aFirstRowIndex,
     539                 :                            PRInt32         aNumRowsToRemove,
     540                 :                            bool            aConsiderSpans,
     541                 :                            nsIntRect&      aDamageArea)
     542                 : {
     543               0 :   PRInt32 rowIndex = aFirstRowIndex;
     544               0 :   PRInt32 rgStartRowIndex = 0;
     545               0 :   nsCellMap* cellMap = mFirstMap;
     546               0 :   while (cellMap) {
     547               0 :     PRInt32 rowCount = cellMap->GetRowCount();
     548               0 :     if (rowCount > rowIndex) {
     549                 :       cellMap->RemoveRows(*this, rowIndex, aNumRowsToRemove, aConsiderSpans,
     550               0 :                           rgStartRowIndex, aDamageArea);
     551               0 :       if (mBCInfo) {
     552               0 :         for (PRInt32 rowX = aFirstRowIndex + aNumRowsToRemove - 1; rowX >= aFirstRowIndex; rowX--) {
     553               0 :           if (PRUint32(rowX) < mBCInfo->mRightBorders.Length()) {
     554               0 :             mBCInfo->mRightBorders.RemoveElementAt(rowX);
     555                 :           }
     556                 :         }
     557                 :       }
     558               0 :       break;
     559                 :     }
     560               0 :     rgStartRowIndex += rowCount;
     561               0 :     rowIndex -= rowCount;
     562               0 :     cellMap = cellMap->GetNextSibling();
     563                 :   }
     564                 : #ifdef DEBUG_TABLE_CELLMAP
     565                 :   Dump("after RemoveRows");
     566                 : #endif
     567               0 : }
     568                 : 
     569                 : 
     570                 : 
     571                 : CellData*
     572               0 : nsTableCellMap::AppendCell(nsTableCellFrame& aCellFrame,
     573                 :                            PRInt32           aRowIndex,
     574                 :                            bool              aRebuildIfNecessary,
     575                 :                            nsIntRect&        aDamageArea)
     576                 : {
     577               0 :   NS_ASSERTION(&aCellFrame == aCellFrame.GetFirstInFlow(), "invalid call on continuing frame");
     578               0 :   nsIFrame* rgFrame = aCellFrame.GetParent(); // get the row
     579               0 :   if (!rgFrame) return 0;
     580               0 :   rgFrame = rgFrame->GetParent();   // get the row group
     581               0 :   if (!rgFrame) return 0;
     582                 : 
     583               0 :   CellData* result = nsnull;
     584               0 :   PRInt32 rowIndex = aRowIndex;
     585               0 :   PRInt32 rgStartRowIndex = 0;
     586               0 :   nsCellMap* cellMap = mFirstMap;
     587               0 :   while (cellMap) {
     588               0 :     if (cellMap->GetRowGroup() == rgFrame) {
     589                 :       result = cellMap->AppendCell(*this, &aCellFrame, rowIndex,
     590                 :                                    aRebuildIfNecessary, rgStartRowIndex,
     591               0 :                                    aDamageArea);
     592               0 :       break;
     593                 :     }
     594               0 :     PRInt32 rowCount = cellMap->GetRowCount();
     595               0 :     rgStartRowIndex += rowCount;
     596               0 :     rowIndex -= rowCount;
     597               0 :     cellMap = cellMap->GetNextSibling();
     598                 :   }
     599                 : #ifdef DEBUG_TABLE_CELLMAP
     600                 :   Dump("after AppendCell");
     601                 : #endif
     602               0 :   return result;
     603                 : }
     604                 : 
     605                 : 
     606                 : void
     607               0 : nsTableCellMap::InsertCells(nsTArray<nsTableCellFrame*>& aCellFrames,
     608                 :                             PRInt32                      aRowIndex,
     609                 :                             PRInt32                      aColIndexBefore,
     610                 :                             nsIntRect&                   aDamageArea)
     611                 : {
     612               0 :   PRInt32 rowIndex = aRowIndex;
     613               0 :   PRInt32 rgStartRowIndex = 0;
     614               0 :   nsCellMap* cellMap = mFirstMap;
     615               0 :   while (cellMap) {
     616               0 :     PRInt32 rowCount = cellMap->GetRowCount();
     617               0 :     if (rowCount > rowIndex) {
     618                 :       cellMap->InsertCells(*this, aCellFrames, rowIndex, aColIndexBefore,
     619               0 :                            rgStartRowIndex, aDamageArea);
     620               0 :       break;
     621                 :     }
     622               0 :     rgStartRowIndex += rowCount;
     623               0 :     rowIndex -= rowCount;
     624               0 :     cellMap = cellMap->GetNextSibling();
     625                 :   }
     626                 : #ifdef DEBUG_TABLE_CELLMAP
     627                 :   Dump("after InsertCells");
     628                 : #endif
     629               0 : }
     630                 : 
     631                 : 
     632                 : void
     633               0 : nsTableCellMap::RemoveCell(nsTableCellFrame* aCellFrame,
     634                 :                            PRInt32           aRowIndex,
     635                 :                            nsIntRect&        aDamageArea)
     636                 : {
     637               0 :   if (!aCellFrame) ABORT0();
     638               0 :   NS_ASSERTION(aCellFrame == (nsTableCellFrame *)aCellFrame->GetFirstInFlow(),
     639                 :                "invalid call on continuing frame");
     640               0 :   PRInt32 rowIndex = aRowIndex;
     641               0 :   PRInt32 rgStartRowIndex = 0;
     642               0 :   nsCellMap* cellMap = mFirstMap;
     643               0 :   while (cellMap) {
     644               0 :     PRInt32 rowCount = cellMap->GetRowCount();
     645               0 :     if (rowCount > rowIndex) {
     646                 :       cellMap->RemoveCell(*this, aCellFrame, rowIndex, rgStartRowIndex,
     647               0 :                           aDamageArea);
     648                 : #ifdef DEBUG_TABLE_CELLMAP
     649                 :       Dump("after RemoveCell");
     650                 : #endif
     651               0 :       return;
     652                 :     }
     653               0 :     rgStartRowIndex += rowCount;
     654               0 :     rowIndex -= rowCount;
     655               0 :     cellMap = cellMap->GetNextSibling();
     656                 :   }
     657                 :   // if we reach this point - the cell did not get removed, the caller of this routine
     658                 :   // will delete the cell and the cellmap will probably hold a reference to
     659                 :   // the deleted cell which will cause a subsequent crash when this cell is
     660                 :   // referenced later
     661               0 :   NS_ERROR("nsTableCellMap::RemoveCell - could not remove cell");
     662                 : }
     663                 : 
     664                 : void
     665               0 : nsTableCellMap::RebuildConsideringCells(nsCellMap*                   aCellMap,
     666                 :                                         nsTArray<nsTableCellFrame*>* aCellFrames,
     667                 :                                         PRInt32                      aRowIndex,
     668                 :                                         PRInt32                      aColIndex,
     669                 :                                         bool                         aInsert,
     670                 :                                         nsIntRect&                   aDamageArea)
     671                 : {
     672               0 :   PRInt32 numOrigCols = GetColCount();
     673               0 :   ClearCols();
     674               0 :   nsCellMap* cellMap = mFirstMap;
     675               0 :   PRInt32 rowCount = 0;
     676               0 :   while (cellMap) {
     677               0 :     if (cellMap == aCellMap) {
     678                 :       cellMap->RebuildConsideringCells(*this, numOrigCols, aCellFrames,
     679               0 :                                        aRowIndex, aColIndex, aInsert);
     680                 :     }
     681                 :     else {
     682                 :       cellMap->RebuildConsideringCells(*this, numOrigCols, nsnull, -1, 0,
     683               0 :                                        false);
     684                 :     }
     685               0 :     rowCount += cellMap->GetRowCount();
     686               0 :     cellMap = cellMap->GetNextSibling();
     687                 :   }
     688               0 :   SetDamageArea(0, 0, GetColCount(), rowCount, aDamageArea);
     689               0 : }
     690                 : 
     691                 : void
     692               0 : nsTableCellMap::RebuildConsideringRows(nsCellMap*                  aCellMap,
     693                 :                                        PRInt32                     aStartRowIndex,
     694                 :                                        nsTArray<nsTableRowFrame*>* aRowsToInsert,
     695                 :                                        PRInt32                     aNumRowsToRemove,
     696                 :                                        nsIntRect&                  aDamageArea)
     697                 : {
     698               0 :   NS_PRECONDITION(!aRowsToInsert || aNumRowsToRemove == 0,
     699                 :                   "Can't handle both removing and inserting rows at once");
     700                 : 
     701               0 :   PRInt32 numOrigCols = GetColCount();
     702               0 :   ClearCols();
     703               0 :   nsCellMap* cellMap = mFirstMap;
     704               0 :   PRInt32 rowCount = 0;
     705               0 :   while (cellMap) {
     706               0 :     if (cellMap == aCellMap) {
     707                 :       cellMap->RebuildConsideringRows(*this, aStartRowIndex, aRowsToInsert,
     708               0 :                                       aNumRowsToRemove);
     709                 :     }
     710                 :     else {
     711                 :       cellMap->RebuildConsideringCells(*this, numOrigCols, nsnull, -1, 0,
     712               0 :                                        false);
     713                 :     }
     714               0 :     rowCount += cellMap->GetRowCount();
     715               0 :     cellMap = cellMap->GetNextSibling();
     716                 :   }
     717               0 :   SetDamageArea(0, 0, GetColCount(), rowCount, aDamageArea);
     718               0 : }
     719                 : 
     720                 : PRInt32
     721               0 : nsTableCellMap::GetNumCellsOriginatingInCol(PRInt32 aColIndex) const
     722                 : {
     723               0 :   PRInt32 colCount = mCols.Length();
     724               0 :   if ((aColIndex >= 0) && (aColIndex < colCount)) {
     725               0 :     return mCols.ElementAt(aColIndex).mNumCellsOrig;
     726                 :   }
     727                 :   else {
     728               0 :     NS_ERROR("nsCellMap::GetNumCellsOriginatingInCol - bad col index");
     729               0 :     return 0;
     730                 :   }
     731                 : }
     732                 : 
     733                 : #ifdef NS_DEBUG
     734                 : void
     735               0 : nsTableCellMap::Dump(char* aString) const
     736                 : {
     737               0 :   if (aString)
     738               0 :     printf("%s \n", aString);
     739               0 :   printf("***** START TABLE CELL MAP DUMP ***** %p\n", (void*)this);
     740                 :   // output col info
     741               0 :   PRInt32 colCount = mCols.Length();
     742               0 :   printf ("cols array orig/span-> %p", (void*)this);
     743               0 :   for (PRInt32 colX = 0; colX < colCount; colX++) {
     744               0 :     const nsColInfo& colInfo = mCols.ElementAt(colX);
     745               0 :     printf ("%d=%d/%d ", colX, colInfo.mNumCellsOrig, colInfo.mNumCellsSpan);
     746                 :   }
     747               0 :   printf(" cols in cache %d\n", mTableFrame.GetColCache().Length());
     748               0 :   nsCellMap* cellMap = mFirstMap;
     749               0 :   while (cellMap) {
     750               0 :     cellMap->Dump(nsnull != mBCInfo);
     751               0 :     cellMap = cellMap->GetNextSibling();
     752                 :   }
     753               0 :   if (nsnull != mBCInfo) {
     754               0 :     printf("***** bottom borders *****\n");
     755                 :     nscoord       size;
     756                 :     BCBorderOwner owner;
     757                 :     mozilla::css::Side side;
     758                 :     bool          segStart;
     759                 :     bool          bevel;
     760                 :     PRInt32       colIndex;
     761               0 :     PRInt32 numCols = mBCInfo->mBottomBorders.Length();
     762               0 :     for (PRInt32 i = 0; i <= 2; i++) {
     763                 : 
     764               0 :       printf("\n          ");
     765               0 :       for (colIndex = 0; colIndex < numCols; colIndex++) {
     766               0 :         BCData& cd = mBCInfo->mBottomBorders.ElementAt(colIndex);
     767               0 :         if (0 == i) {
     768               0 :           size = cd.GetTopEdge(owner, segStart);
     769               0 :           printf("t=%d%X%d ", PRInt32(size), owner, segStart);
     770                 :         }
     771               0 :         else if (1 == i) {
     772               0 :           size = cd.GetLeftEdge(owner, segStart);
     773               0 :           printf("l=%d%X%d ", PRInt32(size), owner, segStart);
     774                 :         }
     775                 :         else {
     776               0 :           size = cd.GetCorner(side, bevel);
     777               0 :           printf("c=%d%X%d ", PRInt32(size), side, bevel);
     778                 :         }
     779                 :       }
     780               0 :       BCData& cd = mBCInfo->mLowerRightCorner;
     781               0 :       if (0 == i) {
     782               0 :          size = cd.GetTopEdge(owner, segStart);
     783               0 :          printf("t=%d%X%d ", PRInt32(size), owner, segStart);
     784                 :       }
     785               0 :       else if (1 == i) {
     786               0 :         size = cd.GetLeftEdge(owner, segStart);
     787               0 :         printf("l=%d%X%d ", PRInt32(size), owner, segStart);
     788                 :       }
     789                 :       else {
     790               0 :         size = cd.GetCorner(side, bevel);
     791               0 :         printf("c=%d%X%d ", PRInt32(size), side, bevel);
     792                 :       }
     793                 :     }
     794               0 :     printf("\n");
     795                 :   }
     796               0 :   printf("***** END TABLE CELL MAP DUMP *****\n");
     797               0 : }
     798                 : #endif
     799                 : 
     800                 : nsTableCellFrame*
     801               0 : nsTableCellMap::GetCellInfoAt(PRInt32  aRowIndex,
     802                 :                               PRInt32  aColIndex,
     803                 :                               bool*  aOriginates,
     804                 :                               PRInt32* aColSpan) const
     805                 : {
     806               0 :   PRInt32 rowIndex = aRowIndex;
     807               0 :   nsCellMap* cellMap = mFirstMap;
     808               0 :   while (cellMap) {
     809               0 :     if (cellMap->GetRowCount() > rowIndex) {
     810               0 :       return cellMap->GetCellInfoAt(*this, rowIndex, aColIndex, aOriginates, aColSpan);
     811                 :     }
     812               0 :     rowIndex -= cellMap->GetRowCount();
     813               0 :     cellMap = cellMap->GetNextSibling();
     814                 :   }
     815               0 :   return nsnull;
     816                 : }
     817                 : 
     818                 : PRInt32
     819               0 : nsTableCellMap::GetIndexByRowAndColumn(PRInt32 aRow, PRInt32 aColumn) const
     820                 : {
     821               0 :   PRInt32 index = 0;
     822                 : 
     823               0 :   PRInt32 colCount = mCols.Length();
     824               0 :   PRInt32 rowIndex = aRow;
     825                 : 
     826               0 :   nsCellMap* cellMap = mFirstMap;
     827               0 :   while (cellMap) {
     828               0 :     PRInt32 rowCount = cellMap->GetRowCount();
     829               0 :     if (rowIndex >= rowCount) {
     830                 :       // If the rowCount is less than the rowIndex, this means that the index is
     831                 :       // not within the current map. If so, get the index of the last cell in
     832                 :       // the last row.
     833               0 :       rowIndex -= rowCount;
     834                 : 
     835               0 :       PRInt32 cellMapIdx = cellMap->GetHighestIndex(colCount);
     836               0 :       if (cellMapIdx != -1)
     837               0 :         index += cellMapIdx + 1;
     838                 : 
     839                 :     } else {
     840                 :       // Index is in valid range for this cellmap, so get the index of rowIndex
     841                 :       // and aColumn.
     842                 :       PRInt32 cellMapIdx = cellMap->GetIndexByRowAndColumn(colCount, rowIndex,
     843               0 :                                                            aColumn);
     844               0 :       if (cellMapIdx == -1)
     845               0 :         return -1; // no cell at the given row and column.
     846                 : 
     847               0 :       index += cellMapIdx;
     848               0 :       return index;  // no need to look through further maps here
     849                 :     }
     850                 : 
     851               0 :     cellMap = cellMap->GetNextSibling();
     852                 :   }
     853                 : 
     854               0 :   return -1;
     855                 : }
     856                 : 
     857                 : void
     858               0 : nsTableCellMap::GetRowAndColumnByIndex(PRInt32 aIndex,
     859                 :                                        PRInt32 *aRow, PRInt32 *aColumn) const
     860                 : {
     861               0 :   *aRow = -1;
     862               0 :   *aColumn = -1;
     863                 : 
     864               0 :   PRInt32 colCount = mCols.Length();
     865                 : 
     866               0 :   PRInt32 previousRows = 0;
     867               0 :   PRInt32 index = aIndex;
     868                 : 
     869               0 :   nsCellMap* cellMap = mFirstMap;
     870               0 :   while (cellMap) {
     871               0 :     PRInt32 rowCount = cellMap->GetRowCount();
     872                 :     // Determine the highest possible index in this map to see
     873                 :     // if wanted index is in here.
     874               0 :     PRInt32 cellMapIdx = cellMap->GetHighestIndex(colCount);
     875               0 :     if (cellMapIdx == -1) {
     876                 :       // The index is not within this map, increase the total row index
     877                 :       // accordingly.
     878               0 :       previousRows += rowCount;
     879                 :     } else {
     880               0 :       if (index > cellMapIdx) {
     881                 :         // The index is not within this map, so decrease it by the cellMapIdx
     882                 :         // determined index and increase the total row index accordingly.
     883               0 :         index -= cellMapIdx + 1;
     884               0 :         previousRows += rowCount;
     885                 :       } else {
     886               0 :         cellMap->GetRowAndColumnByIndex(colCount, index, aRow, aColumn);
     887                 :         // If there were previous indexes, take them into account.
     888               0 :         *aRow += previousRows;
     889               0 :         return; // no need to look any further.
     890                 :       }
     891                 :     }
     892                 : 
     893               0 :     cellMap = cellMap->GetNextSibling();
     894                 :   }
     895                 : }
     896                 : 
     897               0 : bool nsTableCellMap::RowIsSpannedInto(PRInt32 aRowIndex,
     898                 :                                         PRInt32 aNumEffCols) const
     899                 : {
     900               0 :   PRInt32 rowIndex = aRowIndex;
     901               0 :   nsCellMap* cellMap = mFirstMap;
     902               0 :   while (cellMap) {
     903               0 :     if (cellMap->GetRowCount() > rowIndex) {
     904               0 :       return cellMap->RowIsSpannedInto(rowIndex, aNumEffCols);
     905                 :     }
     906               0 :     rowIndex -= cellMap->GetRowCount();
     907               0 :     cellMap = cellMap->GetNextSibling();
     908                 :   }
     909               0 :   return false;
     910                 : }
     911                 : 
     912               0 : bool nsTableCellMap::RowHasSpanningCells(PRInt32 aRowIndex,
     913                 :                                            PRInt32 aNumEffCols) const
     914                 : {
     915               0 :   PRInt32 rowIndex = aRowIndex;
     916               0 :   nsCellMap* cellMap = mFirstMap;
     917               0 :   while (cellMap) {
     918               0 :     if (cellMap->GetRowCount() > rowIndex) {
     919               0 :       return cellMap->RowHasSpanningCells(rowIndex, aNumEffCols);
     920                 :     }
     921               0 :     rowIndex -= cellMap->GetRowCount();
     922               0 :     cellMap = cellMap->GetNextSibling();
     923                 :   }
     924               0 :   return false;
     925                 : }
     926                 : 
     927               0 : void nsTableCellMap::ExpandZeroColSpans()
     928                 : {
     929               0 :   mTableFrame.SetNeedColSpanExpansion(false); // mark the work done
     930               0 :   mTableFrame.SetHasZeroColSpans(false); // reset the bit, if there is a
     931                 :                                             // zerospan it will be set again.
     932               0 :   nsCellMap* cellMap = mFirstMap;
     933               0 :   while (cellMap) {
     934               0 :     cellMap->ExpandZeroColSpans(*this);
     935               0 :     cellMap = cellMap->GetNextSibling();
     936                 :   }
     937               0 : }
     938                 : 
     939                 : void
     940               0 : nsTableCellMap::ResetTopStart(PRUint8    aSide,
     941                 :                               nsCellMap& aCellMap,
     942                 :                               PRUint32   aRowIndex,
     943                 :                               PRUint32   aColIndex,
     944                 :                               bool       aIsLowerRight)
     945                 : {
     946               0 :   if (!mBCInfo || aIsLowerRight) ABORT0();
     947                 : 
     948                 :   BCCellData* cellData;
     949               0 :   BCData* bcData = nsnull;
     950                 : 
     951               0 :   switch(aSide) {
     952                 :   case NS_SIDE_BOTTOM:
     953               0 :     aRowIndex++;
     954                 :     // FALLTHROUGH
     955                 :   case NS_SIDE_TOP:
     956               0 :     cellData = (BCCellData*)aCellMap.GetDataAt(aRowIndex, aColIndex);
     957               0 :     if (cellData) {
     958               0 :       bcData = &cellData->mData;
     959                 :     }
     960                 :     else {
     961               0 :       NS_ASSERTION(aSide == NS_SIDE_BOTTOM, "program error");
     962                 :       // try the next row group
     963               0 :       nsCellMap* cellMap = aCellMap.GetNextSibling();
     964               0 :       if (cellMap) {
     965               0 :         cellData = (BCCellData*)cellMap->GetDataAt(0, aColIndex);
     966               0 :         if (cellData) {
     967               0 :           bcData = &cellData->mData;
     968                 :         }
     969                 :         else {
     970               0 :           bcData = GetBottomMostBorder(aColIndex);
     971                 :         }
     972                 :       }
     973                 :     }
     974               0 :     break;
     975                 :   case NS_SIDE_RIGHT:
     976               0 :     aColIndex++;
     977                 :     // FALLTHROUGH
     978                 :   case NS_SIDE_LEFT:
     979               0 :     cellData = (BCCellData*)aCellMap.GetDataAt(aRowIndex, aColIndex);
     980               0 :     if (cellData) {
     981               0 :       bcData = &cellData->mData;
     982                 :     }
     983                 :     else {
     984               0 :       NS_ASSERTION(aSide == NS_SIDE_RIGHT, "program error");
     985               0 :       bcData = GetRightMostBorder(aRowIndex);
     986                 :     }
     987               0 :     break;
     988                 :   }
     989               0 :   if (bcData) {
     990               0 :     bcData->SetTopStart(false);
     991                 :   }
     992                 : }
     993                 : 
     994                 : // store the aSide border segment at coord = (aRowIndex, aColIndex). For top/left, store
     995                 : // the info at coord. For bottom/left store it at the adjacent location so that it is
     996                 : // top/left at that location. If the new location is at the right or bottom edge of the
     997                 : // table, then store it one of the special arrays (right most borders, bottom most borders).
     998                 : void
     999               0 : nsTableCellMap::SetBCBorderEdge(mozilla::css::Side aSide,
    1000                 :                                 nsCellMap&    aCellMap,
    1001                 :                                 PRUint32      aCellMapStart,
    1002                 :                                 PRUint32      aRowIndex,
    1003                 :                                 PRUint32      aColIndex,
    1004                 :                                 PRUint32      aLength,
    1005                 :                                 BCBorderOwner aOwner,
    1006                 :                                 nscoord       aSize,
    1007                 :                                 bool          aChanged)
    1008                 : {
    1009               0 :   if (!mBCInfo) ABORT0();
    1010                 : 
    1011                 :   BCCellData* cellData;
    1012                 :   PRInt32 lastIndex, xIndex, yIndex;
    1013               0 :   PRInt32 xPos = aColIndex;
    1014               0 :   PRInt32 yPos = aRowIndex;
    1015               0 :   PRInt32 rgYPos = aRowIndex - aCellMapStart;
    1016                 :   bool changed;
    1017                 : 
    1018               0 :   switch(aSide) {
    1019                 :   case NS_SIDE_BOTTOM:
    1020               0 :     rgYPos++;
    1021               0 :     yPos++;
    1022                 :   case NS_SIDE_TOP:
    1023               0 :     lastIndex = xPos + aLength - 1;
    1024               0 :     for (xIndex = xPos; xIndex <= lastIndex; xIndex++) {
    1025               0 :       changed = aChanged && (xIndex == xPos);
    1026               0 :       BCData* bcData = nsnull;
    1027               0 :       cellData = (BCCellData*)aCellMap.GetDataAt(rgYPos, xIndex);
    1028               0 :       if (!cellData) {
    1029               0 :         PRInt32 numRgRows = aCellMap.GetRowCount();
    1030               0 :         if (yPos < numRgRows) { // add a dead cell data
    1031               0 :           nsIntRect damageArea;
    1032                 :           cellData = (BCCellData*)aCellMap.AppendCell(*this, nsnull, rgYPos,
    1033               0 :                                                        false, 0, damageArea);
    1034               0 :           if (!cellData) ABORT0();
    1035                 :         }
    1036                 :         else {
    1037               0 :           NS_ASSERTION(aSide == NS_SIDE_BOTTOM, "program error");
    1038                 :           // try the next non empty row group
    1039               0 :           nsCellMap* cellMap = aCellMap.GetNextSibling();
    1040               0 :           while (cellMap && (0 == cellMap->GetRowCount())) {
    1041               0 :             cellMap = cellMap->GetNextSibling();
    1042                 :           }
    1043               0 :           if (cellMap) {
    1044               0 :             cellData = (BCCellData*)cellMap->GetDataAt(0, xIndex);
    1045               0 :             if (!cellData) { // add a dead cell
    1046               0 :               nsIntRect damageArea;
    1047                 :               cellData = (BCCellData*)cellMap->AppendCell(*this, nsnull, 0,
    1048                 :                                                            false, 0,
    1049               0 :                                                            damageArea);
    1050                 :             }
    1051                 :           }
    1052                 :           else { // must be at the end of the table
    1053               0 :             bcData = GetBottomMostBorder(xIndex);
    1054                 :           }
    1055                 :         }
    1056                 :       }
    1057               0 :       if (!bcData && cellData) {
    1058               0 :         bcData = &cellData->mData;
    1059                 :       }
    1060               0 :       if (bcData) {
    1061               0 :         bcData->SetTopEdge(aOwner, aSize, changed);
    1062                 :       }
    1063               0 :       else NS_ERROR("Cellmap: Top edge not found");
    1064                 :     }
    1065               0 :     break;
    1066                 :   case NS_SIDE_RIGHT:
    1067               0 :     xPos++;
    1068                 :   case NS_SIDE_LEFT:
    1069                 :     // since top, bottom borders were set, there should already be a cellData entry
    1070               0 :     lastIndex = rgYPos + aLength - 1;
    1071               0 :     for (yIndex = rgYPos; yIndex <= lastIndex; yIndex++) {
    1072               0 :       changed = aChanged && (yIndex == rgYPos);
    1073               0 :       cellData = (BCCellData*)aCellMap.GetDataAt(yIndex, xPos);
    1074               0 :       if (cellData) {
    1075               0 :         cellData->mData.SetLeftEdge(aOwner, aSize, changed);
    1076                 :       }
    1077                 :       else {
    1078               0 :         NS_ASSERTION(aSide == NS_SIDE_RIGHT, "program error");
    1079               0 :         BCData* bcData = GetRightMostBorder(yIndex + aCellMapStart);
    1080               0 :         if (bcData) {
    1081               0 :           bcData->SetLeftEdge(aOwner, aSize, changed);
    1082                 :         }
    1083               0 :         else NS_ERROR("Cellmap: Left edge not found");
    1084                 :       }
    1085                 :     }
    1086               0 :     break;
    1087                 :   }
    1088                 : }
    1089                 : 
    1090                 : // store corner info (aOwner, aSubSize, aBevel). For aCorner = eTopLeft, store the info at
    1091                 : // (aRowIndex, aColIndex). For eTopRight, store it in the entry to the right where
    1092                 : // it would be top left. For eBottomRight, store it in the entry to the bottom. etc.
    1093                 : void
    1094               0 : nsTableCellMap::SetBCBorderCorner(Corner      aCorner,
    1095                 :                                   nsCellMap&  aCellMap,
    1096                 :                                   PRUint32    aCellMapStart,
    1097                 :                                   PRUint32    aRowIndex,
    1098                 :                                   PRUint32    aColIndex,
    1099                 :                                   mozilla::css::Side aOwner,
    1100                 :                                   nscoord     aSubSize,
    1101                 :                                   bool        aBevel,
    1102                 :                                   bool        aIsBottomRight)
    1103                 : {
    1104               0 :   if (!mBCInfo) ABORT0();
    1105                 : 
    1106               0 :   if (aIsBottomRight) {
    1107               0 :     mBCInfo->mLowerRightCorner.SetCorner(aSubSize, aOwner, aBevel);
    1108               0 :     return;
    1109                 :   }
    1110                 : 
    1111               0 :   PRInt32 xPos = aColIndex;
    1112               0 :   PRInt32 yPos = aRowIndex;
    1113               0 :   PRInt32 rgYPos = aRowIndex - aCellMapStart;
    1114                 : 
    1115               0 :   if (eTopRight == aCorner) {
    1116               0 :     xPos++;
    1117                 :   }
    1118               0 :   else if (eBottomRight == aCorner) {
    1119               0 :     xPos++;
    1120               0 :     rgYPos++;
    1121               0 :     yPos++;
    1122                 :   }
    1123               0 :   else if (eBottomLeft == aCorner) {
    1124               0 :     rgYPos++;
    1125               0 :     yPos++;
    1126                 :   }
    1127                 : 
    1128               0 :   BCCellData* cellData = nsnull;
    1129               0 :   BCData*     bcData   = nsnull;
    1130               0 :   if (GetColCount() <= xPos) {
    1131               0 :     NS_ASSERTION(xPos == GetColCount(), "program error");
    1132                 :     // at the right edge of the table as we checked the corner before
    1133               0 :     NS_ASSERTION(!aIsBottomRight, "should be handled before");
    1134               0 :     bcData = GetRightMostBorder(yPos);
    1135                 :   }
    1136                 :   else {
    1137               0 :     cellData = (BCCellData*)aCellMap.GetDataAt(rgYPos, xPos);
    1138               0 :     if (!cellData) {
    1139               0 :       PRInt32 numRgRows = aCellMap.GetRowCount();
    1140               0 :       if (yPos < numRgRows) { // add a dead cell data
    1141               0 :         nsIntRect damageArea;
    1142                 :         cellData = (BCCellData*)aCellMap.AppendCell(*this, nsnull, rgYPos,
    1143               0 :                                                      false, 0, damageArea);
    1144                 :       }
    1145                 :       else {
    1146                 :         // try the next non empty row group
    1147               0 :         nsCellMap* cellMap = aCellMap.GetNextSibling();
    1148               0 :         while (cellMap && (0 == cellMap->GetRowCount())) {
    1149               0 :           cellMap = cellMap->GetNextSibling();
    1150                 :         }
    1151               0 :         if (cellMap) {
    1152               0 :           cellData = (BCCellData*)cellMap->GetDataAt(0, xPos);
    1153               0 :           if (!cellData) { // add a dead cell
    1154               0 :             nsIntRect damageArea;
    1155                 :             cellData = (BCCellData*)cellMap->AppendCell(*this, nsnull, 0,
    1156               0 :                                                          false, 0, damageArea);
    1157                 :           }
    1158                 :         }
    1159                 :         else { // must be at the bottom of the table
    1160               0 :           bcData = GetBottomMostBorder(xPos);
    1161                 :         }
    1162                 :       }
    1163                 :     }
    1164                 :   }
    1165               0 :   if (!bcData && cellData) {
    1166               0 :     bcData = &cellData->mData;
    1167                 :   }
    1168               0 :   if (bcData) {
    1169               0 :     bcData->SetCorner(aSubSize, aOwner, aBevel);
    1170                 :   }
    1171               0 :   else NS_ERROR("program error: Corner not found");
    1172                 : }
    1173                 : 
    1174               0 : nsCellMap::nsCellMap(nsTableRowGroupFrame* aRowGroup, bool aIsBC)
    1175                 :   : mRows(8), mContentRowCount(0), mRowGroupFrame(aRowGroup),
    1176                 :     mNextSibling(nsnull), mIsBC(aIsBC),
    1177               0 :     mPresContext(aRowGroup->PresContext())
    1178                 : {
    1179               0 :   MOZ_COUNT_CTOR(nsCellMap);
    1180               0 :   NS_ASSERTION(mPresContext, "Must have prescontext");
    1181               0 : }
    1182                 : 
    1183               0 : nsCellMap::~nsCellMap()
    1184                 : {
    1185               0 :   MOZ_COUNT_DTOR(nsCellMap);
    1186                 : 
    1187               0 :   PRUint32 mapRowCount = mRows.Length();
    1188               0 :   for (PRUint32 rowX = 0; rowX < mapRowCount; rowX++) {
    1189               0 :     CellDataArray &row = mRows[rowX];
    1190               0 :     PRUint32 colCount = row.Length();
    1191               0 :     for (PRUint32 colX = 0; colX < colCount; colX++) {
    1192               0 :       DestroyCellData(row[colX]);
    1193                 :     }
    1194                 :   }
    1195               0 : }
    1196                 : 
    1197                 : /* static */
    1198                 : void
    1199            1404 : nsCellMap::Init()
    1200                 : {
    1201            1404 :   NS_ABORT_IF_FALSE(!sEmptyRow, "How did that happen?");
    1202            1404 :   sEmptyRow = new nsCellMap::CellDataArray();
    1203            1404 : }
    1204                 : 
    1205                 : /* static */
    1206                 : void
    1207            1403 : nsCellMap::Shutdown()
    1208                 : {
    1209            1403 :   delete sEmptyRow;
    1210            1403 :   sEmptyRow = nsnull;
    1211            1403 : }
    1212                 : 
    1213                 : nsTableCellFrame*
    1214               0 : nsCellMap::GetCellFrame(PRInt32   aRowIndexIn,
    1215                 :                         PRInt32   aColIndexIn,
    1216                 :                         CellData& aData,
    1217                 :                         bool      aUseRowIfOverlap) const
    1218                 : {
    1219               0 :   PRInt32 rowIndex = aRowIndexIn - aData.GetRowSpanOffset();
    1220               0 :   PRInt32 colIndex = aColIndexIn - aData.GetColSpanOffset();
    1221               0 :   if (aData.IsOverlap()) {
    1222               0 :     if (aUseRowIfOverlap) {
    1223               0 :       colIndex = aColIndexIn;
    1224                 :     }
    1225                 :     else {
    1226               0 :       rowIndex = aRowIndexIn;
    1227                 :     }
    1228                 :   }
    1229                 : 
    1230                 :   CellData* data =
    1231               0 :     mRows.SafeElementAt(rowIndex, *sEmptyRow).SafeElementAt(colIndex);
    1232               0 :   if (data) {
    1233               0 :     return data->GetCellFrame();
    1234                 :   }
    1235               0 :   return nsnull;
    1236                 : }
    1237                 : 
    1238                 : PRInt32
    1239               0 : nsCellMap::GetHighestIndex(PRInt32 aColCount)
    1240                 : {
    1241               0 :   PRInt32 index = -1;
    1242               0 :   PRInt32 rowCount = mRows.Length();
    1243               0 :   for (PRInt32 rowIdx = 0; rowIdx < rowCount; rowIdx++) {
    1244               0 :     const CellDataArray& row = mRows[rowIdx];
    1245                 : 
    1246               0 :     for (PRInt32 colIdx = 0; colIdx < aColCount; colIdx++) {
    1247               0 :       CellData* data = row.SafeElementAt(colIdx);
    1248                 :       // No data means row doesn't have more cells.
    1249               0 :       if (!data)
    1250               0 :         break;
    1251                 : 
    1252               0 :       if (data->IsOrig())
    1253               0 :         index++;
    1254                 :     }
    1255                 :   }
    1256                 : 
    1257               0 :   return index;
    1258                 : }
    1259                 : 
    1260                 : PRInt32
    1261               0 : nsCellMap::GetIndexByRowAndColumn(PRInt32 aColCount,
    1262                 :                                   PRInt32 aRow, PRInt32 aColumn) const
    1263                 : {
    1264               0 :   if (PRUint32(aRow) >= mRows.Length())
    1265               0 :     return -1;
    1266                 : 
    1267               0 :   PRInt32 index = -1;
    1268               0 :   PRInt32 lastColsIdx = aColCount - 1;
    1269                 : 
    1270                 :   // Find row index of the cell where row span is started.
    1271               0 :   const CellDataArray& row = mRows[aRow];
    1272               0 :   CellData* data = row.SafeElementAt(aColumn);
    1273               0 :   PRInt32 origRow = data ? aRow - data->GetRowSpanOffset() : aRow;
    1274                 : 
    1275                 :   // Calculate cell index.
    1276               0 :   for (PRInt32 rowIdx = 0; rowIdx <= origRow; rowIdx++) {
    1277               0 :     const CellDataArray& row = mRows[rowIdx];
    1278               0 :     PRInt32 colCount = (rowIdx == origRow) ? aColumn : lastColsIdx;
    1279                 : 
    1280               0 :     for (PRInt32 colIdx = 0; colIdx <= colCount; colIdx++) {
    1281               0 :       data = row.SafeElementAt(colIdx);
    1282                 :       // No data means row doesn't have more cells.
    1283               0 :       if (!data)
    1284               0 :         break;
    1285                 : 
    1286               0 :       if (data->IsOrig())
    1287               0 :         index++;
    1288                 :     }
    1289                 :   }
    1290                 : 
    1291                 :   // Given row and column don't point to the cell.
    1292               0 :   if (!data)
    1293               0 :     return -1;
    1294                 : 
    1295               0 :   return index;
    1296                 : }
    1297                 : 
    1298                 : void
    1299               0 : nsCellMap::GetRowAndColumnByIndex(PRInt32 aColCount, PRInt32 aIndex,
    1300                 :                                   PRInt32 *aRow, PRInt32 *aColumn) const
    1301                 : {
    1302               0 :   *aRow = -1;
    1303               0 :   *aColumn = -1;
    1304                 : 
    1305               0 :   PRInt32 index = aIndex;
    1306               0 :   PRInt32 rowCount = mRows.Length();
    1307                 : 
    1308               0 :   for (PRInt32 rowIdx = 0; rowIdx < rowCount; rowIdx++) {
    1309               0 :     const CellDataArray& row = mRows[rowIdx];
    1310                 : 
    1311               0 :     for (PRInt32 colIdx = 0; colIdx < aColCount; colIdx++) {
    1312               0 :       CellData* data = row.SafeElementAt(colIdx);
    1313                 : 
    1314                 :       // The row doesn't have more cells.
    1315               0 :       if (!data)
    1316               0 :         break;
    1317                 : 
    1318               0 :       if (data->IsOrig())
    1319               0 :         index--;
    1320                 : 
    1321               0 :       if (index < 0) {
    1322               0 :         *aRow = rowIdx;
    1323               0 :         *aColumn = colIdx;
    1324               0 :         return;
    1325                 :       }
    1326                 :     }
    1327                 :   }
    1328                 : }
    1329                 : 
    1330               0 : bool nsCellMap::Grow(nsTableCellMap& aMap,
    1331                 :                        PRInt32         aNumRows,
    1332                 :                        PRInt32         aRowIndex)
    1333                 : {
    1334               0 :   NS_ASSERTION(aNumRows >= 1, "Why are we calling this?");
    1335                 : 
    1336                 :   // Get the number of cols we want to use for preallocating the row arrays.
    1337               0 :   PRInt32 numCols = aMap.GetColCount();
    1338               0 :   if (numCols == 0) {
    1339               0 :     numCols = 4;
    1340                 :   }
    1341               0 :   PRUint32 startRowIndex = (aRowIndex >= 0) ? aRowIndex : mRows.Length();
    1342               0 :   NS_ASSERTION(startRowIndex <= mRows.Length(), "Missing grow call inbetween");
    1343                 : 
    1344               0 :   return mRows.InsertElementsAt(startRowIndex, aNumRows, numCols) != nsnull;
    1345                 : }
    1346                 : 
    1347               0 : void nsCellMap::GrowRow(CellDataArray& aRow,
    1348                 :                         PRInt32        aNumCols)
    1349                 : 
    1350                 : {
    1351                 :   // Have to have the cast to get the template to do the right thing.
    1352               0 :   aRow.InsertElementsAt(aRow.Length(), aNumCols, (CellData*)nsnull);
    1353               0 : }
    1354                 : 
    1355                 : void
    1356               0 : nsCellMap::InsertRows(nsTableCellMap&             aMap,
    1357                 :                       nsTArray<nsTableRowFrame*>& aRows,
    1358                 :                       PRInt32                     aFirstRowIndex,
    1359                 :                       bool                        aConsiderSpans,
    1360                 :                       PRInt32                     aRgFirstRowIndex,
    1361                 :                       nsIntRect&                  aDamageArea)
    1362                 : {
    1363               0 :   PRInt32 numCols = aMap.GetColCount();
    1364               0 :   NS_ASSERTION(aFirstRowIndex >= 0, "nsCellMap::InsertRows called with negative rowIndex");
    1365               0 :   if (PRUint32(aFirstRowIndex) > mRows.Length()) {
    1366                 :     // create (aFirstRowIndex - mRows.Length()) empty rows up to aFirstRowIndex
    1367               0 :     PRInt32 numEmptyRows = aFirstRowIndex - mRows.Length();
    1368               0 :     if (!Grow(aMap, numEmptyRows)) {
    1369               0 :       return;
    1370                 :     }
    1371                 :   }
    1372                 : 
    1373               0 :   if (!aConsiderSpans) {
    1374                 :     // update mContentRowCount, since non-empty rows will be added
    1375               0 :     mContentRowCount = NS_MAX(aFirstRowIndex, mContentRowCount);
    1376               0 :     ExpandWithRows(aMap, aRows, aFirstRowIndex, aRgFirstRowIndex, aDamageArea);
    1377               0 :     return;
    1378                 :   }
    1379                 : 
    1380                 :   // if any cells span into or out of the row being inserted, then rebuild
    1381                 :   bool spansCauseRebuild = CellsSpanInOrOut(aFirstRowIndex,
    1382               0 :                                               aFirstRowIndex, 0, numCols - 1);
    1383                 : 
    1384                 :   // update mContentRowCount, since non-empty rows will be added
    1385               0 :   mContentRowCount = NS_MAX(aFirstRowIndex, mContentRowCount);
    1386                 : 
    1387                 :   // if any of the new cells span out of the new rows being added, then rebuild
    1388                 :   // XXX it would be better to only rebuild the portion of the map that follows the new rows
    1389               0 :   if (!spansCauseRebuild && (PRUint32(aFirstRowIndex) < mRows.Length())) {
    1390               0 :     spansCauseRebuild = CellsSpanOut(aRows);
    1391                 :   }
    1392               0 :   if (spansCauseRebuild) {
    1393               0 :     aMap.RebuildConsideringRows(this, aFirstRowIndex, &aRows, 0, aDamageArea);
    1394                 :   }
    1395                 :   else {
    1396               0 :     ExpandWithRows(aMap, aRows, aFirstRowIndex, aRgFirstRowIndex, aDamageArea);
    1397                 :   }
    1398                 : }
    1399                 : 
    1400                 : void
    1401               0 : nsCellMap::RemoveRows(nsTableCellMap& aMap,
    1402                 :                       PRInt32         aFirstRowIndex,
    1403                 :                       PRInt32         aNumRowsToRemove,
    1404                 :                       bool            aConsiderSpans,
    1405                 :                       PRInt32         aRgFirstRowIndex,
    1406                 :                       nsIntRect&      aDamageArea)
    1407                 : {
    1408               0 :   PRInt32 numRows = mRows.Length();
    1409               0 :   PRInt32 numCols = aMap.GetColCount();
    1410                 : 
    1411               0 :   if (aFirstRowIndex >= numRows) {
    1412                 :     // reduce the content based row count based on the function arguments
    1413                 :     // as they are known to be real rows even if the cell map did not create
    1414                 :     // rows for them before.
    1415               0 :     mContentRowCount -= aNumRowsToRemove;
    1416               0 :     return;
    1417                 :   }
    1418               0 :   if (!aConsiderSpans) {
    1419                 :     ShrinkWithoutRows(aMap, aFirstRowIndex, aNumRowsToRemove, aRgFirstRowIndex,
    1420               0 :                       aDamageArea);
    1421               0 :     return;
    1422                 :   }
    1423               0 :   PRInt32 endRowIndex = aFirstRowIndex + aNumRowsToRemove - 1;
    1424               0 :   if (endRowIndex >= numRows) {
    1425               0 :     NS_ERROR("nsCellMap::RemoveRows tried to remove too many rows");
    1426               0 :     endRowIndex = numRows - 1;
    1427                 :   }
    1428                 :   bool spansCauseRebuild = CellsSpanInOrOut(aFirstRowIndex, endRowIndex,
    1429               0 :                                               0, numCols - 1);
    1430               0 :   if (spansCauseRebuild) {
    1431                 :     aMap.RebuildConsideringRows(this, aFirstRowIndex, nsnull, aNumRowsToRemove,
    1432               0 :                                 aDamageArea);
    1433                 :   }
    1434                 :   else {
    1435                 :     ShrinkWithoutRows(aMap, aFirstRowIndex, aNumRowsToRemove, aRgFirstRowIndex,
    1436               0 :                       aDamageArea);
    1437                 :   }
    1438                 : }
    1439                 : 
    1440                 : 
    1441                 : 
    1442                 : 
    1443                 : CellData*
    1444               0 : nsCellMap::AppendCell(nsTableCellMap&   aMap,
    1445                 :                       nsTableCellFrame* aCellFrame,
    1446                 :                       PRInt32           aRowIndex,
    1447                 :                       bool              aRebuildIfNecessary,
    1448                 :                       PRInt32           aRgFirstRowIndex,
    1449                 :                       nsIntRect&        aDamageArea,
    1450                 :                       PRInt32*          aColToBeginSearch)
    1451                 : {
    1452               0 :   NS_ASSERTION(!!aMap.mBCInfo == mIsBC, "BC state mismatch");
    1453               0 :   PRInt32 origNumMapRows = mRows.Length();
    1454               0 :   PRInt32 origNumCols = aMap.GetColCount();
    1455               0 :   bool    zeroRowSpan = false;
    1456                 :   PRInt32 rowSpan = (aCellFrame) ? GetRowSpanForNewCell(aCellFrame, aRowIndex,
    1457               0 :                                                         zeroRowSpan) : 1;
    1458                 :   // add new rows if necessary
    1459               0 :   PRInt32 endRowIndex = aRowIndex + rowSpan - 1;
    1460               0 :   if (endRowIndex >= origNumMapRows) {
    1461                 :     // XXXbz handle allocation failures?
    1462               0 :     Grow(aMap, 1 + endRowIndex - origNumMapRows);
    1463                 :   }
    1464                 : 
    1465                 :   // get the first null or dead CellData in the desired row. It will equal origNumCols if there are none
    1466               0 :   CellData* origData = nsnull;
    1467               0 :   PRInt32 startColIndex = 0;
    1468               0 :   if (aColToBeginSearch)
    1469               0 :     startColIndex = *aColToBeginSearch;
    1470               0 :   for (; startColIndex < origNumCols; startColIndex++) {
    1471               0 :     CellData* data = GetDataAt(aRowIndex, startColIndex);
    1472               0 :     if (!data)
    1473               0 :       break;
    1474                 :     // The border collapse code relies on having multiple dead cell data entries
    1475                 :     // in a row.
    1476               0 :     if (data->IsDead() && aCellFrame) {
    1477               0 :       origData = data;
    1478               0 :       break;
    1479                 :     }
    1480               0 :     if (data->IsZeroColSpan() ) {
    1481                 :       // appending a cell collapses zerospans.
    1482               0 :       CollapseZeroColSpan(aMap, data, aRowIndex, startColIndex);
    1483                 :       // ask again for the data as it should be modified
    1484               0 :       origData = GetDataAt(aRowIndex, startColIndex);
    1485               0 :       NS_ASSERTION(origData->IsDead(),
    1486                 :                    "The cellposition should have been cleared");
    1487               0 :       break;
    1488                 :     }
    1489                 :   }
    1490                 :   // We found the place to append the cell, when the next cell is appended
    1491                 :   // the next search does not need to duplicate the search but can start
    1492                 :   // just at the next cell.
    1493               0 :   if (aColToBeginSearch)
    1494               0 :     *aColToBeginSearch =  startColIndex + 1;
    1495                 : 
    1496               0 :   bool    zeroColSpan = false;
    1497                 :   PRInt32 colSpan = (aCellFrame) ?
    1498               0 :                     GetColSpanForNewCell(*aCellFrame, zeroColSpan) : 1;
    1499               0 :   if (zeroColSpan) {
    1500               0 :     aMap.mTableFrame.SetHasZeroColSpans(true);
    1501               0 :     aMap.mTableFrame.SetNeedColSpanExpansion(true);
    1502                 :   }
    1503                 : 
    1504                 :   // if the new cell could potentially span into other rows and collide with
    1505                 :   // originating cells there, we will play it safe and just rebuild the map
    1506               0 :   if (aRebuildIfNecessary && (aRowIndex < mContentRowCount - 1) && (rowSpan > 1)) {
    1507               0 :     nsAutoTArray<nsTableCellFrame*, 1> newCellArray;
    1508               0 :     newCellArray.AppendElement(aCellFrame);
    1509               0 :     aMap.RebuildConsideringCells(this, &newCellArray, aRowIndex, startColIndex, true, aDamageArea);
    1510               0 :     return origData;
    1511                 :   }
    1512               0 :   mContentRowCount = NS_MAX(mContentRowCount, aRowIndex + 1);
    1513                 : 
    1514                 :   // add new cols to the table map if necessary
    1515               0 :   PRInt32 endColIndex = startColIndex + colSpan - 1;
    1516               0 :   if (endColIndex >= origNumCols) {
    1517               0 :     NS_ASSERTION(aCellFrame, "dead cells should not require new columns");
    1518               0 :     aMap.AddColsAtEnd(1 + endColIndex - origNumCols);
    1519                 :   }
    1520                 : 
    1521                 :   // Setup CellData for this cell
    1522               0 :   if (origData) {
    1523               0 :     NS_ASSERTION(origData->IsDead(), "replacing a non dead cell is a memory leak");
    1524               0 :     if (aCellFrame) { // do nothing to replace a dead cell with a dead cell
    1525               0 :       origData->Init(aCellFrame);
    1526                 :       // we are replacing a dead cell, increase the number of cells
    1527                 :       // originating at this column
    1528               0 :       nsColInfo* colInfo = aMap.GetColInfoAt(startColIndex);
    1529               0 :       NS_ASSERTION(colInfo, "access to a non existing column");
    1530               0 :       if (colInfo) {
    1531               0 :         colInfo->mNumCellsOrig++;
    1532                 :       }
    1533                 :     }
    1534                 :   }
    1535                 :   else {
    1536               0 :     origData = AllocCellData(aCellFrame);
    1537               0 :     if (!origData) ABORT1(origData);
    1538               0 :     SetDataAt(aMap, *origData, aRowIndex, startColIndex);
    1539                 :   }
    1540                 : 
    1541               0 :   if (aRebuildIfNecessary) {
    1542                 :     //the caller depends on the damageArea
    1543                 :     // The special case for zeroRowSpan is to adjust for the '2' in
    1544                 :     // GetRowSpanForNewCell.
    1545                 :     PRUint32 height = zeroRowSpan ? endRowIndex - aRowIndex  :
    1546               0 :                                     1 + endRowIndex - aRowIndex;
    1547                 :     SetDamageArea(startColIndex, aRgFirstRowIndex + aRowIndex,
    1548               0 :                   1 + endColIndex - startColIndex, height, aDamageArea);
    1549                 :   }
    1550                 : 
    1551               0 :   if (!aCellFrame) {
    1552               0 :     return origData;
    1553                 :   }
    1554                 : 
    1555                 :   // initialize the cell frame
    1556               0 :   aCellFrame->SetColIndex(startColIndex);
    1557                 : 
    1558                 :   // Create CellData objects for the rows that this cell spans. Set
    1559                 :   // their mOrigCell to nsnull and their mSpanData to point to data.
    1560               0 :   for (PRInt32 rowX = aRowIndex; rowX <= endRowIndex; rowX++) {
    1561                 :     // The row at rowX will need to have at least endColIndex columns
    1562               0 :     mRows[rowX].SetCapacity(endColIndex);
    1563               0 :     for (PRInt32 colX = startColIndex; colX <= endColIndex; colX++) {
    1564               0 :       if ((rowX != aRowIndex) || (colX != startColIndex)) { // skip orig cell data done above
    1565               0 :         CellData* cellData = GetDataAt(rowX, colX);
    1566               0 :         if (cellData) {
    1567               0 :           if (cellData->IsOrig()) {
    1568               0 :             NS_ERROR("cannot overlap originating cell");
    1569               0 :             continue;
    1570                 :           }
    1571               0 :           if (rowX > aRowIndex) { // row spanning into cell
    1572               0 :             if (cellData->IsRowSpan()) {
    1573                 :               // do nothing, this can be caused by rowspan which is overlapped
    1574                 :               // by a another cell with a rowspan and a colspan
    1575                 :             }
    1576                 :             else {
    1577               0 :               cellData->SetRowSpanOffset(rowX - aRowIndex);
    1578               0 :               if (zeroRowSpan) {
    1579               0 :                 cellData->SetZeroRowSpan(true);
    1580                 :               }
    1581                 :             }
    1582                 :           }
    1583               0 :           if (colX > startColIndex) { // col spanning into cell
    1584               0 :             if (!cellData->IsColSpan()) {
    1585               0 :               if (cellData->IsRowSpan()) {
    1586               0 :                 cellData->SetOverlap(true);
    1587                 :               }
    1588               0 :               cellData->SetColSpanOffset(colX - startColIndex);
    1589               0 :               if (zeroColSpan) {
    1590               0 :                 cellData->SetZeroColSpan(true);
    1591                 :               }
    1592                 : 
    1593               0 :               nsColInfo* colInfo = aMap.GetColInfoAt(colX);
    1594               0 :               colInfo->mNumCellsSpan++;
    1595                 :             }
    1596                 :           }
    1597                 :         }
    1598                 :         else {
    1599               0 :           cellData = AllocCellData(nsnull);
    1600               0 :           if (!cellData) return origData;
    1601               0 :           if (rowX > aRowIndex) {
    1602               0 :             cellData->SetRowSpanOffset(rowX - aRowIndex);
    1603               0 :             if (zeroRowSpan) {
    1604               0 :               cellData->SetZeroRowSpan(true);
    1605                 :             }
    1606                 :           }
    1607               0 :           if (colX > startColIndex) {
    1608               0 :             cellData->SetColSpanOffset(colX - startColIndex);
    1609               0 :             if (zeroColSpan) {
    1610               0 :               cellData->SetZeroColSpan(true);
    1611                 :             }
    1612                 :           }
    1613               0 :           SetDataAt(aMap, *cellData, rowX, colX);
    1614                 :         }
    1615                 :       }
    1616                 :     }
    1617                 :   }
    1618                 : #ifdef DEBUG_TABLE_CELLMAP
    1619                 :   printf("appended cell=%p row=%d \n", aCellFrame, aRowIndex);
    1620                 :   aMap.Dump();
    1621                 : #endif
    1622               0 :   return origData;
    1623                 : }
    1624                 : 
    1625               0 : void nsCellMap::CollapseZeroColSpan(nsTableCellMap& aMap,
    1626                 :                                     CellData*       aOrigData,
    1627                 :                                     PRInt32         aRowIndex,
    1628                 :                                     PRInt32         aColIndex)
    1629                 : {
    1630                 :   // if after a colspan = 0 cell another cell is appended in a row the html 4
    1631                 :   // spec is already violated. In principle one should then append the cell
    1632                 :   // after the last column but then the zero spanning cell would also have
    1633                 :   // to grow. The only plausible way to break this cycle is ignore the zero
    1634                 :   // colspan and reset the cell to colspan = 1.
    1635                 : 
    1636               0 :   NS_ASSERTION(aOrigData && aOrigData->IsZeroColSpan(),
    1637                 :                "zero colspan should have been passed");
    1638                 :   // find the originating cellframe
    1639               0 :   nsTableCellFrame* cell = GetCellFrame(aRowIndex, aColIndex, *aOrigData, true);
    1640               0 :   NS_ASSERTION(cell, "originating cell not found");
    1641                 : 
    1642                 :   // find the clearing region
    1643               0 :   PRInt32 startRowIndex = aRowIndex - aOrigData->GetRowSpanOffset();
    1644                 :   bool    zeroSpan;
    1645               0 :   PRInt32 rowSpan = GetRowSpanForNewCell(cell, startRowIndex, zeroSpan);
    1646               0 :   PRInt32 endRowIndex = startRowIndex + rowSpan;
    1647                 : 
    1648               0 :   PRInt32 origColIndex = aColIndex - aOrigData->GetColSpanOffset();
    1649                 :   PRInt32 endColIndex = origColIndex +
    1650                 :                         GetEffectiveColSpan(aMap, startRowIndex,
    1651               0 :                                             origColIndex, zeroSpan);
    1652               0 :   for (PRInt32 colX = origColIndex +1; colX < endColIndex; colX++) {
    1653                 :     // Start the collapse just after the originating cell, since
    1654                 :     // we're basically making the originating cell act as if it
    1655                 :     // has colspan="1".
    1656               0 :     nsColInfo* colInfo = aMap.GetColInfoAt(colX);
    1657               0 :     colInfo->mNumCellsSpan -= rowSpan;
    1658                 : 
    1659               0 :     for (PRInt32 rowX = startRowIndex; rowX < endRowIndex; rowX++)
    1660                 :     {
    1661               0 :       CellData* data = mRows[rowX][colX];
    1662               0 :       NS_ASSERTION(data->IsZeroColSpan(),
    1663                 :                    "Overwriting previous data - memory leak");
    1664               0 :       data->Init(nsnull); // mark the cell as a dead cell.
    1665                 :     }
    1666                 :   }
    1667               0 : }
    1668                 : 
    1669               0 : bool nsCellMap::CellsSpanOut(nsTArray<nsTableRowFrame*>& aRows) const
    1670                 : {
    1671               0 :   PRInt32 numNewRows = aRows.Length();
    1672               0 :   for (PRInt32 rowX = 0; rowX < numNewRows; rowX++) {
    1673               0 :     nsIFrame* rowFrame = (nsIFrame *) aRows.ElementAt(rowX);
    1674               0 :     nsIFrame* childFrame = rowFrame->GetFirstPrincipalChild();
    1675               0 :     while (childFrame) {
    1676               0 :       nsTableCellFrame *cellFrame = do_QueryFrame(childFrame);
    1677               0 :       if (cellFrame) {
    1678                 :         bool zeroSpan;
    1679               0 :         PRInt32 rowSpan = GetRowSpanForNewCell(cellFrame, rowX, zeroSpan);
    1680               0 :         if (zeroSpan || rowX + rowSpan > numNewRows) {
    1681               0 :           return true;
    1682                 :         }
    1683                 :       }
    1684               0 :       childFrame = childFrame->GetNextSibling();
    1685                 :     }
    1686                 :   }
    1687               0 :   return false;
    1688                 : }
    1689                 : 
    1690                 : // return true if any cells have rows spans into or out of the region
    1691                 : // defined by the row and col indices or any cells have colspans into the region
    1692               0 : bool nsCellMap::CellsSpanInOrOut(PRInt32 aStartRowIndex,
    1693                 :                                    PRInt32 aEndRowIndex,
    1694                 :                                    PRInt32 aStartColIndex,
    1695                 :                                    PRInt32 aEndColIndex) const
    1696                 : {
    1697                 :   /*
    1698                 :    * this routine will watch the cells adjacent to the region or at the edge
    1699                 :    * they are marked with *. The routine will verify whether they span in or
    1700                 :    * are spanned out.
    1701                 :    *
    1702                 :    *                           startCol          endCol
    1703                 :    *             r1c1   r1c2   r1c3      r1c4    r1c5    r1rc6  r1c7
    1704                 :    *  startrow   r2c1   r2c2  *r2c3     *r2c4   *r2c5   *r2rc6  r2c7
    1705                 :    *  endrow     r3c1   r3c2  *r3c3      r3c4    r3c5   *r3rc6  r3c7
    1706                 :    *             r4c1   r4c2  *r4c3     *r4c4   *r4c5    r4rc6  r4c7
    1707                 :    *             r5c1   r5c2   r5c3      r5c4    r5c5    r5rc6  r5c7
    1708                 :    */
    1709                 : 
    1710               0 :   PRInt32 numRows = mRows.Length(); // use the cellmap rows to determine the
    1711                 :                                     // current cellmap extent.
    1712               0 :   for (PRInt32 colX = aStartColIndex; colX <= aEndColIndex; colX++) {
    1713                 :     CellData* cellData;
    1714               0 :     if (aStartRowIndex > 0) {
    1715               0 :       cellData = GetDataAt(aStartRowIndex, colX);
    1716               0 :       if (cellData && (cellData->IsRowSpan())) {
    1717               0 :         return true; // there is a row span into the region
    1718                 :       }
    1719               0 :       if ((aStartRowIndex >= mContentRowCount) &&  (mContentRowCount > 0)) {
    1720               0 :         cellData = GetDataAt(mContentRowCount - 1, colX);
    1721               0 :         if (cellData && cellData->IsZeroRowSpan()) {
    1722               0 :           return true;  // When we expand the zerospan it'll span into our row
    1723                 :         }
    1724                 :       }
    1725                 :     }
    1726               0 :     if (aEndRowIndex < numRows - 1) { // is there anything below aEndRowIndex
    1727               0 :       cellData = GetDataAt(aEndRowIndex + 1, colX);
    1728               0 :       if ((cellData) && (cellData->IsRowSpan())) {
    1729               0 :         return true; // there is a row span out of the region
    1730                 :       }
    1731                 :     }
    1732                 :     else {
    1733               0 :       cellData = GetDataAt(aEndRowIndex, colX);
    1734               0 :       if ((cellData) && (cellData->IsRowSpan()) && (mContentRowCount < numRows)) {
    1735               0 :         return true; // this cell might be the cause of a dead row
    1736                 :       }
    1737                 :     }
    1738                 :   }
    1739               0 :   if (aStartColIndex > 0) {
    1740               0 :     for (PRInt32 rowX = aStartRowIndex; rowX <= aEndRowIndex; rowX++) {
    1741               0 :       CellData* cellData = GetDataAt(rowX, aStartColIndex);
    1742               0 :       if (cellData && (cellData->IsColSpan())) {
    1743               0 :         return true; // there is a col span into the region
    1744                 :       }
    1745               0 :       cellData = GetDataAt(rowX, aEndColIndex + 1);
    1746               0 :       if (cellData && (cellData->IsColSpan())) {
    1747               0 :         return true; // there is a col span out of the region
    1748                 :       }
    1749                 :     }
    1750                 :   }
    1751               0 :   return false;
    1752                 : }
    1753                 : 
    1754               0 : void nsCellMap::InsertCells(nsTableCellMap&              aMap,
    1755                 :                             nsTArray<nsTableCellFrame*>& aCellFrames,
    1756                 :                             PRInt32                      aRowIndex,
    1757                 :                             PRInt32                      aColIndexBefore,
    1758                 :                             PRInt32                      aRgFirstRowIndex,
    1759                 :                             nsIntRect&                   aDamageArea)
    1760                 : {
    1761               0 :   if (aCellFrames.Length() == 0) return;
    1762               0 :   NS_ASSERTION(aColIndexBefore >= -1, "index out of range");
    1763               0 :   PRInt32 numCols = aMap.GetColCount();
    1764               0 :   if (aColIndexBefore >= numCols) {
    1765               0 :     NS_ERROR("Inserting instead of appending cells indicates a serious cellmap error");
    1766               0 :     aColIndexBefore = numCols - 1;
    1767                 :   }
    1768                 : 
    1769                 :   // get the starting col index of the 1st new cells
    1770                 :   PRInt32 startColIndex;
    1771               0 :   for (startColIndex = aColIndexBefore + 1; startColIndex < numCols; startColIndex++) {
    1772               0 :     CellData* data = GetDataAt(aRowIndex, startColIndex);
    1773               0 :     if (!data || data->IsOrig() || data->IsDead()) {
    1774                 :       // // Not a span.  Stop.
    1775               0 :       break;
    1776                 :     }
    1777               0 :     if (data->IsZeroColSpan()) {
    1778                 :       // Zero colspans collapse.  Stop in this case too.
    1779               0 :       CollapseZeroColSpan(aMap, data, aRowIndex, startColIndex);
    1780               0 :       break;
    1781                 :     }
    1782                 :   }
    1783                 : 
    1784                 :   // record whether inserted cells are going to cause complications due
    1785                 :   // to existing row spans, col spans or table sizing.
    1786               0 :   bool spansCauseRebuild = false;
    1787                 : 
    1788                 :   // check that all cells have the same row span
    1789               0 :   PRInt32 numNewCells = aCellFrames.Length();
    1790               0 :   bool zeroRowSpan = false;
    1791               0 :   PRInt32 rowSpan = 0;
    1792               0 :   for (PRInt32 cellX = 0; cellX < numNewCells; cellX++) {
    1793               0 :     nsTableCellFrame* cell = aCellFrames.ElementAt(cellX);
    1794               0 :     PRInt32 rowSpan2 = GetRowSpanForNewCell(cell, aRowIndex, zeroRowSpan);
    1795               0 :     if (rowSpan == 0) {
    1796               0 :       rowSpan = rowSpan2;
    1797                 :     }
    1798               0 :     else if (rowSpan != rowSpan2) {
    1799               0 :       spansCauseRebuild = true;
    1800               0 :       break;
    1801                 :     }
    1802                 :   }
    1803                 : 
    1804                 :   // check if the new cells will cause the table to add more rows
    1805               0 :   if (!spansCauseRebuild) {
    1806               0 :     if (mRows.Length() < PRUint32(aRowIndex + rowSpan)) {
    1807               0 :       spansCauseRebuild = true;
    1808                 :     }
    1809                 :   }
    1810                 : 
    1811               0 :   if (!spansCauseRebuild) {
    1812                 :     spansCauseRebuild = CellsSpanInOrOut(aRowIndex, aRowIndex + rowSpan - 1,
    1813               0 :                                          startColIndex, numCols - 1);
    1814                 :   }
    1815               0 :   if (spansCauseRebuild) {
    1816                 :     aMap.RebuildConsideringCells(this, &aCellFrames, aRowIndex, startColIndex,
    1817               0 :                                  true, aDamageArea);
    1818                 :   }
    1819                 :   else {
    1820                 :     ExpandWithCells(aMap, aCellFrames, aRowIndex, startColIndex, rowSpan,
    1821               0 :                     zeroRowSpan, aRgFirstRowIndex, aDamageArea);
    1822                 :   }
    1823                 : }
    1824                 : 
    1825                 : void
    1826               0 : nsCellMap::ExpandWithRows(nsTableCellMap&             aMap,
    1827                 :                           nsTArray<nsTableRowFrame*>& aRowFrames,
    1828                 :                           PRInt32                     aStartRowIndexIn,
    1829                 :                           PRInt32                     aRgFirstRowIndex,
    1830                 :                           nsIntRect&                  aDamageArea)
    1831                 : {
    1832               0 :   PRInt32 startRowIndex = (aStartRowIndexIn >= 0) ? aStartRowIndexIn : 0;
    1833               0 :   NS_ASSERTION(PRUint32(startRowIndex) <= mRows.Length(), "caller should have grown cellmap before");
    1834                 : 
    1835               0 :   PRInt32 numNewRows  = aRowFrames.Length();
    1836               0 :   mContentRowCount += numNewRows;
    1837                 : 
    1838               0 :   PRInt32 endRowIndex = startRowIndex + numNewRows - 1;
    1839                 : 
    1840                 :   // shift the rows after startRowIndex down and insert empty rows that will
    1841                 :   // be filled via the AppendCell call below
    1842               0 :   if (!Grow(aMap, numNewRows, startRowIndex)) {
    1843               0 :     return;
    1844                 :   }
    1845                 : 
    1846                 : 
    1847               0 :   PRInt32 newRowIndex = 0;
    1848               0 :   for (PRInt32 rowX = startRowIndex; rowX <= endRowIndex; rowX++) {
    1849               0 :     nsTableRowFrame* rFrame = aRowFrames.ElementAt(newRowIndex);
    1850                 :     // append cells
    1851               0 :     nsIFrame* cFrame = rFrame->GetFirstPrincipalChild();
    1852               0 :     PRInt32 colIndex = 0;
    1853               0 :     while (cFrame) {
    1854               0 :       nsTableCellFrame *cellFrame = do_QueryFrame(cFrame);
    1855               0 :       if (cellFrame) {
    1856                 :         AppendCell(aMap, cellFrame, rowX, false, aRgFirstRowIndex, aDamageArea,
    1857               0 :                    &colIndex);
    1858                 :       }
    1859               0 :       cFrame = cFrame->GetNextSibling();
    1860                 :     }
    1861               0 :     newRowIndex++;
    1862                 :   }
    1863                 :   // mark all following rows damaged, they might contain a previously set
    1864                 :   // damage area which we can not shift.
    1865               0 :   PRInt32 firstDamagedRow = aRgFirstRowIndex + startRowIndex;
    1866                 :   SetDamageArea(0, firstDamagedRow, aMap.GetColCount(),
    1867               0 :                 aMap.GetRowCount() - firstDamagedRow, aDamageArea);
    1868                 : }
    1869                 : 
    1870               0 : void nsCellMap::ExpandWithCells(nsTableCellMap&              aMap,
    1871                 :                                 nsTArray<nsTableCellFrame*>& aCellFrames,
    1872                 :                                 PRInt32                      aRowIndex,
    1873                 :                                 PRInt32                      aColIndex,
    1874                 :                                 PRInt32                      aRowSpan, // same for all cells
    1875                 :                                 bool                         aRowSpanIsZero,
    1876                 :                                 PRInt32                      aRgFirstRowIndex,
    1877                 :                                 nsIntRect&                   aDamageArea)
    1878                 : {
    1879               0 :   NS_ASSERTION(!!aMap.mBCInfo == mIsBC, "BC state mismatch");
    1880               0 :   PRInt32 endRowIndex = aRowIndex + aRowSpan - 1;
    1881               0 :   PRInt32 startColIndex = aColIndex;
    1882               0 :   PRInt32 endColIndex = aColIndex;
    1883               0 :   PRInt32 numCells = aCellFrames.Length();
    1884               0 :   PRInt32 totalColSpan = 0;
    1885                 : 
    1886                 :   // add cellData entries for the space taken up by the new cells
    1887               0 :   for (PRInt32 cellX = 0; cellX < numCells; cellX++) {
    1888               0 :     nsTableCellFrame* cellFrame = aCellFrames.ElementAt(cellX);
    1889               0 :     CellData* origData = AllocCellData(cellFrame); // the originating cell
    1890               0 :     if (!origData) return;
    1891                 : 
    1892                 :     // set the starting and ending col index for the new cell
    1893               0 :     bool zeroColSpan = false;
    1894               0 :     PRInt32 colSpan = GetColSpanForNewCell(*cellFrame, zeroColSpan);
    1895               0 :     if (zeroColSpan) {
    1896               0 :       aMap.mTableFrame.SetHasZeroColSpans(true);
    1897               0 :       aMap.mTableFrame.SetNeedColSpanExpansion(true);
    1898                 :     }
    1899               0 :     totalColSpan += colSpan;
    1900               0 :     if (cellX == 0) {
    1901               0 :       endColIndex = aColIndex + colSpan - 1;
    1902                 :     }
    1903                 :     else {
    1904               0 :       startColIndex = endColIndex + 1;
    1905               0 :       endColIndex   = startColIndex + colSpan - 1;
    1906                 :     }
    1907                 : 
    1908                 :     // add the originating cell data and any cell data corresponding to row/col spans
    1909               0 :     for (PRInt32 rowX = aRowIndex; rowX <= endRowIndex; rowX++) {
    1910               0 :       CellDataArray& row = mRows[rowX];
    1911                 :       // Pre-allocate all the cells we'll need in this array, setting
    1912                 :       // them to null.
    1913                 :       // Have to have the cast to get the template to do the right thing.
    1914               0 :       PRInt32 insertionIndex = row.Length();
    1915               0 :       if (insertionIndex > startColIndex) {
    1916               0 :         insertionIndex = startColIndex;
    1917                 :       }
    1918               0 :       if (!row.InsertElementsAt(insertionIndex, endColIndex - insertionIndex + 1,
    1919               0 :                                 (CellData*)nsnull) &&
    1920                 :           rowX == aRowIndex) {
    1921                 :         // Failed to insert the slots, and this is the very first row.  That
    1922                 :         // means that we need to clean up |origData| before returning, since
    1923                 :         // the cellmap doesn't own it yet.
    1924               0 :         DestroyCellData(origData);
    1925               0 :         return;
    1926                 :       }
    1927                 : 
    1928               0 :       for (PRInt32 colX = startColIndex; colX <= endColIndex; colX++) {
    1929               0 :         CellData* data = origData;
    1930               0 :         if ((rowX != aRowIndex) || (colX != startColIndex)) {
    1931               0 :           data = AllocCellData(nsnull);
    1932               0 :           if (!data) return;
    1933               0 :           if (rowX > aRowIndex) {
    1934               0 :             data->SetRowSpanOffset(rowX - aRowIndex);
    1935               0 :             if (aRowSpanIsZero) {
    1936               0 :               data->SetZeroRowSpan(true);
    1937                 :             }
    1938                 :           }
    1939               0 :           if (colX > startColIndex) {
    1940               0 :             data->SetColSpanOffset(colX - startColIndex);
    1941               0 :             if (zeroColSpan) {
    1942               0 :               data->SetZeroColSpan(true);
    1943                 :             }
    1944                 :           }
    1945                 :         }
    1946               0 :         SetDataAt(aMap, *data, rowX, colX);
    1947                 :       }
    1948                 :     }
    1949               0 :     cellFrame->SetColIndex(startColIndex);
    1950                 :   }
    1951               0 :   PRInt32 damageHeight = NS_MIN(GetRowGroup()->GetRowCount() - aRowIndex,
    1952               0 :                                 aRowSpan);
    1953                 :   SetDamageArea(aColIndex, aRgFirstRowIndex + aRowIndex,
    1954               0 :                 1 + endColIndex - aColIndex, damageHeight, aDamageArea);
    1955                 : 
    1956                 :   PRInt32 rowX;
    1957                 : 
    1958                 :   // update the row and col info due to shifting
    1959               0 :   for (rowX = aRowIndex; rowX <= endRowIndex; rowX++) {
    1960               0 :     CellDataArray& row = mRows[rowX];
    1961               0 :     PRUint32 numCols = row.Length();
    1962                 :     PRUint32 colX;
    1963               0 :     for (colX = aColIndex + totalColSpan; colX < numCols; colX++) {
    1964               0 :       CellData* data = row[colX];
    1965               0 :       if (data) {
    1966                 :         // increase the origin and span counts beyond the spanned cols
    1967               0 :         if (data->IsOrig()) {
    1968                 :           // a cell that gets moved needs adjustment as well as it new orignating col
    1969               0 :           data->GetCellFrame()->SetColIndex(colX);
    1970               0 :           nsColInfo* colInfo = aMap.GetColInfoAt(colX);
    1971               0 :           colInfo->mNumCellsOrig++;
    1972                 :         }
    1973               0 :         if (data->IsColSpan()) {
    1974               0 :           nsColInfo* colInfo = aMap.GetColInfoAt(colX);
    1975               0 :           colInfo->mNumCellsSpan++;
    1976                 :         }
    1977                 : 
    1978                 :         // decrease the origin and span counts within the spanned cols
    1979               0 :         PRInt32 colX2 = colX - totalColSpan;
    1980               0 :         nsColInfo* colInfo2 = aMap.GetColInfoAt(colX2);
    1981               0 :         if (data->IsOrig()) {
    1982                 :           // the old originating col of a moved cell needs adjustment
    1983               0 :           colInfo2->mNumCellsOrig--;
    1984                 :         }
    1985               0 :         if (data->IsColSpan()) {
    1986               0 :           colInfo2->mNumCellsSpan--;
    1987                 :         }
    1988                 :       }
    1989                 :     }
    1990                 :   }
    1991                 : }
    1992                 : 
    1993               0 : void nsCellMap::ShrinkWithoutRows(nsTableCellMap& aMap,
    1994                 :                                   PRInt32         aStartRowIndex,
    1995                 :                                   PRInt32         aNumRowsToRemove,
    1996                 :                                   PRInt32         aRgFirstRowIndex,
    1997                 :                                   nsIntRect&      aDamageArea)
    1998                 : {
    1999               0 :   NS_ASSERTION(!!aMap.mBCInfo == mIsBC, "BC state mismatch");
    2000               0 :   PRInt32 endRowIndex = aStartRowIndex + aNumRowsToRemove - 1;
    2001               0 :   PRUint32 colCount = aMap.GetColCount();
    2002               0 :   for (PRInt32 rowX = endRowIndex; rowX >= aStartRowIndex; --rowX) {
    2003               0 :     CellDataArray& row = mRows[rowX];
    2004                 :     PRUint32 colX;
    2005               0 :     for (colX = 0; colX < colCount; colX++) {
    2006               0 :       CellData* data = row.SafeElementAt(colX);
    2007               0 :       if (data) {
    2008                 :         // Adjust the column counts.
    2009               0 :         if (data->IsOrig()) {
    2010                 :           // Decrement the column count.
    2011               0 :           nsColInfo* colInfo = aMap.GetColInfoAt(colX);
    2012               0 :           colInfo->mNumCellsOrig--;
    2013                 :         }
    2014                 :         // colspan=0 is only counted as a spanned cell in the 1st col it spans
    2015               0 :         else if (data->IsColSpan()) {
    2016               0 :           nsColInfo* colInfo = aMap.GetColInfoAt(colX);
    2017               0 :           colInfo->mNumCellsSpan--;
    2018                 :         }
    2019                 :       }
    2020                 :     }
    2021                 : 
    2022               0 :     PRUint32 rowLength = row.Length();
    2023                 :     // Delete our row information.
    2024               0 :     for (colX = 0; colX < rowLength; colX++) {
    2025               0 :       DestroyCellData(row[colX]);
    2026                 :     }
    2027                 : 
    2028               0 :     mRows.RemoveElementAt(rowX);
    2029                 : 
    2030                 :     // Decrement our row and next available index counts.
    2031               0 :     mContentRowCount--;
    2032                 :   }
    2033               0 :   aMap.RemoveColsAtEnd();
    2034                 :   // mark all following rows damaged, they might contain a previously set
    2035                 :   // damage area which we can not shift.
    2036               0 :   PRInt32 firstDamagedRow = aRgFirstRowIndex + aStartRowIndex;
    2037                 :   SetDamageArea(0, firstDamagedRow, aMap.GetColCount(),
    2038               0 :                 aMap.GetRowCount() - firstDamagedRow, aDamageArea);
    2039               0 : }
    2040                 : 
    2041               0 : PRInt32 nsCellMap::GetColSpanForNewCell(nsTableCellFrame& aCellFrameToAdd,
    2042                 :                                         bool&           aIsZeroColSpan) const
    2043                 : {
    2044               0 :   aIsZeroColSpan = false;
    2045               0 :   PRInt32 colSpan = aCellFrameToAdd.GetColSpan();
    2046               0 :   if (0 == colSpan) {
    2047               0 :     colSpan = 1; // set the min colspan it will be expanded later
    2048               0 :     aIsZeroColSpan = true;
    2049                 :   }
    2050               0 :   return colSpan;
    2051                 : }
    2052                 : 
    2053               0 : PRInt32 nsCellMap::GetEffectiveColSpan(const nsTableCellMap& aMap,
    2054                 :                                        PRInt32         aRowIndex,
    2055                 :                                        PRInt32         aColIndex,
    2056                 :                                        bool&         aZeroColSpan) const
    2057                 : {
    2058               0 :   PRInt32 numColsInTable = aMap.GetColCount();
    2059               0 :   aZeroColSpan = false;
    2060               0 :   PRInt32 colSpan = 1;
    2061               0 :   if (PRUint32(aRowIndex) >= mRows.Length()) {
    2062               0 :     return colSpan;
    2063                 :   }
    2064                 : 
    2065               0 :   const CellDataArray& row = mRows[aRowIndex];
    2066                 :   PRInt32 colX;
    2067                 :   CellData* data;
    2068               0 :   PRInt32 maxCols = numColsInTable;
    2069               0 :   bool hitOverlap = false; // XXX this is not ever being set to true
    2070               0 :   for (colX = aColIndex + 1; colX < maxCols; colX++) {
    2071               0 :     data = row.SafeElementAt(colX);
    2072               0 :     if (data) {
    2073                 :       // for an overlapping situation get the colspan from the originating cell and
    2074                 :       // use that as the max number of cols to iterate. Since this is rare, only
    2075                 :       // pay the price of looking up the cell's colspan here.
    2076               0 :       if (!hitOverlap && data->IsOverlap()) {
    2077               0 :         CellData* origData = row.SafeElementAt(aColIndex);
    2078               0 :         if (origData && origData->IsOrig()) {
    2079               0 :           nsTableCellFrame* cellFrame = origData->GetCellFrame();
    2080               0 :           if (cellFrame) {
    2081                 :             // possible change the number of colums to iterate
    2082               0 :             maxCols = NS_MIN(aColIndex + cellFrame->GetColSpan(), maxCols);
    2083               0 :             if (colX >= maxCols)
    2084               0 :               break;
    2085                 :           }
    2086                 :         }
    2087                 :       }
    2088               0 :       if (data->IsColSpan()) {
    2089               0 :         colSpan++;
    2090               0 :         if (data->IsZeroColSpan()) {
    2091               0 :           aZeroColSpan = true;
    2092                 :         }
    2093                 :       }
    2094                 :       else {
    2095               0 :         break;
    2096                 :       }
    2097                 :     }
    2098               0 :     else break;
    2099                 :   }
    2100               0 :   return colSpan;
    2101                 : }
    2102                 : 
    2103                 : PRInt32
    2104               0 : nsCellMap::GetRowSpanForNewCell(nsTableCellFrame* aCellFrameToAdd,
    2105                 :                                 PRInt32           aRowIndex,
    2106                 :                                 bool&           aIsZeroRowSpan) const
    2107                 : {
    2108               0 :   aIsZeroRowSpan = false;
    2109               0 :   PRInt32 rowSpan = aCellFrameToAdd->GetRowSpan();
    2110               0 :   if (0 == rowSpan) {
    2111                 :     // Use a min value of 2 for a zero rowspan to make computations easier
    2112                 :     // elsewhere. Zero rowspans are only content dependent!
    2113               0 :     rowSpan = NS_MAX(2, mContentRowCount - aRowIndex);
    2114               0 :     aIsZeroRowSpan = true;
    2115                 :   }
    2116               0 :   return rowSpan;
    2117                 : }
    2118                 : 
    2119               0 : bool nsCellMap::HasMoreThanOneCell(PRInt32 aRowIndex) const
    2120                 : {
    2121               0 :   const CellDataArray& row = mRows.SafeElementAt(aRowIndex, *sEmptyRow);
    2122               0 :   PRUint32 maxColIndex = row.Length();
    2123               0 :   PRUint32 count = 0;
    2124                 :   PRUint32 colIndex;
    2125               0 :   for (colIndex = 0; colIndex < maxColIndex; colIndex++) {
    2126               0 :     CellData* cellData = row[colIndex];
    2127               0 :     if (cellData && (cellData->GetCellFrame() || cellData->IsRowSpan()))
    2128               0 :       count++;
    2129               0 :     if (count > 1)
    2130               0 :       return true;
    2131                 :   }
    2132               0 :   return false;
    2133                 : }
    2134                 : 
    2135                 : PRInt32
    2136               0 : nsCellMap::GetNumCellsOriginatingInRow(PRInt32 aRowIndex) const
    2137                 : {
    2138               0 :   const CellDataArray& row = mRows.SafeElementAt(aRowIndex, *sEmptyRow);
    2139               0 :   PRUint32 count = 0;
    2140               0 :   PRUint32 maxColIndex = row.Length();
    2141                 :   PRUint32 colIndex;
    2142               0 :   for (colIndex = 0; colIndex < maxColIndex; colIndex++) {
    2143               0 :     CellData* cellData = row[colIndex];
    2144               0 :     if (cellData && cellData->IsOrig())
    2145               0 :       count++;
    2146                 :   }
    2147               0 :   return count;
    2148                 : }
    2149                 : 
    2150               0 : PRInt32 nsCellMap::GetRowSpan(PRInt32  aRowIndex,
    2151                 :                               PRInt32  aColIndex,
    2152                 :                               bool     aGetEffective) const
    2153                 : {
    2154               0 :   PRInt32 rowSpan = 1;
    2155               0 :   PRInt32 rowCount = (aGetEffective) ? mContentRowCount : mRows.Length();
    2156                 :   PRInt32 rowX;
    2157               0 :   for (rowX = aRowIndex + 1; rowX < rowCount; rowX++) {
    2158               0 :     CellData* data = GetDataAt(rowX, aColIndex);
    2159               0 :     if (data) {
    2160               0 :       if (data->IsRowSpan()) {
    2161               0 :         rowSpan++;
    2162                 :       }
    2163                 :       else {
    2164               0 :         break;
    2165                 :       }
    2166                 :     }
    2167               0 :     else break;
    2168                 :   }
    2169               0 :   return rowSpan;
    2170                 : }
    2171                 : 
    2172               0 : void nsCellMap::ShrinkWithoutCell(nsTableCellMap&   aMap,
    2173                 :                                   nsTableCellFrame& aCellFrame,
    2174                 :                                   PRInt32           aRowIndex,
    2175                 :                                   PRInt32           aColIndex,
    2176                 :                                   PRInt32           aRgFirstRowIndex,
    2177                 :                                   nsIntRect&        aDamageArea)
    2178                 : {
    2179               0 :   NS_ASSERTION(!!aMap.mBCInfo == mIsBC, "BC state mismatch");
    2180                 :   PRUint32 colX, rowX;
    2181                 : 
    2182                 :   // get the rowspan and colspan from the cell map since the content may have changed
    2183                 :   bool zeroColSpan;
    2184               0 :   PRUint32 numCols = aMap.GetColCount();
    2185               0 :   PRInt32 rowSpan = GetRowSpan(aRowIndex, aColIndex, true);
    2186               0 :   PRUint32 colSpan = GetEffectiveColSpan(aMap, aRowIndex, aColIndex, zeroColSpan);
    2187               0 :   PRUint32 endRowIndex = aRowIndex + rowSpan - 1;
    2188               0 :   PRUint32 endColIndex = aColIndex + colSpan - 1;
    2189                 : 
    2190               0 :   if (aMap.mTableFrame.HasZeroColSpans()) {
    2191               0 :     aMap.mTableFrame.SetNeedColSpanExpansion(true);
    2192                 :   }
    2193                 : 
    2194                 :   // adjust the col counts due to the deleted cell before removing it
    2195               0 :   for (colX = aColIndex; colX <= endColIndex; colX++) {
    2196               0 :     nsColInfo* colInfo = aMap.GetColInfoAt(colX);
    2197               0 :     if (colX == PRUint32(aColIndex)) {
    2198               0 :       colInfo->mNumCellsOrig--;
    2199                 :     }
    2200                 :     else  {
    2201               0 :       colInfo->mNumCellsSpan--;
    2202                 :     }
    2203                 :   }
    2204                 : 
    2205                 :   // remove the deleted cell and cellData entries for it
    2206               0 :   for (rowX = aRowIndex; rowX <= endRowIndex; rowX++) {
    2207               0 :     CellDataArray& row = mRows[rowX];
    2208                 : 
    2209                 :     // endIndexForRow points at the first slot we don't want to clean up.  This
    2210                 :     // makes the aColIndex == 0 case work right with our unsigned int colX.
    2211               0 :     NS_ASSERTION(endColIndex + 1 <= row.Length(), "span beyond the row size!");
    2212               0 :     PRUint32 endIndexForRow = NS_MIN(endColIndex + 1, row.Length());
    2213                 : 
    2214                 :     // Since endIndexForRow <= row.Length(), enough to compare aColIndex to it.
    2215               0 :     if (PRUint32(aColIndex) < endIndexForRow) {
    2216               0 :       for (colX = endIndexForRow; colX > PRUint32(aColIndex); colX--) {
    2217               0 :         DestroyCellData(row[colX-1]);
    2218                 :       }
    2219               0 :       row.RemoveElementsAt(aColIndex, endIndexForRow - aColIndex);
    2220                 :     }
    2221                 :   }
    2222                 : 
    2223               0 :   numCols = aMap.GetColCount();
    2224                 : 
    2225                 :   // update the row and col info due to shifting
    2226               0 :   for (rowX = aRowIndex; rowX <= endRowIndex; rowX++) {
    2227               0 :     CellDataArray& row = mRows[rowX];
    2228               0 :     for (colX = aColIndex; colX < numCols - colSpan; colX++) {
    2229               0 :       CellData* data = row.SafeElementAt(colX);
    2230               0 :       if (data) {
    2231               0 :         if (data->IsOrig()) {
    2232                 :           // a cell that gets moved to the left needs adjustment in its new location
    2233               0 :           data->GetCellFrame()->SetColIndex(colX);
    2234               0 :           nsColInfo* colInfo = aMap.GetColInfoAt(colX);
    2235               0 :           colInfo->mNumCellsOrig++;
    2236                 :           // a cell that gets moved to the left needs adjustment in its old location
    2237               0 :           colInfo = aMap.GetColInfoAt(colX + colSpan);
    2238               0 :           if (colInfo) {
    2239               0 :             colInfo->mNumCellsOrig--;
    2240                 :           }
    2241                 :         }
    2242                 : 
    2243               0 :         else if (data->IsColSpan()) {
    2244                 :           // a cell that gets moved to the left needs adjustment
    2245                 :           // in its new location
    2246               0 :           nsColInfo* colInfo = aMap.GetColInfoAt(colX);
    2247               0 :           colInfo->mNumCellsSpan++;
    2248                 :           // a cell that gets moved to the left needs adjustment
    2249                 :           // in its old location
    2250               0 :           colInfo = aMap.GetColInfoAt(colX + colSpan);
    2251               0 :           if (colInfo) {
    2252               0 :             colInfo->mNumCellsSpan--;
    2253                 :           }
    2254                 :         }
    2255                 :       }
    2256                 :     }
    2257                 :   }
    2258               0 :   aMap.RemoveColsAtEnd();
    2259                 :   SetDamageArea(aColIndex, aRgFirstRowIndex + aRowIndex,
    2260               0 :                 NS_MAX(0, aMap.GetColCount() - aColIndex - 1),
    2261               0 :                 1 + endRowIndex - aRowIndex, aDamageArea);
    2262               0 : }
    2263                 : 
    2264                 : void
    2265               0 : nsCellMap::RebuildConsideringRows(nsTableCellMap&             aMap,
    2266                 :                                   PRInt32                     aStartRowIndex,
    2267                 :                                   nsTArray<nsTableRowFrame*>* aRowsToInsert,
    2268                 :                                   PRInt32                     aNumRowsToRemove)
    2269                 : {
    2270               0 :   NS_ASSERTION(!!aMap.mBCInfo == mIsBC, "BC state mismatch");
    2271                 :   // copy the old cell map into a new array
    2272               0 :   PRUint32 numOrigRows = mRows.Length();
    2273               0 :   nsTArray<CellDataArray> origRows;
    2274               0 :   mRows.SwapElements(origRows);
    2275                 : 
    2276                 :   PRInt32 rowNumberChange;
    2277               0 :   if (aRowsToInsert) {
    2278               0 :     rowNumberChange = aRowsToInsert->Length();
    2279                 :   } else {
    2280               0 :     rowNumberChange = -aNumRowsToRemove;
    2281                 :   }
    2282                 : 
    2283                 :   // adjust mContentRowCount based on the function arguments as they are known to
    2284                 :   // be real rows.
    2285               0 :   mContentRowCount += rowNumberChange;
    2286               0 :   NS_ASSERTION(mContentRowCount >= 0, "previous mContentRowCount was wrong");
    2287                 :   // mRows is empty now.  Grow it to the size we expect it to have.
    2288               0 :   if (mContentRowCount) {
    2289               0 :     if (!Grow(aMap, mContentRowCount)) {
    2290                 :       // Bail, I guess...  Not sure what else we can do here.
    2291                 :       return;
    2292                 :     }
    2293                 :   }
    2294                 : 
    2295                 :   // aStartRowIndex might be after all existing rows so we should limit the
    2296                 :   // copy to the amount of exisiting rows
    2297               0 :   PRUint32 copyEndRowIndex = NS_MIN(numOrigRows, PRUint32(aStartRowIndex));
    2298                 : 
    2299                 :   // rowX keeps track of where we are in mRows while setting up the
    2300                 :   // new cellmap.
    2301               0 :   PRUint32 rowX = 0;
    2302               0 :   nsIntRect damageArea;
    2303                 :   // put back the rows before the affected ones just as before.  Note that we
    2304                 :   // can't just copy the old rows in bit-for-bit, because they might be
    2305                 :   // spanning out into the rows we're adding/removing.
    2306               0 :   for ( ; rowX < copyEndRowIndex; rowX++) {
    2307               0 :     const CellDataArray& row = origRows[rowX];
    2308               0 :     PRUint32 numCols = row.Length();
    2309               0 :     for (PRUint32 colX = 0; colX < numCols; colX++) {
    2310                 :       // put in the original cell from the cell map
    2311               0 :       const CellData* data = row.ElementAt(colX);
    2312               0 :       if (data && data->IsOrig()) {
    2313               0 :         AppendCell(aMap, data->GetCellFrame(), rowX, false, 0, damageArea);
    2314                 :       }
    2315                 :     }
    2316                 :   }
    2317                 : 
    2318                 :   // Now handle the new rows being inserted, if any.
    2319                 :   PRUint32 copyStartRowIndex;
    2320               0 :   rowX = aStartRowIndex;
    2321               0 :   if (aRowsToInsert) {
    2322                 :     // add in the new cells and create rows if necessary
    2323               0 :     PRInt32 numNewRows = aRowsToInsert->Length();
    2324               0 :     for (PRInt32 newRowX = 0; newRowX < numNewRows; newRowX++) {
    2325               0 :       nsTableRowFrame* rFrame = aRowsToInsert->ElementAt(newRowX);
    2326               0 :       nsIFrame* cFrame = rFrame->GetFirstPrincipalChild();
    2327               0 :       while (cFrame) {
    2328               0 :         nsTableCellFrame *cellFrame = do_QueryFrame(cFrame);
    2329               0 :         if (cellFrame) {
    2330               0 :           AppendCell(aMap, cellFrame, rowX, false, 0, damageArea);
    2331                 :         }
    2332               0 :         cFrame = cFrame->GetNextSibling();
    2333                 :       }
    2334               0 :       rowX++;
    2335                 :     }
    2336               0 :     copyStartRowIndex = aStartRowIndex;
    2337                 :   }
    2338                 :   else {
    2339               0 :     copyStartRowIndex = aStartRowIndex + aNumRowsToRemove;
    2340                 :   }
    2341                 : 
    2342                 :   // put back the rows after the affected ones just as before.  Again, we can't
    2343                 :   // just copy the old bits because that would not handle the new rows spanning
    2344                 :   // out or our earlier old rows spanning through the damaged area.
    2345               0 :   for (PRUint32 copyRowX = copyStartRowIndex; copyRowX < numOrigRows;
    2346                 :        copyRowX++) {
    2347               0 :     const CellDataArray& row = origRows[copyRowX];
    2348               0 :     PRUint32 numCols = row.Length();
    2349               0 :     for (PRUint32 colX = 0; colX < numCols; colX++) {
    2350                 :       // put in the original cell from the cell map
    2351               0 :       CellData* data = row.ElementAt(colX);
    2352               0 :       if (data && data->IsOrig()) {
    2353               0 :         AppendCell(aMap, data->GetCellFrame(), rowX, false, 0, damageArea);
    2354                 :       }
    2355                 :     }
    2356               0 :     rowX++;
    2357                 :   }
    2358                 : 
    2359                 :   // delete the old cell map.  Now rowX no longer has anything to do with mRows
    2360               0 :   for (rowX = 0; rowX < numOrigRows; rowX++) {
    2361               0 :     CellDataArray& row = origRows[rowX];
    2362               0 :     PRUint32 len = row.Length();
    2363               0 :     for (PRUint32 colX = 0; colX < len; colX++) {
    2364               0 :       DestroyCellData(row[colX]);
    2365                 :     }
    2366                 :   }
    2367                 : }
    2368                 : 
    2369                 : void
    2370               0 : nsCellMap::RebuildConsideringCells(nsTableCellMap&              aMap,
    2371                 :                                    PRInt32                      aNumOrigCols,
    2372                 :                                    nsTArray<nsTableCellFrame*>* aCellFrames,
    2373                 :                                    PRInt32                      aRowIndex,
    2374                 :                                    PRInt32                      aColIndex,
    2375                 :                                    bool                         aInsert)
    2376                 : {
    2377               0 :   NS_ASSERTION(!!aMap.mBCInfo == mIsBC, "BC state mismatch");
    2378                 :   // copy the old cell map into a new array
    2379               0 :   PRInt32 numOrigRows  = mRows.Length();
    2380               0 :   nsTArray<CellDataArray> origRows;
    2381               0 :   mRows.SwapElements(origRows);
    2382                 : 
    2383               0 :   PRInt32 numNewCells = (aCellFrames) ? aCellFrames->Length() : 0;
    2384                 : 
    2385                 :   // the new cells might extend the previous column number
    2386               0 :   NS_ASSERTION(aNumOrigCols >= aColIndex, "Appending cells far beyond cellmap data?!");
    2387               0 :   PRInt32 numCols = aInsert ? NS_MAX(aNumOrigCols, aColIndex + 1) : aNumOrigCols;
    2388                 : 
    2389                 :   // build the new cell map.  Hard to say what, if anything, we can preallocate
    2390                 :   // here...  Should come back to that sometime, perhaps.
    2391                 :   PRInt32 rowX;
    2392               0 :   nsIntRect damageArea;
    2393               0 :   for (rowX = 0; rowX < numOrigRows; rowX++) {
    2394               0 :     const CellDataArray& row = origRows[rowX];
    2395               0 :     for (PRInt32 colX = 0; colX < numCols; colX++) {
    2396               0 :       if ((rowX == aRowIndex) && (colX == aColIndex)) {
    2397               0 :         if (aInsert) { // put in the new cells
    2398               0 :           for (PRInt32 cellX = 0; cellX < numNewCells; cellX++) {
    2399               0 :             nsTableCellFrame* cell = aCellFrames->ElementAt(cellX);
    2400               0 :             if (cell) {
    2401               0 :               AppendCell(aMap, cell, rowX, false, 0, damageArea);
    2402                 :             }
    2403                 :           }
    2404                 :         }
    2405                 :         else {
    2406               0 :           continue; // do not put the deleted cell back
    2407                 :         }
    2408                 :       }
    2409                 :       // put in the original cell from the cell map
    2410               0 :       CellData* data = row.SafeElementAt(colX);
    2411               0 :       if (data && data->IsOrig()) {
    2412               0 :         AppendCell(aMap, data->GetCellFrame(), rowX, false, 0, damageArea);
    2413                 :       }
    2414                 :     }
    2415                 :   }
    2416               0 :   if (aInsert && numOrigRows <= aRowIndex) { // append the new cells below the last original row
    2417               0 :     NS_ASSERTION (numOrigRows == aRowIndex, "Appending cells far beyond the last row");
    2418               0 :     for (PRInt32 cellX = 0; cellX < numNewCells; cellX++) {
    2419               0 :       nsTableCellFrame* cell = aCellFrames->ElementAt(cellX);
    2420               0 :       if (cell) {
    2421               0 :         AppendCell(aMap, cell, aRowIndex, false, 0, damageArea);
    2422                 :       }
    2423                 :     }
    2424                 :   }
    2425                 : 
    2426                 :   // delete the old cell map
    2427               0 :   for (rowX = 0; rowX < numOrigRows; rowX++) {
    2428               0 :     CellDataArray& row = origRows[rowX];
    2429               0 :     PRUint32 len = row.Length();
    2430               0 :     for (PRUint32 colX = 0; colX < len; colX++) {
    2431               0 :       DestroyCellData(row.SafeElementAt(colX));
    2432                 :     }
    2433                 :   }
    2434                 :   // expand the cellmap to cover empty content rows
    2435               0 :   if (mRows.Length() < PRUint32(mContentRowCount)) {
    2436               0 :     Grow(aMap, mContentRowCount - mRows.Length());
    2437                 :   }
    2438                 : 
    2439               0 : }
    2440                 : 
    2441               0 : void nsCellMap::RemoveCell(nsTableCellMap&   aMap,
    2442                 :                            nsTableCellFrame* aCellFrame,
    2443                 :                            PRInt32           aRowIndex,
    2444                 :                            PRInt32           aRgFirstRowIndex,
    2445                 :                            nsIntRect&        aDamageArea)
    2446                 : {
    2447               0 :   PRUint32 numRows = mRows.Length();
    2448               0 :   if (PRUint32(aRowIndex) >= numRows) {
    2449               0 :     NS_ERROR("bad arg in nsCellMap::RemoveCell");
    2450               0 :     return;
    2451                 :   }
    2452               0 :   PRInt32 numCols = aMap.GetColCount();
    2453                 : 
    2454                 :   // Now aRowIndex is guaranteed OK.
    2455                 : 
    2456                 :   // get the starting col index of the cell to remove
    2457                 :   PRInt32 startColIndex;
    2458               0 :   for (startColIndex = 0; startColIndex < numCols; startColIndex++) {
    2459               0 :     CellData* data = mRows[aRowIndex].SafeElementAt(startColIndex);
    2460               0 :     if (data && (data->IsOrig()) && (aCellFrame == data->GetCellFrame())) {
    2461               0 :       break; // we found the col index
    2462                 :     }
    2463                 :   }
    2464                 : 
    2465               0 :   PRInt32 rowSpan = GetRowSpan(aRowIndex, startColIndex, false);
    2466                 :   // record whether removing the cells is going to cause complications due
    2467                 :   // to existing row spans, col spans or table sizing.
    2468                 :   bool spansCauseRebuild = CellsSpanInOrOut(aRowIndex,
    2469                 :                                               aRowIndex + rowSpan - 1,
    2470               0 :                                               startColIndex, numCols - 1);
    2471                 :   // XXX if the cell has a col span to the end of the map, and the end has no originating
    2472                 :   // cells, we need to assume that this the only such cell, and rebuild so that there are
    2473                 :   // no extraneous cols at the end. The same is true for removing rows.
    2474               0 :   if (!aCellFrame->GetRowSpan() || !aCellFrame->GetColSpan())
    2475               0 :     spansCauseRebuild = true;
    2476                 : 
    2477               0 :   if (spansCauseRebuild) {
    2478                 :     aMap.RebuildConsideringCells(this, nsnull, aRowIndex, startColIndex, false,
    2479               0 :                                  aDamageArea);
    2480                 :   }
    2481                 :   else {
    2482                 :     ShrinkWithoutCell(aMap, *aCellFrame, aRowIndex, startColIndex,
    2483               0 :                       aRgFirstRowIndex, aDamageArea);
    2484                 :   }
    2485                 : }
    2486                 : 
    2487               0 : void nsCellMap::ExpandZeroColSpans(nsTableCellMap& aMap)
    2488                 : {
    2489               0 :   NS_ASSERTION(!!aMap.mBCInfo == mIsBC, "BC state mismatch");
    2490               0 :   PRUint32 numRows = mRows.Length();
    2491               0 :   PRUint32 numCols = aMap.GetColCount();
    2492                 :   PRUint32 rowIndex, colIndex;
    2493                 : 
    2494               0 :   for (rowIndex = 0; rowIndex < numRows; rowIndex++) {
    2495               0 :     for (colIndex = 0; colIndex < numCols; colIndex++) {
    2496               0 :       CellData* data = mRows[rowIndex].SafeElementAt(colIndex);
    2497               0 :       if (!data || !data->IsOrig())
    2498               0 :         continue;
    2499               0 :       nsTableCellFrame* cell = data->GetCellFrame();
    2500               0 :       NS_ASSERTION(cell, "There has to be a cell");
    2501               0 :       PRInt32 cellRowSpan = cell->GetRowSpan();
    2502               0 :       PRInt32 cellColSpan = cell->GetColSpan();
    2503               0 :       bool rowZeroSpan = (0 == cell->GetRowSpan());
    2504               0 :       bool colZeroSpan = (0 == cell->GetColSpan());
    2505               0 :       if (colZeroSpan) {
    2506               0 :         aMap.mTableFrame.SetHasZeroColSpans(true);
    2507                 :         // do the expansion
    2508               0 :         NS_ASSERTION(numRows > 0, "Bogus numRows");
    2509               0 :         NS_ASSERTION(numCols > 0, "Bogus numCols");
    2510                 :         PRUint32 endRowIndex =  rowZeroSpan ? numRows - 1 :
    2511               0 :                                               rowIndex + cellRowSpan - 1;
    2512                 :         PRUint32 endColIndex =  colZeroSpan ? numCols - 1 :
    2513               0 :                                               colIndex + cellColSpan - 1;
    2514                 :         PRUint32 colX, rowX;
    2515               0 :         colX = colIndex + 1;
    2516               0 :         while (colX <= endColIndex) {
    2517                 :           // look at columns from here to our colspan.  For each one, check
    2518                 :           // the rows from here to our rowspan to make sure there is no
    2519                 :           // obstacle to marking that column as a zerospanned column; if there
    2520                 :           // isn't, mark it so
    2521               0 :           for (rowX = rowIndex; rowX <= endRowIndex; rowX++) {
    2522               0 :             CellData* oldData = GetDataAt(rowX, colX);
    2523               0 :             if (oldData) {
    2524               0 :               if (oldData->IsOrig()) {
    2525               0 :                 break; // something is in the way
    2526                 :               }
    2527               0 :               if (oldData->IsRowSpan()) {
    2528               0 :                 if ((rowX - rowIndex) != oldData->GetRowSpanOffset()) {
    2529               0 :                   break;
    2530                 :                 }
    2531                 :               }
    2532               0 :               if (oldData->IsColSpan()) {
    2533               0 :                 if ((colX - colIndex) != oldData->GetColSpanOffset()) {
    2534               0 :                   break;
    2535                 :                 }
    2536                 :               }
    2537                 :             }
    2538                 :           }
    2539               0 :           if (endRowIndex >= rowX)
    2540               0 :             break;// we hit something
    2541               0 :           for (rowX = rowIndex; rowX <= endRowIndex; rowX++) {
    2542               0 :             CellData* newData = AllocCellData(nsnull);
    2543               0 :             if (!newData) return;
    2544                 : 
    2545               0 :             newData->SetColSpanOffset(colX - colIndex);
    2546               0 :             newData->SetZeroColSpan(true);
    2547                 : 
    2548               0 :             if (rowX > rowIndex) {
    2549               0 :               newData->SetRowSpanOffset(rowX - rowIndex);
    2550               0 :               if (rowZeroSpan)
    2551               0 :                 newData->SetZeroRowSpan(true);
    2552                 :             }
    2553               0 :             SetDataAt(aMap, *newData, rowX, colX);
    2554                 :           }
    2555               0 :           colX++;
    2556                 :         }  // while (colX <= endColIndex)
    2557                 :       } // if zerocolspan
    2558                 :     }
    2559                 :   }
    2560                 : }
    2561                 : #ifdef NS_DEBUG
    2562               0 : void nsCellMap::Dump(bool aIsBorderCollapse) const
    2563                 : {
    2564               0 :   printf("\n  ***** START GROUP CELL MAP DUMP ***** %p\n", (void*)this);
    2565               0 :   nsTableRowGroupFrame* rg = GetRowGroup();
    2566               0 :   const nsStyleDisplay* display = rg->GetStyleDisplay();
    2567               0 :   switch (display->mDisplay) {
    2568                 :   case NS_STYLE_DISPLAY_TABLE_HEADER_GROUP:
    2569               0 :     printf("  thead ");
    2570               0 :     break;
    2571                 :   case NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP:
    2572               0 :     printf("  tfoot ");
    2573               0 :     break;
    2574                 :   case NS_STYLE_DISPLAY_TABLE_ROW_GROUP:
    2575               0 :     printf("  tbody ");
    2576               0 :     break;
    2577                 :   default:
    2578               0 :     printf("HUH? wrong display type on rowgroup");
    2579                 :   }
    2580               0 :   PRUint32 mapRowCount = mRows.Length();
    2581               0 :   printf("mapRowCount=%u tableRowCount=%d\n", mapRowCount, mContentRowCount);
    2582                 : 
    2583                 : 
    2584                 :   PRUint32 rowIndex, colIndex;
    2585               0 :   for (rowIndex = 0; rowIndex < mapRowCount; rowIndex++) {
    2586               0 :     const CellDataArray& row = mRows[rowIndex];
    2587               0 :     printf("  row %d : ", rowIndex);
    2588               0 :     PRUint32 colCount = row.Length();
    2589               0 :     for (colIndex = 0; colIndex < colCount; colIndex++) {
    2590               0 :       CellData* cd = row[colIndex];
    2591               0 :       if (cd) {
    2592               0 :         if (cd->IsOrig()) {
    2593               0 :           printf("C%d,%d  ", rowIndex, colIndex);
    2594                 :         } else {
    2595               0 :           if (cd->IsRowSpan()) {
    2596               0 :             printf("R ");
    2597                 :           }
    2598               0 :           if (cd->IsColSpan()) {
    2599               0 :             printf("C ");
    2600                 :           }
    2601               0 :           if (!(cd->IsRowSpan() && cd->IsColSpan())) {
    2602               0 :             printf("  ");
    2603                 :           }
    2604               0 :           printf("  ");
    2605                 :         }
    2606                 :       } else {
    2607               0 :         printf("----  ");
    2608                 :       }
    2609                 :     }
    2610               0 :     if (aIsBorderCollapse) {
    2611                 :       nscoord       size;
    2612                 :       BCBorderOwner owner;
    2613                 :       mozilla::css::Side side;
    2614                 :       bool          segStart;
    2615                 :       bool          bevel;
    2616               0 :       for (PRInt32 i = 0; i <= 2; i++) {
    2617               0 :         printf("\n          ");
    2618               0 :         for (colIndex = 0; colIndex < colCount; colIndex++) {
    2619               0 :           BCCellData* cd = (BCCellData *)row[colIndex];
    2620               0 :           if (cd) {
    2621               0 :             if (0 == i) {
    2622               0 :               size = cd->mData.GetTopEdge(owner, segStart);
    2623               0 :               printf("t=%d%d%d ", PRInt32(size), owner, segStart);
    2624                 :             }
    2625               0 :             else if (1 == i) {
    2626               0 :               size = cd->mData.GetLeftEdge(owner, segStart);
    2627               0 :               printf("l=%d%d%d ", PRInt32(size), owner, segStart);
    2628                 :             }
    2629                 :             else {
    2630               0 :               size = cd->mData.GetCorner(side, bevel);
    2631               0 :               printf("c=%d%d%d ", PRInt32(size), side, bevel);
    2632                 :             }
    2633                 :           }
    2634                 :         }
    2635                 :       }
    2636                 :     }
    2637               0 :     printf("\n");
    2638                 :   }
    2639                 : 
    2640                 :   // output info mapping Ci,j to cell address
    2641               0 :   PRUint32 cellCount = 0;
    2642               0 :   for (PRUint32 rIndex = 0; rIndex < mapRowCount; rIndex++) {
    2643               0 :     const CellDataArray& row = mRows[rIndex];
    2644               0 :     PRUint32 colCount = row.Length();
    2645               0 :     printf("  ");
    2646               0 :     for (colIndex = 0; colIndex < colCount; colIndex++) {
    2647               0 :       CellData* cd = row[colIndex];
    2648               0 :       if (cd) {
    2649               0 :         if (cd->IsOrig()) {
    2650               0 :           nsTableCellFrame* cellFrame = cd->GetCellFrame();
    2651                 :           PRInt32 cellFrameColIndex;
    2652               0 :           cellFrame->GetColIndex(cellFrameColIndex);
    2653                 :           printf("C%d,%d=%p(%d)  ", rIndex, colIndex, (void*)cellFrame,
    2654               0 :                  cellFrameColIndex);
    2655               0 :           cellCount++;
    2656                 :         }
    2657                 :       }
    2658                 :     }
    2659               0 :     printf("\n");
    2660                 :   }
    2661                 : 
    2662               0 :   printf("  ***** END GROUP CELL MAP DUMP *****\n");
    2663               0 : }
    2664                 : #endif
    2665                 : 
    2666                 : CellData*
    2667               0 : nsCellMap::GetDataAt(PRInt32         aMapRowIndex,
    2668                 :                      PRInt32         aColIndex) const
    2669                 : {
    2670                 :   return
    2671               0 :     mRows.SafeElementAt(aMapRowIndex, *sEmptyRow).SafeElementAt(aColIndex);
    2672                 : }
    2673                 : 
    2674                 : // only called if the cell at aMapRowIndex, aColIndex is null or dead
    2675                 : // (the latter from ExpandZeroColSpans).
    2676               0 : void nsCellMap::SetDataAt(nsTableCellMap& aMap,
    2677                 :                           CellData&       aNewCell,
    2678                 :                           PRInt32         aMapRowIndex,
    2679                 :                           PRInt32         aColIndex)
    2680                 : {
    2681               0 :   NS_ASSERTION(!!aMap.mBCInfo == mIsBC, "BC state mismatch");
    2682               0 :   if (PRUint32(aMapRowIndex) >= mRows.Length()) {
    2683               0 :     NS_ERROR("SetDataAt called with row index > num rows");
    2684               0 :     return;
    2685                 :   }
    2686                 : 
    2687               0 :   CellDataArray& row = mRows[aMapRowIndex];
    2688                 : 
    2689                 :   // the table map may need cols added
    2690               0 :   PRInt32 numColsToAdd = aColIndex + 1 - aMap.GetColCount();
    2691               0 :   if (numColsToAdd > 0) {
    2692               0 :     aMap.AddColsAtEnd(numColsToAdd);
    2693                 :   }
    2694                 :   // the row may need cols added
    2695               0 :   numColsToAdd = aColIndex + 1 - row.Length();
    2696               0 :   if (numColsToAdd > 0) {
    2697                 :     // XXXbz need to handle allocation failures.
    2698               0 :     GrowRow(row, numColsToAdd);
    2699                 :   }
    2700                 : 
    2701               0 :   DestroyCellData(row[aColIndex]);
    2702                 : 
    2703               0 :   row.ReplaceElementsAt(aColIndex, 1, &aNewCell);
    2704                 :   // update the originating cell counts if cell originates in this row, col
    2705               0 :   nsColInfo* colInfo = aMap.GetColInfoAt(aColIndex);
    2706               0 :   if (colInfo) {
    2707               0 :     if (aNewCell.IsOrig()) {
    2708               0 :       colInfo->mNumCellsOrig++;
    2709                 :     }
    2710               0 :     else if (aNewCell.IsColSpan()) {
    2711               0 :       colInfo->mNumCellsSpan++;
    2712                 :     }
    2713                 :   }
    2714               0 :   else NS_ERROR("SetDataAt called with col index > table map num cols");
    2715                 : }
    2716                 : 
    2717                 : nsTableCellFrame*
    2718               0 : nsCellMap::GetCellInfoAt(const nsTableCellMap& aMap,
    2719                 :                          PRInt32               aRowX,
    2720                 :                          PRInt32               aColX,
    2721                 :                          bool*               aOriginates,
    2722                 :                          PRInt32*              aColSpan) const
    2723                 : {
    2724               0 :   if (aOriginates) {
    2725               0 :     *aOriginates = false;
    2726                 :   }
    2727               0 :   CellData* data = GetDataAt(aRowX, aColX);
    2728               0 :   nsTableCellFrame* cellFrame = nsnull;
    2729               0 :   if (data) {
    2730               0 :     if (data->IsOrig()) {
    2731               0 :       cellFrame = data->GetCellFrame();
    2732               0 :       if (aOriginates)
    2733               0 :         *aOriginates = true;
    2734                 :     }
    2735                 :     else {
    2736               0 :       cellFrame = GetCellFrame(aRowX, aColX, *data, true);
    2737                 :     }
    2738               0 :     if (cellFrame && aColSpan) {
    2739                 :       PRInt32 initialColIndex;
    2740               0 :       cellFrame->GetColIndex(initialColIndex);
    2741                 :       bool zeroSpan;
    2742               0 :       *aColSpan = GetEffectiveColSpan(aMap, aRowX, initialColIndex, zeroSpan);
    2743                 :     }
    2744                 :   }
    2745               0 :   return cellFrame;
    2746                 : }
    2747                 : 
    2748                 : 
    2749               0 : bool nsCellMap::RowIsSpannedInto(PRInt32         aRowIndex,
    2750                 :                                    PRInt32         aNumEffCols) const
    2751                 : {
    2752               0 :   if ((0 > aRowIndex) || (aRowIndex >= mContentRowCount)) {
    2753               0 :     return false;
    2754                 :   }
    2755               0 :   for (PRInt32 colIndex = 0; colIndex < aNumEffCols; colIndex++) {
    2756               0 :     CellData* cd = GetDataAt(aRowIndex, colIndex);
    2757               0 :     if (cd) { // there's really a cell at (aRowIndex, colIndex)
    2758               0 :       if (cd->IsSpan()) { // the cell at (aRowIndex, colIndex) is the result of a span
    2759               0 :         if (cd->IsRowSpan() && GetCellFrame(aRowIndex, colIndex, *cd, true)) { // XXX why the last check
    2760               0 :           return true;
    2761                 :         }
    2762                 :       }
    2763                 :     }
    2764                 :   }
    2765               0 :   return false;
    2766                 : }
    2767                 : 
    2768               0 : bool nsCellMap::RowHasSpanningCells(PRInt32 aRowIndex,
    2769                 :                                       PRInt32 aNumEffCols) const
    2770                 : {
    2771               0 :   if ((0 > aRowIndex) || (aRowIndex >= mContentRowCount)) {
    2772               0 :     return false;
    2773                 :   }
    2774               0 :   if (aRowIndex != mContentRowCount - 1) {
    2775                 :     // aRowIndex is not the last row, so we check the next row after aRowIndex for spanners
    2776               0 :     for (PRInt32 colIndex = 0; colIndex < aNumEffCols; colIndex++) {
    2777               0 :       CellData* cd = GetDataAt(aRowIndex, colIndex);
    2778               0 :       if (cd && (cd->IsOrig())) { // cell originates
    2779               0 :         CellData* cd2 = GetDataAt(aRowIndex + 1, colIndex);
    2780               0 :         if (cd2 && cd2->IsRowSpan()) { // cd2 is spanned by a row
    2781               0 :           if (cd->GetCellFrame() == GetCellFrame(aRowIndex + 1, colIndex, *cd2, true)) {
    2782               0 :             return true;
    2783                 :           }
    2784                 :         }
    2785                 :       }
    2786                 :     }
    2787                 :   }
    2788               0 :   return false;
    2789                 : }
    2790                 : 
    2791               0 : void nsCellMap::DestroyCellData(CellData* aData)
    2792                 : {
    2793               0 :   if (!aData) {
    2794               0 :     return;
    2795                 :   }
    2796                 : 
    2797               0 :   if (mIsBC) {
    2798               0 :     BCCellData* bcData = static_cast<BCCellData*>(aData);
    2799               0 :     bcData->~BCCellData();
    2800               0 :     mPresContext->FreeToShell(sizeof(BCCellData), bcData);
    2801                 :   } else {
    2802               0 :     aData->~CellData();
    2803               0 :     mPresContext->FreeToShell(sizeof(CellData), aData);
    2804                 :   }
    2805                 : }
    2806                 : 
    2807               0 : CellData* nsCellMap::AllocCellData(nsTableCellFrame* aOrigCell)
    2808                 : {
    2809               0 :   if (mIsBC) {
    2810                 :     BCCellData* data = (BCCellData*)
    2811               0 :       mPresContext->AllocateFromShell(sizeof(BCCellData));
    2812               0 :     if (data) {
    2813               0 :       new (data) BCCellData(aOrigCell);
    2814                 :     }
    2815               0 :     return data;
    2816                 :   }
    2817                 : 
    2818                 :   CellData* data = (CellData*)
    2819               0 :     mPresContext->AllocateFromShell(sizeof(CellData));
    2820               0 :   if (data) {
    2821               0 :     new (data) CellData(aOrigCell);
    2822                 :   }
    2823               0 :   return data;
    2824                 : }
    2825                 : 
    2826                 : void
    2827               0 : nsCellMapColumnIterator::AdvanceRowGroup()
    2828                 : {
    2829               0 :   do {
    2830               0 :     mCurMapStart += mCurMapContentRowCount;
    2831               0 :     mCurMap = mCurMap->GetNextSibling();
    2832               0 :     if (!mCurMap) {
    2833                 :       // Set mCurMapContentRowCount and mCurMapRelevantRowCount to 0 in case
    2834                 :       // mCurMap has no next sibling.  This can happen if we just handled the
    2835                 :       // last originating cell.  Future calls will end up with mFoundCells ==
    2836                 :       // mOrigCells, but for this one mFoundCells was definitely not big enough
    2837                 :       // if we got here.
    2838               0 :       mCurMapContentRowCount = 0;
    2839               0 :       mCurMapRelevantRowCount = 0;
    2840               0 :       break;
    2841                 :     }
    2842                 : 
    2843               0 :     mCurMapContentRowCount = mCurMap->GetRowCount();
    2844               0 :     PRUint32 rowArrayLength = mCurMap->mRows.Length();
    2845               0 :     mCurMapRelevantRowCount = NS_MIN(mCurMapContentRowCount, rowArrayLength);
    2846                 :   } while (0 == mCurMapRelevantRowCount);
    2847                 : 
    2848               0 :   NS_ASSERTION(mCurMapRelevantRowCount != 0 || !mCurMap,
    2849                 :                "How did that happen?");
    2850                 : 
    2851                 :   // Set mCurMapRow to 0, since cells can't span across table row groups.
    2852               0 :   mCurMapRow = 0;
    2853               0 : }
    2854                 : 
    2855                 : void
    2856               0 : nsCellMapColumnIterator::IncrementRow(PRInt32 aIncrement)
    2857                 : {
    2858               0 :   NS_PRECONDITION(aIncrement >= 0, "Bogus increment");
    2859               0 :   NS_PRECONDITION(mCurMap, "Bogus mOrigCells?");
    2860               0 :   if (aIncrement == 0) {
    2861               0 :     AdvanceRowGroup();
    2862                 :   }
    2863                 :   else {
    2864               0 :     mCurMapRow += aIncrement;
    2865               0 :     if (mCurMapRow >= mCurMapRelevantRowCount) {
    2866               0 :       AdvanceRowGroup();
    2867                 :     }
    2868                 :   }
    2869               0 : }
    2870                 : 
    2871                 : nsTableCellFrame*
    2872               0 : nsCellMapColumnIterator::GetNextFrame(PRInt32* aRow, PRInt32* aColSpan)
    2873                 : {
    2874                 :   // Fast-path for the case when we don't have anything left in the column and
    2875                 :   // we know it.
    2876               0 :   if (mFoundCells == mOrigCells) {
    2877               0 :     *aRow = 0;
    2878               0 :     *aColSpan = 1;
    2879               0 :     return nsnull;
    2880                 :   }
    2881                 : 
    2882               0 :   while (1) {
    2883               0 :     NS_ASSERTION(mCurMapRow < mCurMapRelevantRowCount, "Bogus mOrigCells?");
    2884                 :     // Safe to just get the row (which is faster than calling GetDataAt(), but
    2885                 :     // there may not be that many cells in it, so have to use SafeElementAt for
    2886                 :     // the mCol.
    2887               0 :     const nsCellMap::CellDataArray& row = mCurMap->mRows[mCurMapRow];
    2888               0 :     CellData* cellData = row.SafeElementAt(mCol);
    2889               0 :     if (!cellData || cellData->IsDead()) {
    2890                 :       // Could hit this if there are fewer cells in this row than others, for
    2891                 :       // example.
    2892               0 :       IncrementRow(1);
    2893               0 :       continue;
    2894                 :     }
    2895                 : 
    2896               0 :     if (cellData->IsColSpan()) {
    2897                 :       // Look up the originating data for this cell, advance by its relative rowspan.
    2898               0 :       PRInt32 rowspanOffset = cellData->GetRowSpanOffset();
    2899               0 :       nsTableCellFrame* cellFrame = mCurMap->GetCellFrame(mCurMapRow, mCol, *cellData, false);
    2900               0 :       NS_ASSERTION(cellFrame,"Must have usable originating data here");
    2901               0 :       PRInt32 rowSpan = cellFrame->GetRowSpan();
    2902               0 :       if (rowSpan == 0) {
    2903               0 :         AdvanceRowGroup();
    2904                 :       }
    2905                 :       else {
    2906               0 :         IncrementRow(rowSpan - rowspanOffset);
    2907                 :       }
    2908               0 :       continue;
    2909                 :     }
    2910                 : 
    2911               0 :     NS_ASSERTION(cellData->IsOrig(),
    2912                 :                  "Must have originating cellData by this point.  "
    2913                 :                  "See comment on mCurMapRow in header.");
    2914                 : 
    2915               0 :     nsTableCellFrame* cellFrame = cellData->GetCellFrame();
    2916               0 :     NS_ASSERTION(cellFrame, "Orig data without cellframe?");
    2917                 : 
    2918               0 :     *aRow = mCurMapStart + mCurMapRow;
    2919                 :     bool ignoredZeroSpan;
    2920                 :     *aColSpan = mCurMap->GetEffectiveColSpan(*mMap, mCurMapRow, mCol,
    2921               0 :                                              ignoredZeroSpan);
    2922                 : 
    2923               0 :     IncrementRow(cellFrame->GetRowSpan());
    2924                 : 
    2925               0 :     ++mFoundCells;
    2926                 : 
    2927               0 :     NS_ABORT_IF_FALSE(cellData == mMap->GetDataAt(*aRow, mCol),
    2928                 :                       "Giving caller bogus row?");
    2929                 : 
    2930               0 :     return cellFrame;
    2931                 :   }
    2932                 : 
    2933                 :   NS_NOTREACHED("Can't get here");
    2934                 :   return nsnull;
    2935                 : }

Generated by: LCOV version 1.7