diff --git a/layout/tables/nsCellMap.cpp b/layout/tables/nsCellMap.cpp index d2fdd6d7155e..da374d19c0c0 100644 --- a/layout/tables/nsCellMap.cpp +++ b/layout/tables/nsCellMap.cpp @@ -261,17 +261,40 @@ void nsTableCellMap::RemoveGroupCellMap(nsTableRowGroupFrame* aGroup) } } -nsCellMap* -nsTableCellMap::GetMapFor(nsTableRowGroupFrame& aRowGroup) +static nsCellMap* +FindMapFor(const nsTableRowGroupFrame* aRowGroup, + nsCellMap* aStart, + const nsCellMap* aEnd) { - NS_ASSERTION(!aRowGroup.GetPrevInFlow(), "GetMapFor called with continuation"); - for (nsCellMap* map = mFirstMap; map; map = map->GetNextSibling()) { - if (&aRowGroup == map->GetRowGroup()) { + for (nsCellMap* map = aStart; map != aEnd; map = map->GetNextSibling()) { + if (aRowGroup == map->GetRowGroup()) { return map; } } + + return nsnull; +} + +nsCellMap* +nsTableCellMap::GetMapFor(const nsTableRowGroupFrame* aRowGroup, + nsCellMap* aStartHint) const +{ + NS_PRECONDITION(aRowGroup, "Must have a rowgroup"); + NS_ASSERTION(!aRowGroup->GetPrevInFlow(), "GetMapFor called with continuation"); + if (aStartHint) { + nsCellMap* map = FindMapFor(aRowGroup, aStartHint, nsnull); + if (map) { + return map; + } + } + + nsCellMap* map = FindMapFor(aRowGroup, mFirstMap, aStartHint); + if (map) { + return map; + } + // if aRowGroup is a repeated header or footer find the header or footer it was repeated from - if (aRowGroup.IsRepeatable()) { + if (aRowGroup->IsRepeatable()) { nsTableFrame* fifTable = NS_STATIC_CAST(nsTableFrame*, mTableFrame.GetFirstInFlow()); nsAutoVoidArray rowGroups; @@ -280,16 +303,12 @@ nsTableCellMap::GetMapFor(nsTableRowGroupFrame& aRowGroup) // find the original header/footer fifTable->OrderRowGroups(rowGroups, numRowGroups, &thead, &tfoot); - const nsStyleDisplay* display = aRowGroup.GetStyleDisplay(); + const nsStyleDisplay* display = aRowGroup->GetStyleDisplay(); nsTableRowGroupFrame* rgOrig = (NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == display->mDisplay) ? thead : tfoot; // find the row group cell map using the original header/footer - if (rgOrig) { - for (nsCellMap* map = mFirstMap; map; map = map->GetNextSibling()) { - if (rgOrig == map->GetRowGroup()) { - return map; - } - } + if (rgOrig && rgOrig != aRowGroup) { + return GetMapFor(rgOrig, aStartHint); } } @@ -310,11 +329,13 @@ nsTableCellMap::Synchronize(nsTableFrame* aTableFrame) return; } + // Scope |map| outside the loop so we can use it as a hint. + nsCellMap* map = nsnull; for (PRUint32 rgX = 0; rgX < numRowGroups; rgX++) { nsTableRowGroupFrame* rgFrame = nsTableFrame::GetRowGroupFrame((nsIFrame*)orderedRowGroups.ElementAt(rgX)); if (rgFrame) { - nsCellMap* map = GetMapFor(*rgFrame); + map = GetMapFor(rgFrame, map); if (map) { if (!maps.AppendElement(map)) { delete map; diff --git a/layout/tables/nsCellMap.h b/layout/tables/nsCellMap.h index 19de700dbcd0..443ed6a05414 100644 --- a/layout/tables/nsCellMap.h +++ b/layout/tables/nsCellMap.h @@ -94,7 +94,16 @@ public: void InsertGroupCellMap(nsTableRowGroupFrame& aNewRowGroup, nsTableRowGroupFrame*& aPrevRowGroup); - nsCellMap* GetMapFor(nsTableRowGroupFrame& aRowGroup); + /** + * Get the nsCellMap for the given row group. If aStartHint is non-null, + * will start looking with that cellmap and only fall back to starting at the + * beginning of the list if that doesn't find us the right nsCellMap. + * Otherwise, just start at the beginning. + * + * aRowGroup must not be null. + */ + nsCellMap* GetMapFor(const nsTableRowGroupFrame* aRowGroup, + nsCellMap* aStartHint) const; /** synchronize the cellmaps with the rowgroups again **/ void Synchronize(nsTableFrame* aTableFrame); diff --git a/layout/tables/nsTableFrame.cpp b/layout/tables/nsTableFrame.cpp index f71efb3bf714..074cc8399833 100644 --- a/layout/tables/nsTableFrame.cpp +++ b/layout/tables/nsTableFrame.cpp @@ -4172,14 +4172,16 @@ BCMapCellIterator::SetNewRowGroup(PRBool aFindFirstDamagedRow) mAtEnd = PR_TRUE; mRowGroupIndex++; PRInt32 numRowGroups = mRowGroups.Count(); + mCellMap = nsnull; for (PRInt32 rgX = mRowGroupIndex; rgX < numRowGroups; rgX++) { - nsIFrame* frame = (nsTableRowGroupFrame*)mRowGroups.ElementAt(mRowGroupIndex); if (!frame) ABORT1(PR_FALSE); + nsIFrame* frame = (nsIFrame*)mRowGroups.ElementAt(mRowGroupIndex); if (!frame) ABORT1(PR_FALSE); mRowGroup = mTableFrame.GetRowGroupFrame(frame); if (!mRowGroup) ABORT1(PR_FALSE); PRInt32 rowCount = mRowGroup->GetRowCount(); mRowGroupStart = mRowGroup->GetStartRowIndex(); mRowGroupEnd = mRowGroupStart + rowCount - 1; if (rowCount > 0) { - mCellMap = mTableCellMap->GetMapFor(*mRowGroup); if (!mCellMap) ABORT1(PR_FALSE); + mCellMap = mTableCellMap->GetMapFor(mRowGroup, mCellMap); + if (!mCellMap) ABORT1(PR_FALSE); nsTableRowFrame* firstRow = mRowGroup->GetFirstRow(); if (aFindFirstDamagedRow) { if ((mAreaStart.y >= mRowGroupStart) && (mAreaStart.y <= mRowGroupEnd)) { @@ -4306,7 +4308,7 @@ BCMapCellIterator::PeekBottom(BCMapCellInfo& aRefInfo, nsIFrame* frame = (nsTableRowGroupFrame*)mRowGroups.ElementAt(nextRgIndex); if (!frame) ABORT0(); rg = mTableFrame.GetRowGroupFrame(frame); if (rg) { - cellMap = mTableCellMap->GetMapFor(*rg); if (!cellMap) ABORT0(); + cellMap = mTableCellMap->GetMapFor(rg, cellMap); if (!cellMap) ABORT0(); rgRowIndex = 0; nextRow = rg->GetFirstRow(); } @@ -4917,6 +4919,9 @@ nsTableFrame::ExpandBCDamageArea(nsRect& aRect) const PRUint32 numRowGroups; nsVoidArray rowGroups; OrderRowGroups(rowGroups, numRowGroups); + + // Scope outside loop to be used as hint. + nsCellMap* cellMap = nsnull; for (PRUint32 rgX = 0; rgX < numRowGroups; rgX++) { nsIFrame* kidFrame = (nsIFrame*)rowGroups.ElementAt(rgX); nsTableRowGroupFrame* rgFrame = GetRowGroupFrame(kidFrame); if (!rgFrame) ABORT0(); @@ -4924,7 +4929,8 @@ nsTableFrame::ExpandBCDamageArea(nsRect& aRect) const PRInt32 rgEndY = rgStartY + rgFrame->GetRowCount() - 1; if (dEndY < rgStartY) break; - nsCellMap* cellMap = tableCellMap->GetMapFor(*rgFrame); if (!cellMap) ABORT0(); + cellMap = tableCellMap->GetMapFor(rgFrame, cellMap); + if (!cellMap) ABORT0(); // check for spanners from above and below if ((dStartY > 0) && (dStartY >= rgStartY) && (dStartY <= rgEndY)) { if (PRUint32(dStartY - rgStartY) >= cellMap->mRows.Length()) @@ -5815,7 +5821,10 @@ BCMapBorderIterator::SetNewRowGroup() rowGroupEnd = rowGroupStart + rg->GetRowCount() - 1; if (SetNewRow(rg->GetFirstRow())) { - cellMap = tableCellMap->GetMapFor(*(nsTableRowGroupFrame*)rg->GetFirstInFlow()); if (!cellMap) ABORT1(PR_FALSE); + cellMap = + tableCellMap->GetMapFor((nsTableRowGroupFrame*)rg->GetFirstInFlow(), + nsnull); + if (!cellMap) ABORT1(PR_FALSE); } if (rg && table->GetPrevInFlow() && !rg->GetPrevInFlow()) { // if rg doesn't have a prev in flow, then it may be a repeated header or footer