bug 131020 - process special height reflow when initiator is the containing table. a=roc+moz, sr=attinasi, r=bernd.

This commit is contained in:
karnaze%netscape.com 2002-04-01 06:46:17 +00:00
Родитель b543d6d14c
Коммит 130ae15711
16 изменённых файлов: 470 добавлений и 184 удалений

Просмотреть файл

@ -225,6 +225,9 @@ struct nsHTMLReflowState {
// reflow for percent height calculations // reflow for percent height calculations
nsIPercentHeightObserver* mPercentHeightObserver; nsIPercentHeightObserver* mPercentHeightObserver;
// a frame (e.g. nsTableFrame) which initiates a special reflow for percent height calculations
nsIFrame* mPercentHeightReflowInitiator;
// This value keeps track of how deeply nested a given reflow state // This value keeps track of how deeply nested a given reflow state
// is from the top of the frame tree. // is from the top of the frame tree.
PRInt16 mReflowDepth; PRInt16 mReflowDepth;

Просмотреть файл

@ -80,7 +80,6 @@ class nsIView;
class nsIWidget; class nsIWidget;
class nsIDOMRange; class nsIDOMRange;
class nsISelectionController; class nsISelectionController;
class nsIPercentHeightObserver;
#ifdef ACCESSIBILITY #ifdef ACCESSIBILITY
class nsIAccessible; class nsIAccessible;
#endif #endif

Просмотреть файл

@ -101,6 +101,7 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext,
mLineLayout = nsnull; mLineLayout = nsnull;
mFlags.mIsTopOfPage = PR_FALSE; mFlags.mIsTopOfPage = PR_FALSE;
mPercentHeightObserver = nsnull; mPercentHeightObserver = nsnull;
mPercentHeightReflowInitiator = nsnull;
Init(aPresContext); Init(aPresContext);
#ifdef IBMBIDI #ifdef IBMBIDI
mRightEdge = NS_UNCONSTRAINEDSIZE; mRightEdge = NS_UNCONSTRAINEDSIZE;
@ -130,6 +131,7 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext,
mLineLayout = nsnull; mLineLayout = nsnull;
mFlags.mIsTopOfPage = PR_FALSE; mFlags.mIsTopOfPage = PR_FALSE;
mPercentHeightObserver = nsnull; mPercentHeightObserver = nsnull;
mPercentHeightReflowInitiator = nsnull;
Init(aPresContext); Init(aPresContext);
#ifdef IBMBIDI #ifdef IBMBIDI
mRightEdge = NS_UNCONSTRAINEDSIZE; mRightEdge = NS_UNCONSTRAINEDSIZE;
@ -162,6 +164,7 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext,
mLineLayout = aParentReflowState.mLineLayout; mLineLayout = aParentReflowState.mLineLayout;
mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage; mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage;
mPercentHeightObserver = aParentReflowState.mPercentHeightObserver; mPercentHeightObserver = aParentReflowState.mPercentHeightObserver;
mPercentHeightReflowInitiator = aParentReflowState.mPercentHeightReflowInitiator;
if (aInit) { if (aInit) {
Init(aPresContext); Init(aPresContext);
@ -193,6 +196,7 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext,
mLineLayout = aParentReflowState.mLineLayout; mLineLayout = aParentReflowState.mLineLayout;
mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage; mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage;
mPercentHeightObserver = aParentReflowState.mPercentHeightObserver; mPercentHeightObserver = aParentReflowState.mPercentHeightObserver;
mPercentHeightReflowInitiator = aParentReflowState.mPercentHeightReflowInitiator;
Init(aPresContext); Init(aPresContext);
@ -223,6 +227,7 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext,
mLineLayout = aParentReflowState.mLineLayout; mLineLayout = aParentReflowState.mLineLayout;
mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage; mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage;
mPercentHeightObserver = aParentReflowState.mPercentHeightObserver; mPercentHeightObserver = aParentReflowState.mPercentHeightObserver;
mPercentHeightReflowInitiator = aParentReflowState.mPercentHeightReflowInitiator;
Init(aPresContext, aContainingBlockWidth, aContainingBlockHeight); Init(aPresContext, aContainingBlockWidth, aContainingBlockHeight);

Просмотреть файл

@ -225,6 +225,9 @@ struct nsHTMLReflowState {
// reflow for percent height calculations // reflow for percent height calculations
nsIPercentHeightObserver* mPercentHeightObserver; nsIPercentHeightObserver* mPercentHeightObserver;
// a frame (e.g. nsTableFrame) which initiates a special reflow for percent height calculations
nsIFrame* mPercentHeightReflowInitiator;
// This value keeps track of how deeply nested a given reflow state // This value keeps track of how deeply nested a given reflow state
// is from the top of the frame tree. // is from the top of the frame tree.
PRInt16 mReflowDepth; PRInt16 mReflowDepth;

Просмотреть файл

@ -80,7 +80,6 @@ class nsIView;
class nsIWidget; class nsIWidget;
class nsIDOMRange; class nsIDOMRange;
class nsISelectionController; class nsISelectionController;
class nsIPercentHeightObserver;
#ifdef ACCESSIBILITY #ifdef ACCESSIBILITY
class nsIAccessible; class nsIAccessible;
#endif #endif

Просмотреть файл

@ -101,6 +101,7 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext,
mLineLayout = nsnull; mLineLayout = nsnull;
mFlags.mIsTopOfPage = PR_FALSE; mFlags.mIsTopOfPage = PR_FALSE;
mPercentHeightObserver = nsnull; mPercentHeightObserver = nsnull;
mPercentHeightReflowInitiator = nsnull;
Init(aPresContext); Init(aPresContext);
#ifdef IBMBIDI #ifdef IBMBIDI
mRightEdge = NS_UNCONSTRAINEDSIZE; mRightEdge = NS_UNCONSTRAINEDSIZE;
@ -130,6 +131,7 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext,
mLineLayout = nsnull; mLineLayout = nsnull;
mFlags.mIsTopOfPage = PR_FALSE; mFlags.mIsTopOfPage = PR_FALSE;
mPercentHeightObserver = nsnull; mPercentHeightObserver = nsnull;
mPercentHeightReflowInitiator = nsnull;
Init(aPresContext); Init(aPresContext);
#ifdef IBMBIDI #ifdef IBMBIDI
mRightEdge = NS_UNCONSTRAINEDSIZE; mRightEdge = NS_UNCONSTRAINEDSIZE;
@ -162,6 +164,7 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext,
mLineLayout = aParentReflowState.mLineLayout; mLineLayout = aParentReflowState.mLineLayout;
mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage; mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage;
mPercentHeightObserver = aParentReflowState.mPercentHeightObserver; mPercentHeightObserver = aParentReflowState.mPercentHeightObserver;
mPercentHeightReflowInitiator = aParentReflowState.mPercentHeightReflowInitiator;
if (aInit) { if (aInit) {
Init(aPresContext); Init(aPresContext);
@ -193,6 +196,7 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext,
mLineLayout = aParentReflowState.mLineLayout; mLineLayout = aParentReflowState.mLineLayout;
mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage; mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage;
mPercentHeightObserver = aParentReflowState.mPercentHeightObserver; mPercentHeightObserver = aParentReflowState.mPercentHeightObserver;
mPercentHeightReflowInitiator = aParentReflowState.mPercentHeightReflowInitiator;
Init(aPresContext); Init(aPresContext);
@ -223,6 +227,7 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext,
mLineLayout = aParentReflowState.mLineLayout; mLineLayout = aParentReflowState.mLineLayout;
mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage; mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage;
mPercentHeightObserver = aParentReflowState.mPercentHeightObserver; mPercentHeightObserver = aParentReflowState.mPercentHeightObserver;
mPercentHeightReflowInitiator = aParentReflowState.mPercentHeightReflowInitiator;
Init(aPresContext, aContainingBlockWidth, aContainingBlockHeight); Init(aPresContext, aContainingBlockWidth, aContainingBlockHeight);

Просмотреть файл

@ -162,7 +162,7 @@ nsTableCellFrame::NotifyPercentHeight(const nsHTMLReflowState& aReflowState)
if (!HadSpecialReflow()) { if (!HadSpecialReflow()) {
// Only initiate a special reflow if we will be able to construct a computed height // Only initiate a special reflow if we will be able to construct a computed height
// on the cell that will result in the frame getting a computed height. This can only // on the cell that will result in the frame getting a computed height. This can only
// happen (but not sufficient) if there no computed height already set between the // happen (but not sufficient) if there is no computed height already set between the
// initiating frame and the cell. // initiating frame and the cell.
for (const nsHTMLReflowState* rs = aReflowState.parentReflowState; rs; rs = rs->parentReflowState) { for (const nsHTMLReflowState* rs = aReflowState.parentReflowState; rs; rs = rs->parentReflowState) {
if ((NS_UNCONSTRAINEDSIZE != rs->mComputedHeight) && (0 != rs->mComputedHeight)) { if ((NS_UNCONSTRAINEDSIZE != rs->mComputedHeight) && (0 != rs->mComputedHeight)) {
@ -170,8 +170,7 @@ nsTableCellFrame::NotifyPercentHeight(const nsHTMLReflowState& aReflowState)
} }
// stop when we reach the cell frame // stop when we reach the cell frame
if (rs->frame == this) { if (rs->frame == this) {
nsTableFrame::NotifyAncestorsOfSpecialReflow((nsIFrame&)*this); nsTableFrame::RequestSpecialHeightReflow(*rs);
SetNeedSpecialReflow(PR_TRUE);
return NS_OK; return NS_OK;
} }
} }
@ -798,14 +797,9 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext,
nsresult rv = NS_OK; nsresult rv = NS_OK;
if ((NS_UNCONSTRAINEDSIZE != aReflowState.availableWidth) && // see if a special height reflow needs to occur due to having a pct height
((NS_UNCONSTRAINEDSIZE == aReflowState.mComputedHeight) || nsTableFrame::CheckRequestSpecialHeightReflow(aReflowState);
(0 == aReflowState.mComputedHeight)) &&
!mPrevInFlow &&
nsTableFrame::IsPctHeight(mStyleContext)) {
nsTableFrame::NotifyAncestorsOfSpecialReflow(*this);
SetNeedSpecialReflow(PR_TRUE);
}
// this should probably be cached somewhere // this should probably be cached somewhere
nsCompatibility compatMode; nsCompatibility compatMode;
aPresContext->GetCompatibilityMode(&compatMode); aPresContext->GetCompatibilityMode(&compatMode);

Просмотреть файл

@ -1843,61 +1843,188 @@ ProcessRowInserted(nsIPresContext* aPresContext,
} }
} }
void // Return true if aStylePosition has a pct height
nsTableFrame::NotifyAncestorsOfSpecialReflow(nsIFrame& aFrame) static PRBool
IsPctStyleHeight(const nsStylePosition* aStylePosition)
{ {
nsIFrame* parent; return (aStylePosition &&
for (aFrame.GetParent(&parent); parent; parent->GetParent(&parent)) { (eStyleUnit_Percent == aStylePosition->mHeight.GetUnit()));
}
// Return true if aStylePosition has a coord height
static PRBool
IsFixedStyleHeight(const nsStylePosition* aStylePosition)
{
return (aStylePosition &&
(eStyleUnit_Coord == aStylePosition->mHeight.GetUnit()));
}
// Return true if any of aReflowState.frame's ancestors within the containing table
// have a pct or fixed height
static PRBool
AncestorsHaveStyleHeight(const nsHTMLReflowState& aReflowState)
{
for (const nsHTMLReflowState* parentRS = aReflowState.parentReflowState;
parentRS && parentRS->frame;
parentRS = parentRS->parentReflowState) {
nsCOMPtr<nsIAtom> frameType; nsCOMPtr<nsIAtom> frameType;
parent->GetFrameType(getter_AddRefs(frameType)); parentRS->frame->GetFrameType(getter_AddRefs(frameType));
if (IS_TABLE_CELL(frameType.get())) { if (IS_TABLE_CELL(frameType.get()) ||
((nsTableCellFrame*)parent)->SetNeedSpecialReflow(PR_TRUE); (nsLayoutAtoms::tableRowFrame == frameType.get()) ||
} (nsLayoutAtoms::tableRowGroupFrame == frameType.get())) {
else if (nsLayoutAtoms::tableRowFrame == frameType.get()) { if (::IsPctStyleHeight(parentRS->mStylePosition) || ::IsFixedStyleHeight(parentRS->mStylePosition)) {
((nsTableRowFrame*)parent)->SetNeedSpecialReflow(PR_TRUE); return PR_TRUE;
} }
else if (nsLayoutAtoms::tableRowGroupFrame == frameType.get()) {
((nsTableRowGroupFrame*)parent)->SetNeedSpecialReflow(PR_TRUE);
} }
else if (nsLayoutAtoms::tableFrame == frameType.get()) { else if (nsLayoutAtoms::tableFrame == frameType.get()) {
((nsTableFrame*)parent)->SetNeedToInitiateSpecialReflow(PR_TRUE); // we reached the containing table, so always return
break; if (::IsPctStyleHeight(parentRS->mStylePosition) || ::IsFixedStyleHeight(parentRS->mStylePosition)) {
return PR_TRUE;
}
else return PR_FALSE;
}
}
return PR_FALSE;
}
// See if a special height reflow needs to occur and if so, call RequestSpecialHeightReflow
void
nsTableFrame::CheckRequestSpecialHeightReflow(const nsHTMLReflowState& aReflowState)
{
if (!aReflowState.frame) ABORT0();
nsIFrame* prevInFlow;
aReflowState.frame->GetPrevInFlow(&prevInFlow);
if ((NS_UNCONSTRAINEDSIZE != aReflowState.availableWidth) && // not first pass reflow
!prevInFlow && // 1st in flow && // 1st in flow
((NS_UNCONSTRAINEDSIZE == aReflowState.mComputedHeight) || // no computed height
(0 == aReflowState.mComputedHeight)) &&
::IsPctStyleHeight(aReflowState.mStylePosition)) { // pct height
if (::AncestorsHaveStyleHeight(aReflowState)) {
nsTableFrame::RequestSpecialHeightReflow(aReflowState);
} }
} }
} }
static PRBool // Notify the frame and its ancestors (up to the containing table) that a special
IsSpecialNested(const nsHTMLReflowState& aReflowState) // height reflow will occur. During a special height reflow, a table, row group,
// row, or cell returns the last size it was reflowed at. However, the table may
// change the height of row groups, rows, cells in DistributeHeightToRows after.
// And the row group can change the height of rows, cells in CalculateRowHeights.
void
nsTableFrame::RequestSpecialHeightReflow(const nsHTMLReflowState& aReflowState)
{ {
// Walk up the reflow state tree until we find anything with a style height. // notify the frame and its ancestors of the special reflow, stopping at the containing table
// stop when we reach a table for (const nsHTMLReflowState* rs = &aReflowState; rs && rs->frame; rs = rs->parentReflowState) {
const nsHTMLReflowState* rs = aReflowState.parentReflowState;
while (rs && rs->frame) {
const nsStylePosition* position;
rs->frame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)position);
if (eStyleUnit_Coord == position->mHeight.GetUnit()) {
nscoord coordValue = position->mHeight.GetCoordValue();
if (coordValue > 0) return PR_TRUE;
}
else if (eStyleUnit_Percent == position->mHeight.GetUnit()) {
float percent = position->mHeight.GetPercentValue();
if (percent > 0.0f) return PR_TRUE;
}
nsCOMPtr<nsIAtom> frameType; nsCOMPtr<nsIAtom> frameType;
rs->frame->GetFrameType(getter_AddRefs(frameType)); rs->frame->GetFrameType(getter_AddRefs(frameType));
if (nsLayoutAtoms::tableFrame == frameType.get()) break; if (IS_TABLE_CELL(frameType.get())) {
rs = rs->parentReflowState; ((nsTableCellFrame*)rs->frame)->SetNeedSpecialReflow(PR_TRUE);
}
else if (nsLayoutAtoms::tableRowFrame == frameType.get()) {
((nsTableRowFrame*)rs->frame)->SetNeedSpecialReflow(PR_TRUE);
}
else if (nsLayoutAtoms::tableRowGroupFrame == frameType.get()) {
((nsTableRowGroupFrame*)rs->frame)->SetNeedSpecialReflow(PR_TRUE);
}
else if (nsLayoutAtoms::tableFrame == frameType.get()) {
if (rs == &aReflowState) {
// don't stop because we started with this table
((nsTableFrame*)rs->frame)->SetNeedSpecialReflow(PR_TRUE);
}
else {
((nsTableFrame*)rs->frame)->SetNeedToInitiateSpecialReflow(PR_TRUE);
// always stop when we reach a table that we didn't start with
break;
}
}
} }
return PR_FALSE;
} }
/* overview:
if mFirstPassValid is false, this is our first time through since content was last changed // Return true (and set aMetrics's desiredSize to aRect) if the special height reflow
do pass 1 // was initiated by an ancestor of aReflowState.frame's containing table. In that case,
get min/max info for all cells in an infinite space // aFrame's containing table will eventually initiate a special height reflow which
do column balancing // will cause this method to return false.
do pass 2 PRBool
use column widths to size table and ResizeReflow rowgroups (and therefore rows and cells) nsTableFrame::IsPrematureSpecialHeightReflow(const nsHTMLReflowState& aReflowState,
*/ const nsRect& aRect,
PRBool aNeedSpecialHeightReflow,
nsHTMLReflowMetrics& aMetrics)
{
PRBool premature = PR_FALSE;
if (aReflowState.mFlags.mSpecialHeightReflow) {
if (aNeedSpecialHeightReflow) {
nsTableFrame* tableFrame;
nsTableFrame::GetTableFrame(aReflowState.frame, tableFrame);
if (tableFrame && (tableFrame != aReflowState.mPercentHeightReflowInitiator)) {
premature = PR_TRUE;
}
}
else {
premature = PR_TRUE;
}
if (premature) {
aMetrics.width = aRect.width;
aMetrics.height = aRect.height;
}
}
return premature;
}
/******************************************************************************************
* During the initial reflow the table reflows each child with an unconstrained avail width
* to get its max element width and maximum width. This is referred to as the pass 1 reflow.
*
* After the 1st pass reflow, the table determines the column widths using BalanceColumnWidths()
* then reflows each child again with a constrained avail width. This reflow is referred to
* as the pass 2 reflow.
*
* A special height reflow (pass 3 reflow) can occur during an intitial or resize reflow
* if (a) a row group, row, cell, or a frame inside a cell has a percent height but no computed
* height or (b) in paginated mode, a table has a height. (a) supports percent nested tables
* contained inside cells whose heights aren't known until after the pass 2 reflow. (b) is
* necessary because the table cannot split until after the pass 2 reflow. The mechanics of
* the special height reflow (variety a) are as follows:
*
* 1) Each table related frame (table, row group, row, cell) implements NeedsSpecialReflow()
* to indicate that it should get the reflow. It does this when it has a percent height but
* no computed height by calling CheckRequestSpecialHeightReflow(). This method calls
* RequestSpecialHeightReflow() which calls SetNeedSpecialReflow() on its ancestors until
* it reaches the containing table and calls SetNeedToInitiateSpecialReflow() on it. For
* percent height frames inside cells, during DidReflow(), the cell's NotifyPercentHeight()
* is called (the cell is the reflow state's mPercentHeightObserver in this case).
* NotifyPercentHeight() calls RequestSpecialHeightReflow().
*
* 2) After the pass 2 reflow, if the table's NeedToInitiateSpecialReflow(true) was called, it
* will do the special height reflow, setting the reflow state's mFlages.mSpecialHeightReflow
* to true and mSpecialHeightInitiator to itself. It won't do this if IsPrematureSpecialHeightReflow()
* returns true because in that case another special height reflow will be comming along with the
* containing table as the mSpecialHeightInitiator. It is only relevant to do the reflow when
* the mSpecialHeightInitiator is the containing table, because if it is a remote ancestor, then
* appropriate heights will not be known.
*
* 3) Since the heights of the table, row groups, rows, and cells was determined during the pass 2
* reflow, they return their last desired sizes during the special height reflow. The reflow only
* permits percent height frames inside the cells to resize based on the cells height and that height
* was determined during the pass 2 reflow.
*
* So, in the case of deeply nested tables, all of the tables that were told to initiate a special
* reflow will do so, but if a table is already in a special reflow, it won't inititate the reflow
* until the current initiator is its containing table. Since these reflows are only received by
* frames that need them and they don't cause any rebalancing of tables, the extra overhead is minimal.
*
* The type of special reflow that occurs during printing (variety b) follows the same mechanism except
* that all frames will receive the reflow even if they don't really need them.
*
* Open issues with the special height reflow:
*
* 1) At some point there should be 2 kinds of special height reflows because (a) and (b) above are
* really quite different. This would avoid unnecessary reflows during printing.
* 2) When a cell contains frames whose percent heights > 100%, there is data loss (see bug 115245).
* However, this can also occur if a cell has a fixed height and there is no special height reflow.
*
******************************************************************************************/
/* Layout the entire inner table. */ /* Layout the entire inner table. */
NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext, NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext,
@ -1910,6 +2037,14 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext,
#if defined DEBUG_TABLE_REFLOW_TIMING #if defined DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState); nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState);
#endif #endif
PRBool isPaginated;
aPresContext->IsPaginated(&isPaginated);
// If this is a special height reflow, set our desired size to what is was previously and return
// if we will be getting another special height reflow. In paginated mode, SetNeedSpecialReflow(PR_TRUE)
// may not have been called if reflow was a result of having a height on the containing table
if (IsPrematureSpecialHeightReflow(aReflowState, mRect, NeedSpecialReflow() || isPaginated, aDesiredSize))
return NS_OK;
aStatus = NS_FRAME_COMPLETE; aStatus = NS_FRAME_COMPLETE;
if (!mPrevInFlow && !mTableLayoutStrategy) { if (!mPrevInFlow && !mTableLayoutStrategy) {
@ -1918,9 +2053,6 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext,
} }
nsresult rv = NS_OK; nsresult rv = NS_OK;
PRBool isPaginated;
aPresContext->IsPaginated(&isPaginated);
// see if collapsing borders need to be calculated // see if collapsing borders need to be calculated
if (!mPrevInFlow && IsBorderCollapse() && NeedToCalcBCBorders()) { if (!mPrevInFlow && IsBorderCollapse() && NeedToCalcBCBorders()) {
GET_TWIPS_TO_PIXELS(aPresContext, p2t); GET_TWIPS_TO_PIXELS(aPresContext, p2t);
@ -2002,9 +2134,8 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext,
// no computed height, but a height on the containing table // no computed height, but a height on the containing table
if ( ((NS_UNCONSTRAINEDSIZE == aReflowState.mComputedHeight) || if ( ((NS_UNCONSTRAINEDSIZE == aReflowState.mComputedHeight) ||
(0 == aReflowState.mComputedHeight)) && (0 == aReflowState.mComputedHeight)) &&
IsPctHeight(mStyleContext) && IsSpecialNested(aReflowState)) { IsPctHeight(mStyleContext)) {
NotifyAncestorsOfSpecialReflow(*this); nsTableFrame::CheckRequestSpecialHeightReflow(aReflowState);
SetNeedSpecialReflow(PR_TRUE);
} }
// see if an extra reflow will be necessary in pagination mode when there is a specified table height // see if an extra reflow will be necessary in pagination mode when there is a specified table height
else if (isPaginated && (NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight)) { else if (isPaginated && (NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight)) {
@ -2024,11 +2155,20 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext,
ReflowTable(aPresContext, aDesiredSize, aReflowState, availHeight, nextReason, ReflowTable(aPresContext, aDesiredSize, aReflowState, availHeight, nextReason,
lastChildReflowed, doCollapse, balanced, aStatus); lastChildReflowed, doCollapse, balanced, aStatus);
if (!aReflowState.mFlags.mSpecialHeightReflow && NeedToInitiateSpecialReflow() && !NeedSpecialReflow()) { if (NeedToInitiateSpecialReflow() &&
(aReflowState.mFlags.mSpecialHeightReflow || !NeedSpecialReflow())) {
aDesiredSize.height = CalcDesiredHeight(aPresContext, aReflowState); // distributes extra vertical space to rows aDesiredSize.height = CalcDesiredHeight(aPresContext, aReflowState); // distributes extra vertical space to rows
((nsHTMLReflowState::ReflowStateFlags&)aReflowState.mFlags).mSpecialHeightReflow = PR_TRUE;
// save the previous special height reflow initiator, install us as the new one
nsIFrame* specialReflowInitiator = aReflowState.mPercentHeightReflowInitiator;
((nsHTMLReflowState&)aReflowState).mPercentHeightReflowInitiator = this;
((nsHTMLReflowState::ReflowStateFlags&)aReflowState.mFlags).mSpecialHeightReflow = PR_TRUE; ((nsHTMLReflowState::ReflowStateFlags&)aReflowState.mFlags).mSpecialHeightReflow = PR_TRUE;
ReflowTable(aPresContext, aDesiredSize, aReflowState, aReflowState.availableHeight, ReflowTable(aPresContext, aDesiredSize, aReflowState, aReflowState.availableHeight,
nextReason, lastChildReflowed, doCollapse, balanced, aStatus); nextReason, lastChildReflowed, doCollapse, balanced, aStatus);
// restore the previous special height reflow initiator
((nsHTMLReflowState&)aReflowState).mPercentHeightReflowInitiator = specialReflowInitiator;
if (lastChildReflowed && NS_FRAME_IS_NOT_COMPLETE(aStatus)) { if (lastChildReflowed && NS_FRAME_IS_NOT_COMPLETE(aStatus)) {
// if there is an incomplete child, then set the desired height to include it but not the next one // if there is an incomplete child, then set the desired height to include it but not the next one
nsRect childRect; nsRect childRect;
@ -4160,15 +4300,15 @@ nsTableFrame::GetTableFrame(nsIFrame* aSourceFrame,
{ {
nsresult rv = NS_ERROR_UNEXPECTED; // the value returned nsresult rv = NS_ERROR_UNEXPECTED; // the value returned
aTableFrame = nsnull; // initialize out-param aTableFrame = nsnull; // initialize out-param
nsIFrame* parentFrame=nsnull; nsIFrame* parentFrame = nsnull;
if (aSourceFrame) { if (aSourceFrame) {
// "result" is the result of intermediate calls, not the result we return from this method // "result" is the result of intermediate calls, not the result we return from this method
nsresult result = aSourceFrame->GetParent((nsIFrame **)&parentFrame); nsresult result = aSourceFrame->GetParent((nsIFrame **)&parentFrame);
while ((NS_OK==result) && (nsnull!=parentFrame)) { while ((NS_OK == result) && parentFrame) {
const nsStyleDisplay *display; nsCOMPtr<nsIAtom> frameType;
parentFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&)display); parentFrame->GetFrameType(getter_AddRefs(frameType));
if (NS_STYLE_DISPLAY_TABLE == display->mDisplay) { if (nsLayoutAtoms::tableFrame == frameType.get()) {
aTableFrame = (nsTableFrame *)parentFrame; aTableFrame = (nsTableFrame*)parentFrame;
rv = NS_OK; // only set if we found the table frame rv = NS_OK; // only set if we found the table frame
break; break;
} }

Просмотреть файл

@ -218,7 +218,20 @@ public:
float aPixelToTwips, float aPixelToTwips,
nsPixelRound aRound= eAlwaysRoundUp); nsPixelRound aRound= eAlwaysRoundUp);
static void NotifyAncestorsOfSpecialReflow(nsIFrame& aFrame); // See if a special height reflow will occur due to having a pct height when
// the pct height basis may not yet be valid.
static void CheckRequestSpecialHeightReflow(const nsHTMLReflowState& aReflowState);
// Notify the frame and its ancestors (up to the containing table) that a special
// height reflow will occur.
static void RequestSpecialHeightReflow(const nsHTMLReflowState& aReflowState);
// Return true (and set aMetrics's desiredSize to aRect) if the special height reflow
// was not initiated by aReflowState.frame's containing table.
static PRBool IsPrematureSpecialHeightReflow(const nsHTMLReflowState& aReflowState,
const nsRect& aRect,
PRBool aNeedSpecialHeightReflow,
nsHTMLReflowMetrics& aMetrics);
NS_IMETHOD IsPercentageBase(PRBool& aBase) const; NS_IMETHOD IsPercentageBase(PRBool& aBase) const;

Просмотреть файл

@ -1436,25 +1436,8 @@ nsTableRowFrame::Reflow(nsIPresContext* aPresContext,
rv = nsTableFrame::GetTableFrame(this, tableFrame); rv = nsTableFrame::GetTableFrame(this, tableFrame);
if (!tableFrame) return NS_ERROR_NULL_POINTER; if (!tableFrame) return NS_ERROR_NULL_POINTER;
if ((NS_UNCONSTRAINEDSIZE != aReflowState.availableWidth) && !mPrevInFlow) { // see if a special height reflow needs to occur due to having a pct height
// see if an extra reflow will be necessary when there is a pct height but no height basis nsTableFrame::CheckRequestSpecialHeightReflow(aReflowState);
if ( ((NS_UNCONSTRAINEDSIZE == aReflowState.mComputedHeight) ||
(0 == aReflowState.mComputedHeight)) &&
nsTableFrame::IsPctHeight(mStyleContext)) {
const nsHTMLReflowState* parentRS = aReflowState.parentReflowState;
if (parentRS && parentRS->frame) {
nsCOMPtr<nsIAtom> fType;
parentRS->frame->GetFrameType(getter_AddRefs(fType));
if (nsLayoutAtoms::tableRowGroupFrame == fType.get()) {
nscoord pctBasis = ((nsTableRowGroupFrame*)parentRS->frame)->GetHeightBasis(*parentRS);
if (0 == pctBasis) {
nsTableFrame::NotifyAncestorsOfSpecialReflow(*this);
SetNeedSpecialReflow(PR_TRUE);
}
}
}
}
}
switch (aReflowState.reason) { switch (aReflowState.reason) {
case eReflowReason_Initial: case eReflowReason_Initial:

Просмотреть файл

@ -1180,9 +1180,18 @@ nsTableRowGroupFrame::Reflow(nsIPresContext* aPresContext,
nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState); nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState);
#endif #endif
nsresult rv=NS_OK; nsresult rv = NS_OK;
aStatus = NS_FRAME_COMPLETE; aStatus = NS_FRAME_COMPLETE;
PRBool isPaginated;
aPresContext->IsPaginated(&isPaginated);
// If this is a special height reflow, set our desired size to what is was previously and return
// if we will be getting another special height reflow. In paginated mode, SetNeedSpecialReflow(PR_TRUE)
// may not have been called if reflow was a result of having a height on the containing table
if (nsTableFrame::IsPrematureSpecialHeightReflow(aReflowState, mRect, NeedSpecialReflow() || isPaginated, aDesiredSize))
return NS_OK;
nsTableFrame* tableFrame = nsnull; nsTableFrame* tableFrame = nsnull;
rv = nsTableFrame::GetTableFrame(this, tableFrame); rv = nsTableFrame::GetTableFrame(this, tableFrame);
if (!aPresContext || !tableFrame) return NS_ERROR_NULL_POINTER; if (!aPresContext || !tableFrame) return NS_ERROR_NULL_POINTER;
@ -1190,9 +1199,6 @@ nsTableRowGroupFrame::Reflow(nsIPresContext* aPresContext,
nsRowGroupReflowState state(aReflowState, tableFrame); nsRowGroupReflowState state(aReflowState, tableFrame);
PRBool haveDesiredHeight = PR_FALSE; PRBool haveDesiredHeight = PR_FALSE;
PRBool isPaginated;
aPresContext->IsPaginated(&isPaginated);
if (eReflowReason_Incremental == aReflowState.reason) { if (eReflowReason_Incremental == aReflowState.reason) {
rv = IncrementalReflow(aPresContext, aDesiredSize, state, aStatus); rv = IncrementalReflow(aPresContext, aDesiredSize, state, aStatus);
} }

Просмотреть файл

@ -162,7 +162,7 @@ nsTableCellFrame::NotifyPercentHeight(const nsHTMLReflowState& aReflowState)
if (!HadSpecialReflow()) { if (!HadSpecialReflow()) {
// Only initiate a special reflow if we will be able to construct a computed height // Only initiate a special reflow if we will be able to construct a computed height
// on the cell that will result in the frame getting a computed height. This can only // on the cell that will result in the frame getting a computed height. This can only
// happen (but not sufficient) if there no computed height already set between the // happen (but not sufficient) if there is no computed height already set between the
// initiating frame and the cell. // initiating frame and the cell.
for (const nsHTMLReflowState* rs = aReflowState.parentReflowState; rs; rs = rs->parentReflowState) { for (const nsHTMLReflowState* rs = aReflowState.parentReflowState; rs; rs = rs->parentReflowState) {
if ((NS_UNCONSTRAINEDSIZE != rs->mComputedHeight) && (0 != rs->mComputedHeight)) { if ((NS_UNCONSTRAINEDSIZE != rs->mComputedHeight) && (0 != rs->mComputedHeight)) {
@ -170,8 +170,7 @@ nsTableCellFrame::NotifyPercentHeight(const nsHTMLReflowState& aReflowState)
} }
// stop when we reach the cell frame // stop when we reach the cell frame
if (rs->frame == this) { if (rs->frame == this) {
nsTableFrame::NotifyAncestorsOfSpecialReflow((nsIFrame&)*this); nsTableFrame::RequestSpecialHeightReflow(*rs);
SetNeedSpecialReflow(PR_TRUE);
return NS_OK; return NS_OK;
} }
} }
@ -798,14 +797,9 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext,
nsresult rv = NS_OK; nsresult rv = NS_OK;
if ((NS_UNCONSTRAINEDSIZE != aReflowState.availableWidth) && // see if a special height reflow needs to occur due to having a pct height
((NS_UNCONSTRAINEDSIZE == aReflowState.mComputedHeight) || nsTableFrame::CheckRequestSpecialHeightReflow(aReflowState);
(0 == aReflowState.mComputedHeight)) &&
!mPrevInFlow &&
nsTableFrame::IsPctHeight(mStyleContext)) {
nsTableFrame::NotifyAncestorsOfSpecialReflow(*this);
SetNeedSpecialReflow(PR_TRUE);
}
// this should probably be cached somewhere // this should probably be cached somewhere
nsCompatibility compatMode; nsCompatibility compatMode;
aPresContext->GetCompatibilityMode(&compatMode); aPresContext->GetCompatibilityMode(&compatMode);

Просмотреть файл

@ -1843,61 +1843,188 @@ ProcessRowInserted(nsIPresContext* aPresContext,
} }
} }
void // Return true if aStylePosition has a pct height
nsTableFrame::NotifyAncestorsOfSpecialReflow(nsIFrame& aFrame) static PRBool
IsPctStyleHeight(const nsStylePosition* aStylePosition)
{ {
nsIFrame* parent; return (aStylePosition &&
for (aFrame.GetParent(&parent); parent; parent->GetParent(&parent)) { (eStyleUnit_Percent == aStylePosition->mHeight.GetUnit()));
}
// Return true if aStylePosition has a coord height
static PRBool
IsFixedStyleHeight(const nsStylePosition* aStylePosition)
{
return (aStylePosition &&
(eStyleUnit_Coord == aStylePosition->mHeight.GetUnit()));
}
// Return true if any of aReflowState.frame's ancestors within the containing table
// have a pct or fixed height
static PRBool
AncestorsHaveStyleHeight(const nsHTMLReflowState& aReflowState)
{
for (const nsHTMLReflowState* parentRS = aReflowState.parentReflowState;
parentRS && parentRS->frame;
parentRS = parentRS->parentReflowState) {
nsCOMPtr<nsIAtom> frameType; nsCOMPtr<nsIAtom> frameType;
parent->GetFrameType(getter_AddRefs(frameType)); parentRS->frame->GetFrameType(getter_AddRefs(frameType));
if (IS_TABLE_CELL(frameType.get())) { if (IS_TABLE_CELL(frameType.get()) ||
((nsTableCellFrame*)parent)->SetNeedSpecialReflow(PR_TRUE); (nsLayoutAtoms::tableRowFrame == frameType.get()) ||
} (nsLayoutAtoms::tableRowGroupFrame == frameType.get())) {
else if (nsLayoutAtoms::tableRowFrame == frameType.get()) { if (::IsPctStyleHeight(parentRS->mStylePosition) || ::IsFixedStyleHeight(parentRS->mStylePosition)) {
((nsTableRowFrame*)parent)->SetNeedSpecialReflow(PR_TRUE); return PR_TRUE;
} }
else if (nsLayoutAtoms::tableRowGroupFrame == frameType.get()) {
((nsTableRowGroupFrame*)parent)->SetNeedSpecialReflow(PR_TRUE);
} }
else if (nsLayoutAtoms::tableFrame == frameType.get()) { else if (nsLayoutAtoms::tableFrame == frameType.get()) {
((nsTableFrame*)parent)->SetNeedToInitiateSpecialReflow(PR_TRUE); // we reached the containing table, so always return
break; if (::IsPctStyleHeight(parentRS->mStylePosition) || ::IsFixedStyleHeight(parentRS->mStylePosition)) {
return PR_TRUE;
}
else return PR_FALSE;
}
}
return PR_FALSE;
}
// See if a special height reflow needs to occur and if so, call RequestSpecialHeightReflow
void
nsTableFrame::CheckRequestSpecialHeightReflow(const nsHTMLReflowState& aReflowState)
{
if (!aReflowState.frame) ABORT0();
nsIFrame* prevInFlow;
aReflowState.frame->GetPrevInFlow(&prevInFlow);
if ((NS_UNCONSTRAINEDSIZE != aReflowState.availableWidth) && // not first pass reflow
!prevInFlow && // 1st in flow && // 1st in flow
((NS_UNCONSTRAINEDSIZE == aReflowState.mComputedHeight) || // no computed height
(0 == aReflowState.mComputedHeight)) &&
::IsPctStyleHeight(aReflowState.mStylePosition)) { // pct height
if (::AncestorsHaveStyleHeight(aReflowState)) {
nsTableFrame::RequestSpecialHeightReflow(aReflowState);
} }
} }
} }
static PRBool // Notify the frame and its ancestors (up to the containing table) that a special
IsSpecialNested(const nsHTMLReflowState& aReflowState) // height reflow will occur. During a special height reflow, a table, row group,
// row, or cell returns the last size it was reflowed at. However, the table may
// change the height of row groups, rows, cells in DistributeHeightToRows after.
// And the row group can change the height of rows, cells in CalculateRowHeights.
void
nsTableFrame::RequestSpecialHeightReflow(const nsHTMLReflowState& aReflowState)
{ {
// Walk up the reflow state tree until we find anything with a style height. // notify the frame and its ancestors of the special reflow, stopping at the containing table
// stop when we reach a table for (const nsHTMLReflowState* rs = &aReflowState; rs && rs->frame; rs = rs->parentReflowState) {
const nsHTMLReflowState* rs = aReflowState.parentReflowState;
while (rs && rs->frame) {
const nsStylePosition* position;
rs->frame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)position);
if (eStyleUnit_Coord == position->mHeight.GetUnit()) {
nscoord coordValue = position->mHeight.GetCoordValue();
if (coordValue > 0) return PR_TRUE;
}
else if (eStyleUnit_Percent == position->mHeight.GetUnit()) {
float percent = position->mHeight.GetPercentValue();
if (percent > 0.0f) return PR_TRUE;
}
nsCOMPtr<nsIAtom> frameType; nsCOMPtr<nsIAtom> frameType;
rs->frame->GetFrameType(getter_AddRefs(frameType)); rs->frame->GetFrameType(getter_AddRefs(frameType));
if (nsLayoutAtoms::tableFrame == frameType.get()) break; if (IS_TABLE_CELL(frameType.get())) {
rs = rs->parentReflowState; ((nsTableCellFrame*)rs->frame)->SetNeedSpecialReflow(PR_TRUE);
}
else if (nsLayoutAtoms::tableRowFrame == frameType.get()) {
((nsTableRowFrame*)rs->frame)->SetNeedSpecialReflow(PR_TRUE);
}
else if (nsLayoutAtoms::tableRowGroupFrame == frameType.get()) {
((nsTableRowGroupFrame*)rs->frame)->SetNeedSpecialReflow(PR_TRUE);
}
else if (nsLayoutAtoms::tableFrame == frameType.get()) {
if (rs == &aReflowState) {
// don't stop because we started with this table
((nsTableFrame*)rs->frame)->SetNeedSpecialReflow(PR_TRUE);
}
else {
((nsTableFrame*)rs->frame)->SetNeedToInitiateSpecialReflow(PR_TRUE);
// always stop when we reach a table that we didn't start with
break;
}
}
} }
return PR_FALSE;
} }
/* overview:
if mFirstPassValid is false, this is our first time through since content was last changed // Return true (and set aMetrics's desiredSize to aRect) if the special height reflow
do pass 1 // was initiated by an ancestor of aReflowState.frame's containing table. In that case,
get min/max info for all cells in an infinite space // aFrame's containing table will eventually initiate a special height reflow which
do column balancing // will cause this method to return false.
do pass 2 PRBool
use column widths to size table and ResizeReflow rowgroups (and therefore rows and cells) nsTableFrame::IsPrematureSpecialHeightReflow(const nsHTMLReflowState& aReflowState,
*/ const nsRect& aRect,
PRBool aNeedSpecialHeightReflow,
nsHTMLReflowMetrics& aMetrics)
{
PRBool premature = PR_FALSE;
if (aReflowState.mFlags.mSpecialHeightReflow) {
if (aNeedSpecialHeightReflow) {
nsTableFrame* tableFrame;
nsTableFrame::GetTableFrame(aReflowState.frame, tableFrame);
if (tableFrame && (tableFrame != aReflowState.mPercentHeightReflowInitiator)) {
premature = PR_TRUE;
}
}
else {
premature = PR_TRUE;
}
if (premature) {
aMetrics.width = aRect.width;
aMetrics.height = aRect.height;
}
}
return premature;
}
/******************************************************************************************
* During the initial reflow the table reflows each child with an unconstrained avail width
* to get its max element width and maximum width. This is referred to as the pass 1 reflow.
*
* After the 1st pass reflow, the table determines the column widths using BalanceColumnWidths()
* then reflows each child again with a constrained avail width. This reflow is referred to
* as the pass 2 reflow.
*
* A special height reflow (pass 3 reflow) can occur during an intitial or resize reflow
* if (a) a row group, row, cell, or a frame inside a cell has a percent height but no computed
* height or (b) in paginated mode, a table has a height. (a) supports percent nested tables
* contained inside cells whose heights aren't known until after the pass 2 reflow. (b) is
* necessary because the table cannot split until after the pass 2 reflow. The mechanics of
* the special height reflow (variety a) are as follows:
*
* 1) Each table related frame (table, row group, row, cell) implements NeedsSpecialReflow()
* to indicate that it should get the reflow. It does this when it has a percent height but
* no computed height by calling CheckRequestSpecialHeightReflow(). This method calls
* RequestSpecialHeightReflow() which calls SetNeedSpecialReflow() on its ancestors until
* it reaches the containing table and calls SetNeedToInitiateSpecialReflow() on it. For
* percent height frames inside cells, during DidReflow(), the cell's NotifyPercentHeight()
* is called (the cell is the reflow state's mPercentHeightObserver in this case).
* NotifyPercentHeight() calls RequestSpecialHeightReflow().
*
* 2) After the pass 2 reflow, if the table's NeedToInitiateSpecialReflow(true) was called, it
* will do the special height reflow, setting the reflow state's mFlages.mSpecialHeightReflow
* to true and mSpecialHeightInitiator to itself. It won't do this if IsPrematureSpecialHeightReflow()
* returns true because in that case another special height reflow will be comming along with the
* containing table as the mSpecialHeightInitiator. It is only relevant to do the reflow when
* the mSpecialHeightInitiator is the containing table, because if it is a remote ancestor, then
* appropriate heights will not be known.
*
* 3) Since the heights of the table, row groups, rows, and cells was determined during the pass 2
* reflow, they return their last desired sizes during the special height reflow. The reflow only
* permits percent height frames inside the cells to resize based on the cells height and that height
* was determined during the pass 2 reflow.
*
* So, in the case of deeply nested tables, all of the tables that were told to initiate a special
* reflow will do so, but if a table is already in a special reflow, it won't inititate the reflow
* until the current initiator is its containing table. Since these reflows are only received by
* frames that need them and they don't cause any rebalancing of tables, the extra overhead is minimal.
*
* The type of special reflow that occurs during printing (variety b) follows the same mechanism except
* that all frames will receive the reflow even if they don't really need them.
*
* Open issues with the special height reflow:
*
* 1) At some point there should be 2 kinds of special height reflows because (a) and (b) above are
* really quite different. This would avoid unnecessary reflows during printing.
* 2) When a cell contains frames whose percent heights > 100%, there is data loss (see bug 115245).
* However, this can also occur if a cell has a fixed height and there is no special height reflow.
*
******************************************************************************************/
/* Layout the entire inner table. */ /* Layout the entire inner table. */
NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext, NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext,
@ -1910,6 +2037,14 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext,
#if defined DEBUG_TABLE_REFLOW_TIMING #if defined DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState); nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState);
#endif #endif
PRBool isPaginated;
aPresContext->IsPaginated(&isPaginated);
// If this is a special height reflow, set our desired size to what is was previously and return
// if we will be getting another special height reflow. In paginated mode, SetNeedSpecialReflow(PR_TRUE)
// may not have been called if reflow was a result of having a height on the containing table
if (IsPrematureSpecialHeightReflow(aReflowState, mRect, NeedSpecialReflow() || isPaginated, aDesiredSize))
return NS_OK;
aStatus = NS_FRAME_COMPLETE; aStatus = NS_FRAME_COMPLETE;
if (!mPrevInFlow && !mTableLayoutStrategy) { if (!mPrevInFlow && !mTableLayoutStrategy) {
@ -1918,9 +2053,6 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext,
} }
nsresult rv = NS_OK; nsresult rv = NS_OK;
PRBool isPaginated;
aPresContext->IsPaginated(&isPaginated);
// see if collapsing borders need to be calculated // see if collapsing borders need to be calculated
if (!mPrevInFlow && IsBorderCollapse() && NeedToCalcBCBorders()) { if (!mPrevInFlow && IsBorderCollapse() && NeedToCalcBCBorders()) {
GET_TWIPS_TO_PIXELS(aPresContext, p2t); GET_TWIPS_TO_PIXELS(aPresContext, p2t);
@ -2002,9 +2134,8 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext,
// no computed height, but a height on the containing table // no computed height, but a height on the containing table
if ( ((NS_UNCONSTRAINEDSIZE == aReflowState.mComputedHeight) || if ( ((NS_UNCONSTRAINEDSIZE == aReflowState.mComputedHeight) ||
(0 == aReflowState.mComputedHeight)) && (0 == aReflowState.mComputedHeight)) &&
IsPctHeight(mStyleContext) && IsSpecialNested(aReflowState)) { IsPctHeight(mStyleContext)) {
NotifyAncestorsOfSpecialReflow(*this); nsTableFrame::CheckRequestSpecialHeightReflow(aReflowState);
SetNeedSpecialReflow(PR_TRUE);
} }
// see if an extra reflow will be necessary in pagination mode when there is a specified table height // see if an extra reflow will be necessary in pagination mode when there is a specified table height
else if (isPaginated && (NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight)) { else if (isPaginated && (NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight)) {
@ -2024,11 +2155,20 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext,
ReflowTable(aPresContext, aDesiredSize, aReflowState, availHeight, nextReason, ReflowTable(aPresContext, aDesiredSize, aReflowState, availHeight, nextReason,
lastChildReflowed, doCollapse, balanced, aStatus); lastChildReflowed, doCollapse, balanced, aStatus);
if (!aReflowState.mFlags.mSpecialHeightReflow && NeedToInitiateSpecialReflow() && !NeedSpecialReflow()) { if (NeedToInitiateSpecialReflow() &&
(aReflowState.mFlags.mSpecialHeightReflow || !NeedSpecialReflow())) {
aDesiredSize.height = CalcDesiredHeight(aPresContext, aReflowState); // distributes extra vertical space to rows aDesiredSize.height = CalcDesiredHeight(aPresContext, aReflowState); // distributes extra vertical space to rows
((nsHTMLReflowState::ReflowStateFlags&)aReflowState.mFlags).mSpecialHeightReflow = PR_TRUE;
// save the previous special height reflow initiator, install us as the new one
nsIFrame* specialReflowInitiator = aReflowState.mPercentHeightReflowInitiator;
((nsHTMLReflowState&)aReflowState).mPercentHeightReflowInitiator = this;
((nsHTMLReflowState::ReflowStateFlags&)aReflowState.mFlags).mSpecialHeightReflow = PR_TRUE; ((nsHTMLReflowState::ReflowStateFlags&)aReflowState.mFlags).mSpecialHeightReflow = PR_TRUE;
ReflowTable(aPresContext, aDesiredSize, aReflowState, aReflowState.availableHeight, ReflowTable(aPresContext, aDesiredSize, aReflowState, aReflowState.availableHeight,
nextReason, lastChildReflowed, doCollapse, balanced, aStatus); nextReason, lastChildReflowed, doCollapse, balanced, aStatus);
// restore the previous special height reflow initiator
((nsHTMLReflowState&)aReflowState).mPercentHeightReflowInitiator = specialReflowInitiator;
if (lastChildReflowed && NS_FRAME_IS_NOT_COMPLETE(aStatus)) { if (lastChildReflowed && NS_FRAME_IS_NOT_COMPLETE(aStatus)) {
// if there is an incomplete child, then set the desired height to include it but not the next one // if there is an incomplete child, then set the desired height to include it but not the next one
nsRect childRect; nsRect childRect;
@ -4160,15 +4300,15 @@ nsTableFrame::GetTableFrame(nsIFrame* aSourceFrame,
{ {
nsresult rv = NS_ERROR_UNEXPECTED; // the value returned nsresult rv = NS_ERROR_UNEXPECTED; // the value returned
aTableFrame = nsnull; // initialize out-param aTableFrame = nsnull; // initialize out-param
nsIFrame* parentFrame=nsnull; nsIFrame* parentFrame = nsnull;
if (aSourceFrame) { if (aSourceFrame) {
// "result" is the result of intermediate calls, not the result we return from this method // "result" is the result of intermediate calls, not the result we return from this method
nsresult result = aSourceFrame->GetParent((nsIFrame **)&parentFrame); nsresult result = aSourceFrame->GetParent((nsIFrame **)&parentFrame);
while ((NS_OK==result) && (nsnull!=parentFrame)) { while ((NS_OK == result) && parentFrame) {
const nsStyleDisplay *display; nsCOMPtr<nsIAtom> frameType;
parentFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&)display); parentFrame->GetFrameType(getter_AddRefs(frameType));
if (NS_STYLE_DISPLAY_TABLE == display->mDisplay) { if (nsLayoutAtoms::tableFrame == frameType.get()) {
aTableFrame = (nsTableFrame *)parentFrame; aTableFrame = (nsTableFrame*)parentFrame;
rv = NS_OK; // only set if we found the table frame rv = NS_OK; // only set if we found the table frame
break; break;
} }

Просмотреть файл

@ -218,7 +218,20 @@ public:
float aPixelToTwips, float aPixelToTwips,
nsPixelRound aRound= eAlwaysRoundUp); nsPixelRound aRound= eAlwaysRoundUp);
static void NotifyAncestorsOfSpecialReflow(nsIFrame& aFrame); // See if a special height reflow will occur due to having a pct height when
// the pct height basis may not yet be valid.
static void CheckRequestSpecialHeightReflow(const nsHTMLReflowState& aReflowState);
// Notify the frame and its ancestors (up to the containing table) that a special
// height reflow will occur.
static void RequestSpecialHeightReflow(const nsHTMLReflowState& aReflowState);
// Return true (and set aMetrics's desiredSize to aRect) if the special height reflow
// was not initiated by aReflowState.frame's containing table.
static PRBool IsPrematureSpecialHeightReflow(const nsHTMLReflowState& aReflowState,
const nsRect& aRect,
PRBool aNeedSpecialHeightReflow,
nsHTMLReflowMetrics& aMetrics);
NS_IMETHOD IsPercentageBase(PRBool& aBase) const; NS_IMETHOD IsPercentageBase(PRBool& aBase) const;

Просмотреть файл

@ -1436,25 +1436,8 @@ nsTableRowFrame::Reflow(nsIPresContext* aPresContext,
rv = nsTableFrame::GetTableFrame(this, tableFrame); rv = nsTableFrame::GetTableFrame(this, tableFrame);
if (!tableFrame) return NS_ERROR_NULL_POINTER; if (!tableFrame) return NS_ERROR_NULL_POINTER;
if ((NS_UNCONSTRAINEDSIZE != aReflowState.availableWidth) && !mPrevInFlow) { // see if a special height reflow needs to occur due to having a pct height
// see if an extra reflow will be necessary when there is a pct height but no height basis nsTableFrame::CheckRequestSpecialHeightReflow(aReflowState);
if ( ((NS_UNCONSTRAINEDSIZE == aReflowState.mComputedHeight) ||
(0 == aReflowState.mComputedHeight)) &&
nsTableFrame::IsPctHeight(mStyleContext)) {
const nsHTMLReflowState* parentRS = aReflowState.parentReflowState;
if (parentRS && parentRS->frame) {
nsCOMPtr<nsIAtom> fType;
parentRS->frame->GetFrameType(getter_AddRefs(fType));
if (nsLayoutAtoms::tableRowGroupFrame == fType.get()) {
nscoord pctBasis = ((nsTableRowGroupFrame*)parentRS->frame)->GetHeightBasis(*parentRS);
if (0 == pctBasis) {
nsTableFrame::NotifyAncestorsOfSpecialReflow(*this);
SetNeedSpecialReflow(PR_TRUE);
}
}
}
}
}
switch (aReflowState.reason) { switch (aReflowState.reason) {
case eReflowReason_Initial: case eReflowReason_Initial:

Просмотреть файл

@ -1180,9 +1180,18 @@ nsTableRowGroupFrame::Reflow(nsIPresContext* aPresContext,
nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState); nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState);
#endif #endif
nsresult rv=NS_OK; nsresult rv = NS_OK;
aStatus = NS_FRAME_COMPLETE; aStatus = NS_FRAME_COMPLETE;
PRBool isPaginated;
aPresContext->IsPaginated(&isPaginated);
// If this is a special height reflow, set our desired size to what is was previously and return
// if we will be getting another special height reflow. In paginated mode, SetNeedSpecialReflow(PR_TRUE)
// may not have been called if reflow was a result of having a height on the containing table
if (nsTableFrame::IsPrematureSpecialHeightReflow(aReflowState, mRect, NeedSpecialReflow() || isPaginated, aDesiredSize))
return NS_OK;
nsTableFrame* tableFrame = nsnull; nsTableFrame* tableFrame = nsnull;
rv = nsTableFrame::GetTableFrame(this, tableFrame); rv = nsTableFrame::GetTableFrame(this, tableFrame);
if (!aPresContext || !tableFrame) return NS_ERROR_NULL_POINTER; if (!aPresContext || !tableFrame) return NS_ERROR_NULL_POINTER;
@ -1190,9 +1199,6 @@ nsTableRowGroupFrame::Reflow(nsIPresContext* aPresContext,
nsRowGroupReflowState state(aReflowState, tableFrame); nsRowGroupReflowState state(aReflowState, tableFrame);
PRBool haveDesiredHeight = PR_FALSE; PRBool haveDesiredHeight = PR_FALSE;
PRBool isPaginated;
aPresContext->IsPaginated(&isPaginated);
if (eReflowReason_Incremental == aReflowState.reason) { if (eReflowReason_Incremental == aReflowState.reason) {
rv = IncrementalReflow(aPresContext, aDesiredSize, state, aStatus); rv = IncrementalReflow(aPresContext, aDesiredSize, state, aStatus);
} }