LCOV - code coverage report
Current view: top level - layout/tables - nsCellMap.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 4 1394 0.3 %
Date: 2017-07-14 16:53:18 Functions: 1 83 1.2 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13