Make it possible for callers who want to iterate all the row groups and

GetMapFor() for all of them do so in about O(N) time instead of O(N^2) (in
number of row groups).  Bug 366892, r=bernd, sr=roc
This commit is contained in:
bzbarsky%mit.edu 2007-01-22 04:35:25 +00:00
Родитель 8318e48ec4
Коммит ed9ad7b7bf
3 изменённых файлов: 59 добавлений и 20 удалений

Просмотреть файл

@ -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;

Просмотреть файл

@ -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);

Просмотреть файл

@ -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