incremental reflow: append/insert/delete row group, append/insert/delete col

This commit is contained in:
buster%netscape.com 1998-10-15 21:07:37 +00:00
parent 19dbcd23cb
commit 0c1c724f56
8 changed files with 980 additions and 96 deletions

View File

@ -35,7 +35,13 @@ NS_DEF_PTR(nsIStyleContext);
static NS_DEFINE_IID(kIHTMLTableColElementIID, NS_IHTMLTABLECOLELEMENT_IID);
#ifdef NS_DEBUG
static PRBool gsDebug = PR_FALSE;
static PRBool gsDebugIR = PR_FALSE;
#else
static const PRBool gsDebug = PR_FALSE;
static const PRBool gsDebugIR = PR_FALSE;
#endif
nsTableColGroupFrame::nsTableColGroupFrame(nsIContent* aContent,
nsIFrame* aParentFrame)
@ -48,7 +54,7 @@ nsTableColGroupFrame::~nsTableColGroupFrame()
{
}
nsresult
NS_IMETHODIMP
nsTableColGroupFrame::InitNewFrames(nsIPresContext& aPresContext, nsIFrame* aChildList)
{
nsresult rv=NS_OK;
@ -75,7 +81,6 @@ nsTableColGroupFrame::InitNewFrames(nsIPresContext& aPresContext, nsIFrame* aChi
PRInt32 colIndex = mStartColIndex + mColCount;
((nsTableColFrame *)(kidFrame))->InitColFrame (colIndex, repeat);
mColCount+= repeat;
((nsTableColFrame *)kidFrame)->SetColumnIndex(colIndex);
tableFrame->AddColumnFrame((nsTableColFrame *)kidFrame);
}
// colgroup's span attribute is how many columns the group represents
@ -138,7 +143,7 @@ nsTableColGroupFrame::InitNewFrames(nsIPresContext& aPresContext, nsIFrame* aChi
return rv;
}
nsresult
NS_IMETHODIMP
nsTableColGroupFrame::AppendNewFrames(nsIPresContext& aPresContext, nsIFrame* aChildList)
{
nsIFrame* lastChild = LastFrame(mFirstChild);
@ -171,38 +176,19 @@ NS_METHOD nsTableColGroupFrame::Paint(nsIPresContext& aPresContext,
return NS_OK;
}
// TODO: incremental reflow
// today, we just throw away the column frames and start over every time
// this is dumb, we should be able to maintain column frames and adjust incrementally
NS_METHOD nsTableColGroupFrame::Reflow(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus)
{
NS_ASSERTION(nsnull!=mContent, "bad state -- null content for frame");
nsresult rv=NS_OK;
// for every content child that (is a column thingy and does not already have a frame)
// create a frame and adjust it's style
nsIFrame* kidFrame = nsnull;
if (eReflowReason_Incremental == aReflowState.reason) {
NS_ASSERTION(nsnull != aReflowState.reflowCommand, "null reflow command");
// Get the type of reflow command
nsIReflowCommand::ReflowType reflowCmdType;
aReflowState.reflowCommand->GetType(reflowCmdType);
// Currently we only expect appended reflow commands
NS_ASSERTION(nsIReflowCommand::FrameAppended == reflowCmdType,
"unexpected reflow command");
// Get the new column frames
nsIFrame* childList;
aReflowState.reflowCommand->GetChildFrame(childList);
// Append them to the child list
AppendNewFrames(aPresContext, childList);
InitNewFrames(aPresContext, childList);
rv = IncrementalReflow(aPresContext, aDesiredSize, aReflowState, aStatus);
}
for (kidFrame = mFirstChild; nsnull != kidFrame; kidFrame->GetNextSibling(kidFrame)) {
@ -228,9 +214,355 @@ NS_METHOD nsTableColGroupFrame::Reflow(nsIPresContext& aPresContext,
aDesiredSize.maxElementSize->height=0;
}
aStatus = NS_FRAME_COMPLETE;
return rv;
}
NS_METHOD nsTableColGroupFrame::IncrementalReflow(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus)
{
if (PR_TRUE==gsDebugIR) printf("\nTCGF IR: IncrementalReflow\n");
nsresult rv = NS_OK;
// 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, aReflowState, aStatus);
else
{
// Get the next frame in the reflow chain
nsIFrame* nextFrame;
aReflowState.reflowCommand->GetNext(nextFrame);
rv = IR_TargetIsChild(aPresContext, aDesiredSize, aReflowState, aStatus, nextFrame);
}
}
return rv;
}
NS_METHOD nsTableColGroupFrame::IR_TargetIsMe(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus)
{
nsresult rv = NS_OK;
aStatus = NS_FRAME_COMPLETE;
nsIReflowCommand::ReflowType type;
aReflowState.reflowCommand->GetType(type);
nsIFrame *objectFrame;
aReflowState.reflowCommand->GetChildFrame(objectFrame);
const nsStyleDisplay *childDisplay;
objectFrame->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay));
if (PR_TRUE==gsDebugIR) printf("nTCGF IR: IncrementalReflow_TargetIsMe with type=%d\n", type);
switch (type)
{
case nsIReflowCommand::FrameInserted :
if (NS_STYLE_DISPLAY_TABLE_COLUMN == childDisplay->mDisplay)
{
rv = IR_ColInserted(aPresContext, aDesiredSize, aReflowState, aStatus,
(nsTableColFrame*)objectFrame, PR_FALSE);
}
else
{
rv = IR_UnknownFrameInserted(aPresContext, aDesiredSize, aReflowState, aStatus,
objectFrame, PR_FALSE);
}
break;
case nsIReflowCommand::FrameAppended :
if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == childDisplay->mDisplay)
{
rv = IR_ColAppended(aPresContext, aDesiredSize, aReflowState, aStatus,
(nsTableColFrame*)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_COLUMN_GROUP == childDisplay->mDisplay)
{
rv = IR_ColRemoved(aPresContext, aDesiredSize, aReflowState, aStatus,
(nsTableColFrame*)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("TCGF 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("TCGF IR: reflow command not implemented.\n");
break;
}
return rv;
}
NS_METHOD nsTableColGroupFrame::IR_ColInserted(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus,
nsTableColFrame * aInsertedFrame,
PRBool aReplace)
{
nsresult rv=NS_OK;
PRBool adjustStartingColIndex=PR_FALSE;
rv = IR_UnknownFrameInserted(aPresContext, aDesiredSize, aReflowState, aStatus, aInsertedFrame, aReplace);
if (NS_FAILED(rv))
return rv;
PRInt32 startingColIndex=mStartColIndex;
startingColIndex += GetColumnCount(); // has the side effect of resetting all column indexes
nsIFrame *childFrame=nsnull;
GetNextSibling(childFrame);
while ((NS_SUCCEEDED(rv)) && (nsnull!=childFrame))
{
const nsStyleDisplay *display;
childFrame->GetStyleData(eStyleStruct_Display, (nsStyleStruct *&)display);
if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == display->mDisplay)
{
startingColIndex += ((nsTableColGroupFrame *)childFrame)->SetStartColumnIndex(startingColIndex);
}
rv = childFrame->GetNextSibling(childFrame);
}
nsTableFrame* tableFrame=nsnull;
rv = nsTableFrame::GetTableFrame(this, tableFrame);
if ((NS_SUCCEEDED(rv)) && (nsnull!=tableFrame))
tableFrame->InvalidateColumnCache();
//XXX: what we want to do here is determine if the new COL information changes anything about layout
// if not, we can skip rebalancing the columns
return rv;
}
NS_METHOD nsTableColGroupFrame::IR_ColAppended(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus,
nsTableColFrame * aAppendedFrame)
{
nsresult rv=NS_OK;
PRBool adjustStartingColIndex=PR_FALSE;
rv = IR_UnknownFrameInserted(aPresContext, aDesiredSize, aReflowState, aStatus, aAppendedFrame, PR_FALSE);
if (NS_FAILED(rv))
return rv;
PRInt32 startingColIndex=mStartColIndex;
// this could be optimized
startingColIndex += GetColumnCount(); // has the side effect of resetting all column indexes
nsIFrame *childFrame=nsnull;
GetNextSibling(childFrame);
while ((NS_SUCCEEDED(rv)) && (nsnull!=childFrame))
{
const nsStyleDisplay *display;
childFrame->GetStyleData(eStyleStruct_Display, (nsStyleStruct *&)display);
if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == display->mDisplay)
{
startingColIndex += ((nsTableColGroupFrame *)childFrame)->SetStartColumnIndex(startingColIndex);
}
rv = childFrame->GetNextSibling(childFrame);
}
// today we need to rebuild the whole column cache
// if the table frame is ever recoded to build the column cache incrementally, we could take
// advantage of that here.
nsTableFrame* tableFrame=nsnull;
rv = nsTableFrame::GetTableFrame(this, tableFrame);
if ((NS_SUCCEEDED(rv)) && (nsnull!=tableFrame))
tableFrame->InvalidateColumnCache();
return rv;
}
NS_METHOD nsTableColGroupFrame::IR_ColRemoved(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus,
nsTableColFrame * aDeletedFrame)
{
nsresult rv=NS_OK;
PRInt32 startingColIndex=mStartColIndex;
nsIFrame *childFrame=mFirstChild;
nsIFrame *prevSib=nsnull;
while ((NS_SUCCEEDED(rv)) && (nsnull!=childFrame))
{
if (childFrame==aDeletedFrame)
{
nsIFrame *deleteFrameNextSib=nsnull;
aDeletedFrame->GetNextSibling(deleteFrameNextSib);
if (nsnull!=prevSib)
prevSib->SetNextSibling(deleteFrameNextSib);
else
mFirstChild = deleteFrameNextSib;
startingColIndex += GetColumnCount(); // resets all column indexes
}
const nsStyleDisplay *display;
childFrame->GetStyleData(eStyleStruct_Display, (nsStyleStruct *&)display);
if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == display->mDisplay)
{
// we've removed aDeletedFrame, now adjust the starting col index of all subsequent col groups
startingColIndex += ((nsTableColGroupFrame *)childFrame)->SetStartColumnIndex(startingColIndex);
}
prevSib=childFrame;
rv = childFrame->GetNextSibling(childFrame);
}
// today we need to rebuild the whole column cache
// if the table frame is ever recoded to build the column cache incrementally, we could take
// advantage of that here.
nsTableFrame* tableFrame=nsnull;
rv = nsTableFrame::GetTableFrame(this, tableFrame);
if ((NS_SUCCEEDED(rv)) && (nsnull!=tableFrame))
tableFrame->InvalidateColumnCache();
return rv;
}
//XXX: handle aReplace
NS_METHOD nsTableColGroupFrame::IR_UnknownFrameInserted(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aInsertedFrame,
PRBool aReplace)
{
nsIReflowCommand::ReflowType type;
aReflowState.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("TCGF 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("TCGF IR: FrameInserted adding unknown frame type.\n");
nsIFrame *prevSibling=nsnull;
nsresult rv = aReflowState.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);
}
}
aStatus = NS_FRAME_COMPLETE;
return NS_OK;
}
NS_METHOD nsTableColGroupFrame::IR_UnknownFrameRemoved(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& 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("TCGF 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);
aStatus = NS_FRAME_COMPLETE;
return NS_OK;
}
NS_METHOD nsTableColGroupFrame::IR_TargetIsChild(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aNextFrame)
{
nsresult rv;
if (PR_TRUE==gsDebugIR) printf("\nTCGF IR: IR_TargetIsChild\n");
// Remember the old col count
const PRInt32 oldColCount = GetColumnCount();
// Pass along the reflow command
nsHTMLReflowMetrics desiredSize(nsnull);
nsHTMLReflowState kidReflowState(aPresContext, aNextFrame,
aReflowState,
aReflowState.maxSize);
rv = ReflowChild(aNextFrame, aPresContext, desiredSize, kidReflowState, aStatus);
if (NS_FAILED(rv))
return rv;
nsTableFrame *tableFrame=nsnull;
rv = nsTableFrame::GetTableFrame(this, tableFrame);
if ((NS_SUCCEEDED(rv)) && (nsnull!=tableFrame))
{
// compare the new col count to the old col count.
// If they are the same, we just need to rebalance column widths
// If they differ, we need to fix up other column groups and the column cache
const PRInt32 newColCount = GetColumnCount(); // this will set the new column indexes if necessary
if (oldColCount==newColCount)
tableFrame->InvalidateColumnWidths();
else
tableFrame->InvalidateColumnCache();
}
return rv;
}
// Subclass hook for style post processing
NS_METHOD nsTableColGroupFrame::SetStyleContextForFirstPass(nsIPresContext& aPresContext)
{

View File

@ -102,11 +102,63 @@ protected:
* Since we need to know the full column structure before the COLS attribute
* can be interpreted, we can't just use DidSetStyleContext
*/
NS_METHOD SetStyleContextForFirstPass(nsIPresContext& aPresContext);
NS_IMETHOD SetStyleContextForFirstPass(nsIPresContext& aPresContext);
NS_IMETHOD InitNewFrames(nsIPresContext& aPresContext, nsIFrame* aChildList);
NS_IMETHOD AppendNewFrames(nsIPresContext& aPresContext, nsIFrame* aChildList);
NS_IMETHOD IncrementalReflow(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus);
NS_IMETHOD IR_TargetIsMe(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus);
NS_IMETHOD IR_ColInserted(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus,
nsTableColFrame * aInsertedFrame,
PRBool aReplace);
NS_IMETHOD IR_ColAppended(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus,
nsTableColFrame * aAppendedFrame);
NS_IMETHOD IR_ColRemoved(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus,
nsTableColFrame * aDeletedFrame);
NS_IMETHOD IR_UnknownFrameInserted(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aInsertedFrame,
PRBool aReplace);
NS_IMETHOD IR_UnknownFrameRemoved(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aRemovedFrame);
NS_IMETHOD IR_TargetIsChild(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aNextFrame);
// data members
nsresult InitNewFrames(nsIPresContext& aPresContext, nsIFrame* aChildList);
nsresult AppendNewFrames(nsIPresContext& aPresContext, nsIFrame* aChildList);
PRInt32 mColCount;
/** the starting column index this col group represents. Must be >= 0. */

View File

@ -52,7 +52,6 @@ static const PRBool gsDebug = PR_FALSE;
static const PRBool gsDebugCLD = PR_FALSE;
static const PRBool gsDebugNT = PR_FALSE;
static const PRBool gsDebugIR = PR_FALSE;
#endif
#ifndef max
@ -271,6 +270,7 @@ nsTableFrame::nsTableFrame(nsIContent* aContent, nsIFrame* aParentFrame)
mColCache(nsnull),
mTableLayoutStrategy(nsnull),
mFirstPassValid(PR_FALSE),
mColumnWidthsValid(PR_FALSE),
mColumnCacheValid(PR_FALSE),
mCellMapValid(PR_TRUE),
mIsInvariantWidth(PR_FALSE)
@ -1565,7 +1565,7 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext& aPresContext,
if (PR_TRUE==gsDebug) printf("TIF Reflow: needs reflow\n");
if (eReflowReason_Initial!=aReflowState.reason && PR_FALSE==IsCellMapValid())
{
if (PR_TRUE==gsDebug) printf("TIF Reflow: not initial reflow, so resetting cell map.\n");
if (PR_TRUE==gsDebug) printf("TIF Reflow: cell map invalid, rebuilding...\n");
if (nsnull!=mCellMap)
delete mCellMap;
mCellMap = new nsCellMap(0,0);
@ -1574,14 +1574,17 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext& aPresContext,
}
if (PR_FALSE==IsFirstPassValid())
{
if (PR_TRUE==gsDebug || PR_TRUE==gsDebugIR) printf("TIF Reflow: first pass is invalid\n");
if (PR_TRUE==gsDebug || PR_TRUE==gsDebugIR) printf("TIF Reflow: first pass is invalid, rebuilding...\n");
rv = ResizeReflowPass1(aPresContext, aDesiredSize, aReflowState, aStatus, nsnull, aReflowState.reason);
if (NS_FAILED(rv))
return rv;
needsRecalc=PR_TRUE;
}
if (PR_FALSE==IsColumnCacheValid())
{
if (PR_TRUE==gsDebug || PR_TRUE==gsDebugIR) printf("TIF Reflow: column cache is invalid, rebuilding...\n");
needsRecalc=PR_TRUE;
}
if (PR_TRUE==needsRecalc)
{
if (PR_TRUE==gsDebugIR) printf("TIF Reflow: needs recalc.\n");
@ -1590,11 +1593,20 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext& aPresContext,
{
if (PR_TRUE==gsDebugIR) printf("TIF Reflow: Re-init layout strategy\n");
mTableLayoutStrategy->Initialize(aDesiredSize.maxElementSize);
mColumnWidthsValid=PR_TRUE;
}
BuildColumnCache(aPresContext, aDesiredSize, aReflowState, aStatus);
RecalcLayoutData(); // Recalculate Layout Dependencies
}
if (PR_FALSE==IsColumnWidthsValid())
{
if (PR_TRUE==gsDebugIR) printf("TIF Reflow: Re-init layout strategy\n");
if (nsnull!=mTableLayoutStrategy)
{
mTableLayoutStrategy->Initialize(aDesiredSize.maxElementSize);
mColumnWidthsValid=PR_TRUE;
}
}
if (nsnull==mPrevInFlow)
{ // only do this for a first-in-flow table frame
@ -1707,6 +1719,7 @@ NS_METHOD nsTableFrame::ResizeReflowPass1(nsIPresContext& aPresContext,
PRInt32 yCoord = y;
if (NS_UNCONSTRAINEDSIZE!=yCoord)
yCoord+= topInset;
if (PR_TRUE==gsDebugIR) printf("\nTIF IR: Reflow Pass 1 of frame %p\n", kidFrame);
ReflowChild(kidFrame, aPresContext, kidSize, kidReflowState, aStatus);
// Place the child since some of its content fit in us.
@ -1875,7 +1888,8 @@ NS_METHOD nsTableFrame::IR_TargetIsMe(nsIPresContext& aPresContext,
InnerTableReflowState& aReflowState,
nsReflowStatus& aStatus)
{
nsresult rv = NS_FRAME_COMPLETE;
nsresult rv = NS_OK;
aStatus = NS_FRAME_COMPLETE;
nsIReflowCommand::ReflowType type;
aReflowState.reflowState.reflowCommand->GetType(type);
nsIFrame *objectFrame;
@ -1962,7 +1976,7 @@ NS_METHOD nsTableFrame::IR_TargetIsMe(nsIPresContext& aPresContext,
case nsIReflowCommand::UserDefined :
NS_NOTYETIMPLEMENTED("unimplemented reflow command type");
rv = NS_ERROR_NOT_IMPLEMENTED;
if (PR_TRUE==gsDebugIR) printf("TOF IR: reflow command not implemented.\n");
if (PR_TRUE==gsDebugIR) printf("TIF IR: reflow command not implemented.\n");
break;
}
@ -2172,6 +2186,13 @@ NS_METHOD nsTableFrame::IR_RowGroupInserted(nsIPresContext& aPresContext,
nsresult rv = IR_UnknownFrameInserted(aPresContext, aDesiredSize, aReflowState,
aStatus, (nsIFrame*)aInsertedFrame, aReplace);
// inserting the rowgroup only effects reflow if the rowgroup includes at least one row
PRInt32 rowCount;
aInsertedFrame->GetRowCount(rowCount);
if (0>rowCount)
{ // for now we will assume that if there are rows, then there are cells and we need to recalc table info
InvalidateCellMap();
InvalidateColumnCache();
}
return rv;
}
@ -2189,6 +2210,7 @@ NS_METHOD nsTableFrame::IR_RowGroupAppended(nsIPresContext& aPresContext,
return rv;
// account for the cells in the rows that are children of aAppendedFrame
// this will add the content of the rowgroup to the cell map
rv = DidAppendRowGroup((nsTableRowGroupFrame*)aAppendedFrame);
// do a pass-1 layout of all the cells in all the rows of the rowgroup
@ -2198,7 +2220,8 @@ NS_METHOD nsTableFrame::IR_RowGroupAppended(nsIPresContext& aPresContext,
return rv;
// if any column widths have to change due to this, rebalance column widths
mTableLayoutStrategy->Initialize(aDesiredSize.maxElementSize);
//XXX need to calculate this, but for now just do it
InvalidateColumnWidths();
return rv;
}
@ -2210,6 +2233,20 @@ NS_METHOD nsTableFrame::IR_RowGroupRemoved(nsIPresContext& aPresContext,
nsTableRowGroupFrame * aDeletedFrame)
{
nsresult rv;
rv = IR_UnknownFrameRemoved(aPresContext, aDesiredSize, aReflowState, aStatus,
aDeletedFrame);
PRInt32 rowCount=0;
aDeletedFrame->GetRowCount(rowCount);
if (0>rowCount)
{ // for now we will assume that if there are rows, then there are cells and we need to recalc table info
InvalidateCellMap();
InvalidateColumnCache();
}
// if any column widths have to change due to this, rebalance column widths
//XXX need to calculate this, but for now just do it
InvalidateColumnWidths();
return rv;
}
@ -2262,7 +2299,8 @@ NS_METHOD nsTableFrame::IR_UnknownFrameInserted(nsIPresContext& aPresCont
aInsertedFrame->SetNextSibling(nextSibling);
}
}
return NS_FRAME_COMPLETE;
aStatus = NS_FRAME_COMPLETE;
return NS_OK;
}
NS_METHOD nsTableFrame::IR_UnknownFrameRemoved(nsIPresContext& aPresContext,
@ -2287,7 +2325,8 @@ NS_METHOD nsTableFrame::IR_UnknownFrameRemoved(nsIPresContext& aPresConte
mFirstChild = nextChild;
else
prevChild->SetNextSibling(nextChild);
return NS_FRAME_COMPLETE;
aStatus = NS_FRAME_COMPLETE;
return NS_OK;;
}
NS_METHOD nsTableFrame::IR_TargetIsChild(nsIPresContext& aPresContext,
@ -2322,10 +2361,7 @@ NS_METHOD nsTableFrame::IR_TargetIsChild(nsIPresContext& aPresContext,
// XXX For the time being just fall through and treat it like a
// pass 2 reflow...
// calling intialize here resets all the cached info based on new table content
if (nsnull!=mTableLayoutStrategy)
{
mTableLayoutStrategy->Initialize(aDesiredSize.maxElementSize);
}
InvalidateColumnWidths();
#else
// XXX Hack...
AdjustSiblingsAfterReflow(&aPresContext, aReflowState, aNextFrame, desiredSize.height -
@ -2459,6 +2495,7 @@ void nsTableFrame::PlaceChild(nsIPresContext& aPresContext,
* @return true if we successfully reflowed all the mapped children and false
* otherwise, e.g. we pushed children to the next in flow
*/
// XXX: this interface should change to pass in aStatus, return nsresult
PRBool nsTableFrame::ReflowMappedChildren( nsIPresContext& aPresContext,
InnerTableReflowState& aState,
nsSize* aMaxElementSize)
@ -2518,6 +2555,7 @@ PRBool nsTableFrame::ReflowMappedChildren( nsIPresContext& aPresContext,
nscoord x = aState.leftInset + kidMargin.left;
nscoord y = aState.topInset + aState.y + topMargin;
if (PR_TRUE==gsDebugIR) printf("\nTIF IR: Reflow Pass 2 of frame %p\n", kidFrame);
ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState, status);
// Did the child fit?
if ((kidFrame != mFirstChild) && (desiredSize.height > kidAvailSize.height))
@ -2800,6 +2838,7 @@ void nsTableFrame::BalanceColumnWidths(nsIPresContext& aPresContext,
else
mTableLayoutStrategy = new BasicTableLayoutStrategy(this, numCols);
mTableLayoutStrategy->Initialize(aMaxElementSize);
mColumnWidthsValid=PR_TRUE;
}
mTableLayoutStrategy->BalanceColumnWidths(mStyleContext, aReflowState, maxWidth);
mColumnWidthsSet=PR_TRUE;
@ -3024,11 +3063,10 @@ PRBool nsTableFrame::IsColumnWidthsSet()
* Then we terminate that loop and start a second pass.
* In the second pass, we build column and cell cache info.
*/
void nsTableFrame::BuildColumnCache( nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
void nsTableFrame::BuildColumnCache( nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus
)
nsReflowStatus& aStatus)
{
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!");
@ -3124,6 +3162,20 @@ void nsTableFrame::BuildColumnCache( nsIPresContext& aPresContext,
mColumnCacheValid=PR_TRUE;
}
void nsTableFrame::InvalidateColumnWidths()
{
nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();
NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow");
firstInFlow->mColumnWidthsValid=PR_FALSE;
}
PRBool nsTableFrame::IsColumnWidthsValid() const
{
nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();
NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow");
return firstInFlow->mColumnWidthsValid;
}
PRBool nsTableFrame::IsFirstPassValid() const
{
nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();

View File

@ -447,11 +447,16 @@ protected:
/** returns PR_TRUE if the cached column info is still valid */
virtual PRBool IsColumnCacheValid() const;
/** returns PR_TRUE if the cached column info is still valid */
virtual PRBool IsColumnWidthsValid() const;
public:
virtual void InvalidateFirstPassCache();
virtual void InvalidateColumnCache();
virtual void InvalidateColumnWidths();
protected:
/** do post processing to setting up style information for the frame */
NS_IMETHOD DidSetStyleContext(nsIPresContext& aPresContext);
@ -600,9 +605,10 @@ private:
PRInt32 *mColumnWidths; // widths of each column
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 mColumnCacheValid; // PR_TRUE if column cache info is still legit
PRBool mCellMapValid; // PR_TRUE if cell map data is still legit
PRBool mColumnWidthsValid; // PR_TRUE if column width data is still legit, PR_FALSE if it needs to be recalculated
PRBool mFirstPassValid; // PR_TRUE if first pass data is still legit, PR_FALSE if it needs to be recalculated
PRBool mColumnCacheValid; // PR_TRUE if column cache info is still legit, PR_FALSE if it needs to be recalculated
PRBool mCellMapValid; // PR_TRUE if cell map data is still legit, PR_FALSE if it needs to be recalculated
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

@ -35,7 +35,13 @@ NS_DEF_PTR(nsIStyleContext);
static NS_DEFINE_IID(kIHTMLTableColElementIID, NS_IHTMLTABLECOLELEMENT_IID);
#ifdef NS_DEBUG
static PRBool gsDebug = PR_FALSE;
static PRBool gsDebugIR = PR_FALSE;
#else
static const PRBool gsDebug = PR_FALSE;
static const PRBool gsDebugIR = PR_FALSE;
#endif
nsTableColGroupFrame::nsTableColGroupFrame(nsIContent* aContent,
nsIFrame* aParentFrame)
@ -48,7 +54,7 @@ nsTableColGroupFrame::~nsTableColGroupFrame()
{
}
nsresult
NS_IMETHODIMP
nsTableColGroupFrame::InitNewFrames(nsIPresContext& aPresContext, nsIFrame* aChildList)
{
nsresult rv=NS_OK;
@ -75,7 +81,6 @@ nsTableColGroupFrame::InitNewFrames(nsIPresContext& aPresContext, nsIFrame* aChi
PRInt32 colIndex = mStartColIndex + mColCount;
((nsTableColFrame *)(kidFrame))->InitColFrame (colIndex, repeat);
mColCount+= repeat;
((nsTableColFrame *)kidFrame)->SetColumnIndex(colIndex);
tableFrame->AddColumnFrame((nsTableColFrame *)kidFrame);
}
// colgroup's span attribute is how many columns the group represents
@ -138,7 +143,7 @@ nsTableColGroupFrame::InitNewFrames(nsIPresContext& aPresContext, nsIFrame* aChi
return rv;
}
nsresult
NS_IMETHODIMP
nsTableColGroupFrame::AppendNewFrames(nsIPresContext& aPresContext, nsIFrame* aChildList)
{
nsIFrame* lastChild = LastFrame(mFirstChild);
@ -171,38 +176,19 @@ NS_METHOD nsTableColGroupFrame::Paint(nsIPresContext& aPresContext,
return NS_OK;
}
// TODO: incremental reflow
// today, we just throw away the column frames and start over every time
// this is dumb, we should be able to maintain column frames and adjust incrementally
NS_METHOD nsTableColGroupFrame::Reflow(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus)
{
NS_ASSERTION(nsnull!=mContent, "bad state -- null content for frame");
nsresult rv=NS_OK;
// for every content child that (is a column thingy and does not already have a frame)
// create a frame and adjust it's style
nsIFrame* kidFrame = nsnull;
if (eReflowReason_Incremental == aReflowState.reason) {
NS_ASSERTION(nsnull != aReflowState.reflowCommand, "null reflow command");
// Get the type of reflow command
nsIReflowCommand::ReflowType reflowCmdType;
aReflowState.reflowCommand->GetType(reflowCmdType);
// Currently we only expect appended reflow commands
NS_ASSERTION(nsIReflowCommand::FrameAppended == reflowCmdType,
"unexpected reflow command");
// Get the new column frames
nsIFrame* childList;
aReflowState.reflowCommand->GetChildFrame(childList);
// Append them to the child list
AppendNewFrames(aPresContext, childList);
InitNewFrames(aPresContext, childList);
rv = IncrementalReflow(aPresContext, aDesiredSize, aReflowState, aStatus);
}
for (kidFrame = mFirstChild; nsnull != kidFrame; kidFrame->GetNextSibling(kidFrame)) {
@ -228,9 +214,355 @@ NS_METHOD nsTableColGroupFrame::Reflow(nsIPresContext& aPresContext,
aDesiredSize.maxElementSize->height=0;
}
aStatus = NS_FRAME_COMPLETE;
return rv;
}
NS_METHOD nsTableColGroupFrame::IncrementalReflow(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus)
{
if (PR_TRUE==gsDebugIR) printf("\nTCGF IR: IncrementalReflow\n");
nsresult rv = NS_OK;
// 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, aReflowState, aStatus);
else
{
// Get the next frame in the reflow chain
nsIFrame* nextFrame;
aReflowState.reflowCommand->GetNext(nextFrame);
rv = IR_TargetIsChild(aPresContext, aDesiredSize, aReflowState, aStatus, nextFrame);
}
}
return rv;
}
NS_METHOD nsTableColGroupFrame::IR_TargetIsMe(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus)
{
nsresult rv = NS_OK;
aStatus = NS_FRAME_COMPLETE;
nsIReflowCommand::ReflowType type;
aReflowState.reflowCommand->GetType(type);
nsIFrame *objectFrame;
aReflowState.reflowCommand->GetChildFrame(objectFrame);
const nsStyleDisplay *childDisplay;
objectFrame->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay));
if (PR_TRUE==gsDebugIR) printf("nTCGF IR: IncrementalReflow_TargetIsMe with type=%d\n", type);
switch (type)
{
case nsIReflowCommand::FrameInserted :
if (NS_STYLE_DISPLAY_TABLE_COLUMN == childDisplay->mDisplay)
{
rv = IR_ColInserted(aPresContext, aDesiredSize, aReflowState, aStatus,
(nsTableColFrame*)objectFrame, PR_FALSE);
}
else
{
rv = IR_UnknownFrameInserted(aPresContext, aDesiredSize, aReflowState, aStatus,
objectFrame, PR_FALSE);
}
break;
case nsIReflowCommand::FrameAppended :
if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == childDisplay->mDisplay)
{
rv = IR_ColAppended(aPresContext, aDesiredSize, aReflowState, aStatus,
(nsTableColFrame*)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_COLUMN_GROUP == childDisplay->mDisplay)
{
rv = IR_ColRemoved(aPresContext, aDesiredSize, aReflowState, aStatus,
(nsTableColFrame*)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("TCGF 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("TCGF IR: reflow command not implemented.\n");
break;
}
return rv;
}
NS_METHOD nsTableColGroupFrame::IR_ColInserted(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus,
nsTableColFrame * aInsertedFrame,
PRBool aReplace)
{
nsresult rv=NS_OK;
PRBool adjustStartingColIndex=PR_FALSE;
rv = IR_UnknownFrameInserted(aPresContext, aDesiredSize, aReflowState, aStatus, aInsertedFrame, aReplace);
if (NS_FAILED(rv))
return rv;
PRInt32 startingColIndex=mStartColIndex;
startingColIndex += GetColumnCount(); // has the side effect of resetting all column indexes
nsIFrame *childFrame=nsnull;
GetNextSibling(childFrame);
while ((NS_SUCCEEDED(rv)) && (nsnull!=childFrame))
{
const nsStyleDisplay *display;
childFrame->GetStyleData(eStyleStruct_Display, (nsStyleStruct *&)display);
if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == display->mDisplay)
{
startingColIndex += ((nsTableColGroupFrame *)childFrame)->SetStartColumnIndex(startingColIndex);
}
rv = childFrame->GetNextSibling(childFrame);
}
nsTableFrame* tableFrame=nsnull;
rv = nsTableFrame::GetTableFrame(this, tableFrame);
if ((NS_SUCCEEDED(rv)) && (nsnull!=tableFrame))
tableFrame->InvalidateColumnCache();
//XXX: what we want to do here is determine if the new COL information changes anything about layout
// if not, we can skip rebalancing the columns
return rv;
}
NS_METHOD nsTableColGroupFrame::IR_ColAppended(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus,
nsTableColFrame * aAppendedFrame)
{
nsresult rv=NS_OK;
PRBool adjustStartingColIndex=PR_FALSE;
rv = IR_UnknownFrameInserted(aPresContext, aDesiredSize, aReflowState, aStatus, aAppendedFrame, PR_FALSE);
if (NS_FAILED(rv))
return rv;
PRInt32 startingColIndex=mStartColIndex;
// this could be optimized
startingColIndex += GetColumnCount(); // has the side effect of resetting all column indexes
nsIFrame *childFrame=nsnull;
GetNextSibling(childFrame);
while ((NS_SUCCEEDED(rv)) && (nsnull!=childFrame))
{
const nsStyleDisplay *display;
childFrame->GetStyleData(eStyleStruct_Display, (nsStyleStruct *&)display);
if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == display->mDisplay)
{
startingColIndex += ((nsTableColGroupFrame *)childFrame)->SetStartColumnIndex(startingColIndex);
}
rv = childFrame->GetNextSibling(childFrame);
}
// today we need to rebuild the whole column cache
// if the table frame is ever recoded to build the column cache incrementally, we could take
// advantage of that here.
nsTableFrame* tableFrame=nsnull;
rv = nsTableFrame::GetTableFrame(this, tableFrame);
if ((NS_SUCCEEDED(rv)) && (nsnull!=tableFrame))
tableFrame->InvalidateColumnCache();
return rv;
}
NS_METHOD nsTableColGroupFrame::IR_ColRemoved(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus,
nsTableColFrame * aDeletedFrame)
{
nsresult rv=NS_OK;
PRInt32 startingColIndex=mStartColIndex;
nsIFrame *childFrame=mFirstChild;
nsIFrame *prevSib=nsnull;
while ((NS_SUCCEEDED(rv)) && (nsnull!=childFrame))
{
if (childFrame==aDeletedFrame)
{
nsIFrame *deleteFrameNextSib=nsnull;
aDeletedFrame->GetNextSibling(deleteFrameNextSib);
if (nsnull!=prevSib)
prevSib->SetNextSibling(deleteFrameNextSib);
else
mFirstChild = deleteFrameNextSib;
startingColIndex += GetColumnCount(); // resets all column indexes
}
const nsStyleDisplay *display;
childFrame->GetStyleData(eStyleStruct_Display, (nsStyleStruct *&)display);
if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == display->mDisplay)
{
// we've removed aDeletedFrame, now adjust the starting col index of all subsequent col groups
startingColIndex += ((nsTableColGroupFrame *)childFrame)->SetStartColumnIndex(startingColIndex);
}
prevSib=childFrame;
rv = childFrame->GetNextSibling(childFrame);
}
// today we need to rebuild the whole column cache
// if the table frame is ever recoded to build the column cache incrementally, we could take
// advantage of that here.
nsTableFrame* tableFrame=nsnull;
rv = nsTableFrame::GetTableFrame(this, tableFrame);
if ((NS_SUCCEEDED(rv)) && (nsnull!=tableFrame))
tableFrame->InvalidateColumnCache();
return rv;
}
//XXX: handle aReplace
NS_METHOD nsTableColGroupFrame::IR_UnknownFrameInserted(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aInsertedFrame,
PRBool aReplace)
{
nsIReflowCommand::ReflowType type;
aReflowState.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("TCGF 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("TCGF IR: FrameInserted adding unknown frame type.\n");
nsIFrame *prevSibling=nsnull;
nsresult rv = aReflowState.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);
}
}
aStatus = NS_FRAME_COMPLETE;
return NS_OK;
}
NS_METHOD nsTableColGroupFrame::IR_UnknownFrameRemoved(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& 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("TCGF 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);
aStatus = NS_FRAME_COMPLETE;
return NS_OK;
}
NS_METHOD nsTableColGroupFrame::IR_TargetIsChild(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aNextFrame)
{
nsresult rv;
if (PR_TRUE==gsDebugIR) printf("\nTCGF IR: IR_TargetIsChild\n");
// Remember the old col count
const PRInt32 oldColCount = GetColumnCount();
// Pass along the reflow command
nsHTMLReflowMetrics desiredSize(nsnull);
nsHTMLReflowState kidReflowState(aPresContext, aNextFrame,
aReflowState,
aReflowState.maxSize);
rv = ReflowChild(aNextFrame, aPresContext, desiredSize, kidReflowState, aStatus);
if (NS_FAILED(rv))
return rv;
nsTableFrame *tableFrame=nsnull;
rv = nsTableFrame::GetTableFrame(this, tableFrame);
if ((NS_SUCCEEDED(rv)) && (nsnull!=tableFrame))
{
// compare the new col count to the old col count.
// If they are the same, we just need to rebalance column widths
// If they differ, we need to fix up other column groups and the column cache
const PRInt32 newColCount = GetColumnCount(); // this will set the new column indexes if necessary
if (oldColCount==newColCount)
tableFrame->InvalidateColumnWidths();
else
tableFrame->InvalidateColumnCache();
}
return rv;
}
// Subclass hook for style post processing
NS_METHOD nsTableColGroupFrame::SetStyleContextForFirstPass(nsIPresContext& aPresContext)
{

View File

@ -102,11 +102,63 @@ protected:
* Since we need to know the full column structure before the COLS attribute
* can be interpreted, we can't just use DidSetStyleContext
*/
NS_METHOD SetStyleContextForFirstPass(nsIPresContext& aPresContext);
NS_IMETHOD SetStyleContextForFirstPass(nsIPresContext& aPresContext);
NS_IMETHOD InitNewFrames(nsIPresContext& aPresContext, nsIFrame* aChildList);
NS_IMETHOD AppendNewFrames(nsIPresContext& aPresContext, nsIFrame* aChildList);
NS_IMETHOD IncrementalReflow(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus);
NS_IMETHOD IR_TargetIsMe(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus);
NS_IMETHOD IR_ColInserted(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus,
nsTableColFrame * aInsertedFrame,
PRBool aReplace);
NS_IMETHOD IR_ColAppended(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus,
nsTableColFrame * aAppendedFrame);
NS_IMETHOD IR_ColRemoved(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus,
nsTableColFrame * aDeletedFrame);
NS_IMETHOD IR_UnknownFrameInserted(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aInsertedFrame,
PRBool aReplace);
NS_IMETHOD IR_UnknownFrameRemoved(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aRemovedFrame);
NS_IMETHOD IR_TargetIsChild(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame * aNextFrame);
// data members
nsresult InitNewFrames(nsIPresContext& aPresContext, nsIFrame* aChildList);
nsresult AppendNewFrames(nsIPresContext& aPresContext, nsIFrame* aChildList);
PRInt32 mColCount;
/** the starting column index this col group represents. Must be >= 0. */

View File

@ -52,7 +52,6 @@ static const PRBool gsDebug = PR_FALSE;
static const PRBool gsDebugCLD = PR_FALSE;
static const PRBool gsDebugNT = PR_FALSE;
static const PRBool gsDebugIR = PR_FALSE;
#endif
#ifndef max
@ -271,6 +270,7 @@ nsTableFrame::nsTableFrame(nsIContent* aContent, nsIFrame* aParentFrame)
mColCache(nsnull),
mTableLayoutStrategy(nsnull),
mFirstPassValid(PR_FALSE),
mColumnWidthsValid(PR_FALSE),
mColumnCacheValid(PR_FALSE),
mCellMapValid(PR_TRUE),
mIsInvariantWidth(PR_FALSE)
@ -1565,7 +1565,7 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext& aPresContext,
if (PR_TRUE==gsDebug) printf("TIF Reflow: needs reflow\n");
if (eReflowReason_Initial!=aReflowState.reason && PR_FALSE==IsCellMapValid())
{
if (PR_TRUE==gsDebug) printf("TIF Reflow: not initial reflow, so resetting cell map.\n");
if (PR_TRUE==gsDebug) printf("TIF Reflow: cell map invalid, rebuilding...\n");
if (nsnull!=mCellMap)
delete mCellMap;
mCellMap = new nsCellMap(0,0);
@ -1574,14 +1574,17 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext& aPresContext,
}
if (PR_FALSE==IsFirstPassValid())
{
if (PR_TRUE==gsDebug || PR_TRUE==gsDebugIR) printf("TIF Reflow: first pass is invalid\n");
if (PR_TRUE==gsDebug || PR_TRUE==gsDebugIR) printf("TIF Reflow: first pass is invalid, rebuilding...\n");
rv = ResizeReflowPass1(aPresContext, aDesiredSize, aReflowState, aStatus, nsnull, aReflowState.reason);
if (NS_FAILED(rv))
return rv;
needsRecalc=PR_TRUE;
}
if (PR_FALSE==IsColumnCacheValid())
{
if (PR_TRUE==gsDebug || PR_TRUE==gsDebugIR) printf("TIF Reflow: column cache is invalid, rebuilding...\n");
needsRecalc=PR_TRUE;
}
if (PR_TRUE==needsRecalc)
{
if (PR_TRUE==gsDebugIR) printf("TIF Reflow: needs recalc.\n");
@ -1590,11 +1593,20 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext& aPresContext,
{
if (PR_TRUE==gsDebugIR) printf("TIF Reflow: Re-init layout strategy\n");
mTableLayoutStrategy->Initialize(aDesiredSize.maxElementSize);
mColumnWidthsValid=PR_TRUE;
}
BuildColumnCache(aPresContext, aDesiredSize, aReflowState, aStatus);
RecalcLayoutData(); // Recalculate Layout Dependencies
}
if (PR_FALSE==IsColumnWidthsValid())
{
if (PR_TRUE==gsDebugIR) printf("TIF Reflow: Re-init layout strategy\n");
if (nsnull!=mTableLayoutStrategy)
{
mTableLayoutStrategy->Initialize(aDesiredSize.maxElementSize);
mColumnWidthsValid=PR_TRUE;
}
}
if (nsnull==mPrevInFlow)
{ // only do this for a first-in-flow table frame
@ -1707,6 +1719,7 @@ NS_METHOD nsTableFrame::ResizeReflowPass1(nsIPresContext& aPresContext,
PRInt32 yCoord = y;
if (NS_UNCONSTRAINEDSIZE!=yCoord)
yCoord+= topInset;
if (PR_TRUE==gsDebugIR) printf("\nTIF IR: Reflow Pass 1 of frame %p\n", kidFrame);
ReflowChild(kidFrame, aPresContext, kidSize, kidReflowState, aStatus);
// Place the child since some of its content fit in us.
@ -1875,7 +1888,8 @@ NS_METHOD nsTableFrame::IR_TargetIsMe(nsIPresContext& aPresContext,
InnerTableReflowState& aReflowState,
nsReflowStatus& aStatus)
{
nsresult rv = NS_FRAME_COMPLETE;
nsresult rv = NS_OK;
aStatus = NS_FRAME_COMPLETE;
nsIReflowCommand::ReflowType type;
aReflowState.reflowState.reflowCommand->GetType(type);
nsIFrame *objectFrame;
@ -1962,7 +1976,7 @@ NS_METHOD nsTableFrame::IR_TargetIsMe(nsIPresContext& aPresContext,
case nsIReflowCommand::UserDefined :
NS_NOTYETIMPLEMENTED("unimplemented reflow command type");
rv = NS_ERROR_NOT_IMPLEMENTED;
if (PR_TRUE==gsDebugIR) printf("TOF IR: reflow command not implemented.\n");
if (PR_TRUE==gsDebugIR) printf("TIF IR: reflow command not implemented.\n");
break;
}
@ -2172,6 +2186,13 @@ NS_METHOD nsTableFrame::IR_RowGroupInserted(nsIPresContext& aPresContext,
nsresult rv = IR_UnknownFrameInserted(aPresContext, aDesiredSize, aReflowState,
aStatus, (nsIFrame*)aInsertedFrame, aReplace);
// inserting the rowgroup only effects reflow if the rowgroup includes at least one row
PRInt32 rowCount;
aInsertedFrame->GetRowCount(rowCount);
if (0>rowCount)
{ // for now we will assume that if there are rows, then there are cells and we need to recalc table info
InvalidateCellMap();
InvalidateColumnCache();
}
return rv;
}
@ -2189,6 +2210,7 @@ NS_METHOD nsTableFrame::IR_RowGroupAppended(nsIPresContext& aPresContext,
return rv;
// account for the cells in the rows that are children of aAppendedFrame
// this will add the content of the rowgroup to the cell map
rv = DidAppendRowGroup((nsTableRowGroupFrame*)aAppendedFrame);
// do a pass-1 layout of all the cells in all the rows of the rowgroup
@ -2198,7 +2220,8 @@ NS_METHOD nsTableFrame::IR_RowGroupAppended(nsIPresContext& aPresContext,
return rv;
// if any column widths have to change due to this, rebalance column widths
mTableLayoutStrategy->Initialize(aDesiredSize.maxElementSize);
//XXX need to calculate this, but for now just do it
InvalidateColumnWidths();
return rv;
}
@ -2210,6 +2233,20 @@ NS_METHOD nsTableFrame::IR_RowGroupRemoved(nsIPresContext& aPresContext,
nsTableRowGroupFrame * aDeletedFrame)
{
nsresult rv;
rv = IR_UnknownFrameRemoved(aPresContext, aDesiredSize, aReflowState, aStatus,
aDeletedFrame);
PRInt32 rowCount=0;
aDeletedFrame->GetRowCount(rowCount);
if (0>rowCount)
{ // for now we will assume that if there are rows, then there are cells and we need to recalc table info
InvalidateCellMap();
InvalidateColumnCache();
}
// if any column widths have to change due to this, rebalance column widths
//XXX need to calculate this, but for now just do it
InvalidateColumnWidths();
return rv;
}
@ -2262,7 +2299,8 @@ NS_METHOD nsTableFrame::IR_UnknownFrameInserted(nsIPresContext& aPresCont
aInsertedFrame->SetNextSibling(nextSibling);
}
}
return NS_FRAME_COMPLETE;
aStatus = NS_FRAME_COMPLETE;
return NS_OK;
}
NS_METHOD nsTableFrame::IR_UnknownFrameRemoved(nsIPresContext& aPresContext,
@ -2287,7 +2325,8 @@ NS_METHOD nsTableFrame::IR_UnknownFrameRemoved(nsIPresContext& aPresConte
mFirstChild = nextChild;
else
prevChild->SetNextSibling(nextChild);
return NS_FRAME_COMPLETE;
aStatus = NS_FRAME_COMPLETE;
return NS_OK;;
}
NS_METHOD nsTableFrame::IR_TargetIsChild(nsIPresContext& aPresContext,
@ -2322,10 +2361,7 @@ NS_METHOD nsTableFrame::IR_TargetIsChild(nsIPresContext& aPresContext,
// XXX For the time being just fall through and treat it like a
// pass 2 reflow...
// calling intialize here resets all the cached info based on new table content
if (nsnull!=mTableLayoutStrategy)
{
mTableLayoutStrategy->Initialize(aDesiredSize.maxElementSize);
}
InvalidateColumnWidths();
#else
// XXX Hack...
AdjustSiblingsAfterReflow(&aPresContext, aReflowState, aNextFrame, desiredSize.height -
@ -2459,6 +2495,7 @@ void nsTableFrame::PlaceChild(nsIPresContext& aPresContext,
* @return true if we successfully reflowed all the mapped children and false
* otherwise, e.g. we pushed children to the next in flow
*/
// XXX: this interface should change to pass in aStatus, return nsresult
PRBool nsTableFrame::ReflowMappedChildren( nsIPresContext& aPresContext,
InnerTableReflowState& aState,
nsSize* aMaxElementSize)
@ -2518,6 +2555,7 @@ PRBool nsTableFrame::ReflowMappedChildren( nsIPresContext& aPresContext,
nscoord x = aState.leftInset + kidMargin.left;
nscoord y = aState.topInset + aState.y + topMargin;
if (PR_TRUE==gsDebugIR) printf("\nTIF IR: Reflow Pass 2 of frame %p\n", kidFrame);
ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState, status);
// Did the child fit?
if ((kidFrame != mFirstChild) && (desiredSize.height > kidAvailSize.height))
@ -2800,6 +2838,7 @@ void nsTableFrame::BalanceColumnWidths(nsIPresContext& aPresContext,
else
mTableLayoutStrategy = new BasicTableLayoutStrategy(this, numCols);
mTableLayoutStrategy->Initialize(aMaxElementSize);
mColumnWidthsValid=PR_TRUE;
}
mTableLayoutStrategy->BalanceColumnWidths(mStyleContext, aReflowState, maxWidth);
mColumnWidthsSet=PR_TRUE;
@ -3024,11 +3063,10 @@ PRBool nsTableFrame::IsColumnWidthsSet()
* Then we terminate that loop and start a second pass.
* In the second pass, we build column and cell cache info.
*/
void nsTableFrame::BuildColumnCache( nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
void nsTableFrame::BuildColumnCache( nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus
)
nsReflowStatus& aStatus)
{
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!");
@ -3124,6 +3162,20 @@ void nsTableFrame::BuildColumnCache( nsIPresContext& aPresContext,
mColumnCacheValid=PR_TRUE;
}
void nsTableFrame::InvalidateColumnWidths()
{
nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();
NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow");
firstInFlow->mColumnWidthsValid=PR_FALSE;
}
PRBool nsTableFrame::IsColumnWidthsValid() const
{
nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();
NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow");
return firstInFlow->mColumnWidthsValid;
}
PRBool nsTableFrame::IsFirstPassValid() const
{
nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();

View File

@ -447,11 +447,16 @@ protected:
/** returns PR_TRUE if the cached column info is still valid */
virtual PRBool IsColumnCacheValid() const;
/** returns PR_TRUE if the cached column info is still valid */
virtual PRBool IsColumnWidthsValid() const;
public:
virtual void InvalidateFirstPassCache();
virtual void InvalidateColumnCache();
virtual void InvalidateColumnWidths();
protected:
/** do post processing to setting up style information for the frame */
NS_IMETHOD DidSetStyleContext(nsIPresContext& aPresContext);
@ -600,9 +605,10 @@ private:
PRInt32 *mColumnWidths; // widths of each column
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 mColumnCacheValid; // PR_TRUE if column cache info is still legit
PRBool mCellMapValid; // PR_TRUE if cell map data is still legit
PRBool mColumnWidthsValid; // PR_TRUE if column width data is still legit, PR_FALSE if it needs to be recalculated
PRBool mFirstPassValid; // PR_TRUE if first pass data is still legit, PR_FALSE if it needs to be recalculated
PRBool mColumnCacheValid; // PR_TRUE if column cache info is still legit, PR_FALSE if it needs to be recalculated
PRBool mCellMapValid; // PR_TRUE if cell map data is still legit, PR_FALSE if it needs to be recalculated
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