reimplemented cell map in terms of nsVoidArrays for incremental building.
the cellmap is now built incrementally, driven by nsTableRowFrame::InitialReflow git-svn-id: svn://10.0.0.236/trunk@8888 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
@@ -321,7 +321,7 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths()
|
||||
maxColSpan = colSpan;
|
||||
if (colIndex!=cellFrame->GetColIndex()) {
|
||||
// For cells that span cols, we figure in the row using previously-built SpanInfo
|
||||
NS_ASSERTION(1 != cellFrame->GetColSpan(), "col index does not match row span"); // sanity check
|
||||
NS_ASSERTION(1 != cellFrame->GetColSpan(), "col index does not match col span"); // sanity check
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1251,6 +1251,8 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(const nsReflowState& aR
|
||||
}
|
||||
tableWidth += mTableFrame->GetColumnWidth(colIndex) + colInset;
|
||||
}
|
||||
if (1==mNumCols)
|
||||
tableWidth += colInset;
|
||||
|
||||
/* --- post-process if necessary --- */
|
||||
|
||||
@@ -1966,6 +1968,8 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsConstrained( const nsReflowState&
|
||||
}
|
||||
tableWidth += mTableFrame->GetColumnWidth(colIndex) + colInset;
|
||||
}
|
||||
if (1==mNumCols)
|
||||
tableWidth += colInset;
|
||||
/* --- post-process if necessary --- */
|
||||
// first, assign autoWidth columns a width
|
||||
if (PR_TRUE==atLeastOneAutoWidthColumn)
|
||||
|
||||
@@ -29,6 +29,9 @@ struct nsStylePosition;
|
||||
|
||||
/* ----------- SpanInfo ---------- */
|
||||
|
||||
/** SpanInfo is a transient data structure that holds info about
|
||||
* cells that have col spans. Used during column balancing.
|
||||
*/
|
||||
struct SpanInfo
|
||||
{
|
||||
PRInt32 span;
|
||||
@@ -59,6 +62,11 @@ inline SpanInfo::SpanInfo(PRInt32 aColIndex, PRInt32 aSpan,
|
||||
|
||||
/* ---------- BasicTableLayoutStrategy ---------- */
|
||||
|
||||
/** Implementation of Nav4 compatible HTML browser table layout.
|
||||
* The input to this class is the results from pass1 table layout.
|
||||
* The output from this class is to set the column widths in
|
||||
* mTableFrame.
|
||||
*/
|
||||
class BasicTableLayoutStrategy : public nsITableLayoutStrategy
|
||||
{
|
||||
public:
|
||||
@@ -69,15 +77,25 @@ public:
|
||||
*/
|
||||
BasicTableLayoutStrategy(nsTableFrame *aFrame, PRInt32 aNumCols);
|
||||
|
||||
~BasicTableLayoutStrategy();
|
||||
/** destructor */
|
||||
virtual ~BasicTableLayoutStrategy();
|
||||
|
||||
/** call once every time any table thing changes (content, structure, or style) */
|
||||
virtual PRBool Initialize(nsSize* aMaxElementSize);
|
||||
|
||||
/** Called during resize reflow to determine the new column widths
|
||||
* @param aTableStyle - the resolved style for mTableFrame
|
||||
* @param aReflowState - the reflow state for mTableFrame
|
||||
* @param aMaxWidth - the computed max width for columns to fit into
|
||||
*/
|
||||
virtual PRBool BalanceColumnWidths(nsIStyleContext * aTableStyle,
|
||||
const nsReflowState& aReflowState,
|
||||
nscoord aMaxWidth);
|
||||
|
||||
nscoord GetTableMaxWidth() const;
|
||||
|
||||
protected:
|
||||
|
||||
/** assign widths for each column.
|
||||
* if the column has a fixed coord width, use it.
|
||||
* if the column includes col spanning cells,
|
||||
@@ -235,5 +253,8 @@ protected:
|
||||
|
||||
};
|
||||
|
||||
inline nscoord BasicTableLayoutStrategy::GetTableMaxWidth() const
|
||||
{ return mMaxTableWidth; };
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -33,6 +33,10 @@ class nsTableCellFrame;
|
||||
class CellData
|
||||
{
|
||||
public:
|
||||
/** if not null, the cell that this CellData maps.
|
||||
* if null, mRealCell points to the CellData that holds the
|
||||
* mapped cell frame.
|
||||
*/
|
||||
nsTableCellFrame *mCell;
|
||||
CellData *mRealCell;
|
||||
CellData *mOverlap;
|
||||
|
||||
@@ -16,121 +16,155 @@
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#include "nsCRT.h"
|
||||
#include "nsVoidArray.h"
|
||||
#include "nsCellMap.h"
|
||||
#include "nsTableFrame.h"
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
static PRBool gsDebug1 = PR_FALSE;
|
||||
static PRBool gsDebug = PR_FALSE;
|
||||
#else
|
||||
static const PRBool gsDebug1 = PR_FALSE;
|
||||
static const PRBool gsDebug = PR_FALSE;
|
||||
#endif
|
||||
|
||||
static const PRInt32 gBytesPerPointer = sizeof(PRInt32);
|
||||
|
||||
nsCellMap::nsCellMap(int aRows, int aColumns)
|
||||
: mRowCount(aRows),
|
||||
mColCount(aColumns)
|
||||
nsCellMap::nsCellMap(int aRowCount, int aColCount)
|
||||
: mRowCount(0),
|
||||
mColCount(0),
|
||||
mTotalRowCount(0)
|
||||
{
|
||||
mCells = nsnull;
|
||||
mRows = nsnull;
|
||||
mColFrames = nsnull;
|
||||
mMinColSpans = nsnull;
|
||||
Reset(aRows, aColumns);
|
||||
Reset(aRowCount, aColCount);
|
||||
}
|
||||
|
||||
nsCellMap::~nsCellMap()
|
||||
{
|
||||
if (nsnull!=mCells)
|
||||
if (nsnull!=mRows)
|
||||
{
|
||||
for (int i=0;i<mRowCount;i++)
|
||||
for (int i=mTotalRowCount-1; 0<i; i--)
|
||||
{
|
||||
for (int j=0;j<mColCount;j++)
|
||||
nsVoidArray *row = (nsVoidArray *)(mRows->ElementAt(i));
|
||||
for (int j=mColCount; 0<j ;j--)
|
||||
{
|
||||
int index = (i*mColCount)+j;
|
||||
CellData* data = (CellData*)mCells[index];
|
||||
CellData* data = (CellData *)(row->ElementAt(j));
|
||||
if (data != nsnull)
|
||||
{
|
||||
delete data;
|
||||
mCells[index] = 0;
|
||||
}
|
||||
}
|
||||
delete row;
|
||||
}
|
||||
delete [] mCells;
|
||||
delete mRows;
|
||||
}
|
||||
if (nsnull != mColFrames)
|
||||
delete mColFrames;
|
||||
if (nsnull != mMinColSpans)
|
||||
delete [] mMinColSpans;
|
||||
mCells = nsnull;
|
||||
mRows = nsnull;
|
||||
mColFrames = nsnull;
|
||||
mMinColSpans = nsnull;
|
||||
};
|
||||
|
||||
|
||||
void nsCellMap::Reset(int aRows, int aColumns)
|
||||
void nsCellMap::Reset(int aRowCount, int aColCount)
|
||||
{
|
||||
if (gsDebug) printf("calling Reset(%d,%d) with mRC=%d, mCC=%d, mTRC=%d\n",
|
||||
aRowCount, aColCount, mRowCount, mColCount, mTotalRowCount);
|
||||
if (nsnull==mColFrames)
|
||||
{
|
||||
mColFrames = new nsVoidArray();
|
||||
mColFrames = new nsVoidArray(); // don't give the array a count, because null col frames are illegal (unlike null cell entries in a row)
|
||||
}
|
||||
|
||||
// needs to be more efficient, to reuse space if possible
|
||||
if (nsnull!=mCells)
|
||||
if (nsnull==mRowCount)
|
||||
{
|
||||
delete [] mCells;
|
||||
mCells = nsnull;
|
||||
mRows = new nsVoidArray(); // don't give the array a count, because null rows are illegal (unlike null cell entries in a row)
|
||||
}
|
||||
mRowCount = aRows;
|
||||
mColCount = aColumns;
|
||||
mCells = new PRInt32 [mRowCount*mColCount*gBytesPerPointer];
|
||||
nsCRT::memset (mCells, 0, (mRowCount*mColCount)*gBytesPerPointer);
|
||||
|
||||
}
|
||||
|
||||
void nsCellMap::GrowTo(int aColCount)
|
||||
{
|
||||
if (aColCount <= mColCount)
|
||||
return;
|
||||
PRInt32 * newCells = new PRInt32 [mRowCount*aColCount*gBytesPerPointer];
|
||||
for (int rowIndex = 0; rowIndex < mRowCount; rowIndex++)
|
||||
// void arrays force the caller to handle null padding elements themselves
|
||||
// so if the number of columns has increased, we need to add extra cols to each row
|
||||
PRInt32 newCols = mColCount-aColCount;
|
||||
for (PRInt32 rowIndex=0; rowIndex<mRowCount; rowIndex++)
|
||||
{
|
||||
PRInt32* rowMap = (PRInt32*)&(newCells[rowIndex*aColCount]);
|
||||
nsCRT::memset (rowMap, 0, aColCount*gBytesPerPointer);
|
||||
nsCRT::memcpy(rowMap, &(mCells[rowIndex*mColCount]), mColCount*gBytesPerPointer);
|
||||
nsVoidArray *row = (nsVoidArray *)(mRows->ElementAt(rowIndex));
|
||||
const PRInt32 colsInRow = row->Count();
|
||||
if (colsInRow == aColCount)
|
||||
break; // we already have enough columns in each row
|
||||
for (PRInt32 colIndex = colsInRow; colIndex<aColCount; colIndex++)
|
||||
row->AppendElement(nsnull);
|
||||
}
|
||||
if (mCells != nsnull)
|
||||
delete [] mCells;
|
||||
mCells = newCells;
|
||||
|
||||
// if the number of rows has increased, add the extra rows
|
||||
PRInt32 newRows = aRowCount-mTotalRowCount; // (new row count) - (total row allocation)
|
||||
for ( ; newRows>0; newRows--)
|
||||
{
|
||||
nsVoidArray *row;
|
||||
if (0!=aColCount)
|
||||
row = new nsVoidArray(aColCount);
|
||||
else
|
||||
row = new nsVoidArray();
|
||||
mRows->AppendElement(row);
|
||||
}
|
||||
|
||||
mRowCount = aRowCount;
|
||||
mTotalRowCount = PR_MAX(mTotalRowCount, mRowCount);
|
||||
mColCount = aColCount;
|
||||
if (gsDebug) printf("leaving Reset with mRC=%d, mCC=%d, mTRC=%d\n",
|
||||
mRowCount, mColCount, mTotalRowCount);
|
||||
}
|
||||
|
||||
void nsCellMap::DumpCellMap() const
|
||||
{
|
||||
if (gsDebug1==PR_TRUE)
|
||||
if (gsDebug==PR_TRUE)
|
||||
{
|
||||
printf("Cell Map =\n");
|
||||
for (int i=0;i<mRowCount;i++)
|
||||
for (int j=0;j<mColCount;j++)
|
||||
for (int rowIndex=0; rowIndex<mRowCount ; rowIndex++)
|
||||
{
|
||||
nsVoidArray *row = (nsVoidArray *)(mRows->ElementAt(rowIndex));
|
||||
for (int colIndex=0; colIndex<mColCount; colIndex++)
|
||||
{
|
||||
int index = (i*mColCount)+j;
|
||||
printf("Cell [%d,%d] = %d for index = %d\n", i, j, mCells[index], index);
|
||||
CellData* data = (CellData *)(row->ElementAt(colIndex));
|
||||
printf("Cell [%d,%d] = %p for index = %d\n", rowIndex, colIndex, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void nsCellMap::SetCellAt(CellData *aCell, int aRow, int aColumn)
|
||||
void nsCellMap::GrowToRow(PRInt32 aRowCount)
|
||||
{
|
||||
//Assert aRow, aColumn
|
||||
int index = (aRow*mColCount)+aColumn;
|
||||
CellData* cell = GetCellAt(aRow,aColumn);
|
||||
if (cell != nsnull)
|
||||
delete cell;
|
||||
mCells[index] = (PRInt32)aCell;
|
||||
Reset(aRowCount, mColCount);
|
||||
}
|
||||
|
||||
nsTableColFrame* nsCellMap::GetColumnFrame(PRInt32 aColIndex)
|
||||
void nsCellMap::GrowToCol(PRInt32 aColCount)
|
||||
{
|
||||
Reset(mRowCount, aColCount);
|
||||
}
|
||||
|
||||
void nsCellMap::SetCellAt(CellData *aCell, int aRowIndex, int aColIndex)
|
||||
{
|
||||
NS_PRECONDITION(nsnull!=aCell, "bad aCell");
|
||||
PRInt32 newRows = (aRowIndex+1)-mRowCount; // add 1 to the "index" to get a "count"
|
||||
if (0<newRows)
|
||||
{
|
||||
for ( ; newRows>0; newRows--)
|
||||
{
|
||||
nsVoidArray *row = new nsVoidArray(mColCount);
|
||||
mRows->AppendElement(row);
|
||||
}
|
||||
mTotalRowCount = aRowIndex+1; // remember to always add 1 to an index when you want a count
|
||||
}
|
||||
|
||||
CellData* cell = GetCellAt(aRowIndex,aColIndex);
|
||||
if (cell != nsnull)
|
||||
delete cell;
|
||||
nsVoidArray *row = (nsVoidArray *)(mRows->ElementAt(aRowIndex));
|
||||
row->ReplaceElementAt(aCell, aColIndex);
|
||||
if (gsDebug) printf("leaving SetCellAt(%p,%d,%d) with mRC=%d, mCC=%d, mTRC=%d\n",
|
||||
aCell, aRowIndex, aColIndex, mRowCount, mColCount, mTotalRowCount);
|
||||
}
|
||||
|
||||
nsTableColFrame* nsCellMap::GetColumnFrame(PRInt32 aColIndex) const
|
||||
{
|
||||
NS_ASSERTION(nsnull!=mColFrames, "bad state");
|
||||
return (nsTableColFrame *)(mColFrames->ElementAt(aColIndex));
|
||||
}
|
||||
|
||||
@@ -151,7 +185,7 @@ void nsCellMap::SetMinColSpan(PRInt32 aColIndex, PRBool aColSpan)
|
||||
mMinColSpans[aColIndex] = aColSpan;
|
||||
}
|
||||
|
||||
PRInt32 nsCellMap::GetMinColSpan(PRInt32 aColIndex)
|
||||
PRInt32 nsCellMap::GetMinColSpan(PRInt32 aColIndex) const
|
||||
{
|
||||
NS_ASSERTION(aColIndex<mColCount, "bad aColIndex");
|
||||
|
||||
@@ -161,6 +195,34 @@ PRInt32 nsCellMap::GetMinColSpan(PRInt32 aColIndex)
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/** return the index of the next column in aRowIndex that does not have a cell assigned to it */
|
||||
PRInt32 nsCellMap::GetNextAvailColIndex(PRInt32 aRowIndex, PRInt32 aColIndex) const
|
||||
{
|
||||
PRInt32 result = 0;
|
||||
if (aColIndex > mColCount)
|
||||
{
|
||||
result = aColIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (aRowIndex < mRowCount)
|
||||
{
|
||||
result = aColIndex;
|
||||
nsVoidArray *row = (nsVoidArray *)(mRows->ElementAt(aRowIndex));
|
||||
PRInt32 count = row->Count();
|
||||
for (PRInt32 colIndex=aColIndex; colIndex<count; colIndex++)
|
||||
{
|
||||
void * data = row->ElementAt(colIndex);
|
||||
if (nsnull==data)
|
||||
{
|
||||
result = colIndex;
|
||||
break;
|
||||
}
|
||||
result++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -31,17 +31,18 @@ class nsTableCellFrame;
|
||||
* Each cell is represented by a CellData object.
|
||||
*
|
||||
* @see CellData
|
||||
* @see nsTableFrame::BuildCellMap
|
||||
* @see nsTableFrame::AddCellToMap
|
||||
* @see nsTableFrame::GrowCellMap
|
||||
* @see nsTableFrame::BuildCellIntoMap
|
||||
*
|
||||
* acts like a 2-dimensional array, so all offsets are 0-indexed
|
||||
* mRows is an array of rows. a row cannot be null.
|
||||
* each row is an array of cells. a cell can be null.
|
||||
*/
|
||||
class nsCellMap
|
||||
{
|
||||
protected:
|
||||
/** storage for CellData pointers */
|
||||
PRInt32 *mCells; ///XXX CellData *?
|
||||
/** storage for rows */
|
||||
nsVoidArray *mRows;
|
||||
|
||||
/** storage for CellData pointers */
|
||||
PRInt32 *mMinColSpans;
|
||||
@@ -49,19 +50,28 @@ protected:
|
||||
/** a cache of the column frames, by col index */
|
||||
nsVoidArray * mColFrames;
|
||||
|
||||
/** the number of rows */
|
||||
PRInt32 mRowCount; // in java, we could just do fCellMap.length;
|
||||
/** the number of rows. mRows[0] - mRows[mRowCount-1] are non-null. */
|
||||
PRInt32 mRowCount;
|
||||
|
||||
/** the number of rows allocated (due to cells having rowspans extending beyond the end of the table */
|
||||
PRInt32 mTotalRowCount;
|
||||
|
||||
/** the number of columns (the max of all row lengths) */
|
||||
PRInt32 mColCount;
|
||||
|
||||
public:
|
||||
/** constructor
|
||||
* @param aRows - initial number of rows
|
||||
* @param aColumns - initial number of columns
|
||||
*/
|
||||
nsCellMap(PRInt32 aRows, PRInt32 aColumns);
|
||||
|
||||
// NOT VIRTUAL BECAUSE THIS CLASS SHOULD **NEVER** BE SUBCLASSED
|
||||
/** destructor
|
||||
* NOT VIRTUAL BECAUSE THIS CLASS SHOULD **NEVER** BE SUBCLASSED
|
||||
*/
|
||||
~nsCellMap();
|
||||
|
||||
/** initialize the CellMap to (aRows x aColumns) */
|
||||
/** set the CellMap to (aRows x aColumns) */
|
||||
void Reset(PRInt32 aRows, PRInt32 aColumns);
|
||||
|
||||
/** return the CellData for the cell at (aRowIndex,aColIndex) */
|
||||
@@ -73,24 +83,49 @@ public:
|
||||
/** assign aCellData to the cell at (aRow,aColumn) */
|
||||
void SetCellAt(CellData *aCellData, PRInt32 aRow, PRInt32 aColumn);
|
||||
|
||||
/** expand the CellMap to have aRowCount rows. The number of columns remains the same */
|
||||
void GrowToRow(PRInt32 aRowCount);
|
||||
|
||||
/** expand the CellMap to have aColCount columns. The number of rows remains the same */
|
||||
void GrowTo(PRInt32 aColCount);
|
||||
void GrowToCol(PRInt32 aColCount);
|
||||
|
||||
/** return the total number of columns in the table represented by this CellMap */
|
||||
PRInt32 GetColCount() const;
|
||||
|
||||
/** return the total number of rows in the table represented by this CellMap */
|
||||
/** return the actual number of rows in the table represented by this CellMap */
|
||||
PRInt32 GetRowCount() const;
|
||||
|
||||
nsTableColFrame * GetColumnFrame(PRInt32 aColIndex);
|
||||
/** return the column frame associated with aColIndex */
|
||||
nsTableColFrame * GetColumnFrame(PRInt32 aColIndex) const;
|
||||
|
||||
/** return the index of the next column in aRowIndex after aColIndex
|
||||
* that does not have a cell assigned to it.
|
||||
* If aColIndex is past the end of the row, it is returned.
|
||||
* If the row is not initialized in the cell map, 0 is returned.
|
||||
*/
|
||||
PRInt32 GetNextAvailColIndex(PRInt32 aRowIndex, PRInt32 aColIndex) const;
|
||||
|
||||
/** cache the min col span for all cells in aColIndex */
|
||||
void SetMinColSpan(PRInt32 aColIndex, PRBool aColSpan);
|
||||
PRInt32 GetMinColSpan(PRInt32 aColIndex);
|
||||
|
||||
/** get the cached min col span for aColIndex */
|
||||
PRInt32 GetMinColSpan(PRInt32 aColIndex) const;
|
||||
|
||||
/** 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);
|
||||
|
||||
/** 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);
|
||||
|
||||
/** for debugging */
|
||||
@@ -102,16 +137,22 @@ public:
|
||||
|
||||
inline CellData * nsCellMap::GetCellAt(PRInt32 aRowIndex, PRInt32 aColIndex) const
|
||||
{
|
||||
NS_PRECONDITION(0<=aRowIndex && aRowIndex < mRowCount, "bad aRowIndex arg");
|
||||
NS_PRECONDITION(0<=aColIndex && aColIndex < mColCount, "bad aColIndex arg");
|
||||
NS_PRECONDITION(0<=aRowIndex, "bad aRowIndex arg");
|
||||
NS_PRECONDITION(0<=aColIndex, "bad aColIndex arg");
|
||||
// don't check index vs. count for row or col, because it's ok to ask for a cell that doesn't yet exist
|
||||
NS_PRECONDITION(nsnull!=mRows, "bad mRows");
|
||||
|
||||
PRInt32 index = (aRowIndex*mColCount)+aColIndex;
|
||||
return (CellData *)mCells[index];
|
||||
CellData *result = nsnull;
|
||||
nsVoidArray *row = (nsVoidArray *)(mRows->ElementAt(aRowIndex));
|
||||
if (nsnull!=row)
|
||||
result = (CellData *)(row->ElementAt(aColIndex));
|
||||
return result;
|
||||
}
|
||||
|
||||
inline nsTableCellFrame * nsCellMap::GetCellFrameAt(PRInt32 aRowIndex, PRInt32 aColIndex) const
|
||||
{
|
||||
NS_PRECONDITION(0<=aRowIndex && aRowIndex < mRowCount, "bad aRowIndex arg");
|
||||
NS_PRECONDITION(0<=aRowIndex, "bad aRowIndex arg");
|
||||
// don't check aRowIndex vs. mRowCount, because it's ok to ask for a cell in a row that doesn't yet exist
|
||||
NS_PRECONDITION(0<=aColIndex && aColIndex < mColCount, "bad aColIndex arg");
|
||||
|
||||
nsTableCellFrame *result = nsnull;
|
||||
@@ -134,8 +175,6 @@ inline PRInt32 nsCellMap::GetRowCount() const
|
||||
inline void nsCellMap::AppendColumnFrame(nsTableColFrame *aColFrame)
|
||||
{
|
||||
mColFrames->AppendElement(aColFrame);
|
||||
// sanity check
|
||||
NS_ASSERTION(mColFrames->Count()<=mColCount, "too many columns appended to CellMap");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -44,6 +44,15 @@ public:
|
||||
virtual PRBool BalanceColumnWidths(nsIStyleContext *aTableStyle,
|
||||
const nsReflowState& aReflowState,
|
||||
nscoord aMaxWidth)=0;
|
||||
|
||||
/** return the computed max "natural" size of the table.
|
||||
* this is the sum of the desired size of the content taking into account table
|
||||
* attributes, but NOT factoring in the available size the table is laying out into.
|
||||
* the actual table width in a given situation will depend on the available size
|
||||
* provided by the parent (especially for percent-width tables.)
|
||||
*/
|
||||
virtual nscoord GetTableMaxWidth() const = 0;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
#include "nsTableColGroupFrame.h"
|
||||
#include "nsTableColFrame.h"
|
||||
#include "nsTableFrame.h"
|
||||
#include "nsITableContent.h"
|
||||
#include "nsIReflowCommand.h"
|
||||
#include "nsIStyleContext.h"
|
||||
@@ -117,6 +118,9 @@ NS_METHOD nsTableColGroupFrame::Reflow(nsIPresContext& aPresContext,
|
||||
|
||||
// set nsColFrame-specific information
|
||||
((nsTableColFrame *)kidFrame)->SetColumnIndex(colIndex+mStartColIndex);
|
||||
nsIFrame* tableFrame=nsnull;
|
||||
GetGeometricParent(tableFrame);
|
||||
((nsTableFrame *)tableFrame)->AddColumnFrame((nsTableColFrame *)kidFrame);
|
||||
|
||||
// Link child frame into the list of children
|
||||
if (nsnull != prevKidFrame) {
|
||||
|
||||
@@ -517,12 +517,6 @@ void nsTableFrame::ResetCellMap ()
|
||||
mCellMap = nsnull; // for now, will rebuild when needed
|
||||
}
|
||||
|
||||
/* call when column structure has changed. */
|
||||
void nsTableFrame::ResetColumns ()
|
||||
{
|
||||
EnsureCellMap();
|
||||
}
|
||||
|
||||
/** sum the columns represented by all nsTableColGroup objects
|
||||
* if the cell map says there are more columns than this,
|
||||
* add extra implicit columns to the content tree.
|
||||
@@ -533,7 +527,7 @@ void nsTableFrame::EnsureColumns(nsIPresContext* aPresContext,
|
||||
nsReflowStatus& aStatus)
|
||||
{
|
||||
// XXX sec should only be called on firstInFlow
|
||||
EnsureCellMap();
|
||||
SetMinColSpanForTable();
|
||||
if (nsnull==mCellMap)
|
||||
return; // no info yet, so nothing useful to do
|
||||
|
||||
@@ -637,10 +631,6 @@ void nsTableFrame::EnsureColumnFrameAt(PRInt32 aColIndex,
|
||||
const nsReflowState& aReflowState,
|
||||
nsReflowStatus& aStatus)
|
||||
{
|
||||
|
||||
if (nsnull!=mCellMap)
|
||||
return; // we already have a cell map so this makes no sense
|
||||
|
||||
PRInt32 actualColumns = 0;
|
||||
nsTableColGroupFrame *lastColGroupFrame = nsnull;
|
||||
nsIFrame * firstRowGroupFrame=nsnull;
|
||||
@@ -724,6 +714,32 @@ void nsTableFrame::EnsureColumnFrameAt(PRInt32 aColIndex,
|
||||
}
|
||||
}
|
||||
|
||||
void nsTableFrame::AddColumnFrame (nsTableColFrame *aColFrame)
|
||||
{
|
||||
mCellMap->AppendColumnFrame(aColFrame);
|
||||
}
|
||||
|
||||
/** return the index of the next row that is not yet assigned */
|
||||
PRInt32 nsTableFrame::GetNextAvailRowIndex() const
|
||||
{
|
||||
PRInt32 result=0;
|
||||
if (nsnull!=mCellMap)
|
||||
{
|
||||
result = mCellMap->GetRowCount(); // the next index is the current count
|
||||
mCellMap->GrowToRow(result+1); // expand the cell map to include this new row
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/** return the index of the next column in aRowIndex that does not have a cell assigned to it */
|
||||
PRInt32 nsTableFrame::GetNextAvailColIndex(PRInt32 aRowIndex, PRInt32 aColIndex) const
|
||||
{
|
||||
PRInt32 result=0;
|
||||
if (nsnull!=mCellMap)
|
||||
result = mCellMap->GetNextAvailColIndex(aRowIndex, aColIndex);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Get the cell map for this table frame. It is not always mCellMap.
|
||||
* Only the firstInFlow has a legit cell map
|
||||
*/
|
||||
@@ -737,123 +753,10 @@ nsCellMap * nsTableFrame::GetCellMap()
|
||||
return mCellMap;
|
||||
}
|
||||
|
||||
void nsTableFrame::EnsureCellMap()
|
||||
void nsTableFrame::SetMinColSpanForTable()
|
||||
{ // XXX: must be called ONLY on first-in-flow
|
||||
if (mCellMap == nsnull)
|
||||
BuildCellMap();
|
||||
}
|
||||
|
||||
void nsTableFrame::BuildCellMap ()
|
||||
{
|
||||
// XXX: must be called only on first-in-flow!
|
||||
if (gsDebug==PR_TRUE) printf("Build Cell Map...\n");
|
||||
|
||||
int rowCount = GetRowCount();
|
||||
if (0 == rowCount)
|
||||
{
|
||||
// until we have some rows, there's nothing useful to do
|
||||
return;
|
||||
}
|
||||
|
||||
// Make an educated guess as to how many columns we have. It's
|
||||
// only a guess because we can't know exactly until we have
|
||||
// processed the last row.
|
||||
nsTableRowGroupFrame *rowGroupFrame = NextRowGroupFrame(nsnull);
|
||||
if (0 == mColCount)
|
||||
mColCount = GetSpecifiedColumnCount();
|
||||
if (0 == mColCount) // no column parts
|
||||
{
|
||||
// Use the first row to estimate the number of columns
|
||||
nsTableRowFrame *rowFrame;
|
||||
rowGroupFrame->FirstChild((nsIFrame*&)rowFrame);
|
||||
if (nsnull!=rowFrame)
|
||||
{
|
||||
mColCount = rowFrame->GetMaxColumns();
|
||||
if (gsDebug==PR_TRUE)
|
||||
printf("mColCount=0 at start. Guessing col count to be %d from a row.\n", mColCount);
|
||||
}
|
||||
}
|
||||
|
||||
// If we have a cell map reset it; otherwise allocate a new cell map
|
||||
if (nsnull==mCellMap)
|
||||
mCellMap = new nsCellMap(rowCount, mColCount);
|
||||
else
|
||||
mCellMap->Reset(rowCount, mColCount);
|
||||
if (gsDebug==PR_TRUE) printf("mCellMap set to (%d, %d)\n", rowCount, mColCount);
|
||||
|
||||
// Iterate over each row group frame
|
||||
PRInt32 rowIndex = -1;
|
||||
while (nsnull != rowGroupFrame)
|
||||
{
|
||||
// Iterate over each row frame within the row group
|
||||
nsTableRowFrame *rowFrame;
|
||||
rowGroupFrame->FirstChild((nsIFrame*&)rowFrame);
|
||||
while (nsnull != rowFrame)
|
||||
{
|
||||
// Set the row frame's row index. Note that this is a table-wide index,
|
||||
// and not the index within the row group
|
||||
rowIndex++;
|
||||
rowFrame->SetRowIndex(rowIndex);
|
||||
|
||||
// Iterate the table cells
|
||||
PRInt32 cellIndex = 0;
|
||||
PRInt32 colIndex = 0;
|
||||
nsIFrame* cellFrame;
|
||||
rowFrame->FirstChild(cellFrame);
|
||||
|
||||
while ((nsnull != cellFrame) && (colIndex < mColCount))
|
||||
{
|
||||
if (gsDebug==PR_TRUE) printf(" colIndex = %d, with mColCount = %d\n", colIndex, mColCount);
|
||||
CellData *data = mCellMap->GetCellAt(rowIndex, colIndex);
|
||||
if (nsnull == data)
|
||||
{
|
||||
BuildCellIntoMap((nsTableCellFrame*)cellFrame, rowIndex, colIndex);
|
||||
cellIndex++;
|
||||
|
||||
// Get the next cell frame
|
||||
cellFrame->GetNextSibling(cellFrame);
|
||||
}
|
||||
colIndex++;
|
||||
}
|
||||
|
||||
// See if there are any cell frames left in this row
|
||||
if (nsnull != cellFrame)
|
||||
{
|
||||
// We didn't use all the cells in this row up. Grow the cell
|
||||
// data because we now know that we have more columns than we
|
||||
// originally thought we had.
|
||||
PRInt32 cellCount = cellIndex + LengthOf(cellFrame);
|
||||
|
||||
if (gsDebug==PR_TRUE) printf(" calling GrowCellMap because cellIndex < %d\n", cellIndex, cellCount);
|
||||
GrowCellMap (cellCount);
|
||||
while (nsnull != cellFrame)
|
||||
{
|
||||
if (gsDebug==PR_TRUE) printf(" calling GrowCellMap again because cellIndex < %d\n", cellIndex, cellCount);
|
||||
GrowCellMap (colIndex + 1); // ensure enough cols in map, may be low due to colspans
|
||||
CellData *data =mCellMap->GetCellAt(rowIndex, colIndex);
|
||||
if (data == nsnull)
|
||||
{
|
||||
BuildCellIntoMap((nsTableCellFrame*)cellFrame, rowIndex, colIndex);
|
||||
cellIndex++;
|
||||
|
||||
// Get the next cell frame
|
||||
cellFrame->GetNextSibling(cellFrame);
|
||||
}
|
||||
colIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the next row frame
|
||||
rowFrame->GetNextSibling((nsIFrame *&)rowFrame);
|
||||
}
|
||||
|
||||
// Get the next row group frame
|
||||
rowGroupFrame = NextRowGroupFrame(rowGroupFrame);
|
||||
}
|
||||
if (gsDebug==PR_TRUE)
|
||||
DumpCellMap ();
|
||||
// iterate through the columns setting the min col span if necessary
|
||||
// it would be more efficient if we could do this in the above loop
|
||||
// set the minColSpan for each column
|
||||
PRInt32 rowCount = mCellMap->GetRowCount();
|
||||
for (PRInt32 colIndex=0; colIndex<mColCount; colIndex++)
|
||||
{
|
||||
PRInt32 minColSpan;
|
||||
@@ -874,6 +777,56 @@ void nsTableFrame::BuildCellMap ()
|
||||
}
|
||||
}
|
||||
|
||||
void nsTableFrame::AddCellToTable (nsTableRowFrame *aRowFrame,
|
||||
nsTableCellFrame *aCellFrame,
|
||||
PRBool aAddRow)
|
||||
{
|
||||
NS_ASSERTION(nsnull!=aRowFrame, "bad aRowFrame arg");
|
||||
NS_ASSERTION(nsnull!=aCellFrame, "bad aCellFrame arg");
|
||||
NS_PRECONDITION(nsnull!=mCellMap, "bad cellMap");
|
||||
|
||||
// XXX: must be called only on first-in-flow!
|
||||
if (gsDebug==PR_TRUE) printf("Build Cell Map...\n");
|
||||
|
||||
// Make an educated guess as to how many columns we have. It's
|
||||
// only a guess because we can't know exactly until we have
|
||||
// processed the last row.
|
||||
if (0 == mColCount)
|
||||
mColCount = GetSpecifiedColumnCount();
|
||||
if (0 == mColCount) // no column parts
|
||||
{
|
||||
mColCount = aRowFrame->GetMaxColumns();
|
||||
}
|
||||
|
||||
PRInt32 rowIndex;
|
||||
// If we have a cell map reset it; otherwise allocate a new cell map
|
||||
// also determine the index of aRowFrame and set it if necessary
|
||||
if (0==mCellMap->GetRowCount())
|
||||
{ // this is the first time we've ever been called
|
||||
rowIndex = 0;
|
||||
if (gsDebug==PR_TRUE) printf("rowFrame %p set to index %d\n", aRowFrame, rowIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
rowIndex = mCellMap->GetRowCount() - 1; // rowIndex is 0-indexed, rowCount is 1-indexed
|
||||
}
|
||||
|
||||
PRInt32 colIndex=0;
|
||||
while (PR_TRUE)
|
||||
{
|
||||
CellData *data = mCellMap->GetCellAt(rowIndex, colIndex);
|
||||
if (nsnull == data)
|
||||
{
|
||||
BuildCellIntoMap(aCellFrame, rowIndex, colIndex);
|
||||
break;
|
||||
}
|
||||
colIndex++;
|
||||
}
|
||||
|
||||
if (gsDebug==PR_TRUE)
|
||||
DumpCellMap ();
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
void nsTableFrame::DumpCellMap ()
|
||||
@@ -882,7 +835,7 @@ void nsTableFrame::DumpCellMap ()
|
||||
if (nsnull != mCellMap)
|
||||
{
|
||||
PRInt32 rowCount = mCellMap->GetRowCount();
|
||||
PRInt32 cols = GetColCount();
|
||||
PRInt32 cols = mCellMap->GetColCount();
|
||||
for (PRInt32 r = 0; r < rowCount; r++)
|
||||
{
|
||||
if (gsDebug==PR_TRUE)
|
||||
@@ -933,29 +886,35 @@ void nsTableFrame::DumpCellMap ()
|
||||
void nsTableFrame::BuildCellIntoMap (nsTableCellFrame *aCell, PRInt32 aRowIndex, PRInt32 aColIndex)
|
||||
{
|
||||
NS_PRECONDITION (nsnull!=aCell, "bad cell arg");
|
||||
NS_PRECONDITION (aColIndex < mColCount, "bad column index arg");
|
||||
NS_PRECONDITION (aRowIndex < GetRowCount(), "bad row index arg");
|
||||
NS_PRECONDITION (0 <= aColIndex, "bad column index arg");
|
||||
NS_PRECONDITION (0 <= aRowIndex, "bad row index arg");
|
||||
|
||||
// Setup CellMap for this cell
|
||||
int rowSpan = GetEffectiveRowSpan (aRowIndex, aCell);
|
||||
int colSpan = aCell->GetColSpan ();
|
||||
int rowSpan = aCell->GetRowSpan();
|
||||
int colSpan = aCell->GetColSpan();
|
||||
if (gsDebug==PR_TRUE) printf(" BuildCellIntoMap. rowSpan = %d, colSpan = %d\n", rowSpan, colSpan);
|
||||
|
||||
// Grow the mCellMap array if we will end up addressing
|
||||
// some new columns.
|
||||
if (mColCount < (aColIndex + colSpan))
|
||||
if (mCellMap->GetColCount() < (aColIndex + colSpan))
|
||||
{
|
||||
if (gsDebug==PR_TRUE) printf(" mColCount=%d<aColIndex+colSpan so calling GrowCellMap(%d)\n", mColCount, aColIndex+colSpan);
|
||||
if (gsDebug==PR_TRUE)
|
||||
printf(" calling GrowCellMap(%d)\n", aColIndex+colSpan);
|
||||
GrowCellMap (aColIndex + colSpan);
|
||||
}
|
||||
|
||||
if (mCellMap->GetRowCount() < (aRowIndex+1))
|
||||
{
|
||||
printf("*********************************************** calling GrowToRow(%d)\n", aRowIndex+1);
|
||||
mCellMap->GrowToRow(aRowIndex+1);
|
||||
}
|
||||
|
||||
// Setup CellMap for this cell in the table
|
||||
CellData *data = new CellData ();
|
||||
data->mCell = aCell;
|
||||
data->mRealCell = data;
|
||||
if (gsDebug==PR_TRUE) printf(" calling mCellMap->SetCellAt(data, %d, %d)\n", aRowIndex, aColIndex);
|
||||
mCellMap->SetCellAt(data, aRowIndex, aColIndex);
|
||||
aCell->SetColIndex (aColIndex);
|
||||
|
||||
// Create CellData objects for the rows that this cell spans. Set
|
||||
// their mCell to nsnull and their mRealCell to point to data. If
|
||||
@@ -1000,10 +959,7 @@ void nsTableFrame::GrowCellMap (PRInt32 aColCount)
|
||||
{
|
||||
if (nsnull!=mCellMap)
|
||||
{
|
||||
if (mColCount < aColCount)
|
||||
{
|
||||
mCellMap->GrowTo(aColCount);
|
||||
}
|
||||
mCellMap->GrowToCol(aColCount);
|
||||
mColCount = aColCount;
|
||||
}
|
||||
}
|
||||
@@ -1444,6 +1400,9 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext& aPresContext,
|
||||
{
|
||||
if (PR_FALSE==IsFirstPassValid())
|
||||
{ // we treat the table as if we've never seen the layout data before
|
||||
if (mCellMap!=nsnull)
|
||||
delete mCellMap;
|
||||
mCellMap = new nsCellMap(0, 0);
|
||||
mPass = kPASS_FIRST;
|
||||
aStatus = ResizeReflowPass1(&aPresContext, aDesiredSize, aReflowState, aStatus);
|
||||
// check result
|
||||
@@ -1651,8 +1610,6 @@ nsReflowStatus nsTableFrame::ResizeReflowPass1(nsIPresContext* aPresContext,
|
||||
}
|
||||
}
|
||||
|
||||
// BuildColumnCache calls EnsureCellMap. If that ever changes, be sure to call EnsureCellMap
|
||||
// here first.
|
||||
BuildColumnCache(aPresContext, aDesiredSize, aReflowState, aStatus);
|
||||
// Recalculate Layout Dependencies
|
||||
RecalcLayoutData();
|
||||
@@ -1749,7 +1706,7 @@ nsReflowStatus nsTableFrame::ResizeReflowPass2(nsIPresContext* aPresContext,
|
||||
}
|
||||
|
||||
// Return our size and our status
|
||||
aDesiredSize.width = aReflowState.maxSize.width;
|
||||
aDesiredSize.width = ComputeDesiredWidth(aReflowState);
|
||||
aDesiredSize.height = state.y + myBorderPadding.top + myBorderPadding.bottom;
|
||||
|
||||
|
||||
@@ -1773,6 +1730,20 @@ nsReflowStatus nsTableFrame::ResizeReflowPass2(nsIPresContext* aPresContext,
|
||||
|
||||
}
|
||||
|
||||
nscoord nsTableFrame::ComputeDesiredWidth(const nsReflowState& aReflowState) const
|
||||
{
|
||||
nscoord desiredWidth=aReflowState.maxSize.width;
|
||||
// this is the biggest hack in the world. But there's no other rational way to handle nested percent tables
|
||||
nsStylePosition* position;
|
||||
PRBool isNested=IsNested(aReflowState, position);
|
||||
if((eReflowReason_Initial==aReflowState.reason) &&
|
||||
(PR_TRUE==isNested) && (eStyleUnit_Percent==position->mWidth.GetUnit()))
|
||||
{
|
||||
desiredWidth = mTableLayoutStrategy->GetTableMaxWidth();
|
||||
}
|
||||
return desiredWidth;
|
||||
}
|
||||
|
||||
// Collapse child's top margin with previous bottom margin
|
||||
nscoord nsTableFrame::GetTopMarginFor(nsIPresContext* aCX,
|
||||
InnerTableReflowState& aState,
|
||||
@@ -2492,9 +2463,7 @@ void nsTableFrame::BalanceColumnWidths(nsIPresContext* aPresContext,
|
||||
nsSize* aMaxElementSize)
|
||||
{
|
||||
NS_ASSERTION(nsnull==mPrevInFlow, "never ever call me on a continuing frame!");
|
||||
|
||||
if (nsnull==mCellMap)
|
||||
return; // we don't have any information yet, so we can't do any useful work
|
||||
NS_ASSERTION(nsnull!=mCellMap, "never ever call me until the cell map is built!");
|
||||
|
||||
PRInt32 numCols = GetColCount();
|
||||
if (nsnull==mColumnWidths)
|
||||
@@ -2570,13 +2539,12 @@ void nsTableFrame::BalanceColumnWidths(nsIPresContext* aPresContext,
|
||||
void nsTableFrame::SetTableWidth(nsIPresContext* aPresContext)
|
||||
{
|
||||
NS_ASSERTION(nsnull==mPrevInFlow, "never ever call me on a continuing frame!");
|
||||
NS_ASSERTION(nsnull!=mCellMap, "never ever call me until the cell map is built!");
|
||||
|
||||
nscoord cellSpacing = GetCellSpacing();
|
||||
if (gsDebug==PR_TRUE)
|
||||
printf ("SetTableWidth with cellSpacing = %d ", cellSpacing);
|
||||
PRInt32 tableWidth = cellSpacing;
|
||||
if (nsnull==mCellMap)
|
||||
return; // no info, so nothing to do
|
||||
|
||||
PRInt32 numCols = GetColCount();
|
||||
for (PRInt32 colIndex = 0; colIndex<numCols; colIndex++)
|
||||
@@ -2762,6 +2730,8 @@ void nsTableFrame::BuildColumnCache( nsIPresContext* aPresContext,
|
||||
nsReflowStatus& aStatus
|
||||
)
|
||||
{
|
||||
// probably want this assertion : NS_ASSERTION(nsnull==mPrevInFlow, "never ever call me on a continuing frame!");
|
||||
NS_ASSERTION(nsnull!=mCellMap, "never ever call me until the cell map is built!");
|
||||
EnsureColumns(aPresContext, aDesiredSize, aReflowState, aStatus);
|
||||
if (nsnull==mColCache)
|
||||
{
|
||||
@@ -2938,8 +2908,8 @@ PRInt32 nsTableFrame::GetColumnWidth(PRInt32 aColIndex)
|
||||
else
|
||||
{
|
||||
NS_ASSERTION(nsnull!=mColumnWidths, "illegal state");
|
||||
#ifdef DEBUG
|
||||
NS_ASSERTION(nsnull!=mCellMap, "no column layout data");
|
||||
#ifdef NS_DEBUG
|
||||
NS_ASSERTION(nsnull!=mCellMap, "no cell map");
|
||||
PRInt32 numCols = GetColCount();
|
||||
NS_ASSERTION (numCols > aColIndex, "bad arg, col index out of bounds");
|
||||
#endif
|
||||
@@ -2957,7 +2927,7 @@ void nsTableFrame::SetColumnWidth(PRInt32 aColIndex, nscoord aWidth)
|
||||
{
|
||||
nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();
|
||||
NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow");
|
||||
//printf("SET_COL_WIDTH: %p, FIF=%p setting col %d to %d\n", this, firstInFlow, aColIndex, aWidth);
|
||||
|
||||
if (this!=firstInFlow)
|
||||
firstInFlow->SetColumnWidth(aColIndex, aWidth);
|
||||
else
|
||||
@@ -2968,9 +2938,6 @@ void nsTableFrame::SetColumnWidth(PRInt32 aColIndex, nscoord aWidth)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Update the border style to map to the HTML border style
|
||||
@@ -3176,6 +3143,34 @@ nsresult nsTableFrame::NewFrame(nsIFrame** aInstancePtrResult,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* helper method for determining if this is a nested table or not */
|
||||
PRBool nsTableFrame::IsNested(const nsReflowState& aReflowState, nsStylePosition *& aPosition) const
|
||||
{
|
||||
PRBool result = PR_FALSE;
|
||||
#ifdef NS_DEBUG
|
||||
PRInt32 counter=0;
|
||||
#endif
|
||||
// Walk up the reflow state chain until we find a cell or the root
|
||||
const nsReflowState* rs = aReflowState.parentReflowState;
|
||||
while (nsnull != rs)
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
counter++;
|
||||
NS_ASSERTION(counter<100000, "infinite loop in IsNested");
|
||||
#endif
|
||||
nsIFrame* parentTable = nsnull;
|
||||
rs->frame->QueryInterface(kTableFrameCID, (void**) &parentTable);
|
||||
if (nsnull!=parentTable)
|
||||
{
|
||||
result = PR_TRUE;
|
||||
parentTable->GetStyleData(eStyleStruct_Position, ((nsStyleStruct *&)aPosition));
|
||||
break;
|
||||
}
|
||||
rs = rs->parentReflowState;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* helper method for getting the width of the table's containing block */
|
||||
nscoord nsTableFrame::GetTableContainerWidth(const nsReflowState& aReflowState)
|
||||
{
|
||||
|
||||
@@ -73,6 +73,9 @@ public:
|
||||
// nsISupports
|
||||
NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr);
|
||||
|
||||
/** helper method for determining if this is a nested table or not */
|
||||
PRBool IsNested(const nsReflowState& aReflowState, nsStylePosition *& aPosition) const;
|
||||
|
||||
/** helper method for getting the width of the table's containing block */
|
||||
static nscoord GetTableContainerWidth(const nsReflowState& aState);
|
||||
|
||||
@@ -210,6 +213,26 @@ public:
|
||||
const nsReflowState& aReflowState,
|
||||
nsReflowStatus& aStatus);
|
||||
|
||||
/** return the index of the next row that is not yet assigned.
|
||||
* If no row is initialized, 0 is returned.
|
||||
*/
|
||||
PRInt32 GetNextAvailRowIndex() const;
|
||||
|
||||
/** return the index of the next column in aRowIndex after aColIndex
|
||||
* that does not have a cell assigned to it.
|
||||
* If aColIndex is past the end of the row, it is returned.
|
||||
* If the row is not initialized, 0 is returned.
|
||||
*/
|
||||
PRInt32 GetNextAvailColIndex(PRInt32 aRowIndex, PRInt32 aColIndex) const;
|
||||
|
||||
/** build as much of the CellMap as possible from the info we have so far
|
||||
*/
|
||||
virtual void AddCellToTable (nsTableRowFrame *aRowFrame,
|
||||
nsTableCellFrame *aCellFrame,
|
||||
PRBool aAddRow);
|
||||
|
||||
virtual void AddColumnFrame (nsTableColFrame *aColFrame);
|
||||
|
||||
protected:
|
||||
|
||||
/** protected constructor.
|
||||
@@ -256,6 +279,11 @@ protected:
|
||||
nsIFrame* aKidFrame,
|
||||
nscoord aDeltaY);
|
||||
|
||||
/** return the desired width of this table accounting for the current
|
||||
* reflow state, and for the table attributes and parent
|
||||
*/
|
||||
nscoord ComputeDesiredWidth(const nsReflowState& aReflowState) const;
|
||||
|
||||
nscoord GetTopMarginFor(nsIPresContext* aCX,
|
||||
InnerTableReflowState& aState,
|
||||
const nsMargin& aKidMargin);
|
||||
@@ -345,10 +373,6 @@ protected:
|
||||
void MapHTMLBorderStyle(nsStyleSpacing& aSpacingStyle, nscoord aBorderWidth);
|
||||
PRBool ConvertToPixelValue(nsHTMLValue& aValue, PRInt32 aDefault, PRInt32& aResult);
|
||||
|
||||
/** build as much of the CellMap as possible from the info we have so far
|
||||
*/
|
||||
virtual void BuildCellMap ();
|
||||
|
||||
/** called whenever the number of columns changes, to increase the storage in mCellMap
|
||||
*/
|
||||
virtual void GrowCellMap(PRInt32 aColCount);
|
||||
@@ -374,12 +398,6 @@ protected:
|
||||
*/
|
||||
void ListColumnLayoutData(FILE* out, PRInt32 aIndent);
|
||||
|
||||
/** ResetColumns is called when the column structure of the table is changed.
|
||||
* Call with caution, only when adding or removing columns, changing
|
||||
* column attributes, changing the rowspan or colspan attribute of a cell, etc.
|
||||
*/
|
||||
virtual void ResetColumns ();
|
||||
|
||||
/** sum the columns represented by all nsTableColGroup objects.
|
||||
* if the cell map says there are more columns than this,
|
||||
* add extra implicit columns to the content tree.
|
||||
@@ -389,9 +407,8 @@ protected:
|
||||
const nsReflowState& aReflowState,
|
||||
nsReflowStatus& aStatus);
|
||||
|
||||
/** Ensure that the cell map has been built for the table
|
||||
*/
|
||||
virtual void EnsureCellMap();
|
||||
/** Set the min col span for every column in the table. Scans the whole table. */
|
||||
virtual void SetMinColSpanForTable();
|
||||
|
||||
virtual void BuildColumnCache(nsIPresContext* aPresContext,
|
||||
nsReflowMetrics& aDesiredSize,
|
||||
|
||||
@@ -31,6 +31,11 @@
|
||||
#include "nsIPtr.h"
|
||||
#include "nsIReflowCommand.h"
|
||||
#include "nsCSSRendering.h"
|
||||
// the following header files are required for style optimizations that work only when the child content is really a cell
|
||||
#include "nsITableContent.h"
|
||||
#include "nsTableCell.h"
|
||||
static NS_DEFINE_IID(kITableContentIID, NS_ITABLECONTENT_IID);
|
||||
// end includes for style optimizations that require real content knowledge
|
||||
|
||||
NS_DEF_PTR(nsIStyleContext);
|
||||
|
||||
@@ -502,12 +507,13 @@ nsTableRowFrame::InitialReflow(nsIPresContext& aPresContext,
|
||||
// Place our children, one at a time, until we are out of children
|
||||
nsSize kidMaxElementSize;
|
||||
PRInt32 kidIndex = 0;
|
||||
PRInt32 colIndex = -1;
|
||||
PRInt32 colIndex = 0;
|
||||
nsIFrame* prevKidFrame = nsnull;
|
||||
nscoord maxTopMargin = 0;
|
||||
nscoord maxBottomMargin = 0;
|
||||
nscoord x = 0;
|
||||
nsresult result = NS_OK;
|
||||
PRBool isFirst=PR_TRUE;
|
||||
|
||||
for (;;) {
|
||||
// Get the next content object
|
||||
@@ -517,22 +523,41 @@ nsTableRowFrame::InitialReflow(nsIPresContext& aPresContext,
|
||||
break; // no more content
|
||||
}
|
||||
|
||||
// what column does this cell span to?
|
||||
nsHTMLValue value;
|
||||
((nsHTMLTagContent *)cell)->GetAttribute(nsHTMLAtoms::align, value);
|
||||
if (value.GetUnit() == eHTMLUnit_Integer)
|
||||
colIndex += value.GetIntValue();
|
||||
else
|
||||
colIndex += 1;
|
||||
// what row am I?
|
||||
if (PR_TRUE==isFirst)
|
||||
SetRowIndex(aState.tableFrame->GetNextAvailRowIndex());
|
||||
|
||||
// create column frames if necessary
|
||||
// what column does this cell belong to?
|
||||
colIndex = aState.tableFrame->GetNextAvailColIndex(mRowIndex, colIndex);
|
||||
if (gsDebug) printf("%p : next col index = %d\n", this, colIndex);
|
||||
|
||||
/* for style context optimization, set the content's column index if possible.
|
||||
* this can only be done if we really have an nsTableCell.
|
||||
* other tags mapped to table cell display won't benefit from this optimization
|
||||
* see nsHTMLStyleSheet::RulesMatching
|
||||
*/
|
||||
nsITableContent *tableContentInterface = nsnull;
|
||||
nsresult rv = cell->QueryInterface(kITableContentIID,
|
||||
(void **)&tableContentInterface); // tableContentInterface: REFCNT++
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{ // we know it's a table part of some sort, is it a cell?
|
||||
const int contentType = ((nsTableContent *)tableContentInterface)->GetType();
|
||||
if (contentType == nsITableContent::kTableCellType)
|
||||
{
|
||||
((nsTableCell *)tableContentInterface)->SetColIndex(colIndex);
|
||||
if (gsDebug) printf("%p : set cell content %p to col index = %d\n", this, tableContentInterface, colIndex);
|
||||
}
|
||||
NS_RELEASE(tableContentInterface);
|
||||
}
|
||||
// part of the style optimization is to ensure that the column frame for the cell exists
|
||||
// we used to do this post-pass1, now we do it incrementally for the optimization
|
||||
nsReflowStatus status;
|
||||
aState.tableFrame->EnsureColumnFrameAt(colIndex,
|
||||
&aPresContext,
|
||||
aDesiredSize,
|
||||
aState.reflowState,
|
||||
status);
|
||||
// Create a child frame -- always an nsTableCell frame
|
||||
// Create a child frame -- always an nsTableCellFrame
|
||||
nsIStyleContext* kidSC = aPresContext.ResolveStyleContextFor(cell, this, PR_FALSE);
|
||||
nsIContentDelegate* kidDel = cell->GetDelegate(&aPresContext);
|
||||
nsIFrame* kidFrame;
|
||||
@@ -544,21 +569,16 @@ nsTableRowFrame::InitialReflow(nsIPresContext& aPresContext,
|
||||
NS_RELEASE(kidSC);
|
||||
break;
|
||||
}
|
||||
// this sets the frame's notion of it's column index
|
||||
((nsTableCellFrame *)kidFrame)->SetColIndex(colIndex);
|
||||
if (gsDebug) printf("%p : set cell frame %p to col index = %d\n", this, kidFrame, colIndex);
|
||||
// add the cell frame to the table's cell map
|
||||
aState.tableFrame->AddCellToTable(this, (nsTableCellFrame *)kidFrame, isFirst);
|
||||
|
||||
// Because we're not splittable always allow the child to be as high as
|
||||
// it wants. The default available width is also unconstrained so we can
|
||||
// get the child's maximum width
|
||||
nsSize kidAvailSize(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
|
||||
|
||||
// See if there's a width constraint for the cell
|
||||
/*
|
||||
const nsStylePosition* cellPosition = (const nsStylePosition*)
|
||||
kidSC->GetStyleData(eStyleStruct_Position);
|
||||
if (eStyleUnit_Coord == cellPosition->mWidth.GetUnit())
|
||||
{
|
||||
kidAvailSize.width = cellPosition->mWidth.GetCoordValue();
|
||||
}
|
||||
*/
|
||||
NS_IF_RELEASE(kidSC);
|
||||
|
||||
// Get the child's margins
|
||||
@@ -622,6 +642,7 @@ nsTableRowFrame::InitialReflow(nsIPresContext& aPresContext,
|
||||
// Move to the next content child
|
||||
prevKidFrame = kidFrame;
|
||||
kidIndex++;
|
||||
isFirst=PR_FALSE;
|
||||
}
|
||||
|
||||
SetMaxChildHeight(aState.maxCellHeight, maxTopMargin, maxBottomMargin); // remember height of tallest child who doesn't have a row span
|
||||
|
||||
@@ -321,7 +321,7 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths()
|
||||
maxColSpan = colSpan;
|
||||
if (colIndex!=cellFrame->GetColIndex()) {
|
||||
// For cells that span cols, we figure in the row using previously-built SpanInfo
|
||||
NS_ASSERTION(1 != cellFrame->GetColSpan(), "col index does not match row span"); // sanity check
|
||||
NS_ASSERTION(1 != cellFrame->GetColSpan(), "col index does not match col span"); // sanity check
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1251,6 +1251,8 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(const nsReflowState& aR
|
||||
}
|
||||
tableWidth += mTableFrame->GetColumnWidth(colIndex) + colInset;
|
||||
}
|
||||
if (1==mNumCols)
|
||||
tableWidth += colInset;
|
||||
|
||||
/* --- post-process if necessary --- */
|
||||
|
||||
@@ -1966,6 +1968,8 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsConstrained( const nsReflowState&
|
||||
}
|
||||
tableWidth += mTableFrame->GetColumnWidth(colIndex) + colInset;
|
||||
}
|
||||
if (1==mNumCols)
|
||||
tableWidth += colInset;
|
||||
/* --- post-process if necessary --- */
|
||||
// first, assign autoWidth columns a width
|
||||
if (PR_TRUE==atLeastOneAutoWidthColumn)
|
||||
|
||||
@@ -29,6 +29,9 @@ struct nsStylePosition;
|
||||
|
||||
/* ----------- SpanInfo ---------- */
|
||||
|
||||
/** SpanInfo is a transient data structure that holds info about
|
||||
* cells that have col spans. Used during column balancing.
|
||||
*/
|
||||
struct SpanInfo
|
||||
{
|
||||
PRInt32 span;
|
||||
@@ -59,6 +62,11 @@ inline SpanInfo::SpanInfo(PRInt32 aColIndex, PRInt32 aSpan,
|
||||
|
||||
/* ---------- BasicTableLayoutStrategy ---------- */
|
||||
|
||||
/** Implementation of Nav4 compatible HTML browser table layout.
|
||||
* The input to this class is the results from pass1 table layout.
|
||||
* The output from this class is to set the column widths in
|
||||
* mTableFrame.
|
||||
*/
|
||||
class BasicTableLayoutStrategy : public nsITableLayoutStrategy
|
||||
{
|
||||
public:
|
||||
@@ -69,15 +77,25 @@ public:
|
||||
*/
|
||||
BasicTableLayoutStrategy(nsTableFrame *aFrame, PRInt32 aNumCols);
|
||||
|
||||
~BasicTableLayoutStrategy();
|
||||
/** destructor */
|
||||
virtual ~BasicTableLayoutStrategy();
|
||||
|
||||
/** call once every time any table thing changes (content, structure, or style) */
|
||||
virtual PRBool Initialize(nsSize* aMaxElementSize);
|
||||
|
||||
/** Called during resize reflow to determine the new column widths
|
||||
* @param aTableStyle - the resolved style for mTableFrame
|
||||
* @param aReflowState - the reflow state for mTableFrame
|
||||
* @param aMaxWidth - the computed max width for columns to fit into
|
||||
*/
|
||||
virtual PRBool BalanceColumnWidths(nsIStyleContext * aTableStyle,
|
||||
const nsReflowState& aReflowState,
|
||||
nscoord aMaxWidth);
|
||||
|
||||
nscoord GetTableMaxWidth() const;
|
||||
|
||||
protected:
|
||||
|
||||
/** assign widths for each column.
|
||||
* if the column has a fixed coord width, use it.
|
||||
* if the column includes col spanning cells,
|
||||
@@ -235,5 +253,8 @@ protected:
|
||||
|
||||
};
|
||||
|
||||
inline nscoord BasicTableLayoutStrategy::GetTableMaxWidth() const
|
||||
{ return mMaxTableWidth; };
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -33,6 +33,10 @@ class nsTableCellFrame;
|
||||
class CellData
|
||||
{
|
||||
public:
|
||||
/** if not null, the cell that this CellData maps.
|
||||
* if null, mRealCell points to the CellData that holds the
|
||||
* mapped cell frame.
|
||||
*/
|
||||
nsTableCellFrame *mCell;
|
||||
CellData *mRealCell;
|
||||
CellData *mOverlap;
|
||||
|
||||
@@ -16,121 +16,155 @@
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#include "nsCRT.h"
|
||||
#include "nsVoidArray.h"
|
||||
#include "nsCellMap.h"
|
||||
#include "nsTableFrame.h"
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
static PRBool gsDebug1 = PR_FALSE;
|
||||
static PRBool gsDebug = PR_FALSE;
|
||||
#else
|
||||
static const PRBool gsDebug1 = PR_FALSE;
|
||||
static const PRBool gsDebug = PR_FALSE;
|
||||
#endif
|
||||
|
||||
static const PRInt32 gBytesPerPointer = sizeof(PRInt32);
|
||||
|
||||
nsCellMap::nsCellMap(int aRows, int aColumns)
|
||||
: mRowCount(aRows),
|
||||
mColCount(aColumns)
|
||||
nsCellMap::nsCellMap(int aRowCount, int aColCount)
|
||||
: mRowCount(0),
|
||||
mColCount(0),
|
||||
mTotalRowCount(0)
|
||||
{
|
||||
mCells = nsnull;
|
||||
mRows = nsnull;
|
||||
mColFrames = nsnull;
|
||||
mMinColSpans = nsnull;
|
||||
Reset(aRows, aColumns);
|
||||
Reset(aRowCount, aColCount);
|
||||
}
|
||||
|
||||
nsCellMap::~nsCellMap()
|
||||
{
|
||||
if (nsnull!=mCells)
|
||||
if (nsnull!=mRows)
|
||||
{
|
||||
for (int i=0;i<mRowCount;i++)
|
||||
for (int i=mTotalRowCount-1; 0<i; i--)
|
||||
{
|
||||
for (int j=0;j<mColCount;j++)
|
||||
nsVoidArray *row = (nsVoidArray *)(mRows->ElementAt(i));
|
||||
for (int j=mColCount; 0<j ;j--)
|
||||
{
|
||||
int index = (i*mColCount)+j;
|
||||
CellData* data = (CellData*)mCells[index];
|
||||
CellData* data = (CellData *)(row->ElementAt(j));
|
||||
if (data != nsnull)
|
||||
{
|
||||
delete data;
|
||||
mCells[index] = 0;
|
||||
}
|
||||
}
|
||||
delete row;
|
||||
}
|
||||
delete [] mCells;
|
||||
delete mRows;
|
||||
}
|
||||
if (nsnull != mColFrames)
|
||||
delete mColFrames;
|
||||
if (nsnull != mMinColSpans)
|
||||
delete [] mMinColSpans;
|
||||
mCells = nsnull;
|
||||
mRows = nsnull;
|
||||
mColFrames = nsnull;
|
||||
mMinColSpans = nsnull;
|
||||
};
|
||||
|
||||
|
||||
void nsCellMap::Reset(int aRows, int aColumns)
|
||||
void nsCellMap::Reset(int aRowCount, int aColCount)
|
||||
{
|
||||
if (gsDebug) printf("calling Reset(%d,%d) with mRC=%d, mCC=%d, mTRC=%d\n",
|
||||
aRowCount, aColCount, mRowCount, mColCount, mTotalRowCount);
|
||||
if (nsnull==mColFrames)
|
||||
{
|
||||
mColFrames = new nsVoidArray();
|
||||
mColFrames = new nsVoidArray(); // don't give the array a count, because null col frames are illegal (unlike null cell entries in a row)
|
||||
}
|
||||
|
||||
// needs to be more efficient, to reuse space if possible
|
||||
if (nsnull!=mCells)
|
||||
if (nsnull==mRowCount)
|
||||
{
|
||||
delete [] mCells;
|
||||
mCells = nsnull;
|
||||
mRows = new nsVoidArray(); // don't give the array a count, because null rows are illegal (unlike null cell entries in a row)
|
||||
}
|
||||
mRowCount = aRows;
|
||||
mColCount = aColumns;
|
||||
mCells = new PRInt32 [mRowCount*mColCount*gBytesPerPointer];
|
||||
nsCRT::memset (mCells, 0, (mRowCount*mColCount)*gBytesPerPointer);
|
||||
|
||||
}
|
||||
|
||||
void nsCellMap::GrowTo(int aColCount)
|
||||
{
|
||||
if (aColCount <= mColCount)
|
||||
return;
|
||||
PRInt32 * newCells = new PRInt32 [mRowCount*aColCount*gBytesPerPointer];
|
||||
for (int rowIndex = 0; rowIndex < mRowCount; rowIndex++)
|
||||
// void arrays force the caller to handle null padding elements themselves
|
||||
// so if the number of columns has increased, we need to add extra cols to each row
|
||||
PRInt32 newCols = mColCount-aColCount;
|
||||
for (PRInt32 rowIndex=0; rowIndex<mRowCount; rowIndex++)
|
||||
{
|
||||
PRInt32* rowMap = (PRInt32*)&(newCells[rowIndex*aColCount]);
|
||||
nsCRT::memset (rowMap, 0, aColCount*gBytesPerPointer);
|
||||
nsCRT::memcpy(rowMap, &(mCells[rowIndex*mColCount]), mColCount*gBytesPerPointer);
|
||||
nsVoidArray *row = (nsVoidArray *)(mRows->ElementAt(rowIndex));
|
||||
const PRInt32 colsInRow = row->Count();
|
||||
if (colsInRow == aColCount)
|
||||
break; // we already have enough columns in each row
|
||||
for (PRInt32 colIndex = colsInRow; colIndex<aColCount; colIndex++)
|
||||
row->AppendElement(nsnull);
|
||||
}
|
||||
if (mCells != nsnull)
|
||||
delete [] mCells;
|
||||
mCells = newCells;
|
||||
|
||||
// if the number of rows has increased, add the extra rows
|
||||
PRInt32 newRows = aRowCount-mTotalRowCount; // (new row count) - (total row allocation)
|
||||
for ( ; newRows>0; newRows--)
|
||||
{
|
||||
nsVoidArray *row;
|
||||
if (0!=aColCount)
|
||||
row = new nsVoidArray(aColCount);
|
||||
else
|
||||
row = new nsVoidArray();
|
||||
mRows->AppendElement(row);
|
||||
}
|
||||
|
||||
mRowCount = aRowCount;
|
||||
mTotalRowCount = PR_MAX(mTotalRowCount, mRowCount);
|
||||
mColCount = aColCount;
|
||||
if (gsDebug) printf("leaving Reset with mRC=%d, mCC=%d, mTRC=%d\n",
|
||||
mRowCount, mColCount, mTotalRowCount);
|
||||
}
|
||||
|
||||
void nsCellMap::DumpCellMap() const
|
||||
{
|
||||
if (gsDebug1==PR_TRUE)
|
||||
if (gsDebug==PR_TRUE)
|
||||
{
|
||||
printf("Cell Map =\n");
|
||||
for (int i=0;i<mRowCount;i++)
|
||||
for (int j=0;j<mColCount;j++)
|
||||
for (int rowIndex=0; rowIndex<mRowCount ; rowIndex++)
|
||||
{
|
||||
nsVoidArray *row = (nsVoidArray *)(mRows->ElementAt(rowIndex));
|
||||
for (int colIndex=0; colIndex<mColCount; colIndex++)
|
||||
{
|
||||
int index = (i*mColCount)+j;
|
||||
printf("Cell [%d,%d] = %d for index = %d\n", i, j, mCells[index], index);
|
||||
CellData* data = (CellData *)(row->ElementAt(colIndex));
|
||||
printf("Cell [%d,%d] = %p for index = %d\n", rowIndex, colIndex, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void nsCellMap::SetCellAt(CellData *aCell, int aRow, int aColumn)
|
||||
void nsCellMap::GrowToRow(PRInt32 aRowCount)
|
||||
{
|
||||
//Assert aRow, aColumn
|
||||
int index = (aRow*mColCount)+aColumn;
|
||||
CellData* cell = GetCellAt(aRow,aColumn);
|
||||
if (cell != nsnull)
|
||||
delete cell;
|
||||
mCells[index] = (PRInt32)aCell;
|
||||
Reset(aRowCount, mColCount);
|
||||
}
|
||||
|
||||
nsTableColFrame* nsCellMap::GetColumnFrame(PRInt32 aColIndex)
|
||||
void nsCellMap::GrowToCol(PRInt32 aColCount)
|
||||
{
|
||||
Reset(mRowCount, aColCount);
|
||||
}
|
||||
|
||||
void nsCellMap::SetCellAt(CellData *aCell, int aRowIndex, int aColIndex)
|
||||
{
|
||||
NS_PRECONDITION(nsnull!=aCell, "bad aCell");
|
||||
PRInt32 newRows = (aRowIndex+1)-mRowCount; // add 1 to the "index" to get a "count"
|
||||
if (0<newRows)
|
||||
{
|
||||
for ( ; newRows>0; newRows--)
|
||||
{
|
||||
nsVoidArray *row = new nsVoidArray(mColCount);
|
||||
mRows->AppendElement(row);
|
||||
}
|
||||
mTotalRowCount = aRowIndex+1; // remember to always add 1 to an index when you want a count
|
||||
}
|
||||
|
||||
CellData* cell = GetCellAt(aRowIndex,aColIndex);
|
||||
if (cell != nsnull)
|
||||
delete cell;
|
||||
nsVoidArray *row = (nsVoidArray *)(mRows->ElementAt(aRowIndex));
|
||||
row->ReplaceElementAt(aCell, aColIndex);
|
||||
if (gsDebug) printf("leaving SetCellAt(%p,%d,%d) with mRC=%d, mCC=%d, mTRC=%d\n",
|
||||
aCell, aRowIndex, aColIndex, mRowCount, mColCount, mTotalRowCount);
|
||||
}
|
||||
|
||||
nsTableColFrame* nsCellMap::GetColumnFrame(PRInt32 aColIndex) const
|
||||
{
|
||||
NS_ASSERTION(nsnull!=mColFrames, "bad state");
|
||||
return (nsTableColFrame *)(mColFrames->ElementAt(aColIndex));
|
||||
}
|
||||
|
||||
@@ -151,7 +185,7 @@ void nsCellMap::SetMinColSpan(PRInt32 aColIndex, PRBool aColSpan)
|
||||
mMinColSpans[aColIndex] = aColSpan;
|
||||
}
|
||||
|
||||
PRInt32 nsCellMap::GetMinColSpan(PRInt32 aColIndex)
|
||||
PRInt32 nsCellMap::GetMinColSpan(PRInt32 aColIndex) const
|
||||
{
|
||||
NS_ASSERTION(aColIndex<mColCount, "bad aColIndex");
|
||||
|
||||
@@ -161,6 +195,34 @@ PRInt32 nsCellMap::GetMinColSpan(PRInt32 aColIndex)
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/** return the index of the next column in aRowIndex that does not have a cell assigned to it */
|
||||
PRInt32 nsCellMap::GetNextAvailColIndex(PRInt32 aRowIndex, PRInt32 aColIndex) const
|
||||
{
|
||||
PRInt32 result = 0;
|
||||
if (aColIndex > mColCount)
|
||||
{
|
||||
result = aColIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (aRowIndex < mRowCount)
|
||||
{
|
||||
result = aColIndex;
|
||||
nsVoidArray *row = (nsVoidArray *)(mRows->ElementAt(aRowIndex));
|
||||
PRInt32 count = row->Count();
|
||||
for (PRInt32 colIndex=aColIndex; colIndex<count; colIndex++)
|
||||
{
|
||||
void * data = row->ElementAt(colIndex);
|
||||
if (nsnull==data)
|
||||
{
|
||||
result = colIndex;
|
||||
break;
|
||||
}
|
||||
result++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -31,17 +31,18 @@ class nsTableCellFrame;
|
||||
* Each cell is represented by a CellData object.
|
||||
*
|
||||
* @see CellData
|
||||
* @see nsTableFrame::BuildCellMap
|
||||
* @see nsTableFrame::AddCellToMap
|
||||
* @see nsTableFrame::GrowCellMap
|
||||
* @see nsTableFrame::BuildCellIntoMap
|
||||
*
|
||||
* acts like a 2-dimensional array, so all offsets are 0-indexed
|
||||
* mRows is an array of rows. a row cannot be null.
|
||||
* each row is an array of cells. a cell can be null.
|
||||
*/
|
||||
class nsCellMap
|
||||
{
|
||||
protected:
|
||||
/** storage for CellData pointers */
|
||||
PRInt32 *mCells; ///XXX CellData *?
|
||||
/** storage for rows */
|
||||
nsVoidArray *mRows;
|
||||
|
||||
/** storage for CellData pointers */
|
||||
PRInt32 *mMinColSpans;
|
||||
@@ -49,19 +50,28 @@ protected:
|
||||
/** a cache of the column frames, by col index */
|
||||
nsVoidArray * mColFrames;
|
||||
|
||||
/** the number of rows */
|
||||
PRInt32 mRowCount; // in java, we could just do fCellMap.length;
|
||||
/** the number of rows. mRows[0] - mRows[mRowCount-1] are non-null. */
|
||||
PRInt32 mRowCount;
|
||||
|
||||
/** the number of rows allocated (due to cells having rowspans extending beyond the end of the table */
|
||||
PRInt32 mTotalRowCount;
|
||||
|
||||
/** the number of columns (the max of all row lengths) */
|
||||
PRInt32 mColCount;
|
||||
|
||||
public:
|
||||
/** constructor
|
||||
* @param aRows - initial number of rows
|
||||
* @param aColumns - initial number of columns
|
||||
*/
|
||||
nsCellMap(PRInt32 aRows, PRInt32 aColumns);
|
||||
|
||||
// NOT VIRTUAL BECAUSE THIS CLASS SHOULD **NEVER** BE SUBCLASSED
|
||||
/** destructor
|
||||
* NOT VIRTUAL BECAUSE THIS CLASS SHOULD **NEVER** BE SUBCLASSED
|
||||
*/
|
||||
~nsCellMap();
|
||||
|
||||
/** initialize the CellMap to (aRows x aColumns) */
|
||||
/** set the CellMap to (aRows x aColumns) */
|
||||
void Reset(PRInt32 aRows, PRInt32 aColumns);
|
||||
|
||||
/** return the CellData for the cell at (aRowIndex,aColIndex) */
|
||||
@@ -73,24 +83,49 @@ public:
|
||||
/** assign aCellData to the cell at (aRow,aColumn) */
|
||||
void SetCellAt(CellData *aCellData, PRInt32 aRow, PRInt32 aColumn);
|
||||
|
||||
/** expand the CellMap to have aRowCount rows. The number of columns remains the same */
|
||||
void GrowToRow(PRInt32 aRowCount);
|
||||
|
||||
/** expand the CellMap to have aColCount columns. The number of rows remains the same */
|
||||
void GrowTo(PRInt32 aColCount);
|
||||
void GrowToCol(PRInt32 aColCount);
|
||||
|
||||
/** return the total number of columns in the table represented by this CellMap */
|
||||
PRInt32 GetColCount() const;
|
||||
|
||||
/** return the total number of rows in the table represented by this CellMap */
|
||||
/** return the actual number of rows in the table represented by this CellMap */
|
||||
PRInt32 GetRowCount() const;
|
||||
|
||||
nsTableColFrame * GetColumnFrame(PRInt32 aColIndex);
|
||||
/** return the column frame associated with aColIndex */
|
||||
nsTableColFrame * GetColumnFrame(PRInt32 aColIndex) const;
|
||||
|
||||
/** return the index of the next column in aRowIndex after aColIndex
|
||||
* that does not have a cell assigned to it.
|
||||
* If aColIndex is past the end of the row, it is returned.
|
||||
* If the row is not initialized in the cell map, 0 is returned.
|
||||
*/
|
||||
PRInt32 GetNextAvailColIndex(PRInt32 aRowIndex, PRInt32 aColIndex) const;
|
||||
|
||||
/** cache the min col span for all cells in aColIndex */
|
||||
void SetMinColSpan(PRInt32 aColIndex, PRBool aColSpan);
|
||||
PRInt32 GetMinColSpan(PRInt32 aColIndex);
|
||||
|
||||
/** get the cached min col span for aColIndex */
|
||||
PRInt32 GetMinColSpan(PRInt32 aColIndex) const;
|
||||
|
||||
/** 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);
|
||||
|
||||
/** 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);
|
||||
|
||||
/** for debugging */
|
||||
@@ -102,16 +137,22 @@ public:
|
||||
|
||||
inline CellData * nsCellMap::GetCellAt(PRInt32 aRowIndex, PRInt32 aColIndex) const
|
||||
{
|
||||
NS_PRECONDITION(0<=aRowIndex && aRowIndex < mRowCount, "bad aRowIndex arg");
|
||||
NS_PRECONDITION(0<=aColIndex && aColIndex < mColCount, "bad aColIndex arg");
|
||||
NS_PRECONDITION(0<=aRowIndex, "bad aRowIndex arg");
|
||||
NS_PRECONDITION(0<=aColIndex, "bad aColIndex arg");
|
||||
// don't check index vs. count for row or col, because it's ok to ask for a cell that doesn't yet exist
|
||||
NS_PRECONDITION(nsnull!=mRows, "bad mRows");
|
||||
|
||||
PRInt32 index = (aRowIndex*mColCount)+aColIndex;
|
||||
return (CellData *)mCells[index];
|
||||
CellData *result = nsnull;
|
||||
nsVoidArray *row = (nsVoidArray *)(mRows->ElementAt(aRowIndex));
|
||||
if (nsnull!=row)
|
||||
result = (CellData *)(row->ElementAt(aColIndex));
|
||||
return result;
|
||||
}
|
||||
|
||||
inline nsTableCellFrame * nsCellMap::GetCellFrameAt(PRInt32 aRowIndex, PRInt32 aColIndex) const
|
||||
{
|
||||
NS_PRECONDITION(0<=aRowIndex && aRowIndex < mRowCount, "bad aRowIndex arg");
|
||||
NS_PRECONDITION(0<=aRowIndex, "bad aRowIndex arg");
|
||||
// don't check aRowIndex vs. mRowCount, because it's ok to ask for a cell in a row that doesn't yet exist
|
||||
NS_PRECONDITION(0<=aColIndex && aColIndex < mColCount, "bad aColIndex arg");
|
||||
|
||||
nsTableCellFrame *result = nsnull;
|
||||
@@ -134,8 +175,6 @@ inline PRInt32 nsCellMap::GetRowCount() const
|
||||
inline void nsCellMap::AppendColumnFrame(nsTableColFrame *aColFrame)
|
||||
{
|
||||
mColFrames->AppendElement(aColFrame);
|
||||
// sanity check
|
||||
NS_ASSERTION(mColFrames->Count()<=mColCount, "too many columns appended to CellMap");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -44,6 +44,15 @@ public:
|
||||
virtual PRBool BalanceColumnWidths(nsIStyleContext *aTableStyle,
|
||||
const nsReflowState& aReflowState,
|
||||
nscoord aMaxWidth)=0;
|
||||
|
||||
/** return the computed max "natural" size of the table.
|
||||
* this is the sum of the desired size of the content taking into account table
|
||||
* attributes, but NOT factoring in the available size the table is laying out into.
|
||||
* the actual table width in a given situation will depend on the available size
|
||||
* provided by the parent (especially for percent-width tables.)
|
||||
*/
|
||||
virtual nscoord GetTableMaxWidth() const = 0;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
#include "nsTableColGroupFrame.h"
|
||||
#include "nsTableColFrame.h"
|
||||
#include "nsTableFrame.h"
|
||||
#include "nsITableContent.h"
|
||||
#include "nsIReflowCommand.h"
|
||||
#include "nsIStyleContext.h"
|
||||
@@ -117,6 +118,9 @@ NS_METHOD nsTableColGroupFrame::Reflow(nsIPresContext& aPresContext,
|
||||
|
||||
// set nsColFrame-specific information
|
||||
((nsTableColFrame *)kidFrame)->SetColumnIndex(colIndex+mStartColIndex);
|
||||
nsIFrame* tableFrame=nsnull;
|
||||
GetGeometricParent(tableFrame);
|
||||
((nsTableFrame *)tableFrame)->AddColumnFrame((nsTableColFrame *)kidFrame);
|
||||
|
||||
// Link child frame into the list of children
|
||||
if (nsnull != prevKidFrame) {
|
||||
|
||||
@@ -517,12 +517,6 @@ void nsTableFrame::ResetCellMap ()
|
||||
mCellMap = nsnull; // for now, will rebuild when needed
|
||||
}
|
||||
|
||||
/* call when column structure has changed. */
|
||||
void nsTableFrame::ResetColumns ()
|
||||
{
|
||||
EnsureCellMap();
|
||||
}
|
||||
|
||||
/** sum the columns represented by all nsTableColGroup objects
|
||||
* if the cell map says there are more columns than this,
|
||||
* add extra implicit columns to the content tree.
|
||||
@@ -533,7 +527,7 @@ void nsTableFrame::EnsureColumns(nsIPresContext* aPresContext,
|
||||
nsReflowStatus& aStatus)
|
||||
{
|
||||
// XXX sec should only be called on firstInFlow
|
||||
EnsureCellMap();
|
||||
SetMinColSpanForTable();
|
||||
if (nsnull==mCellMap)
|
||||
return; // no info yet, so nothing useful to do
|
||||
|
||||
@@ -637,10 +631,6 @@ void nsTableFrame::EnsureColumnFrameAt(PRInt32 aColIndex,
|
||||
const nsReflowState& aReflowState,
|
||||
nsReflowStatus& aStatus)
|
||||
{
|
||||
|
||||
if (nsnull!=mCellMap)
|
||||
return; // we already have a cell map so this makes no sense
|
||||
|
||||
PRInt32 actualColumns = 0;
|
||||
nsTableColGroupFrame *lastColGroupFrame = nsnull;
|
||||
nsIFrame * firstRowGroupFrame=nsnull;
|
||||
@@ -724,6 +714,32 @@ void nsTableFrame::EnsureColumnFrameAt(PRInt32 aColIndex,
|
||||
}
|
||||
}
|
||||
|
||||
void nsTableFrame::AddColumnFrame (nsTableColFrame *aColFrame)
|
||||
{
|
||||
mCellMap->AppendColumnFrame(aColFrame);
|
||||
}
|
||||
|
||||
/** return the index of the next row that is not yet assigned */
|
||||
PRInt32 nsTableFrame::GetNextAvailRowIndex() const
|
||||
{
|
||||
PRInt32 result=0;
|
||||
if (nsnull!=mCellMap)
|
||||
{
|
||||
result = mCellMap->GetRowCount(); // the next index is the current count
|
||||
mCellMap->GrowToRow(result+1); // expand the cell map to include this new row
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/** return the index of the next column in aRowIndex that does not have a cell assigned to it */
|
||||
PRInt32 nsTableFrame::GetNextAvailColIndex(PRInt32 aRowIndex, PRInt32 aColIndex) const
|
||||
{
|
||||
PRInt32 result=0;
|
||||
if (nsnull!=mCellMap)
|
||||
result = mCellMap->GetNextAvailColIndex(aRowIndex, aColIndex);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Get the cell map for this table frame. It is not always mCellMap.
|
||||
* Only the firstInFlow has a legit cell map
|
||||
*/
|
||||
@@ -737,123 +753,10 @@ nsCellMap * nsTableFrame::GetCellMap()
|
||||
return mCellMap;
|
||||
}
|
||||
|
||||
void nsTableFrame::EnsureCellMap()
|
||||
void nsTableFrame::SetMinColSpanForTable()
|
||||
{ // XXX: must be called ONLY on first-in-flow
|
||||
if (mCellMap == nsnull)
|
||||
BuildCellMap();
|
||||
}
|
||||
|
||||
void nsTableFrame::BuildCellMap ()
|
||||
{
|
||||
// XXX: must be called only on first-in-flow!
|
||||
if (gsDebug==PR_TRUE) printf("Build Cell Map...\n");
|
||||
|
||||
int rowCount = GetRowCount();
|
||||
if (0 == rowCount)
|
||||
{
|
||||
// until we have some rows, there's nothing useful to do
|
||||
return;
|
||||
}
|
||||
|
||||
// Make an educated guess as to how many columns we have. It's
|
||||
// only a guess because we can't know exactly until we have
|
||||
// processed the last row.
|
||||
nsTableRowGroupFrame *rowGroupFrame = NextRowGroupFrame(nsnull);
|
||||
if (0 == mColCount)
|
||||
mColCount = GetSpecifiedColumnCount();
|
||||
if (0 == mColCount) // no column parts
|
||||
{
|
||||
// Use the first row to estimate the number of columns
|
||||
nsTableRowFrame *rowFrame;
|
||||
rowGroupFrame->FirstChild((nsIFrame*&)rowFrame);
|
||||
if (nsnull!=rowFrame)
|
||||
{
|
||||
mColCount = rowFrame->GetMaxColumns();
|
||||
if (gsDebug==PR_TRUE)
|
||||
printf("mColCount=0 at start. Guessing col count to be %d from a row.\n", mColCount);
|
||||
}
|
||||
}
|
||||
|
||||
// If we have a cell map reset it; otherwise allocate a new cell map
|
||||
if (nsnull==mCellMap)
|
||||
mCellMap = new nsCellMap(rowCount, mColCount);
|
||||
else
|
||||
mCellMap->Reset(rowCount, mColCount);
|
||||
if (gsDebug==PR_TRUE) printf("mCellMap set to (%d, %d)\n", rowCount, mColCount);
|
||||
|
||||
// Iterate over each row group frame
|
||||
PRInt32 rowIndex = -1;
|
||||
while (nsnull != rowGroupFrame)
|
||||
{
|
||||
// Iterate over each row frame within the row group
|
||||
nsTableRowFrame *rowFrame;
|
||||
rowGroupFrame->FirstChild((nsIFrame*&)rowFrame);
|
||||
while (nsnull != rowFrame)
|
||||
{
|
||||
// Set the row frame's row index. Note that this is a table-wide index,
|
||||
// and not the index within the row group
|
||||
rowIndex++;
|
||||
rowFrame->SetRowIndex(rowIndex);
|
||||
|
||||
// Iterate the table cells
|
||||
PRInt32 cellIndex = 0;
|
||||
PRInt32 colIndex = 0;
|
||||
nsIFrame* cellFrame;
|
||||
rowFrame->FirstChild(cellFrame);
|
||||
|
||||
while ((nsnull != cellFrame) && (colIndex < mColCount))
|
||||
{
|
||||
if (gsDebug==PR_TRUE) printf(" colIndex = %d, with mColCount = %d\n", colIndex, mColCount);
|
||||
CellData *data = mCellMap->GetCellAt(rowIndex, colIndex);
|
||||
if (nsnull == data)
|
||||
{
|
||||
BuildCellIntoMap((nsTableCellFrame*)cellFrame, rowIndex, colIndex);
|
||||
cellIndex++;
|
||||
|
||||
// Get the next cell frame
|
||||
cellFrame->GetNextSibling(cellFrame);
|
||||
}
|
||||
colIndex++;
|
||||
}
|
||||
|
||||
// See if there are any cell frames left in this row
|
||||
if (nsnull != cellFrame)
|
||||
{
|
||||
// We didn't use all the cells in this row up. Grow the cell
|
||||
// data because we now know that we have more columns than we
|
||||
// originally thought we had.
|
||||
PRInt32 cellCount = cellIndex + LengthOf(cellFrame);
|
||||
|
||||
if (gsDebug==PR_TRUE) printf(" calling GrowCellMap because cellIndex < %d\n", cellIndex, cellCount);
|
||||
GrowCellMap (cellCount);
|
||||
while (nsnull != cellFrame)
|
||||
{
|
||||
if (gsDebug==PR_TRUE) printf(" calling GrowCellMap again because cellIndex < %d\n", cellIndex, cellCount);
|
||||
GrowCellMap (colIndex + 1); // ensure enough cols in map, may be low due to colspans
|
||||
CellData *data =mCellMap->GetCellAt(rowIndex, colIndex);
|
||||
if (data == nsnull)
|
||||
{
|
||||
BuildCellIntoMap((nsTableCellFrame*)cellFrame, rowIndex, colIndex);
|
||||
cellIndex++;
|
||||
|
||||
// Get the next cell frame
|
||||
cellFrame->GetNextSibling(cellFrame);
|
||||
}
|
||||
colIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the next row frame
|
||||
rowFrame->GetNextSibling((nsIFrame *&)rowFrame);
|
||||
}
|
||||
|
||||
// Get the next row group frame
|
||||
rowGroupFrame = NextRowGroupFrame(rowGroupFrame);
|
||||
}
|
||||
if (gsDebug==PR_TRUE)
|
||||
DumpCellMap ();
|
||||
// iterate through the columns setting the min col span if necessary
|
||||
// it would be more efficient if we could do this in the above loop
|
||||
// set the minColSpan for each column
|
||||
PRInt32 rowCount = mCellMap->GetRowCount();
|
||||
for (PRInt32 colIndex=0; colIndex<mColCount; colIndex++)
|
||||
{
|
||||
PRInt32 minColSpan;
|
||||
@@ -874,6 +777,56 @@ void nsTableFrame::BuildCellMap ()
|
||||
}
|
||||
}
|
||||
|
||||
void nsTableFrame::AddCellToTable (nsTableRowFrame *aRowFrame,
|
||||
nsTableCellFrame *aCellFrame,
|
||||
PRBool aAddRow)
|
||||
{
|
||||
NS_ASSERTION(nsnull!=aRowFrame, "bad aRowFrame arg");
|
||||
NS_ASSERTION(nsnull!=aCellFrame, "bad aCellFrame arg");
|
||||
NS_PRECONDITION(nsnull!=mCellMap, "bad cellMap");
|
||||
|
||||
// XXX: must be called only on first-in-flow!
|
||||
if (gsDebug==PR_TRUE) printf("Build Cell Map...\n");
|
||||
|
||||
// Make an educated guess as to how many columns we have. It's
|
||||
// only a guess because we can't know exactly until we have
|
||||
// processed the last row.
|
||||
if (0 == mColCount)
|
||||
mColCount = GetSpecifiedColumnCount();
|
||||
if (0 == mColCount) // no column parts
|
||||
{
|
||||
mColCount = aRowFrame->GetMaxColumns();
|
||||
}
|
||||
|
||||
PRInt32 rowIndex;
|
||||
// If we have a cell map reset it; otherwise allocate a new cell map
|
||||
// also determine the index of aRowFrame and set it if necessary
|
||||
if (0==mCellMap->GetRowCount())
|
||||
{ // this is the first time we've ever been called
|
||||
rowIndex = 0;
|
||||
if (gsDebug==PR_TRUE) printf("rowFrame %p set to index %d\n", aRowFrame, rowIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
rowIndex = mCellMap->GetRowCount() - 1; // rowIndex is 0-indexed, rowCount is 1-indexed
|
||||
}
|
||||
|
||||
PRInt32 colIndex=0;
|
||||
while (PR_TRUE)
|
||||
{
|
||||
CellData *data = mCellMap->GetCellAt(rowIndex, colIndex);
|
||||
if (nsnull == data)
|
||||
{
|
||||
BuildCellIntoMap(aCellFrame, rowIndex, colIndex);
|
||||
break;
|
||||
}
|
||||
colIndex++;
|
||||
}
|
||||
|
||||
if (gsDebug==PR_TRUE)
|
||||
DumpCellMap ();
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
void nsTableFrame::DumpCellMap ()
|
||||
@@ -882,7 +835,7 @@ void nsTableFrame::DumpCellMap ()
|
||||
if (nsnull != mCellMap)
|
||||
{
|
||||
PRInt32 rowCount = mCellMap->GetRowCount();
|
||||
PRInt32 cols = GetColCount();
|
||||
PRInt32 cols = mCellMap->GetColCount();
|
||||
for (PRInt32 r = 0; r < rowCount; r++)
|
||||
{
|
||||
if (gsDebug==PR_TRUE)
|
||||
@@ -933,29 +886,35 @@ void nsTableFrame::DumpCellMap ()
|
||||
void nsTableFrame::BuildCellIntoMap (nsTableCellFrame *aCell, PRInt32 aRowIndex, PRInt32 aColIndex)
|
||||
{
|
||||
NS_PRECONDITION (nsnull!=aCell, "bad cell arg");
|
||||
NS_PRECONDITION (aColIndex < mColCount, "bad column index arg");
|
||||
NS_PRECONDITION (aRowIndex < GetRowCount(), "bad row index arg");
|
||||
NS_PRECONDITION (0 <= aColIndex, "bad column index arg");
|
||||
NS_PRECONDITION (0 <= aRowIndex, "bad row index arg");
|
||||
|
||||
// Setup CellMap for this cell
|
||||
int rowSpan = GetEffectiveRowSpan (aRowIndex, aCell);
|
||||
int colSpan = aCell->GetColSpan ();
|
||||
int rowSpan = aCell->GetRowSpan();
|
||||
int colSpan = aCell->GetColSpan();
|
||||
if (gsDebug==PR_TRUE) printf(" BuildCellIntoMap. rowSpan = %d, colSpan = %d\n", rowSpan, colSpan);
|
||||
|
||||
// Grow the mCellMap array if we will end up addressing
|
||||
// some new columns.
|
||||
if (mColCount < (aColIndex + colSpan))
|
||||
if (mCellMap->GetColCount() < (aColIndex + colSpan))
|
||||
{
|
||||
if (gsDebug==PR_TRUE) printf(" mColCount=%d<aColIndex+colSpan so calling GrowCellMap(%d)\n", mColCount, aColIndex+colSpan);
|
||||
if (gsDebug==PR_TRUE)
|
||||
printf(" calling GrowCellMap(%d)\n", aColIndex+colSpan);
|
||||
GrowCellMap (aColIndex + colSpan);
|
||||
}
|
||||
|
||||
if (mCellMap->GetRowCount() < (aRowIndex+1))
|
||||
{
|
||||
printf("*********************************************** calling GrowToRow(%d)\n", aRowIndex+1);
|
||||
mCellMap->GrowToRow(aRowIndex+1);
|
||||
}
|
||||
|
||||
// Setup CellMap for this cell in the table
|
||||
CellData *data = new CellData ();
|
||||
data->mCell = aCell;
|
||||
data->mRealCell = data;
|
||||
if (gsDebug==PR_TRUE) printf(" calling mCellMap->SetCellAt(data, %d, %d)\n", aRowIndex, aColIndex);
|
||||
mCellMap->SetCellAt(data, aRowIndex, aColIndex);
|
||||
aCell->SetColIndex (aColIndex);
|
||||
|
||||
// Create CellData objects for the rows that this cell spans. Set
|
||||
// their mCell to nsnull and their mRealCell to point to data. If
|
||||
@@ -1000,10 +959,7 @@ void nsTableFrame::GrowCellMap (PRInt32 aColCount)
|
||||
{
|
||||
if (nsnull!=mCellMap)
|
||||
{
|
||||
if (mColCount < aColCount)
|
||||
{
|
||||
mCellMap->GrowTo(aColCount);
|
||||
}
|
||||
mCellMap->GrowToCol(aColCount);
|
||||
mColCount = aColCount;
|
||||
}
|
||||
}
|
||||
@@ -1444,6 +1400,9 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext& aPresContext,
|
||||
{
|
||||
if (PR_FALSE==IsFirstPassValid())
|
||||
{ // we treat the table as if we've never seen the layout data before
|
||||
if (mCellMap!=nsnull)
|
||||
delete mCellMap;
|
||||
mCellMap = new nsCellMap(0, 0);
|
||||
mPass = kPASS_FIRST;
|
||||
aStatus = ResizeReflowPass1(&aPresContext, aDesiredSize, aReflowState, aStatus);
|
||||
// check result
|
||||
@@ -1651,8 +1610,6 @@ nsReflowStatus nsTableFrame::ResizeReflowPass1(nsIPresContext* aPresContext,
|
||||
}
|
||||
}
|
||||
|
||||
// BuildColumnCache calls EnsureCellMap. If that ever changes, be sure to call EnsureCellMap
|
||||
// here first.
|
||||
BuildColumnCache(aPresContext, aDesiredSize, aReflowState, aStatus);
|
||||
// Recalculate Layout Dependencies
|
||||
RecalcLayoutData();
|
||||
@@ -1749,7 +1706,7 @@ nsReflowStatus nsTableFrame::ResizeReflowPass2(nsIPresContext* aPresContext,
|
||||
}
|
||||
|
||||
// Return our size and our status
|
||||
aDesiredSize.width = aReflowState.maxSize.width;
|
||||
aDesiredSize.width = ComputeDesiredWidth(aReflowState);
|
||||
aDesiredSize.height = state.y + myBorderPadding.top + myBorderPadding.bottom;
|
||||
|
||||
|
||||
@@ -1773,6 +1730,20 @@ nsReflowStatus nsTableFrame::ResizeReflowPass2(nsIPresContext* aPresContext,
|
||||
|
||||
}
|
||||
|
||||
nscoord nsTableFrame::ComputeDesiredWidth(const nsReflowState& aReflowState) const
|
||||
{
|
||||
nscoord desiredWidth=aReflowState.maxSize.width;
|
||||
// this is the biggest hack in the world. But there's no other rational way to handle nested percent tables
|
||||
nsStylePosition* position;
|
||||
PRBool isNested=IsNested(aReflowState, position);
|
||||
if((eReflowReason_Initial==aReflowState.reason) &&
|
||||
(PR_TRUE==isNested) && (eStyleUnit_Percent==position->mWidth.GetUnit()))
|
||||
{
|
||||
desiredWidth = mTableLayoutStrategy->GetTableMaxWidth();
|
||||
}
|
||||
return desiredWidth;
|
||||
}
|
||||
|
||||
// Collapse child's top margin with previous bottom margin
|
||||
nscoord nsTableFrame::GetTopMarginFor(nsIPresContext* aCX,
|
||||
InnerTableReflowState& aState,
|
||||
@@ -2492,9 +2463,7 @@ void nsTableFrame::BalanceColumnWidths(nsIPresContext* aPresContext,
|
||||
nsSize* aMaxElementSize)
|
||||
{
|
||||
NS_ASSERTION(nsnull==mPrevInFlow, "never ever call me on a continuing frame!");
|
||||
|
||||
if (nsnull==mCellMap)
|
||||
return; // we don't have any information yet, so we can't do any useful work
|
||||
NS_ASSERTION(nsnull!=mCellMap, "never ever call me until the cell map is built!");
|
||||
|
||||
PRInt32 numCols = GetColCount();
|
||||
if (nsnull==mColumnWidths)
|
||||
@@ -2570,13 +2539,12 @@ void nsTableFrame::BalanceColumnWidths(nsIPresContext* aPresContext,
|
||||
void nsTableFrame::SetTableWidth(nsIPresContext* aPresContext)
|
||||
{
|
||||
NS_ASSERTION(nsnull==mPrevInFlow, "never ever call me on a continuing frame!");
|
||||
NS_ASSERTION(nsnull!=mCellMap, "never ever call me until the cell map is built!");
|
||||
|
||||
nscoord cellSpacing = GetCellSpacing();
|
||||
if (gsDebug==PR_TRUE)
|
||||
printf ("SetTableWidth with cellSpacing = %d ", cellSpacing);
|
||||
PRInt32 tableWidth = cellSpacing;
|
||||
if (nsnull==mCellMap)
|
||||
return; // no info, so nothing to do
|
||||
|
||||
PRInt32 numCols = GetColCount();
|
||||
for (PRInt32 colIndex = 0; colIndex<numCols; colIndex++)
|
||||
@@ -2762,6 +2730,8 @@ void nsTableFrame::BuildColumnCache( nsIPresContext* aPresContext,
|
||||
nsReflowStatus& aStatus
|
||||
)
|
||||
{
|
||||
// probably want this assertion : NS_ASSERTION(nsnull==mPrevInFlow, "never ever call me on a continuing frame!");
|
||||
NS_ASSERTION(nsnull!=mCellMap, "never ever call me until the cell map is built!");
|
||||
EnsureColumns(aPresContext, aDesiredSize, aReflowState, aStatus);
|
||||
if (nsnull==mColCache)
|
||||
{
|
||||
@@ -2938,8 +2908,8 @@ PRInt32 nsTableFrame::GetColumnWidth(PRInt32 aColIndex)
|
||||
else
|
||||
{
|
||||
NS_ASSERTION(nsnull!=mColumnWidths, "illegal state");
|
||||
#ifdef DEBUG
|
||||
NS_ASSERTION(nsnull!=mCellMap, "no column layout data");
|
||||
#ifdef NS_DEBUG
|
||||
NS_ASSERTION(nsnull!=mCellMap, "no cell map");
|
||||
PRInt32 numCols = GetColCount();
|
||||
NS_ASSERTION (numCols > aColIndex, "bad arg, col index out of bounds");
|
||||
#endif
|
||||
@@ -2957,7 +2927,7 @@ void nsTableFrame::SetColumnWidth(PRInt32 aColIndex, nscoord aWidth)
|
||||
{
|
||||
nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();
|
||||
NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow");
|
||||
//printf("SET_COL_WIDTH: %p, FIF=%p setting col %d to %d\n", this, firstInFlow, aColIndex, aWidth);
|
||||
|
||||
if (this!=firstInFlow)
|
||||
firstInFlow->SetColumnWidth(aColIndex, aWidth);
|
||||
else
|
||||
@@ -2968,9 +2938,6 @@ void nsTableFrame::SetColumnWidth(PRInt32 aColIndex, nscoord aWidth)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Update the border style to map to the HTML border style
|
||||
@@ -3176,6 +3143,34 @@ nsresult nsTableFrame::NewFrame(nsIFrame** aInstancePtrResult,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* helper method for determining if this is a nested table or not */
|
||||
PRBool nsTableFrame::IsNested(const nsReflowState& aReflowState, nsStylePosition *& aPosition) const
|
||||
{
|
||||
PRBool result = PR_FALSE;
|
||||
#ifdef NS_DEBUG
|
||||
PRInt32 counter=0;
|
||||
#endif
|
||||
// Walk up the reflow state chain until we find a cell or the root
|
||||
const nsReflowState* rs = aReflowState.parentReflowState;
|
||||
while (nsnull != rs)
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
counter++;
|
||||
NS_ASSERTION(counter<100000, "infinite loop in IsNested");
|
||||
#endif
|
||||
nsIFrame* parentTable = nsnull;
|
||||
rs->frame->QueryInterface(kTableFrameCID, (void**) &parentTable);
|
||||
if (nsnull!=parentTable)
|
||||
{
|
||||
result = PR_TRUE;
|
||||
parentTable->GetStyleData(eStyleStruct_Position, ((nsStyleStruct *&)aPosition));
|
||||
break;
|
||||
}
|
||||
rs = rs->parentReflowState;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* helper method for getting the width of the table's containing block */
|
||||
nscoord nsTableFrame::GetTableContainerWidth(const nsReflowState& aReflowState)
|
||||
{
|
||||
|
||||
@@ -73,6 +73,9 @@ public:
|
||||
// nsISupports
|
||||
NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr);
|
||||
|
||||
/** helper method for determining if this is a nested table or not */
|
||||
PRBool IsNested(const nsReflowState& aReflowState, nsStylePosition *& aPosition) const;
|
||||
|
||||
/** helper method for getting the width of the table's containing block */
|
||||
static nscoord GetTableContainerWidth(const nsReflowState& aState);
|
||||
|
||||
@@ -210,6 +213,26 @@ public:
|
||||
const nsReflowState& aReflowState,
|
||||
nsReflowStatus& aStatus);
|
||||
|
||||
/** return the index of the next row that is not yet assigned.
|
||||
* If no row is initialized, 0 is returned.
|
||||
*/
|
||||
PRInt32 GetNextAvailRowIndex() const;
|
||||
|
||||
/** return the index of the next column in aRowIndex after aColIndex
|
||||
* that does not have a cell assigned to it.
|
||||
* If aColIndex is past the end of the row, it is returned.
|
||||
* If the row is not initialized, 0 is returned.
|
||||
*/
|
||||
PRInt32 GetNextAvailColIndex(PRInt32 aRowIndex, PRInt32 aColIndex) const;
|
||||
|
||||
/** build as much of the CellMap as possible from the info we have so far
|
||||
*/
|
||||
virtual void AddCellToTable (nsTableRowFrame *aRowFrame,
|
||||
nsTableCellFrame *aCellFrame,
|
||||
PRBool aAddRow);
|
||||
|
||||
virtual void AddColumnFrame (nsTableColFrame *aColFrame);
|
||||
|
||||
protected:
|
||||
|
||||
/** protected constructor.
|
||||
@@ -256,6 +279,11 @@ protected:
|
||||
nsIFrame* aKidFrame,
|
||||
nscoord aDeltaY);
|
||||
|
||||
/** return the desired width of this table accounting for the current
|
||||
* reflow state, and for the table attributes and parent
|
||||
*/
|
||||
nscoord ComputeDesiredWidth(const nsReflowState& aReflowState) const;
|
||||
|
||||
nscoord GetTopMarginFor(nsIPresContext* aCX,
|
||||
InnerTableReflowState& aState,
|
||||
const nsMargin& aKidMargin);
|
||||
@@ -345,10 +373,6 @@ protected:
|
||||
void MapHTMLBorderStyle(nsStyleSpacing& aSpacingStyle, nscoord aBorderWidth);
|
||||
PRBool ConvertToPixelValue(nsHTMLValue& aValue, PRInt32 aDefault, PRInt32& aResult);
|
||||
|
||||
/** build as much of the CellMap as possible from the info we have so far
|
||||
*/
|
||||
virtual void BuildCellMap ();
|
||||
|
||||
/** called whenever the number of columns changes, to increase the storage in mCellMap
|
||||
*/
|
||||
virtual void GrowCellMap(PRInt32 aColCount);
|
||||
@@ -374,12 +398,6 @@ protected:
|
||||
*/
|
||||
void ListColumnLayoutData(FILE* out, PRInt32 aIndent);
|
||||
|
||||
/** ResetColumns is called when the column structure of the table is changed.
|
||||
* Call with caution, only when adding or removing columns, changing
|
||||
* column attributes, changing the rowspan or colspan attribute of a cell, etc.
|
||||
*/
|
||||
virtual void ResetColumns ();
|
||||
|
||||
/** sum the columns represented by all nsTableColGroup objects.
|
||||
* if the cell map says there are more columns than this,
|
||||
* add extra implicit columns to the content tree.
|
||||
@@ -389,9 +407,8 @@ protected:
|
||||
const nsReflowState& aReflowState,
|
||||
nsReflowStatus& aStatus);
|
||||
|
||||
/** Ensure that the cell map has been built for the table
|
||||
*/
|
||||
virtual void EnsureCellMap();
|
||||
/** Set the min col span for every column in the table. Scans the whole table. */
|
||||
virtual void SetMinColSpanForTable();
|
||||
|
||||
virtual void BuildColumnCache(nsIPresContext* aPresContext,
|
||||
nsReflowMetrics& aDesiredSize,
|
||||
|
||||
@@ -31,6 +31,11 @@
|
||||
#include "nsIPtr.h"
|
||||
#include "nsIReflowCommand.h"
|
||||
#include "nsCSSRendering.h"
|
||||
// the following header files are required for style optimizations that work only when the child content is really a cell
|
||||
#include "nsITableContent.h"
|
||||
#include "nsTableCell.h"
|
||||
static NS_DEFINE_IID(kITableContentIID, NS_ITABLECONTENT_IID);
|
||||
// end includes for style optimizations that require real content knowledge
|
||||
|
||||
NS_DEF_PTR(nsIStyleContext);
|
||||
|
||||
@@ -502,12 +507,13 @@ nsTableRowFrame::InitialReflow(nsIPresContext& aPresContext,
|
||||
// Place our children, one at a time, until we are out of children
|
||||
nsSize kidMaxElementSize;
|
||||
PRInt32 kidIndex = 0;
|
||||
PRInt32 colIndex = -1;
|
||||
PRInt32 colIndex = 0;
|
||||
nsIFrame* prevKidFrame = nsnull;
|
||||
nscoord maxTopMargin = 0;
|
||||
nscoord maxBottomMargin = 0;
|
||||
nscoord x = 0;
|
||||
nsresult result = NS_OK;
|
||||
PRBool isFirst=PR_TRUE;
|
||||
|
||||
for (;;) {
|
||||
// Get the next content object
|
||||
@@ -517,22 +523,41 @@ nsTableRowFrame::InitialReflow(nsIPresContext& aPresContext,
|
||||
break; // no more content
|
||||
}
|
||||
|
||||
// what column does this cell span to?
|
||||
nsHTMLValue value;
|
||||
((nsHTMLTagContent *)cell)->GetAttribute(nsHTMLAtoms::align, value);
|
||||
if (value.GetUnit() == eHTMLUnit_Integer)
|
||||
colIndex += value.GetIntValue();
|
||||
else
|
||||
colIndex += 1;
|
||||
// what row am I?
|
||||
if (PR_TRUE==isFirst)
|
||||
SetRowIndex(aState.tableFrame->GetNextAvailRowIndex());
|
||||
|
||||
// create column frames if necessary
|
||||
// what column does this cell belong to?
|
||||
colIndex = aState.tableFrame->GetNextAvailColIndex(mRowIndex, colIndex);
|
||||
if (gsDebug) printf("%p : next col index = %d\n", this, colIndex);
|
||||
|
||||
/* for style context optimization, set the content's column index if possible.
|
||||
* this can only be done if we really have an nsTableCell.
|
||||
* other tags mapped to table cell display won't benefit from this optimization
|
||||
* see nsHTMLStyleSheet::RulesMatching
|
||||
*/
|
||||
nsITableContent *tableContentInterface = nsnull;
|
||||
nsresult rv = cell->QueryInterface(kITableContentIID,
|
||||
(void **)&tableContentInterface); // tableContentInterface: REFCNT++
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{ // we know it's a table part of some sort, is it a cell?
|
||||
const int contentType = ((nsTableContent *)tableContentInterface)->GetType();
|
||||
if (contentType == nsITableContent::kTableCellType)
|
||||
{
|
||||
((nsTableCell *)tableContentInterface)->SetColIndex(colIndex);
|
||||
if (gsDebug) printf("%p : set cell content %p to col index = %d\n", this, tableContentInterface, colIndex);
|
||||
}
|
||||
NS_RELEASE(tableContentInterface);
|
||||
}
|
||||
// part of the style optimization is to ensure that the column frame for the cell exists
|
||||
// we used to do this post-pass1, now we do it incrementally for the optimization
|
||||
nsReflowStatus status;
|
||||
aState.tableFrame->EnsureColumnFrameAt(colIndex,
|
||||
&aPresContext,
|
||||
aDesiredSize,
|
||||
aState.reflowState,
|
||||
status);
|
||||
// Create a child frame -- always an nsTableCell frame
|
||||
// Create a child frame -- always an nsTableCellFrame
|
||||
nsIStyleContext* kidSC = aPresContext.ResolveStyleContextFor(cell, this, PR_FALSE);
|
||||
nsIContentDelegate* kidDel = cell->GetDelegate(&aPresContext);
|
||||
nsIFrame* kidFrame;
|
||||
@@ -544,21 +569,16 @@ nsTableRowFrame::InitialReflow(nsIPresContext& aPresContext,
|
||||
NS_RELEASE(kidSC);
|
||||
break;
|
||||
}
|
||||
// this sets the frame's notion of it's column index
|
||||
((nsTableCellFrame *)kidFrame)->SetColIndex(colIndex);
|
||||
if (gsDebug) printf("%p : set cell frame %p to col index = %d\n", this, kidFrame, colIndex);
|
||||
// add the cell frame to the table's cell map
|
||||
aState.tableFrame->AddCellToTable(this, (nsTableCellFrame *)kidFrame, isFirst);
|
||||
|
||||
// Because we're not splittable always allow the child to be as high as
|
||||
// it wants. The default available width is also unconstrained so we can
|
||||
// get the child's maximum width
|
||||
nsSize kidAvailSize(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
|
||||
|
||||
// See if there's a width constraint for the cell
|
||||
/*
|
||||
const nsStylePosition* cellPosition = (const nsStylePosition*)
|
||||
kidSC->GetStyleData(eStyleStruct_Position);
|
||||
if (eStyleUnit_Coord == cellPosition->mWidth.GetUnit())
|
||||
{
|
||||
kidAvailSize.width = cellPosition->mWidth.GetCoordValue();
|
||||
}
|
||||
*/
|
||||
NS_IF_RELEASE(kidSC);
|
||||
|
||||
// Get the child's margins
|
||||
@@ -622,6 +642,7 @@ nsTableRowFrame::InitialReflow(nsIPresContext& aPresContext,
|
||||
// Move to the next content child
|
||||
prevKidFrame = kidFrame;
|
||||
kidIndex++;
|
||||
isFirst=PR_FALSE;
|
||||
}
|
||||
|
||||
SetMaxChildHeight(aState.maxCellHeight, maxTopMargin, maxBottomMargin); // remember height of tallest child who doesn't have a row span
|
||||
|
||||
Reference in New Issue
Block a user