lots of work for incremental reflow when the target frame is a table frame

This commit is contained in:
buster%netscape.com 1998-10-14 16:32:45 +00:00
parent e28895d594
commit 0d373afd21
20 changed files with 3152 additions and 1196 deletions

View File

@ -119,6 +119,9 @@ public:
*/
void AppendColumnFrame(nsTableColFrame *aColFrame);
/** empty the column frame cache */
void ClearColumnCache();
/** returns PR_TRUE if the row at aRowIndex has any cells that are the result
* of a row-spanning cell above it. So, given this table:<BR>
* <PRE>
@ -227,5 +230,11 @@ inline void nsCellMap::AppendColumnFrame(nsTableColFrame *aColFrame)
mColFrames->AppendElement(aColFrame);
}
inline void nsCellMap::ClearColumnCache()
{
if (nsnull!=mColFrames)
mColFrames->Clear();
}
#endif

View File

@ -52,8 +52,10 @@ nsresult
nsTableColGroupFrame::InitNewFrames(nsIPresContext& aPresContext, nsIFrame* aChildList)
{
nsresult rv=NS_OK;
nsIFrame* tableFrame=nsnull;
GetGeometricParent(tableFrame);
nsTableFrame* tableFrame=nsnull;
rv = nsTableFrame::GetTableFrame(this, tableFrame);
if ((NS_SUCCEEDED(rv)) && (nsnull!=tableFrame))
{
// Process the newly added column frames
for (nsIFrame* kidFrame = aChildList; nsnull != kidFrame; kidFrame->GetNextSibling(kidFrame)) {
// Set the preliminary values for the column frame
@ -74,7 +76,7 @@ nsTableColGroupFrame::InitNewFrames(nsIPresContext& aPresContext, nsIFrame* aChi
((nsTableColFrame *)(kidFrame))->InitColFrame (colIndex, repeat);
mColCount+= repeat;
((nsTableColFrame *)kidFrame)->SetColumnIndex(colIndex);
((nsTableFrame *)tableFrame)->AddColumnFrame((nsTableColFrame *)kidFrame);
tableFrame->AddColumnFrame((nsTableColFrame *)kidFrame);
}
// colgroup's span attribute is how many columns the group represents
// in the absence of any COL children
@ -107,7 +109,7 @@ nsTableColGroupFrame::InitNewFrames(nsIPresContext& aPresContext, nsIFrame* aChi
PRInt32 absColIndex = mStartColIndex + colIndex;
((nsTableColFrame *)(colFrame))->InitColFrame (absColIndex, 1);
((nsTableColFrame *)colFrame)->SetColumnIndex(absColIndex);
((nsTableFrame *)tableFrame)->AddColumnFrame((nsTableColFrame *)colFrame);
tableFrame->AddColumnFrame((nsTableColFrame *)colFrame);
//hook into list of children
if (nsnull==firstImplicitColFrame)
@ -132,7 +134,7 @@ nsTableColGroupFrame::InitNewFrames(nsIPresContext& aPresContext, nsIFrame* aChi
}
}
SetStyleContextForFirstPass(aPresContext);
}
return rv;
}
@ -233,9 +235,10 @@ NS_METHOD nsTableColGroupFrame::Reflow(nsIPresContext& aPresContext,
NS_METHOD nsTableColGroupFrame::SetStyleContextForFirstPass(nsIPresContext& aPresContext)
{
// get the table frame
nsIFrame* tableFrame=nsnull;
GetGeometricParent(tableFrame);
nsTableFrame* tableFrame=nsnull;
nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame);
if ((NS_SUCCEEDED(rv)) && (nsnull!=tableFrame))
{
// get the style for the table frame
nsStyleTable *tableStyle;
tableFrame->GetStyleData(eStyleStruct_Table, (nsStyleStruct *&)tableStyle);
@ -277,10 +280,10 @@ NS_METHOD nsTableColGroupFrame::SetStyleContextForFirstPass(nsIPresContext& aPre
}
colFrame->GetNextSibling(colFrame);
}
mStyleContext->RecalcAutomaticData(&aPresContext);
}
return NS_OK;
}
return rv;
}

View File

@ -270,6 +270,7 @@ nsTableFrame::nsTableFrame(nsIContent* aContent, nsIFrame* aParentFrame)
mColCache(nsnull),
mTableLayoutStrategy(nsnull),
mFirstPassValid(PR_FALSE),
mCellMapValid(PR_TRUE),
mIsInvariantWidth(PR_FALSE)
{
mEffectiveColCount = -1; // -1 means uninitialized
@ -298,10 +299,43 @@ nsTableFrame::~nsTableFrame()
NS_IMETHODIMP
nsTableFrame::Init(nsIPresContext& aPresContext, nsIFrame* aChildList)
{
nsresult rv=NS_OK;
mFirstChild = aChildList;
EnsureColumns(aPresContext);
return NS_OK;
// I know now that I have all my children, so build the cell map
nsIFrame *nextRowGroup=mFirstChild;
for ( ; nsnull!=nextRowGroup; nextRowGroup->GetNextSibling(nextRowGroup))
{
const nsStyleDisplay *rowGroupDisplay;
nextRowGroup->GetStyleData(eStyleStruct_Display, (nsStyleStruct *&)rowGroupDisplay);
if (PR_TRUE==IsRowGroup(rowGroupDisplay->mDisplay))
{
rv = DidAppendRowGroup((nsTableRowGroupFrame*)nextRowGroup);
}
}
if (NS_SUCCEEDED(rv))
EnsureColumns(aPresContext);
return rv;
}
NS_IMETHODIMP nsTableFrame::DidAppendRowGroup(nsTableRowGroupFrame *aRowGroupFrame)
{
nsresult rv=NS_OK;
nsIFrame *nextRow=nsnull;
aRowGroupFrame->FirstChild(nextRow);
for ( ; nsnull!=nextRow; nextRow->GetNextSibling(nextRow))
{
const nsStyleDisplay *rowDisplay;
nextRow->GetStyleData(eStyleStruct_Display, (nsStyleStruct *&)rowDisplay);
if (NS_STYLE_DISPLAY_TABLE_ROW==rowDisplay->mDisplay)
{
rv = ((nsTableRowFrame *)nextRow)->InitChildren();
if (NS_FAILED(rv))
return rv;
}
}
return rv;
}
/* ****** CellMap methods ******* */
@ -322,14 +356,12 @@ nsTableRowGroupFrame* nsTableFrame::NextRowGroupFrame(nsTableRowGroupFrame* aRow
const nsStyleDisplay *display;
aRowGroupFrame->GetStyleData(eStyleStruct_Display, (nsStyleStruct *&)display);
if (PR_TRUE==IsRowGroup(display->mDisplay))
{ //XXX: assumes content order
{
break;
}
// Get the next frame
aRowGroupFrame->GetNextSibling((nsIFrame*&)aRowGroupFrame);
}
return aRowGroupFrame;
}
@ -346,10 +378,6 @@ PRInt32 nsTableFrame::GetSpecifiedColumnCount ()
{
mColCount += ((nsTableColGroupFrame *)childFrame)->GetColumnCount();
}
else if (PR_TRUE==IsRowGroup(childDisplay->mDisplay))
{ //XXX: assumes content order
break;
}
childFrame->GetNextSibling(childFrame);
}
return mColCount;
@ -358,24 +386,10 @@ PRInt32 nsTableFrame::GetSpecifiedColumnCount ()
PRInt32 nsTableFrame::GetRowCount ()
{
PRInt32 rowCount = 0;
nsCellMap *cellMap = GetCellMap();
NS_ASSERTION(nsnull!=cellMap, "GetRowCount null cellmap");
if (nsnull!=cellMap)
return cellMap->GetRowCount();
nsIFrame *child=mFirstChild;
while (nsnull!=child)
{
const nsStyleDisplay *childDisplay;
child->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay));
if (PR_TRUE==IsRowGroup(childDisplay->mDisplay))
{
PRInt32 thisRowCount=0;
((nsTableRowGroupFrame *)child)->GetRowCount(thisRowCount);
rowCount += thisRowCount;
}
child->GetNextSibling(child);
}
rowCount = cellMap->GetRowCount();
return rowCount;
}
@ -383,7 +397,7 @@ PRInt32 nsTableFrame::GetRowCount ()
PRInt32 nsTableFrame::GetColCount ()
{
nsCellMap *cellMap = GetCellMap();
NS_ASSERTION(nsnull!=cellMap, "GetColCount can only be called after cellmap has been created");
NS_ASSERTION(nsnull!=cellMap, "GetColCount null cellmap");
if (nsnull!=cellMap)
{
@ -396,6 +410,7 @@ PRInt32 nsTableFrame::GetColCount ()
void nsTableFrame::SetEffectiveColCount()
{
nsCellMap *cellMap = GetCellMap();
NS_ASSERTION(nsnull!=cellMap, "SetEffectiveColCount null cellmap");
if (nsnull!=cellMap)
{
PRInt32 colCount = cellMap->GetColCount();
@ -589,7 +604,7 @@ NS_ASSERTION(0<result, "bad effective col span");
PRInt32 nsTableFrame::GetEffectiveCOLSAttribute()
{
nsCellMap *cellMap = GetCellMap();
NS_PRECONDITION (nsnull!=cellMap, "bad call, cellMap not yet allocated.");
NS_PRECONDITION (nsnull!=cellMap, "null cellMap.");
PRInt32 result;
nsIFrame *tableFrame = this;
nsStyleTable *tableStyle=nsnull;
@ -601,16 +616,6 @@ PRInt32 nsTableFrame::GetEffectiveCOLSAttribute()
return result;
}
/* call when the cell structure has changed. mCellMap will be rebuilt on demand. */
void nsTableFrame::ResetCellMap ()
{
// XXX: SEC should this call ResetCellMap on firstInFlow?
if (nsnull!=mCellMap)
delete mCellMap;
mCellMap = nsnull; // for now, will rebuild when needed
}
/** 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.
@ -632,7 +637,7 @@ void nsTableFrame::EnsureColumns(nsIPresContext& aPresContext)
PRInt32 actualColumns = 0;
nsTableColGroupFrame *lastColGroupFrame = nsnull;
nsIFrame * firstRowGroupFrame=nsnull;
nsIFrame * prevSibFrame=nsnull;
nsIFrame * prevSibFrame=nsnull; // this is the child just before the first row group frame
nsIFrame * childFrame=mFirstChild;
while (nsnull!=childFrame)
{
@ -646,11 +651,14 @@ void nsTableFrame::EnsureColumns(nsIPresContext& aPresContext)
if (PR_TRUE==gsDebug) printf("EC: found a col group %p\n", lastColGroupFrame);
}
else if (PR_TRUE==IsRowGroup(childDisplay->mDisplay))
{ // XXX: assumes content order
{
if (nsnull==firstRowGroupFrame)
{
firstRowGroupFrame = childFrame;
if (PR_TRUE==gsDebug) printf("EC: found a row group %p\n", firstRowGroupFrame);
break;
}
}
if (nsnull==firstRowGroupFrame)
prevSibFrame = childFrame;
childFrame->GetNextSibling(childFrame);
}
@ -666,7 +674,7 @@ void nsTableFrame::EnsureColumns(nsIPresContext& aPresContext)
nsAutoString colGroupTag;
nsHTMLAtoms::colgroup->ToString(colGroupTag);
rv = NS_CreateHTMLElement(&lastColGroup, colGroupTag); // ADDREF a: lastColGroup++
//XXX mark it as implicit!
//XXX: make synthetic
mContent->AppendChildTo(lastColGroup, PR_FALSE); // add the implicit colgroup to my content
// Resolve style for the child
nsIStyleContext* colGroupStyleContext =
@ -716,7 +724,7 @@ void nsTableFrame::EnsureColumns(nsIPresContext& aPresContext)
nsIHTMLContent *col=nsnull;
// create an implicit col
rv = NS_CreateHTMLElement(&col, colTag); // ADDREF: col++
//XXX mark the col implicit
//XXX: make synthetic
lastColGroup->AppendChildTo((nsIContent*)col, PR_FALSE);
// Create a new col frame
@ -759,7 +767,7 @@ void nsTableFrame::EnsureColumnFrameAt(PRInt32 aColIndex,
PRInt32 actualColumns = 0;
nsTableColGroupFrame *lastColGroupFrame = nsnull;
nsIFrame * firstRowGroupFrame=nsnull;
nsIFrame * prevSibFrame=nsnull;
nsIFrame * prevSibFrame=nsnull; // this is the child just before the first row group frame
nsIFrame * childFrame=mFirstChild;
while (nsnull!=childFrame)
{
@ -774,10 +782,11 @@ void nsTableFrame::EnsureColumnFrameAt(PRInt32 aColIndex,
break; // we have enough col frames at this point
}
else if (PR_TRUE==IsRowGroup(childDisplay->mDisplay))
{ // XXX: assumes content order
{
if (nsnull==firstRowGroupFrame)
firstRowGroupFrame = childFrame;
break;
}
if (nsnull==firstRowGroupFrame)
prevSibFrame = childFrame;
childFrame->GetNextSibling(childFrame);
}
@ -790,6 +799,7 @@ void nsTableFrame::EnsureColumnFrameAt(PRInt32 aColIndex,
nsAutoString colGroupTag;
nsHTMLAtoms::colgroup->ToString(colGroupTag);
rv = NS_CreateHTMLElement(&lastColGroup, colGroupTag); // ADDREF a: lastColGroup++
//XXX: make synthetic
//XXX mark it as implicit!
mContent->AppendChildTo(lastColGroup, PR_FALSE); // add the implicit colgroup to my content
// Resolve style for the child
@ -837,7 +847,7 @@ void nsTableFrame::EnsureColumnFrameAt(PRInt32 aColIndex,
nsIHTMLContent *col=nsnull;
// create an implicit col
rv = NS_CreateHTMLElement(&col, colTag); // ADDREF: col++
//XXX mark the col implicit
//XXX: make synthetic
lastColGroup->AppendChildTo((nsIContent*)col, PR_FALSE);
// Create a new col frame
@ -868,17 +878,22 @@ void nsTableFrame::EnsureColumnFrameAt(PRInt32 aColIndex,
void nsTableFrame::AddColumnFrame (nsTableColFrame *aColFrame)
{
mCellMap->AppendColumnFrame(aColFrame);
nsCellMap *cellMap = GetCellMap();
NS_PRECONDITION (nsnull!=cellMap, "null cellMap.");
if (nsnull!=cellMap)
cellMap->AppendColumnFrame(aColFrame);
}
/** return the index of the next row that is not yet assigned */
PRInt32 nsTableFrame::GetNextAvailRowIndex() const
{
PRInt32 result=0;
if (nsnull!=mCellMap)
nsCellMap *cellMap = GetCellMap();
NS_PRECONDITION (nsnull!=cellMap, "null cellMap.");
if (nsnull!=cellMap)
{
result = mCellMap->GetRowCount(); // the next index is the current count
mCellMap->GrowToRow(result+1); // expand the cell map to include this new row
result = cellMap->GetRowCount(); // the next index is the current count
cellMap->GrowToRow(result+1); // expand the cell map to include this new row
}
return result;
}
@ -887,15 +902,17 @@ PRInt32 nsTableFrame::GetNextAvailRowIndex() const
PRInt32 nsTableFrame::GetNextAvailColIndex(PRInt32 aRowIndex, PRInt32 aColIndex) const
{
PRInt32 result=0;
if (nsnull!=mCellMap)
result = mCellMap->GetNextAvailColIndex(aRowIndex, aColIndex);
nsCellMap *cellMap = GetCellMap();
NS_PRECONDITION (nsnull!=cellMap, "null cellMap.");
if (nsnull!=cellMap)
result = cellMap->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
*/
nsCellMap * nsTableFrame::GetCellMap()
nsCellMap * nsTableFrame::GetCellMap() const
{
nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();
if (this!=firstInFlow)
@ -951,7 +968,6 @@ void nsTableFrame::AddCellToTable (nsTableRowFrame *aRowFrame,
}
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
@ -979,6 +995,34 @@ void nsTableFrame::AddCellToTable (nsTableRowFrame *aRowFrame,
DumpCellMap ();
}
NS_METHOD nsTableFrame::ReBuildCellMap()
{
nsresult rv=NS_OK;
nsIFrame *rowGroupFrame=mFirstChild;
for ( ; nsnull!=rowGroupFrame; rowGroupFrame->GetNextSibling(rowGroupFrame))
{
const nsStyleDisplay *rowGroupDisplay;
rowGroupFrame->GetStyleData(eStyleStruct_Display, (nsStyleStruct *&)rowGroupDisplay);
if (PR_TRUE==IsRowGroup(rowGroupDisplay->mDisplay))
{
nsIFrame *rowFrame;
rowGroupFrame->FirstChild(rowFrame);
for ( ; nsnull!=rowFrame; rowFrame->GetNextSibling(rowFrame))
{
const nsStyleDisplay *rowDisplay;
rowFrame->GetStyleData(eStyleStruct_Display, (nsStyleStruct *&)rowDisplay);
if (NS_STYLE_DISPLAY_TABLE_ROW==rowDisplay->mDisplay)
{
rv = ((nsTableRowFrame *)rowFrame)->InitChildren();
if (NS_FAILED(rv))
return rv;
}
}
}
}
return rv;
}
/**
*/
void nsTableFrame::DumpCellMap ()
@ -1054,20 +1098,20 @@ void nsTableFrame::BuildCellIntoMap (nsTableCellFrame *aCell, PRInt32 aRowIndex,
// Setup CellMap for this cell
int rowSpan = aCell->GetRowSpan();
int colSpan = aCell->GetColSpan();
if (gsDebug==PR_TRUE) printf(" BuildCellIntoMap. rowSpan = %d, colSpan = %d\n", rowSpan, colSpan);
if (gsDebug==PR_TRUE) printf("BCIM: rowSpan = %d, colSpan = %d\n", rowSpan, colSpan);
// Grow the mCellMap array if we will end up addressing
// some new columns.
if (mCellMap->GetColCount() < (aColIndex + colSpan))
{
if (gsDebug==PR_TRUE)
printf(" calling GrowCellMap(%d)\n", aColIndex+colSpan);
printf("BCIM: calling GrowCellMap(%d)\n", aColIndex+colSpan);
GrowCellMap (aColIndex + colSpan);
}
if (mCellMap->GetRowCount() < (aRowIndex+1))
{
printf("*********************************************** calling GrowToRow(%d)\n", aRowIndex+1);
printf("BCIM: calling GrowToRow(%d)\n", aRowIndex+1);
mCellMap->GrowToRow(aRowIndex+1);
}
@ -1075,7 +1119,7 @@ void nsTableFrame::BuildCellIntoMap (nsTableCellFrame *aCell, PRInt32 aRowIndex,
CellData *data = new CellData ();
data->mCell = aCell;
data->mRealCell = data;
if (gsDebug==PR_TRUE) printf(" calling mCellMap->SetCellAt(data, %d, %d)\n", aRowIndex, aColIndex);
if (gsDebug==PR_TRUE) printf("BCIM: calling mCellMap->SetCellAt(data, %d, %d)\n", aRowIndex, aColIndex);
mCellMap->SetCellAt(data, aRowIndex, aColIndex);
// Create CellData objects for the rows that this cell spans. Set
@ -1084,28 +1128,28 @@ void nsTableFrame::BuildCellIntoMap (nsTableCellFrame *aCell, PRInt32 aRowIndex,
// CellData object for each row that we span...
if ((1 < rowSpan) || (1 < colSpan))
{
if (gsDebug==PR_TRUE) printf(" spans\n");
if (gsDebug==PR_TRUE) printf("BCIM: spans\n");
for (int rowIndex = 0; rowIndex < rowSpan; rowIndex++)
{
if (gsDebug==PR_TRUE) printf(" rowIndex = %d\n", rowIndex);
if (gsDebug==PR_TRUE) printf("BCIM: rowIndex = %d\n", rowIndex);
int workRow = aRowIndex + rowIndex;
if (gsDebug==PR_TRUE) printf(" workRow = %d\n", workRow);
if (gsDebug==PR_TRUE) printf("BCIM: workRow = %d\n", workRow);
for (int colIndex = 0; colIndex < colSpan; colIndex++)
{
if (gsDebug==PR_TRUE) printf(" colIndex = %d\n", colIndex);
if (gsDebug==PR_TRUE) printf("BCIM: colIndex = %d\n", colIndex);
int workCol = aColIndex + colIndex;
if (gsDebug==PR_TRUE) printf(" workCol = %d\n", workCol);
if (gsDebug==PR_TRUE) printf("BCIM: workCol = %d\n", workCol);
CellData *testData = mCellMap->GetCellAt(workRow, workCol);
if (nsnull == testData)
{
CellData *spanData = new CellData ();
spanData->mRealCell = data;
if (gsDebug==PR_TRUE) printf(" null GetCellFrameAt(%d, %d) so setting to spanData\n", workRow, workCol);
if (gsDebug==PR_TRUE) printf("BCIM: null GetCellFrameAt(%d, %d) so setting to spanData\n", workRow, workCol);
mCellMap->SetCellAt(spanData, workRow, workCol);
}
else if ((0 < rowIndex) || (0 < colIndex))
{ // we overlap, replace existing data, it might be shared
if (gsDebug==PR_TRUE) printf(" overlapping Cell from GetCellFrameAt(%d, %d) so setting to spanData\n", workRow, workCol);
if (gsDebug==PR_TRUE) printf("BCIM: overlapping Cell from GetCellFrameAt(%d, %d) so setting to spanData\n", workRow, workCol);
CellData *overlap = new CellData ();
overlap->mCell = testData->mCell;
overlap->mRealCell = testData->mRealCell;
@ -1414,12 +1458,15 @@ NS_METHOD nsTableFrame::Paint(nsIPresContext& aPresContext,
return NS_OK;
}
PRBool nsTableFrame::NeedsReflow(const nsSize& aMaxSize)
PRBool nsTableFrame::NeedsReflow(const nsHTMLReflowState& aReflowState, const nsSize& aMaxSize)
{
PRBool result = PR_TRUE;
if (eReflowReason_Incremental != aReflowState.reason)
{ // incremental reflows always need to be reflowed (for now)
if (PR_TRUE==mIsInvariantWidth)
result = PR_FALSE;
// TODO: other cases...
// XXX TODO: other optimization cases...
}
return result;
}
@ -1509,20 +1556,44 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext& aPresContext,
rv = IncrementalReflow(aPresContext, aDesiredSize, aReflowState, aStatus);
}
if (PR_TRUE==NeedsReflow(aReflowState.maxSize))
// NeedsReflow and IsFirstPassValid take into account reflow type = Initial_Reflow
if (PR_TRUE==NeedsReflow(aReflowState, aReflowState.maxSize))
{
PRBool needsRecalc=PR_FALSE;
if (PR_TRUE==gsDebug) printf("TF Reflow: needs reflow\n");
if (eReflowReason_Initial!=aReflowState.reason && PR_FALSE==IsCellMapValid())
{
if (PR_TRUE==gsDebug) printf("TF Reflow: not initial reflow, so resetting cell map.\n");
if (nsnull!=mCellMap)
delete mCellMap;
mCellMap = new nsCellMap(0,0);
ReBuildCellMap();
needsRecalc=PR_TRUE;
}
if (PR_FALSE==IsFirstPassValid())
{
// XXX TROY: we used to rebuild the cellmap here for incremental reflow.
// now that the cellmap is built in the constructor
// we need to reset the cellmap during incremental reflow before we get here
if (PR_TRUE==gsDebug || PR_TRUE==gsDebugIR) printf("TF Reflow: first pass is invalid\n");
rv = ResizeReflowPass1(aPresContext, aDesiredSize, aReflowState, aStatus);
if (NS_FAILED(rv))
return rv;
needsRecalc=PR_TRUE;
}
if (PR_TRUE==needsRecalc)
{
if (PR_TRUE==gsDebugIR) printf("TF Reflow: needs recalc.\n");
// if we need to recalc, the data stored in the layout strategy is invalid
if (nsnull!=mTableLayoutStrategy)
{
if (PR_TRUE==gsDebugIR) printf("TF Reflow: Re-init layout strategy\n");
mTableLayoutStrategy->Initialize(aDesiredSize.maxElementSize);
}
BuildColumnCache(aPresContext, aDesiredSize, aReflowState, aStatus);
RecalcLayoutData(); // Recalculate Layout Dependencies
}
if (nsnull==mPrevInFlow)
{
{ // only do this for a first-in-flow table frame
// assign column widths, and assign aMaxElementSize->width
BalanceColumnWidths(aPresContext, aReflowState, aReflowState.maxSize,
aDesiredSize.maxElementSize);
@ -1656,10 +1727,6 @@ NS_METHOD nsTableFrame::ResizeReflowPass1(nsIPresContext& aPresContext,
}
}
BuildColumnCache(aPresContext, aDesiredSize, aReflowState, aStatus);
// Recalculate Layout Dependencies
RecalcLayoutData();
aDesiredSize.width = kidSize.width;
mFirstPassValid = PR_TRUE;
@ -1756,6 +1823,7 @@ NS_METHOD nsTableFrame::ResizeReflowPass2(nsIPresContext& aPresContext,
return rv;
}
NS_METHOD nsTableFrame::IncrementalReflow(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
@ -1776,7 +1844,10 @@ NS_METHOD nsTableFrame::IncrementalReflow(nsIPresContext& aPresContext,
rv = aReflowState.reflowCommand->GetTarget(target);
if ((PR_TRUE==NS_SUCCEEDED(rv)) && (nsnull!=target))
{
if (this==target)
// this is the target if target is either this or the outer table frame containing this inner frame
nsIFrame *outerTableFrame=nsnull;
GetGeometricParent(outerTableFrame);
if ((this==target) || (outerTableFrame==target))
rv = IR_TargetIsMe(aPresContext, aDesiredSize, state, aStatus);
else
{
@ -1802,14 +1873,12 @@ NS_METHOD nsTableFrame::IR_TargetIsMe(nsIPresContext& aPresContext,
aReflowState.reflowState.reflowCommand->GetType(type);
nsIFrame *objectFrame;
aReflowState.reflowState.reflowCommand->GetChildFrame(objectFrame);
const nsStyleDisplay *childDisplay;
objectFrame->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay));
if (PR_TRUE==gsDebugIR) printf("TIF IR: IncrementalReflow_TargetIsMe with type=%d\n", type);
switch (type)
{
case nsIReflowCommand::FrameAppended :
case nsIReflowCommand::FrameInserted :
{
const nsStyleDisplay *childDisplay;
objectFrame->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay));
if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == childDisplay->mDisplay)
{
rv = IR_ColGroupInserted(aPresContext, aDesiredSize, aReflowState, aStatus,
@ -1826,7 +1895,22 @@ NS_METHOD nsTableFrame::IR_TargetIsMe(nsIPresContext& aPresContext,
objectFrame, PR_FALSE);
}
break;
case nsIReflowCommand::FrameAppended :
if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == childDisplay->mDisplay)
{
rv = IR_ColGroupAppended(aPresContext, aDesiredSize, aReflowState, aStatus, objectFrame);
}
else if (IsRowGroup(childDisplay->mDisplay))
{
rv = IR_RowGroupAppended(aPresContext, aDesiredSize, aReflowState, aStatus, objectFrame);
}
else
{ // no optimization to be done for Unknown frame types, so just reuse the Inserted method
rv = IR_UnknownFrameInserted(aPresContext, aDesiredSize, aReflowState, aStatus,
objectFrame, PR_FALSE);
}
break;
/*
case nsIReflowCommand::FrameReplaced :
@ -1834,9 +1918,6 @@ NS_METHOD nsTableFrame::IR_TargetIsMe(nsIPresContext& aPresContext,
*/
case nsIReflowCommand::FrameRemoved :
{
const nsStyleDisplay *childDisplay;
objectFrame->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay));
if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == childDisplay->mDisplay)
{
rv = IR_ColGroupRemoved(aPresContext, aDesiredSize, aReflowState, aStatus,
@ -1854,7 +1935,6 @@ NS_METHOD nsTableFrame::IR_TargetIsMe(nsIPresContext& aPresContext,
objectFrame);
}
break;
}
case nsIReflowCommand::StyleChanged :
NS_NOTYETIMPLEMENTED("unimplemented reflow command type");
@ -1898,6 +1978,80 @@ NS_METHOD nsTableFrame::IR_ColGroupInserted(nsIPresContext& aPresContext,
return rv;
}
NS_METHOD nsTableFrame::IR_ColGroupAppended(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aAppendedFrame)
{
nsresult rv=NS_OK;
/*
find where to place colgroup (skipping implicit children?)
for every col in the colgroup (including implicit cols due to span attribute)
an implicit col from the first implicit colgroup is removed
when an implicit colgroups col count goes to 0, it is removed
*/
/* need to really verify that issynthetic is specified on implicit colgroups and cols */
// build a vector of colgroups. XXX might want to do this as a class thing, so we don't have to rebuild it each time
nsVoidArray colGroupList;
nsIFrame *childFrame=mFirstChild;
nsIFrame *lastChild=mFirstChild;
while ((NS_SUCCEEDED(rv)) && (nsnull!=childFrame))
{
const nsStyleDisplay *display;
childFrame->GetStyleData(eStyleStruct_Display, (nsStyleStruct *&)display);
if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == display->mDisplay)
{
colGroupList.AppendElement((void*)childFrame);
}
lastChild=childFrame;
rv = childFrame->GetNextSibling(childFrame);
}
// append aAppendedFrame
if (nsnull!=lastChild)
lastChild->SetNextSibling(aAppendedFrame);
else
mFirstChild = aAppendedFrame;
/* go through the list of colgroups, sucking out implicit columns that are not the result of a span attribute
* and replacing them with columns in aAppendedFrame
* if the column had an attribute from a cell, be sure to preserve that
* if any implicit colgroup becomes empty, destroy it
* if any real colgroup becomes empty, we have to keep it
* factor the new cols into the column cache
* this means having a flag that says whether the col cache needs to be rebuilt or not
*/
PRInt32 colGroupCount = colGroupList.Count();
if (0<colGroupCount)
{
aAppendedFrame->FirstChild(childFrame);
while ((NS_SUCCEEDED(rv)) && (nsnull!=childFrame))
{
const nsStyleDisplay *colDisplay;
childFrame->GetStyleData(eStyleStruct_Display, (nsStyleStruct *&)colDisplay);
if (NS_STYLE_DISPLAY_TABLE_COLUMN == colDisplay->mDisplay)
{ // find an implicit column that is not from a span attribute if there is one and remove it
for (PRInt32 colGroupIndex=0; colGroupIndex<colGroupCount; colGroupIndex++)
{
nsTableColGroupFrame *colGroup = (nsTableColGroupFrame *)(colGroupList.ElementAt(colGroupIndex));
// XXX: here's where we yank colGroups if necessary
}
}
}
}
//InvalidateFirstPassCache(); // for now, redo the first pass reflow
// could probably just get away with mTableLayoutStrategy->Initialize(aMaxElementSize);
mTableLayoutStrategy->Initialize(aDesiredSize.maxElementSize);
//XXX: what we want to do here is determine if the new COL information changes anything about layout
// if not, skip invalidating the first passs
// if so, and we can fix the first pass info
return rv;
}
NS_METHOD nsTableFrame::IR_ColGroupRemoved(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
@ -1921,6 +2075,39 @@ NS_METHOD nsTableFrame::IR_RowGroupInserted(nsIPresContext& aPresContext,
PRBool aReplace)
{
nsresult rv;
// inserting the rowgroup only effects reflow if the rowgroup includes at least one row
return rv;
}
// since we know we're doing an append here, we can optimize
NS_METHOD nsTableFrame::IR_RowGroupAppended(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aAppendedFrame)
{
// hook aAppendedFrame into the child list
nsIFrame *lastChild = mFirstChild;
nsIFrame *nextChild = lastChild;
while (nsnull!=nextChild)
{
lastChild = nextChild;
nextChild->GetNextSibling(nextChild);
}
if (nsnull==lastChild)
mFirstChild = aAppendedFrame;
else
lastChild->SetNextSibling(aAppendedFrame);
// account for the cells in the rows that are children of aAppendedFrame
nsresult rv = DidAppendRowGroup((nsTableRowGroupFrame*)aAppendedFrame);
// do a pass-1 layout of all the cells in all the rows of the rowgroup
InvalidateFirstPassCache();
// if any column widths have to change due to this, re-init the layout strategy
// mTableLayoutStrategy->Initialize(aDesiredSize.aMaxElementSize); //XXX for now, we're just doing the whole enchelada
return rv;
}
@ -2032,7 +2219,7 @@ NS_METHOD nsTableFrame::IR_TargetIsChild(nsIPresContext& aPresContext,
aReflowState.reflowState,
aReflowState.reflowState.maxSize);
ReflowChild(aNextFrame, aPresContext, desiredSize, kidReflowState, aStatus);
rv = ReflowChild(aNextFrame, aPresContext, desiredSize, kidReflowState, aStatus);
// Resize the row group frame
nsRect kidRect;
@ -2160,8 +2347,6 @@ void nsTableFrame::PlaceChild(nsIPresContext& aPresContext,
{
nsMargin borderPadding;
const nsStyleSpacing* tableSpacing;
// begin REMOVE_ME_WHEN_TABLE_STYLE_IS_RESOLVED!
nsIFrame * parent = nsnull;
GetStyleData(eStyleStruct_Spacing , ((nsStyleStruct *&)tableSpacing));
tableSpacing->CalcBorderPaddingFor(this, borderPadding);
nscoord cellSpacing = GetCellSpacing();
@ -2753,13 +2938,18 @@ 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==mPrevInFlow, "never ever call me on a continuing frame!");
NS_ASSERTION(nsnull!=mCellMap, "never ever call me until the cell map is built!");
nsStyleTable* tableStyle;
GetStyleData(eStyleStruct_Table, (nsStyleStruct *&)tableStyle);
EnsureColumns(aPresContext);
if (nsnull==mColCache)
if (nsnull!=mColCache)
{
if (PR_TRUE==gsDebugIR) printf("TIF BCB: clearing column cache and cell map column frame cache.\n");
mCellMap->ClearColumnCache();
delete mColCache;
}
mColCache = new ColumnInfoCache(mColCount);
nsIFrame * childFrame = mFirstChild;
while (nsnull!=childFrame)
@ -2836,14 +3026,9 @@ void nsTableFrame::BuildColumnCache( nsIPresContext& aPresContext,
colFrame->GetNextSibling((nsIFrame *&)colFrame);
}
}
else if (PR_TRUE==IsRowGroup(childDisplay->mDisplay))
{ // XXX: assumes content order
break; // once we hit a row group, we're done
}
childFrame->GetNextSibling(childFrame);
}
}
}
PRBool nsTableFrame::IsFirstPassValid() const
{
@ -2852,6 +3037,48 @@ PRBool nsTableFrame::IsFirstPassValid() const
return firstInFlow->mFirstPassValid;
}
void nsTableFrame::InvalidateFirstPassCache()
{
nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();
NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow");
firstInFlow->mFirstPassValid=PR_FALSE;
}
PRBool nsTableFrame::IsCellMapValid() const
{
nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();
NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow");
return firstInFlow->mCellMapValid;
}
void nsTableFrame::InvalidateCellMap()
{
nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();
NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow");
firstInFlow->mCellMapValid=PR_FALSE;
// reset the state in each row
nsIFrame *rowGroupFrame=mFirstChild;
for ( ; nsnull!=rowGroupFrame; rowGroupFrame->GetNextSibling(rowGroupFrame))
{
const nsStyleDisplay *rowGroupDisplay;
rowGroupFrame->GetStyleData(eStyleStruct_Display, (nsStyleStruct *&)rowGroupDisplay);
if (PR_TRUE==IsRowGroup(rowGroupDisplay->mDisplay))
{
nsIFrame *rowFrame;
rowGroupFrame->FirstChild(rowFrame);
for ( ; nsnull!=rowFrame; rowFrame->GetNextSibling(rowFrame))
{
const nsStyleDisplay *rowDisplay;
rowFrame->GetStyleData(eStyleStruct_Display, (nsStyleStruct *&)rowDisplay);
if (NS_STYLE_DISPLAY_TABLE_ROW==rowDisplay->mDisplay)
{
((nsTableRowFrame *)rowFrame)->ResetInitChildren();
}
}
}
}
}
NS_METHOD
nsTableFrame::CreateContinuingFrame(nsIPresContext& aPresContext,
nsIFrame* aParent,
@ -3148,25 +3375,44 @@ NS_NewTableFrame(nsIContent* aContent,
return NS_OK;
}
NS_METHOD nsTableFrame::GetTableFrame(nsIFrame *aSourceFrame, nsTableFrame *& aOutFrame)
NS_METHOD nsTableFrame::GetTableFrame(nsIFrame *aSourceFrame, nsTableFrame *& aTableFrame)
{
nsresult result = NS_OK;
aOutFrame = nsnull; // initialize out-param
aTableFrame = nsnull; // initialize out-param
if (nsnull!=aSourceFrame)
{
nsresult result = aSourceFrame->GetContentParent((nsIFrame *&)aOutFrame);
while ((NS_OK==result) && (nsnull!=aOutFrame))
nsresult result = aSourceFrame->GetContentParent((nsIFrame *&)aTableFrame);
while ((NS_OK==result) && (nsnull!=aTableFrame))
{
const nsStyleDisplay *display;
aOutFrame->GetStyleData(eStyleStruct_Display, (nsStyleStruct *&)display);
aTableFrame->GetStyleData(eStyleStruct_Display, (nsStyleStruct *&)display);
if (NS_STYLE_DISPLAY_TABLE == display->mDisplay)
{
// at this point, aTableFrame could be an outer frame,
// to find out, scan it's children for another frame with a table display type
// if found, the childFrame must be the inner frame
nsresult rv;
nsIFrame *childFrame=nsnull;
rv = aTableFrame->FirstChild(childFrame);
while ((NS_OK==rv) && (nsnull!=childFrame))
{
const nsStyleDisplay *childDisplay;
childFrame->GetStyleData(eStyleStruct_Display, (nsStyleStruct *&)childDisplay);
if (NS_STYLE_DISPLAY_TABLE == childDisplay->mDisplay)
{
aTableFrame = (nsTableFrame *)childFrame;
break;
result = aOutFrame->GetContentParent((nsIFrame *&)aOutFrame);
}
rv = childFrame->GetNextSibling(childFrame);
}
break;
}
result = aTableFrame->GetContentParent((nsIFrame *&)aTableFrame);
}
}
else
result = NS_ERROR_UNEXPECTED; // bad source param
NS_POSTCONDITION(nsnull!=aOutFrame, "unable to find table parent. aOutFrame null.");
NS_POSTCONDITION(nsnull!=aTableFrame, "unable to find table parent. aTableFrame null.");
NS_POSTCONDITION(NS_OK==result, "unable to find table parent. result!=NS_OK");
return result;
}

View File

@ -79,7 +79,7 @@ public:
PRBool IsNested(const nsHTMLReflowState& aReflowState, nsStylePosition *& aPosition) const;
/** helper method to find the table parent of any table frame object */
static NS_METHOD GetTableFrame(nsIFrame *aSourceFrame, nsTableFrame *& aOutFrame);
static NS_METHOD GetTableFrame(nsIFrame *aSourceFrame, nsTableFrame *& aTableFrame);
/** helper method for getting the width of the table's containing block */
static nscoord GetTableContainerWidth(const nsHTMLReflowState& aState);
@ -97,6 +97,11 @@ public:
NS_IMETHOD Init(nsIPresContext& aPresContext, nsIFrame* aChildList);
/** complete the append of aRowGroupFrame to the table
* this builds the cell map
*/
NS_IMETHOD DidAppendRowGroup(nsTableRowGroupFrame *aRowGroupFrame);
/** @see nsIFrame::Paint */
NS_IMETHOD Paint(nsIPresContext& aPresContext,
nsIRenderingContext& aRenderingContext,
@ -315,6 +320,12 @@ protected:
nsIFrame * aInsertedFrame,
PRBool aReplace);
NS_IMETHOD IR_ColGroupAppended(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aAppendedFrame);
NS_IMETHOD IR_ColGroupRemoved(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
@ -328,6 +339,12 @@ protected:
nsIFrame * aInsertedFrame,
PRBool aReplace);
NS_IMETHOD IR_RowGroupAppended(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aAppendedFrame);
NS_IMETHOD IR_RowGroupRemoved(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
@ -414,11 +431,16 @@ protected:
nscoord aMaxHeight);
/** given the new parent size, do I really need to do a reflow? */
virtual PRBool NeedsReflow(const nsSize& aMaxSize);
virtual PRBool NeedsReflow(const nsHTMLReflowState& aReflowState,
const nsSize& aMaxSize);
/** returns PR_TRUE if the cached pass 1 data is still valid */
virtual PRBool IsFirstPassValid() const;
public:
virtual void InvalidateFirstPassCache();
protected:
/** do post processing to setting up style information for the frame */
NS_IMETHOD DidSetStyleContext(nsIPresContext& aPresContext);
@ -431,16 +453,24 @@ protected:
*/
virtual void GrowCellMap(PRInt32 aColCount);
/** returns PR_TRUE if the cached pass 1 data is still valid */
virtual PRBool IsCellMapValid() const;
public:
/** ResetCellMap is called when the cell structure of the table is changed.
* Call with caution, only when changing the structure of the table such as
* inserting or removing rows, changing the rowspan or colspan attribute of a cell, etc.
*/
virtual void ResetCellMap ();
virtual void InvalidateCellMap();
protected:
/** iterates all child frames and creates a new cell map */
NS_IMETHOD ReBuildCellMap();
/** Get the cell map for this table frame. It is not always mCellMap.
* Only the firstInFlow has a legit cell map
*/
virtual nsCellMap *GetCellMap();
virtual nsCellMap *GetCellMap() const;
/** for debugging only
* prints out information about the cell map
@ -559,6 +589,7 @@ private:
PRInt32 mColumnWidthsLength; // the number of column lengths this frame has allocated
PRBool mColumnWidthsSet; // PR_TRUE if column widths have been set at least once
PRBool mFirstPassValid; // PR_TRUE if first pass data is still legit
PRBool mCellMapValid; // PR_TRUE if cell map data is still legit
PRBool mIsInvariantWidth; // PR_TRUE if table width cannot change
PRInt32 mColCount; // the number of columns in this table
PRInt32 mEffectiveColCount; // the number of columns in this table adjusted for weird table attributes

View File

@ -132,11 +132,11 @@ NS_METHOD nsTableOuterFrame::Paint(nsIPresContext& aPresContext,
return NS_OK;
}
PRBool nsTableOuterFrame::NeedsReflow(const nsSize& aMaxSize)
PRBool nsTableOuterFrame::NeedsReflow(const nsHTMLReflowState& aReflowState, const nsSize& aMaxSize)
{
PRBool result=PR_TRUE;
if (nsnull!=mInnerTableFrame)
result = ((nsTableFrame *)mInnerTableFrame)->NeedsReflow(aMaxSize);
result = ((nsTableFrame *)mInnerTableFrame)->NeedsReflow(aReflowState, aMaxSize);
return result;
}

View File

@ -85,7 +85,7 @@ protected:
* or if the table style attributes or parent max height/width have
* changed.
*/
PRBool NeedsReflow(const nsSize& aMaxSize);
PRBool NeedsReflow(const nsHTMLReflowState& aReflowState, const nsSize& aMaxSize);
void PlaceChild(OuterTableReflowState& aReflowState,
nsIFrame* aKidFrame,

View File

@ -39,10 +39,10 @@ NS_DEF_PTR(nsIStyleContext);
#ifdef NS_DEBUG
static PRBool gsDebug = PR_FALSE;
//#define NOISY
//#define NOISY_FLOW
static PRBool gsDebugIR = PR_FALSE;
#else
static const PRBool gsDebug = PR_FALSE;
static const PRBool gsDebugIR = PR_FALSE;
#endif
/* ----------- RowReflowState ---------- */
@ -88,7 +88,8 @@ nsTableRowFrame::nsTableRowFrame(nsIContent* aContent,
mTallestCell(0),
mCellMaxTopMargin(0),
mCellMaxBottomMargin(0),
mMinRowSpan(1)
mMinRowSpan(1),
mInitializedChildren(PR_FALSE)
{
}
@ -100,13 +101,29 @@ NS_IMETHODIMP
nsTableRowFrame::Init(nsIPresContext& aPresContext, nsIFrame* aChildList)
{
mFirstChild = aChildList;
nsTableFrame* table = nsnull;
nsresult result;
return NS_OK;
}
NS_IMETHODIMP
nsTableRowFrame::InitChildren(PRInt32 aRowIndex)
{
nsTableFrame* table = nsnull;
nsresult result=NS_OK;
// each child cell can only be added to the table one time.
// for now, we remember globally whether we've added all or none
if (PR_FALSE==mInitializedChildren)
{
result = nsTableFrame::GetTableFrame(this, table);
if ((NS_OK==result) && (table != nsnull))
{
SetRowIndex(table->GetNextAvailRowIndex());
mInitializedChildren=PR_TRUE;
PRInt32 rowIndex;
if (-1==aRowIndex)
rowIndex = table->GetNextAvailRowIndex();
else
rowIndex = aRowIndex;
SetRowIndex(rowIndex);
PRInt32 colIndex = 0;
for (nsIFrame* kidFrame = mFirstChild; nsnull != kidFrame; kidFrame->GetNextSibling(kidFrame))
{
@ -142,6 +159,7 @@ nsTableRowFrame::Init(nsIPresContext& aPresContext, nsIFrame* aChildList)
}
}
}
}
return NS_OK;
}
@ -346,7 +364,7 @@ void nsTableRowFrame::FixMinCellHeight(nsTableFrame *aTableFrame)
// aKidRect is relative to the upper-left origin of our frame, and includes
// any left/top margin.
void nsTableRowFrame::PlaceChild(nsIPresContext& aPresContext,
RowReflowState& aState,
RowReflowState& aReflowState,
nsIFrame* aKidFrame,
const nsRect& aKidRect,
nsSize* aMaxElementSize,
@ -360,10 +378,10 @@ void nsTableRowFrame::PlaceChild(nsIPresContext& aPresContext,
aKidFrame->SetRect(aKidRect);
// update the running total for the row width
aState.x += aKidRect.width;
aReflowState.x += aKidRect.width;
// Update the maximum element size
PRInt32 rowSpan = aState.tableFrame->GetEffectiveRowSpan(mRowIndex,
PRInt32 rowSpan = aReflowState.tableFrame->GetEffectiveRowSpan(mRowIndex,
((nsTableCellFrame*)aKidFrame));
if (nsnull != aMaxElementSize)
{
@ -377,18 +395,18 @@ void nsTableRowFrame::PlaceChild(nsIPresContext& aPresContext,
if (mMinRowSpan == rowSpan)
{
// Update maxCellHeight
if (aKidRect.height > aState.maxCellHeight)
aState.maxCellHeight = aKidRect.height;
if (aKidRect.height > aReflowState.maxCellHeight)
aReflowState.maxCellHeight = aKidRect.height;
// Update maxCellVertSpace
nsMargin margin;
if (aState.tableFrame->GetCellMarginData((nsTableCellFrame *)aKidFrame, margin) == NS_OK)
if (aReflowState.tableFrame->GetCellMarginData((nsTableCellFrame *)aKidFrame, margin) == NS_OK)
{
nscoord height = aKidRect.height + margin.top + margin.bottom;
if (height > aState.maxCellVertSpace)
aState.maxCellVertSpace = height;
if (height > aReflowState.maxCellVertSpace)
aReflowState.maxCellVertSpace = height;
}
}
}
@ -398,7 +416,7 @@ void nsTableRowFrame::PlaceChild(nsIPresContext& aPresContext,
* changed. Reflows all the existing table cell frames
*/
nsresult nsTableRowFrame::ResizeReflow(nsIPresContext& aPresContext,
RowReflowState& aState,
RowReflowState& aReflowState,
nsHTMLReflowMetrics& aDesiredSize)
{
if (nsnull == mFirstChild)
@ -410,7 +428,7 @@ nsresult nsTableRowFrame::ResizeReflow(nsIPresContext& aPresContext,
&kidMaxElementSize : nsnull;
nscoord maxCellTopMargin = 0;
nscoord maxCellBottomMargin = 0;
nscoord cellSpacing = aState.tableFrame->GetCellSpacing();
nscoord cellSpacing = aReflowState.tableFrame->GetCellSpacing();
PRInt32 cellColSpan=1; // must be defined here so it's set properly for non-cell kids
if (PR_TRUE==gsDebug) printf("%p: RR\n", this);
// Reflow each of our existing cell frames
@ -421,7 +439,7 @@ nsresult nsTableRowFrame::ResizeReflow(nsIPresContext& aPresContext,
if (NS_STYLE_DISPLAY_TABLE_CELL == kidDisplay->mDisplay)
{
nsMargin kidMargin;
aState.tableFrame->GetCellMarginData((nsTableCellFrame *)kidFrame,kidMargin);
aReflowState.tableFrame->GetCellMarginData((nsTableCellFrame *)kidFrame,kidMargin);
if (kidMargin.top > maxCellTopMargin)
maxCellTopMargin = kidMargin.top;
if (kidMargin.bottom > maxCellBottomMargin)
@ -434,31 +452,31 @@ nsresult nsTableRowFrame::ResizeReflow(nsIPresContext& aPresContext,
{ // if this cell is not immediately adjacent to the previous cell, factor in missing col info
for (PRInt32 colIndex=prevColIndex+1; colIndex<cellColIndex; colIndex++)
{
aState.x += aState.tableFrame->GetColumnWidth(colIndex);
aState.x += cellSpacing;
aReflowState.x += aReflowState.tableFrame->GetColumnWidth(colIndex);
aReflowState.x += cellSpacing;
if (PR_TRUE==gsDebug)
printf(" in loop, aState.x set to %d from cellSpacing %d and col width\n",
aState.x, aState.tableFrame->GetColumnWidth(colIndex), cellSpacing);
printf(" in loop, aReflowState.x set to %d from cellSpacing %d and col width\n",
aReflowState.x, aReflowState.tableFrame->GetColumnWidth(colIndex), cellSpacing);
}
}
aState.x += cellSpacing;
if (PR_TRUE==gsDebug) printf(" past loop, aState.x set to %d\n", aState.x);
aReflowState.x += cellSpacing;
if (PR_TRUE==gsDebug) printf(" past loop, aReflowState.x set to %d\n", aReflowState.x);
// at this point, we know the column widths.
// so we get the avail width from the known column widths
cellColSpan = aState.tableFrame->GetEffectiveColSpan(((nsTableCellFrame *)kidFrame)->GetColIndex(),
cellColSpan = aReflowState.tableFrame->GetEffectiveColSpan(((nsTableCellFrame *)kidFrame)->GetColIndex(),
((nsTableCellFrame *)kidFrame));
nscoord availWidth = 0;
for (PRInt32 numColSpan=0; numColSpan<cellColSpan; numColSpan++)
{
availWidth += aState.tableFrame->GetColumnWidth(cellColIndex+numColSpan);
availWidth += aReflowState.tableFrame->GetColumnWidth(cellColIndex+numColSpan);
if (numColSpan != 0)
{
availWidth += cellSpacing;
}
if (PR_TRUE==gsDebug)
printf(" in loop, availWidth set to %d from colIndex %d width %d and cellSpacing\n",
availWidth, cellColIndex, aState.tableFrame->GetColumnWidth(cellColIndex+numColSpan), cellSpacing);
availWidth, cellColIndex, aReflowState.tableFrame->GetColumnWidth(cellColIndex+numColSpan), cellSpacing);
}
if (PR_TRUE==gsDebug) printf(" availWidth for this cell is %d\n", availWidth);
@ -478,7 +496,7 @@ nsresult nsTableRowFrame::ResizeReflow(nsIPresContext& aPresContext,
// Reflow the child
nsHTMLReflowState kidReflowState(aPresContext, kidFrame,
aState.reflowState, kidAvailSize,
aReflowState.reflowState, kidAvailSize,
eReflowReason_Resize);
if (gsDebug) printf ("%p RR: avail=%d\n", this, availWidth);
nsReflowStatus status;
@ -545,12 +563,12 @@ nsresult nsTableRowFrame::ResizeReflow(nsIPresContext& aPresContext,
// end special Nav4 compatibility code
// Place the child
nsRect kidRect (aState.x, kidMargin.top, cellWidth, cellHeight);
nsRect kidRect (aReflowState.x, kidMargin.top, cellWidth, cellHeight);
PlaceChild(aPresContext, aState, kidFrame, kidRect, aDesiredSize.maxElementSize,
PlaceChild(aPresContext, aReflowState, kidFrame, kidRect, aDesiredSize.maxElementSize,
pKidMaxElementSize);
if (PR_TRUE==gsDebug) printf(" past PlaceChild, aState.x set to %d\n", aState.x);
if (PR_TRUE==gsDebug) printf(" past PlaceChild, aReflowState.x set to %d\n", aReflowState.x);
}
// Get the next child
@ -558,27 +576,27 @@ nsresult nsTableRowFrame::ResizeReflow(nsIPresContext& aPresContext,
// if this was the last child, and it had a colspan>1, add in the cellSpacing for the colspan
// if the last kid wasn't a colspan, then we still have the colspan of the last real cell
if ((nsnull==kidFrame) && (cellColSpan>1))
aState.x += cellSpacing;
aReflowState.x += cellSpacing;
}
SetMaxChildHeight(aState.maxCellHeight,maxCellTopMargin, maxCellBottomMargin); // remember height of tallest child who doesn't have a row span
SetMaxChildHeight(aReflowState.maxCellHeight,maxCellTopMargin, maxCellBottomMargin); // remember height of tallest child who doesn't have a row span
// Return our desired size. Note that our desired width is just whatever width
// we were given by the row group frame
aDesiredSize.width = aState.x;
aDesiredSize.height = aState.maxCellVertSpace;
aDesiredSize.width = aReflowState.x;
aDesiredSize.height = aReflowState.maxCellVertSpace;
if (gsDebug)
printf("rr -- row %p width = %d from maxSize %d\n",
this, aDesiredSize.width, aState.reflowState.maxSize.width);
this, aDesiredSize.width, aReflowState.reflowState.maxSize.width);
if (aDesiredSize.width > aState.reflowState.maxSize.width)
if (aDesiredSize.width > aReflowState.reflowState.maxSize.width)
{
printf ("%p error case, desired width = %d, maxSize=%d\n",
this, aDesiredSize.width, aState.reflowState.maxSize.width);
this, aDesiredSize.width, aReflowState.reflowState.maxSize.width);
fflush (stdout);
}
NS_ASSERTION(aDesiredSize.width <= aState.reflowState.maxSize.width, "row calculated to be too wide.");
NS_ASSERTION(aDesiredSize.width <= aReflowState.reflowState.maxSize.width, "row calculated to be too wide.");
return NS_OK;
}
@ -588,7 +606,7 @@ nsresult nsTableRowFrame::ResizeReflow(nsIPresContext& aPresContext,
*/
nsresult
nsTableRowFrame::InitialReflow(nsIPresContext& aPresContext,
RowReflowState& aState,
RowReflowState& aReflowState,
nsHTMLReflowMetrics& aDesiredSize)
{
// Place our children, one at a time, until we are out of children
@ -622,7 +640,7 @@ nsTableRowFrame::InitialReflow(nsIPresContext& aPresContext,
nsMargin margin;
nscoord topMargin = 0;
if (aState.tableFrame->GetCellMarginData((nsTableCellFrame *)kidFrame, margin) == NS_OK)
if (aReflowState.tableFrame->GetCellMarginData((nsTableCellFrame *)kidFrame, margin) == NS_OK)
{
topMargin = margin.top;
}
@ -647,7 +665,7 @@ nsTableRowFrame::InitialReflow(nsIPresContext& aPresContext,
}
nsHTMLReflowState kidReflowState(aPresContext, kidFrame,
aState.reflowState, kidAvailSize,
aReflowState.reflowState, kidAvailSize,
eReflowReason_Initial);
if (gsDebug) printf ("%p InitR: avail=%d\n", this, kidAvailSize.width);
@ -677,17 +695,17 @@ nsTableRowFrame::InitialReflow(nsIPresContext& aPresContext,
// Place the child
x += margin.left;
nsRect kidRect(x, topMargin, kidSize.width, kidSize.height);
PlaceChild(aPresContext, aState, kidFrame, kidRect, aDesiredSize.maxElementSize,
PlaceChild(aPresContext, aReflowState, kidFrame, kidRect, aDesiredSize.maxElementSize,
&kidMaxElementSize);
x += kidSize.width + margin.right;
}
}
SetMaxChildHeight(aState.maxCellHeight, maxTopMargin, maxBottomMargin); // remember height of tallest child who doesn't have a row span
SetMaxChildHeight(aReflowState.maxCellHeight, maxTopMargin, maxBottomMargin); // remember height of tallest child who doesn't have a row span
// Return our desired size
aDesiredSize.width = x;
aDesiredSize.height = aState.maxCellVertSpace;
aDesiredSize.height = aReflowState.maxCellVertSpace;
return result;
}
@ -700,7 +718,7 @@ nsTableRowFrame::InitialReflow(nsIPresContext& aPresContext,
// - maxVertCellSpace
// - x
nsresult nsTableRowFrame::RecoverState(nsIPresContext& aPresContext,
RowReflowState& aState,
RowReflowState& aReflowState,
nsIFrame* aKidFrame,
nscoord& aMaxCellTopMargin,
nscoord& aMaxCellBottomMargin)
@ -710,8 +728,8 @@ nsresult nsTableRowFrame::RecoverState(nsIPresContext& aPresContext,
// Walk the list of children looking for aKidFrame. While we're at
// it get the maxCellHeight and maxVertCellSpace for all the
// frames except aKidFrame
// nsIFrame* prevKidFrame = nsnull;
for (nsIFrame* frame = mFirstChild; nsnull != frame;) {
for (nsIFrame* frame = mFirstChild; nsnull != frame;)
{
const nsStyleDisplay *kidDisplay;
frame->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)kidDisplay));
if (NS_STYLE_DISPLAY_TABLE_CELL == kidDisplay->mDisplay)
@ -719,13 +737,13 @@ nsresult nsTableRowFrame::RecoverState(nsIPresContext& aPresContext,
if (frame != aKidFrame) {
// Update the max top and bottom margins
nsMargin kidMargin;
aState.tableFrame->GetCellMarginData((nsTableCellFrame *)frame, kidMargin);
aReflowState.tableFrame->GetCellMarginData((nsTableCellFrame *)frame, kidMargin);
if (kidMargin.top > aMaxCellTopMargin)
aMaxCellTopMargin = kidMargin.top;
if (kidMargin.bottom > aMaxCellBottomMargin)
aMaxCellBottomMargin = kidMargin.bottom;
PRInt32 rowSpan = aState.tableFrame->GetEffectiveRowSpan(mRowIndex, ((nsTableCellFrame *)frame));
PRInt32 rowSpan = aReflowState.tableFrame->GetEffectiveRowSpan(mRowIndex, ((nsTableCellFrame *)frame));
if (mMinRowSpan == rowSpan) {
// Get the cell's desired height the last time it was reflowed
nsSize desiredSize = ((nsTableCellFrame *)frame)->GetDesiredSize();
@ -751,18 +769,18 @@ nsresult nsTableRowFrame::RecoverState(nsIPresContext& aPresContext,
desiredSize.height = specifiedHeight;
// Update maxCellHeight
if (desiredSize.height > aState.maxCellHeight) {
aState.maxCellHeight = desiredSize.height;
if (desiredSize.height > aReflowState.maxCellHeight) {
aReflowState.maxCellHeight = desiredSize.height;
}
// Update maxCellVertHeight
nsMargin margin;
if (aState.tableFrame->GetCellMarginData((nsTableCellFrame *)frame, margin) == NS_OK)
if (aReflowState.tableFrame->GetCellMarginData((nsTableCellFrame *)frame, margin) == NS_OK)
{
nscoord height = desiredSize.height + margin.top + margin.bottom;
if (height > aState.maxCellVertSpace) {
aState.maxCellVertSpace = height;
if (height > aReflowState.maxCellVertSpace) {
aReflowState.maxCellVertSpace = height;
}
}
}
@ -775,44 +793,294 @@ nsresult nsTableRowFrame::RecoverState(nsIPresContext& aPresContext,
}
}
// Remember the frame that precedes aKidFrame
// prevKidFrame = frame;
frame->GetNextSibling(frame);
}
// Update the running x-offset based on the frame's current x-origin
nsPoint origin;
aKidFrame->GetOrigin(origin);
aState.x = origin.x;
aReflowState.x = origin.x;
return NS_OK;
}
nsresult nsTableRowFrame::IncrementalReflow(nsIPresContext& aPresContext,
RowReflowState& aState,
nsHTMLReflowMetrics& aDesiredSize)
{
nsresult status;
// XXX Deal with the case where the reflow command is targeted at us
nsIFrame* target;
aState.reflowState.reflowCommand->GetTarget(target);
if (this == target) {
NS_NOTYETIMPLEMENTED("unexpected reflow command");
return NS_ERROR_NOT_IMPLEMENTED;
NS_METHOD nsTableRowFrame::IncrementalReflow(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowReflowState& aReflowState,
nsReflowStatus& aStatus)
{
if (PR_TRUE==gsDebugIR) printf("\nTRF IR: IncrementalReflow\n");
nsresult rv = NS_OK;
// determine if this frame is the target or not
nsIFrame *target=nsnull;
rv = aReflowState.reflowState.reflowCommand->GetTarget(target);
if ((PR_TRUE==NS_SUCCEEDED(rv)) && (nsnull!=target))
{
if (this==target)
rv = IR_TargetIsMe(aPresContext, aDesiredSize, aReflowState, aStatus);
else
{
// Get the next frame in the reflow chain
nsIFrame* nextFrame;
aReflowState.reflowState.reflowCommand->GetNext(nextFrame);
rv = IR_TargetIsChild(aPresContext, aDesiredSize, aReflowState, aStatus, nextFrame);
}
}
return rv;
}
// Get the next frame in the reflow chain
nsIFrame* kidFrame;
aState.reflowState.reflowCommand->GetNext(kidFrame);
NS_METHOD nsTableRowFrame::IR_TargetIsMe(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowReflowState& aReflowState,
nsReflowStatus& aStatus)
{
nsresult rv = NS_FRAME_COMPLETE;
nsIReflowCommand::ReflowType type;
aReflowState.reflowState.reflowCommand->GetType(type);
nsIFrame *objectFrame;
aReflowState.reflowState.reflowCommand->GetChildFrame(objectFrame);
const nsStyleDisplay *childDisplay;
objectFrame->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay));
if (PR_TRUE==gsDebugIR) printf("TRF IR: IncrementalReflow_TargetIsMe with type=%d\n", type);
switch (type)
{
case nsIReflowCommand::FrameInserted :
if (NS_STYLE_DISPLAY_TABLE_CELL == childDisplay->mDisplay)
{
rv = IR_CellInserted(aPresContext, aDesiredSize, aReflowState, aStatus,
objectFrame, PR_FALSE);
}
else
{
rv = IR_UnknownFrameInserted(aPresContext, aDesiredSize, aReflowState, aStatus,
objectFrame, PR_FALSE);
}
break;
case nsIReflowCommand::FrameAppended :
if (NS_STYLE_DISPLAY_TABLE_CELL == childDisplay->mDisplay)
{
rv = IR_CellAppended(aPresContext, aDesiredSize, aReflowState, aStatus, objectFrame);
}
else
{ // no optimization to be done for Unknown frame types, so just reuse the Inserted method
rv = IR_UnknownFrameInserted(aPresContext, aDesiredSize, aReflowState, aStatus,
objectFrame, PR_FALSE);
}
break;
/*
case nsIReflowCommand::FrameReplaced :
*/
case nsIReflowCommand::FrameRemoved :
if (NS_STYLE_DISPLAY_TABLE_CELL == childDisplay->mDisplay)
{
rv = IR_CellRemoved(aPresContext, aDesiredSize, aReflowState, aStatus,
objectFrame);
}
else
{
rv = IR_UnknownFrameRemoved(aPresContext, aDesiredSize, aReflowState, aStatus,
objectFrame);
}
break;
case nsIReflowCommand::StyleChanged :
NS_NOTYETIMPLEMENTED("unimplemented reflow command type");
rv = NS_ERROR_NOT_IMPLEMENTED;
if (PR_TRUE==gsDebugIR) printf("TRF IR: StyleChanged not implemented.\n");
break;
case nsIReflowCommand::ContentChanged :
NS_ASSERTION(PR_FALSE, "illegal reflow type: ContentChanged");
rv = NS_ERROR_ILLEGAL_VALUE;
break;
case nsIReflowCommand::PullupReflow:
case nsIReflowCommand::PushReflow:
case nsIReflowCommand::CheckPullupReflow :
case nsIReflowCommand::UserDefined :
NS_NOTYETIMPLEMENTED("unimplemented reflow command type");
rv = NS_ERROR_NOT_IMPLEMENTED;
if (PR_TRUE==gsDebugIR) printf("TRF IR: reflow command not implemented.\n");
break;
}
return rv;
}
NS_METHOD nsTableRowFrame::IR_CellInserted(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aInsertedFrame,
PRBool aReplace)
{
nsresult rv=NS_OK;
return rv;
}
NS_METHOD nsTableRowFrame::IR_DidAppendCell(nsTableRowFrame *aRowFrame)
{
nsresult rv=NS_OK;
return rv;
}
// since we know we're doing an append here, we can optimize
NS_METHOD nsTableRowFrame::IR_CellAppended(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aAppendedFrame)
{
nsresult rv=NS_OK;
// hook aAppendedFrame into the child list
nsIFrame *lastChild = mFirstChild;
nsIFrame *nextChild = lastChild;
nsIFrame *lastRow = nsnull;
while (nsnull!=nextChild)
{
// remember the last child that is really a cell
const nsStyleDisplay *childDisplay;
nextChild->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay));
if (NS_STYLE_DISPLAY_TABLE_CELL == childDisplay->mDisplay)
lastRow = nextChild;
lastChild = nextChild;
nextChild->GetNextSibling(nextChild);
}
if (nsnull==lastChild)
mFirstChild = aAppendedFrame;
else
lastChild->SetNextSibling(aAppendedFrame);
aReflowState.tableFrame->InvalidateFirstPassCache();
// the table will see that it's cached info is bogus and rebuild the cell map,
// and do a reflow
#if 0
// find the col index of the new cell
// account for the new cell
nsresult rv = DidAppendCell((nsTableCellFrame*)aAppendedFrame);
// need to increment the row index of all subsequent rows
#endif
return rv;
}
NS_METHOD nsTableRowFrame::IR_CellRemoved(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aDeletedFrame)
{
nsresult rv=NS_OK;
return rv;
}
//XXX: handle aReplace
NS_METHOD nsTableRowFrame::IR_UnknownFrameInserted(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aInsertedFrame,
PRBool aReplace)
{
nsIReflowCommand::ReflowType type;
aReflowState.reflowState.reflowCommand->GetType(type);
// we have a generic frame that gets inserted but doesn't effect reflow
// hook it up then ignore it
if (nsIReflowCommand::FrameAppended==type)
{ // frameAppended reflow -- find the last child and make aInsertedFrame its next sibling
if (PR_TRUE==gsDebugIR) printf("TRF IR: FrameAppended adding unknown frame type.\n");
nsIFrame *lastChild=mFirstChild;
nsIFrame *nextChild=mFirstChild;
while (nsnull!=nextChild)
{
lastChild=nextChild;
nextChild->GetNextSibling(nextChild);
}
if (nsnull==lastChild)
mFirstChild = aInsertedFrame;
else
lastChild->SetNextSibling(aInsertedFrame);
}
else
{ // frameInserted reflow -- hook up aInsertedFrame as prevSibling's next sibling,
// and be sure to hook in aInsertedFrame's nextSibling (from prevSibling)
if (PR_TRUE==gsDebugIR) printf("TRF IR: FrameInserted adding unknown frame type.\n");
nsIFrame *prevSibling=nsnull;
nsresult rv = aReflowState.reflowState.reflowCommand->GetPrevSiblingFrame(prevSibling);
if (NS_SUCCEEDED(rv) && (nsnull!=prevSibling))
{
nsIFrame *nextSibling=nsnull;
prevSibling->GetNextSibling(nextSibling);
prevSibling->SetNextSibling(aInsertedFrame);
aInsertedFrame->SetNextSibling(nextSibling);
}
else
{
nsIFrame *nextSibling=nsnull;
if (nsnull!=mFirstChild)
mFirstChild->GetNextSibling(nextSibling);
mFirstChild = aInsertedFrame;
aInsertedFrame->SetNextSibling(nextSibling);
}
}
return NS_FRAME_COMPLETE;
}
NS_METHOD nsTableRowFrame::IR_UnknownFrameRemoved(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aRemovedFrame)
{
// we have a generic frame that gets removed but doesn't effect reflow
// unhook it then ignore it
if (PR_TRUE==gsDebugIR) printf("TRF IR: FrameRemoved removing unknown frame type.\n");
nsIFrame *prevChild=nsnull;
nsIFrame *nextChild=mFirstChild;
while (nextChild!=aRemovedFrame)
{
prevChild=nextChild;
nextChild->GetNextSibling(nextChild);
}
nextChild=nsnull;
aRemovedFrame->GetNextSibling(nextChild);
if (nsnull==prevChild) // objectFrame was first child
mFirstChild = nextChild;
else
prevChild->SetNextSibling(nextChild);
return NS_FRAME_COMPLETE;
}
NS_METHOD nsTableRowFrame::IR_TargetIsChild(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aNextFrame)
{
nsresult rv;
const nsStyleDisplay *childDisplay;
aNextFrame->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay));
if (NS_STYLE_DISPLAY_TABLE_CELL == childDisplay->mDisplay)
{
// Recover our reflow state
nscoord maxCellTopMargin, maxCellBottomMargin;
RecoverState(aPresContext, aState, kidFrame, maxCellTopMargin, maxCellBottomMargin);
RecoverState(aPresContext, aReflowState, aNextFrame, maxCellTopMargin, maxCellBottomMargin);
// Get the frame's margins
nsMargin kidMargin;
aState.tableFrame->GetCellMarginData((nsTableCellFrame *)kidFrame, kidMargin);
aReflowState.tableFrame->GetCellMarginData((nsTableCellFrame *)aNextFrame, kidMargin);
if (kidMargin.top > maxCellTopMargin)
maxCellTopMargin = kidMargin.top;
if (kidMargin.bottom > maxCellBottomMargin)
@ -820,13 +1088,13 @@ nsresult nsTableRowFrame::IncrementalReflow(nsIPresContext& aPresContext,
// At this point, we know the column widths. Get the available width
// from the known column widths
PRInt32 cellColIndex = ((nsTableCellFrame *)kidFrame)->GetColIndex();
PRInt32 cellColSpan = aState.tableFrame->GetEffectiveColSpan(((nsTableCellFrame *)kidFrame)->GetColIndex(),
((nsTableCellFrame *)kidFrame));
PRInt32 cellColIndex = ((nsTableCellFrame *)aNextFrame)->GetColIndex();
PRInt32 cellColSpan = aReflowState.tableFrame->GetEffectiveColSpan(((nsTableCellFrame *)aNextFrame)->GetColIndex(),
((nsTableCellFrame *)aNextFrame));
nscoord availWidth = 0;
for (PRInt32 numColSpan = 0; numColSpan < cellColSpan; numColSpan++)
{
availWidth += aState.tableFrame->GetColumnWidth(cellColIndex+numColSpan);
availWidth += aReflowState.tableFrame->GetColumnWidth(cellColIndex+numColSpan);
if (0<numColSpan)
{
availWidth += kidMargin.right;
@ -843,14 +1111,14 @@ nsresult nsTableRowFrame::IncrementalReflow(nsIPresContext& aPresContext,
// Pass along the reflow command
nsSize kidMaxElementSize;
nsHTMLReflowMetrics desiredSize(&kidMaxElementSize);
nsHTMLReflowState kidReflowState(aPresContext, kidFrame, aState.reflowState,
nsHTMLReflowState kidReflowState(aPresContext, aNextFrame, aReflowState.reflowState,
kidAvailSize);
// XXX Unfortunately we need to reflow the child several times.
// The first time is for the incremental reflow command. We can't pass in
// a max width of NS_UNCONSTRAINEDSIZE, because the max width must match
// the width of the previous reflow...
ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState, status);
rv = ReflowChild(aNextFrame, aPresContext, desiredSize, kidReflowState, aStatus);
// Now do the regular pass 1 reflow and gather the max width and max element
// size.
@ -859,10 +1127,10 @@ nsresult nsTableRowFrame::IncrementalReflow(nsIPresContext& aPresContext,
kidReflowState.reason = eReflowReason_Resize;
kidReflowState.reflowCommand = nsnull;
kidReflowState.maxSize.width = NS_UNCONSTRAINEDSIZE;
ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState, status);
rv = ReflowChild(aNextFrame, aPresContext, desiredSize, kidReflowState, aStatus);
if (gsDebug)
printf ("TR %p for cell %p Incremental Reflow: desired=%d, MES=%d\n",
this, kidFrame, desiredSize.width, kidMaxElementSize.width);
this, aNextFrame, desiredSize.width, kidMaxElementSize.width);
// Update the cell layout data.
//XXX: this is a hack, shouldn't it be the case that a min size is
// never larger than a desired size?
@ -870,13 +1138,13 @@ nsresult nsTableRowFrame::IncrementalReflow(nsIPresContext& aPresContext,
desiredSize.width = kidMaxElementSize.width;
if (kidMaxElementSize.height>desiredSize.height)
desiredSize.height = kidMaxElementSize.height;
((nsTableCellFrame *)kidFrame)->SetPass1DesiredSize(desiredSize);
((nsTableCellFrame *)kidFrame)->SetPass1MaxElementSize(kidMaxElementSize);
((nsTableCellFrame *)aNextFrame)->SetPass1DesiredSize(desiredSize);
((nsTableCellFrame *)aNextFrame)->SetPass1MaxElementSize(kidMaxElementSize);
// Now reflow the cell again this time constraining the width
// XXX Ignore for now the possibility that the column width has changed...
kidReflowState.maxSize.width = availWidth;
ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState, status);
rv = ReflowChild(aNextFrame, aPresContext, desiredSize, kidReflowState, aStatus);
// Place the child after taking into account it's margin and attributes
// XXX We need to ask the table (or the table layout strategy) if the column
@ -885,7 +1153,7 @@ nsresult nsTableRowFrame::IncrementalReflow(nsIPresContext& aPresContext,
nscoord specifiedHeight = 0;
nscoord cellHeight = desiredSize.height;
nsIStyleContextPtr kidSC;
kidFrame->GetStyleContext(&aPresContext, kidSC.AssignRef());
aNextFrame->GetStyleContext(&aPresContext, kidSC.AssignRef());
const nsStylePosition* kidPosition = (const nsStylePosition*)
kidSC->GetStyleData(eStyleStruct_Position);
switch (kidPosition->mHeight.GetUnit()) {
@ -906,30 +1174,35 @@ nsresult nsTableRowFrame::IncrementalReflow(nsIPresContext& aPresContext,
// begin special Nav4 compatibility code
if (0==cellWidth)
{
cellWidth = aState.tableFrame->GetColumnWidth(cellColIndex);
cellWidth = aReflowState.tableFrame->GetColumnWidth(cellColIndex);
}
// end special Nav4 compatibility code
// Now place the child
nsRect kidRect (aState.x, kidMargin.top, cellWidth, cellHeight);
nsRect kidRect (aReflowState.x, kidMargin.top, cellWidth, cellHeight);
PlaceChild(aPresContext, aState, kidFrame, kidRect, aDesiredSize.maxElementSize,
PlaceChild(aPresContext, aReflowState, aNextFrame, kidRect, aDesiredSize.maxElementSize,
&kidMaxElementSize);
SetMaxChildHeight(aState.maxCellHeight, maxCellTopMargin, maxCellBottomMargin);
SetMaxChildHeight(aReflowState.maxCellHeight, maxCellTopMargin, maxCellBottomMargin);
// Return our desired size. Note that our desired width is just whatever width
// we were given by the row group frame
aDesiredSize.width = aState.availSize.width;
aDesiredSize.height = aState.maxCellVertSpace;
aDesiredSize.width = aReflowState.availSize.width;
aDesiredSize.height = aReflowState.maxCellVertSpace;
if (gsDebug)
printf("incr -- row %p width = %d MES=%d from maxSize %d\n",
this, aDesiredSize.width, aDesiredSize.maxElementSize->width,
aState.reflowState.maxSize.width);
return status;
aReflowState.reflowState.maxSize.width);
}
else
{ // pass reflow to unknown frame child
// aDesiredSize does not change
}
return rv;
}
/** Layout the entire row.
* This method stacks cells horizontally according to HTML 4.0 rules.
@ -940,45 +1213,46 @@ nsTableRowFrame::Reflow(nsIPresContext& aPresContext,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus)
{
nsresult rv=NS_OK;
if (gsDebug==PR_TRUE)
printf("nsTableRowFrame::Reflow - aMaxSize = %d, %d\n",
aReflowState.maxSize.width, aReflowState.maxSize.height);
// Initialize 'out' parameters
// Initialize 'out' parameters (aStatus set below, undefined if rv returns an error)
if (nsnull != aDesiredSize.maxElementSize) {
aDesiredSize.maxElementSize->width = 0;
aDesiredSize.maxElementSize->height = 0;
}
aStatus = NS_FRAME_COMPLETE; // we're never continued
// Initialize our internal data
ResetMaxChildHeight();
// Initialize our automatic state object
nsTableFrame* tableFrame;
mContentParent->GetContentParent((nsIFrame*&)tableFrame);
// Create a reflow state
nsTableFrame *tableFrame=nsnull;
rv = nsTableFrame::GetTableFrame(this, tableFrame);
if (NS_FAILED(rv) || nsnull==tableFrame)
return rv;
RowReflowState state(aReflowState, tableFrame);
// Do the reflow
nsresult result;
switch (aReflowState.reason) {
case eReflowReason_Initial:
result = InitialReflow(aPresContext, state, aDesiredSize);
rv = InitialReflow(aPresContext, state, aDesiredSize);
GetMinRowSpan(tableFrame);
FixMinCellHeight(tableFrame);
break;
case eReflowReason_Resize:
result = ResizeReflow(aPresContext, state, aDesiredSize);
rv = ResizeReflow(aPresContext, state, aDesiredSize);
break;
case eReflowReason_Incremental:
result = IncrementalReflow(aPresContext, state, aDesiredSize);
rv = IncrementalReflow(aPresContext, aDesiredSize, state, aStatus);
break;
}
aStatus = NS_FRAME_COMPLETE; // we're never continued
if (gsDebug==PR_TRUE)
{
if (nsnull!=aDesiredSize.maxElementSize)
@ -992,7 +1266,7 @@ nsTableRowFrame::Reflow(nsIPresContext& aPresContext,
aDesiredSize.width, aDesiredSize.height);
}
return result;
return rv;
}
NS_METHOD

View File

@ -38,8 +38,13 @@ struct RowReflowState;
class nsTableRowFrame : public nsContainerFrame
{
public:
/** Initialization procedure */
void Init(PRInt32 aRowIndex);
/** Initialization of frame as a row */
void InitRowData(PRInt32 aRowIndex);
/** Initialization of data */
NS_IMETHOD InitChildren(PRInt32 aRowIndex=-1);
void ResetInitChildren();
/** instantiate a new instance of nsTableRowFrame.
* @param aResult the new object is returned in this out-param
@ -126,6 +131,64 @@ protected:
/** destructor */
virtual ~nsTableRowFrame();
/** Incremental Reflow attempts to do column balancing with the minimum number of reflow
* commands to child elements. This is done by processing the reflow command,
* rebalancing column widths (if necessary), then comparing the resulting column widths
* to the prior column widths and reflowing only those cells that require a reflow.
*
* @see Reflow
*/
NS_IMETHOD IncrementalReflow(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowReflowState& aReflowState,
nsReflowStatus& aStatus);
NS_IMETHOD IR_TargetIsChild(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aNextFrame);
NS_IMETHOD IR_TargetIsMe(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowReflowState& aReflowState,
nsReflowStatus& aStatus);
NS_IMETHOD IR_CellInserted(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aInsertedFrame,
PRBool aReplace);
NS_IMETHOD IR_CellAppended(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aAppendedFrame);
NS_IMETHOD IR_DidAppendCell(nsTableRowFrame *aRowFrame);
NS_IMETHOD IR_CellRemoved(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aDeletedFrame);
NS_IMETHOD IR_UnknownFrameInserted(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aInsertedFrame,
PRBool aReplace);
NS_IMETHOD IR_UnknownFrameRemoved(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aDeletedFrame);
// row-specific methods
void GetMinRowSpan(nsTableFrame *aTableFrame);
@ -180,11 +243,14 @@ private:
nscoord mCellMaxTopMargin;
nscoord mCellMaxBottomMargin;
PRInt32 mMinRowSpan; // the smallest row span among all my child cells
PRBool mInitializedChildren; // PR_TRUE if child cells have been initialized
// (for now, that means "added to the table", and
// is NOT the same as having nsIFrame::Init() called.)
};
inline void nsTableRowFrame::Init(PRInt32 aRowIndex)
inline void nsTableRowFrame::InitRowData(PRInt32 aRowIndex)
{
NS_ASSERTION(0<=aRowIndex, "bad param row index");
mRowIndex = aRowIndex;
@ -196,4 +262,7 @@ inline PRInt32 nsTableRowFrame::GetRowIndex() const
return (mRowIndex);
}
inline void nsTableRowFrame::ResetInitChildren()
{ mInitializedChildren=PR_FALSE; }
#endif

View File

@ -30,10 +30,10 @@
#ifdef NS_DEBUG
static PRBool gsDebug = PR_FALSE;
//#define NOISY
//#define NOISY_FLOW
static PRBool gsDebugIR = PR_FALSE;
#else
static const PRBool gsDebug = PR_FALSE;
static const PRBool gsDebugIR = PR_FALSE;
#endif
NS_DEF_PTR(nsIStyleContext);
@ -42,8 +42,8 @@ NS_DEF_PTR(nsIContent);
/* ----------- RowGroupReflowState ---------- */
struct RowGroupReflowState {
// Our reflow state
const nsHTMLReflowState& reflowState;
nsIPresContext& mPresContext; // Our pres context
const nsHTMLReflowState& reflowState; // Our reflow state
// The body's available size (computed from the body's parent)
nsSize availSize;
@ -65,9 +65,10 @@ struct RowGroupReflowState {
// Remember the height of the first row, because it's our maxElementHeight (plus header/footers)
nscoord firstRowHeight;
RowGroupReflowState(nsIPresContext* aPresContext,
RowGroupReflowState(nsIPresContext& aPresContext,
const nsHTMLReflowState& aReflowState)
: reflowState(aReflowState)
: mPresContext(aPresContext),
reflowState(aReflowState)
{
availSize.width = reflowState.maxSize.width;
availSize.height = reflowState.maxSize.height;
@ -686,7 +687,7 @@ void nsTableRowGroupFrame::ShrinkWrapChildren(nsIPresContext* aPresContext,
delete []rowHeights;
}
nsresult nsTableRowGroupFrame::AdjustSiblingsAfterReflow(nsIPresContext* aPresContext,
nsresult nsTableRowGroupFrame::AdjustSiblingsAfterReflow(nsIPresContext& aPresContext,
RowGroupReflowState& aState,
nsIFrame* aKidFrame,
nscoord aDeltaY)
@ -708,7 +709,7 @@ nsresult nsTableRowGroupFrame::AdjustSiblingsAfterReflow(nsIPresContext* aP
// XXX We need to send move notifications to the frame...
nsIHTMLReflow* htmlReflow;
if (NS_OK == kidFrame->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow)) {
htmlReflow->WillReflow(*aPresContext);
htmlReflow->WillReflow(aPresContext);
}
kidFrame->MoveTo(origin.x, origin.y);
@ -742,6 +743,7 @@ nsTableRowGroupFrame::Reflow(nsIPresContext& aPresContext,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus)
{
nsresult rv=NS_OK;
if (gsDebug==PR_TRUE)
printf("nsTableRowGroupFrame::Reflow - aMaxSize = %d, %d\n",
aReflowState.maxSize.width, aReflowState.maxSize.height);
@ -752,45 +754,10 @@ nsTableRowGroupFrame::Reflow(nsIPresContext& aPresContext,
aDesiredSize.maxElementSize->height = 0;
}
RowGroupReflowState state(&aPresContext, aReflowState);
RowGroupReflowState state(aPresContext, aReflowState);
if (eReflowReason_Incremental == aReflowState.reason) {
nsIFrame* target;
aReflowState.reflowCommand->GetTarget(target);
if (this == target) {
NS_NOTYETIMPLEMENTED("unexpected reflow command");
}
// XXX Recover state
// XXX Deal with the case where the reflow command is targeted at us
nsIFrame* kidFrame;
aReflowState.reflowCommand->GetNext(kidFrame);
// Remember the old rect
nsRect oldKidRect;
kidFrame->GetRect(oldKidRect);
// Pass along the reflow command
// XXX Correctly compute the available space...
nsHTMLReflowState kidReflowState(aPresContext, kidFrame,
aReflowState, aReflowState.maxSize);
nsHTMLReflowMetrics desiredSize(nsnull);
ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState, aStatus);
// Resize the row frame
nsRect kidRect;
kidFrame->GetRect(kidRect);
kidFrame->SizeTo(desiredSize.width, desiredSize.height);
// Adjust the frames that follow...
AdjustSiblingsAfterReflow(&aPresContext, state, kidFrame, desiredSize.height -
oldKidRect.height);
// Return of desired size
aDesiredSize.width = aReflowState.maxSize.width;
aDesiredSize.height = state.y;
rv = IncrementalReflow(aPresContext, aDesiredSize, aReflowState, aStatus);
} else {
PRBool reflowMappedOK = PR_TRUE;
@ -855,10 +822,329 @@ nsTableRowGroupFrame::Reflow(nsIPresContext& aPresContext,
aDesiredSize.width, aDesiredSize.height);
}
return NS_OK;
return rv;
}
NS_METHOD nsTableRowGroupFrame::IncrementalReflow(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus)
{
if (PR_TRUE==gsDebugIR) printf("\nTRGF IR: IncrementalReflow\n");
nsresult rv = NS_OK;
// create an inner table reflow state
RowGroupReflowState state(aPresContext, aReflowState);
// determine if this frame is the target or not
nsIFrame *target=nsnull;
rv = aReflowState.reflowCommand->GetTarget(target);
if ((PR_TRUE==NS_SUCCEEDED(rv)) && (nsnull!=target))
{
if (this==target)
rv = IR_TargetIsMe(aPresContext, aDesiredSize, state, aStatus);
else
{
// Get the next frame in the reflow chain
nsIFrame* nextFrame;
aReflowState.reflowCommand->GetNext(nextFrame);
// Recover our reflow state
//RecoverState(state, nextFrame);
rv = IR_TargetIsChild(aPresContext, aDesiredSize, state, aStatus, nextFrame);
}
}
return rv;
}
NS_METHOD nsTableRowGroupFrame::IR_TargetIsMe(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowGroupReflowState& aReflowState,
nsReflowStatus& aStatus)
{
nsresult rv = NS_FRAME_COMPLETE;
nsIReflowCommand::ReflowType type;
aReflowState.reflowState.reflowCommand->GetType(type);
nsIFrame *objectFrame;
aReflowState.reflowState.reflowCommand->GetChildFrame(objectFrame);
const nsStyleDisplay *childDisplay;
objectFrame->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay));
if (PR_TRUE==gsDebugIR) printf("TRGF IR: IncrementalReflow_TargetIsMe with type=%d\n", type);
switch (type)
{
case nsIReflowCommand::FrameInserted :
if (NS_STYLE_DISPLAY_TABLE_ROW == childDisplay->mDisplay)
{
rv = IR_RowInserted(aPresContext, aDesiredSize, aReflowState, aStatus,
objectFrame, PR_FALSE);
}
else
{
rv = IR_UnknownFrameInserted(aPresContext, aDesiredSize, aReflowState, aStatus,
objectFrame, PR_FALSE);
}
break;
case nsIReflowCommand::FrameAppended :
if (NS_STYLE_DISPLAY_TABLE_ROW == childDisplay->mDisplay)
{
rv = IR_RowAppended(aPresContext, aDesiredSize, aReflowState, aStatus, objectFrame);
}
else
{ // no optimization to be done for Unknown frame types, so just reuse the Inserted method
rv = IR_UnknownFrameInserted(aPresContext, aDesiredSize, aReflowState, aStatus,
objectFrame, PR_FALSE);
}
break;
/*
case nsIReflowCommand::FrameReplaced :
*/
case nsIReflowCommand::FrameRemoved :
if (NS_STYLE_DISPLAY_TABLE_ROW == childDisplay->mDisplay)
{
rv = IR_RowRemoved(aPresContext, aDesiredSize, aReflowState, aStatus,
objectFrame);
}
else
{
rv = IR_UnknownFrameRemoved(aPresContext, aDesiredSize, aReflowState, aStatus,
objectFrame);
}
break;
case nsIReflowCommand::StyleChanged :
NS_NOTYETIMPLEMENTED("unimplemented reflow command type");
rv = NS_ERROR_NOT_IMPLEMENTED;
if (PR_TRUE==gsDebugIR) printf("TRGF IR: StyleChanged not implemented.\n");
break;
case nsIReflowCommand::ContentChanged :
NS_ASSERTION(PR_FALSE, "illegal reflow type: ContentChanged");
rv = NS_ERROR_ILLEGAL_VALUE;
break;
case nsIReflowCommand::PullupReflow:
case nsIReflowCommand::PushReflow:
case nsIReflowCommand::CheckPullupReflow :
case nsIReflowCommand::UserDefined :
NS_NOTYETIMPLEMENTED("unimplemented reflow command type");
rv = NS_ERROR_NOT_IMPLEMENTED;
if (PR_TRUE==gsDebugIR) printf("TRGF IR: reflow command not implemented.\n");
break;
}
return rv;
}
NS_METHOD nsTableRowGroupFrame::IR_RowInserted(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowGroupReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aInsertedFrame,
PRBool aReplace)
{
nsresult rv=NS_OK;
// inserting the rowgroup only effects reflow if the rowgroup includes at least one row
return rv;
}
NS_METHOD nsTableRowGroupFrame::IR_DidAppendRow(nsTableRowFrame *aRowFrame)
{
nsresult rv=NS_OK;
/* need to make space in the cell map. Remeber that row spans can't cross row groups
once the space is made, tell the row to initizalize its children.
it will automatically find the row to initialize into.
but this is tough because a cell in aInsertedFrame could have a rowspan
which must be respected if a subsequent row is appended.
*/
rv = aRowFrame->InitChildren();
return rv;
}
// since we know we're doing an append here, we can optimize
NS_METHOD nsTableRowGroupFrame::IR_RowAppended(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowGroupReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aAppendedFrame)
{
nsresult rv=NS_OK;
// hook aAppendedFrame into the child list
nsIFrame *lastChild = mFirstChild;
nsIFrame *nextChild = lastChild;
nsIFrame *lastRow = nsnull;
while (nsnull!=nextChild)
{
// remember the last child that is really a row
const nsStyleDisplay *childDisplay;
nextChild->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay));
if (NS_STYLE_DISPLAY_TABLE_ROW == childDisplay->mDisplay)
lastRow = nextChild;
lastChild = nextChild;
nextChild->GetNextSibling(nextChild);
}
if (nsnull==lastChild)
mFirstChild = aAppendedFrame;
else
lastChild->SetNextSibling(aAppendedFrame);
nsTableFrame *tableFrame=nsnull;
rv = nsTableFrame::GetTableFrame(this, tableFrame);
if (NS_FAILED(rv) || nsnull==tableFrame)
return rv;
tableFrame->InvalidateFirstPassCache();
// the table will see that it's cached info is bogus and rebuild the cell map,
// and do a reflow
#if 0
// find the row index of the new row
PRInt32 newRowIndex=-1;
if (nsnull!=
lastChild=mFirstChild;
nextChild=lastChild;
while (nsnull!=nextChild)
{
}
// account for the cells in aAppendedFrame
nsresult rv = DidAppendRow((nsTableRowFrame*)aAppendedFrame, newRowIndex);
// need to increment the row index of all subsequent rows
#endif
return rv;
}
NS_METHOD nsTableRowGroupFrame::IR_RowRemoved(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowGroupReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aDeletedFrame)
{
nsresult rv;
return rv;
}
//XXX: handle aReplace
NS_METHOD nsTableRowGroupFrame::IR_UnknownFrameInserted(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowGroupReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aInsertedFrame,
PRBool aReplace)
{
nsIReflowCommand::ReflowType type;
aReflowState.reflowState.reflowCommand->GetType(type);
// we have a generic frame that gets inserted but doesn't effect reflow
// hook it up then ignore it
if (nsIReflowCommand::FrameAppended==type)
{ // frameAppended reflow -- find the last child and make aInsertedFrame its next sibling
if (PR_TRUE==gsDebugIR) printf("TRGF IR: FrameAppended adding unknown frame type.\n");
nsIFrame *lastChild=mFirstChild;
nsIFrame *nextChild=mFirstChild;
while (nsnull!=nextChild)
{
lastChild=nextChild;
nextChild->GetNextSibling(nextChild);
}
if (nsnull==lastChild)
mFirstChild = aInsertedFrame;
else
lastChild->SetNextSibling(aInsertedFrame);
}
else
{ // frameInserted reflow -- hook up aInsertedFrame as prevSibling's next sibling,
// and be sure to hook in aInsertedFrame's nextSibling (from prevSibling)
if (PR_TRUE==gsDebugIR) printf("TRGF IR: FrameInserted adding unknown frame type.\n");
nsIFrame *prevSibling=nsnull;
nsresult rv = aReflowState.reflowState.reflowCommand->GetPrevSiblingFrame(prevSibling);
if (NS_SUCCEEDED(rv) && (nsnull!=prevSibling))
{
nsIFrame *nextSibling=nsnull;
prevSibling->GetNextSibling(nextSibling);
prevSibling->SetNextSibling(aInsertedFrame);
aInsertedFrame->SetNextSibling(nextSibling);
}
else
{
nsIFrame *nextSibling=nsnull;
if (nsnull!=mFirstChild)
mFirstChild->GetNextSibling(nextSibling);
mFirstChild = aInsertedFrame;
aInsertedFrame->SetNextSibling(nextSibling);
}
}
return NS_FRAME_COMPLETE;
}
NS_METHOD nsTableRowGroupFrame::IR_UnknownFrameRemoved(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowGroupReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aRemovedFrame)
{
// we have a generic frame that gets removed but doesn't effect reflow
// unhook it then ignore it
if (PR_TRUE==gsDebugIR) printf("TRGF IR: FrameRemoved removing unknown frame type.\n");
nsIFrame *prevChild=nsnull;
nsIFrame *nextChild=mFirstChild;
while (nextChild!=aRemovedFrame)
{
prevChild=nextChild;
nextChild->GetNextSibling(nextChild);
}
nextChild=nsnull;
aRemovedFrame->GetNextSibling(nextChild);
if (nsnull==prevChild) // objectFrame was first child
mFirstChild = nextChild;
else
prevChild->SetNextSibling(nextChild);
return NS_FRAME_COMPLETE;
}
NS_METHOD nsTableRowGroupFrame::IR_TargetIsChild(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowGroupReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aNextFrame)
{
nsresult rv;
if (PR_TRUE==gsDebugIR) printf("\nTRGF IR: IR_TargetIsChild\n");
// XXX Recover state
// Remember the old rect
nsRect oldKidRect;
aNextFrame->GetRect(oldKidRect);
// Pass along the reflow command
// XXX Correctly compute the available space...
nsHTMLReflowState kidReflowState(aPresContext, aNextFrame, aReflowState.reflowState, aReflowState.reflowState.maxSize);
nsHTMLReflowMetrics desiredSize(nsnull);
rv = ReflowChild(aNextFrame, aPresContext, desiredSize, kidReflowState, aStatus);
// Resize the row frame
nsRect kidRect;
aNextFrame->GetRect(kidRect);
aNextFrame->SizeTo(desiredSize.width, desiredSize.height);
// Adjust the frames that follow...
AdjustSiblingsAfterReflow(aPresContext, aReflowState, aNextFrame, desiredSize.height -
oldKidRect.height);
// Return of desired size
aDesiredSize.width = aReflowState.reflowState.maxSize.width;
aDesiredSize.height = aReflowState.y;
return rv;
}
NS_METHOD
nsTableRowGroupFrame::CreateContinuingFrame(nsIPresContext& aPresContext,
nsIFrame* aParent,

View File

@ -22,6 +22,7 @@
#include "nsContainerFrame.h"
#include "nsIAtom.h"
class nsTableRowFrame;
struct RowGroupReflowState;
/**
@ -79,6 +80,65 @@ public:
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus);
/** Incremental Reflow attempts to do column balancing with the minimum number of reflow
* commands to child elements. This is done by processing the reflow command,
* rebalancing column widths (if necessary), then comparing the resulting column widths
* to the prior column widths and reflowing only those cells that require a reflow.
*
* @see Reflow
*/
NS_IMETHOD IncrementalReflow(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus);
NS_IMETHOD IR_TargetIsChild(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowGroupReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aNextFrame);
NS_IMETHOD IR_TargetIsMe(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowGroupReflowState& aReflowState,
nsReflowStatus& aStatus);
NS_IMETHOD IR_RowInserted(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowGroupReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aInsertedFrame,
PRBool aReplace);
NS_IMETHOD IR_RowAppended(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowGroupReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aAppendedFrame);
NS_IMETHOD IR_DidAppendRow(nsTableRowFrame *aRowFrame);
NS_IMETHOD IR_RowRemoved(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowGroupReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aDeletedFrame);
NS_IMETHOD IR_UnknownFrameInserted(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowGroupReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aInsertedFrame,
PRBool aReplace);
NS_IMETHOD IR_UnknownFrameRemoved(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowGroupReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aDeletedFrame);
/** @see nsContainerFrame::CreateContinuingFrame */
NS_IMETHOD CreateContinuingFrame(nsIPresContext& aPresContext,
nsIFrame* aParent,
@ -111,11 +171,11 @@ protected:
~nsTableRowGroupFrame();
nscoord GetTopMarginFor(nsIPresContext* aCX,
RowGroupReflowState& aState,
RowGroupReflowState& aReflowState,
const nsMargin& aKidMargin);
void PlaceChild( nsIPresContext* aPresContext,
RowGroupReflowState& aState,
RowGroupReflowState& aReflowState,
nsIFrame* aKidFrame,
const nsRect& aKidRect,
nsSize* aMaxElementSize,
@ -124,8 +184,8 @@ protected:
void ShrinkWrapChildren(nsIPresContext* aPresContext,
nsHTMLReflowMetrics& aDesiredSize);
nsresult AdjustSiblingsAfterReflow(nsIPresContext* aPresContext,
RowGroupReflowState& aState,
nsresult AdjustSiblingsAfterReflow(nsIPresContext& aPresContext,
RowGroupReflowState& aReflowState,
nsIFrame* aKidFrame,
nscoord aDeltaY);
@ -133,24 +193,24 @@ protected:
* Reflow the frames we've already created
*
* @param aPresContext presentation context to use
* @param aState current inline state
* @param aReflowState current inline state
* @return true if we successfully reflowed all the mapped children and false
* otherwise, e.g. we pushed children to the next in flow
*/
PRBool ReflowMappedChildren(nsIPresContext* aPresContext,
RowGroupReflowState& aState,
RowGroupReflowState& aReflowState,
nsSize* aMaxElementSize);
/**
* Try and pull-up frames from our next-in-flow
*
* @param aPresContext presentation context to use
* @param aState current inline state
* @param aReflowState current inline state
* @return true if we successfully pulled-up all the children and false
* otherwise, e.g. child didn't fit
*/
PRBool PullUpChildren(nsIPresContext* aPresContext,
RowGroupReflowState& aState,
RowGroupReflowState& aReflowState,
nsSize* aMaxElementSize);
private:

View File

@ -119,6 +119,9 @@ public:
*/
void AppendColumnFrame(nsTableColFrame *aColFrame);
/** empty the column frame cache */
void ClearColumnCache();
/** returns PR_TRUE if the row at aRowIndex has any cells that are the result
* of a row-spanning cell above it. So, given this table:<BR>
* <PRE>
@ -227,5 +230,11 @@ inline void nsCellMap::AppendColumnFrame(nsTableColFrame *aColFrame)
mColFrames->AppendElement(aColFrame);
}
inline void nsCellMap::ClearColumnCache()
{
if (nsnull!=mColFrames)
mColFrames->Clear();
}
#endif

View File

@ -52,8 +52,10 @@ nsresult
nsTableColGroupFrame::InitNewFrames(nsIPresContext& aPresContext, nsIFrame* aChildList)
{
nsresult rv=NS_OK;
nsIFrame* tableFrame=nsnull;
GetGeometricParent(tableFrame);
nsTableFrame* tableFrame=nsnull;
rv = nsTableFrame::GetTableFrame(this, tableFrame);
if ((NS_SUCCEEDED(rv)) && (nsnull!=tableFrame))
{
// Process the newly added column frames
for (nsIFrame* kidFrame = aChildList; nsnull != kidFrame; kidFrame->GetNextSibling(kidFrame)) {
// Set the preliminary values for the column frame
@ -74,7 +76,7 @@ nsTableColGroupFrame::InitNewFrames(nsIPresContext& aPresContext, nsIFrame* aChi
((nsTableColFrame *)(kidFrame))->InitColFrame (colIndex, repeat);
mColCount+= repeat;
((nsTableColFrame *)kidFrame)->SetColumnIndex(colIndex);
((nsTableFrame *)tableFrame)->AddColumnFrame((nsTableColFrame *)kidFrame);
tableFrame->AddColumnFrame((nsTableColFrame *)kidFrame);
}
// colgroup's span attribute is how many columns the group represents
// in the absence of any COL children
@ -107,7 +109,7 @@ nsTableColGroupFrame::InitNewFrames(nsIPresContext& aPresContext, nsIFrame* aChi
PRInt32 absColIndex = mStartColIndex + colIndex;
((nsTableColFrame *)(colFrame))->InitColFrame (absColIndex, 1);
((nsTableColFrame *)colFrame)->SetColumnIndex(absColIndex);
((nsTableFrame *)tableFrame)->AddColumnFrame((nsTableColFrame *)colFrame);
tableFrame->AddColumnFrame((nsTableColFrame *)colFrame);
//hook into list of children
if (nsnull==firstImplicitColFrame)
@ -132,7 +134,7 @@ nsTableColGroupFrame::InitNewFrames(nsIPresContext& aPresContext, nsIFrame* aChi
}
}
SetStyleContextForFirstPass(aPresContext);
}
return rv;
}
@ -233,9 +235,10 @@ NS_METHOD nsTableColGroupFrame::Reflow(nsIPresContext& aPresContext,
NS_METHOD nsTableColGroupFrame::SetStyleContextForFirstPass(nsIPresContext& aPresContext)
{
// get the table frame
nsIFrame* tableFrame=nsnull;
GetGeometricParent(tableFrame);
nsTableFrame* tableFrame=nsnull;
nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame);
if ((NS_SUCCEEDED(rv)) && (nsnull!=tableFrame))
{
// get the style for the table frame
nsStyleTable *tableStyle;
tableFrame->GetStyleData(eStyleStruct_Table, (nsStyleStruct *&)tableStyle);
@ -277,10 +280,10 @@ NS_METHOD nsTableColGroupFrame::SetStyleContextForFirstPass(nsIPresContext& aPre
}
colFrame->GetNextSibling(colFrame);
}
mStyleContext->RecalcAutomaticData(&aPresContext);
}
return NS_OK;
}
return rv;
}

View File

@ -270,6 +270,7 @@ nsTableFrame::nsTableFrame(nsIContent* aContent, nsIFrame* aParentFrame)
mColCache(nsnull),
mTableLayoutStrategy(nsnull),
mFirstPassValid(PR_FALSE),
mCellMapValid(PR_TRUE),
mIsInvariantWidth(PR_FALSE)
{
mEffectiveColCount = -1; // -1 means uninitialized
@ -298,10 +299,43 @@ nsTableFrame::~nsTableFrame()
NS_IMETHODIMP
nsTableFrame::Init(nsIPresContext& aPresContext, nsIFrame* aChildList)
{
nsresult rv=NS_OK;
mFirstChild = aChildList;
EnsureColumns(aPresContext);
return NS_OK;
// I know now that I have all my children, so build the cell map
nsIFrame *nextRowGroup=mFirstChild;
for ( ; nsnull!=nextRowGroup; nextRowGroup->GetNextSibling(nextRowGroup))
{
const nsStyleDisplay *rowGroupDisplay;
nextRowGroup->GetStyleData(eStyleStruct_Display, (nsStyleStruct *&)rowGroupDisplay);
if (PR_TRUE==IsRowGroup(rowGroupDisplay->mDisplay))
{
rv = DidAppendRowGroup((nsTableRowGroupFrame*)nextRowGroup);
}
}
if (NS_SUCCEEDED(rv))
EnsureColumns(aPresContext);
return rv;
}
NS_IMETHODIMP nsTableFrame::DidAppendRowGroup(nsTableRowGroupFrame *aRowGroupFrame)
{
nsresult rv=NS_OK;
nsIFrame *nextRow=nsnull;
aRowGroupFrame->FirstChild(nextRow);
for ( ; nsnull!=nextRow; nextRow->GetNextSibling(nextRow))
{
const nsStyleDisplay *rowDisplay;
nextRow->GetStyleData(eStyleStruct_Display, (nsStyleStruct *&)rowDisplay);
if (NS_STYLE_DISPLAY_TABLE_ROW==rowDisplay->mDisplay)
{
rv = ((nsTableRowFrame *)nextRow)->InitChildren();
if (NS_FAILED(rv))
return rv;
}
}
return rv;
}
/* ****** CellMap methods ******* */
@ -322,14 +356,12 @@ nsTableRowGroupFrame* nsTableFrame::NextRowGroupFrame(nsTableRowGroupFrame* aRow
const nsStyleDisplay *display;
aRowGroupFrame->GetStyleData(eStyleStruct_Display, (nsStyleStruct *&)display);
if (PR_TRUE==IsRowGroup(display->mDisplay))
{ //XXX: assumes content order
{
break;
}
// Get the next frame
aRowGroupFrame->GetNextSibling((nsIFrame*&)aRowGroupFrame);
}
return aRowGroupFrame;
}
@ -346,10 +378,6 @@ PRInt32 nsTableFrame::GetSpecifiedColumnCount ()
{
mColCount += ((nsTableColGroupFrame *)childFrame)->GetColumnCount();
}
else if (PR_TRUE==IsRowGroup(childDisplay->mDisplay))
{ //XXX: assumes content order
break;
}
childFrame->GetNextSibling(childFrame);
}
return mColCount;
@ -358,24 +386,10 @@ PRInt32 nsTableFrame::GetSpecifiedColumnCount ()
PRInt32 nsTableFrame::GetRowCount ()
{
PRInt32 rowCount = 0;
nsCellMap *cellMap = GetCellMap();
NS_ASSERTION(nsnull!=cellMap, "GetRowCount null cellmap");
if (nsnull!=cellMap)
return cellMap->GetRowCount();
nsIFrame *child=mFirstChild;
while (nsnull!=child)
{
const nsStyleDisplay *childDisplay;
child->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay));
if (PR_TRUE==IsRowGroup(childDisplay->mDisplay))
{
PRInt32 thisRowCount=0;
((nsTableRowGroupFrame *)child)->GetRowCount(thisRowCount);
rowCount += thisRowCount;
}
child->GetNextSibling(child);
}
rowCount = cellMap->GetRowCount();
return rowCount;
}
@ -383,7 +397,7 @@ PRInt32 nsTableFrame::GetRowCount ()
PRInt32 nsTableFrame::GetColCount ()
{
nsCellMap *cellMap = GetCellMap();
NS_ASSERTION(nsnull!=cellMap, "GetColCount can only be called after cellmap has been created");
NS_ASSERTION(nsnull!=cellMap, "GetColCount null cellmap");
if (nsnull!=cellMap)
{
@ -396,6 +410,7 @@ PRInt32 nsTableFrame::GetColCount ()
void nsTableFrame::SetEffectiveColCount()
{
nsCellMap *cellMap = GetCellMap();
NS_ASSERTION(nsnull!=cellMap, "SetEffectiveColCount null cellmap");
if (nsnull!=cellMap)
{
PRInt32 colCount = cellMap->GetColCount();
@ -589,7 +604,7 @@ NS_ASSERTION(0<result, "bad effective col span");
PRInt32 nsTableFrame::GetEffectiveCOLSAttribute()
{
nsCellMap *cellMap = GetCellMap();
NS_PRECONDITION (nsnull!=cellMap, "bad call, cellMap not yet allocated.");
NS_PRECONDITION (nsnull!=cellMap, "null cellMap.");
PRInt32 result;
nsIFrame *tableFrame = this;
nsStyleTable *tableStyle=nsnull;
@ -601,16 +616,6 @@ PRInt32 nsTableFrame::GetEffectiveCOLSAttribute()
return result;
}
/* call when the cell structure has changed. mCellMap will be rebuilt on demand. */
void nsTableFrame::ResetCellMap ()
{
// XXX: SEC should this call ResetCellMap on firstInFlow?
if (nsnull!=mCellMap)
delete mCellMap;
mCellMap = nsnull; // for now, will rebuild when needed
}
/** 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.
@ -632,7 +637,7 @@ void nsTableFrame::EnsureColumns(nsIPresContext& aPresContext)
PRInt32 actualColumns = 0;
nsTableColGroupFrame *lastColGroupFrame = nsnull;
nsIFrame * firstRowGroupFrame=nsnull;
nsIFrame * prevSibFrame=nsnull;
nsIFrame * prevSibFrame=nsnull; // this is the child just before the first row group frame
nsIFrame * childFrame=mFirstChild;
while (nsnull!=childFrame)
{
@ -646,11 +651,14 @@ void nsTableFrame::EnsureColumns(nsIPresContext& aPresContext)
if (PR_TRUE==gsDebug) printf("EC: found a col group %p\n", lastColGroupFrame);
}
else if (PR_TRUE==IsRowGroup(childDisplay->mDisplay))
{ // XXX: assumes content order
{
if (nsnull==firstRowGroupFrame)
{
firstRowGroupFrame = childFrame;
if (PR_TRUE==gsDebug) printf("EC: found a row group %p\n", firstRowGroupFrame);
break;
}
}
if (nsnull==firstRowGroupFrame)
prevSibFrame = childFrame;
childFrame->GetNextSibling(childFrame);
}
@ -666,7 +674,7 @@ void nsTableFrame::EnsureColumns(nsIPresContext& aPresContext)
nsAutoString colGroupTag;
nsHTMLAtoms::colgroup->ToString(colGroupTag);
rv = NS_CreateHTMLElement(&lastColGroup, colGroupTag); // ADDREF a: lastColGroup++
//XXX mark it as implicit!
//XXX: make synthetic
mContent->AppendChildTo(lastColGroup, PR_FALSE); // add the implicit colgroup to my content
// Resolve style for the child
nsIStyleContext* colGroupStyleContext =
@ -716,7 +724,7 @@ void nsTableFrame::EnsureColumns(nsIPresContext& aPresContext)
nsIHTMLContent *col=nsnull;
// create an implicit col
rv = NS_CreateHTMLElement(&col, colTag); // ADDREF: col++
//XXX mark the col implicit
//XXX: make synthetic
lastColGroup->AppendChildTo((nsIContent*)col, PR_FALSE);
// Create a new col frame
@ -759,7 +767,7 @@ void nsTableFrame::EnsureColumnFrameAt(PRInt32 aColIndex,
PRInt32 actualColumns = 0;
nsTableColGroupFrame *lastColGroupFrame = nsnull;
nsIFrame * firstRowGroupFrame=nsnull;
nsIFrame * prevSibFrame=nsnull;
nsIFrame * prevSibFrame=nsnull; // this is the child just before the first row group frame
nsIFrame * childFrame=mFirstChild;
while (nsnull!=childFrame)
{
@ -774,10 +782,11 @@ void nsTableFrame::EnsureColumnFrameAt(PRInt32 aColIndex,
break; // we have enough col frames at this point
}
else if (PR_TRUE==IsRowGroup(childDisplay->mDisplay))
{ // XXX: assumes content order
{
if (nsnull==firstRowGroupFrame)
firstRowGroupFrame = childFrame;
break;
}
if (nsnull==firstRowGroupFrame)
prevSibFrame = childFrame;
childFrame->GetNextSibling(childFrame);
}
@ -790,6 +799,7 @@ void nsTableFrame::EnsureColumnFrameAt(PRInt32 aColIndex,
nsAutoString colGroupTag;
nsHTMLAtoms::colgroup->ToString(colGroupTag);
rv = NS_CreateHTMLElement(&lastColGroup, colGroupTag); // ADDREF a: lastColGroup++
//XXX: make synthetic
//XXX mark it as implicit!
mContent->AppendChildTo(lastColGroup, PR_FALSE); // add the implicit colgroup to my content
// Resolve style for the child
@ -837,7 +847,7 @@ void nsTableFrame::EnsureColumnFrameAt(PRInt32 aColIndex,
nsIHTMLContent *col=nsnull;
// create an implicit col
rv = NS_CreateHTMLElement(&col, colTag); // ADDREF: col++
//XXX mark the col implicit
//XXX: make synthetic
lastColGroup->AppendChildTo((nsIContent*)col, PR_FALSE);
// Create a new col frame
@ -868,17 +878,22 @@ void nsTableFrame::EnsureColumnFrameAt(PRInt32 aColIndex,
void nsTableFrame::AddColumnFrame (nsTableColFrame *aColFrame)
{
mCellMap->AppendColumnFrame(aColFrame);
nsCellMap *cellMap = GetCellMap();
NS_PRECONDITION (nsnull!=cellMap, "null cellMap.");
if (nsnull!=cellMap)
cellMap->AppendColumnFrame(aColFrame);
}
/** return the index of the next row that is not yet assigned */
PRInt32 nsTableFrame::GetNextAvailRowIndex() const
{
PRInt32 result=0;
if (nsnull!=mCellMap)
nsCellMap *cellMap = GetCellMap();
NS_PRECONDITION (nsnull!=cellMap, "null cellMap.");
if (nsnull!=cellMap)
{
result = mCellMap->GetRowCount(); // the next index is the current count
mCellMap->GrowToRow(result+1); // expand the cell map to include this new row
result = cellMap->GetRowCount(); // the next index is the current count
cellMap->GrowToRow(result+1); // expand the cell map to include this new row
}
return result;
}
@ -887,15 +902,17 @@ PRInt32 nsTableFrame::GetNextAvailRowIndex() const
PRInt32 nsTableFrame::GetNextAvailColIndex(PRInt32 aRowIndex, PRInt32 aColIndex) const
{
PRInt32 result=0;
if (nsnull!=mCellMap)
result = mCellMap->GetNextAvailColIndex(aRowIndex, aColIndex);
nsCellMap *cellMap = GetCellMap();
NS_PRECONDITION (nsnull!=cellMap, "null cellMap.");
if (nsnull!=cellMap)
result = cellMap->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
*/
nsCellMap * nsTableFrame::GetCellMap()
nsCellMap * nsTableFrame::GetCellMap() const
{
nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();
if (this!=firstInFlow)
@ -951,7 +968,6 @@ void nsTableFrame::AddCellToTable (nsTableRowFrame *aRowFrame,
}
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
@ -979,6 +995,34 @@ void nsTableFrame::AddCellToTable (nsTableRowFrame *aRowFrame,
DumpCellMap ();
}
NS_METHOD nsTableFrame::ReBuildCellMap()
{
nsresult rv=NS_OK;
nsIFrame *rowGroupFrame=mFirstChild;
for ( ; nsnull!=rowGroupFrame; rowGroupFrame->GetNextSibling(rowGroupFrame))
{
const nsStyleDisplay *rowGroupDisplay;
rowGroupFrame->GetStyleData(eStyleStruct_Display, (nsStyleStruct *&)rowGroupDisplay);
if (PR_TRUE==IsRowGroup(rowGroupDisplay->mDisplay))
{
nsIFrame *rowFrame;
rowGroupFrame->FirstChild(rowFrame);
for ( ; nsnull!=rowFrame; rowFrame->GetNextSibling(rowFrame))
{
const nsStyleDisplay *rowDisplay;
rowFrame->GetStyleData(eStyleStruct_Display, (nsStyleStruct *&)rowDisplay);
if (NS_STYLE_DISPLAY_TABLE_ROW==rowDisplay->mDisplay)
{
rv = ((nsTableRowFrame *)rowFrame)->InitChildren();
if (NS_FAILED(rv))
return rv;
}
}
}
}
return rv;
}
/**
*/
void nsTableFrame::DumpCellMap ()
@ -1054,20 +1098,20 @@ void nsTableFrame::BuildCellIntoMap (nsTableCellFrame *aCell, PRInt32 aRowIndex,
// Setup CellMap for this cell
int rowSpan = aCell->GetRowSpan();
int colSpan = aCell->GetColSpan();
if (gsDebug==PR_TRUE) printf(" BuildCellIntoMap. rowSpan = %d, colSpan = %d\n", rowSpan, colSpan);
if (gsDebug==PR_TRUE) printf("BCIM: rowSpan = %d, colSpan = %d\n", rowSpan, colSpan);
// Grow the mCellMap array if we will end up addressing
// some new columns.
if (mCellMap->GetColCount() < (aColIndex + colSpan))
{
if (gsDebug==PR_TRUE)
printf(" calling GrowCellMap(%d)\n", aColIndex+colSpan);
printf("BCIM: calling GrowCellMap(%d)\n", aColIndex+colSpan);
GrowCellMap (aColIndex + colSpan);
}
if (mCellMap->GetRowCount() < (aRowIndex+1))
{
printf("*********************************************** calling GrowToRow(%d)\n", aRowIndex+1);
printf("BCIM: calling GrowToRow(%d)\n", aRowIndex+1);
mCellMap->GrowToRow(aRowIndex+1);
}
@ -1075,7 +1119,7 @@ void nsTableFrame::BuildCellIntoMap (nsTableCellFrame *aCell, PRInt32 aRowIndex,
CellData *data = new CellData ();
data->mCell = aCell;
data->mRealCell = data;
if (gsDebug==PR_TRUE) printf(" calling mCellMap->SetCellAt(data, %d, %d)\n", aRowIndex, aColIndex);
if (gsDebug==PR_TRUE) printf("BCIM: calling mCellMap->SetCellAt(data, %d, %d)\n", aRowIndex, aColIndex);
mCellMap->SetCellAt(data, aRowIndex, aColIndex);
// Create CellData objects for the rows that this cell spans. Set
@ -1084,28 +1128,28 @@ void nsTableFrame::BuildCellIntoMap (nsTableCellFrame *aCell, PRInt32 aRowIndex,
// CellData object for each row that we span...
if ((1 < rowSpan) || (1 < colSpan))
{
if (gsDebug==PR_TRUE) printf(" spans\n");
if (gsDebug==PR_TRUE) printf("BCIM: spans\n");
for (int rowIndex = 0; rowIndex < rowSpan; rowIndex++)
{
if (gsDebug==PR_TRUE) printf(" rowIndex = %d\n", rowIndex);
if (gsDebug==PR_TRUE) printf("BCIM: rowIndex = %d\n", rowIndex);
int workRow = aRowIndex + rowIndex;
if (gsDebug==PR_TRUE) printf(" workRow = %d\n", workRow);
if (gsDebug==PR_TRUE) printf("BCIM: workRow = %d\n", workRow);
for (int colIndex = 0; colIndex < colSpan; colIndex++)
{
if (gsDebug==PR_TRUE) printf(" colIndex = %d\n", colIndex);
if (gsDebug==PR_TRUE) printf("BCIM: colIndex = %d\n", colIndex);
int workCol = aColIndex + colIndex;
if (gsDebug==PR_TRUE) printf(" workCol = %d\n", workCol);
if (gsDebug==PR_TRUE) printf("BCIM: workCol = %d\n", workCol);
CellData *testData = mCellMap->GetCellAt(workRow, workCol);
if (nsnull == testData)
{
CellData *spanData = new CellData ();
spanData->mRealCell = data;
if (gsDebug==PR_TRUE) printf(" null GetCellFrameAt(%d, %d) so setting to spanData\n", workRow, workCol);
if (gsDebug==PR_TRUE) printf("BCIM: null GetCellFrameAt(%d, %d) so setting to spanData\n", workRow, workCol);
mCellMap->SetCellAt(spanData, workRow, workCol);
}
else if ((0 < rowIndex) || (0 < colIndex))
{ // we overlap, replace existing data, it might be shared
if (gsDebug==PR_TRUE) printf(" overlapping Cell from GetCellFrameAt(%d, %d) so setting to spanData\n", workRow, workCol);
if (gsDebug==PR_TRUE) printf("BCIM: overlapping Cell from GetCellFrameAt(%d, %d) so setting to spanData\n", workRow, workCol);
CellData *overlap = new CellData ();
overlap->mCell = testData->mCell;
overlap->mRealCell = testData->mRealCell;
@ -1414,12 +1458,15 @@ NS_METHOD nsTableFrame::Paint(nsIPresContext& aPresContext,
return NS_OK;
}
PRBool nsTableFrame::NeedsReflow(const nsSize& aMaxSize)
PRBool nsTableFrame::NeedsReflow(const nsHTMLReflowState& aReflowState, const nsSize& aMaxSize)
{
PRBool result = PR_TRUE;
if (eReflowReason_Incremental != aReflowState.reason)
{ // incremental reflows always need to be reflowed (for now)
if (PR_TRUE==mIsInvariantWidth)
result = PR_FALSE;
// TODO: other cases...
// XXX TODO: other optimization cases...
}
return result;
}
@ -1509,20 +1556,44 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext& aPresContext,
rv = IncrementalReflow(aPresContext, aDesiredSize, aReflowState, aStatus);
}
if (PR_TRUE==NeedsReflow(aReflowState.maxSize))
// NeedsReflow and IsFirstPassValid take into account reflow type = Initial_Reflow
if (PR_TRUE==NeedsReflow(aReflowState, aReflowState.maxSize))
{
PRBool needsRecalc=PR_FALSE;
if (PR_TRUE==gsDebug) printf("TF Reflow: needs reflow\n");
if (eReflowReason_Initial!=aReflowState.reason && PR_FALSE==IsCellMapValid())
{
if (PR_TRUE==gsDebug) printf("TF Reflow: not initial reflow, so resetting cell map.\n");
if (nsnull!=mCellMap)
delete mCellMap;
mCellMap = new nsCellMap(0,0);
ReBuildCellMap();
needsRecalc=PR_TRUE;
}
if (PR_FALSE==IsFirstPassValid())
{
// XXX TROY: we used to rebuild the cellmap here for incremental reflow.
// now that the cellmap is built in the constructor
// we need to reset the cellmap during incremental reflow before we get here
if (PR_TRUE==gsDebug || PR_TRUE==gsDebugIR) printf("TF Reflow: first pass is invalid\n");
rv = ResizeReflowPass1(aPresContext, aDesiredSize, aReflowState, aStatus);
if (NS_FAILED(rv))
return rv;
needsRecalc=PR_TRUE;
}
if (PR_TRUE==needsRecalc)
{
if (PR_TRUE==gsDebugIR) printf("TF Reflow: needs recalc.\n");
// if we need to recalc, the data stored in the layout strategy is invalid
if (nsnull!=mTableLayoutStrategy)
{
if (PR_TRUE==gsDebugIR) printf("TF Reflow: Re-init layout strategy\n");
mTableLayoutStrategy->Initialize(aDesiredSize.maxElementSize);
}
BuildColumnCache(aPresContext, aDesiredSize, aReflowState, aStatus);
RecalcLayoutData(); // Recalculate Layout Dependencies
}
if (nsnull==mPrevInFlow)
{
{ // only do this for a first-in-flow table frame
// assign column widths, and assign aMaxElementSize->width
BalanceColumnWidths(aPresContext, aReflowState, aReflowState.maxSize,
aDesiredSize.maxElementSize);
@ -1656,10 +1727,6 @@ NS_METHOD nsTableFrame::ResizeReflowPass1(nsIPresContext& aPresContext,
}
}
BuildColumnCache(aPresContext, aDesiredSize, aReflowState, aStatus);
// Recalculate Layout Dependencies
RecalcLayoutData();
aDesiredSize.width = kidSize.width;
mFirstPassValid = PR_TRUE;
@ -1756,6 +1823,7 @@ NS_METHOD nsTableFrame::ResizeReflowPass2(nsIPresContext& aPresContext,
return rv;
}
NS_METHOD nsTableFrame::IncrementalReflow(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
@ -1776,7 +1844,10 @@ NS_METHOD nsTableFrame::IncrementalReflow(nsIPresContext& aPresContext,
rv = aReflowState.reflowCommand->GetTarget(target);
if ((PR_TRUE==NS_SUCCEEDED(rv)) && (nsnull!=target))
{
if (this==target)
// this is the target if target is either this or the outer table frame containing this inner frame
nsIFrame *outerTableFrame=nsnull;
GetGeometricParent(outerTableFrame);
if ((this==target) || (outerTableFrame==target))
rv = IR_TargetIsMe(aPresContext, aDesiredSize, state, aStatus);
else
{
@ -1802,14 +1873,12 @@ NS_METHOD nsTableFrame::IR_TargetIsMe(nsIPresContext& aPresContext,
aReflowState.reflowState.reflowCommand->GetType(type);
nsIFrame *objectFrame;
aReflowState.reflowState.reflowCommand->GetChildFrame(objectFrame);
const nsStyleDisplay *childDisplay;
objectFrame->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay));
if (PR_TRUE==gsDebugIR) printf("TIF IR: IncrementalReflow_TargetIsMe with type=%d\n", type);
switch (type)
{
case nsIReflowCommand::FrameAppended :
case nsIReflowCommand::FrameInserted :
{
const nsStyleDisplay *childDisplay;
objectFrame->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay));
if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == childDisplay->mDisplay)
{
rv = IR_ColGroupInserted(aPresContext, aDesiredSize, aReflowState, aStatus,
@ -1826,7 +1895,22 @@ NS_METHOD nsTableFrame::IR_TargetIsMe(nsIPresContext& aPresContext,
objectFrame, PR_FALSE);
}
break;
case nsIReflowCommand::FrameAppended :
if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == childDisplay->mDisplay)
{
rv = IR_ColGroupAppended(aPresContext, aDesiredSize, aReflowState, aStatus, objectFrame);
}
else if (IsRowGroup(childDisplay->mDisplay))
{
rv = IR_RowGroupAppended(aPresContext, aDesiredSize, aReflowState, aStatus, objectFrame);
}
else
{ // no optimization to be done for Unknown frame types, so just reuse the Inserted method
rv = IR_UnknownFrameInserted(aPresContext, aDesiredSize, aReflowState, aStatus,
objectFrame, PR_FALSE);
}
break;
/*
case nsIReflowCommand::FrameReplaced :
@ -1834,9 +1918,6 @@ NS_METHOD nsTableFrame::IR_TargetIsMe(nsIPresContext& aPresContext,
*/
case nsIReflowCommand::FrameRemoved :
{
const nsStyleDisplay *childDisplay;
objectFrame->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay));
if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == childDisplay->mDisplay)
{
rv = IR_ColGroupRemoved(aPresContext, aDesiredSize, aReflowState, aStatus,
@ -1854,7 +1935,6 @@ NS_METHOD nsTableFrame::IR_TargetIsMe(nsIPresContext& aPresContext,
objectFrame);
}
break;
}
case nsIReflowCommand::StyleChanged :
NS_NOTYETIMPLEMENTED("unimplemented reflow command type");
@ -1898,6 +1978,80 @@ NS_METHOD nsTableFrame::IR_ColGroupInserted(nsIPresContext& aPresContext,
return rv;
}
NS_METHOD nsTableFrame::IR_ColGroupAppended(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aAppendedFrame)
{
nsresult rv=NS_OK;
/*
find where to place colgroup (skipping implicit children?)
for every col in the colgroup (including implicit cols due to span attribute)
an implicit col from the first implicit colgroup is removed
when an implicit colgroups col count goes to 0, it is removed
*/
/* need to really verify that issynthetic is specified on implicit colgroups and cols */
// build a vector of colgroups. XXX might want to do this as a class thing, so we don't have to rebuild it each time
nsVoidArray colGroupList;
nsIFrame *childFrame=mFirstChild;
nsIFrame *lastChild=mFirstChild;
while ((NS_SUCCEEDED(rv)) && (nsnull!=childFrame))
{
const nsStyleDisplay *display;
childFrame->GetStyleData(eStyleStruct_Display, (nsStyleStruct *&)display);
if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == display->mDisplay)
{
colGroupList.AppendElement((void*)childFrame);
}
lastChild=childFrame;
rv = childFrame->GetNextSibling(childFrame);
}
// append aAppendedFrame
if (nsnull!=lastChild)
lastChild->SetNextSibling(aAppendedFrame);
else
mFirstChild = aAppendedFrame;
/* go through the list of colgroups, sucking out implicit columns that are not the result of a span attribute
* and replacing them with columns in aAppendedFrame
* if the column had an attribute from a cell, be sure to preserve that
* if any implicit colgroup becomes empty, destroy it
* if any real colgroup becomes empty, we have to keep it
* factor the new cols into the column cache
* this means having a flag that says whether the col cache needs to be rebuilt or not
*/
PRInt32 colGroupCount = colGroupList.Count();
if (0<colGroupCount)
{
aAppendedFrame->FirstChild(childFrame);
while ((NS_SUCCEEDED(rv)) && (nsnull!=childFrame))
{
const nsStyleDisplay *colDisplay;
childFrame->GetStyleData(eStyleStruct_Display, (nsStyleStruct *&)colDisplay);
if (NS_STYLE_DISPLAY_TABLE_COLUMN == colDisplay->mDisplay)
{ // find an implicit column that is not from a span attribute if there is one and remove it
for (PRInt32 colGroupIndex=0; colGroupIndex<colGroupCount; colGroupIndex++)
{
nsTableColGroupFrame *colGroup = (nsTableColGroupFrame *)(colGroupList.ElementAt(colGroupIndex));
// XXX: here's where we yank colGroups if necessary
}
}
}
}
//InvalidateFirstPassCache(); // for now, redo the first pass reflow
// could probably just get away with mTableLayoutStrategy->Initialize(aMaxElementSize);
mTableLayoutStrategy->Initialize(aDesiredSize.maxElementSize);
//XXX: what we want to do here is determine if the new COL information changes anything about layout
// if not, skip invalidating the first passs
// if so, and we can fix the first pass info
return rv;
}
NS_METHOD nsTableFrame::IR_ColGroupRemoved(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
@ -1921,6 +2075,39 @@ NS_METHOD nsTableFrame::IR_RowGroupInserted(nsIPresContext& aPresContext,
PRBool aReplace)
{
nsresult rv;
// inserting the rowgroup only effects reflow if the rowgroup includes at least one row
return rv;
}
// since we know we're doing an append here, we can optimize
NS_METHOD nsTableFrame::IR_RowGroupAppended(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aAppendedFrame)
{
// hook aAppendedFrame into the child list
nsIFrame *lastChild = mFirstChild;
nsIFrame *nextChild = lastChild;
while (nsnull!=nextChild)
{
lastChild = nextChild;
nextChild->GetNextSibling(nextChild);
}
if (nsnull==lastChild)
mFirstChild = aAppendedFrame;
else
lastChild->SetNextSibling(aAppendedFrame);
// account for the cells in the rows that are children of aAppendedFrame
nsresult rv = DidAppendRowGroup((nsTableRowGroupFrame*)aAppendedFrame);
// do a pass-1 layout of all the cells in all the rows of the rowgroup
InvalidateFirstPassCache();
// if any column widths have to change due to this, re-init the layout strategy
// mTableLayoutStrategy->Initialize(aDesiredSize.aMaxElementSize); //XXX for now, we're just doing the whole enchelada
return rv;
}
@ -2032,7 +2219,7 @@ NS_METHOD nsTableFrame::IR_TargetIsChild(nsIPresContext& aPresContext,
aReflowState.reflowState,
aReflowState.reflowState.maxSize);
ReflowChild(aNextFrame, aPresContext, desiredSize, kidReflowState, aStatus);
rv = ReflowChild(aNextFrame, aPresContext, desiredSize, kidReflowState, aStatus);
// Resize the row group frame
nsRect kidRect;
@ -2160,8 +2347,6 @@ void nsTableFrame::PlaceChild(nsIPresContext& aPresContext,
{
nsMargin borderPadding;
const nsStyleSpacing* tableSpacing;
// begin REMOVE_ME_WHEN_TABLE_STYLE_IS_RESOLVED!
nsIFrame * parent = nsnull;
GetStyleData(eStyleStruct_Spacing , ((nsStyleStruct *&)tableSpacing));
tableSpacing->CalcBorderPaddingFor(this, borderPadding);
nscoord cellSpacing = GetCellSpacing();
@ -2753,13 +2938,18 @@ 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==mPrevInFlow, "never ever call me on a continuing frame!");
NS_ASSERTION(nsnull!=mCellMap, "never ever call me until the cell map is built!");
nsStyleTable* tableStyle;
GetStyleData(eStyleStruct_Table, (nsStyleStruct *&)tableStyle);
EnsureColumns(aPresContext);
if (nsnull==mColCache)
if (nsnull!=mColCache)
{
if (PR_TRUE==gsDebugIR) printf("TIF BCB: clearing column cache and cell map column frame cache.\n");
mCellMap->ClearColumnCache();
delete mColCache;
}
mColCache = new ColumnInfoCache(mColCount);
nsIFrame * childFrame = mFirstChild;
while (nsnull!=childFrame)
@ -2836,14 +3026,9 @@ void nsTableFrame::BuildColumnCache( nsIPresContext& aPresContext,
colFrame->GetNextSibling((nsIFrame *&)colFrame);
}
}
else if (PR_TRUE==IsRowGroup(childDisplay->mDisplay))
{ // XXX: assumes content order
break; // once we hit a row group, we're done
}
childFrame->GetNextSibling(childFrame);
}
}
}
PRBool nsTableFrame::IsFirstPassValid() const
{
@ -2852,6 +3037,48 @@ PRBool nsTableFrame::IsFirstPassValid() const
return firstInFlow->mFirstPassValid;
}
void nsTableFrame::InvalidateFirstPassCache()
{
nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();
NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow");
firstInFlow->mFirstPassValid=PR_FALSE;
}
PRBool nsTableFrame::IsCellMapValid() const
{
nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();
NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow");
return firstInFlow->mCellMapValid;
}
void nsTableFrame::InvalidateCellMap()
{
nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();
NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow");
firstInFlow->mCellMapValid=PR_FALSE;
// reset the state in each row
nsIFrame *rowGroupFrame=mFirstChild;
for ( ; nsnull!=rowGroupFrame; rowGroupFrame->GetNextSibling(rowGroupFrame))
{
const nsStyleDisplay *rowGroupDisplay;
rowGroupFrame->GetStyleData(eStyleStruct_Display, (nsStyleStruct *&)rowGroupDisplay);
if (PR_TRUE==IsRowGroup(rowGroupDisplay->mDisplay))
{
nsIFrame *rowFrame;
rowGroupFrame->FirstChild(rowFrame);
for ( ; nsnull!=rowFrame; rowFrame->GetNextSibling(rowFrame))
{
const nsStyleDisplay *rowDisplay;
rowFrame->GetStyleData(eStyleStruct_Display, (nsStyleStruct *&)rowDisplay);
if (NS_STYLE_DISPLAY_TABLE_ROW==rowDisplay->mDisplay)
{
((nsTableRowFrame *)rowFrame)->ResetInitChildren();
}
}
}
}
}
NS_METHOD
nsTableFrame::CreateContinuingFrame(nsIPresContext& aPresContext,
nsIFrame* aParent,
@ -3148,25 +3375,44 @@ NS_NewTableFrame(nsIContent* aContent,
return NS_OK;
}
NS_METHOD nsTableFrame::GetTableFrame(nsIFrame *aSourceFrame, nsTableFrame *& aOutFrame)
NS_METHOD nsTableFrame::GetTableFrame(nsIFrame *aSourceFrame, nsTableFrame *& aTableFrame)
{
nsresult result = NS_OK;
aOutFrame = nsnull; // initialize out-param
aTableFrame = nsnull; // initialize out-param
if (nsnull!=aSourceFrame)
{
nsresult result = aSourceFrame->GetContentParent((nsIFrame *&)aOutFrame);
while ((NS_OK==result) && (nsnull!=aOutFrame))
nsresult result = aSourceFrame->GetContentParent((nsIFrame *&)aTableFrame);
while ((NS_OK==result) && (nsnull!=aTableFrame))
{
const nsStyleDisplay *display;
aOutFrame->GetStyleData(eStyleStruct_Display, (nsStyleStruct *&)display);
aTableFrame->GetStyleData(eStyleStruct_Display, (nsStyleStruct *&)display);
if (NS_STYLE_DISPLAY_TABLE == display->mDisplay)
{
// at this point, aTableFrame could be an outer frame,
// to find out, scan it's children for another frame with a table display type
// if found, the childFrame must be the inner frame
nsresult rv;
nsIFrame *childFrame=nsnull;
rv = aTableFrame->FirstChild(childFrame);
while ((NS_OK==rv) && (nsnull!=childFrame))
{
const nsStyleDisplay *childDisplay;
childFrame->GetStyleData(eStyleStruct_Display, (nsStyleStruct *&)childDisplay);
if (NS_STYLE_DISPLAY_TABLE == childDisplay->mDisplay)
{
aTableFrame = (nsTableFrame *)childFrame;
break;
result = aOutFrame->GetContentParent((nsIFrame *&)aOutFrame);
}
rv = childFrame->GetNextSibling(childFrame);
}
break;
}
result = aTableFrame->GetContentParent((nsIFrame *&)aTableFrame);
}
}
else
result = NS_ERROR_UNEXPECTED; // bad source param
NS_POSTCONDITION(nsnull!=aOutFrame, "unable to find table parent. aOutFrame null.");
NS_POSTCONDITION(nsnull!=aTableFrame, "unable to find table parent. aTableFrame null.");
NS_POSTCONDITION(NS_OK==result, "unable to find table parent. result!=NS_OK");
return result;
}

View File

@ -79,7 +79,7 @@ public:
PRBool IsNested(const nsHTMLReflowState& aReflowState, nsStylePosition *& aPosition) const;
/** helper method to find the table parent of any table frame object */
static NS_METHOD GetTableFrame(nsIFrame *aSourceFrame, nsTableFrame *& aOutFrame);
static NS_METHOD GetTableFrame(nsIFrame *aSourceFrame, nsTableFrame *& aTableFrame);
/** helper method for getting the width of the table's containing block */
static nscoord GetTableContainerWidth(const nsHTMLReflowState& aState);
@ -97,6 +97,11 @@ public:
NS_IMETHOD Init(nsIPresContext& aPresContext, nsIFrame* aChildList);
/** complete the append of aRowGroupFrame to the table
* this builds the cell map
*/
NS_IMETHOD DidAppendRowGroup(nsTableRowGroupFrame *aRowGroupFrame);
/** @see nsIFrame::Paint */
NS_IMETHOD Paint(nsIPresContext& aPresContext,
nsIRenderingContext& aRenderingContext,
@ -315,6 +320,12 @@ protected:
nsIFrame * aInsertedFrame,
PRBool aReplace);
NS_IMETHOD IR_ColGroupAppended(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aAppendedFrame);
NS_IMETHOD IR_ColGroupRemoved(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
@ -328,6 +339,12 @@ protected:
nsIFrame * aInsertedFrame,
PRBool aReplace);
NS_IMETHOD IR_RowGroupAppended(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aAppendedFrame);
NS_IMETHOD IR_RowGroupRemoved(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
@ -414,11 +431,16 @@ protected:
nscoord aMaxHeight);
/** given the new parent size, do I really need to do a reflow? */
virtual PRBool NeedsReflow(const nsSize& aMaxSize);
virtual PRBool NeedsReflow(const nsHTMLReflowState& aReflowState,
const nsSize& aMaxSize);
/** returns PR_TRUE if the cached pass 1 data is still valid */
virtual PRBool IsFirstPassValid() const;
public:
virtual void InvalidateFirstPassCache();
protected:
/** do post processing to setting up style information for the frame */
NS_IMETHOD DidSetStyleContext(nsIPresContext& aPresContext);
@ -431,16 +453,24 @@ protected:
*/
virtual void GrowCellMap(PRInt32 aColCount);
/** returns PR_TRUE if the cached pass 1 data is still valid */
virtual PRBool IsCellMapValid() const;
public:
/** ResetCellMap is called when the cell structure of the table is changed.
* Call with caution, only when changing the structure of the table such as
* inserting or removing rows, changing the rowspan or colspan attribute of a cell, etc.
*/
virtual void ResetCellMap ();
virtual void InvalidateCellMap();
protected:
/** iterates all child frames and creates a new cell map */
NS_IMETHOD ReBuildCellMap();
/** Get the cell map for this table frame. It is not always mCellMap.
* Only the firstInFlow has a legit cell map
*/
virtual nsCellMap *GetCellMap();
virtual nsCellMap *GetCellMap() const;
/** for debugging only
* prints out information about the cell map
@ -559,6 +589,7 @@ private:
PRInt32 mColumnWidthsLength; // the number of column lengths this frame has allocated
PRBool mColumnWidthsSet; // PR_TRUE if column widths have been set at least once
PRBool mFirstPassValid; // PR_TRUE if first pass data is still legit
PRBool mCellMapValid; // PR_TRUE if cell map data is still legit
PRBool mIsInvariantWidth; // PR_TRUE if table width cannot change
PRInt32 mColCount; // the number of columns in this table
PRInt32 mEffectiveColCount; // the number of columns in this table adjusted for weird table attributes

View File

@ -132,11 +132,11 @@ NS_METHOD nsTableOuterFrame::Paint(nsIPresContext& aPresContext,
return NS_OK;
}
PRBool nsTableOuterFrame::NeedsReflow(const nsSize& aMaxSize)
PRBool nsTableOuterFrame::NeedsReflow(const nsHTMLReflowState& aReflowState, const nsSize& aMaxSize)
{
PRBool result=PR_TRUE;
if (nsnull!=mInnerTableFrame)
result = ((nsTableFrame *)mInnerTableFrame)->NeedsReflow(aMaxSize);
result = ((nsTableFrame *)mInnerTableFrame)->NeedsReflow(aReflowState, aMaxSize);
return result;
}

View File

@ -85,7 +85,7 @@ protected:
* or if the table style attributes or parent max height/width have
* changed.
*/
PRBool NeedsReflow(const nsSize& aMaxSize);
PRBool NeedsReflow(const nsHTMLReflowState& aReflowState, const nsSize& aMaxSize);
void PlaceChild(OuterTableReflowState& aReflowState,
nsIFrame* aKidFrame,

View File

@ -39,10 +39,10 @@ NS_DEF_PTR(nsIStyleContext);
#ifdef NS_DEBUG
static PRBool gsDebug = PR_FALSE;
//#define NOISY
//#define NOISY_FLOW
static PRBool gsDebugIR = PR_FALSE;
#else
static const PRBool gsDebug = PR_FALSE;
static const PRBool gsDebugIR = PR_FALSE;
#endif
/* ----------- RowReflowState ---------- */
@ -88,7 +88,8 @@ nsTableRowFrame::nsTableRowFrame(nsIContent* aContent,
mTallestCell(0),
mCellMaxTopMargin(0),
mCellMaxBottomMargin(0),
mMinRowSpan(1)
mMinRowSpan(1),
mInitializedChildren(PR_FALSE)
{
}
@ -100,13 +101,29 @@ NS_IMETHODIMP
nsTableRowFrame::Init(nsIPresContext& aPresContext, nsIFrame* aChildList)
{
mFirstChild = aChildList;
nsTableFrame* table = nsnull;
nsresult result;
return NS_OK;
}
NS_IMETHODIMP
nsTableRowFrame::InitChildren(PRInt32 aRowIndex)
{
nsTableFrame* table = nsnull;
nsresult result=NS_OK;
// each child cell can only be added to the table one time.
// for now, we remember globally whether we've added all or none
if (PR_FALSE==mInitializedChildren)
{
result = nsTableFrame::GetTableFrame(this, table);
if ((NS_OK==result) && (table != nsnull))
{
SetRowIndex(table->GetNextAvailRowIndex());
mInitializedChildren=PR_TRUE;
PRInt32 rowIndex;
if (-1==aRowIndex)
rowIndex = table->GetNextAvailRowIndex();
else
rowIndex = aRowIndex;
SetRowIndex(rowIndex);
PRInt32 colIndex = 0;
for (nsIFrame* kidFrame = mFirstChild; nsnull != kidFrame; kidFrame->GetNextSibling(kidFrame))
{
@ -142,6 +159,7 @@ nsTableRowFrame::Init(nsIPresContext& aPresContext, nsIFrame* aChildList)
}
}
}
}
return NS_OK;
}
@ -346,7 +364,7 @@ void nsTableRowFrame::FixMinCellHeight(nsTableFrame *aTableFrame)
// aKidRect is relative to the upper-left origin of our frame, and includes
// any left/top margin.
void nsTableRowFrame::PlaceChild(nsIPresContext& aPresContext,
RowReflowState& aState,
RowReflowState& aReflowState,
nsIFrame* aKidFrame,
const nsRect& aKidRect,
nsSize* aMaxElementSize,
@ -360,10 +378,10 @@ void nsTableRowFrame::PlaceChild(nsIPresContext& aPresContext,
aKidFrame->SetRect(aKidRect);
// update the running total for the row width
aState.x += aKidRect.width;
aReflowState.x += aKidRect.width;
// Update the maximum element size
PRInt32 rowSpan = aState.tableFrame->GetEffectiveRowSpan(mRowIndex,
PRInt32 rowSpan = aReflowState.tableFrame->GetEffectiveRowSpan(mRowIndex,
((nsTableCellFrame*)aKidFrame));
if (nsnull != aMaxElementSize)
{
@ -377,18 +395,18 @@ void nsTableRowFrame::PlaceChild(nsIPresContext& aPresContext,
if (mMinRowSpan == rowSpan)
{
// Update maxCellHeight
if (aKidRect.height > aState.maxCellHeight)
aState.maxCellHeight = aKidRect.height;
if (aKidRect.height > aReflowState.maxCellHeight)
aReflowState.maxCellHeight = aKidRect.height;
// Update maxCellVertSpace
nsMargin margin;
if (aState.tableFrame->GetCellMarginData((nsTableCellFrame *)aKidFrame, margin) == NS_OK)
if (aReflowState.tableFrame->GetCellMarginData((nsTableCellFrame *)aKidFrame, margin) == NS_OK)
{
nscoord height = aKidRect.height + margin.top + margin.bottom;
if (height > aState.maxCellVertSpace)
aState.maxCellVertSpace = height;
if (height > aReflowState.maxCellVertSpace)
aReflowState.maxCellVertSpace = height;
}
}
}
@ -398,7 +416,7 @@ void nsTableRowFrame::PlaceChild(nsIPresContext& aPresContext,
* changed. Reflows all the existing table cell frames
*/
nsresult nsTableRowFrame::ResizeReflow(nsIPresContext& aPresContext,
RowReflowState& aState,
RowReflowState& aReflowState,
nsHTMLReflowMetrics& aDesiredSize)
{
if (nsnull == mFirstChild)
@ -410,7 +428,7 @@ nsresult nsTableRowFrame::ResizeReflow(nsIPresContext& aPresContext,
&kidMaxElementSize : nsnull;
nscoord maxCellTopMargin = 0;
nscoord maxCellBottomMargin = 0;
nscoord cellSpacing = aState.tableFrame->GetCellSpacing();
nscoord cellSpacing = aReflowState.tableFrame->GetCellSpacing();
PRInt32 cellColSpan=1; // must be defined here so it's set properly for non-cell kids
if (PR_TRUE==gsDebug) printf("%p: RR\n", this);
// Reflow each of our existing cell frames
@ -421,7 +439,7 @@ nsresult nsTableRowFrame::ResizeReflow(nsIPresContext& aPresContext,
if (NS_STYLE_DISPLAY_TABLE_CELL == kidDisplay->mDisplay)
{
nsMargin kidMargin;
aState.tableFrame->GetCellMarginData((nsTableCellFrame *)kidFrame,kidMargin);
aReflowState.tableFrame->GetCellMarginData((nsTableCellFrame *)kidFrame,kidMargin);
if (kidMargin.top > maxCellTopMargin)
maxCellTopMargin = kidMargin.top;
if (kidMargin.bottom > maxCellBottomMargin)
@ -434,31 +452,31 @@ nsresult nsTableRowFrame::ResizeReflow(nsIPresContext& aPresContext,
{ // if this cell is not immediately adjacent to the previous cell, factor in missing col info
for (PRInt32 colIndex=prevColIndex+1; colIndex<cellColIndex; colIndex++)
{
aState.x += aState.tableFrame->GetColumnWidth(colIndex);
aState.x += cellSpacing;
aReflowState.x += aReflowState.tableFrame->GetColumnWidth(colIndex);
aReflowState.x += cellSpacing;
if (PR_TRUE==gsDebug)
printf(" in loop, aState.x set to %d from cellSpacing %d and col width\n",
aState.x, aState.tableFrame->GetColumnWidth(colIndex), cellSpacing);
printf(" in loop, aReflowState.x set to %d from cellSpacing %d and col width\n",
aReflowState.x, aReflowState.tableFrame->GetColumnWidth(colIndex), cellSpacing);
}
}
aState.x += cellSpacing;
if (PR_TRUE==gsDebug) printf(" past loop, aState.x set to %d\n", aState.x);
aReflowState.x += cellSpacing;
if (PR_TRUE==gsDebug) printf(" past loop, aReflowState.x set to %d\n", aReflowState.x);
// at this point, we know the column widths.
// so we get the avail width from the known column widths
cellColSpan = aState.tableFrame->GetEffectiveColSpan(((nsTableCellFrame *)kidFrame)->GetColIndex(),
cellColSpan = aReflowState.tableFrame->GetEffectiveColSpan(((nsTableCellFrame *)kidFrame)->GetColIndex(),
((nsTableCellFrame *)kidFrame));
nscoord availWidth = 0;
for (PRInt32 numColSpan=0; numColSpan<cellColSpan; numColSpan++)
{
availWidth += aState.tableFrame->GetColumnWidth(cellColIndex+numColSpan);
availWidth += aReflowState.tableFrame->GetColumnWidth(cellColIndex+numColSpan);
if (numColSpan != 0)
{
availWidth += cellSpacing;
}
if (PR_TRUE==gsDebug)
printf(" in loop, availWidth set to %d from colIndex %d width %d and cellSpacing\n",
availWidth, cellColIndex, aState.tableFrame->GetColumnWidth(cellColIndex+numColSpan), cellSpacing);
availWidth, cellColIndex, aReflowState.tableFrame->GetColumnWidth(cellColIndex+numColSpan), cellSpacing);
}
if (PR_TRUE==gsDebug) printf(" availWidth for this cell is %d\n", availWidth);
@ -478,7 +496,7 @@ nsresult nsTableRowFrame::ResizeReflow(nsIPresContext& aPresContext,
// Reflow the child
nsHTMLReflowState kidReflowState(aPresContext, kidFrame,
aState.reflowState, kidAvailSize,
aReflowState.reflowState, kidAvailSize,
eReflowReason_Resize);
if (gsDebug) printf ("%p RR: avail=%d\n", this, availWidth);
nsReflowStatus status;
@ -545,12 +563,12 @@ nsresult nsTableRowFrame::ResizeReflow(nsIPresContext& aPresContext,
// end special Nav4 compatibility code
// Place the child
nsRect kidRect (aState.x, kidMargin.top, cellWidth, cellHeight);
nsRect kidRect (aReflowState.x, kidMargin.top, cellWidth, cellHeight);
PlaceChild(aPresContext, aState, kidFrame, kidRect, aDesiredSize.maxElementSize,
PlaceChild(aPresContext, aReflowState, kidFrame, kidRect, aDesiredSize.maxElementSize,
pKidMaxElementSize);
if (PR_TRUE==gsDebug) printf(" past PlaceChild, aState.x set to %d\n", aState.x);
if (PR_TRUE==gsDebug) printf(" past PlaceChild, aReflowState.x set to %d\n", aReflowState.x);
}
// Get the next child
@ -558,27 +576,27 @@ nsresult nsTableRowFrame::ResizeReflow(nsIPresContext& aPresContext,
// if this was the last child, and it had a colspan>1, add in the cellSpacing for the colspan
// if the last kid wasn't a colspan, then we still have the colspan of the last real cell
if ((nsnull==kidFrame) && (cellColSpan>1))
aState.x += cellSpacing;
aReflowState.x += cellSpacing;
}
SetMaxChildHeight(aState.maxCellHeight,maxCellTopMargin, maxCellBottomMargin); // remember height of tallest child who doesn't have a row span
SetMaxChildHeight(aReflowState.maxCellHeight,maxCellTopMargin, maxCellBottomMargin); // remember height of tallest child who doesn't have a row span
// Return our desired size. Note that our desired width is just whatever width
// we were given by the row group frame
aDesiredSize.width = aState.x;
aDesiredSize.height = aState.maxCellVertSpace;
aDesiredSize.width = aReflowState.x;
aDesiredSize.height = aReflowState.maxCellVertSpace;
if (gsDebug)
printf("rr -- row %p width = %d from maxSize %d\n",
this, aDesiredSize.width, aState.reflowState.maxSize.width);
this, aDesiredSize.width, aReflowState.reflowState.maxSize.width);
if (aDesiredSize.width > aState.reflowState.maxSize.width)
if (aDesiredSize.width > aReflowState.reflowState.maxSize.width)
{
printf ("%p error case, desired width = %d, maxSize=%d\n",
this, aDesiredSize.width, aState.reflowState.maxSize.width);
this, aDesiredSize.width, aReflowState.reflowState.maxSize.width);
fflush (stdout);
}
NS_ASSERTION(aDesiredSize.width <= aState.reflowState.maxSize.width, "row calculated to be too wide.");
NS_ASSERTION(aDesiredSize.width <= aReflowState.reflowState.maxSize.width, "row calculated to be too wide.");
return NS_OK;
}
@ -588,7 +606,7 @@ nsresult nsTableRowFrame::ResizeReflow(nsIPresContext& aPresContext,
*/
nsresult
nsTableRowFrame::InitialReflow(nsIPresContext& aPresContext,
RowReflowState& aState,
RowReflowState& aReflowState,
nsHTMLReflowMetrics& aDesiredSize)
{
// Place our children, one at a time, until we are out of children
@ -622,7 +640,7 @@ nsTableRowFrame::InitialReflow(nsIPresContext& aPresContext,
nsMargin margin;
nscoord topMargin = 0;
if (aState.tableFrame->GetCellMarginData((nsTableCellFrame *)kidFrame, margin) == NS_OK)
if (aReflowState.tableFrame->GetCellMarginData((nsTableCellFrame *)kidFrame, margin) == NS_OK)
{
topMargin = margin.top;
}
@ -647,7 +665,7 @@ nsTableRowFrame::InitialReflow(nsIPresContext& aPresContext,
}
nsHTMLReflowState kidReflowState(aPresContext, kidFrame,
aState.reflowState, kidAvailSize,
aReflowState.reflowState, kidAvailSize,
eReflowReason_Initial);
if (gsDebug) printf ("%p InitR: avail=%d\n", this, kidAvailSize.width);
@ -677,17 +695,17 @@ nsTableRowFrame::InitialReflow(nsIPresContext& aPresContext,
// Place the child
x += margin.left;
nsRect kidRect(x, topMargin, kidSize.width, kidSize.height);
PlaceChild(aPresContext, aState, kidFrame, kidRect, aDesiredSize.maxElementSize,
PlaceChild(aPresContext, aReflowState, kidFrame, kidRect, aDesiredSize.maxElementSize,
&kidMaxElementSize);
x += kidSize.width + margin.right;
}
}
SetMaxChildHeight(aState.maxCellHeight, maxTopMargin, maxBottomMargin); // remember height of tallest child who doesn't have a row span
SetMaxChildHeight(aReflowState.maxCellHeight, maxTopMargin, maxBottomMargin); // remember height of tallest child who doesn't have a row span
// Return our desired size
aDesiredSize.width = x;
aDesiredSize.height = aState.maxCellVertSpace;
aDesiredSize.height = aReflowState.maxCellVertSpace;
return result;
}
@ -700,7 +718,7 @@ nsTableRowFrame::InitialReflow(nsIPresContext& aPresContext,
// - maxVertCellSpace
// - x
nsresult nsTableRowFrame::RecoverState(nsIPresContext& aPresContext,
RowReflowState& aState,
RowReflowState& aReflowState,
nsIFrame* aKidFrame,
nscoord& aMaxCellTopMargin,
nscoord& aMaxCellBottomMargin)
@ -710,8 +728,8 @@ nsresult nsTableRowFrame::RecoverState(nsIPresContext& aPresContext,
// Walk the list of children looking for aKidFrame. While we're at
// it get the maxCellHeight and maxVertCellSpace for all the
// frames except aKidFrame
// nsIFrame* prevKidFrame = nsnull;
for (nsIFrame* frame = mFirstChild; nsnull != frame;) {
for (nsIFrame* frame = mFirstChild; nsnull != frame;)
{
const nsStyleDisplay *kidDisplay;
frame->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)kidDisplay));
if (NS_STYLE_DISPLAY_TABLE_CELL == kidDisplay->mDisplay)
@ -719,13 +737,13 @@ nsresult nsTableRowFrame::RecoverState(nsIPresContext& aPresContext,
if (frame != aKidFrame) {
// Update the max top and bottom margins
nsMargin kidMargin;
aState.tableFrame->GetCellMarginData((nsTableCellFrame *)frame, kidMargin);
aReflowState.tableFrame->GetCellMarginData((nsTableCellFrame *)frame, kidMargin);
if (kidMargin.top > aMaxCellTopMargin)
aMaxCellTopMargin = kidMargin.top;
if (kidMargin.bottom > aMaxCellBottomMargin)
aMaxCellBottomMargin = kidMargin.bottom;
PRInt32 rowSpan = aState.tableFrame->GetEffectiveRowSpan(mRowIndex, ((nsTableCellFrame *)frame));
PRInt32 rowSpan = aReflowState.tableFrame->GetEffectiveRowSpan(mRowIndex, ((nsTableCellFrame *)frame));
if (mMinRowSpan == rowSpan) {
// Get the cell's desired height the last time it was reflowed
nsSize desiredSize = ((nsTableCellFrame *)frame)->GetDesiredSize();
@ -751,18 +769,18 @@ nsresult nsTableRowFrame::RecoverState(nsIPresContext& aPresContext,
desiredSize.height = specifiedHeight;
// Update maxCellHeight
if (desiredSize.height > aState.maxCellHeight) {
aState.maxCellHeight = desiredSize.height;
if (desiredSize.height > aReflowState.maxCellHeight) {
aReflowState.maxCellHeight = desiredSize.height;
}
// Update maxCellVertHeight
nsMargin margin;
if (aState.tableFrame->GetCellMarginData((nsTableCellFrame *)frame, margin) == NS_OK)
if (aReflowState.tableFrame->GetCellMarginData((nsTableCellFrame *)frame, margin) == NS_OK)
{
nscoord height = desiredSize.height + margin.top + margin.bottom;
if (height > aState.maxCellVertSpace) {
aState.maxCellVertSpace = height;
if (height > aReflowState.maxCellVertSpace) {
aReflowState.maxCellVertSpace = height;
}
}
}
@ -775,44 +793,294 @@ nsresult nsTableRowFrame::RecoverState(nsIPresContext& aPresContext,
}
}
// Remember the frame that precedes aKidFrame
// prevKidFrame = frame;
frame->GetNextSibling(frame);
}
// Update the running x-offset based on the frame's current x-origin
nsPoint origin;
aKidFrame->GetOrigin(origin);
aState.x = origin.x;
aReflowState.x = origin.x;
return NS_OK;
}
nsresult nsTableRowFrame::IncrementalReflow(nsIPresContext& aPresContext,
RowReflowState& aState,
nsHTMLReflowMetrics& aDesiredSize)
{
nsresult status;
// XXX Deal with the case where the reflow command is targeted at us
nsIFrame* target;
aState.reflowState.reflowCommand->GetTarget(target);
if (this == target) {
NS_NOTYETIMPLEMENTED("unexpected reflow command");
return NS_ERROR_NOT_IMPLEMENTED;
NS_METHOD nsTableRowFrame::IncrementalReflow(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowReflowState& aReflowState,
nsReflowStatus& aStatus)
{
if (PR_TRUE==gsDebugIR) printf("\nTRF IR: IncrementalReflow\n");
nsresult rv = NS_OK;
// determine if this frame is the target or not
nsIFrame *target=nsnull;
rv = aReflowState.reflowState.reflowCommand->GetTarget(target);
if ((PR_TRUE==NS_SUCCEEDED(rv)) && (nsnull!=target))
{
if (this==target)
rv = IR_TargetIsMe(aPresContext, aDesiredSize, aReflowState, aStatus);
else
{
// Get the next frame in the reflow chain
nsIFrame* nextFrame;
aReflowState.reflowState.reflowCommand->GetNext(nextFrame);
rv = IR_TargetIsChild(aPresContext, aDesiredSize, aReflowState, aStatus, nextFrame);
}
}
return rv;
}
// Get the next frame in the reflow chain
nsIFrame* kidFrame;
aState.reflowState.reflowCommand->GetNext(kidFrame);
NS_METHOD nsTableRowFrame::IR_TargetIsMe(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowReflowState& aReflowState,
nsReflowStatus& aStatus)
{
nsresult rv = NS_FRAME_COMPLETE;
nsIReflowCommand::ReflowType type;
aReflowState.reflowState.reflowCommand->GetType(type);
nsIFrame *objectFrame;
aReflowState.reflowState.reflowCommand->GetChildFrame(objectFrame);
const nsStyleDisplay *childDisplay;
objectFrame->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay));
if (PR_TRUE==gsDebugIR) printf("TRF IR: IncrementalReflow_TargetIsMe with type=%d\n", type);
switch (type)
{
case nsIReflowCommand::FrameInserted :
if (NS_STYLE_DISPLAY_TABLE_CELL == childDisplay->mDisplay)
{
rv = IR_CellInserted(aPresContext, aDesiredSize, aReflowState, aStatus,
objectFrame, PR_FALSE);
}
else
{
rv = IR_UnknownFrameInserted(aPresContext, aDesiredSize, aReflowState, aStatus,
objectFrame, PR_FALSE);
}
break;
case nsIReflowCommand::FrameAppended :
if (NS_STYLE_DISPLAY_TABLE_CELL == childDisplay->mDisplay)
{
rv = IR_CellAppended(aPresContext, aDesiredSize, aReflowState, aStatus, objectFrame);
}
else
{ // no optimization to be done for Unknown frame types, so just reuse the Inserted method
rv = IR_UnknownFrameInserted(aPresContext, aDesiredSize, aReflowState, aStatus,
objectFrame, PR_FALSE);
}
break;
/*
case nsIReflowCommand::FrameReplaced :
*/
case nsIReflowCommand::FrameRemoved :
if (NS_STYLE_DISPLAY_TABLE_CELL == childDisplay->mDisplay)
{
rv = IR_CellRemoved(aPresContext, aDesiredSize, aReflowState, aStatus,
objectFrame);
}
else
{
rv = IR_UnknownFrameRemoved(aPresContext, aDesiredSize, aReflowState, aStatus,
objectFrame);
}
break;
case nsIReflowCommand::StyleChanged :
NS_NOTYETIMPLEMENTED("unimplemented reflow command type");
rv = NS_ERROR_NOT_IMPLEMENTED;
if (PR_TRUE==gsDebugIR) printf("TRF IR: StyleChanged not implemented.\n");
break;
case nsIReflowCommand::ContentChanged :
NS_ASSERTION(PR_FALSE, "illegal reflow type: ContentChanged");
rv = NS_ERROR_ILLEGAL_VALUE;
break;
case nsIReflowCommand::PullupReflow:
case nsIReflowCommand::PushReflow:
case nsIReflowCommand::CheckPullupReflow :
case nsIReflowCommand::UserDefined :
NS_NOTYETIMPLEMENTED("unimplemented reflow command type");
rv = NS_ERROR_NOT_IMPLEMENTED;
if (PR_TRUE==gsDebugIR) printf("TRF IR: reflow command not implemented.\n");
break;
}
return rv;
}
NS_METHOD nsTableRowFrame::IR_CellInserted(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aInsertedFrame,
PRBool aReplace)
{
nsresult rv=NS_OK;
return rv;
}
NS_METHOD nsTableRowFrame::IR_DidAppendCell(nsTableRowFrame *aRowFrame)
{
nsresult rv=NS_OK;
return rv;
}
// since we know we're doing an append here, we can optimize
NS_METHOD nsTableRowFrame::IR_CellAppended(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aAppendedFrame)
{
nsresult rv=NS_OK;
// hook aAppendedFrame into the child list
nsIFrame *lastChild = mFirstChild;
nsIFrame *nextChild = lastChild;
nsIFrame *lastRow = nsnull;
while (nsnull!=nextChild)
{
// remember the last child that is really a cell
const nsStyleDisplay *childDisplay;
nextChild->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay));
if (NS_STYLE_DISPLAY_TABLE_CELL == childDisplay->mDisplay)
lastRow = nextChild;
lastChild = nextChild;
nextChild->GetNextSibling(nextChild);
}
if (nsnull==lastChild)
mFirstChild = aAppendedFrame;
else
lastChild->SetNextSibling(aAppendedFrame);
aReflowState.tableFrame->InvalidateFirstPassCache();
// the table will see that it's cached info is bogus and rebuild the cell map,
// and do a reflow
#if 0
// find the col index of the new cell
// account for the new cell
nsresult rv = DidAppendCell((nsTableCellFrame*)aAppendedFrame);
// need to increment the row index of all subsequent rows
#endif
return rv;
}
NS_METHOD nsTableRowFrame::IR_CellRemoved(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aDeletedFrame)
{
nsresult rv=NS_OK;
return rv;
}
//XXX: handle aReplace
NS_METHOD nsTableRowFrame::IR_UnknownFrameInserted(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aInsertedFrame,
PRBool aReplace)
{
nsIReflowCommand::ReflowType type;
aReflowState.reflowState.reflowCommand->GetType(type);
// we have a generic frame that gets inserted but doesn't effect reflow
// hook it up then ignore it
if (nsIReflowCommand::FrameAppended==type)
{ // frameAppended reflow -- find the last child and make aInsertedFrame its next sibling
if (PR_TRUE==gsDebugIR) printf("TRF IR: FrameAppended adding unknown frame type.\n");
nsIFrame *lastChild=mFirstChild;
nsIFrame *nextChild=mFirstChild;
while (nsnull!=nextChild)
{
lastChild=nextChild;
nextChild->GetNextSibling(nextChild);
}
if (nsnull==lastChild)
mFirstChild = aInsertedFrame;
else
lastChild->SetNextSibling(aInsertedFrame);
}
else
{ // frameInserted reflow -- hook up aInsertedFrame as prevSibling's next sibling,
// and be sure to hook in aInsertedFrame's nextSibling (from prevSibling)
if (PR_TRUE==gsDebugIR) printf("TRF IR: FrameInserted adding unknown frame type.\n");
nsIFrame *prevSibling=nsnull;
nsresult rv = aReflowState.reflowState.reflowCommand->GetPrevSiblingFrame(prevSibling);
if (NS_SUCCEEDED(rv) && (nsnull!=prevSibling))
{
nsIFrame *nextSibling=nsnull;
prevSibling->GetNextSibling(nextSibling);
prevSibling->SetNextSibling(aInsertedFrame);
aInsertedFrame->SetNextSibling(nextSibling);
}
else
{
nsIFrame *nextSibling=nsnull;
if (nsnull!=mFirstChild)
mFirstChild->GetNextSibling(nextSibling);
mFirstChild = aInsertedFrame;
aInsertedFrame->SetNextSibling(nextSibling);
}
}
return NS_FRAME_COMPLETE;
}
NS_METHOD nsTableRowFrame::IR_UnknownFrameRemoved(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aRemovedFrame)
{
// we have a generic frame that gets removed but doesn't effect reflow
// unhook it then ignore it
if (PR_TRUE==gsDebugIR) printf("TRF IR: FrameRemoved removing unknown frame type.\n");
nsIFrame *prevChild=nsnull;
nsIFrame *nextChild=mFirstChild;
while (nextChild!=aRemovedFrame)
{
prevChild=nextChild;
nextChild->GetNextSibling(nextChild);
}
nextChild=nsnull;
aRemovedFrame->GetNextSibling(nextChild);
if (nsnull==prevChild) // objectFrame was first child
mFirstChild = nextChild;
else
prevChild->SetNextSibling(nextChild);
return NS_FRAME_COMPLETE;
}
NS_METHOD nsTableRowFrame::IR_TargetIsChild(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aNextFrame)
{
nsresult rv;
const nsStyleDisplay *childDisplay;
aNextFrame->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay));
if (NS_STYLE_DISPLAY_TABLE_CELL == childDisplay->mDisplay)
{
// Recover our reflow state
nscoord maxCellTopMargin, maxCellBottomMargin;
RecoverState(aPresContext, aState, kidFrame, maxCellTopMargin, maxCellBottomMargin);
RecoverState(aPresContext, aReflowState, aNextFrame, maxCellTopMargin, maxCellBottomMargin);
// Get the frame's margins
nsMargin kidMargin;
aState.tableFrame->GetCellMarginData((nsTableCellFrame *)kidFrame, kidMargin);
aReflowState.tableFrame->GetCellMarginData((nsTableCellFrame *)aNextFrame, kidMargin);
if (kidMargin.top > maxCellTopMargin)
maxCellTopMargin = kidMargin.top;
if (kidMargin.bottom > maxCellBottomMargin)
@ -820,13 +1088,13 @@ nsresult nsTableRowFrame::IncrementalReflow(nsIPresContext& aPresContext,
// At this point, we know the column widths. Get the available width
// from the known column widths
PRInt32 cellColIndex = ((nsTableCellFrame *)kidFrame)->GetColIndex();
PRInt32 cellColSpan = aState.tableFrame->GetEffectiveColSpan(((nsTableCellFrame *)kidFrame)->GetColIndex(),
((nsTableCellFrame *)kidFrame));
PRInt32 cellColIndex = ((nsTableCellFrame *)aNextFrame)->GetColIndex();
PRInt32 cellColSpan = aReflowState.tableFrame->GetEffectiveColSpan(((nsTableCellFrame *)aNextFrame)->GetColIndex(),
((nsTableCellFrame *)aNextFrame));
nscoord availWidth = 0;
for (PRInt32 numColSpan = 0; numColSpan < cellColSpan; numColSpan++)
{
availWidth += aState.tableFrame->GetColumnWidth(cellColIndex+numColSpan);
availWidth += aReflowState.tableFrame->GetColumnWidth(cellColIndex+numColSpan);
if (0<numColSpan)
{
availWidth += kidMargin.right;
@ -843,14 +1111,14 @@ nsresult nsTableRowFrame::IncrementalReflow(nsIPresContext& aPresContext,
// Pass along the reflow command
nsSize kidMaxElementSize;
nsHTMLReflowMetrics desiredSize(&kidMaxElementSize);
nsHTMLReflowState kidReflowState(aPresContext, kidFrame, aState.reflowState,
nsHTMLReflowState kidReflowState(aPresContext, aNextFrame, aReflowState.reflowState,
kidAvailSize);
// XXX Unfortunately we need to reflow the child several times.
// The first time is for the incremental reflow command. We can't pass in
// a max width of NS_UNCONSTRAINEDSIZE, because the max width must match
// the width of the previous reflow...
ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState, status);
rv = ReflowChild(aNextFrame, aPresContext, desiredSize, kidReflowState, aStatus);
// Now do the regular pass 1 reflow and gather the max width and max element
// size.
@ -859,10 +1127,10 @@ nsresult nsTableRowFrame::IncrementalReflow(nsIPresContext& aPresContext,
kidReflowState.reason = eReflowReason_Resize;
kidReflowState.reflowCommand = nsnull;
kidReflowState.maxSize.width = NS_UNCONSTRAINEDSIZE;
ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState, status);
rv = ReflowChild(aNextFrame, aPresContext, desiredSize, kidReflowState, aStatus);
if (gsDebug)
printf ("TR %p for cell %p Incremental Reflow: desired=%d, MES=%d\n",
this, kidFrame, desiredSize.width, kidMaxElementSize.width);
this, aNextFrame, desiredSize.width, kidMaxElementSize.width);
// Update the cell layout data.
//XXX: this is a hack, shouldn't it be the case that a min size is
// never larger than a desired size?
@ -870,13 +1138,13 @@ nsresult nsTableRowFrame::IncrementalReflow(nsIPresContext& aPresContext,
desiredSize.width = kidMaxElementSize.width;
if (kidMaxElementSize.height>desiredSize.height)
desiredSize.height = kidMaxElementSize.height;
((nsTableCellFrame *)kidFrame)->SetPass1DesiredSize(desiredSize);
((nsTableCellFrame *)kidFrame)->SetPass1MaxElementSize(kidMaxElementSize);
((nsTableCellFrame *)aNextFrame)->SetPass1DesiredSize(desiredSize);
((nsTableCellFrame *)aNextFrame)->SetPass1MaxElementSize(kidMaxElementSize);
// Now reflow the cell again this time constraining the width
// XXX Ignore for now the possibility that the column width has changed...
kidReflowState.maxSize.width = availWidth;
ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState, status);
rv = ReflowChild(aNextFrame, aPresContext, desiredSize, kidReflowState, aStatus);
// Place the child after taking into account it's margin and attributes
// XXX We need to ask the table (or the table layout strategy) if the column
@ -885,7 +1153,7 @@ nsresult nsTableRowFrame::IncrementalReflow(nsIPresContext& aPresContext,
nscoord specifiedHeight = 0;
nscoord cellHeight = desiredSize.height;
nsIStyleContextPtr kidSC;
kidFrame->GetStyleContext(&aPresContext, kidSC.AssignRef());
aNextFrame->GetStyleContext(&aPresContext, kidSC.AssignRef());
const nsStylePosition* kidPosition = (const nsStylePosition*)
kidSC->GetStyleData(eStyleStruct_Position);
switch (kidPosition->mHeight.GetUnit()) {
@ -906,30 +1174,35 @@ nsresult nsTableRowFrame::IncrementalReflow(nsIPresContext& aPresContext,
// begin special Nav4 compatibility code
if (0==cellWidth)
{
cellWidth = aState.tableFrame->GetColumnWidth(cellColIndex);
cellWidth = aReflowState.tableFrame->GetColumnWidth(cellColIndex);
}
// end special Nav4 compatibility code
// Now place the child
nsRect kidRect (aState.x, kidMargin.top, cellWidth, cellHeight);
nsRect kidRect (aReflowState.x, kidMargin.top, cellWidth, cellHeight);
PlaceChild(aPresContext, aState, kidFrame, kidRect, aDesiredSize.maxElementSize,
PlaceChild(aPresContext, aReflowState, aNextFrame, kidRect, aDesiredSize.maxElementSize,
&kidMaxElementSize);
SetMaxChildHeight(aState.maxCellHeight, maxCellTopMargin, maxCellBottomMargin);
SetMaxChildHeight(aReflowState.maxCellHeight, maxCellTopMargin, maxCellBottomMargin);
// Return our desired size. Note that our desired width is just whatever width
// we were given by the row group frame
aDesiredSize.width = aState.availSize.width;
aDesiredSize.height = aState.maxCellVertSpace;
aDesiredSize.width = aReflowState.availSize.width;
aDesiredSize.height = aReflowState.maxCellVertSpace;
if (gsDebug)
printf("incr -- row %p width = %d MES=%d from maxSize %d\n",
this, aDesiredSize.width, aDesiredSize.maxElementSize->width,
aState.reflowState.maxSize.width);
return status;
aReflowState.reflowState.maxSize.width);
}
else
{ // pass reflow to unknown frame child
// aDesiredSize does not change
}
return rv;
}
/** Layout the entire row.
* This method stacks cells horizontally according to HTML 4.0 rules.
@ -940,45 +1213,46 @@ nsTableRowFrame::Reflow(nsIPresContext& aPresContext,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus)
{
nsresult rv=NS_OK;
if (gsDebug==PR_TRUE)
printf("nsTableRowFrame::Reflow - aMaxSize = %d, %d\n",
aReflowState.maxSize.width, aReflowState.maxSize.height);
// Initialize 'out' parameters
// Initialize 'out' parameters (aStatus set below, undefined if rv returns an error)
if (nsnull != aDesiredSize.maxElementSize) {
aDesiredSize.maxElementSize->width = 0;
aDesiredSize.maxElementSize->height = 0;
}
aStatus = NS_FRAME_COMPLETE; // we're never continued
// Initialize our internal data
ResetMaxChildHeight();
// Initialize our automatic state object
nsTableFrame* tableFrame;
mContentParent->GetContentParent((nsIFrame*&)tableFrame);
// Create a reflow state
nsTableFrame *tableFrame=nsnull;
rv = nsTableFrame::GetTableFrame(this, tableFrame);
if (NS_FAILED(rv) || nsnull==tableFrame)
return rv;
RowReflowState state(aReflowState, tableFrame);
// Do the reflow
nsresult result;
switch (aReflowState.reason) {
case eReflowReason_Initial:
result = InitialReflow(aPresContext, state, aDesiredSize);
rv = InitialReflow(aPresContext, state, aDesiredSize);
GetMinRowSpan(tableFrame);
FixMinCellHeight(tableFrame);
break;
case eReflowReason_Resize:
result = ResizeReflow(aPresContext, state, aDesiredSize);
rv = ResizeReflow(aPresContext, state, aDesiredSize);
break;
case eReflowReason_Incremental:
result = IncrementalReflow(aPresContext, state, aDesiredSize);
rv = IncrementalReflow(aPresContext, aDesiredSize, state, aStatus);
break;
}
aStatus = NS_FRAME_COMPLETE; // we're never continued
if (gsDebug==PR_TRUE)
{
if (nsnull!=aDesiredSize.maxElementSize)
@ -992,7 +1266,7 @@ nsTableRowFrame::Reflow(nsIPresContext& aPresContext,
aDesiredSize.width, aDesiredSize.height);
}
return result;
return rv;
}
NS_METHOD

View File

@ -38,8 +38,13 @@ struct RowReflowState;
class nsTableRowFrame : public nsContainerFrame
{
public:
/** Initialization procedure */
void Init(PRInt32 aRowIndex);
/** Initialization of frame as a row */
void InitRowData(PRInt32 aRowIndex);
/** Initialization of data */
NS_IMETHOD InitChildren(PRInt32 aRowIndex=-1);
void ResetInitChildren();
/** instantiate a new instance of nsTableRowFrame.
* @param aResult the new object is returned in this out-param
@ -126,6 +131,64 @@ protected:
/** destructor */
virtual ~nsTableRowFrame();
/** Incremental Reflow attempts to do column balancing with the minimum number of reflow
* commands to child elements. This is done by processing the reflow command,
* rebalancing column widths (if necessary), then comparing the resulting column widths
* to the prior column widths and reflowing only those cells that require a reflow.
*
* @see Reflow
*/
NS_IMETHOD IncrementalReflow(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowReflowState& aReflowState,
nsReflowStatus& aStatus);
NS_IMETHOD IR_TargetIsChild(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aNextFrame);
NS_IMETHOD IR_TargetIsMe(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowReflowState& aReflowState,
nsReflowStatus& aStatus);
NS_IMETHOD IR_CellInserted(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aInsertedFrame,
PRBool aReplace);
NS_IMETHOD IR_CellAppended(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aAppendedFrame);
NS_IMETHOD IR_DidAppendCell(nsTableRowFrame *aRowFrame);
NS_IMETHOD IR_CellRemoved(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aDeletedFrame);
NS_IMETHOD IR_UnknownFrameInserted(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aInsertedFrame,
PRBool aReplace);
NS_IMETHOD IR_UnknownFrameRemoved(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aDeletedFrame);
// row-specific methods
void GetMinRowSpan(nsTableFrame *aTableFrame);
@ -180,11 +243,14 @@ private:
nscoord mCellMaxTopMargin;
nscoord mCellMaxBottomMargin;
PRInt32 mMinRowSpan; // the smallest row span among all my child cells
PRBool mInitializedChildren; // PR_TRUE if child cells have been initialized
// (for now, that means "added to the table", and
// is NOT the same as having nsIFrame::Init() called.)
};
inline void nsTableRowFrame::Init(PRInt32 aRowIndex)
inline void nsTableRowFrame::InitRowData(PRInt32 aRowIndex)
{
NS_ASSERTION(0<=aRowIndex, "bad param row index");
mRowIndex = aRowIndex;
@ -196,4 +262,7 @@ inline PRInt32 nsTableRowFrame::GetRowIndex() const
return (mRowIndex);
}
inline void nsTableRowFrame::ResetInitChildren()
{ mInitializedChildren=PR_FALSE; }
#endif

View File

@ -30,10 +30,10 @@
#ifdef NS_DEBUG
static PRBool gsDebug = PR_FALSE;
//#define NOISY
//#define NOISY_FLOW
static PRBool gsDebugIR = PR_FALSE;
#else
static const PRBool gsDebug = PR_FALSE;
static const PRBool gsDebugIR = PR_FALSE;
#endif
NS_DEF_PTR(nsIStyleContext);
@ -42,8 +42,8 @@ NS_DEF_PTR(nsIContent);
/* ----------- RowGroupReflowState ---------- */
struct RowGroupReflowState {
// Our reflow state
const nsHTMLReflowState& reflowState;
nsIPresContext& mPresContext; // Our pres context
const nsHTMLReflowState& reflowState; // Our reflow state
// The body's available size (computed from the body's parent)
nsSize availSize;
@ -65,9 +65,10 @@ struct RowGroupReflowState {
// Remember the height of the first row, because it's our maxElementHeight (plus header/footers)
nscoord firstRowHeight;
RowGroupReflowState(nsIPresContext* aPresContext,
RowGroupReflowState(nsIPresContext& aPresContext,
const nsHTMLReflowState& aReflowState)
: reflowState(aReflowState)
: mPresContext(aPresContext),
reflowState(aReflowState)
{
availSize.width = reflowState.maxSize.width;
availSize.height = reflowState.maxSize.height;
@ -686,7 +687,7 @@ void nsTableRowGroupFrame::ShrinkWrapChildren(nsIPresContext* aPresContext,
delete []rowHeights;
}
nsresult nsTableRowGroupFrame::AdjustSiblingsAfterReflow(nsIPresContext* aPresContext,
nsresult nsTableRowGroupFrame::AdjustSiblingsAfterReflow(nsIPresContext& aPresContext,
RowGroupReflowState& aState,
nsIFrame* aKidFrame,
nscoord aDeltaY)
@ -708,7 +709,7 @@ nsresult nsTableRowGroupFrame::AdjustSiblingsAfterReflow(nsIPresContext* aP
// XXX We need to send move notifications to the frame...
nsIHTMLReflow* htmlReflow;
if (NS_OK == kidFrame->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow)) {
htmlReflow->WillReflow(*aPresContext);
htmlReflow->WillReflow(aPresContext);
}
kidFrame->MoveTo(origin.x, origin.y);
@ -742,6 +743,7 @@ nsTableRowGroupFrame::Reflow(nsIPresContext& aPresContext,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus)
{
nsresult rv=NS_OK;
if (gsDebug==PR_TRUE)
printf("nsTableRowGroupFrame::Reflow - aMaxSize = %d, %d\n",
aReflowState.maxSize.width, aReflowState.maxSize.height);
@ -752,45 +754,10 @@ nsTableRowGroupFrame::Reflow(nsIPresContext& aPresContext,
aDesiredSize.maxElementSize->height = 0;
}
RowGroupReflowState state(&aPresContext, aReflowState);
RowGroupReflowState state(aPresContext, aReflowState);
if (eReflowReason_Incremental == aReflowState.reason) {
nsIFrame* target;
aReflowState.reflowCommand->GetTarget(target);
if (this == target) {
NS_NOTYETIMPLEMENTED("unexpected reflow command");
}
// XXX Recover state
// XXX Deal with the case where the reflow command is targeted at us
nsIFrame* kidFrame;
aReflowState.reflowCommand->GetNext(kidFrame);
// Remember the old rect
nsRect oldKidRect;
kidFrame->GetRect(oldKidRect);
// Pass along the reflow command
// XXX Correctly compute the available space...
nsHTMLReflowState kidReflowState(aPresContext, kidFrame,
aReflowState, aReflowState.maxSize);
nsHTMLReflowMetrics desiredSize(nsnull);
ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState, aStatus);
// Resize the row frame
nsRect kidRect;
kidFrame->GetRect(kidRect);
kidFrame->SizeTo(desiredSize.width, desiredSize.height);
// Adjust the frames that follow...
AdjustSiblingsAfterReflow(&aPresContext, state, kidFrame, desiredSize.height -
oldKidRect.height);
// Return of desired size
aDesiredSize.width = aReflowState.maxSize.width;
aDesiredSize.height = state.y;
rv = IncrementalReflow(aPresContext, aDesiredSize, aReflowState, aStatus);
} else {
PRBool reflowMappedOK = PR_TRUE;
@ -855,10 +822,329 @@ nsTableRowGroupFrame::Reflow(nsIPresContext& aPresContext,
aDesiredSize.width, aDesiredSize.height);
}
return NS_OK;
return rv;
}
NS_METHOD nsTableRowGroupFrame::IncrementalReflow(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus)
{
if (PR_TRUE==gsDebugIR) printf("\nTRGF IR: IncrementalReflow\n");
nsresult rv = NS_OK;
// create an inner table reflow state
RowGroupReflowState state(aPresContext, aReflowState);
// determine if this frame is the target or not
nsIFrame *target=nsnull;
rv = aReflowState.reflowCommand->GetTarget(target);
if ((PR_TRUE==NS_SUCCEEDED(rv)) && (nsnull!=target))
{
if (this==target)
rv = IR_TargetIsMe(aPresContext, aDesiredSize, state, aStatus);
else
{
// Get the next frame in the reflow chain
nsIFrame* nextFrame;
aReflowState.reflowCommand->GetNext(nextFrame);
// Recover our reflow state
//RecoverState(state, nextFrame);
rv = IR_TargetIsChild(aPresContext, aDesiredSize, state, aStatus, nextFrame);
}
}
return rv;
}
NS_METHOD nsTableRowGroupFrame::IR_TargetIsMe(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowGroupReflowState& aReflowState,
nsReflowStatus& aStatus)
{
nsresult rv = NS_FRAME_COMPLETE;
nsIReflowCommand::ReflowType type;
aReflowState.reflowState.reflowCommand->GetType(type);
nsIFrame *objectFrame;
aReflowState.reflowState.reflowCommand->GetChildFrame(objectFrame);
const nsStyleDisplay *childDisplay;
objectFrame->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay));
if (PR_TRUE==gsDebugIR) printf("TRGF IR: IncrementalReflow_TargetIsMe with type=%d\n", type);
switch (type)
{
case nsIReflowCommand::FrameInserted :
if (NS_STYLE_DISPLAY_TABLE_ROW == childDisplay->mDisplay)
{
rv = IR_RowInserted(aPresContext, aDesiredSize, aReflowState, aStatus,
objectFrame, PR_FALSE);
}
else
{
rv = IR_UnknownFrameInserted(aPresContext, aDesiredSize, aReflowState, aStatus,
objectFrame, PR_FALSE);
}
break;
case nsIReflowCommand::FrameAppended :
if (NS_STYLE_DISPLAY_TABLE_ROW == childDisplay->mDisplay)
{
rv = IR_RowAppended(aPresContext, aDesiredSize, aReflowState, aStatus, objectFrame);
}
else
{ // no optimization to be done for Unknown frame types, so just reuse the Inserted method
rv = IR_UnknownFrameInserted(aPresContext, aDesiredSize, aReflowState, aStatus,
objectFrame, PR_FALSE);
}
break;
/*
case nsIReflowCommand::FrameReplaced :
*/
case nsIReflowCommand::FrameRemoved :
if (NS_STYLE_DISPLAY_TABLE_ROW == childDisplay->mDisplay)
{
rv = IR_RowRemoved(aPresContext, aDesiredSize, aReflowState, aStatus,
objectFrame);
}
else
{
rv = IR_UnknownFrameRemoved(aPresContext, aDesiredSize, aReflowState, aStatus,
objectFrame);
}
break;
case nsIReflowCommand::StyleChanged :
NS_NOTYETIMPLEMENTED("unimplemented reflow command type");
rv = NS_ERROR_NOT_IMPLEMENTED;
if (PR_TRUE==gsDebugIR) printf("TRGF IR: StyleChanged not implemented.\n");
break;
case nsIReflowCommand::ContentChanged :
NS_ASSERTION(PR_FALSE, "illegal reflow type: ContentChanged");
rv = NS_ERROR_ILLEGAL_VALUE;
break;
case nsIReflowCommand::PullupReflow:
case nsIReflowCommand::PushReflow:
case nsIReflowCommand::CheckPullupReflow :
case nsIReflowCommand::UserDefined :
NS_NOTYETIMPLEMENTED("unimplemented reflow command type");
rv = NS_ERROR_NOT_IMPLEMENTED;
if (PR_TRUE==gsDebugIR) printf("TRGF IR: reflow command not implemented.\n");
break;
}
return rv;
}
NS_METHOD nsTableRowGroupFrame::IR_RowInserted(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowGroupReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aInsertedFrame,
PRBool aReplace)
{
nsresult rv=NS_OK;
// inserting the rowgroup only effects reflow if the rowgroup includes at least one row
return rv;
}
NS_METHOD nsTableRowGroupFrame::IR_DidAppendRow(nsTableRowFrame *aRowFrame)
{
nsresult rv=NS_OK;
/* need to make space in the cell map. Remeber that row spans can't cross row groups
once the space is made, tell the row to initizalize its children.
it will automatically find the row to initialize into.
but this is tough because a cell in aInsertedFrame could have a rowspan
which must be respected if a subsequent row is appended.
*/
rv = aRowFrame->InitChildren();
return rv;
}
// since we know we're doing an append here, we can optimize
NS_METHOD nsTableRowGroupFrame::IR_RowAppended(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowGroupReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aAppendedFrame)
{
nsresult rv=NS_OK;
// hook aAppendedFrame into the child list
nsIFrame *lastChild = mFirstChild;
nsIFrame *nextChild = lastChild;
nsIFrame *lastRow = nsnull;
while (nsnull!=nextChild)
{
// remember the last child that is really a row
const nsStyleDisplay *childDisplay;
nextChild->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay));
if (NS_STYLE_DISPLAY_TABLE_ROW == childDisplay->mDisplay)
lastRow = nextChild;
lastChild = nextChild;
nextChild->GetNextSibling(nextChild);
}
if (nsnull==lastChild)
mFirstChild = aAppendedFrame;
else
lastChild->SetNextSibling(aAppendedFrame);
nsTableFrame *tableFrame=nsnull;
rv = nsTableFrame::GetTableFrame(this, tableFrame);
if (NS_FAILED(rv) || nsnull==tableFrame)
return rv;
tableFrame->InvalidateFirstPassCache();
// the table will see that it's cached info is bogus and rebuild the cell map,
// and do a reflow
#if 0
// find the row index of the new row
PRInt32 newRowIndex=-1;
if (nsnull!=
lastChild=mFirstChild;
nextChild=lastChild;
while (nsnull!=nextChild)
{
}
// account for the cells in aAppendedFrame
nsresult rv = DidAppendRow((nsTableRowFrame*)aAppendedFrame, newRowIndex);
// need to increment the row index of all subsequent rows
#endif
return rv;
}
NS_METHOD nsTableRowGroupFrame::IR_RowRemoved(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowGroupReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aDeletedFrame)
{
nsresult rv;
return rv;
}
//XXX: handle aReplace
NS_METHOD nsTableRowGroupFrame::IR_UnknownFrameInserted(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowGroupReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aInsertedFrame,
PRBool aReplace)
{
nsIReflowCommand::ReflowType type;
aReflowState.reflowState.reflowCommand->GetType(type);
// we have a generic frame that gets inserted but doesn't effect reflow
// hook it up then ignore it
if (nsIReflowCommand::FrameAppended==type)
{ // frameAppended reflow -- find the last child and make aInsertedFrame its next sibling
if (PR_TRUE==gsDebugIR) printf("TRGF IR: FrameAppended adding unknown frame type.\n");
nsIFrame *lastChild=mFirstChild;
nsIFrame *nextChild=mFirstChild;
while (nsnull!=nextChild)
{
lastChild=nextChild;
nextChild->GetNextSibling(nextChild);
}
if (nsnull==lastChild)
mFirstChild = aInsertedFrame;
else
lastChild->SetNextSibling(aInsertedFrame);
}
else
{ // frameInserted reflow -- hook up aInsertedFrame as prevSibling's next sibling,
// and be sure to hook in aInsertedFrame's nextSibling (from prevSibling)
if (PR_TRUE==gsDebugIR) printf("TRGF IR: FrameInserted adding unknown frame type.\n");
nsIFrame *prevSibling=nsnull;
nsresult rv = aReflowState.reflowState.reflowCommand->GetPrevSiblingFrame(prevSibling);
if (NS_SUCCEEDED(rv) && (nsnull!=prevSibling))
{
nsIFrame *nextSibling=nsnull;
prevSibling->GetNextSibling(nextSibling);
prevSibling->SetNextSibling(aInsertedFrame);
aInsertedFrame->SetNextSibling(nextSibling);
}
else
{
nsIFrame *nextSibling=nsnull;
if (nsnull!=mFirstChild)
mFirstChild->GetNextSibling(nextSibling);
mFirstChild = aInsertedFrame;
aInsertedFrame->SetNextSibling(nextSibling);
}
}
return NS_FRAME_COMPLETE;
}
NS_METHOD nsTableRowGroupFrame::IR_UnknownFrameRemoved(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowGroupReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aRemovedFrame)
{
// we have a generic frame that gets removed but doesn't effect reflow
// unhook it then ignore it
if (PR_TRUE==gsDebugIR) printf("TRGF IR: FrameRemoved removing unknown frame type.\n");
nsIFrame *prevChild=nsnull;
nsIFrame *nextChild=mFirstChild;
while (nextChild!=aRemovedFrame)
{
prevChild=nextChild;
nextChild->GetNextSibling(nextChild);
}
nextChild=nsnull;
aRemovedFrame->GetNextSibling(nextChild);
if (nsnull==prevChild) // objectFrame was first child
mFirstChild = nextChild;
else
prevChild->SetNextSibling(nextChild);
return NS_FRAME_COMPLETE;
}
NS_METHOD nsTableRowGroupFrame::IR_TargetIsChild(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowGroupReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aNextFrame)
{
nsresult rv;
if (PR_TRUE==gsDebugIR) printf("\nTRGF IR: IR_TargetIsChild\n");
// XXX Recover state
// Remember the old rect
nsRect oldKidRect;
aNextFrame->GetRect(oldKidRect);
// Pass along the reflow command
// XXX Correctly compute the available space...
nsHTMLReflowState kidReflowState(aPresContext, aNextFrame, aReflowState.reflowState, aReflowState.reflowState.maxSize);
nsHTMLReflowMetrics desiredSize(nsnull);
rv = ReflowChild(aNextFrame, aPresContext, desiredSize, kidReflowState, aStatus);
// Resize the row frame
nsRect kidRect;
aNextFrame->GetRect(kidRect);
aNextFrame->SizeTo(desiredSize.width, desiredSize.height);
// Adjust the frames that follow...
AdjustSiblingsAfterReflow(aPresContext, aReflowState, aNextFrame, desiredSize.height -
oldKidRect.height);
// Return of desired size
aDesiredSize.width = aReflowState.reflowState.maxSize.width;
aDesiredSize.height = aReflowState.y;
return rv;
}
NS_METHOD
nsTableRowGroupFrame::CreateContinuingFrame(nsIPresContext& aPresContext,
nsIFrame* aParent,

View File

@ -22,6 +22,7 @@
#include "nsContainerFrame.h"
#include "nsIAtom.h"
class nsTableRowFrame;
struct RowGroupReflowState;
/**
@ -79,6 +80,65 @@ public:
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus);
/** Incremental Reflow attempts to do column balancing with the minimum number of reflow
* commands to child elements. This is done by processing the reflow command,
* rebalancing column widths (if necessary), then comparing the resulting column widths
* to the prior column widths and reflowing only those cells that require a reflow.
*
* @see Reflow
*/
NS_IMETHOD IncrementalReflow(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus);
NS_IMETHOD IR_TargetIsChild(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowGroupReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aNextFrame);
NS_IMETHOD IR_TargetIsMe(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowGroupReflowState& aReflowState,
nsReflowStatus& aStatus);
NS_IMETHOD IR_RowInserted(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowGroupReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aInsertedFrame,
PRBool aReplace);
NS_IMETHOD IR_RowAppended(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowGroupReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aAppendedFrame);
NS_IMETHOD IR_DidAppendRow(nsTableRowFrame *aRowFrame);
NS_IMETHOD IR_RowRemoved(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowGroupReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aDeletedFrame);
NS_IMETHOD IR_UnknownFrameInserted(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowGroupReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aInsertedFrame,
PRBool aReplace);
NS_IMETHOD IR_UnknownFrameRemoved(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowGroupReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aDeletedFrame);
/** @see nsContainerFrame::CreateContinuingFrame */
NS_IMETHOD CreateContinuingFrame(nsIPresContext& aPresContext,
nsIFrame* aParent,
@ -111,11 +171,11 @@ protected:
~nsTableRowGroupFrame();
nscoord GetTopMarginFor(nsIPresContext* aCX,
RowGroupReflowState& aState,
RowGroupReflowState& aReflowState,
const nsMargin& aKidMargin);
void PlaceChild( nsIPresContext* aPresContext,
RowGroupReflowState& aState,
RowGroupReflowState& aReflowState,
nsIFrame* aKidFrame,
const nsRect& aKidRect,
nsSize* aMaxElementSize,
@ -124,8 +184,8 @@ protected:
void ShrinkWrapChildren(nsIPresContext* aPresContext,
nsHTMLReflowMetrics& aDesiredSize);
nsresult AdjustSiblingsAfterReflow(nsIPresContext* aPresContext,
RowGroupReflowState& aState,
nsresult AdjustSiblingsAfterReflow(nsIPresContext& aPresContext,
RowGroupReflowState& aReflowState,
nsIFrame* aKidFrame,
nscoord aDeltaY);
@ -133,24 +193,24 @@ protected:
* Reflow the frames we've already created
*
* @param aPresContext presentation context to use
* @param aState current inline state
* @param aReflowState current inline state
* @return true if we successfully reflowed all the mapped children and false
* otherwise, e.g. we pushed children to the next in flow
*/
PRBool ReflowMappedChildren(nsIPresContext* aPresContext,
RowGroupReflowState& aState,
RowGroupReflowState& aReflowState,
nsSize* aMaxElementSize);
/**
* Try and pull-up frames from our next-in-flow
*
* @param aPresContext presentation context to use
* @param aState current inline state
* @param aReflowState current inline state
* @return true if we successfully pulled-up all the children and false
* otherwise, e.g. child didn't fit
*/
PRBool PullUpChildren(nsIPresContext* aPresContext,
RowGroupReflowState& aState,
RowGroupReflowState& aReflowState,
nsSize* aMaxElementSize);
private: