diff --git a/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp b/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp
index 1aed57a121e..64e8b90de5e 100644
--- a/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp
+++ b/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp
@@ -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)
diff --git a/mozilla/layout/html/table/src/BasicTableLayoutStrategy.h b/mozilla/layout/html/table/src/BasicTableLayoutStrategy.h
index 726d8cf0093..efc59c43550 100644
--- a/mozilla/layout/html/table/src/BasicTableLayoutStrategy.h
+++ b/mozilla/layout/html/table/src/BasicTableLayoutStrategy.h
@@ -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
diff --git a/mozilla/layout/html/table/src/celldata.h b/mozilla/layout/html/table/src/celldata.h
index 37c519326bf..29134571b65 100644
--- a/mozilla/layout/html/table/src/celldata.h
+++ b/mozilla/layout/html/table/src/celldata.h
@@ -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;
diff --git a/mozilla/layout/html/table/src/nsCellMap.cpp b/mozilla/layout/html/table/src/nsCellMap.cpp
index daba16d32b5..67b91b27888 100644
--- a/mozilla/layout/html/table/src/nsCellMap.cpp
+++ b/mozilla/layout/html/table/src/nsCellMap.cpp
@@ -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;iElementAt(i));
+ for (int j=mColCount; 0ElementAt(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; rowIndexElementAt(rowIndex));
+ const PRInt32 colsInRow = row->Count();
+ if (colsInRow == aColCount)
+ break; // we already have enough columns in each row
+ for (PRInt32 colIndex = colsInRow; colIndexAppendElement(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;iElementAt(rowIndex));
+ for (int colIndex=0; colIndexElementAt(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 (00; 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)
+ {
+ result = aColIndex;
+ }
+ else
+ {
+ if (aRowIndex < mRowCount)
+ {
+ result = aColIndex;
+ nsVoidArray *row = (nsVoidArray *)(mRows->ElementAt(aRowIndex));
+ PRInt32 count = row->Count();
+ for (PRInt32 colIndex=aColIndex; colIndexElementAt(colIndex);
+ if (nsnull==data)
+ {
+ result = colIndex;
+ break;
+ }
+ result++;
+ }
+ }
+ }
+ return result;
+}
diff --git a/mozilla/layout/html/table/src/nsCellMap.h b/mozilla/layout/html/table/src/nsCellMap.h
index 54dfdc51f0c..a461ba9bfa0 100644
--- a/mozilla/layout/html/table/src/nsCellMap.h
+++ b/mozilla/layout/html/table/src/nsCellMap.h
@@ -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");
}
diff --git a/mozilla/layout/html/table/src/nsITableLayoutStrategy.h b/mozilla/layout/html/table/src/nsITableLayoutStrategy.h
index 543235dbf91..77bb1986c2c 100644
--- a/mozilla/layout/html/table/src/nsITableLayoutStrategy.h
+++ b/mozilla/layout/html/table/src/nsITableLayoutStrategy.h
@@ -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
diff --git a/mozilla/layout/html/table/src/nsTableColGroupFrame.cpp b/mozilla/layout/html/table/src/nsTableColGroupFrame.cpp
index d2f7cd02537..b6f1910cdea 100644
--- a/mozilla/layout/html/table/src/nsTableColGroupFrame.cpp
+++ b/mozilla/layout/html/table/src/nsTableColGroupFrame.cpp
@@ -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) {
diff --git a/mozilla/layout/html/table/src/nsTableFrame.cpp b/mozilla/layout/html/table/src/nsTableFrame.cpp
index 495b5a12152..aae92adcfad 100644
--- a/mozilla/layout/html/table/src/nsTableFrame.cpp
+++ b/mozilla/layout/html/table/src/nsTableFrame.cpp
@@ -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; colIndexGetMaxColumns();
+ }
+
+ 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=%dGetRowCount() < (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 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)
{
diff --git a/mozilla/layout/html/table/src/nsTableFrame.h b/mozilla/layout/html/table/src/nsTableFrame.h
index a913c8fdb43..fdc8caafbad 100644
--- a/mozilla/layout/html/table/src/nsTableFrame.h
+++ b/mozilla/layout/html/table/src/nsTableFrame.h
@@ -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,
diff --git a/mozilla/layout/html/table/src/nsTableRowFrame.cpp b/mozilla/layout/html/table/src/nsTableRowFrame.cpp
index bb8b72bc7f3..7ba1f2d7680 100644
--- a/mozilla/layout/html/table/src/nsTableRowFrame.cpp
+++ b/mozilla/layout/html/table/src/nsTableRowFrame.cpp
@@ -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
diff --git a/mozilla/layout/tables/BasicTableLayoutStrategy.cpp b/mozilla/layout/tables/BasicTableLayoutStrategy.cpp
index 1aed57a121e..64e8b90de5e 100644
--- a/mozilla/layout/tables/BasicTableLayoutStrategy.cpp
+++ b/mozilla/layout/tables/BasicTableLayoutStrategy.cpp
@@ -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)
diff --git a/mozilla/layout/tables/BasicTableLayoutStrategy.h b/mozilla/layout/tables/BasicTableLayoutStrategy.h
index 726d8cf0093..efc59c43550 100644
--- a/mozilla/layout/tables/BasicTableLayoutStrategy.h
+++ b/mozilla/layout/tables/BasicTableLayoutStrategy.h
@@ -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
diff --git a/mozilla/layout/tables/celldata.h b/mozilla/layout/tables/celldata.h
index 37c519326bf..29134571b65 100644
--- a/mozilla/layout/tables/celldata.h
+++ b/mozilla/layout/tables/celldata.h
@@ -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;
diff --git a/mozilla/layout/tables/nsCellMap.cpp b/mozilla/layout/tables/nsCellMap.cpp
index daba16d32b5..67b91b27888 100644
--- a/mozilla/layout/tables/nsCellMap.cpp
+++ b/mozilla/layout/tables/nsCellMap.cpp
@@ -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;iElementAt(i));
+ for (int j=mColCount; 0ElementAt(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; rowIndexElementAt(rowIndex));
+ const PRInt32 colsInRow = row->Count();
+ if (colsInRow == aColCount)
+ break; // we already have enough columns in each row
+ for (PRInt32 colIndex = colsInRow; colIndexAppendElement(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;iElementAt(rowIndex));
+ for (int colIndex=0; colIndexElementAt(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 (00; 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)
+ {
+ result = aColIndex;
+ }
+ else
+ {
+ if (aRowIndex < mRowCount)
+ {
+ result = aColIndex;
+ nsVoidArray *row = (nsVoidArray *)(mRows->ElementAt(aRowIndex));
+ PRInt32 count = row->Count();
+ for (PRInt32 colIndex=aColIndex; colIndexElementAt(colIndex);
+ if (nsnull==data)
+ {
+ result = colIndex;
+ break;
+ }
+ result++;
+ }
+ }
+ }
+ return result;
+}
diff --git a/mozilla/layout/tables/nsCellMap.h b/mozilla/layout/tables/nsCellMap.h
index 54dfdc51f0c..a461ba9bfa0 100644
--- a/mozilla/layout/tables/nsCellMap.h
+++ b/mozilla/layout/tables/nsCellMap.h
@@ -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");
}
diff --git a/mozilla/layout/tables/nsITableLayoutStrategy.h b/mozilla/layout/tables/nsITableLayoutStrategy.h
index 543235dbf91..77bb1986c2c 100644
--- a/mozilla/layout/tables/nsITableLayoutStrategy.h
+++ b/mozilla/layout/tables/nsITableLayoutStrategy.h
@@ -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
diff --git a/mozilla/layout/tables/nsTableColGroupFrame.cpp b/mozilla/layout/tables/nsTableColGroupFrame.cpp
index d2f7cd02537..b6f1910cdea 100644
--- a/mozilla/layout/tables/nsTableColGroupFrame.cpp
+++ b/mozilla/layout/tables/nsTableColGroupFrame.cpp
@@ -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) {
diff --git a/mozilla/layout/tables/nsTableFrame.cpp b/mozilla/layout/tables/nsTableFrame.cpp
index 495b5a12152..aae92adcfad 100644
--- a/mozilla/layout/tables/nsTableFrame.cpp
+++ b/mozilla/layout/tables/nsTableFrame.cpp
@@ -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; colIndexGetMaxColumns();
+ }
+
+ 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=%dGetRowCount() < (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 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)
{
diff --git a/mozilla/layout/tables/nsTableFrame.h b/mozilla/layout/tables/nsTableFrame.h
index a913c8fdb43..fdc8caafbad 100644
--- a/mozilla/layout/tables/nsTableFrame.h
+++ b/mozilla/layout/tables/nsTableFrame.h
@@ -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,
diff --git a/mozilla/layout/tables/nsTableRowFrame.cpp b/mozilla/layout/tables/nsTableRowFrame.cpp
index bb8b72bc7f3..7ba1f2d7680 100644
--- a/mozilla/layout/tables/nsTableRowFrame.cpp
+++ b/mozilla/layout/tables/nsTableRowFrame.cpp
@@ -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