diff --git a/layout/tables/BasicTableLayoutStrategy.cpp b/layout/tables/BasicTableLayoutStrategy.cpp index eeff54cb763..4a84782dccd 100644 --- a/layout/tables/BasicTableLayoutStrategy.cpp +++ b/layout/tables/BasicTableLayoutStrategy.cpp @@ -269,15 +269,10 @@ BasicTableLayoutStrategy::ComputeColumnIntrinsicWidths(nsIRenderingContext* aRen // Consider the contents of and the widths on the cells without // colspans. - for (PRInt32 row = 0, row_end = cellMap->GetRowCount(); - row < row_end; ++row) { - PRBool originates; - PRInt32 colSpan; - nsTableCellFrame *cellFrame = - cellMap->GetCellInfoAt(row, col, &originates, &colSpan); - if (!cellFrame || !originates) { - continue; - } + nsCellMapColumnIterator columnIter(cellMap, col); + PRInt32 row, colSpan; + nsTableCellFrame* cellFrame; + while ((cellFrame = columnIter.GetNextFrame(&row, &colSpan))) { if (colSpan > 1) { spanningCells.AddCell(colSpan, row, col); continue; diff --git a/layout/tables/nsCellMap.cpp b/layout/tables/nsCellMap.cpp index 56430358c17..d2fdd6d7155 100644 --- a/layout/tables/nsCellMap.cpp +++ b/layout/tables/nsCellMap.cpp @@ -2679,3 +2679,90 @@ CellData* nsCellMap::AllocCellData(nsTableCellFrame* aOrigCell) } return data; } + +void +nsCellMapColumnIterator::AdvanceRowGroup() +{ + mCurMap = mCurMap->GetNextSibling(); + + /* mCurMap could now be null, if we just handled the last originating cell. + Future calls will end up with mFoundCells == mOrigCells, but for this + one mFoundCells was definitely not big enough if we got here... */ + mCurMapRowCount = mCurMap ? mCurMap->GetRowCount() : 0; + + // Set mRow to 0, since cells can't span across table row groups. + mRow = 0; +} + +void +nsCellMapColumnIterator::IncrementRow(PRInt32 aIncrement) +{ + NS_PRECONDITION(aIncrement >= 0, "Bogus increment"); + NS_PRECONDITION(mCurMap, "Bogus mOrigCells?"); + if (aIncrement == 0) { + // This will span to the end of the row group + AdvanceRowGroup(); + } + else { + mRow += aIncrement; + if (mRow >= mCurMapRowCount) { + AdvanceRowGroup(); + } + } +} + +nsTableCellFrame* +nsCellMapColumnIterator::GetNextFrame(PRInt32* aRow, PRInt32* aColSpan) +{ + // Fast-path for the case when we don't have anything left in the column and + // we know it. + if (mFoundCells == mOrigCells) { + *aRow = 0; + *aColSpan = 1; + return nsnull; + } + + while (1) { + NS_ASSERTION(mRow < mCurMapRowCount, "Bogus mOrigCells?"); + // Safe to just get the row (which is faster than calling GetDataAt(), but + // there may not be that many cells in it, so have to use SafeElementAt for + // the mCol. + const nsCellMap::CellDataArray& row = mCurMap->mRows[mRow]; + CellData* cellData = row.SafeElementAt(mCol); + if (!cellData || cellData->IsDead()) { + // Could hit this if there are fewer cells in this row than others, for + // example. + IncrementRow(1); + continue; + } + + if (cellData->IsColSpan()) { + // Look up the originating data for this cell, advance by its rowspan. + CellData* origData = row[mCol - cellData->GetColSpanOffset()]; + NS_ASSERTION(origData && origData->IsOrig() && origData->GetCellFrame(), + "Must have usable originating data here"); + IncrementRow(origData->GetCellFrame()->GetRowSpan()); + continue; + } + + NS_ASSERTION(cellData->IsOrig(), + "Must have originating cellData by this point. " + "See comment on mRow in header."); + + nsTableCellFrame* cellFrame = cellData->GetCellFrame(); + NS_ASSERTION(cellFrame, "Orig data without cellframe?"); + + *aRow = mRow; + PRBool ignoredZeroSpan; + *aColSpan = mCurMap->GetEffectiveColSpan(*mMap, mRow, mCol, ignoredZeroSpan); + + IncrementRow(cellFrame->GetRowSpan()); + + ++mFoundCells; + + return cellFrame; + } + + NS_NOTREACHED("Can't get here"); + return nsnull; +} diff --git a/layout/tables/nsCellMap.h b/layout/tables/nsCellMap.h index 51cb8ffc08c..19de700dbcd 100644 --- a/layout/tables/nsCellMap.h +++ b/layout/tables/nsCellMap.h @@ -51,6 +51,7 @@ class nsTableRowGroupFrame; class nsTableFrame; class nsCellMap; class nsPresContext; +class nsCellMapColumnIterator; struct nsColInfo { @@ -233,6 +234,8 @@ protected: friend class nsCellMap; friend class BCMapCellIterator; friend class BCMapBorderIterator; + friend class nsCellMapColumnIterator; + /** Insert a row group cellmap after aPrevMap, if aPrefMap is null insert it * at the beginning, the ordering of the cellmap corresponds to the ordering of * rowgroups once OrderRowGroups has been called @@ -403,6 +406,7 @@ protected: friend class BCMapCellIterator; friend class BCMapBorderIterator; friend class nsTableFrame; + friend class nsCellMapColumnIterator; /** * Increase the number of rows in this cellmap by aNumRows. Put the @@ -539,6 +543,47 @@ protected: nsCOMPtr mPresContext; }; +/** + * A class for iterating the cells in a given column. Must be given a + * non-null nsTableCellMap and a column number valid for that cellmap. + */ +class nsCellMapColumnIterator +{ +public: + nsCellMapColumnIterator(const nsTableCellMap* aMap, PRInt32 aCol) : + mMap(aMap), mCurMap(aMap->mFirstMap), mRow(0), mCol(aCol), mFoundCells(0) + { + NS_PRECONDITION(aMap, "Must have map"); + NS_PRECONDITION(mCol < aMap->GetColCount(), "Invalid column"); + mOrigCells = aMap->GetNumCellsOriginatingInCol(mCol); + if (mCurMap) { + mCurMapRowCount = mCurMap->GetRowCount(); + } + } + + nsTableCellFrame* GetNextFrame(PRInt32* aRow, PRInt32* aColSpan); + +private: + void AdvanceRowGroup(); + + // Advance the row; aIncrement is considered to be a cell's rowspan, + // so if 0 is passed in we'll advance to the next rowgroup. + void IncrementRow(PRInt32 aIncrement); + + const nsTableCellMap* mMap; + const nsCellMap* mCurMap; + // In steady-state mRow is the row in our current nsCellMap that we'll use + // the next time GetNextFrame() is called. Due to the way we skip over + // rowspans, the entry in mRow and mCol is either null, dead, originating, or + // a colspan. In particular, it cannot be a rowspan or overlap entry. + PRUint32 mRow; + const PRInt32 mCol; + PRUint32 mOrigCells; + PRUint32 mFoundCells; + PRUint32 mCurMapRowCount; +}; + + /* ----- inline methods ----- */ inline PRInt32 nsTableCellMap::GetColCount() const {