added ColIsSpannedInto, ColHasSpanningCells

moved *IsSpannedInto and *HasSpanningCells into cellmap, giving us the oppurtunity
to easily cache results if we want.  These methods are still accessed through nsTableFrame.
changed nsTableFrame::GetCellAt to nsTableFrame::GetCellFrameAt to make it more clear what
the method returns:  a frame, not content.
This commit is contained in:
buster%netscape.com 1998-09-18 22:37:14 +00:00
parent b044f59743
commit 9a953b8672
12 changed files with 774 additions and 62 deletions

View File

@ -306,7 +306,7 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths()
PRBool cellGrantingWidth=PR_TRUE;
for (rowIndex = 0; rowIndex<numRows; rowIndex++)
{
nsTableCellFrame * cellFrame = mTableFrame->GetCellAt(rowIndex, colIndex);
nsTableCellFrame * cellFrame = mTableFrame->GetCellFrameAt(rowIndex, colIndex);
if (nsnull==cellFrame)
{ // there is no cell in this row that corresponds to this column
continue;
@ -704,7 +704,7 @@ void BasicTableLayoutStrategy::SetMinAndMaxTableWidths()
for (colIndex = 0; colIndex<mNumCols; colIndex++)
{
if (gsDebug) printf(" col %d\n", colIndex);
nsTableCellFrame * cellFrame = mTableFrame->GetCellAt(rowIndex, colIndex);
nsTableCellFrame * cellFrame = mTableFrame->GetCellFrameAt(rowIndex, colIndex);
rowMinWidth += colInset;
rowMaxWidth += colInset;
if (nsnull==cellFrame)
@ -1053,7 +1053,7 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(const nsReflowState& aR
{
for (rowIndex = 0; rowIndex<numRows; rowIndex++)
{ // this col has proportional width, so determine its width requirements
nsTableCellFrame * cellFrame = mTableFrame->GetCellAt(rowIndex, colIndex);
nsTableCellFrame * cellFrame = mTableFrame->GetCellFrameAt(rowIndex, colIndex);
if (nsnull==cellFrame)
{ // there is no cell in this row that corresponds to this column
continue;
@ -1770,7 +1770,7 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsConstrained( const nsReflowState&
{
for (rowIndex = 0; rowIndex<numRows; rowIndex++)
{
nsTableCellFrame * cellFrame = mTableFrame->GetCellAt(rowIndex, colIndex);
nsTableCellFrame * cellFrame = mTableFrame->GetCellFrameAt(rowIndex, colIndex);
if (nsnull==cellFrame)
{ // there is no cell in this row that corresponds to this column
continue;

View File

@ -19,6 +19,7 @@
#include "nsVoidArray.h"
#include "nsCellMap.h"
#include "nsTableFrame.h"
#include "nsTableCellFrame.h"
#ifdef NS_DEBUG
static PRBool gsDebug = PR_FALSE;
@ -226,4 +227,187 @@ PRInt32 nsCellMap::GetNextAvailColIndex(PRInt32 aRowIndex, PRInt32 aColIndex) co
return result;
}
/** returns PR_TRUE if the row at aRowIndex has any cells that are the result
* of a row-spanning cell above it. So, given this table:<BR>
* <PRE>
* TABLE
* TR
* TD ROWSPAN=2
* TD
* TR
* TD
* </PRE>
* RowIsSpannedInto(0) returns PR_FALSE, and RowIsSpannedInto(1) returns PR_TRUE.
* @see RowHasSpanningCells
*/
// if computing this and related info gets expensive, we can easily
// cache it. The only thing to remember is to rebuild the cache
// whenever a row|col|cell is added/deleted, or a span attribute is changed.
PRBool nsCellMap::RowIsSpannedInto(PRInt32 aRowIndex)
{
NS_PRECONDITION (0<=aRowIndex && aRowIndex<GetRowCount(), "bad row index arg");
PRBool result = PR_FALSE;
PRInt32 colCount = GetColCount();
for (PRInt32 colIndex=0; colIndex<colCount; colIndex++)
{
CellData *cd = GetCellAt(aRowIndex, colIndex);
if (cd != nsnull)
{ // there's really a cell at (aRowIndex, colIndex)
if (nsnull==cd->mCell)
{ // the cell at (aRowIndex, colIndex) is the result of a span
nsTableCellFrame *cell = cd->mRealCell->mCell;
NS_ASSERTION(nsnull!=cell, "bad cell map state, missing real cell");
const PRInt32 realRowIndex = cell->GetRowIndex ();
if (realRowIndex!=aRowIndex)
{ // the span is caused by a rowspan
result = PR_TRUE;
break;
}
}
}
}
return result;
}
/** returns PR_TRUE if the row at aRowIndex has any cells that have a rowspan>1
* So, given this table:<BR>
* <PRE>
* TABLE
* TR
* TD ROWSPAN=2
* TD
* TR
* TD
* </PRE>
* RowHasSpanningCells(0) returns PR_TRUE, and RowHasSpanningCells(1) returns PR_FALSE.
* @see RowIsSpannedInto
*/
PRBool nsCellMap::RowHasSpanningCells(PRInt32 aRowIndex)
{
NS_PRECONDITION (0<=aRowIndex && aRowIndex<GetRowCount(), "bad row index arg");
PRBool result = PR_FALSE;
const PRInt32 rowCount = GetRowCount();
if (aRowIndex!=rowCount-1)
{ // aRowIndex is not the last row, so we check the next row after aRowIndex for spanners
const PRInt32 colCount = GetColCount();
for (PRInt32 colIndex=0; colIndex<colCount; colIndex++)
{
PRInt32 nextRowIndex = aRowIndex+1;
CellData *cd =GetCellAt(nextRowIndex, colIndex);
if (cd != nsnull)
{ // there's really a cell at (nextRowIndex, colIndex)
if (nsnull==cd->mCell)
{ // the cell at (nextRowIndex, colIndex) is the result of a span
nsTableCellFrame *cell = cd->mRealCell->mCell;
NS_ASSERTION(nsnull!=cell, "bad cell map state, missing real cell");
const PRInt32 realRowIndex = cell->GetRowIndex ();
if (realRowIndex!=nextRowIndex)
{ // the span is caused by a rowspan
CellData *spanningCell = GetCellAt(aRowIndex, colIndex);
if (nsnull!=spanningCell)
{ // there's really a cell at (aRowIndex, colIndex)
if (nsnull!=spanningCell->mCell)
{ // aRowIndex is where the rowspan originated
result = PR_TRUE;
break;
}
}
}
}
}
}
}
return result;
}
/** returns PR_TRUE if the col at aColIndex has any cells that are the result
* of a col-spanning cell. So, given this table:<BR>
* <PRE>
* TABLE
* TR
* TD COLSPAN=2
* TD
* TD
* </PRE>
* ColIsSpannedInto(0) returns PR_FALSE, ColIsSpannedInto(1) returns PR_TRUE,
* and ColIsSpannedInto(2) returns PR_FALSE.
* @see ColHasSpanningCells
*/
PRBool nsCellMap::ColIsSpannedInto(PRInt32 aColIndex)
{
NS_PRECONDITION (0<=aColIndex && aColIndex<GetColCount(), "bad col index arg");
PRBool result = PR_FALSE;
PRInt32 rowCount = GetRowCount();
for (PRInt32 rowIndex=0; rowIndex<rowCount; rowIndex++)
{
CellData *cd =GetCellAt(rowIndex, aColIndex);
if (cd != nsnull)
{ // there's really a cell at (aRowIndex, aColIndex)
if (nsnull==cd->mCell)
{ // the cell at (rowIndex, aColIndex) is the result of a span
nsTableCellFrame *cell = cd->mRealCell->mCell;
NS_ASSERTION(nsnull!=cell, "bad cell map state, missing real cell");
const PRInt32 realColIndex = cell->GetColIndex ();
if (realColIndex!=aColIndex)
{ // the span is caused by a colspan
result = PR_TRUE;
break;
}
}
}
}
return result;
}
/** returns PR_TRUE if the row at aColIndex has any cells that have a colspan>1
* So, given this table:<BR>
* <PRE>
* TABLE
* TR
* TD COLSPAN=2
* TD
* </PRE>
* ColHasSpanningCells(0) returns PR_TRUE, and ColHasSpanningCells(1) returns PR_FALSE.
* @see ColIsSpannedInto
*/
PRBool nsCellMap::ColHasSpanningCells(PRInt32 aColIndex)
{
NS_PRECONDITION (0<=aColIndex && aColIndex<GetColCount(), "bad col index arg");
PRBool result = PR_FALSE;
const PRInt32 colCount = GetColCount();
if (aColIndex!=colCount-1)
{ // aColIndex is not the last col, so we check the next col after aColIndex for spanners
const PRInt32 rowCount = GetRowCount();
for (PRInt32 rowIndex=0; rowIndex<rowCount; rowIndex++)
{
PRInt32 nextColIndex = aColIndex+1;
CellData *cd =GetCellAt(rowIndex, nextColIndex);
if (cd != nsnull)
{ // there's really a cell at (rowIndex, nextColIndex)
if (nsnull==cd->mCell)
{ // the cell at (rowIndex, nextColIndex) is the result of a span
nsTableCellFrame *cell = cd->mRealCell->mCell;
NS_ASSERTION(nsnull!=cell, "bad cell map state, missing real cell");
const PRInt32 realColIndex = cell->GetColIndex ();
if (realColIndex!=nextColIndex)
{ // the span is caused by a colspan
CellData *spanningCell =GetCellAt(rowIndex, aColIndex);
if (nsnull!=spanningCell)
{ // there's really a cell at (rowIndex, aColIndex)
if (nsnull!=spanningCell->mCell)
{ // aCowIndex is where the cowspan originated
result = PR_TRUE;
break;
}
}
}
}
}
}
}
return result;
}

View File

@ -44,7 +44,10 @@ protected:
/** storage for rows */
nsVoidArray *mRows;
/** storage for CellData pointers */
/** storage for min col span info, just an int that gives the smallest
* colspan for all cells originating in each column. If allocated,
* each entry must be >= 1.
*/
PRInt32 *mMinColSpans;
/** a cache of the column frames, by col index */
@ -62,8 +65,8 @@ protected:
public:
/** constructor
* @param aRows - initial number of rows
* @param aColumns - initial number of columns
*/
* @param aColumns - initial number of columns
*/
nsCellMap(PRInt32 aRows, PRInt32 aColumns);
/** destructor
@ -113,22 +116,69 @@ public:
/** add a column frame to the list of column frames
* column frames must be added in order
*/
*/
void AppendColumnFrame(nsTableColFrame *aColFrame);
/** return PR_TRUE if aRowIndex has any cells with rowspan>1 contained
* within it (not just cells that are in the row, but cells that span
* into the row as well.
*/
PRBool RowImpactedBySpanningCell(PRInt32 aRowIndex);
/** returns PR_TRUE if the row at aRowIndex has any cells that are the result
* of a row-spanning cell above it. So, given this table:<BR>
* <PRE>
* TABLE
* TR
* TD ROWSPAN=2
* TD
* TR
* TD
* </PRE>
* RowIsSpannedInto(0) returns PR_FALSE, and RowIsSpannedInto(1) returns PR_TRUE.
* @see RowHasSpanningCells
*/
PRBool RowIsSpannedInto(PRInt32 aRowIndex);
/** return PR_TRUE if aColIndex has any cells with colspan>1 contained
* within it (not just cells that are in the col, but cells that span
* into the col as well.
*/
PRBool ColumnImpactedBySpanningCell(PRInt32 aColIndex);
/** returns PR_TRUE if the row at aRowIndex has any cells that have a rowspan>1
* So, given this table:<BR>
* <PRE>
* TABLE
* TR
* TD ROWSPAN=2
* TD
* TR
* TD
* </PRE>
* RowHasSpanningCells(0) returns PR_TRUE, and RowHasSpanningCells(1) returns PR_FALSE.
* @see RowIsSpannedInto
*/
PRBool RowHasSpanningCells(PRInt32 aRowIndex);
/** for debugging */
/** returns PR_TRUE if the col at aColIndex has any cells that are the result
* of a col-spanning cell. So, given this table:<BR>
* <PRE>
* TABLE
* TR
* TD COLSPAN=2
* TD
* TD
* </PRE>
* ColIsSpannedInto(0) returns PR_FALSE, ColIsSpannedInto(1) returns PR_TRUE,
* and ColIsSpannedInto(2) returns PR_FALSE.
* @see ColHasSpanningCells
*/
PRBool ColIsSpannedInto(PRInt32 aColIndex);
/** returns PR_TRUE if the row at aColIndex has any cells that have a colspan>1
* So, given this table:<BR>
* <PRE>
* TABLE
* TR
* TD COLSPAN=2
* TD
* </PRE>
* ColHasSpanningCells(0) returns PR_TRUE, and ColHasSpanningCells(1) returns PR_FALSE.
* @see ColIsSpannedInto
*/
PRBool ColHasSpanningCells(PRInt32 aColIndex);
/** dump a representation of the cell map to stdout for debugging */
void DumpCellMap() const;
};

View File

@ -429,7 +429,7 @@ nsTableColFrame * nsTableFrame::GetColFrame(PRInt32 aColIndex)
}
// can return nsnull
nsTableCellFrame * nsTableFrame::GetCellAt(PRInt32 aRowIndex, PRInt32 aColIndex)
nsTableCellFrame * nsTableFrame::GetCellFrameAt(PRInt32 aRowIndex, PRInt32 aColIndex)
{
nsTableCellFrame *result = nsnull;
nsCellMap *cellMap = GetCellMap();
@ -446,6 +446,73 @@ nsTableCellFrame * nsTableFrame::GetCellAt(PRInt32 aRowIndex, PRInt32 aColIndex)
return result;
}
/** returns PR_TRUE if the row at aRowIndex has any cells that are the result
* of a row-spanning cell.
* @see nsCellMap::RowIsSpannedInto
*/
PRBool nsTableFrame::RowIsSpannedInto(PRInt32 aRowIndex)
{
NS_PRECONDITION (0<=aRowIndex && aRowIndex<GetRowCount(), "bad row index arg");
PRBool result = PR_FALSE;
nsCellMap * cellMap = GetCellMap();
NS_PRECONDITION (nsnull!=cellMap, "bad call, cellMap not yet allocated.");
if (nsnull!=cellMap)
{
result = cellMap->RowIsSpannedInto(aRowIndex);
}
return result;
}
/** returns PR_TRUE if the row at aRowIndex has any cells that have a rowspan>1
* @see nsCellMap::RowHasSpanningCells
*/
PRBool nsTableFrame::RowHasSpanningCells(PRInt32 aRowIndex)
{
NS_PRECONDITION (0<=aRowIndex && aRowIndex<GetRowCount(), "bad row index arg");
PRBool result = PR_FALSE;
nsCellMap * cellMap = GetCellMap();
NS_PRECONDITION (nsnull!=cellMap, "bad call, cellMap not yet allocated.");
if (nsnull!=cellMap)
{
result = cellMap->RowHasSpanningCells(aRowIndex);
}
return result;
}
/** returns PR_TRUE if the col at aColIndex has any cells that are the result
* of a col-spanning cell.
* @see nsCellMap::ColIsSpannedInto
*/
PRBool nsTableFrame::ColIsSpannedInto(PRInt32 aColIndex)
{
NS_PRECONDITION (0<=aColIndex && aColIndex<GetColCount(), "bad col index arg");
PRBool result = PR_FALSE;
nsCellMap * cellMap = GetCellMap();
NS_PRECONDITION (nsnull!=cellMap, "bad call, cellMap not yet allocated.");
if (nsnull!=cellMap)
{
result = cellMap->ColIsSpannedInto(aColIndex);
}
return result;
}
/** returns PR_TRUE if the row at aColIndex has any cells that have a colspan>1
* @see nsCellMap::ColHasSpanningCells
*/
PRBool nsTableFrame::ColHasSpanningCells(PRInt32 aColIndex)
{
NS_PRECONDITION (0<=aColIndex && aColIndex<GetColCount(), "bad col index arg");
PRBool result = PR_FALSE;
nsCellMap * cellMap = GetCellMap();
NS_PRECONDITION (nsnull!=cellMap, "bad call, cellMap not yet allocated.");
if (nsnull!=cellMap)
{
result = cellMap->ColHasSpanningCells(aColIndex);
}
return result;
}
// return the number of rows spanned by aCell starting at aRowIndex
// note that this is different from just the rowspan of aCell
// (that would be GetEffectiveRowSpan (indexOfRowThatContains_aCell, aCell)
@ -499,7 +566,17 @@ PRInt32 nsTableFrame::GetEffectiveColSpan (PRInt32 aColIndex, nsTableCellFrame *
result -= (minColSpanForCol - 1); // minColSpanForCol is always at least 1
// and we want to treat default as 0 (no effect)
}
#ifdef NS_DEBUG
if (0>=result)
{
printf("ERROR!\n");
DumpCellMap();
printf("aColIndex=%d, cell->colIndex=%d\n", aColIndex, aCell->GetColIndex());
printf("aCell->colSpan=%d\n", aCell->GetColSpan());
printf("colCount=%d\n", mCellMap->GetColCount());
}
#endif
NS_ASSERTION(0<result, "bad effective col span");
return result;
}
@ -890,21 +967,21 @@ void nsTableFrame::DumpCellMap ()
if (nsnull != mCellMap)
{
PRInt32 rowCount = mCellMap->GetRowCount();
PRInt32 cols = mCellMap->GetColCount();
for (PRInt32 r = 0; r < rowCount; r++)
PRInt32 colCount = mCellMap->GetColCount();
for (PRInt32 rowIndex = 0; rowIndex < rowCount; rowIndex++)
{
if (gsDebug==PR_TRUE)
{ printf("row %d", r);
{ printf("row %d", rowIndex);
printf(": ");
}
for (PRInt32 c = 0; c < cols; c++)
for (PRInt32 colIndex = 0; colIndex < colCount; colIndex++)
{
CellData *cd =mCellMap->GetCellAt(r, c);
CellData *cd =mCellMap->GetCellAt(rowIndex, colIndex);
if (cd != nsnull)
{
if (cd->mCell != nsnull)
{
printf("C%d,%d ", r, c);
printf("C%d,%d ", rowIndex, colIndex);
printf(" ");
}
else
@ -931,8 +1008,18 @@ void nsTableFrame::DumpCellMap ()
else
printf("---- ");
}
printf("\n");
PRBool spanners = RowHasSpanningCells(rowIndex);
PRBool spannedInto = RowIsSpannedInto(rowIndex);
printf (" spanners=%s spannedInto=%s\n", spanners?"T":"F", spannedInto?"T":"F");
}
// output colspan info
for (PRInt32 colIndex=0; colIndex<colCount; colIndex++)
{
PRBool colSpanners = ColHasSpanningCells(colIndex);
PRBool colSpannedInto = ColIsSpannedInto(colIndex);
printf ("%d colSpanners=%s colSpannedInto=%s\n",
colIndex, colSpanners?"T":"F", colSpannedInto?"T":"F");
}
}
else
printf ("[nsnull]");
@ -993,12 +1080,12 @@ void nsTableFrame::BuildCellIntoMap (nsTableCellFrame *aCell, PRInt32 aRowIndex,
{
CellData *spanData = new CellData ();
spanData->mRealCell = data;
if (gsDebug==PR_TRUE) printf(" null GetCellAt(%d, %d) so setting to spanData\n", workRow, workCol);
if (gsDebug==PR_TRUE) printf(" null GetCellFrameAt(%d, %d) so setting to spanData\n", workRow, workCol);
mCellMap->SetCellAt(spanData, workRow, workCol);
}
else if ((0 < rowIndex) || (0 < colIndex))
{ // we overlap, replace existing data, it might be shared
if (gsDebug==PR_TRUE) printf(" overlapping Cell from GetCellAt(%d, %d) so setting to spanData\n", workRow, workCol);
if (gsDebug==PR_TRUE) printf(" overlapping Cell from GetCellFrameAt(%d, %d) so setting to spanData\n", workRow, workCol);
CellData *overlap = new CellData ();
overlap->mCell = testData->mCell;
overlap->mRealCell = testData->mRealCell;
@ -1623,6 +1710,7 @@ nsReflowStatus nsTableFrame::ResizeReflowPass2(nsIPresContext* aPresContext,
PRInt32 aMinCaptionWidth,
PRInt32 mMaxCaptionWidth)
{
//DumpCellMap();
NS_PRECONDITION(aReflowState.frame == this, "bad reflow state");
NS_PRECONDITION(aReflowState.parentReflowState->frame == mGeometricParent,
"bad parent reflow state");

View File

@ -436,6 +436,7 @@ public: /* ----- Cell Map public methods ----- */
*/
virtual PRInt32 GetRowCount();
/** returns the number of columns in this table. */
virtual PRInt32 GetColCount();
/** adjust the col count for screwy table attributes.
@ -443,11 +444,39 @@ public: /* ----- Cell Map public methods ----- */
*/
virtual void SetEffectiveColCount();
/** return the column frame at colIndex.
* returns nsnull if the col frame has not yet been allocated, or if aColIndex is out of range
*/
nsTableColFrame * GetColFrame(PRInt32 aColIndex);
nsTableCellFrame * GetCellAt(PRInt32 aRowIndex, PRInt32 aColIndex);
/** return the cell frame at aRowIndex, aColIndex.
* returns nsnull if the cell frame has not yet been allocated,
* or if aRowIndex or aColIndex is out of range
*/
nsTableCellFrame * GetCellFrameAt(PRInt32 aRowIndex, PRInt32 aColIndex);
/** returns PR_TRUE if the row at aRowIndex has any cells that are the result
* of a row-spanning cell above it.
* @see nsCellMap::RowIsSpannedInto
*/
PRBool RowIsSpannedInto(PRInt32 aRowIndex);
/** returns PR_TRUE if the row at aRowIndex has any cells that have a rowspan>1
* that originate in aRowIndex.
* @see nsCellMap::RowHasSpanningCells
*/
PRBool RowHasSpanningCells(PRInt32 aRowIndex);
/** returns PR_TRUE if the col at aColIndex has any cells that are the result
* of a col-spanning cell.
* @see nsCellMap::ColIsSpannedInto
*/
PRBool ColIsSpannedInto(PRInt32 aColIndex);
/** returns PR_TRUE if the row at aColIndex has any cells that have a colspan>1
* @see nsCellMap::ColHasSpanningCells
*/
PRBool ColHasSpanningCells(PRInt32 aColIndex);
private:
void DebugPrintCount() const; // Debugging routine

View File

@ -114,6 +114,11 @@ nsTableRowFrame::DidReflow(nsIPresContext& aPresContext,
if (NS_FRAME_REFLOW_FINISHED == aStatus) {
// Resize and re-align the cell frames based on our row height
nscoord cellHeight = mRect.height - mCellMaxTopMargin - mCellMaxBottomMargin;
// XXX
// every place in this module where we cast to nsTableCellFrame,
// we first have to check the display-type of the frame and skip non-cells.
nsTableCellFrame *cellFrame = (nsTableCellFrame*)mFirstChild;
nsTableFrame* tableFrame;
mContentParent->GetContentParent((nsIFrame*&)tableFrame);

View File

@ -306,7 +306,7 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths()
PRBool cellGrantingWidth=PR_TRUE;
for (rowIndex = 0; rowIndex<numRows; rowIndex++)
{
nsTableCellFrame * cellFrame = mTableFrame->GetCellAt(rowIndex, colIndex);
nsTableCellFrame * cellFrame = mTableFrame->GetCellFrameAt(rowIndex, colIndex);
if (nsnull==cellFrame)
{ // there is no cell in this row that corresponds to this column
continue;
@ -704,7 +704,7 @@ void BasicTableLayoutStrategy::SetMinAndMaxTableWidths()
for (colIndex = 0; colIndex<mNumCols; colIndex++)
{
if (gsDebug) printf(" col %d\n", colIndex);
nsTableCellFrame * cellFrame = mTableFrame->GetCellAt(rowIndex, colIndex);
nsTableCellFrame * cellFrame = mTableFrame->GetCellFrameAt(rowIndex, colIndex);
rowMinWidth += colInset;
rowMaxWidth += colInset;
if (nsnull==cellFrame)
@ -1053,7 +1053,7 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(const nsReflowState& aR
{
for (rowIndex = 0; rowIndex<numRows; rowIndex++)
{ // this col has proportional width, so determine its width requirements
nsTableCellFrame * cellFrame = mTableFrame->GetCellAt(rowIndex, colIndex);
nsTableCellFrame * cellFrame = mTableFrame->GetCellFrameAt(rowIndex, colIndex);
if (nsnull==cellFrame)
{ // there is no cell in this row that corresponds to this column
continue;
@ -1770,7 +1770,7 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsConstrained( const nsReflowState&
{
for (rowIndex = 0; rowIndex<numRows; rowIndex++)
{
nsTableCellFrame * cellFrame = mTableFrame->GetCellAt(rowIndex, colIndex);
nsTableCellFrame * cellFrame = mTableFrame->GetCellFrameAt(rowIndex, colIndex);
if (nsnull==cellFrame)
{ // there is no cell in this row that corresponds to this column
continue;

View File

@ -19,6 +19,7 @@
#include "nsVoidArray.h"
#include "nsCellMap.h"
#include "nsTableFrame.h"
#include "nsTableCellFrame.h"
#ifdef NS_DEBUG
static PRBool gsDebug = PR_FALSE;
@ -226,4 +227,187 @@ PRInt32 nsCellMap::GetNextAvailColIndex(PRInt32 aRowIndex, PRInt32 aColIndex) co
return result;
}
/** returns PR_TRUE if the row at aRowIndex has any cells that are the result
* of a row-spanning cell above it. So, given this table:<BR>
* <PRE>
* TABLE
* TR
* TD ROWSPAN=2
* TD
* TR
* TD
* </PRE>
* RowIsSpannedInto(0) returns PR_FALSE, and RowIsSpannedInto(1) returns PR_TRUE.
* @see RowHasSpanningCells
*/
// if computing this and related info gets expensive, we can easily
// cache it. The only thing to remember is to rebuild the cache
// whenever a row|col|cell is added/deleted, or a span attribute is changed.
PRBool nsCellMap::RowIsSpannedInto(PRInt32 aRowIndex)
{
NS_PRECONDITION (0<=aRowIndex && aRowIndex<GetRowCount(), "bad row index arg");
PRBool result = PR_FALSE;
PRInt32 colCount = GetColCount();
for (PRInt32 colIndex=0; colIndex<colCount; colIndex++)
{
CellData *cd = GetCellAt(aRowIndex, colIndex);
if (cd != nsnull)
{ // there's really a cell at (aRowIndex, colIndex)
if (nsnull==cd->mCell)
{ // the cell at (aRowIndex, colIndex) is the result of a span
nsTableCellFrame *cell = cd->mRealCell->mCell;
NS_ASSERTION(nsnull!=cell, "bad cell map state, missing real cell");
const PRInt32 realRowIndex = cell->GetRowIndex ();
if (realRowIndex!=aRowIndex)
{ // the span is caused by a rowspan
result = PR_TRUE;
break;
}
}
}
}
return result;
}
/** returns PR_TRUE if the row at aRowIndex has any cells that have a rowspan>1
* So, given this table:<BR>
* <PRE>
* TABLE
* TR
* TD ROWSPAN=2
* TD
* TR
* TD
* </PRE>
* RowHasSpanningCells(0) returns PR_TRUE, and RowHasSpanningCells(1) returns PR_FALSE.
* @see RowIsSpannedInto
*/
PRBool nsCellMap::RowHasSpanningCells(PRInt32 aRowIndex)
{
NS_PRECONDITION (0<=aRowIndex && aRowIndex<GetRowCount(), "bad row index arg");
PRBool result = PR_FALSE;
const PRInt32 rowCount = GetRowCount();
if (aRowIndex!=rowCount-1)
{ // aRowIndex is not the last row, so we check the next row after aRowIndex for spanners
const PRInt32 colCount = GetColCount();
for (PRInt32 colIndex=0; colIndex<colCount; colIndex++)
{
PRInt32 nextRowIndex = aRowIndex+1;
CellData *cd =GetCellAt(nextRowIndex, colIndex);
if (cd != nsnull)
{ // there's really a cell at (nextRowIndex, colIndex)
if (nsnull==cd->mCell)
{ // the cell at (nextRowIndex, colIndex) is the result of a span
nsTableCellFrame *cell = cd->mRealCell->mCell;
NS_ASSERTION(nsnull!=cell, "bad cell map state, missing real cell");
const PRInt32 realRowIndex = cell->GetRowIndex ();
if (realRowIndex!=nextRowIndex)
{ // the span is caused by a rowspan
CellData *spanningCell = GetCellAt(aRowIndex, colIndex);
if (nsnull!=spanningCell)
{ // there's really a cell at (aRowIndex, colIndex)
if (nsnull!=spanningCell->mCell)
{ // aRowIndex is where the rowspan originated
result = PR_TRUE;
break;
}
}
}
}
}
}
}
return result;
}
/** returns PR_TRUE if the col at aColIndex has any cells that are the result
* of a col-spanning cell. So, given this table:<BR>
* <PRE>
* TABLE
* TR
* TD COLSPAN=2
* TD
* TD
* </PRE>
* ColIsSpannedInto(0) returns PR_FALSE, ColIsSpannedInto(1) returns PR_TRUE,
* and ColIsSpannedInto(2) returns PR_FALSE.
* @see ColHasSpanningCells
*/
PRBool nsCellMap::ColIsSpannedInto(PRInt32 aColIndex)
{
NS_PRECONDITION (0<=aColIndex && aColIndex<GetColCount(), "bad col index arg");
PRBool result = PR_FALSE;
PRInt32 rowCount = GetRowCount();
for (PRInt32 rowIndex=0; rowIndex<rowCount; rowIndex++)
{
CellData *cd =GetCellAt(rowIndex, aColIndex);
if (cd != nsnull)
{ // there's really a cell at (aRowIndex, aColIndex)
if (nsnull==cd->mCell)
{ // the cell at (rowIndex, aColIndex) is the result of a span
nsTableCellFrame *cell = cd->mRealCell->mCell;
NS_ASSERTION(nsnull!=cell, "bad cell map state, missing real cell");
const PRInt32 realColIndex = cell->GetColIndex ();
if (realColIndex!=aColIndex)
{ // the span is caused by a colspan
result = PR_TRUE;
break;
}
}
}
}
return result;
}
/** returns PR_TRUE if the row at aColIndex has any cells that have a colspan>1
* So, given this table:<BR>
* <PRE>
* TABLE
* TR
* TD COLSPAN=2
* TD
* </PRE>
* ColHasSpanningCells(0) returns PR_TRUE, and ColHasSpanningCells(1) returns PR_FALSE.
* @see ColIsSpannedInto
*/
PRBool nsCellMap::ColHasSpanningCells(PRInt32 aColIndex)
{
NS_PRECONDITION (0<=aColIndex && aColIndex<GetColCount(), "bad col index arg");
PRBool result = PR_FALSE;
const PRInt32 colCount = GetColCount();
if (aColIndex!=colCount-1)
{ // aColIndex is not the last col, so we check the next col after aColIndex for spanners
const PRInt32 rowCount = GetRowCount();
for (PRInt32 rowIndex=0; rowIndex<rowCount; rowIndex++)
{
PRInt32 nextColIndex = aColIndex+1;
CellData *cd =GetCellAt(rowIndex, nextColIndex);
if (cd != nsnull)
{ // there's really a cell at (rowIndex, nextColIndex)
if (nsnull==cd->mCell)
{ // the cell at (rowIndex, nextColIndex) is the result of a span
nsTableCellFrame *cell = cd->mRealCell->mCell;
NS_ASSERTION(nsnull!=cell, "bad cell map state, missing real cell");
const PRInt32 realColIndex = cell->GetColIndex ();
if (realColIndex!=nextColIndex)
{ // the span is caused by a colspan
CellData *spanningCell =GetCellAt(rowIndex, aColIndex);
if (nsnull!=spanningCell)
{ // there's really a cell at (rowIndex, aColIndex)
if (nsnull!=spanningCell->mCell)
{ // aCowIndex is where the cowspan originated
result = PR_TRUE;
break;
}
}
}
}
}
}
}
return result;
}

View File

@ -44,7 +44,10 @@ protected:
/** storage for rows */
nsVoidArray *mRows;
/** storage for CellData pointers */
/** storage for min col span info, just an int that gives the smallest
* colspan for all cells originating in each column. If allocated,
* each entry must be >= 1.
*/
PRInt32 *mMinColSpans;
/** a cache of the column frames, by col index */
@ -62,8 +65,8 @@ protected:
public:
/** constructor
* @param aRows - initial number of rows
* @param aColumns - initial number of columns
*/
* @param aColumns - initial number of columns
*/
nsCellMap(PRInt32 aRows, PRInt32 aColumns);
/** destructor
@ -113,22 +116,69 @@ public:
/** add a column frame to the list of column frames
* column frames must be added in order
*/
*/
void AppendColumnFrame(nsTableColFrame *aColFrame);
/** return PR_TRUE if aRowIndex has any cells with rowspan>1 contained
* within it (not just cells that are in the row, but cells that span
* into the row as well.
*/
PRBool RowImpactedBySpanningCell(PRInt32 aRowIndex);
/** returns PR_TRUE if the row at aRowIndex has any cells that are the result
* of a row-spanning cell above it. So, given this table:<BR>
* <PRE>
* TABLE
* TR
* TD ROWSPAN=2
* TD
* TR
* TD
* </PRE>
* RowIsSpannedInto(0) returns PR_FALSE, and RowIsSpannedInto(1) returns PR_TRUE.
* @see RowHasSpanningCells
*/
PRBool RowIsSpannedInto(PRInt32 aRowIndex);
/** return PR_TRUE if aColIndex has any cells with colspan>1 contained
* within it (not just cells that are in the col, but cells that span
* into the col as well.
*/
PRBool ColumnImpactedBySpanningCell(PRInt32 aColIndex);
/** returns PR_TRUE if the row at aRowIndex has any cells that have a rowspan>1
* So, given this table:<BR>
* <PRE>
* TABLE
* TR
* TD ROWSPAN=2
* TD
* TR
* TD
* </PRE>
* RowHasSpanningCells(0) returns PR_TRUE, and RowHasSpanningCells(1) returns PR_FALSE.
* @see RowIsSpannedInto
*/
PRBool RowHasSpanningCells(PRInt32 aRowIndex);
/** for debugging */
/** returns PR_TRUE if the col at aColIndex has any cells that are the result
* of a col-spanning cell. So, given this table:<BR>
* <PRE>
* TABLE
* TR
* TD COLSPAN=2
* TD
* TD
* </PRE>
* ColIsSpannedInto(0) returns PR_FALSE, ColIsSpannedInto(1) returns PR_TRUE,
* and ColIsSpannedInto(2) returns PR_FALSE.
* @see ColHasSpanningCells
*/
PRBool ColIsSpannedInto(PRInt32 aColIndex);
/** returns PR_TRUE if the row at aColIndex has any cells that have a colspan>1
* So, given this table:<BR>
* <PRE>
* TABLE
* TR
* TD COLSPAN=2
* TD
* </PRE>
* ColHasSpanningCells(0) returns PR_TRUE, and ColHasSpanningCells(1) returns PR_FALSE.
* @see ColIsSpannedInto
*/
PRBool ColHasSpanningCells(PRInt32 aColIndex);
/** dump a representation of the cell map to stdout for debugging */
void DumpCellMap() const;
};

View File

@ -429,7 +429,7 @@ nsTableColFrame * nsTableFrame::GetColFrame(PRInt32 aColIndex)
}
// can return nsnull
nsTableCellFrame * nsTableFrame::GetCellAt(PRInt32 aRowIndex, PRInt32 aColIndex)
nsTableCellFrame * nsTableFrame::GetCellFrameAt(PRInt32 aRowIndex, PRInt32 aColIndex)
{
nsTableCellFrame *result = nsnull;
nsCellMap *cellMap = GetCellMap();
@ -446,6 +446,73 @@ nsTableCellFrame * nsTableFrame::GetCellAt(PRInt32 aRowIndex, PRInt32 aColIndex)
return result;
}
/** returns PR_TRUE if the row at aRowIndex has any cells that are the result
* of a row-spanning cell.
* @see nsCellMap::RowIsSpannedInto
*/
PRBool nsTableFrame::RowIsSpannedInto(PRInt32 aRowIndex)
{
NS_PRECONDITION (0<=aRowIndex && aRowIndex<GetRowCount(), "bad row index arg");
PRBool result = PR_FALSE;
nsCellMap * cellMap = GetCellMap();
NS_PRECONDITION (nsnull!=cellMap, "bad call, cellMap not yet allocated.");
if (nsnull!=cellMap)
{
result = cellMap->RowIsSpannedInto(aRowIndex);
}
return result;
}
/** returns PR_TRUE if the row at aRowIndex has any cells that have a rowspan>1
* @see nsCellMap::RowHasSpanningCells
*/
PRBool nsTableFrame::RowHasSpanningCells(PRInt32 aRowIndex)
{
NS_PRECONDITION (0<=aRowIndex && aRowIndex<GetRowCount(), "bad row index arg");
PRBool result = PR_FALSE;
nsCellMap * cellMap = GetCellMap();
NS_PRECONDITION (nsnull!=cellMap, "bad call, cellMap not yet allocated.");
if (nsnull!=cellMap)
{
result = cellMap->RowHasSpanningCells(aRowIndex);
}
return result;
}
/** returns PR_TRUE if the col at aColIndex has any cells that are the result
* of a col-spanning cell.
* @see nsCellMap::ColIsSpannedInto
*/
PRBool nsTableFrame::ColIsSpannedInto(PRInt32 aColIndex)
{
NS_PRECONDITION (0<=aColIndex && aColIndex<GetColCount(), "bad col index arg");
PRBool result = PR_FALSE;
nsCellMap * cellMap = GetCellMap();
NS_PRECONDITION (nsnull!=cellMap, "bad call, cellMap not yet allocated.");
if (nsnull!=cellMap)
{
result = cellMap->ColIsSpannedInto(aColIndex);
}
return result;
}
/** returns PR_TRUE if the row at aColIndex has any cells that have a colspan>1
* @see nsCellMap::ColHasSpanningCells
*/
PRBool nsTableFrame::ColHasSpanningCells(PRInt32 aColIndex)
{
NS_PRECONDITION (0<=aColIndex && aColIndex<GetColCount(), "bad col index arg");
PRBool result = PR_FALSE;
nsCellMap * cellMap = GetCellMap();
NS_PRECONDITION (nsnull!=cellMap, "bad call, cellMap not yet allocated.");
if (nsnull!=cellMap)
{
result = cellMap->ColHasSpanningCells(aColIndex);
}
return result;
}
// return the number of rows spanned by aCell starting at aRowIndex
// note that this is different from just the rowspan of aCell
// (that would be GetEffectiveRowSpan (indexOfRowThatContains_aCell, aCell)
@ -499,7 +566,17 @@ PRInt32 nsTableFrame::GetEffectiveColSpan (PRInt32 aColIndex, nsTableCellFrame *
result -= (minColSpanForCol - 1); // minColSpanForCol is always at least 1
// and we want to treat default as 0 (no effect)
}
#ifdef NS_DEBUG
if (0>=result)
{
printf("ERROR!\n");
DumpCellMap();
printf("aColIndex=%d, cell->colIndex=%d\n", aColIndex, aCell->GetColIndex());
printf("aCell->colSpan=%d\n", aCell->GetColSpan());
printf("colCount=%d\n", mCellMap->GetColCount());
}
#endif
NS_ASSERTION(0<result, "bad effective col span");
return result;
}
@ -890,21 +967,21 @@ void nsTableFrame::DumpCellMap ()
if (nsnull != mCellMap)
{
PRInt32 rowCount = mCellMap->GetRowCount();
PRInt32 cols = mCellMap->GetColCount();
for (PRInt32 r = 0; r < rowCount; r++)
PRInt32 colCount = mCellMap->GetColCount();
for (PRInt32 rowIndex = 0; rowIndex < rowCount; rowIndex++)
{
if (gsDebug==PR_TRUE)
{ printf("row %d", r);
{ printf("row %d", rowIndex);
printf(": ");
}
for (PRInt32 c = 0; c < cols; c++)
for (PRInt32 colIndex = 0; colIndex < colCount; colIndex++)
{
CellData *cd =mCellMap->GetCellAt(r, c);
CellData *cd =mCellMap->GetCellAt(rowIndex, colIndex);
if (cd != nsnull)
{
if (cd->mCell != nsnull)
{
printf("C%d,%d ", r, c);
printf("C%d,%d ", rowIndex, colIndex);
printf(" ");
}
else
@ -931,8 +1008,18 @@ void nsTableFrame::DumpCellMap ()
else
printf("---- ");
}
printf("\n");
PRBool spanners = RowHasSpanningCells(rowIndex);
PRBool spannedInto = RowIsSpannedInto(rowIndex);
printf (" spanners=%s spannedInto=%s\n", spanners?"T":"F", spannedInto?"T":"F");
}
// output colspan info
for (PRInt32 colIndex=0; colIndex<colCount; colIndex++)
{
PRBool colSpanners = ColHasSpanningCells(colIndex);
PRBool colSpannedInto = ColIsSpannedInto(colIndex);
printf ("%d colSpanners=%s colSpannedInto=%s\n",
colIndex, colSpanners?"T":"F", colSpannedInto?"T":"F");
}
}
else
printf ("[nsnull]");
@ -993,12 +1080,12 @@ void nsTableFrame::BuildCellIntoMap (nsTableCellFrame *aCell, PRInt32 aRowIndex,
{
CellData *spanData = new CellData ();
spanData->mRealCell = data;
if (gsDebug==PR_TRUE) printf(" null GetCellAt(%d, %d) so setting to spanData\n", workRow, workCol);
if (gsDebug==PR_TRUE) printf(" null GetCellFrameAt(%d, %d) so setting to spanData\n", workRow, workCol);
mCellMap->SetCellAt(spanData, workRow, workCol);
}
else if ((0 < rowIndex) || (0 < colIndex))
{ // we overlap, replace existing data, it might be shared
if (gsDebug==PR_TRUE) printf(" overlapping Cell from GetCellAt(%d, %d) so setting to spanData\n", workRow, workCol);
if (gsDebug==PR_TRUE) printf(" overlapping Cell from GetCellFrameAt(%d, %d) so setting to spanData\n", workRow, workCol);
CellData *overlap = new CellData ();
overlap->mCell = testData->mCell;
overlap->mRealCell = testData->mRealCell;
@ -1623,6 +1710,7 @@ nsReflowStatus nsTableFrame::ResizeReflowPass2(nsIPresContext* aPresContext,
PRInt32 aMinCaptionWidth,
PRInt32 mMaxCaptionWidth)
{
//DumpCellMap();
NS_PRECONDITION(aReflowState.frame == this, "bad reflow state");
NS_PRECONDITION(aReflowState.parentReflowState->frame == mGeometricParent,
"bad parent reflow state");

View File

@ -436,6 +436,7 @@ public: /* ----- Cell Map public methods ----- */
*/
virtual PRInt32 GetRowCount();
/** returns the number of columns in this table. */
virtual PRInt32 GetColCount();
/** adjust the col count for screwy table attributes.
@ -443,11 +444,39 @@ public: /* ----- Cell Map public methods ----- */
*/
virtual void SetEffectiveColCount();
/** return the column frame at colIndex.
* returns nsnull if the col frame has not yet been allocated, or if aColIndex is out of range
*/
nsTableColFrame * GetColFrame(PRInt32 aColIndex);
nsTableCellFrame * GetCellAt(PRInt32 aRowIndex, PRInt32 aColIndex);
/** return the cell frame at aRowIndex, aColIndex.
* returns nsnull if the cell frame has not yet been allocated,
* or if aRowIndex or aColIndex is out of range
*/
nsTableCellFrame * GetCellFrameAt(PRInt32 aRowIndex, PRInt32 aColIndex);
/** returns PR_TRUE if the row at aRowIndex has any cells that are the result
* of a row-spanning cell above it.
* @see nsCellMap::RowIsSpannedInto
*/
PRBool RowIsSpannedInto(PRInt32 aRowIndex);
/** returns PR_TRUE if the row at aRowIndex has any cells that have a rowspan>1
* that originate in aRowIndex.
* @see nsCellMap::RowHasSpanningCells
*/
PRBool RowHasSpanningCells(PRInt32 aRowIndex);
/** returns PR_TRUE if the col at aColIndex has any cells that are the result
* of a col-spanning cell.
* @see nsCellMap::ColIsSpannedInto
*/
PRBool ColIsSpannedInto(PRInt32 aColIndex);
/** returns PR_TRUE if the row at aColIndex has any cells that have a colspan>1
* @see nsCellMap::ColHasSpanningCells
*/
PRBool ColHasSpanningCells(PRInt32 aColIndex);
private:
void DebugPrintCount() const; // Debugging routine

View File

@ -114,6 +114,11 @@ nsTableRowFrame::DidReflow(nsIPresContext& aPresContext,
if (NS_FRAME_REFLOW_FINISHED == aStatus) {
// Resize and re-align the cell frames based on our row height
nscoord cellHeight = mRect.height - mCellMaxTopMargin - mCellMaxBottomMargin;
// XXX
// every place in this module where we cast to nsTableCellFrame,
// we first have to check the display-type of the frame and skip non-cells.
nsTableCellFrame *cellFrame = (nsTableCellFrame*)mFirstChild;
nsTableFrame* tableFrame;
mContentParent->GetContentParent((nsIFrame*&)tableFrame);