bug 97138 - rework of table, row group, row, cell height code. sr=attinasi, r=alexsavulov

git-svn-id: svn://10.0.0.236/trunk@107299 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
karnaze%netscape.com 2001-11-05 00:15:51 +00:00
parent 57b929e4bf
commit d30758e3fc
24 changed files with 2180 additions and 1304 deletions

View File

@ -239,7 +239,14 @@ struct nsHTMLReflowState {
// This value keeps track of how deeply nested a given reflow state
// is from the top of the frame tree.
PRInt32 mReflowDepth;
PRInt16 mReflowDepth;
struct ReflowStateFlags {
//unsigned mUseAlignCharOffset:1; // ditto
//unsigned isTopOfPage:1; // ditto
PRUint16 mSpecialTableReflow:1; // used by tables to communicate special reflow in process
PRUint16 mUnused:15;
} mFlags;
#ifdef IBMBIDI
nscoord mRightEdge;

View File

@ -86,7 +86,7 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext,
: mReflowDepth(0)
{
NS_PRECONDITION(nsnull != aRenderingContext, "no rendering context");
mFlags.mSpecialTableReflow = mFlags.mUnused = 0;
parentReflowState = nsnull;
frame = aFrame;
reason = aReason;
@ -114,6 +114,7 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext,
{
NS_PRECONDITION(nsnull != aRenderingContext, "no rendering context");
mFlags.mSpecialTableReflow = mFlags.mUnused = 0;
reason = eReflowReason_Incremental;
parentReflowState = nsnull;
frame = aFrame;
@ -138,7 +139,8 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext,
nsIFrame* aFrame,
const nsSize& aAvailableSpace,
nsReflowReason aReason)
: mReflowDepth(aParentReflowState.mReflowDepth + 1)
: mReflowDepth(aParentReflowState.mReflowDepth + 1),
mFlags(aParentReflowState.mFlags)
{
parentReflowState = &aParentReflowState;
frame = aFrame;
@ -167,7 +169,8 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext,
const nsHTMLReflowState& aParentReflowState,
nsIFrame* aFrame,
const nsSize& aAvailableSpace)
: mReflowDepth(aParentReflowState.mReflowDepth + 1)
: mReflowDepth(aParentReflowState.mReflowDepth + 1),
mFlags(aParentReflowState.mFlags)
{
parentReflowState = &aParentReflowState;
frame = aFrame;
@ -195,7 +198,8 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext,
const nsSize& aAvailableSpace,
nscoord aContainingBlockWidth,
nscoord aContainingBlockHeight)
: mReflowDepth(aParentReflowState.mReflowDepth + 1)
: mReflowDepth(aParentReflowState.mReflowDepth + 1),
mFlags(aParentReflowState.mFlags)
{
parentReflowState = &aParentReflowState;
frame = aFrame;

View File

@ -239,7 +239,14 @@ struct nsHTMLReflowState {
// This value keeps track of how deeply nested a given reflow state
// is from the top of the frame tree.
PRInt32 mReflowDepth;
PRInt16 mReflowDepth;
struct ReflowStateFlags {
//unsigned mUseAlignCharOffset:1; // ditto
//unsigned isTopOfPage:1; // ditto
PRUint16 mSpecialTableReflow:1; // used by tables to communicate special reflow in process
PRUint16 mUnused:15;
} mFlags;
#ifdef IBMBIDI
nscoord mRightEdge;

View File

@ -86,7 +86,7 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext,
: mReflowDepth(0)
{
NS_PRECONDITION(nsnull != aRenderingContext, "no rendering context");
mFlags.mSpecialTableReflow = mFlags.mUnused = 0;
parentReflowState = nsnull;
frame = aFrame;
reason = aReason;
@ -114,6 +114,7 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext,
{
NS_PRECONDITION(nsnull != aRenderingContext, "no rendering context");
mFlags.mSpecialTableReflow = mFlags.mUnused = 0;
reason = eReflowReason_Incremental;
parentReflowState = nsnull;
frame = aFrame;
@ -138,7 +139,8 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext,
nsIFrame* aFrame,
const nsSize& aAvailableSpace,
nsReflowReason aReason)
: mReflowDepth(aParentReflowState.mReflowDepth + 1)
: mReflowDepth(aParentReflowState.mReflowDepth + 1),
mFlags(aParentReflowState.mFlags)
{
parentReflowState = &aParentReflowState;
frame = aFrame;
@ -167,7 +169,8 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext,
const nsHTMLReflowState& aParentReflowState,
nsIFrame* aFrame,
const nsSize& aAvailableSpace)
: mReflowDepth(aParentReflowState.mReflowDepth + 1)
: mReflowDepth(aParentReflowState.mReflowDepth + 1),
mFlags(aParentReflowState.mFlags)
{
parentReflowState = &aParentReflowState;
frame = aFrame;
@ -195,7 +198,8 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext,
const nsSize& aAvailableSpace,
nscoord aContainingBlockWidth,
nscoord aContainingBlockHeight)
: mReflowDepth(aParentReflowState.mReflowDepth + 1)
: mReflowDepth(aParentReflowState.mReflowDepth + 1),
mFlags(aParentReflowState.mFlags)
{
parentReflowState = &aParentReflowState;
frame = aFrame;

View File

@ -337,15 +337,19 @@ nsTableCellMap::RemoveRows(nsIPresContext* aPresContext,
PRInt32
nsTableCellMap::GetNumCellsOriginatingInRow(PRInt32 aRowIndex)
{
PRInt32 cellCount = 0;
CellData* tempCell;
do
{
tempCell = GetCellAt(aRowIndex,cellCount);
if (tempCell)
cellCount++;
}while(tempCell);
return cellCount;
PRInt32 originCount = 0;
CellData* cellData;
PRInt32 colIndex = 0;
do {
cellData = GetCellAt(aRowIndex, colIndex);
if (cellData && cellData->GetCellFrame())
originCount++;
colIndex++;
} while(cellData);
return originCount;
}
PRInt32

View File

@ -91,6 +91,22 @@ nsTableCellFrame::~nsTableCellFrame()
#endif
}
nsTableCellFrame*
nsTableCellFrame::GetNextCell() const
{
nsIFrame* childFrame;
GetNextSibling(&childFrame);
while (childFrame) {
nsCOMPtr<nsIAtom> frameType;
childFrame->GetFrameType(getter_AddRefs(frameType));
if (nsLayoutAtoms::tableCellFrame == frameType.get()) {
return (nsTableCellFrame*)childFrame;
}
childFrame->GetNextSibling(&childFrame);
}
return nsnull;
}
NS_IMETHODIMP
nsTableCellFrame::Init(nsIPresContext* aPresContext,
nsIContent* aContent,
@ -694,6 +710,15 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext,
}
nsresult rv = NS_OK;
if ((NS_UNCONSTRAINEDSIZE != aReflowState.availableWidth) &&
((NS_UNCONSTRAINEDSIZE == aReflowState.mComputedHeight) ||
(0 == aReflowState.mComputedHeight)) &&
!mPrevInFlow &&
nsTableFrame::IsPctHeight(mStyleContext)) {
nsTableFrame::NotifyAncestorsOfSpecialReflow(aReflowState);
SetNeedSpecialReflow(PR_TRUE);
}
// this should probably be cached somewhere
nsCompatibility compatMode;
aPresContext->GetCompatibilityMode(&compatMode);
@ -714,6 +739,8 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext,
/* XXX: remove tableFrame when border-collapse inherits */
nsTableFrame* tableFrame=nsnull;
rv = nsTableFrame::GetTableFrame(this, tableFrame);
nsTableFrame* tableFrameFirstInFlow = (nsTableFrame*)tableFrame->GetFirstInFlow();
nsMargin borderPadding = aReflowState.mComputedPadding;
nsMargin border;
GetCellBorder(border, tableFrame);
@ -768,6 +795,10 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext,
kidSize.width=kidSize.height=kidSize.ascent=kidSize.descent=0;
SetPriorAvailWidth(aReflowState.availableWidth);
nsIFrame* firstKid = mFrames.FirstChild();
if (aReflowState.mFlags.mSpecialTableReflow) {
((nsHTMLReflowState&)aReflowState).mComputedHeight = mRect.height - topInset - bottomInset;
}
nsHTMLReflowState kidReflowState(aPresContext, aReflowState, firstKid,
availSize);
@ -898,8 +929,7 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext,
// if the table allocated extra vertical space to row groups, rows, cells in pagination mode
// then use that height as the desired height unless the cell needs to split.
nsTableFrame* tableFrameFirstInFlow = (nsTableFrame*)tableFrame->GetFirstInFlow();
if ((NS_FRAME_COMPLETE == aStatus) && tableFrameFirstInFlow->IsThirdPassReflow()) {
if ((NS_FRAME_COMPLETE == aStatus) && aReflowState.mFlags.mSpecialTableReflow) {
cellHeight = PR_MAX(cellHeight, mRect.height);
}
// next determine the cell's width
@ -942,6 +972,10 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext,
// remember my desired size for this reflow
SetDesiredSize(aDesiredSize);
if (aReflowState.mFlags.mSpecialTableReflow) {
SetNeedSpecialReflow(PR_FALSE);
}
#if defined DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState, &aDesiredSize, aStatus);
#endif

View File

@ -49,7 +49,8 @@ class nsHTMLValue;
/**
* Additional frame-state bits
*/
#define NS_TABLE_CELL_FRAME_CONTENT_EMPTY 0x80000000
#define NS_TABLE_CELL_CONTENT_EMPTY 0x80000000
#define NS_TABLE_CELL_NEED_SPECIAL_REFLOW 0x40000000
/**
* nsTableCellFrame
@ -239,11 +240,16 @@ public:
PRBool GetContentEmpty();
void SetContentEmpty(PRBool aContentEmpty);
PRBool NeedSpecialReflow();
void SetNeedSpecialReflow(PRBool aContentEmpty);
// The collapse offset is (0,0) except for cells originating in a row/col which is collapsed
void SetCollapseOffsetX(nsIPresContext* aPresContext, nscoord aXOffset);
void SetCollapseOffsetY(nsIPresContext* aPresContext, nscoord aYOffset);
void GetCollapseOffset(nsIPresContext* aPresContext, nsPoint& aOffset);
nsTableCellFrame* GetNextCell() const;
protected:
/** implement abstract method on nsHTMLContainerFrame */
virtual PRIntn GetSkipSides() const;
@ -332,19 +338,33 @@ inline nsSize nsTableCellFrame::GetPass1MaxElementSize() const
inline PRBool nsTableCellFrame::GetContentEmpty()
{
return (mState & NS_TABLE_CELL_FRAME_CONTENT_EMPTY) ==
NS_TABLE_CELL_FRAME_CONTENT_EMPTY;
return (mState & NS_TABLE_CELL_CONTENT_EMPTY) ==
NS_TABLE_CELL_CONTENT_EMPTY;
}
inline void nsTableCellFrame::SetContentEmpty(PRBool aContentEmpty)
{
if (aContentEmpty) {
mState |= NS_TABLE_CELL_FRAME_CONTENT_EMPTY;
mState |= NS_TABLE_CELL_CONTENT_EMPTY;
} else {
mState &= ~NS_TABLE_CELL_FRAME_CONTENT_EMPTY;
mState &= ~NS_TABLE_CELL_CONTENT_EMPTY;
}
}
inline PRBool nsTableCellFrame::NeedSpecialReflow()
{
return (mState & NS_TABLE_CELL_NEED_SPECIAL_REFLOW) ==
NS_TABLE_CELL_NEED_SPECIAL_REFLOW;
}
inline void nsTableCellFrame::SetNeedSpecialReflow(PRBool aValue)
{
if (aValue) {
mState |= NS_TABLE_CELL_NEED_SPECIAL_REFLOW;
} else {
mState &= ~NS_TABLE_CELL_NEED_SPECIAL_REFLOW;
}
}
#endif

View File

@ -84,6 +84,7 @@ void nsTableColFrame::SetType(nsTableColType aType) {
mBits.mType = aType - eColContent;
}
// XXX what about other style besides width
nsStyleCoord nsTableColFrame::GetStyleWidth() const
{

View File

@ -1580,8 +1580,15 @@ nsTableFrame::GetSkipSides() const
PRBool nsTableFrame::NeedsReflow(const nsHTMLReflowState& aReflowState)
{
PRBool result = PR_TRUE;
if ((eReflowReason_Incremental == aReflowState.reason) &&
(NS_UNCONSTRAINEDSIZE == aReflowState.availableHeight)) {
if (eReflowReason_Resize == aReflowState.reason) {
if (aReflowState.mFlags.mSpecialTableReflow &&
!NeedSpecialReflow() &&
!NeedToInitiateSpecialReflow()) {
result = PR_FALSE;
}
}
else if ((eReflowReason_Incremental == aReflowState.reason) &&
(NS_UNCONSTRAINEDSIZE == aReflowState.availableHeight)) {
// It's an incremental reflow and we're in galley mode. Only
// do a full reflow if we need to.
#ifndef TABLE_REFLOW_COALESCING_OFF
@ -1809,6 +1816,30 @@ ProcessRowInserted(nsIPresContext* aPresContext,
}
}
void
nsTableFrame::NotifyAncestorsOfSpecialReflow(const nsHTMLReflowState& aReflowState)
{
const nsHTMLReflowState* rs = aReflowState.parentReflowState;
while (rs) {
nsCOMPtr<nsIAtom> frameType;
rs->frame->GetFrameType(getter_AddRefs(frameType));
if (nsLayoutAtoms::tableCellFrame == frameType.get()) {
((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()) {
((nsTableFrame*)rs->frame)->SetNeedToInitiateSpecialReflow(PR_TRUE);
break;
}
rs = rs->parentReflowState;
}
}
/* overview:
if mFirstPassValid is false, this is our first time through since content was last changed
do pass 1
@ -1904,36 +1935,57 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext,
if (NS_FAILED(rv)) return rv;
PRBool needPass3Reflow = PR_FALSE;
PRBool haveDesiredHeight = PR_FALSE;
PRBool balanced = PR_FALSE;
// Reflow the entire table. This phase is necessary during a constrained initial reflow
// and other reflows which require either a strategy init or balance. This isn't done
// during an unconstrained reflow because another reflow will be processed later.
if (NeedsReflow(aReflowState) && (NS_UNCONSTRAINEDSIZE != aReflowState.availableWidth)) {
// see if an extra (3rd) reflow will be necessary in pagination mode when there is a specified table height
if (isPaginated && !mPrevInFlow && (NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight)) {
nscoord tableSpecifiedHeight = CalcBorderBoxHeight(aReflowState);
if ((tableSpecifiedHeight > 0) &&
(tableSpecifiedHeight != NS_UNCONSTRAINEDSIZE)) {
needPass3Reflow = PR_TRUE;
if (!mPrevInFlow) {
// see if an extra reflow will be necessary when there is a pct height but no height on the parent
if ( ((NS_UNCONSTRAINEDSIZE == aReflowState.mComputedHeight) ||
(0 == aReflowState.mComputedHeight)) && IsPctHeight(mStyleContext)) {
NotifyAncestorsOfSpecialReflow(aReflowState);
SetNeedSpecialReflow(PR_TRUE);
}
// 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)) {
nscoord tableSpecifiedHeight = CalcBorderBoxHeight(aReflowState);
if ((tableSpecifiedHeight > 0) &&
(tableSpecifiedHeight != NS_UNCONSTRAINEDSIZE)) {
SetNeedToInitiateSpecialReflow(PR_TRUE);
}
}
}
// if we need to reflow the table an extra time, then don't constrain the height of the previous reflow
nscoord availHeight = (needPass3Reflow) ? NS_UNCONSTRAINEDSIZE : aReflowState.availableHeight;
nscoord availHeight = !aReflowState.mFlags.mSpecialTableReflow &&
(NeedSpecialReflow() | NeedToInitiateSpecialReflow())
? NS_UNCONSTRAINEDSIZE : aReflowState.availableHeight;
ReflowTable(aPresContext, aDesiredSize, aReflowState, availHeight, nextReason, doCollapse, balanced, aStatus);
if (needPass3Reflow) {
if (!aReflowState.mFlags.mSpecialTableReflow && NeedToInitiateSpecialReflow() && !NeedSpecialReflow()) {
aDesiredSize.height = CalcDesiredHeight(aPresContext, aReflowState); // distributes extra vertical space to rows
SetThirdPassReflow(PR_TRUE); // set it and leave it set for frames that may split
((nsHTMLReflowState::ReflowStateFlags&)aReflowState.mFlags).mSpecialTableReflow = PR_TRUE;
ReflowTable(aPresContext, aDesiredSize, aReflowState, aReflowState.availableHeight,
nextReason, doCollapse, balanced, aStatus);
haveDesiredHeight = PR_TRUE;;
}
}
else if (aReflowState.mFlags.mSpecialTableReflow) {
aDesiredSize.width = mRect.width;
aDesiredSize.height = mRect.height;
#if defined DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState, &aDesiredSize, aStatus);
#endif
SetNeedSpecialReflow(PR_FALSE);
SetNeedToInitiateSpecialReflow(PR_FALSE);
return NS_OK;
}
aDesiredSize.width = GetDesiredWidth();
if (!needPass3Reflow) {
aDesiredSize.width = GetDesiredWidth();
if (!haveDesiredHeight) {
aDesiredSize.height = CalcDesiredHeight(aPresContext, aReflowState);
}
@ -1986,6 +2038,10 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext,
}
}
if (aReflowState.mFlags.mSpecialTableReflow) {
SetNeedSpecialReflow(PR_FALSE);
SetNeedToInitiateSpecialReflow(PR_FALSE);
}
#if defined DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState, &aDesiredSize, aStatus);
#endif
@ -3253,81 +3309,6 @@ nsTableFrame::CalcDesiredWidth(const nsHTMLReflowState& aReflowState)
return tableWidth;
}
/**
get the table height attribute
if it is auto, table height = SUM(height of rowgroups)
else if (resolved table height attribute > SUM(height of rowgroups))
proportionately distribute extra height to each row
we assume we are passed in the default table height==the sum of the heights of the table's rowgroups
in aDesiredSize.height.
*/
void
nsTableFrame::DistributeSpaceToCells(nsIPresContext* aPresContext,
const nsHTMLReflowState& aReflowState,
nsIFrame* aRowGroupFrame)
{
// now that all of the rows have been resized, resize the cells
nsTableRowGroupFrame* rowGroupFrame = (nsTableRowGroupFrame*)aRowGroupFrame;
nsIFrame * rowFrame = rowGroupFrame->GetFirstFrame();
while (rowFrame) {
const nsStyleDisplay *rowDisplay;
rowFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)rowDisplay));
if (NS_STYLE_DISPLAY_TABLE_ROW == rowDisplay->mDisplay) {
((nsTableRowFrame *)rowFrame)->DidResize(aPresContext, aReflowState);
}
rowGroupFrame->GetNextFrame(rowFrame, &rowFrame);
}
}
void
nsTableFrame::DistributeSpaceToRows(nsIPresContext* aPresContext,
const nsHTMLReflowState& aReflowState,
nsIFrame* aRowGroupFrame,
nscoord aSumOfRowHeights,
nscoord aExcess,
nscoord& aExcessAllocated,
nscoord& aRowGroupYPos)
{
// the rows in rowGroupFrame need to be expanded by rowHeightDelta[i]
// and the rowgroup itself needs to be expanded by SUM(row height deltas)
nscoord cellSpacingY = GetCellSpacingY();
nsTableRowGroupFrame* rowGroupFrame = (nsTableRowGroupFrame*)aRowGroupFrame;
nsIFrame* rowFrame = rowGroupFrame->GetFirstFrame();
nscoord excessForRowGroup = 0;
nscoord y = 0;
float p2t;
aPresContext->GetPixelsToTwips(&p2t);
while (rowFrame) {
const nsStyleDisplay *rowDisplay;
rowFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)rowDisplay));
if (NS_STYLE_DISPLAY_TABLE_ROW == rowDisplay->mDisplay) {
// the row needs to be expanded by the proportion this row contributed to the original height
nsRect rowRect;
rowFrame->GetRect(rowRect);
float percent = ((float)(rowRect.height)) / (float)aSumOfRowHeights;
nscoord excessForRow = RoundToPixel(NSToCoordRound((float)aExcess * percent), p2t);
excessForRow = PR_MIN(excessForRow, aExcess - aExcessAllocated);
nsRect newRowRect(rowRect.x, y, rowRect.width, excessForRow + rowRect.height);
rowFrame->SetRect(aPresContext, newRowRect);
y = newRowRect.YMost() + cellSpacingY;
aExcessAllocated += excessForRow;
excessForRowGroup += excessForRow;
}
rowGroupFrame->GetNextFrame(rowFrame, &rowFrame);
}
nsRect rowGroupRect;
aRowGroupFrame->GetRect(rowGroupRect);
nsRect newRowGroupRect(rowGroupRect.x, aRowGroupYPos, rowGroupRect.width,
excessForRowGroup + rowGroupRect.height);
aRowGroupFrame->SetRect(aPresContext, newRowGroupRect);
aRowGroupYPos = newRowGroupRect.YMost();
DistributeSpaceToCells(aPresContext, aReflowState, aRowGroupFrame);
}
nscoord
nsTableFrame::CalcDesiredHeight(nsIPresContext* aPresContext,
@ -3347,65 +3328,239 @@ nsTableFrame::CalcDesiredHeight(nsIPresContext* aPresContext,
OrderRowGroups(rowGroups, numRowGroups, nsnull);
if (numRowGroups <= 0) return 0;
nscoord naturalHeight = borderPadding.top + cellSpacingY + borderPadding.bottom;
nscoord desiredHeight = borderPadding.top + cellSpacingY + borderPadding.bottom;
for (PRUint32 rgX = 0; rgX < numRowGroups; rgX++) {
nsIFrame* rg = (nsIFrame*)rowGroups.ElementAt(rgX);
if (rg) {
nsRect rgRect;
rg->GetRect(rgRect);
naturalHeight += rgRect.height + cellSpacingY;
desiredHeight += rgRect.height + cellSpacingY;
}
}
nscoord desiredHeight = naturalHeight;
// see if a specified table height requires dividing additional space to rows
if (!mPrevInFlow) {
nscoord tableSpecifiedHeight = CalcBorderBoxHeight(aReflowState);
if ((tableSpecifiedHeight > 0) &&
(tableSpecifiedHeight != NS_UNCONSTRAINEDSIZE) &&
(tableSpecifiedHeight > naturalHeight)) {
desiredHeight = tableSpecifiedHeight;
(tableSpecifiedHeight > desiredHeight)) {
// proportionately distribute the excess height to unconstrained rows in each
// unconstrained row group.We don't need to do this if it's an unconstrained reflow
if (NS_UNCONSTRAINEDSIZE != aReflowState.availableWidth) {
// proportionately distribute the excess height to each row. Note that we
// don't need to do this if it's an unconstrained reflow
nscoord excess = tableSpecifiedHeight - naturalHeight;
nscoord sumOfRowHeights = 0;
nscoord rowGroupYPos = aReflowState.mComputedBorderPadding.top + cellSpacingY;
nsAutoVoidArray rowGroups;
PRUint32 numRowGroups;
OrderRowGroups(rowGroups, numRowGroups, nsnull);
PRUint32 rgX;
for (rgX = 0; rgX < numRowGroups; rgX++) {
nsTableRowGroupFrame* rgFrame =
GetRowGroupFrame((nsIFrame*)rowGroups.ElementAt(rgX));
if (rgFrame) {
sumOfRowHeights += rgFrame->GetHeightOfRows(aPresContext);
}
}
nscoord excessAllocated = 0;
for (rgX = 0; rgX < numRowGroups; rgX++) {
nsTableRowGroupFrame* rgFrame =
GetRowGroupFrame((nsIFrame*)rowGroups.ElementAt(rgX));
if (rgFrame) {
DistributeSpaceToRows(aPresContext, aReflowState, rgFrame, sumOfRowHeights,
excess, excessAllocated, rowGroupYPos);
// Make sure child views are properly positioned
// XXX what happens if childFrame is a scroll frame and this gets skipped?
nsTableFrame::RePositionViews(aPresContext, rgFrame);
}
rowGroupYPos += cellSpacingY;
}
DistributeHeightToRows(aPresContext, aReflowState, tableSpecifiedHeight - desiredHeight);
}
desiredHeight = tableSpecifiedHeight;
}
}
return desiredHeight;
}
static
void ResizeCells(nsTableFrame& aTableFrame,
nsIPresContext* aPresContext,
const nsHTMLReflowState& aReflowState)
{
nsAutoVoidArray rowGroups;
PRUint32 numRowGroups;
aTableFrame.OrderRowGroups(rowGroups, numRowGroups, nsnull);
for (PRUint32 rgX = 0; (rgX < numRowGroups); rgX++) {
nsTableRowGroupFrame* rgFrame = aTableFrame.GetRowGroupFrame((nsIFrame*)rowGroups.ElementAt(rgX));
nsTableRowFrame* rowFrame = rgFrame->GetFirstRow();
while (rowFrame) {
rowFrame->DidResize(aPresContext, aReflowState);
rowFrame = rowFrame->GetNextRow();
}
}
}
void
nsTableFrame::DistributeHeightToRows(nsIPresContext* aPresContext,
const nsHTMLReflowState& aReflowState,
nscoord aAmount)
{
float p2t;
aPresContext->GetPixelsToTwips(&p2t);
nscoord cellSpacingY = GetCellSpacingY();
nscoord sumOfRowHeights = 0;
nscoord rowGroupYPos = aReflowState.mComputedBorderPadding.top + cellSpacingY;
nsVoidArray rowGroups;
PRUint32 numRowGroups;
OrderRowGroups(rowGroups, numRowGroups, nsnull);
nscoord amountUsed = 0;
// distribute space to each pct height row whose row group doesn't have a computed
// height, and base the pct on the table height. If the row group had a computed
// height, then this was already done in nsTableRowGroupFrame::CalculateRowHeights
nscoord pctBasis = aReflowState.mComputedHeight - (GetCellSpacingY() * (GetRowCount() + 1));
nscoord yOriginRG = aReflowState.mComputedBorderPadding.top + GetCellSpacingY();
nscoord yEndRG = yOriginRG;
PRUint32 rgX;
for (rgX = 0; (rgX < numRowGroups); rgX++) {
nsTableRowGroupFrame* rgFrame = GetRowGroupFrame((nsIFrame*)rowGroups.ElementAt(rgX));
nscoord amountUsedByRG = 0;
nscoord yOriginRow = 0;
nsRect rgRect;
rgFrame->GetRect(rgRect);
if (rgFrame && !rgFrame->HasStyleHeight()) {
nsTableRowFrame* rowFrame = rgFrame->GetFirstRow();
while (rowFrame) {
nsRect rowRect;
rowFrame->GetRect(rowRect);
if ((amountUsed < aAmount) && rowFrame->HasPctHeight()) {
nscoord pctHeight = nsTableFrame::RoundToPixel(rowFrame->GetHeight(pctBasis), p2t);
nscoord amountForRow = PR_MIN(aAmount - amountUsed, pctHeight - rowRect.height);
if (amountForRow > 0) {
rowRect.height += amountForRow;
rowFrame->SetRect(aPresContext, rowRect);
yOriginRow += rowRect.height + cellSpacingY;
yEndRG += rowRect.height + cellSpacingY;
amountUsed += amountForRow;
amountUsedByRG += amountForRow;
//rowFrame->DidResize(aPresContext, aReflowState);
nsTableFrame::RePositionViews(aPresContext, rowFrame);
}
}
else {
if (amountUsed > 0) {
rowFrame->MoveTo(aPresContext, rowRect.x, yOriginRow);
nsTableFrame::RePositionViews(aPresContext, rowFrame);
}
yOriginRow += rowRect.height + cellSpacingY;
yEndRG += rowRect.height + cellSpacingY;
}
rowFrame = rowFrame->GetNextRow();
}
if (amountUsed > 0) {
rgRect.y = yOriginRG;
rgRect.height += amountUsedByRG;
rgFrame->SetRect(aPresContext, rgRect);
}
}
else if (amountUsed > 0) {
rgFrame->MoveTo(aPresContext, 0, yOriginRG);
// Make sure child views are properly positioned
nsTableFrame::RePositionViews(aPresContext, rgFrame);
}
yOriginRG = yEndRG;
}
if (amountUsed >= aAmount) {
ResizeCells(*this, aPresContext, aReflowState);
return;
}
// get the first row without a style height where its row group has an unconstrianed height
nsTableRowGroupFrame* firstUnStyledRG = nsnull;
nsTableRowFrame* firstUnStyledRow = nsnull;
for (rgX = 0; (rgX < numRowGroups) && !firstUnStyledRG; rgX++) {
nsTableRowGroupFrame* rgFrame = GetRowGroupFrame((nsIFrame*)rowGroups.ElementAt(rgX));
if (rgFrame && !rgFrame->HasStyleHeight()) {
nsTableRowFrame* rowFrame = rgFrame->GetFirstRow();
while (rowFrame) {
if (!rowFrame->HasStyleHeight()) {
firstUnStyledRG = rgFrame;
firstUnStyledRow = rowFrame;
break;
}
rowFrame = rowFrame->GetNextRow();
}
}
}
nsTableRowFrame* lastElligibleRow = nsnull;
// accumulate the correct divisor. This will be the total of all unstyled rows inside
// unstyled row groups, unless there are none, in which case, it will be all rows
nscoord divisor = 0;
for (rgX = 0; rgX < numRowGroups; rgX++) {
nsTableRowGroupFrame* rgFrame = GetRowGroupFrame((nsIFrame*)rowGroups.ElementAt(rgX));
if (rgFrame && (!firstUnStyledRG || !rgFrame->HasStyleHeight())) {
nsTableRowFrame* rowFrame = rgFrame->GetFirstRow();
while (rowFrame) {
if (!firstUnStyledRG || !rowFrame->HasStyleHeight()) {
nsRect rowRect;
rowFrame->GetRect(rowRect);
divisor += rowRect.height;
lastElligibleRow = rowFrame;
}
rowFrame = rowFrame->GetNextRow();
}
}
}
if (divisor <= 0) {
NS_ASSERTION(PR_FALSE, "invlaid divisor");
return;
}
// allocate the extra height to the unstyled row groups and rows
pctBasis = aAmount - amountUsed;
yOriginRG = aReflowState.mComputedBorderPadding.top + cellSpacingY;
yEndRG = yOriginRG;
for (rgX = 0; rgX < numRowGroups; rgX++) {
nsTableRowGroupFrame* rgFrame = GetRowGroupFrame((nsIFrame*)rowGroups.ElementAt(rgX));
if (!rgFrame) continue;
nscoord amountUsedByRG = 0;
nscoord yOriginRow = 0;
nsRect rgRect;
rgFrame->GetRect(rgRect);
// see if there is an eligible row group
if (!firstUnStyledRG || !rgFrame->HasStyleHeight()) {
nsTableRowFrame* rowFrame = rgFrame->GetFirstRow();
while (rowFrame) {
nsRect rowRect;
rowFrame->GetRect(rowRect);
// see if there is an eligible row
if (!firstUnStyledRow || !rowFrame->HasStyleHeight()) {
// The amount of additional space each row gets is proportional to its height
float percent = rowRect.height / ((float)divisor);
// give rows their percentage, except for the last row which gets the remainder
nscoord amountForRow = (rowFrame == lastElligibleRow)
? aAmount - amountUsed : NSToCoordRound(((float)(pctBasis)) * percent);
amountForRow = PR_MIN(nsTableFrame::RoundToPixel(amountForRow, p2t), aAmount - amountUsed);
// update the row height
nsRect newRowRect(rowRect.x, yOriginRow, rowRect.width, rowRect.height + amountForRow);
rowFrame->SetRect(aPresContext, newRowRect);
yOriginRow += newRowRect.height + cellSpacingY;
yEndRG += newRowRect.height + cellSpacingY;
amountUsed += amountForRow;
amountUsedByRG += amountForRow;
NS_ASSERTION((amountUsed <= aAmount), "invalid row allocation");
//rowFrame->DidResize(aPresContext, aReflowState);
nsTableFrame::RePositionViews(aPresContext, rowFrame);
}
else {
if (amountUsed > 0) {
rowFrame->MoveTo(aPresContext, rowRect.x, yOriginRow);
nsTableFrame::RePositionViews(aPresContext, rowFrame);
}
yOriginRow += rowRect.height + cellSpacingY;
yEndRG += rowRect.height + cellSpacingY;
}
rowFrame = rowFrame->GetNextRow();
}
if (amountUsed > 0) {
rgRect.y = yOriginRG;
rgRect.height += amountUsedByRG;
rgFrame->SetRect(aPresContext, rgRect);
}
// Make sure child views are properly positioned
// XXX what happens if childFrame is a scroll frame and this gets skipped? see also below
}
else if (amountUsed > 0) {
rgFrame->MoveTo(aPresContext, 0, yOriginRG);
// Make sure child views are properly positioned
nsTableFrame::RePositionViews(aPresContext, rgFrame);
}
yOriginRG = yEndRG;
}
ResizeCells(*this, aPresContext, aReflowState);
}
static void
UpdateCol(nsTableFrame& aTableFrame,
nsTableColFrame& aColFrame,
@ -3435,6 +3590,17 @@ UpdateCol(nsTableFrame& aTableFrame,
}
}
PRBool
nsTableFrame::IsPctHeight(nsIStyleContext* aStyleContext)
{
PRBool result = PR_FALSE;
if (aStyleContext) {
nsStylePosition* position = (nsStylePosition*)aStyleContext->GetStyleData(eStyleStruct_Position);
result = (eStyleUnit_Percent == position->mHeight.GetUnit());
}
return result;
}
PRBool
nsTableFrame::CellChangedWidth(const nsTableCellFrame& aCellFrame,
nscoord aPrevCellMin,
@ -4370,9 +4536,20 @@ NS_IMETHODIMP nsTableFrame::GetTableSize(PRInt32& aRowCount, PRInt32& aColCount)
PRInt32 nsTableFrame::GetNumCellsOriginatingInCol(PRInt32 aColIndex) const
{
nsTableCellMap* cellMap = GetCellMap();
return cellMap->GetNumCellsOriginatingInCol(aColIndex);
if (cellMap)
return cellMap->GetNumCellsOriginatingInCol(aColIndex);
else
return 0;
}
PRInt32 nsTableFrame::GetNumCellsOriginatingInRow(PRInt32 aRowIndex) const
{
nsTableCellMap* cellMap = GetCellMap();
if (cellMap)
return cellMap->GetNumCellsOriginatingInRow(aRowIndex);
else
return 0;
}
/********************************************************************************
@ -4477,7 +4654,11 @@ void nsTableFrame::DebugReflow(nsIFrame* aFrame,
if (!aMetrics) { // start
PrettyUC(aState.availableWidth, width);
PrettyUC(aState.availableHeight, height);
printf("r=%d a=%s,%s ", aState.reason, width, height);
printf("r=%d ", aState.reason);
if (aState.mFlags.mSpecialTableReflow) {
printf("special ");
}
printf("a=%s,%s ", width, height);
PrettyUC(aState.mComputedWidth, width);
PrettyUC(aState.mComputedHeight, height);
printf("c=%s,%s ", width, height);

View File

@ -207,6 +207,8 @@ public:
float aPixelToTwips,
nsPixelRound aRound= eAlwaysRoundUp);
static void NotifyAncestorsOfSpecialReflow(const nsHTMLReflowState& aReflowState);
NS_IMETHOD IsPercentageBase(PRBool& aBase) const;
static nsresult AppendDirtyReflowCommand(nsIPresShell* aPresShell,
@ -258,6 +260,7 @@ public:
nsIAtom* aChildType);
PRBool IsAutoWidth(PRBool* aIsPctWidth = nsnull);
PRBool IsAutoHeight();
static PRBool IsPctHeight(nsIStyleContext* aStyleContext);
/** @return PR_TRUE if aDisplayType represents a rowgroup of any sort
* (header, footer, or body)
@ -491,14 +494,18 @@ public:
PRInt32* aColSpan = nsnull);
PRInt32 GetNumCellsOriginatingInCol(PRInt32 aColIndex) const;
PRInt32 GetNumCellsOriginatingInRow(PRInt32 aRowIndex) const;
PRBool HasPctCol() const;
void SetHasPctCol(PRBool aValue);
PRBool HasCellSpanningPctCol() const;
void SetHasCellSpanningPctCol(PRBool aValue);
// is this the 3rd reflow due to a height on a table in pagination mode.
PRBool IsThirdPassReflow() const;
PRBool NeedSpecialReflow() const;
void SetNeedSpecialReflow(PRBool aValue);
PRBool NeedToInitiateSpecialReflow() const;
void SetNeedToInitiateSpecialReflow(PRBool aValue);
protected:
@ -527,7 +534,6 @@ protected:
void SetDescendantReflowedNotTimeout(PRBool aValue);
PRBool RequestedTimeoutReflow() const;
void SetRequestedTimeoutReflow(PRBool aValue);
void SetThirdPassReflow(PRBool aValue);
void InterruptNotification(nsIPresContext* aPresContext,
PRBool aIsRequest);
@ -652,18 +658,12 @@ protected:
// reflow state, and for the table attributes and parent
nscoord CalcDesiredHeight(nsIPresContext* aPresContext,
const nsHTMLReflowState& aReflowState);
// The following two functions are helpers for CalcDesiredHeight
// The following is a helper for CalcDesiredHeight
void DistributeSpaceToCells(nsIPresContext* aPresContext,
void DistributeHeightToRows(nsIPresContext* aPresContext,
const nsHTMLReflowState& aReflowState,
nsIFrame* aRowGroupFrame);
void DistributeSpaceToRows(nsIPresContext* aPresContext,
const nsHTMLReflowState& aReflowState,
nsIFrame* aRowGroupFrame,
nscoord aSumOfRowHeights,
nscoord aExcess,
nscoord& aExcessAllocated,
nscoord& aRowGroupYPos);
nscoord aAmount);
void PlaceChild(nsIPresContext* aPresContext,
nsTableReflowState& aReflowState,
@ -830,8 +830,6 @@ public: /* ----- Cell Map public methods ----- */
// percentage height cells
void ComputePercentBasisForRows(const nsHTMLReflowState& aReflowState);
nscoord GetPercentBasisForRows();
nscoord GetMinWidth() const;
void SetMinWidth(nscoord aWidth);
@ -895,8 +893,9 @@ protected:
// targeted at us, as an optimization.
unsigned mRequestedTimeoutReflow:1;
unsigned mRowInserted:1;
unsigned mThirdPassReflow:1;
int : 21; // unused
unsigned mNeedSpecialReflow:1;
unsigned mNeedToInitiateSpecialReflow:1;
int : 19; // unused
} mBits;
nsTableCellMap* mCellMap; // maintains the relationships between rows, cols, and cells
@ -941,11 +940,6 @@ inline PRBool nsTableFrame::IsRowGroup(PRInt32 aDisplayType) const
(NS_STYLE_DISPLAY_TABLE_ROW_GROUP == aDisplayType));
}
inline nscoord nsTableFrame::GetPercentBasisForRows()
{
return mPercentBasisForRows;
}
inline void nsTableFrame::SetHadInitialReflow(PRBool aValue)
{
mBits.mHadInitialReflow = aValue;
@ -1006,16 +1000,25 @@ inline void nsTableFrame::SetRequestedTimeoutReflow(PRBool aValue)
mBits.mRequestedTimeoutReflow = (unsigned)aValue;
}
inline PRBool nsTableFrame::IsThirdPassReflow() const
inline PRBool nsTableFrame::NeedSpecialReflow() const
{
return (PRBool)mBits.mThirdPassReflow;
return (PRBool)mBits.mNeedSpecialReflow;
}
inline void nsTableFrame::SetThirdPassReflow(PRBool aValue)
inline void nsTableFrame::SetNeedSpecialReflow(PRBool aValue)
{
mBits.mThirdPassReflow = (unsigned)aValue;
mBits.mNeedSpecialReflow = (unsigned)aValue;
}
inline PRBool nsTableFrame::NeedToInitiateSpecialReflow() const
{
return (PRBool)mBits.mNeedToInitiateSpecialReflow;
}
inline void nsTableFrame::SetNeedToInitiateSpecialReflow(PRBool aValue)
{
mBits.mNeedToInitiateSpecialReflow = (unsigned)aValue;
}
inline PRBool nsTableFrame::IsRowInserted() const
{
return (PRBool)mBits.mRowInserted;

View File

@ -94,6 +94,42 @@ nsTableCellReflowState::nsTableCellReflowState(nsIPresContext* aPresCon
FixUp(aAvailSpace);
}
void
nsTableRowFrame::SetFixedHeight(nscoord aValue)
{
if (!HasPctHeight()) {
nscoord height = PR_MAX(0, aValue);
if (HasFixedHeight()) {
if (height > mStyleHeight) {
mStyleHeight = height;
}
}
else {
mStyleHeight = height;
if (height > 0) {
SetHasFixedHeight(PR_TRUE);
}
}
}
}
void
nsTableRowFrame::SetPctHeight(float aPctValue)
{
nscoord height = PR_MAX(0, NSToCoordRound(aPctValue * 100.0f));
if (HasPctHeight()) {
if (height > mStyleHeight) {
mStyleHeight = height;
}
}
else {
mStyleHeight = height;
if (height > 0.0f) {
SetHasPctHeight(PR_TRUE);
}
}
}
void nsTableCellReflowState::FixUp(const nsSize& aAvailSpace)
{
// fix the mComputed values during a pass 2 reflow since the cell can be a percentage base
@ -121,15 +157,13 @@ TallestCellGotShorter(nscoord aOld,
return ((aNew < aOld) && (aOld == aTallest));
}
/* ----------- nsTableRowpFrame ---------- */
/* ----------- nsTableRowFrame ---------- */
nsTableRowFrame::nsTableRowFrame()
: nsHTMLContainerFrame(),
mAllBits(0)
: nsHTMLContainerFrame()
{
mBits.mMinRowSpan = 1;
mBits.mRowIndex = 0;
ResetTallestCell(0);
mBits.mRowIndex = mBits.mFirstInserted = 0;
ResetHeight(0);
#ifdef DEBUG_TABLE_REFLOW_TIMING
mTimer = new nsReflowTimer(this);
#endif
@ -329,6 +363,20 @@ GetHeightOfRowsSpannedBelowFirst(nsTableCellFrame& aTableCellFrame,
return height;
}
nsTableCellFrame*
nsTableRowFrame::GetFirstCell()
{
nsIFrame* childFrame = mFrames.FirstChild();
while (childFrame) {
nsCOMPtr<nsIAtom> frameType;
childFrame->GetFrameType(getter_AddRefs(frameType));
if (nsLayoutAtoms::tableCellFrame == frameType.get()) {
return (nsTableCellFrame*)childFrame;
}
childFrame->GetNextSibling(&childFrame);
}
return nsnull;
}
/**
* Post-reflow hook. This is where the table row does its post-processing
@ -390,43 +438,53 @@ nscoord nsTableRowFrame::GetMaxCellAscent() const
return mMaxCellAscent;
}
#if 0 // nobody uses this
// returns max-descent amongst all cells that have 'vertical-align: baseline'
// does *not* include cells with rowspans
nscoord nsTableRowFrame::GetMaxCellDescent() const
nscoord
nsTableRowFrame::GetHeight(nscoord aPctBasis) const
{
return mMaxCellDescent;
}
#endif
/** returns the height of the tallest child in this row (ignoring any cell with rowspans) */
nscoord nsTableRowFrame::GetTallestCell() const
{
return mTallestCell;
nscoord height = 0;
if ((aPctBasis > 0) && HasPctHeight()) {
height = NSToCoordRound(GetPctHeight() * (float)aPctBasis);
}
else if (HasFixedHeight()) {
height = GetFixedHeight();
}
return PR_MAX(height, GetContentHeight());
}
void
nsTableRowFrame::ResetTallestCell(nscoord aRowStyleHeight)
nsTableRowFrame::ResetHeight(nscoord aFixedHeight)
{
mTallestCell = (NS_UNCONSTRAINEDSIZE == aRowStyleHeight) ? 0 : aRowStyleHeight;
SetHasFixedHeight(PR_FALSE);
SetHasPctHeight(PR_FALSE);
SetFixedHeight(0);
SetContentHeight(0);
if (aFixedHeight > 0) {
SetFixedHeight(aFixedHeight);
}
mMaxCellAscent = 0;
mMaxCellDescent = 0;
}
void
nsTableRowFrame::SetTallestCell(nscoord aHeight,
nscoord aAscent,
nscoord aDescent,
nsTableFrame* aTableFrame,
nsTableCellFrame* aCellFrame)
nsTableRowFrame::UpdateHeight(nscoord aHeight,
nscoord aAscent,
nscoord aDescent,
nsTableFrame* aTableFrame,
nsTableCellFrame* aCellFrame)
{
NS_ASSERTION((aTableFrame && aCellFrame) , "invalid call");
if (!aTableFrame || !aCellFrame) {
NS_ASSERTION(PR_FALSE , "invalid call");
return;
}
if (aHeight != NS_UNCONSTRAINEDSIZE) {
if (!(aCellFrame->HasVerticalAlignBaseline())) { // only the cell's height matters
if (mTallestCell < aHeight) {
if (GetHeight() < aHeight) {
PRInt32 rowSpan = aTableFrame->GetEffectiveRowSpan(*aCellFrame);
if (rowSpan == 1) {
mTallestCell = aHeight;
SetContentHeight(aHeight);
}
}
}
@ -444,21 +502,23 @@ nsTableRowFrame::SetTallestCell(nscoord aHeight,
}
}
// keep the tallest height in sync
if (mTallestCell < mMaxCellAscent + mMaxCellDescent) {
mTallestCell = mMaxCellAscent + mMaxCellDescent;
if (GetHeight() < mMaxCellAscent + mMaxCellDescent) {
SetContentHeight(mMaxCellAscent + mMaxCellDescent);
}
}
}
}
void
nsTableRowFrame::CalcTallestCell()
nscoord
nsTableRowFrame::CalcHeight(const nsHTMLReflowState& aReflowState)
{
nsTableFrame* tableFrame = nsnull;
nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame);
if (NS_FAILED(rv)) return;
if (!tableFrame) return 0;
ResetTallestCell(0);
nscoord computedHeight = (NS_UNCONSTRAINEDSIZE == aReflowState.mComputedHeight)
? 0 : aReflowState.mComputedHeight;
ResetHeight(computedHeight);
for (nsIFrame* kidFrame = mFrames.FirstChild(); kidFrame; kidFrame->GetNextSibling(&kidFrame)) {
nsCOMPtr<nsIAtom> frameType;
@ -470,9 +530,10 @@ nsTableRowFrame::CalcTallestCell()
// height may have changed, adjust descent to absorb any excess difference
nscoord ascent = ((nsTableCellFrame *)kidFrame)->GetDesiredAscent();
nscoord descent = desSize.height - ascent;
SetTallestCell(desSize.height, ascent, descent, tableFrame, (nsTableCellFrame*)kidFrame);
UpdateHeight(desSize.height, ascent, descent, tableFrame, (nsTableCellFrame*)kidFrame);
}
}
return GetHeight();
}
#if 0
@ -648,49 +709,6 @@ nsTableRowFrame::GetFrameForPoint(nsIPresContext* aPresContext,
return NS_ERROR_FAILURE;
}
/* GetMinRowSpan is needed for deviant cases where every cell in a row has a rowspan > 1.
* It sets mMinRowSpan, which is used in FixMinCellHeight
*/
void nsTableRowFrame::GetMinRowSpan(nsTableFrame *aTableFrame)
{
PRInt32 minRowSpan=-1;
nsIFrame* frame = mFrames.FirstChild();
while (frame)
{
const nsStyleDisplay *kidDisplay;
frame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)kidDisplay));
if (NS_STYLE_DISPLAY_TABLE_CELL == kidDisplay->mDisplay)
{
PRInt32 rowSpan = aTableFrame->GetEffectiveRowSpan((nsTableCellFrame &)*frame);
if (-1==minRowSpan)
minRowSpan = rowSpan;
else if (minRowSpan>rowSpan)
minRowSpan = rowSpan;
}
frame->GetNextSibling(&frame);
}
mBits.mMinRowSpan = unsigned(minRowSpan);
}
void nsTableRowFrame::FixMinCellHeight(nsTableFrame *aTableFrame)
{
nsIFrame* frame = mFrames.FirstChild();
while (frame) {
nsCOMPtr<nsIAtom> frameType;
frame->GetFrameType(getter_AddRefs(frameType));
if (nsLayoutAtoms::tableCellFrame == frameType.get()) {
PRInt32 rowSpan = aTableFrame->GetEffectiveRowSpan((nsTableCellFrame &)*frame);
if (PRInt32(mBits.mMinRowSpan) == rowSpan) {
nsRect rect;
frame->GetRect(rect);
if (rect.height > mTallestCell)
mTallestCell = rect.height;
}
}
frame->GetNextSibling(&frame);
}
}
// Calculate the cell's actual size given its pass2 desired width and height.
// Takes into account the specified height (in the style), and any special logic
// needed for backwards compatibility.
@ -701,37 +719,37 @@ nsTableRowFrame::CalculateCellActualSize(nsIFrame* aCellFrame,
nscoord& aDesiredHeight,
nscoord aAvailWidth)
{
nscoord specifiedHeight = 0;
const nsStylePosition* position;
nscoord specifiedHeight = 0;
// Get the height specified in the style information
const nsStylePosition* position;
aCellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)position);
nsTableFrame* tableFrame = nsnull;
nsTableFrame::GetTableFrame(this, tableFrame);
if (!tableFrame) return NS_ERROR_NULL_POINTER;
PRInt32 rowSpan = tableFrame->GetEffectiveRowSpan((nsTableCellFrame&)*aCellFrame);
switch (position->mHeight.GetUnit()) {
case eStyleUnit_Coord:
specifiedHeight = position->mHeight.GetCoordValue();
if (1 == rowSpan)
SetFixedHeight(specifiedHeight);
break;
case eStyleUnit_Percent: {
nsTableFrame* table = nsnull;
nsTableFrame::GetTableFrame(this, table);
if (table) {
nscoord basis = table->GetPercentBasisForRows();
if (basis > 0) {
float percent = position->mHeight.GetPercentValue();
specifiedHeight = NSToCoordRound(percent * ((float)basis));
}
}
if (1 == rowSpan)
SetPctHeight(position->mHeight.GetPercentValue());
// pct heights are handled when all of the cells are finished, so don't set specifiedHeight
break;
}
case eStyleUnit_Inherit:
// XXX for now, do nothing
case eStyleUnit_Auto:
default:
break;
}
// If the specified height is greater than the desired height, then use the
// specified height
// If the specified height is greater than the desired height, then use the specified height
if (specifiedHeight > aDesiredHeight)
aDesiredHeight = specifiedHeight;
@ -865,6 +883,7 @@ nsTableRowFrame::ReflowChildren(nsIPresContext* aPresContext,
PRInt32 prevColIndex = firstPrevColIndex;
nscoord x = 0; // running total of children x offset
nsTableFrame* tableFirstInFlow = (nsTableFrame*)tableFrame->GetFirstInFlow();
PRBool isAutoLayout = tableFrame->IsAutoLayout();
PRBool needToNotifyTable = PR_TRUE;
// Reflow each of our existing cell frames
@ -874,14 +893,21 @@ nsTableRowFrame::ReflowChildren(nsIPresContext* aPresContext,
nsFrameState frameState;
kidFrame->GetFrameState(&frameState);
nsCOMPtr<nsIAtom> frameType;
kidFrame->GetFrameType(getter_AddRefs(frameType));
// See if we should only reflow the dirty child frames
PRBool doReflowChild = PR_TRUE;
if (aDirtyOnly && ((frameState & NS_FRAME_IS_DIRTY) == 0)) {
doReflowChild = PR_FALSE;
}
nsCOMPtr<nsIAtom> frameType;
kidFrame->GetFrameType(getter_AddRefs(frameType));
if (aReflowState.mFlags.mSpecialTableReflow) {
if (!isPaginated && (nsLayoutAtoms::tableCellFrame == frameType.get() &&
!((nsTableCellFrame*)kidFrame)->NeedSpecialReflow())) {
kidFrame = iter.Next();
continue;
}
}
// Reflow the child frame
if (doReflowChild) {
@ -919,7 +945,9 @@ nsTableRowFrame::ReflowChildren(nsIPresContext* aPresContext,
if ((availCellWidth != cellFrame->GetPriorAvailWidth()) ||
(cellDesiredSize.width > cellFrame->GetPriorAvailWidth()) ||
(eReflowReason_StyleChange == aReflowState.reason) ||
isPaginated) {
isPaginated ||
(aReflowState.mFlags.mSpecialTableReflow && cellFrame->NeedSpecialReflow()) ||
HasPctHeight()) {
// Reflow the cell to fit the available width, height
nsSize kidAvailSize(availColWidth, aReflowState.availableHeight);
nsReflowReason reason = eReflowReason_Resize;
@ -1002,7 +1030,7 @@ nsTableRowFrame::ReflowChildren(nsIPresContext* aPresContext,
// height may have changed, adjust descent to absorb any excess difference
nscoord ascent = cellFrame->GetDesiredAscent();
nscoord descent = desiredSize.height - ascent;
SetTallestCell(desiredSize.height, ascent, descent, tableFrame, cellFrame);
UpdateHeight(desiredSize.height, ascent, descent, tableFrame, cellFrame);
// Place the child
if (NS_UNCONSTRAINEDSIZE != availColWidth) {
@ -1037,8 +1065,7 @@ nsTableRowFrame::ReflowChildren(nsIPresContext* aPresContext,
// just set our width to what was available. The table will calculate the width and not use our value.
aDesiredSize.width = aReflowState.availableWidth;
CalcTallestCell();
aDesiredSize.height = GetTallestCell();
aDesiredSize.height = CalcHeight(aReflowState);
return rv;
}
@ -1050,7 +1077,7 @@ NS_METHOD nsTableRowFrame::IncrementalReflow(nsIPresContext* aPresConte
nsReflowStatus& aStatus)
{
nsresult rv = NS_OK;
CalcTallestCell(); // need to recalculate it based on last reflow sizes
CalcHeight(aReflowState); // need to recalculate it based on last reflow sizes
// determine if this frame is the target or not
nsIFrame* target = nsnull;
@ -1193,7 +1220,7 @@ nsTableRowFrame::IR_TargetIsChild(nsIPresContext* aPresContext,
if (!hasVerticalAlignBaseline) {
// only the height matters
tallestCellGotShorter =
TallestCellGotShorter(oldCellDesSize.height, cellMet.height, mTallestCell);
TallestCellGotShorter(oldCellDesSize.height, cellMet.height, GetHeight());
}
else {
// the ascent matters
@ -1209,10 +1236,10 @@ nsTableRowFrame::IR_TargetIsChild(nsIPresContext* aPresContext,
}
}
if (tallestCellGotShorter) {
CalcTallestCell();
CalcHeight(aReflowState);
}
else {
SetTallestCell(cellMet.height, cellMet.ascent, cellMet.descent, &aTableFrame, cellFrame);
UpdateHeight(cellMet.height, cellMet.ascent, cellMet.descent, &aTableFrame, cellFrame);
}
// if the cell's desired size didn't changed, our height is unchanged
@ -1232,7 +1259,7 @@ nsTableRowFrame::IR_TargetIsChild(nsIPresContext* aPresContext,
}
}
}
aDesiredSize.height = (aDesiredSize.mNothingChanged) ? mRect.height : GetTallestCell();
aDesiredSize.height = (aDesiredSize.mNothingChanged) ? mRect.height : GetHeight();
if (1 == rowSpan) {
cellMet.height = aDesiredSize.height;
}
@ -1308,25 +1335,19 @@ nsTableRowFrame::Reflow(nsIPresContext* aPresContext,
rv = nsTableFrame::GetTableFrame(this, tableFrame);
if (!tableFrame) return NS_ERROR_NULL_POINTER;
if ((NS_UNCONSTRAINEDSIZE != aReflowState.availableWidth) && !mPrevInFlow) {
// see if an extra reflow will be necessary when there is a pct height but no height on the parent
if ( ((NS_UNCONSTRAINEDSIZE == aReflowState.mComputedHeight) ||
(0 == aReflowState.mComputedHeight)) &&
nsTableFrame::IsPctHeight(mStyleContext)) {
nsTableFrame::NotifyAncestorsOfSpecialReflow(aReflowState);
SetNeedSpecialReflow(PR_TRUE);
}
}
switch (aReflowState.reason) {
case eReflowReason_Initial:
rv = ReflowChildren(aPresContext, aDesiredSize, aReflowState, *tableFrame, aStatus, PR_FALSE);
#ifdef WHY
if (!tableFrame->IsAutoLayout()) {
// this resize reflow is necessary to place the cells correctly in the case of rowspans and colspans.
// It is very efficient. It does not actually need to pass a reflow down to the cells.
nsSize availSpace(aReflowState.availableWidth, aReflowState.availableHeight);
nsHTMLReflowState resizeReflowState(aPresContext,
(const nsHTMLReflowState&)(*(aReflowState.parentReflowState)),
(nsIFrame *)this,
availSpace,
eReflowReason_Resize);
RowReflowState rowResizeReflowState(resizeReflowState, tableFrame);
rv = ReflowChildren(aPresContext, aDesiredSize, rowResizeReflowState, aStatus);
}
#endif
//GetMinRowSpan(tableFrame);
//FixMinCellHeight(tableFrame);
aStatus = NS_FRAME_COMPLETE;
break;
@ -1343,6 +1364,10 @@ nsTableRowFrame::Reflow(nsIPresContext* aPresContext,
// just set our width to what was available. The table will calculate the width and not use our value.
aDesiredSize.width = aReflowState.availableWidth;
if (aReflowState.mFlags.mSpecialTableReflow) {
SetNeedSpecialReflow(PR_FALSE);
}
#if defined DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState, &aDesiredSize, aStatus);
#endif
@ -1463,6 +1488,21 @@ nsTableRowFrame::GetFrameType(nsIAtom** aType) const
return NS_OK;
}
nsTableRowFrame*
nsTableRowFrame::GetNextRow() const
{
nsIFrame* childFrame;
GetNextSibling(&childFrame);
while (childFrame) {
nsCOMPtr<nsIAtom> frameType;
childFrame->GetFrameType(getter_AddRefs(frameType));
if (nsLayoutAtoms::tableRowFrame == frameType.get()) {
return (nsTableRowFrame*)childFrame;
}
childFrame->GetNextSibling(&childFrame);
}
return nsnull;
}
/* ----- global methods ----- */

View File

@ -47,7 +47,7 @@ class nsTableCellFrame;
class nsReflowTimer;
#endif
#define NS_TABLE_MAX_ROW_INDEX (1<<19)
#define NS_ROW_NEED_SPECIAL_REFLOW 0x20000000
#define NS_ROW_FRAME_PAINT_SKIP_ROW 0x00000001
#define NS_ROW_FRAME_PAINT_SKIP_CELLS 0x00000002
@ -121,6 +121,8 @@ public:
nsFramePaintLayer aWhichLayer,
nsIFrame** aFrame);
nsTableCellFrame* GetFirstCell() ;
/** calls Reflow for all of its child cells.
* Cells with rowspan=1 are all set to the same height and stacked horizontally.
* <P> Cells are not split unless absolutely necessary.
@ -155,19 +157,17 @@ public:
PRUint32* aResult) const;
#endif
void SetTallestCell(nscoord aHeight,
nscoord aAscent,
nscoord aDescent,
nsTableFrame* aTableFrame = nsnull,
nsTableCellFrame* aCellFrame = nsnull);
void UpdateHeight(nscoord aHeight,
nscoord aAscent,
nscoord aDescent,
nsTableFrame* aTableFrame = nsnull,
nsTableCellFrame* aCellFrame = nsnull);
void ResetTallestCell(nscoord aRowStyleHeight);
void ResetHeight(nscoord aRowStyleHeight);
// calculate the tallest child when the previous tallest child gets shorter
void CalcTallestCell();
/** returns the tallest child in this row (ignoring any cell with rowspans) */
nscoord GetTallestCell() const;
// calculate the height, considering content height of the
// cells and the style height of the row and cells, excluding pct heights
nscoord CalcHeight(const nsHTMLReflowState& aReflowState);
// Support for cells with 'vertical-align: baseline'.
@ -210,14 +210,38 @@ public:
void RemoveCellFrame(nsTableCellFrame* aFrame);
nsresult CalculateCellActualSize(nsIFrame* aRowFrame,
nscoord& aDesiredWidth,
nscoord& aDesiredHeight,
nscoord aAvailWidth);
nsresult CalculateCellActualSize(nsIFrame* aRowFrame,
nscoord& aDesiredWidth,
nscoord& aDesiredHeight,
nscoord aAvailWidth);
PRBool IsFirstInserted() const;
void SetFirstInserted(PRBool aValue);
PRBool NeedSpecialReflow() const;
void SetNeedSpecialReflow(PRBool aValue);
PRBool GetContentHeight() const;
void SetContentHeight(nscoord aTwipValue);
PRBool HasStyleHeight() const;
PRBool HasFixedHeight() const;
void SetHasFixedHeight(PRBool aValue);
PRBool HasPctHeight() const;
void SetHasPctHeight(PRBool aValue);
nscoord GetFixedHeight() const;
void SetFixedHeight(nscoord aValue);
float GetPctHeight() const;
void SetPctHeight(float aPctValue);
nscoord GetHeight(nscoord aBasis = 0) const;
nsTableRowFrame* GetNextRow() const;
protected:
/** protected constructor.
@ -262,10 +286,6 @@ protected:
// row-specific methods
void GetMinRowSpan(nsTableFrame *aTableFrame);
void FixMinCellHeight(nsTableFrame *aTableFrame);
nscoord ComputeCellXOffset(const nsHTMLReflowState& aState,
nsIFrame* aKidFrame,
const nsMargin& aKidMargin) const;
@ -280,19 +300,18 @@ protected:
nsReflowStatus& aStatus,
PRBool aDirtyOnly = PR_FALSE);
public:
struct RowBits {
int mRowIndex:20;
unsigned mMinRowSpan:11; // the smallest row span among all my child cells
unsigned mFirstInserted; // if true, then it was the top most newly inserted row
};
private:
union {
PRUint32 mAllBits;
RowBits mBits;
};
nscoord mTallestCell; // not my height, but the height of my tallest child
struct RowBits {
unsigned mRowIndex:29;
unsigned mHasFixedHeight:1; // set if the dominating style height on the row or any cell is pixel based
unsigned mHasPctHeight:1; // set if the dominating style height on the row or any cell is pct based
unsigned mFirstInserted:1; // if true, then it was the top most newly inserted row
} mBits;
nscoord mContentHeight; // the desired height based on the content of the tallest cell in the row
nscoord mStyleHeight; // the height based on a style pct on either the row or any cell if mHasPctHeight
// is set, otherwise the height based on a style pixel height on the row or any
// cell if mHasFixedHeight is set
// max-ascent and max-descent amongst all cells that have 'vertical-align: baseline'
nscoord mMaxCellAscent; // does include cells with rowspan > 1
@ -311,7 +330,6 @@ inline PRInt32 nsTableRowFrame::GetRowIndex() const
inline void nsTableRowFrame::SetRowIndex (int aRowIndex)
{
NS_PRECONDITION(aRowIndex < NS_TABLE_MAX_ROW_INDEX, "unexpected row index");
mBits.mRowIndex = aRowIndex;
}
@ -325,4 +343,68 @@ inline void nsTableRowFrame::SetFirstInserted(PRBool aValue)
mBits.mFirstInserted = aValue;
}
inline PRBool nsTableRowFrame::HasStyleHeight() const
{
return (PRBool)mBits.mHasFixedHeight || (PRBool)mBits.mHasPctHeight;
}
inline PRBool nsTableRowFrame::HasFixedHeight() const
{
return (PRBool)mBits.mHasFixedHeight;
}
inline void nsTableRowFrame::SetHasFixedHeight(PRBool aValue)
{
mBits.mHasFixedHeight = aValue;
}
inline PRBool nsTableRowFrame::HasPctHeight() const
{
return (PRBool)mBits.mHasPctHeight;
}
inline void nsTableRowFrame::SetHasPctHeight(PRBool aValue)
{
mBits.mHasPctHeight = aValue;
}
inline nscoord nsTableRowFrame::GetContentHeight() const
{
return mContentHeight;
}
inline void nsTableRowFrame::SetContentHeight(nscoord aValue)
{
mContentHeight = aValue;
}
inline nscoord nsTableRowFrame::GetFixedHeight() const
{
if (mBits.mHasFixedHeight && !mBits.mHasPctHeight)
return mStyleHeight;
else
return 0;
}
inline float nsTableRowFrame::GetPctHeight() const
{
if (mBits.mHasPctHeight)
return (float)mStyleHeight / 100.0f;
else
return 0.0f;
}
inline PRBool nsTableRowFrame::NeedSpecialReflow() const
{
return (mState & NS_ROW_NEED_SPECIAL_REFLOW) == NS_ROW_NEED_SPECIAL_REFLOW;
}
inline void nsTableRowFrame::SetNeedSpecialReflow(PRBool aValue)
{
if (aValue) {
mState |= NS_ROW_NEED_SPECIAL_REFLOW;
} else {
mState &= ~NS_ROW_NEED_SPECIAL_REFLOW;
}
}
#endif

View File

@ -105,6 +105,13 @@ nsTableRowGroupFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr)
}
}
NS_IMETHODIMP
nsTableRowGroupFrame::IsPercentageBase(PRBool& aBase) const
{
aBase = PR_TRUE;
return NS_OK;
}
PRInt32
nsTableRowGroupFrame::GetRowCount()
{
@ -362,6 +369,9 @@ nsTableRowGroupFrame::ReflowChildren(nsIPresContext* aPresContext,
nscoord cellSpacingY = tableFrame->GetCellSpacingY();
PRBool isPaginated;
aPresContext->IsPaginated(&isPaginated);
if (aFirstRowReflowed) {
*aFirstRowReflowed = nsnull;
}
@ -369,8 +379,11 @@ nsTableRowGroupFrame::ReflowChildren(nsIPresContext* aPresContext,
PRBool adjustSiblings = PR_TRUE;
nsIFrame* kidFrame = (aStartFrame) ? aStartFrame : mFrames.FirstChild();
for ( ; kidFrame; ) {
nsTableFrame* tableFirstInFlow = (nsTableFrame*)tableFrame->GetFirstInFlow();
for ( ; kidFrame; kidFrame->GetNextSibling(&kidFrame)) {
// Get the frame state bits
nsCOMPtr<nsIAtom> kidType;
kidFrame->GetFrameType(getter_AddRefs(kidType));
nsFrameState frameState;
kidFrame->GetFrameState(&frameState);
@ -379,6 +392,12 @@ nsTableRowGroupFrame::ReflowChildren(nsIPresContext* aPresContext,
if (aDirtyOnly && ((frameState & NS_FRAME_IS_DIRTY) == 0)) {
doReflowChild = PR_FALSE;
}
if (aReflowState.reflowState.mFlags.mSpecialTableReflow) {
if (!isPaginated && (nsLayoutAtoms::tableRowFrame == kidType.get() &&
!((nsTableRowFrame*)kidFrame)->NeedSpecialReflow())) {
doReflowChild = PR_FALSE;
}
}
// Reflow the row frame
if (doReflowChild) {
@ -413,9 +432,7 @@ nsTableRowGroupFrame::ReflowChildren(nsIPresContext* aPresContext,
lastReflowedRow = kidFrame;
if (aFirstRowReflowed && !*aFirstRowReflowed) {
nsCOMPtr<nsIAtom> fType;
kidFrame->GetFrameType(getter_AddRefs(fType));
if (nsLayoutAtoms::tableRowFrame == fType.get()) {
if (nsLayoutAtoms::tableRowFrame == kidType.get()) {
*aFirstRowReflowed = (nsTableRowFrame*)kidFrame;
}
}
@ -432,8 +449,6 @@ nsTableRowGroupFrame::ReflowChildren(nsIPresContext* aPresContext,
kidFrame->GetSize(kidSize);
aReflowState.y += kidSize.height + cellSpacingY;
}
kidFrame->GetNextSibling(&kidFrame); // Get the next child
}
// adjust the rows after the ones that were reflowed
@ -454,56 +469,82 @@ nsTableRowGroupFrame::ReflowChildren(nsIPresContext* aPresContext,
return rv;
}
void
nsTableRowGroupFrame::GetNextRowSibling(nsIFrame** aRowFrame)
nsTableRowFrame*
nsTableRowGroupFrame::GetFirstRow()
{
if (!*aRowFrame) return;
GetNextFrame(*aRowFrame, aRowFrame);
while(*aRowFrame) {
const nsStyleDisplay *display;
(*aRowFrame)->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)display));
if (NS_STYLE_DISPLAY_TABLE_ROW == display->mDisplay) {
return;
nsIFrame* childFrame = GetFirstFrame();
while (childFrame) {
nsCOMPtr<nsIAtom> frameType;
childFrame->GetFrameType(getter_AddRefs(frameType));
if (nsLayoutAtoms::tableRowFrame == frameType.get()) {
return (nsTableRowFrame*)childFrame;
}
GetNextFrame(*aRowFrame, aRowFrame);
childFrame->GetNextSibling(&childFrame);
}
return nsnull;
}
struct RowInfo {
unsigned height:30;
unsigned hasStyleHeight:1;
unsigned isSpecial:1; // there is no cell originating in the row with rowspan=1 and there are at
// least 2 cells spanning the row and there is no style height on the row
};
static void
UpdateHeights(RowInfo& aRowInfo,
nscoord aAdditionalHeight,
nscoord& aTotal,
nscoord& aUnconstrainedTotal)
{
aRowInfo.height += aAdditionalHeight;
aTotal += aAdditionalHeight;
if (!aRowInfo.hasStyleHeight) {
aUnconstrainedTotal += aAdditionalHeight;
}
}
// allocate the height of rows which have no cells originating in them
// except with cells with rowspan > 1. Store the height as negative
// to distinguish them from regular rows.
void
AllocateSpecialHeight(nsIPresContext* aPresContext,
nsTableFrame* aTableFrame,
nsIFrame* aRowFrame,
nscoord& aHeight)
nsTableRowGroupFrame::DidResizeRows(nsIPresContext& aPresContext,
const nsHTMLReflowState& aReflowState,
nsTableRowFrame* aStartRowFrameIn)
{
nsIFrame* cellFrame;
aRowFrame->FirstChild(aPresContext, nsnull, &cellFrame);
while (cellFrame) {
nsCOMPtr<nsIAtom> cellType;
cellFrame->GetFrameType(getter_AddRefs(cellType));
if (nsLayoutAtoms::tableCellFrame == cellType.get()) {
PRInt32 rowSpan = aTableFrame->GetEffectiveRowSpan((nsTableCellFrame&)*cellFrame);
if (rowSpan > 1) {
// use a simple average to allocate the special row. This is not exact,
// but much better than nothing.
nsSize cellDesSize = ((nsTableCellFrame*)cellFrame)->GetDesiredSize();
((nsTableRowFrame*)aRowFrame)->CalculateCellActualSize(cellFrame, cellDesSize.width,
cellDesSize.height, cellDesSize.width);
PRInt32 propHeight = NSToCoordRound((float)cellDesSize.height / (float)rowSpan);
// special rows store the largest negative value
aHeight = PR_MIN(aHeight, -propHeight);
}
}
cellFrame->GetNextSibling(&cellFrame);
// update the cells spanning rows with their new heights
// this is the place where all of the cells in the row get set to the height of the row
PRInt32 rowIndex;
nsTableRowFrame* rowFrame;
nsTableRowFrame* startRowFrame = (aStartRowFrameIn) ? aStartRowFrameIn: GetFirstRow();
for (rowFrame = startRowFrame, rowIndex = 0; rowFrame; rowFrame = rowFrame->GetNextRow(), rowIndex++) {
rowFrame->DidResize(&aPresContext, aReflowState);
}
}
/* CalculateRowHeights provides default heights for all rows in the rowgroup.
* Actual row heights are ultimately determined by the table, when the table
* height attribute is factored in.
*/
static PRBool
HasMoreThanOneCell(nsTableCellMap* aCellMap,
PRInt32 aRowIndex)
{
if (aCellMap) {
CellData* cellData;
PRInt32 colIndex = 0;
PRInt32 count = 0;
do {
cellData = aCellMap->GetCellAt(aRowIndex, colIndex);
if (cellData && (cellData->GetCellFrame() || cellData->IsRowSpan()))
count++;
if (count > 1)
return PR_TRUE;
colIndex++;
} while(cellData);
}
return PR_FALSE;
}
// This calculates the height of rows starting at aStartRowFrameIn and takes into account
// style height on the row group, style heights on rows and cells, style heights on rowspans.
// Actual row heights will be adjusted later if the table has a style height.
// Even if rows don't change height, this method must be called to set the heights of each
// cell in the row to the height of its row.
void
nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
@ -511,280 +552,259 @@ nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext,
nsTableRowFrame* aStartRowFrameIn)
{
nsTableFrame* tableFrame = nsnull;
nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame);
if (NS_FAILED(rv) || nsnull==tableFrame) return;
nsTableFrame::GetTableFrame(this, tableFrame);
if (!aPresContext || !tableFrame) return;
// all table cells have the same top and bottom margins, namely cellSpacingY
nscoord cellSpacingY = tableFrame->GetCellSpacingY();
float p2t;
aPresContext->GetPixelsToTwips(&p2t);
// find the nearest row to the starting row (including the starting row) that isn't spanned into
nsTableRowFrame* startRowFrame = nsnull;
nsIFrame* childFrame = GetFirstFrame();
PRBool foundFirstRow = PR_FALSE;
while (childFrame) {
nsCOMPtr<nsIAtom> frameType;
childFrame->GetFrameType(getter_AddRefs(frameType));
if (nsLayoutAtoms::tableRowFrame == frameType.get()) {
PRInt32 rowIndex = ((nsTableRowFrame*)childFrame)->GetRowIndex();
if (!foundFirstRow || !tableFrame->RowIsSpannedInto(rowIndex)) {
startRowFrame = (nsTableRowFrame*)childFrame;
if (!aStartRowFrameIn || (aStartRowFrameIn == startRowFrame)) break;
// find the nearest row at or before aStartRowFrameIn that isn't spanned into.
// If we have a computed height, then we can't compute the heights
// incrementally from aStartRowFrameIn, and we must start at the first row.
nsTableRowFrame* startRowFrame = GetFirstRow();
if (aStartRowFrameIn && (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedHeight)
&& (aReflowState.mComputedHeight > 0)) {
nsTableRowFrame* rowFrame = startRowFrame;
while (rowFrame) {
PRInt32 rowIndex = rowFrame->GetRowIndex();
if (!tableFrame->RowIsSpannedInto(rowIndex)) {
startRowFrame = rowFrame;
if (aStartRowFrameIn == startRowFrame)
break;
}
else if (aStartRowFrameIn == (nsTableRowFrame*)childFrame) break;
foundFirstRow = PR_TRUE;
else if (aStartRowFrameIn == rowFrame)
break;
rowFrame = rowFrame->GetNextRow();
}
childFrame->GetNextSibling(&childFrame);
}
if (!startRowFrame) return;
PRInt32 startRowIndex = startRowFrame->GetRowIndex();
nsRect startRowRect;
startRowFrame->GetRect(startRowRect);
nscoord rowGroupHeight = startRowRect.y;
// the current row group height is the y origin of the 1st row we are about to calculated a height for
nscoord startRowGroupHeight = startRowRect.y;
PRInt32 numRows = GetRowCount() - (startRowFrame->GetRowIndex() - GetStartRowIndex());
// collect the current height of each row. nscoord* rowHeights = nsnull;
RowInfo* rowInfo;
if (numRows > 0) {
rowInfo = new RowInfo[numRows];
if (!rowInfo) return;
nsCRT::memset (rowInfo, 0, numRows*sizeof(RowInfo));
}
else return;
PRBool hasRowSpanningCell = PR_FALSE;
PRInt32 numRows = GetRowCount() - (startRowFrame->GetRowIndex() - GetStartRowIndex());
// collect the current height of each row. rows which have 0 height because
// they have no cells originating in them without rowspans > 1, are referred to as
// special rows. The current height of a special row will be a negative number until
// it comes time to actually resize frames.
nscoord* rowHeights = nsnull;
if (numRows > 0) {
rowHeights = new nscoord[numRows];
if (!rowHeights) return;
nsCRT::memset (rowHeights, 0, numRows*sizeof(nscoord));
} // else - tree row groups need not have rows directly beneath them
nscoord heightOfRows = 0;
nscoord heightOfUnStyledRows = 0;
// Get the height of each row without considering rowspans. This will be the max of
// the largest desired height of each cell, the largest style height of each cell,
// the style height of the row.
nscoord pctHeightBasis = GetHeightBasis(aReflowState);
nsTableRowFrame* rowFrame;
PRInt32 rowIndex; // the index in rowInfo, not among the rows in the row group
for (rowFrame = startRowFrame, rowIndex = 0; rowFrame; rowFrame = rowFrame->GetNextRow(), rowIndex++) {
UpdateHeights(rowInfo[rowIndex], nsTableFrame::RoundToPixel(rowFrame->GetHeight(pctHeightBasis), p2t),
heightOfRows, heightOfUnStyledRows);
rowInfo[rowIndex].hasStyleHeight = rowFrame->HasStyleHeight();
// Step 1: get the height of the tallest cell in the row and save it for
// pass 2. This height is for table cells that originate in this
// row and that don't span into the rows that follow
nsIFrame* rowFrame = startRowFrame;
PRInt32 rowIndex = 0;
// For row groups that are split across pages, the first row frame won't
// necessarily be index 0
PRInt32 startRowIndex = -1;
while (rowFrame) {
nsCOMPtr<nsIAtom> frameType;
rowFrame->GetFrameType(getter_AddRefs(frameType));
if (nsLayoutAtoms::tableRowFrame == frameType.get()) {
if (startRowIndex == -1) {
startRowIndex = ((nsTableRowFrame*)rowFrame)->GetRowIndex();
}
// get the height of the tallest cell in the row (excluding cells that span rows)
rowHeights[rowIndex] = ((nsTableRowFrame*)rowFrame)->GetTallestCell();
// See if a cell spans into the row. If so we'll have to do step 2
if (!hasRowSpanningCell) {
if (tableFrame->RowIsSpannedInto(rowIndex + startRowIndex)) {
hasRowSpanningCell = PR_TRUE;
if (!rowInfo[rowIndex].hasStyleHeight) {
if (HasMoreThanOneCell(tableFrame->GetCellMap(), rowIndex)) {
rowInfo[rowIndex].isSpecial = PR_TRUE;
// iteratate the row's cell frames to see if any do not have rowspan > 1
nsTableCellFrame* cellFrame = rowFrame->GetFirstCell();
while (cellFrame) {
PRInt32 rowSpan = tableFrame->GetEffectiveRowSpan(rowIndex + startRowIndex, *cellFrame);
if (1 == rowSpan) {
rowInfo[rowIndex].isSpecial = PR_FALSE;
break;
}
cellFrame = cellFrame->GetNextCell();
}
}
// special rows need to have some values, so they will get allocations
// later. If left at 0, they would get nothing.
if (0 == rowHeights[rowIndex]) {
AllocateSpecialHeight(aPresContext, tableFrame, rowFrame, rowHeights[rowIndex]);
}
rowIndex++;
}
GetNextFrame(rowFrame, &rowFrame); // Get the next row
// See if a cell spans into the row. If so we'll have to do the next step
if (!hasRowSpanningCell) {
if (tableFrame->RowIsSpannedInto(rowIndex + startRowIndex)) {
hasRowSpanningCell = PR_TRUE;
}
}
}
// Step 2: Now account for cells that span rows. A spanning cell's height is the sum of the heights of the
// rows it spans, or it's own desired height, whichever is greater.
// If the cell's desired height is the larger value, resize the rows and contained
// cells by an equal percentage of the additional space.
// We go through this loop twice. The first time, we are adjusting cell heights
// on the fly. The second time through the loop, we're ensuring that subsequent
// row-spanning cells didn't change prior calculations. Since we are guaranteed
// to have found the max height spanners the first time through, we know we only
// need two passes, not an arbitrary number.
nscoord yOrigin = rowGroupHeight;
nscoord lastCount = (hasRowSpanningCell) ? 2 : 1;
for (PRInt32 counter = 0; counter <= lastCount; counter++) {
rowFrame = startRowFrame;
rowIndex = 0;
while (rowFrame) {
nsCOMPtr<nsIAtom> rowType;
rowFrame->GetFrameType(getter_AddRefs(rowType));
if (nsLayoutAtoms::tableRowFrame == rowType.get()) {
if (hasRowSpanningCell) {
// check this row for a cell with rowspans
nsIFrame* cellFrame;
rowFrame->FirstChild(aPresContext, nsnull, &cellFrame);
while (cellFrame) {
nsCOMPtr<nsIAtom> cellType;
cellFrame->GetFrameType(getter_AddRefs(cellType));
if (nsLayoutAtoms::tableCellFrame == cellType.get()) {
PRInt32 rowSpan = tableFrame->GetEffectiveRowSpan(rowIndex + startRowIndex,
(nsTableCellFrame&)*cellFrame);
if (rowSpan > 1) { // found a cell with rowspan > 1, determine the height
// of the rows it spans
nscoord heightOfRowsSpanned = 0;
nscoord cellSpacingOfRowsSpanned = 0;
PRInt32 spanX;
PRBool cellsOrigInSpan = PR_FALSE; // do any cells originate in the spanned rows
for (spanX = 0; spanX < rowSpan; spanX++) {
PRInt32 rIndex = rowIndex + spanX;
if (rowHeights[rIndex] > 0) {
// don't consider negative values of special rows
heightOfRowsSpanned += rowHeights[rowIndex + spanX];
cellsOrigInSpan = PR_TRUE;
}
if (0 != spanX) {
cellSpacingOfRowsSpanned += cellSpacingY;
}
}
nscoord availHeightOfRowsSpanned = heightOfRowsSpanned + cellSpacingOfRowsSpanned;
if (hasRowSpanningCell) {
// Get the height of cells with rowspans and allocate any extra space to the rows they span
// iteratate the child frames and process the row frames among them
for (rowFrame = startRowFrame, rowIndex = 0; rowFrame; rowFrame = rowFrame->GetNextRow(), rowIndex++) {
if (tableFrame->RowHasSpanningCells(startRowIndex + rowIndex)) {
nsTableCellFrame* cellFrame = rowFrame->GetFirstCell();
// iteratate the row's cell frames
while (cellFrame) {
PRInt32 rowSpan = tableFrame->GetEffectiveRowSpan(rowIndex + startRowIndex, *cellFrame);
if (rowSpan > 1) { // a cell with rowspan > 1, determine the height of the rows it spans
nscoord heightOfRowsSpanned = 0;
nscoord heightOfUnStyledRowsSpanned = 0;
nscoord numSpecialRowsSpanned = 0;
nscoord cellSpacingTotal = 0;
PRInt32 spanX;
for (spanX = 0; spanX < rowSpan; spanX++) {
heightOfRowsSpanned += rowInfo[rowIndex + spanX].height;
if (!rowInfo[rowIndex + spanX].hasStyleHeight) {
heightOfUnStyledRowsSpanned += rowInfo[rowIndex + spanX].height;
}
if (0 != spanX) {
cellSpacingTotal += cellSpacingY;
}
if (rowInfo[rowIndex + spanX].isSpecial) {
numSpecialRowsSpanned++;
}
}
nscoord heightOfAreaSpanned = heightOfRowsSpanned + cellSpacingTotal;
// get the height of the cell
nsSize cellFrameSize;
cellFrame->GetSize(cellFrameSize);
nsSize cellDesSize = cellFrame->GetDesiredSize();
rowFrame->CalculateCellActualSize(cellFrame, cellDesSize.width,
cellDesSize.height, cellDesSize.width);
cellFrameSize.height = cellDesSize.height;
if (cellFrame->HasVerticalAlignBaseline()) {
// to ensure that a spanning cell with a long descender doesn't
// collide with the next row, we need to take into account the shift
// that will be done to align the cell on the baseline of the row.
cellFrameSize.height += rowFrame->GetMaxCellAscent() - cellFrame->GetDesiredAscent();
}
// see if the cell's height fits within the rows it spans. If this is
// pass 1 then use the cell's desired height and not the current height
// of its frame. That way this works for incremental reflow, too
nsSize cellFrameSize;
cellFrame->GetSize(cellFrameSize);
if (0 == counter) {
nsSize cellDesSize = ((nsTableCellFrame*)cellFrame)->GetDesiredSize();
((nsTableRowFrame*)rowFrame)->CalculateCellActualSize(cellFrame, cellDesSize.width,
cellDesSize.height, cellDesSize.width);
cellFrameSize.height = cellDesSize.height;
// see if the cell has 'vertical-align: baseline'
if (((nsTableCellFrame*)cellFrame)->HasVerticalAlignBaseline()) {
// to ensure that a spanning cell with a long descender doesn't
// collide with the next row, we need to take into account the shift
// that will be done to align the cell on the baseline of the row.
cellFrameSize.height += ((nsTableRowFrame*)rowFrame)->GetMaxCellAscent()
- ((nsTableCellFrame*)cellFrame)->GetDesiredAscent();
}
}
if (availHeightOfRowsSpanned >= cellFrameSize.height) {
// the cell's height fits with the available space of the rows it
// spans. Set the cell frame's height
cellFrame->SizeTo(aPresContext, cellFrameSize.width, availHeightOfRowsSpanned);
// Realign cell content based on new height
((nsTableCellFrame*)cellFrame)->VerticallyAlignChild(aPresContext, aReflowState, ((nsTableRowFrame*)rowFrame)->GetMaxCellAscent());
}
else {
// the cell's height is larger than the available space of the rows it
// spans so distribute the excess height to the rows affected
nscoord excessAvail = cellFrameSize.height - availHeightOfRowsSpanned;
nscoord excessBasis = excessAvail;
nsTableRowFrame* rowFrameToBeResized = (nsTableRowFrame *)rowFrame;
// iterate every row starting at last row spanned and up to the row with
// the spanning cell. do this bottom up so that special rows can get a full
// allocation before other rows.
PRInt32 beginRowIndex = rowIndex + rowSpan - 1;
for (PRInt32 rowX = beginRowIndex; (rowX >= rowIndex) && (excessAvail > 0); rowX--) {
nscoord excessForRow = 0;
// special rows gets as much as they can
if (rowHeights[rowX] <= 0) {
if ((rowX == beginRowIndex) || (!cellsOrigInSpan)) {
if (0 == rowHeights[rowX]) {
// give it all since no cell originates in the row
excessForRow = excessBasis;
}
else { // don't let the allocation excced what it needs
excessForRow = (excessBasis > -rowHeights[rowX]) ? -rowHeights[rowX] : excessBasis;
}
rowHeights[rowX] = excessForRow;
excessBasis -= excessForRow;
excessAvail -= excessForRow;
if (heightOfAreaSpanned < cellFrameSize.height) {
// the cell's height is larger than the available space of the rows it
// spans so distribute the excess height to the rows affected
nscoord extra = cellFrameSize.height - heightOfAreaSpanned;
nscoord extraUsed = 0;
if (0 == numSpecialRowsSpanned) {
//NS_ASSERTION(heightOfRowsSpanned > 0, "invalid row span situation");
PRBool haveUnStyledRowsSpanned = (heightOfUnStyledRowsSpanned > 0);
nscoord divisor = (haveUnStyledRowsSpanned)
? heightOfUnStyledRowsSpanned : heightOfRowsSpanned;
if (divisor > 0) {
for (spanX = rowSpan - 1; spanX >= 0; spanX--) {
if (!haveUnStyledRowsSpanned || !rowInfo[rowIndex + spanX].hasStyleHeight) {
// The amount of additional space each row gets is proportional to its height
float percent = ((float)rowInfo[rowIndex + spanX].height) / ((float)divisor);
// give rows their percentage, except for the first row which gets the remainder
nscoord extraForRow = (0 == spanX) ? extra - extraUsed
: NSToCoordRound(((float)(extra)) * percent);
extraForRow = PR_MIN(nsTableFrame::RoundToPixel(extraForRow, p2t), extra - extraUsed);
// update the row height
UpdateHeights(rowInfo[rowIndex + spanX], extraForRow, heightOfRows, heightOfUnStyledRows);
extraUsed += extraForRow;
if (extraUsed >= extra) {
NS_ASSERTION((extraUsed == extra), "invalid row height calculation");
break;
}
}
else if (cellsOrigInSpan) { // normal rows
// The amount of additional space each normal row gets is based on the
// percentage of space it occupies, i.e. they don't all get the
// same amount of available space
float percent = ((float)rowHeights[rowX]) / ((float)heightOfRowsSpanned);
// give rows their percentage, except for the first row which gets
// the remainder
excessForRow = (rowX == rowIndex)
? excessAvail
: NSToCoordRound(((float)(excessBasis)) * percent);
// update the row height
rowHeights[rowX] += excessForRow;
excessAvail -= excessForRow;
}
// Get the next row frame
GetNextRowSibling((nsIFrame**)&rowFrameToBeResized);
}
// if excessAvail is > 0 it is because !cellsOrigInSpan and the
// allocation involving special rows couldn't allocate everything.
// just give the remainder to the last row spanned.
if (excessAvail > 0) {
if (rowHeights[beginRowIndex] >= 0) {
rowHeights[beginRowIndex] += excessAvail;
}
else {
rowHeights[beginRowIndex] = excessAvail;
}
else {
// put everything in the last row
UpdateHeights(rowInfo[rowIndex + rowSpan - 1], extra, heightOfRows, heightOfUnStyledRows);
}
}
else {
// give the extra to the special rows
nscoord numSpecialRowsAllocated = 0;
for (spanX = rowSpan - 1; spanX >= 0; spanX--) {
if (rowInfo[rowIndex + spanX].isSpecial) {
// The amount of additional space each degenerate row gets is proportional to the number of them
float percent = 1.0f / ((float)numSpecialRowsSpanned);
// give rows their percentage, except for the first row which gets the remainder
nscoord extraForRow = (numSpecialRowsSpanned - 1 == numSpecialRowsAllocated)
? extra - extraUsed
: NSToCoordRound(((float)(extra)) * percent);
extraForRow = PR_MIN(nsTableFrame::RoundToPixel(extraForRow, p2t), extra - extraUsed);
// update the row height
UpdateHeights(rowInfo[rowIndex + spanX], extraForRow, heightOfRows, heightOfUnStyledRows);
extraUsed += extraForRow;
if (extraUsed >= extra) {
NS_ASSERTION((extraUsed == extra), "invalid row height calculation");
break;
}
}
}
}
}
cellFrame->GetNextSibling(&cellFrame); // Get the next row child (cell frame)
}
}
// If this is the last pass then resize the row to its final size and move the
// row's position if the previous rows have caused a shift
if (lastCount == counter) {
nsRect rowBounds;
rowFrame->GetRect(rowBounds);
PRBool movedFrame = (rowBounds.y != yOrigin);
nscoord rowHeight = (rowHeights[rowIndex] > 0) ? rowHeights[rowIndex] : 0;
// Resize the row to its final size and position
rowBounds.y = yOrigin;
rowBounds.height = rowHeight;
rowFrame->SetRect(aPresContext, rowBounds);
if (movedFrame) {
nsTableFrame::RePositionViews(aPresContext, rowFrame);
}
// set the origin of the next row.
yOrigin += rowHeight + cellSpacingY;
}
rowIndex++;
}
GetNextFrame(rowFrame, &rowFrame); // Get the next rowgroup child (row frame)
}
}
} // if (rowSpan > 1)
cellFrame = cellFrame->GetNextCell();
} // while (cellFrame)
} // if (tableFrame->RowHasSpanningCells(startRowIndex + rowIndex) {
} // while (rowFrame)
}
// step 3: notify the rows of their new heights
rowFrame = startRowFrame;
rowIndex = 0;
while (rowFrame) {
if (NS_UNCONSTRAINEDSIZE != aReflowState.availableWidth) {
nsCOMPtr<nsIAtom> rowType;
rowFrame->GetFrameType(getter_AddRefs(rowType));
if (nsLayoutAtoms::tableRowFrame == rowType.get()) {
// Notify the row of the new size
((nsTableRowFrame *)rowFrame)->DidResize(aPresContext, aReflowState);
nscoord rowGroupHeight = startRowGroupHeight + heightOfRows + ((numRows - 1) * cellSpacingY);
nscoord extraComputedHeight = 0;
// if we have a style height, allocate the extra height to unconstrained rows
if ((aReflowState.mComputedHeight > rowGroupHeight) &&
(NS_UNCONSTRAINEDSIZE != aReflowState.mComputedHeight)) {
extraComputedHeight = aReflowState.mComputedHeight - rowGroupHeight;
nscoord extraUsed = 0;
PRBool haveUnStyledRows = (heightOfUnStyledRows > 0);
nscoord divisor = (haveUnStyledRows)
? heightOfUnStyledRows : heightOfRows;
if (divisor > 0) {
for (rowIndex = 0; rowIndex < numRows; rowIndex++) {
if (!haveUnStyledRows || !rowInfo[rowIndex].hasStyleHeight) {
// The amount of additional space each row gets is based on the
// percentage of space it occupies
float percent = ((float)rowInfo[rowIndex].height) / ((float)divisor);
// give rows their percentage, except for the last row which gets the remainder
nscoord extraForRow = (numRows - 1 == rowIndex)
? extraComputedHeight - extraUsed
: NSToCoordRound(((float)extraComputedHeight) * percent);
extraForRow = PR_MIN(nsTableFrame::RoundToPixel(extraForRow, p2t), extraComputedHeight - extraUsed);
// update the row height
UpdateHeights(rowInfo[rowIndex], extraForRow, heightOfRows, heightOfUnStyledRows);
extraUsed += extraForRow;
if (extraUsed >= extraComputedHeight) {
NS_ASSERTION((extraUsed == extraComputedHeight), "invalid row height calculation");
break;
}
}
}
}
// Update the running row group height. The height includes frames that
// aren't rows as well
nsSize rowSize;
rowFrame->GetSize(rowSize);
rowGroupHeight += rowSize.height;
if (0 != rowIndex) {
rowGroupHeight += cellSpacingY;
}
GetNextFrame(rowFrame, &rowFrame); // Get the next row
rowIndex++;
rowGroupHeight = aReflowState.mComputedHeight;
}
nscoord yOrigin = startRowGroupHeight;
// update the rows with their (potentially) new heights
for (rowFrame = startRowFrame, rowIndex = 0; rowFrame; rowFrame = rowFrame->GetNextRow(), rowIndex++) {
nsRect rowBounds;
rowFrame->GetRect(rowBounds);
PRBool movedFrame = (rowBounds.y != yOrigin);
nscoord rowHeight = (rowInfo[rowIndex].height > 0) ? rowInfo[rowIndex].height : 0;
if (movedFrame || (rowHeight != rowBounds.height)) {
// Resize the row to its final size and position
rowBounds.y = yOrigin;
rowBounds.height = rowHeight;
rowFrame->SetRect(aPresContext, rowBounds);
}
if (movedFrame) {
nsTableFrame::RePositionViews(aPresContext, rowFrame);
}
yOrigin += rowHeight + cellSpacingY;
}
DidResizeRows(*aPresContext, aReflowState, startRowFrame);
aDesiredSize.height = rowGroupHeight; // Adjust our desired size
delete [] rowHeights; // cleanup
delete [] rowInfo; // cleanup
}
// Called by IR_TargetIsChild() to adjust the sibling frames that follow
// after an incremental reflow of aKidFrame.
// This function is not used for paginated mode so we don't need to deal
@ -918,31 +938,6 @@ nsTableRowGroupFrame::SplitSpanningCells(nsIPresContext& aPresContext,
return tallestCell;
}
nsIFrame* GetNextRow(nsIFrame& aFrame)
{
nsIFrame* rowFrame;
for (aFrame.GetNextSibling(&rowFrame); rowFrame; rowFrame->GetNextSibling(&rowFrame)) {
nsCOMPtr<nsIAtom> fType;
rowFrame->GetFrameType(getter_AddRefs(fType));
if (nsLayoutAtoms::tableRowFrame == fType.get()) {
return rowFrame;
}
}
return nsnull;
}
nsIFrame* GetFirstRow(nsTableRowGroupFrame& aRowGroupFrame)
{
for (nsIFrame* rowFrame = aRowGroupFrame.GetFirstFrame(); rowFrame; rowFrame = GetNextRow(*rowFrame)) {
nsCOMPtr<nsIAtom> fType;
rowFrame->GetFrameType(getter_AddRefs(fType));
if (nsLayoutAtoms::tableRowFrame == fType.get()) {
return rowFrame;
}
}
return nsnull;
}
nsresult
nsTableRowGroupFrame::SplitRowGroup(nsIPresContext* aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
@ -971,7 +966,7 @@ nsTableRowGroupFrame::SplitRowGroup(nsIPresContext* aPresContext,
// Walk each of the row frames looking for the first row frame that
// doesn't fit in the available space
for (nsIFrame* rowFrame = GetFirstRow(*this); rowFrame; rowFrame = GetNextRow(*rowFrame)) {
for (nsTableRowFrame* rowFrame = GetFirstRow(); rowFrame; rowFrame = rowFrame->GetNextRow()) {
PRBool rowIsOnCurrentPage = PR_TRUE;
PRBool degenerateRow = PR_FALSE;
nsRect bounds;
@ -995,7 +990,7 @@ nsTableRowGroupFrame::SplitRowGroup(nsIPresContext* aPresContext,
0, 0, NS_FRAME_NO_MOVE_FRAME, aStatus);
rowFrame->SizeTo(aPresContext, desiredSize.width, desiredSize.height);
rowFrame->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED);
((nsTableRowFrame *)rowFrame)->DidResize(aPresContext, aReflowState);
rowFrame->DidResize(aPresContext, aReflowState);
if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) {
// the row frame is incomplete and all of the cells' block frames have split
@ -1043,7 +1038,7 @@ nsTableRowGroupFrame::SplitRowGroup(nsIPresContext* aPresContext,
if (prevRowFrame) {
nscoord tallestCell =
SplitSpanningCells(*aPresContext, aReflowState, *styleSet, *aTableFrame,
*(nsTableRowFrame*)rowFrame, aDesiredSize.height, (nsTableRowFrame*)contRowFrame);
*rowFrame, aDesiredSize.height, (nsTableRowFrame*)contRowFrame);
if (degenerateRow) {
aDesiredSize.height = lastDesiredHeight + aTableFrame->GetCellSpacingY() + tallestCell;
}
@ -1077,10 +1072,10 @@ nsTableRowGroupFrame::Reflow(nsIPresContext* aPresContext,
nsresult rv=NS_OK;
aStatus = NS_FRAME_COMPLETE;
nsTableFrame* tableFrame = nsnull;
rv = nsTableFrame::GetTableFrame(this, tableFrame);
if (!tableFrame) return NS_ERROR_NULL_POINTER;
if (!aPresContext || !tableFrame) return NS_ERROR_NULL_POINTER;
nsRowGroupReflowState state(aReflowState, tableFrame);
PRBool haveDesiredHeight = PR_FALSE;
@ -1111,9 +1106,12 @@ nsTableRowGroupFrame::Reflow(nsIPresContext* aPresContext,
// reflow, then we need to do this because the table will skip the pass 2 reflow,
// but we need to correctly calculate the row group height and we can't if there
// are row spans unless we do this step
if ((eReflowReason_Initial != aReflowState.reason) ||
isTableUnconstrainedReflow ||
isPaginated) {
if (aReflowState.mFlags.mSpecialTableReflow) {
DidResizeRows(*aPresContext, aReflowState);
}
else if ((eReflowReason_Initial != aReflowState.reason) ||
isTableUnconstrainedReflow ||
isPaginated) {
CalculateRowHeights(aPresContext, aDesiredSize, aReflowState);
haveDesiredHeight = PR_TRUE;
}
@ -1124,6 +1122,12 @@ nsTableRowGroupFrame::Reflow(nsIPresContext* aPresContext,
SplitRowGroup(aPresContext, aDesiredSize, aReflowState, tableFrame, aStatus);
}
}
SetHasStyleHeight((NS_UNCONSTRAINEDSIZE != aReflowState.mComputedHeight) &&
(aReflowState.mComputedHeight > 0));
if (aReflowState.mFlags.mSpecialTableReflow) {
SetNeedSpecialReflow(PR_FALSE);
}
// just set our width to what was available. The table will calculate the width and not use our value.
aDesiredSize.width = aReflowState.availableWidth;
@ -1318,6 +1322,21 @@ nsTableRowGroupFrame::IR_TargetIsMe(nsIPresContext* aPresContext,
return rv;
}
nscoord
nsTableRowGroupFrame::GetHeightBasis(const nsHTMLReflowState& aReflowState)
{
nscoord result = 0;
if ((aReflowState.mComputedHeight > 0) && (aReflowState.mComputedHeight < NS_UNCONSTRAINEDSIZE)) {
nsTableFrame* tableFrame = nsnull;
nsTableFrame::GetTableFrame((nsIFrame*)this, tableFrame);
if (tableFrame) {
nscoord cellSpacing = PR_MAX(0, GetRowCount() - 1) * tableFrame->GetCellSpacingY();
result -= cellSpacing;
}
}
return result;
}
nscoord
nsTableRowGroupFrame::GetHeightOfRows(nsIPresContext* aPresContext)
{

View File

@ -79,9 +79,13 @@ struct nsRowGroupReflowState {
{ 0xe940e7bc, 0xb534, 0x11d2, \
{ 0x95, 0xa2, 0x0, 0x60, 0xb0, 0xc3, 0x44, 0x14 } }
// use a bit from nsFrame's frame state bits to determine whether a
// use the following bits from nsFrame's frame state
// thead or tfoot should be repeated on every printed page
#define NS_ROWGROUP_REPEATABLE 0x80000000
#define NS_ROWGROUP_REPEATABLE 0x80000000
#define NS_ROWGROUP_HAS_STYLE_HEIGHT 0x40000000
// we need a 3rd pass reflow to deal with pct height nested tables
#define NS_ROWGROUP_NEED_SPECIAL_REFLOW 0x20000000
/**
* nsTableRowGroupFrame is the frame that maps row groups
* (HTML tags THEAD, TFOOT, and TBODY). This class cannot be reused
@ -176,6 +180,10 @@ public:
*/
NS_IMETHOD GetFrameType(nsIAtom** aType) const;
NS_IMETHOD IsPercentageBase(PRBool& aBase) const;
nsTableRowFrame* GetFirstRow();
#ifdef DEBUG
NS_IMETHOD GetFrameName(nsString& aResult) const;
NS_IMETHOD SizeOf(nsISizeOfHandler* aSizer, PRUint32* aResult) const;
@ -206,6 +214,7 @@ public:
* Get the total height of all the row rects
*/
nscoord GetHeightOfRows(nsIPresContext* aPresContext);
nscoord GetHeightBasis(const nsHTMLReflowState& aReflowState);
// nsILineIterator methods
public:
@ -255,6 +264,9 @@ protected:
const nsHTMLReflowState& aReflowState,
nsTableRowFrame* aStartRowFrameIn = nsnull);
void DidResizeRows(nsIPresContext& aPresContext,
const nsHTMLReflowState& aReflowState,
nsTableRowFrame* aStartRowFrameIn = nsnull);
/** Incremental Reflow attempts to do column balancing with the minimum number of reflow
* commands to child elements. This is done by processing the reflow command,
@ -337,8 +349,12 @@ public:
virtual nsIFrame* GetLastFrame() { return mFrames.LastChild(); };
virtual void GetNextFrame(nsIFrame* aFrame,
nsIFrame** aResult) { aFrame->GetNextSibling(aResult); };
PRBool IsRepeatable();
void SetRepeatable(PRBool aRepeatable);
PRBool IsRepeatable() const;
void SetRepeatable(PRBool aRepeatable);
PRBool HasStyleHeight() const;
void SetHasStyleHeight(PRBool aValue);
PRBool NeedSpecialReflow() const;
void SetNeedSpecialReflow(PRBool aValue);
#ifdef DEBUG_TABLE_REFLOW_TIMING
public:
@ -347,7 +363,7 @@ public:
};
inline PRBool nsTableRowGroupFrame::IsRepeatable()
inline PRBool nsTableRowGroupFrame::IsRepeatable() const
{
return (mState & NS_ROWGROUP_REPEATABLE) == NS_ROWGROUP_REPEATABLE;
}
@ -361,4 +377,31 @@ inline void nsTableRowGroupFrame::SetRepeatable(PRBool aRepeatable)
}
}
inline PRBool nsTableRowGroupFrame::NeedSpecialReflow() const
{
return (mState & NS_ROWGROUP_NEED_SPECIAL_REFLOW) == NS_ROWGROUP_NEED_SPECIAL_REFLOW;
}
inline void nsTableRowGroupFrame::SetNeedSpecialReflow(PRBool aValue)
{
if (aValue) {
mState |= NS_ROWGROUP_NEED_SPECIAL_REFLOW;
} else {
mState &= ~NS_ROWGROUP_NEED_SPECIAL_REFLOW;
}
}
inline PRBool nsTableRowGroupFrame::HasStyleHeight() const
{
return (mState & NS_ROWGROUP_HAS_STYLE_HEIGHT) == NS_ROWGROUP_HAS_STYLE_HEIGHT;
}
inline void nsTableRowGroupFrame::SetHasStyleHeight(PRBool aValue)
{
if (aValue) {
mState |= NS_ROWGROUP_HAS_STYLE_HEIGHT;
} else {
mState &= ~NS_ROWGROUP_HAS_STYLE_HEIGHT;
}
}
#endif

View File

@ -337,15 +337,19 @@ nsTableCellMap::RemoveRows(nsIPresContext* aPresContext,
PRInt32
nsTableCellMap::GetNumCellsOriginatingInRow(PRInt32 aRowIndex)
{
PRInt32 cellCount = 0;
CellData* tempCell;
do
{
tempCell = GetCellAt(aRowIndex,cellCount);
if (tempCell)
cellCount++;
}while(tempCell);
return cellCount;
PRInt32 originCount = 0;
CellData* cellData;
PRInt32 colIndex = 0;
do {
cellData = GetCellAt(aRowIndex, colIndex);
if (cellData && cellData->GetCellFrame())
originCount++;
colIndex++;
} while(cellData);
return originCount;
}
PRInt32

View File

@ -91,6 +91,22 @@ nsTableCellFrame::~nsTableCellFrame()
#endif
}
nsTableCellFrame*
nsTableCellFrame::GetNextCell() const
{
nsIFrame* childFrame;
GetNextSibling(&childFrame);
while (childFrame) {
nsCOMPtr<nsIAtom> frameType;
childFrame->GetFrameType(getter_AddRefs(frameType));
if (nsLayoutAtoms::tableCellFrame == frameType.get()) {
return (nsTableCellFrame*)childFrame;
}
childFrame->GetNextSibling(&childFrame);
}
return nsnull;
}
NS_IMETHODIMP
nsTableCellFrame::Init(nsIPresContext* aPresContext,
nsIContent* aContent,
@ -694,6 +710,15 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext,
}
nsresult rv = NS_OK;
if ((NS_UNCONSTRAINEDSIZE != aReflowState.availableWidth) &&
((NS_UNCONSTRAINEDSIZE == aReflowState.mComputedHeight) ||
(0 == aReflowState.mComputedHeight)) &&
!mPrevInFlow &&
nsTableFrame::IsPctHeight(mStyleContext)) {
nsTableFrame::NotifyAncestorsOfSpecialReflow(aReflowState);
SetNeedSpecialReflow(PR_TRUE);
}
// this should probably be cached somewhere
nsCompatibility compatMode;
aPresContext->GetCompatibilityMode(&compatMode);
@ -714,6 +739,8 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext,
/* XXX: remove tableFrame when border-collapse inherits */
nsTableFrame* tableFrame=nsnull;
rv = nsTableFrame::GetTableFrame(this, tableFrame);
nsTableFrame* tableFrameFirstInFlow = (nsTableFrame*)tableFrame->GetFirstInFlow();
nsMargin borderPadding = aReflowState.mComputedPadding;
nsMargin border;
GetCellBorder(border, tableFrame);
@ -768,6 +795,10 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext,
kidSize.width=kidSize.height=kidSize.ascent=kidSize.descent=0;
SetPriorAvailWidth(aReflowState.availableWidth);
nsIFrame* firstKid = mFrames.FirstChild();
if (aReflowState.mFlags.mSpecialTableReflow) {
((nsHTMLReflowState&)aReflowState).mComputedHeight = mRect.height - topInset - bottomInset;
}
nsHTMLReflowState kidReflowState(aPresContext, aReflowState, firstKid,
availSize);
@ -898,8 +929,7 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext,
// if the table allocated extra vertical space to row groups, rows, cells in pagination mode
// then use that height as the desired height unless the cell needs to split.
nsTableFrame* tableFrameFirstInFlow = (nsTableFrame*)tableFrame->GetFirstInFlow();
if ((NS_FRAME_COMPLETE == aStatus) && tableFrameFirstInFlow->IsThirdPassReflow()) {
if ((NS_FRAME_COMPLETE == aStatus) && aReflowState.mFlags.mSpecialTableReflow) {
cellHeight = PR_MAX(cellHeight, mRect.height);
}
// next determine the cell's width
@ -942,6 +972,10 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext,
// remember my desired size for this reflow
SetDesiredSize(aDesiredSize);
if (aReflowState.mFlags.mSpecialTableReflow) {
SetNeedSpecialReflow(PR_FALSE);
}
#if defined DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState, &aDesiredSize, aStatus);
#endif

View File

@ -49,7 +49,8 @@ class nsHTMLValue;
/**
* Additional frame-state bits
*/
#define NS_TABLE_CELL_FRAME_CONTENT_EMPTY 0x80000000
#define NS_TABLE_CELL_CONTENT_EMPTY 0x80000000
#define NS_TABLE_CELL_NEED_SPECIAL_REFLOW 0x40000000
/**
* nsTableCellFrame
@ -239,11 +240,16 @@ public:
PRBool GetContentEmpty();
void SetContentEmpty(PRBool aContentEmpty);
PRBool NeedSpecialReflow();
void SetNeedSpecialReflow(PRBool aContentEmpty);
// The collapse offset is (0,0) except for cells originating in a row/col which is collapsed
void SetCollapseOffsetX(nsIPresContext* aPresContext, nscoord aXOffset);
void SetCollapseOffsetY(nsIPresContext* aPresContext, nscoord aYOffset);
void GetCollapseOffset(nsIPresContext* aPresContext, nsPoint& aOffset);
nsTableCellFrame* GetNextCell() const;
protected:
/** implement abstract method on nsHTMLContainerFrame */
virtual PRIntn GetSkipSides() const;
@ -332,19 +338,33 @@ inline nsSize nsTableCellFrame::GetPass1MaxElementSize() const
inline PRBool nsTableCellFrame::GetContentEmpty()
{
return (mState & NS_TABLE_CELL_FRAME_CONTENT_EMPTY) ==
NS_TABLE_CELL_FRAME_CONTENT_EMPTY;
return (mState & NS_TABLE_CELL_CONTENT_EMPTY) ==
NS_TABLE_CELL_CONTENT_EMPTY;
}
inline void nsTableCellFrame::SetContentEmpty(PRBool aContentEmpty)
{
if (aContentEmpty) {
mState |= NS_TABLE_CELL_FRAME_CONTENT_EMPTY;
mState |= NS_TABLE_CELL_CONTENT_EMPTY;
} else {
mState &= ~NS_TABLE_CELL_FRAME_CONTENT_EMPTY;
mState &= ~NS_TABLE_CELL_CONTENT_EMPTY;
}
}
inline PRBool nsTableCellFrame::NeedSpecialReflow()
{
return (mState & NS_TABLE_CELL_NEED_SPECIAL_REFLOW) ==
NS_TABLE_CELL_NEED_SPECIAL_REFLOW;
}
inline void nsTableCellFrame::SetNeedSpecialReflow(PRBool aValue)
{
if (aValue) {
mState |= NS_TABLE_CELL_NEED_SPECIAL_REFLOW;
} else {
mState &= ~NS_TABLE_CELL_NEED_SPECIAL_REFLOW;
}
}
#endif

View File

@ -84,6 +84,7 @@ void nsTableColFrame::SetType(nsTableColType aType) {
mBits.mType = aType - eColContent;
}
// XXX what about other style besides width
nsStyleCoord nsTableColFrame::GetStyleWidth() const
{

View File

@ -1580,8 +1580,15 @@ nsTableFrame::GetSkipSides() const
PRBool nsTableFrame::NeedsReflow(const nsHTMLReflowState& aReflowState)
{
PRBool result = PR_TRUE;
if ((eReflowReason_Incremental == aReflowState.reason) &&
(NS_UNCONSTRAINEDSIZE == aReflowState.availableHeight)) {
if (eReflowReason_Resize == aReflowState.reason) {
if (aReflowState.mFlags.mSpecialTableReflow &&
!NeedSpecialReflow() &&
!NeedToInitiateSpecialReflow()) {
result = PR_FALSE;
}
}
else if ((eReflowReason_Incremental == aReflowState.reason) &&
(NS_UNCONSTRAINEDSIZE == aReflowState.availableHeight)) {
// It's an incremental reflow and we're in galley mode. Only
// do a full reflow if we need to.
#ifndef TABLE_REFLOW_COALESCING_OFF
@ -1809,6 +1816,30 @@ ProcessRowInserted(nsIPresContext* aPresContext,
}
}
void
nsTableFrame::NotifyAncestorsOfSpecialReflow(const nsHTMLReflowState& aReflowState)
{
const nsHTMLReflowState* rs = aReflowState.parentReflowState;
while (rs) {
nsCOMPtr<nsIAtom> frameType;
rs->frame->GetFrameType(getter_AddRefs(frameType));
if (nsLayoutAtoms::tableCellFrame == frameType.get()) {
((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()) {
((nsTableFrame*)rs->frame)->SetNeedToInitiateSpecialReflow(PR_TRUE);
break;
}
rs = rs->parentReflowState;
}
}
/* overview:
if mFirstPassValid is false, this is our first time through since content was last changed
do pass 1
@ -1904,36 +1935,57 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext,
if (NS_FAILED(rv)) return rv;
PRBool needPass3Reflow = PR_FALSE;
PRBool haveDesiredHeight = PR_FALSE;
PRBool balanced = PR_FALSE;
// Reflow the entire table. This phase is necessary during a constrained initial reflow
// and other reflows which require either a strategy init or balance. This isn't done
// during an unconstrained reflow because another reflow will be processed later.
if (NeedsReflow(aReflowState) && (NS_UNCONSTRAINEDSIZE != aReflowState.availableWidth)) {
// see if an extra (3rd) reflow will be necessary in pagination mode when there is a specified table height
if (isPaginated && !mPrevInFlow && (NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight)) {
nscoord tableSpecifiedHeight = CalcBorderBoxHeight(aReflowState);
if ((tableSpecifiedHeight > 0) &&
(tableSpecifiedHeight != NS_UNCONSTRAINEDSIZE)) {
needPass3Reflow = PR_TRUE;
if (!mPrevInFlow) {
// see if an extra reflow will be necessary when there is a pct height but no height on the parent
if ( ((NS_UNCONSTRAINEDSIZE == aReflowState.mComputedHeight) ||
(0 == aReflowState.mComputedHeight)) && IsPctHeight(mStyleContext)) {
NotifyAncestorsOfSpecialReflow(aReflowState);
SetNeedSpecialReflow(PR_TRUE);
}
// 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)) {
nscoord tableSpecifiedHeight = CalcBorderBoxHeight(aReflowState);
if ((tableSpecifiedHeight > 0) &&
(tableSpecifiedHeight != NS_UNCONSTRAINEDSIZE)) {
SetNeedToInitiateSpecialReflow(PR_TRUE);
}
}
}
// if we need to reflow the table an extra time, then don't constrain the height of the previous reflow
nscoord availHeight = (needPass3Reflow) ? NS_UNCONSTRAINEDSIZE : aReflowState.availableHeight;
nscoord availHeight = !aReflowState.mFlags.mSpecialTableReflow &&
(NeedSpecialReflow() | NeedToInitiateSpecialReflow())
? NS_UNCONSTRAINEDSIZE : aReflowState.availableHeight;
ReflowTable(aPresContext, aDesiredSize, aReflowState, availHeight, nextReason, doCollapse, balanced, aStatus);
if (needPass3Reflow) {
if (!aReflowState.mFlags.mSpecialTableReflow && NeedToInitiateSpecialReflow() && !NeedSpecialReflow()) {
aDesiredSize.height = CalcDesiredHeight(aPresContext, aReflowState); // distributes extra vertical space to rows
SetThirdPassReflow(PR_TRUE); // set it and leave it set for frames that may split
((nsHTMLReflowState::ReflowStateFlags&)aReflowState.mFlags).mSpecialTableReflow = PR_TRUE;
ReflowTable(aPresContext, aDesiredSize, aReflowState, aReflowState.availableHeight,
nextReason, doCollapse, balanced, aStatus);
haveDesiredHeight = PR_TRUE;;
}
}
else if (aReflowState.mFlags.mSpecialTableReflow) {
aDesiredSize.width = mRect.width;
aDesiredSize.height = mRect.height;
#if defined DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState, &aDesiredSize, aStatus);
#endif
SetNeedSpecialReflow(PR_FALSE);
SetNeedToInitiateSpecialReflow(PR_FALSE);
return NS_OK;
}
aDesiredSize.width = GetDesiredWidth();
if (!needPass3Reflow) {
aDesiredSize.width = GetDesiredWidth();
if (!haveDesiredHeight) {
aDesiredSize.height = CalcDesiredHeight(aPresContext, aReflowState);
}
@ -1986,6 +2038,10 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext,
}
}
if (aReflowState.mFlags.mSpecialTableReflow) {
SetNeedSpecialReflow(PR_FALSE);
SetNeedToInitiateSpecialReflow(PR_FALSE);
}
#if defined DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState, &aDesiredSize, aStatus);
#endif
@ -3253,81 +3309,6 @@ nsTableFrame::CalcDesiredWidth(const nsHTMLReflowState& aReflowState)
return tableWidth;
}
/**
get the table height attribute
if it is auto, table height = SUM(height of rowgroups)
else if (resolved table height attribute > SUM(height of rowgroups))
proportionately distribute extra height to each row
we assume we are passed in the default table height==the sum of the heights of the table's rowgroups
in aDesiredSize.height.
*/
void
nsTableFrame::DistributeSpaceToCells(nsIPresContext* aPresContext,
const nsHTMLReflowState& aReflowState,
nsIFrame* aRowGroupFrame)
{
// now that all of the rows have been resized, resize the cells
nsTableRowGroupFrame* rowGroupFrame = (nsTableRowGroupFrame*)aRowGroupFrame;
nsIFrame * rowFrame = rowGroupFrame->GetFirstFrame();
while (rowFrame) {
const nsStyleDisplay *rowDisplay;
rowFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)rowDisplay));
if (NS_STYLE_DISPLAY_TABLE_ROW == rowDisplay->mDisplay) {
((nsTableRowFrame *)rowFrame)->DidResize(aPresContext, aReflowState);
}
rowGroupFrame->GetNextFrame(rowFrame, &rowFrame);
}
}
void
nsTableFrame::DistributeSpaceToRows(nsIPresContext* aPresContext,
const nsHTMLReflowState& aReflowState,
nsIFrame* aRowGroupFrame,
nscoord aSumOfRowHeights,
nscoord aExcess,
nscoord& aExcessAllocated,
nscoord& aRowGroupYPos)
{
// the rows in rowGroupFrame need to be expanded by rowHeightDelta[i]
// and the rowgroup itself needs to be expanded by SUM(row height deltas)
nscoord cellSpacingY = GetCellSpacingY();
nsTableRowGroupFrame* rowGroupFrame = (nsTableRowGroupFrame*)aRowGroupFrame;
nsIFrame* rowFrame = rowGroupFrame->GetFirstFrame();
nscoord excessForRowGroup = 0;
nscoord y = 0;
float p2t;
aPresContext->GetPixelsToTwips(&p2t);
while (rowFrame) {
const nsStyleDisplay *rowDisplay;
rowFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)rowDisplay));
if (NS_STYLE_DISPLAY_TABLE_ROW == rowDisplay->mDisplay) {
// the row needs to be expanded by the proportion this row contributed to the original height
nsRect rowRect;
rowFrame->GetRect(rowRect);
float percent = ((float)(rowRect.height)) / (float)aSumOfRowHeights;
nscoord excessForRow = RoundToPixel(NSToCoordRound((float)aExcess * percent), p2t);
excessForRow = PR_MIN(excessForRow, aExcess - aExcessAllocated);
nsRect newRowRect(rowRect.x, y, rowRect.width, excessForRow + rowRect.height);
rowFrame->SetRect(aPresContext, newRowRect);
y = newRowRect.YMost() + cellSpacingY;
aExcessAllocated += excessForRow;
excessForRowGroup += excessForRow;
}
rowGroupFrame->GetNextFrame(rowFrame, &rowFrame);
}
nsRect rowGroupRect;
aRowGroupFrame->GetRect(rowGroupRect);
nsRect newRowGroupRect(rowGroupRect.x, aRowGroupYPos, rowGroupRect.width,
excessForRowGroup + rowGroupRect.height);
aRowGroupFrame->SetRect(aPresContext, newRowGroupRect);
aRowGroupYPos = newRowGroupRect.YMost();
DistributeSpaceToCells(aPresContext, aReflowState, aRowGroupFrame);
}
nscoord
nsTableFrame::CalcDesiredHeight(nsIPresContext* aPresContext,
@ -3347,65 +3328,239 @@ nsTableFrame::CalcDesiredHeight(nsIPresContext* aPresContext,
OrderRowGroups(rowGroups, numRowGroups, nsnull);
if (numRowGroups <= 0) return 0;
nscoord naturalHeight = borderPadding.top + cellSpacingY + borderPadding.bottom;
nscoord desiredHeight = borderPadding.top + cellSpacingY + borderPadding.bottom;
for (PRUint32 rgX = 0; rgX < numRowGroups; rgX++) {
nsIFrame* rg = (nsIFrame*)rowGroups.ElementAt(rgX);
if (rg) {
nsRect rgRect;
rg->GetRect(rgRect);
naturalHeight += rgRect.height + cellSpacingY;
desiredHeight += rgRect.height + cellSpacingY;
}
}
nscoord desiredHeight = naturalHeight;
// see if a specified table height requires dividing additional space to rows
if (!mPrevInFlow) {
nscoord tableSpecifiedHeight = CalcBorderBoxHeight(aReflowState);
if ((tableSpecifiedHeight > 0) &&
(tableSpecifiedHeight != NS_UNCONSTRAINEDSIZE) &&
(tableSpecifiedHeight > naturalHeight)) {
desiredHeight = tableSpecifiedHeight;
(tableSpecifiedHeight > desiredHeight)) {
// proportionately distribute the excess height to unconstrained rows in each
// unconstrained row group.We don't need to do this if it's an unconstrained reflow
if (NS_UNCONSTRAINEDSIZE != aReflowState.availableWidth) {
// proportionately distribute the excess height to each row. Note that we
// don't need to do this if it's an unconstrained reflow
nscoord excess = tableSpecifiedHeight - naturalHeight;
nscoord sumOfRowHeights = 0;
nscoord rowGroupYPos = aReflowState.mComputedBorderPadding.top + cellSpacingY;
nsAutoVoidArray rowGroups;
PRUint32 numRowGroups;
OrderRowGroups(rowGroups, numRowGroups, nsnull);
PRUint32 rgX;
for (rgX = 0; rgX < numRowGroups; rgX++) {
nsTableRowGroupFrame* rgFrame =
GetRowGroupFrame((nsIFrame*)rowGroups.ElementAt(rgX));
if (rgFrame) {
sumOfRowHeights += rgFrame->GetHeightOfRows(aPresContext);
}
}
nscoord excessAllocated = 0;
for (rgX = 0; rgX < numRowGroups; rgX++) {
nsTableRowGroupFrame* rgFrame =
GetRowGroupFrame((nsIFrame*)rowGroups.ElementAt(rgX));
if (rgFrame) {
DistributeSpaceToRows(aPresContext, aReflowState, rgFrame, sumOfRowHeights,
excess, excessAllocated, rowGroupYPos);
// Make sure child views are properly positioned
// XXX what happens if childFrame is a scroll frame and this gets skipped?
nsTableFrame::RePositionViews(aPresContext, rgFrame);
}
rowGroupYPos += cellSpacingY;
}
DistributeHeightToRows(aPresContext, aReflowState, tableSpecifiedHeight - desiredHeight);
}
desiredHeight = tableSpecifiedHeight;
}
}
return desiredHeight;
}
static
void ResizeCells(nsTableFrame& aTableFrame,
nsIPresContext* aPresContext,
const nsHTMLReflowState& aReflowState)
{
nsAutoVoidArray rowGroups;
PRUint32 numRowGroups;
aTableFrame.OrderRowGroups(rowGroups, numRowGroups, nsnull);
for (PRUint32 rgX = 0; (rgX < numRowGroups); rgX++) {
nsTableRowGroupFrame* rgFrame = aTableFrame.GetRowGroupFrame((nsIFrame*)rowGroups.ElementAt(rgX));
nsTableRowFrame* rowFrame = rgFrame->GetFirstRow();
while (rowFrame) {
rowFrame->DidResize(aPresContext, aReflowState);
rowFrame = rowFrame->GetNextRow();
}
}
}
void
nsTableFrame::DistributeHeightToRows(nsIPresContext* aPresContext,
const nsHTMLReflowState& aReflowState,
nscoord aAmount)
{
float p2t;
aPresContext->GetPixelsToTwips(&p2t);
nscoord cellSpacingY = GetCellSpacingY();
nscoord sumOfRowHeights = 0;
nscoord rowGroupYPos = aReflowState.mComputedBorderPadding.top + cellSpacingY;
nsVoidArray rowGroups;
PRUint32 numRowGroups;
OrderRowGroups(rowGroups, numRowGroups, nsnull);
nscoord amountUsed = 0;
// distribute space to each pct height row whose row group doesn't have a computed
// height, and base the pct on the table height. If the row group had a computed
// height, then this was already done in nsTableRowGroupFrame::CalculateRowHeights
nscoord pctBasis = aReflowState.mComputedHeight - (GetCellSpacingY() * (GetRowCount() + 1));
nscoord yOriginRG = aReflowState.mComputedBorderPadding.top + GetCellSpacingY();
nscoord yEndRG = yOriginRG;
PRUint32 rgX;
for (rgX = 0; (rgX < numRowGroups); rgX++) {
nsTableRowGroupFrame* rgFrame = GetRowGroupFrame((nsIFrame*)rowGroups.ElementAt(rgX));
nscoord amountUsedByRG = 0;
nscoord yOriginRow = 0;
nsRect rgRect;
rgFrame->GetRect(rgRect);
if (rgFrame && !rgFrame->HasStyleHeight()) {
nsTableRowFrame* rowFrame = rgFrame->GetFirstRow();
while (rowFrame) {
nsRect rowRect;
rowFrame->GetRect(rowRect);
if ((amountUsed < aAmount) && rowFrame->HasPctHeight()) {
nscoord pctHeight = nsTableFrame::RoundToPixel(rowFrame->GetHeight(pctBasis), p2t);
nscoord amountForRow = PR_MIN(aAmount - amountUsed, pctHeight - rowRect.height);
if (amountForRow > 0) {
rowRect.height += amountForRow;
rowFrame->SetRect(aPresContext, rowRect);
yOriginRow += rowRect.height + cellSpacingY;
yEndRG += rowRect.height + cellSpacingY;
amountUsed += amountForRow;
amountUsedByRG += amountForRow;
//rowFrame->DidResize(aPresContext, aReflowState);
nsTableFrame::RePositionViews(aPresContext, rowFrame);
}
}
else {
if (amountUsed > 0) {
rowFrame->MoveTo(aPresContext, rowRect.x, yOriginRow);
nsTableFrame::RePositionViews(aPresContext, rowFrame);
}
yOriginRow += rowRect.height + cellSpacingY;
yEndRG += rowRect.height + cellSpacingY;
}
rowFrame = rowFrame->GetNextRow();
}
if (amountUsed > 0) {
rgRect.y = yOriginRG;
rgRect.height += amountUsedByRG;
rgFrame->SetRect(aPresContext, rgRect);
}
}
else if (amountUsed > 0) {
rgFrame->MoveTo(aPresContext, 0, yOriginRG);
// Make sure child views are properly positioned
nsTableFrame::RePositionViews(aPresContext, rgFrame);
}
yOriginRG = yEndRG;
}
if (amountUsed >= aAmount) {
ResizeCells(*this, aPresContext, aReflowState);
return;
}
// get the first row without a style height where its row group has an unconstrianed height
nsTableRowGroupFrame* firstUnStyledRG = nsnull;
nsTableRowFrame* firstUnStyledRow = nsnull;
for (rgX = 0; (rgX < numRowGroups) && !firstUnStyledRG; rgX++) {
nsTableRowGroupFrame* rgFrame = GetRowGroupFrame((nsIFrame*)rowGroups.ElementAt(rgX));
if (rgFrame && !rgFrame->HasStyleHeight()) {
nsTableRowFrame* rowFrame = rgFrame->GetFirstRow();
while (rowFrame) {
if (!rowFrame->HasStyleHeight()) {
firstUnStyledRG = rgFrame;
firstUnStyledRow = rowFrame;
break;
}
rowFrame = rowFrame->GetNextRow();
}
}
}
nsTableRowFrame* lastElligibleRow = nsnull;
// accumulate the correct divisor. This will be the total of all unstyled rows inside
// unstyled row groups, unless there are none, in which case, it will be all rows
nscoord divisor = 0;
for (rgX = 0; rgX < numRowGroups; rgX++) {
nsTableRowGroupFrame* rgFrame = GetRowGroupFrame((nsIFrame*)rowGroups.ElementAt(rgX));
if (rgFrame && (!firstUnStyledRG || !rgFrame->HasStyleHeight())) {
nsTableRowFrame* rowFrame = rgFrame->GetFirstRow();
while (rowFrame) {
if (!firstUnStyledRG || !rowFrame->HasStyleHeight()) {
nsRect rowRect;
rowFrame->GetRect(rowRect);
divisor += rowRect.height;
lastElligibleRow = rowFrame;
}
rowFrame = rowFrame->GetNextRow();
}
}
}
if (divisor <= 0) {
NS_ASSERTION(PR_FALSE, "invlaid divisor");
return;
}
// allocate the extra height to the unstyled row groups and rows
pctBasis = aAmount - amountUsed;
yOriginRG = aReflowState.mComputedBorderPadding.top + cellSpacingY;
yEndRG = yOriginRG;
for (rgX = 0; rgX < numRowGroups; rgX++) {
nsTableRowGroupFrame* rgFrame = GetRowGroupFrame((nsIFrame*)rowGroups.ElementAt(rgX));
if (!rgFrame) continue;
nscoord amountUsedByRG = 0;
nscoord yOriginRow = 0;
nsRect rgRect;
rgFrame->GetRect(rgRect);
// see if there is an eligible row group
if (!firstUnStyledRG || !rgFrame->HasStyleHeight()) {
nsTableRowFrame* rowFrame = rgFrame->GetFirstRow();
while (rowFrame) {
nsRect rowRect;
rowFrame->GetRect(rowRect);
// see if there is an eligible row
if (!firstUnStyledRow || !rowFrame->HasStyleHeight()) {
// The amount of additional space each row gets is proportional to its height
float percent = rowRect.height / ((float)divisor);
// give rows their percentage, except for the last row which gets the remainder
nscoord amountForRow = (rowFrame == lastElligibleRow)
? aAmount - amountUsed : NSToCoordRound(((float)(pctBasis)) * percent);
amountForRow = PR_MIN(nsTableFrame::RoundToPixel(amountForRow, p2t), aAmount - amountUsed);
// update the row height
nsRect newRowRect(rowRect.x, yOriginRow, rowRect.width, rowRect.height + amountForRow);
rowFrame->SetRect(aPresContext, newRowRect);
yOriginRow += newRowRect.height + cellSpacingY;
yEndRG += newRowRect.height + cellSpacingY;
amountUsed += amountForRow;
amountUsedByRG += amountForRow;
NS_ASSERTION((amountUsed <= aAmount), "invalid row allocation");
//rowFrame->DidResize(aPresContext, aReflowState);
nsTableFrame::RePositionViews(aPresContext, rowFrame);
}
else {
if (amountUsed > 0) {
rowFrame->MoveTo(aPresContext, rowRect.x, yOriginRow);
nsTableFrame::RePositionViews(aPresContext, rowFrame);
}
yOriginRow += rowRect.height + cellSpacingY;
yEndRG += rowRect.height + cellSpacingY;
}
rowFrame = rowFrame->GetNextRow();
}
if (amountUsed > 0) {
rgRect.y = yOriginRG;
rgRect.height += amountUsedByRG;
rgFrame->SetRect(aPresContext, rgRect);
}
// Make sure child views are properly positioned
// XXX what happens if childFrame is a scroll frame and this gets skipped? see also below
}
else if (amountUsed > 0) {
rgFrame->MoveTo(aPresContext, 0, yOriginRG);
// Make sure child views are properly positioned
nsTableFrame::RePositionViews(aPresContext, rgFrame);
}
yOriginRG = yEndRG;
}
ResizeCells(*this, aPresContext, aReflowState);
}
static void
UpdateCol(nsTableFrame& aTableFrame,
nsTableColFrame& aColFrame,
@ -3435,6 +3590,17 @@ UpdateCol(nsTableFrame& aTableFrame,
}
}
PRBool
nsTableFrame::IsPctHeight(nsIStyleContext* aStyleContext)
{
PRBool result = PR_FALSE;
if (aStyleContext) {
nsStylePosition* position = (nsStylePosition*)aStyleContext->GetStyleData(eStyleStruct_Position);
result = (eStyleUnit_Percent == position->mHeight.GetUnit());
}
return result;
}
PRBool
nsTableFrame::CellChangedWidth(const nsTableCellFrame& aCellFrame,
nscoord aPrevCellMin,
@ -4370,9 +4536,20 @@ NS_IMETHODIMP nsTableFrame::GetTableSize(PRInt32& aRowCount, PRInt32& aColCount)
PRInt32 nsTableFrame::GetNumCellsOriginatingInCol(PRInt32 aColIndex) const
{
nsTableCellMap* cellMap = GetCellMap();
return cellMap->GetNumCellsOriginatingInCol(aColIndex);
if (cellMap)
return cellMap->GetNumCellsOriginatingInCol(aColIndex);
else
return 0;
}
PRInt32 nsTableFrame::GetNumCellsOriginatingInRow(PRInt32 aRowIndex) const
{
nsTableCellMap* cellMap = GetCellMap();
if (cellMap)
return cellMap->GetNumCellsOriginatingInRow(aRowIndex);
else
return 0;
}
/********************************************************************************
@ -4477,7 +4654,11 @@ void nsTableFrame::DebugReflow(nsIFrame* aFrame,
if (!aMetrics) { // start
PrettyUC(aState.availableWidth, width);
PrettyUC(aState.availableHeight, height);
printf("r=%d a=%s,%s ", aState.reason, width, height);
printf("r=%d ", aState.reason);
if (aState.mFlags.mSpecialTableReflow) {
printf("special ");
}
printf("a=%s,%s ", width, height);
PrettyUC(aState.mComputedWidth, width);
PrettyUC(aState.mComputedHeight, height);
printf("c=%s,%s ", width, height);

View File

@ -207,6 +207,8 @@ public:
float aPixelToTwips,
nsPixelRound aRound= eAlwaysRoundUp);
static void NotifyAncestorsOfSpecialReflow(const nsHTMLReflowState& aReflowState);
NS_IMETHOD IsPercentageBase(PRBool& aBase) const;
static nsresult AppendDirtyReflowCommand(nsIPresShell* aPresShell,
@ -258,6 +260,7 @@ public:
nsIAtom* aChildType);
PRBool IsAutoWidth(PRBool* aIsPctWidth = nsnull);
PRBool IsAutoHeight();
static PRBool IsPctHeight(nsIStyleContext* aStyleContext);
/** @return PR_TRUE if aDisplayType represents a rowgroup of any sort
* (header, footer, or body)
@ -491,14 +494,18 @@ public:
PRInt32* aColSpan = nsnull);
PRInt32 GetNumCellsOriginatingInCol(PRInt32 aColIndex) const;
PRInt32 GetNumCellsOriginatingInRow(PRInt32 aRowIndex) const;
PRBool HasPctCol() const;
void SetHasPctCol(PRBool aValue);
PRBool HasCellSpanningPctCol() const;
void SetHasCellSpanningPctCol(PRBool aValue);
// is this the 3rd reflow due to a height on a table in pagination mode.
PRBool IsThirdPassReflow() const;
PRBool NeedSpecialReflow() const;
void SetNeedSpecialReflow(PRBool aValue);
PRBool NeedToInitiateSpecialReflow() const;
void SetNeedToInitiateSpecialReflow(PRBool aValue);
protected:
@ -527,7 +534,6 @@ protected:
void SetDescendantReflowedNotTimeout(PRBool aValue);
PRBool RequestedTimeoutReflow() const;
void SetRequestedTimeoutReflow(PRBool aValue);
void SetThirdPassReflow(PRBool aValue);
void InterruptNotification(nsIPresContext* aPresContext,
PRBool aIsRequest);
@ -652,18 +658,12 @@ protected:
// reflow state, and for the table attributes and parent
nscoord CalcDesiredHeight(nsIPresContext* aPresContext,
const nsHTMLReflowState& aReflowState);
// The following two functions are helpers for CalcDesiredHeight
// The following is a helper for CalcDesiredHeight
void DistributeSpaceToCells(nsIPresContext* aPresContext,
void DistributeHeightToRows(nsIPresContext* aPresContext,
const nsHTMLReflowState& aReflowState,
nsIFrame* aRowGroupFrame);
void DistributeSpaceToRows(nsIPresContext* aPresContext,
const nsHTMLReflowState& aReflowState,
nsIFrame* aRowGroupFrame,
nscoord aSumOfRowHeights,
nscoord aExcess,
nscoord& aExcessAllocated,
nscoord& aRowGroupYPos);
nscoord aAmount);
void PlaceChild(nsIPresContext* aPresContext,
nsTableReflowState& aReflowState,
@ -830,8 +830,6 @@ public: /* ----- Cell Map public methods ----- */
// percentage height cells
void ComputePercentBasisForRows(const nsHTMLReflowState& aReflowState);
nscoord GetPercentBasisForRows();
nscoord GetMinWidth() const;
void SetMinWidth(nscoord aWidth);
@ -895,8 +893,9 @@ protected:
// targeted at us, as an optimization.
unsigned mRequestedTimeoutReflow:1;
unsigned mRowInserted:1;
unsigned mThirdPassReflow:1;
int : 21; // unused
unsigned mNeedSpecialReflow:1;
unsigned mNeedToInitiateSpecialReflow:1;
int : 19; // unused
} mBits;
nsTableCellMap* mCellMap; // maintains the relationships between rows, cols, and cells
@ -941,11 +940,6 @@ inline PRBool nsTableFrame::IsRowGroup(PRInt32 aDisplayType) const
(NS_STYLE_DISPLAY_TABLE_ROW_GROUP == aDisplayType));
}
inline nscoord nsTableFrame::GetPercentBasisForRows()
{
return mPercentBasisForRows;
}
inline void nsTableFrame::SetHadInitialReflow(PRBool aValue)
{
mBits.mHadInitialReflow = aValue;
@ -1006,16 +1000,25 @@ inline void nsTableFrame::SetRequestedTimeoutReflow(PRBool aValue)
mBits.mRequestedTimeoutReflow = (unsigned)aValue;
}
inline PRBool nsTableFrame::IsThirdPassReflow() const
inline PRBool nsTableFrame::NeedSpecialReflow() const
{
return (PRBool)mBits.mThirdPassReflow;
return (PRBool)mBits.mNeedSpecialReflow;
}
inline void nsTableFrame::SetThirdPassReflow(PRBool aValue)
inline void nsTableFrame::SetNeedSpecialReflow(PRBool aValue)
{
mBits.mThirdPassReflow = (unsigned)aValue;
mBits.mNeedSpecialReflow = (unsigned)aValue;
}
inline PRBool nsTableFrame::NeedToInitiateSpecialReflow() const
{
return (PRBool)mBits.mNeedToInitiateSpecialReflow;
}
inline void nsTableFrame::SetNeedToInitiateSpecialReflow(PRBool aValue)
{
mBits.mNeedToInitiateSpecialReflow = (unsigned)aValue;
}
inline PRBool nsTableFrame::IsRowInserted() const
{
return (PRBool)mBits.mRowInserted;

View File

@ -94,6 +94,42 @@ nsTableCellReflowState::nsTableCellReflowState(nsIPresContext* aPresCon
FixUp(aAvailSpace);
}
void
nsTableRowFrame::SetFixedHeight(nscoord aValue)
{
if (!HasPctHeight()) {
nscoord height = PR_MAX(0, aValue);
if (HasFixedHeight()) {
if (height > mStyleHeight) {
mStyleHeight = height;
}
}
else {
mStyleHeight = height;
if (height > 0) {
SetHasFixedHeight(PR_TRUE);
}
}
}
}
void
nsTableRowFrame::SetPctHeight(float aPctValue)
{
nscoord height = PR_MAX(0, NSToCoordRound(aPctValue * 100.0f));
if (HasPctHeight()) {
if (height > mStyleHeight) {
mStyleHeight = height;
}
}
else {
mStyleHeight = height;
if (height > 0.0f) {
SetHasPctHeight(PR_TRUE);
}
}
}
void nsTableCellReflowState::FixUp(const nsSize& aAvailSpace)
{
// fix the mComputed values during a pass 2 reflow since the cell can be a percentage base
@ -121,15 +157,13 @@ TallestCellGotShorter(nscoord aOld,
return ((aNew < aOld) && (aOld == aTallest));
}
/* ----------- nsTableRowpFrame ---------- */
/* ----------- nsTableRowFrame ---------- */
nsTableRowFrame::nsTableRowFrame()
: nsHTMLContainerFrame(),
mAllBits(0)
: nsHTMLContainerFrame()
{
mBits.mMinRowSpan = 1;
mBits.mRowIndex = 0;
ResetTallestCell(0);
mBits.mRowIndex = mBits.mFirstInserted = 0;
ResetHeight(0);
#ifdef DEBUG_TABLE_REFLOW_TIMING
mTimer = new nsReflowTimer(this);
#endif
@ -329,6 +363,20 @@ GetHeightOfRowsSpannedBelowFirst(nsTableCellFrame& aTableCellFrame,
return height;
}
nsTableCellFrame*
nsTableRowFrame::GetFirstCell()
{
nsIFrame* childFrame = mFrames.FirstChild();
while (childFrame) {
nsCOMPtr<nsIAtom> frameType;
childFrame->GetFrameType(getter_AddRefs(frameType));
if (nsLayoutAtoms::tableCellFrame == frameType.get()) {
return (nsTableCellFrame*)childFrame;
}
childFrame->GetNextSibling(&childFrame);
}
return nsnull;
}
/**
* Post-reflow hook. This is where the table row does its post-processing
@ -390,43 +438,53 @@ nscoord nsTableRowFrame::GetMaxCellAscent() const
return mMaxCellAscent;
}
#if 0 // nobody uses this
// returns max-descent amongst all cells that have 'vertical-align: baseline'
// does *not* include cells with rowspans
nscoord nsTableRowFrame::GetMaxCellDescent() const
nscoord
nsTableRowFrame::GetHeight(nscoord aPctBasis) const
{
return mMaxCellDescent;
}
#endif
/** returns the height of the tallest child in this row (ignoring any cell with rowspans) */
nscoord nsTableRowFrame::GetTallestCell() const
{
return mTallestCell;
nscoord height = 0;
if ((aPctBasis > 0) && HasPctHeight()) {
height = NSToCoordRound(GetPctHeight() * (float)aPctBasis);
}
else if (HasFixedHeight()) {
height = GetFixedHeight();
}
return PR_MAX(height, GetContentHeight());
}
void
nsTableRowFrame::ResetTallestCell(nscoord aRowStyleHeight)
nsTableRowFrame::ResetHeight(nscoord aFixedHeight)
{
mTallestCell = (NS_UNCONSTRAINEDSIZE == aRowStyleHeight) ? 0 : aRowStyleHeight;
SetHasFixedHeight(PR_FALSE);
SetHasPctHeight(PR_FALSE);
SetFixedHeight(0);
SetContentHeight(0);
if (aFixedHeight > 0) {
SetFixedHeight(aFixedHeight);
}
mMaxCellAscent = 0;
mMaxCellDescent = 0;
}
void
nsTableRowFrame::SetTallestCell(nscoord aHeight,
nscoord aAscent,
nscoord aDescent,
nsTableFrame* aTableFrame,
nsTableCellFrame* aCellFrame)
nsTableRowFrame::UpdateHeight(nscoord aHeight,
nscoord aAscent,
nscoord aDescent,
nsTableFrame* aTableFrame,
nsTableCellFrame* aCellFrame)
{
NS_ASSERTION((aTableFrame && aCellFrame) , "invalid call");
if (!aTableFrame || !aCellFrame) {
NS_ASSERTION(PR_FALSE , "invalid call");
return;
}
if (aHeight != NS_UNCONSTRAINEDSIZE) {
if (!(aCellFrame->HasVerticalAlignBaseline())) { // only the cell's height matters
if (mTallestCell < aHeight) {
if (GetHeight() < aHeight) {
PRInt32 rowSpan = aTableFrame->GetEffectiveRowSpan(*aCellFrame);
if (rowSpan == 1) {
mTallestCell = aHeight;
SetContentHeight(aHeight);
}
}
}
@ -444,21 +502,23 @@ nsTableRowFrame::SetTallestCell(nscoord aHeight,
}
}
// keep the tallest height in sync
if (mTallestCell < mMaxCellAscent + mMaxCellDescent) {
mTallestCell = mMaxCellAscent + mMaxCellDescent;
if (GetHeight() < mMaxCellAscent + mMaxCellDescent) {
SetContentHeight(mMaxCellAscent + mMaxCellDescent);
}
}
}
}
void
nsTableRowFrame::CalcTallestCell()
nscoord
nsTableRowFrame::CalcHeight(const nsHTMLReflowState& aReflowState)
{
nsTableFrame* tableFrame = nsnull;
nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame);
if (NS_FAILED(rv)) return;
if (!tableFrame) return 0;
ResetTallestCell(0);
nscoord computedHeight = (NS_UNCONSTRAINEDSIZE == aReflowState.mComputedHeight)
? 0 : aReflowState.mComputedHeight;
ResetHeight(computedHeight);
for (nsIFrame* kidFrame = mFrames.FirstChild(); kidFrame; kidFrame->GetNextSibling(&kidFrame)) {
nsCOMPtr<nsIAtom> frameType;
@ -470,9 +530,10 @@ nsTableRowFrame::CalcTallestCell()
// height may have changed, adjust descent to absorb any excess difference
nscoord ascent = ((nsTableCellFrame *)kidFrame)->GetDesiredAscent();
nscoord descent = desSize.height - ascent;
SetTallestCell(desSize.height, ascent, descent, tableFrame, (nsTableCellFrame*)kidFrame);
UpdateHeight(desSize.height, ascent, descent, tableFrame, (nsTableCellFrame*)kidFrame);
}
}
return GetHeight();
}
#if 0
@ -648,49 +709,6 @@ nsTableRowFrame::GetFrameForPoint(nsIPresContext* aPresContext,
return NS_ERROR_FAILURE;
}
/* GetMinRowSpan is needed for deviant cases where every cell in a row has a rowspan > 1.
* It sets mMinRowSpan, which is used in FixMinCellHeight
*/
void nsTableRowFrame::GetMinRowSpan(nsTableFrame *aTableFrame)
{
PRInt32 minRowSpan=-1;
nsIFrame* frame = mFrames.FirstChild();
while (frame)
{
const nsStyleDisplay *kidDisplay;
frame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)kidDisplay));
if (NS_STYLE_DISPLAY_TABLE_CELL == kidDisplay->mDisplay)
{
PRInt32 rowSpan = aTableFrame->GetEffectiveRowSpan((nsTableCellFrame &)*frame);
if (-1==minRowSpan)
minRowSpan = rowSpan;
else if (minRowSpan>rowSpan)
minRowSpan = rowSpan;
}
frame->GetNextSibling(&frame);
}
mBits.mMinRowSpan = unsigned(minRowSpan);
}
void nsTableRowFrame::FixMinCellHeight(nsTableFrame *aTableFrame)
{
nsIFrame* frame = mFrames.FirstChild();
while (frame) {
nsCOMPtr<nsIAtom> frameType;
frame->GetFrameType(getter_AddRefs(frameType));
if (nsLayoutAtoms::tableCellFrame == frameType.get()) {
PRInt32 rowSpan = aTableFrame->GetEffectiveRowSpan((nsTableCellFrame &)*frame);
if (PRInt32(mBits.mMinRowSpan) == rowSpan) {
nsRect rect;
frame->GetRect(rect);
if (rect.height > mTallestCell)
mTallestCell = rect.height;
}
}
frame->GetNextSibling(&frame);
}
}
// Calculate the cell's actual size given its pass2 desired width and height.
// Takes into account the specified height (in the style), and any special logic
// needed for backwards compatibility.
@ -701,37 +719,37 @@ nsTableRowFrame::CalculateCellActualSize(nsIFrame* aCellFrame,
nscoord& aDesiredHeight,
nscoord aAvailWidth)
{
nscoord specifiedHeight = 0;
const nsStylePosition* position;
nscoord specifiedHeight = 0;
// Get the height specified in the style information
const nsStylePosition* position;
aCellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)position);
nsTableFrame* tableFrame = nsnull;
nsTableFrame::GetTableFrame(this, tableFrame);
if (!tableFrame) return NS_ERROR_NULL_POINTER;
PRInt32 rowSpan = tableFrame->GetEffectiveRowSpan((nsTableCellFrame&)*aCellFrame);
switch (position->mHeight.GetUnit()) {
case eStyleUnit_Coord:
specifiedHeight = position->mHeight.GetCoordValue();
if (1 == rowSpan)
SetFixedHeight(specifiedHeight);
break;
case eStyleUnit_Percent: {
nsTableFrame* table = nsnull;
nsTableFrame::GetTableFrame(this, table);
if (table) {
nscoord basis = table->GetPercentBasisForRows();
if (basis > 0) {
float percent = position->mHeight.GetPercentValue();
specifiedHeight = NSToCoordRound(percent * ((float)basis));
}
}
if (1 == rowSpan)
SetPctHeight(position->mHeight.GetPercentValue());
// pct heights are handled when all of the cells are finished, so don't set specifiedHeight
break;
}
case eStyleUnit_Inherit:
// XXX for now, do nothing
case eStyleUnit_Auto:
default:
break;
}
// If the specified height is greater than the desired height, then use the
// specified height
// If the specified height is greater than the desired height, then use the specified height
if (specifiedHeight > aDesiredHeight)
aDesiredHeight = specifiedHeight;
@ -865,6 +883,7 @@ nsTableRowFrame::ReflowChildren(nsIPresContext* aPresContext,
PRInt32 prevColIndex = firstPrevColIndex;
nscoord x = 0; // running total of children x offset
nsTableFrame* tableFirstInFlow = (nsTableFrame*)tableFrame->GetFirstInFlow();
PRBool isAutoLayout = tableFrame->IsAutoLayout();
PRBool needToNotifyTable = PR_TRUE;
// Reflow each of our existing cell frames
@ -874,14 +893,21 @@ nsTableRowFrame::ReflowChildren(nsIPresContext* aPresContext,
nsFrameState frameState;
kidFrame->GetFrameState(&frameState);
nsCOMPtr<nsIAtom> frameType;
kidFrame->GetFrameType(getter_AddRefs(frameType));
// See if we should only reflow the dirty child frames
PRBool doReflowChild = PR_TRUE;
if (aDirtyOnly && ((frameState & NS_FRAME_IS_DIRTY) == 0)) {
doReflowChild = PR_FALSE;
}
nsCOMPtr<nsIAtom> frameType;
kidFrame->GetFrameType(getter_AddRefs(frameType));
if (aReflowState.mFlags.mSpecialTableReflow) {
if (!isPaginated && (nsLayoutAtoms::tableCellFrame == frameType.get() &&
!((nsTableCellFrame*)kidFrame)->NeedSpecialReflow())) {
kidFrame = iter.Next();
continue;
}
}
// Reflow the child frame
if (doReflowChild) {
@ -919,7 +945,9 @@ nsTableRowFrame::ReflowChildren(nsIPresContext* aPresContext,
if ((availCellWidth != cellFrame->GetPriorAvailWidth()) ||
(cellDesiredSize.width > cellFrame->GetPriorAvailWidth()) ||
(eReflowReason_StyleChange == aReflowState.reason) ||
isPaginated) {
isPaginated ||
(aReflowState.mFlags.mSpecialTableReflow && cellFrame->NeedSpecialReflow()) ||
HasPctHeight()) {
// Reflow the cell to fit the available width, height
nsSize kidAvailSize(availColWidth, aReflowState.availableHeight);
nsReflowReason reason = eReflowReason_Resize;
@ -1002,7 +1030,7 @@ nsTableRowFrame::ReflowChildren(nsIPresContext* aPresContext,
// height may have changed, adjust descent to absorb any excess difference
nscoord ascent = cellFrame->GetDesiredAscent();
nscoord descent = desiredSize.height - ascent;
SetTallestCell(desiredSize.height, ascent, descent, tableFrame, cellFrame);
UpdateHeight(desiredSize.height, ascent, descent, tableFrame, cellFrame);
// Place the child
if (NS_UNCONSTRAINEDSIZE != availColWidth) {
@ -1037,8 +1065,7 @@ nsTableRowFrame::ReflowChildren(nsIPresContext* aPresContext,
// just set our width to what was available. The table will calculate the width and not use our value.
aDesiredSize.width = aReflowState.availableWidth;
CalcTallestCell();
aDesiredSize.height = GetTallestCell();
aDesiredSize.height = CalcHeight(aReflowState);
return rv;
}
@ -1050,7 +1077,7 @@ NS_METHOD nsTableRowFrame::IncrementalReflow(nsIPresContext* aPresConte
nsReflowStatus& aStatus)
{
nsresult rv = NS_OK;
CalcTallestCell(); // need to recalculate it based on last reflow sizes
CalcHeight(aReflowState); // need to recalculate it based on last reflow sizes
// determine if this frame is the target or not
nsIFrame* target = nsnull;
@ -1193,7 +1220,7 @@ nsTableRowFrame::IR_TargetIsChild(nsIPresContext* aPresContext,
if (!hasVerticalAlignBaseline) {
// only the height matters
tallestCellGotShorter =
TallestCellGotShorter(oldCellDesSize.height, cellMet.height, mTallestCell);
TallestCellGotShorter(oldCellDesSize.height, cellMet.height, GetHeight());
}
else {
// the ascent matters
@ -1209,10 +1236,10 @@ nsTableRowFrame::IR_TargetIsChild(nsIPresContext* aPresContext,
}
}
if (tallestCellGotShorter) {
CalcTallestCell();
CalcHeight(aReflowState);
}
else {
SetTallestCell(cellMet.height, cellMet.ascent, cellMet.descent, &aTableFrame, cellFrame);
UpdateHeight(cellMet.height, cellMet.ascent, cellMet.descent, &aTableFrame, cellFrame);
}
// if the cell's desired size didn't changed, our height is unchanged
@ -1232,7 +1259,7 @@ nsTableRowFrame::IR_TargetIsChild(nsIPresContext* aPresContext,
}
}
}
aDesiredSize.height = (aDesiredSize.mNothingChanged) ? mRect.height : GetTallestCell();
aDesiredSize.height = (aDesiredSize.mNothingChanged) ? mRect.height : GetHeight();
if (1 == rowSpan) {
cellMet.height = aDesiredSize.height;
}
@ -1308,25 +1335,19 @@ nsTableRowFrame::Reflow(nsIPresContext* aPresContext,
rv = nsTableFrame::GetTableFrame(this, tableFrame);
if (!tableFrame) return NS_ERROR_NULL_POINTER;
if ((NS_UNCONSTRAINEDSIZE != aReflowState.availableWidth) && !mPrevInFlow) {
// see if an extra reflow will be necessary when there is a pct height but no height on the parent
if ( ((NS_UNCONSTRAINEDSIZE == aReflowState.mComputedHeight) ||
(0 == aReflowState.mComputedHeight)) &&
nsTableFrame::IsPctHeight(mStyleContext)) {
nsTableFrame::NotifyAncestorsOfSpecialReflow(aReflowState);
SetNeedSpecialReflow(PR_TRUE);
}
}
switch (aReflowState.reason) {
case eReflowReason_Initial:
rv = ReflowChildren(aPresContext, aDesiredSize, aReflowState, *tableFrame, aStatus, PR_FALSE);
#ifdef WHY
if (!tableFrame->IsAutoLayout()) {
// this resize reflow is necessary to place the cells correctly in the case of rowspans and colspans.
// It is very efficient. It does not actually need to pass a reflow down to the cells.
nsSize availSpace(aReflowState.availableWidth, aReflowState.availableHeight);
nsHTMLReflowState resizeReflowState(aPresContext,
(const nsHTMLReflowState&)(*(aReflowState.parentReflowState)),
(nsIFrame *)this,
availSpace,
eReflowReason_Resize);
RowReflowState rowResizeReflowState(resizeReflowState, tableFrame);
rv = ReflowChildren(aPresContext, aDesiredSize, rowResizeReflowState, aStatus);
}
#endif
//GetMinRowSpan(tableFrame);
//FixMinCellHeight(tableFrame);
aStatus = NS_FRAME_COMPLETE;
break;
@ -1343,6 +1364,10 @@ nsTableRowFrame::Reflow(nsIPresContext* aPresContext,
// just set our width to what was available. The table will calculate the width and not use our value.
aDesiredSize.width = aReflowState.availableWidth;
if (aReflowState.mFlags.mSpecialTableReflow) {
SetNeedSpecialReflow(PR_FALSE);
}
#if defined DEBUG_TABLE_REFLOW_TIMING
nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState, &aDesiredSize, aStatus);
#endif
@ -1463,6 +1488,21 @@ nsTableRowFrame::GetFrameType(nsIAtom** aType) const
return NS_OK;
}
nsTableRowFrame*
nsTableRowFrame::GetNextRow() const
{
nsIFrame* childFrame;
GetNextSibling(&childFrame);
while (childFrame) {
nsCOMPtr<nsIAtom> frameType;
childFrame->GetFrameType(getter_AddRefs(frameType));
if (nsLayoutAtoms::tableRowFrame == frameType.get()) {
return (nsTableRowFrame*)childFrame;
}
childFrame->GetNextSibling(&childFrame);
}
return nsnull;
}
/* ----- global methods ----- */

View File

@ -47,7 +47,7 @@ class nsTableCellFrame;
class nsReflowTimer;
#endif
#define NS_TABLE_MAX_ROW_INDEX (1<<19)
#define NS_ROW_NEED_SPECIAL_REFLOW 0x20000000
#define NS_ROW_FRAME_PAINT_SKIP_ROW 0x00000001
#define NS_ROW_FRAME_PAINT_SKIP_CELLS 0x00000002
@ -121,6 +121,8 @@ public:
nsFramePaintLayer aWhichLayer,
nsIFrame** aFrame);
nsTableCellFrame* GetFirstCell() ;
/** calls Reflow for all of its child cells.
* Cells with rowspan=1 are all set to the same height and stacked horizontally.
* <P> Cells are not split unless absolutely necessary.
@ -155,19 +157,17 @@ public:
PRUint32* aResult) const;
#endif
void SetTallestCell(nscoord aHeight,
nscoord aAscent,
nscoord aDescent,
nsTableFrame* aTableFrame = nsnull,
nsTableCellFrame* aCellFrame = nsnull);
void UpdateHeight(nscoord aHeight,
nscoord aAscent,
nscoord aDescent,
nsTableFrame* aTableFrame = nsnull,
nsTableCellFrame* aCellFrame = nsnull);
void ResetTallestCell(nscoord aRowStyleHeight);
void ResetHeight(nscoord aRowStyleHeight);
// calculate the tallest child when the previous tallest child gets shorter
void CalcTallestCell();
/** returns the tallest child in this row (ignoring any cell with rowspans) */
nscoord GetTallestCell() const;
// calculate the height, considering content height of the
// cells and the style height of the row and cells, excluding pct heights
nscoord CalcHeight(const nsHTMLReflowState& aReflowState);
// Support for cells with 'vertical-align: baseline'.
@ -210,14 +210,38 @@ public:
void RemoveCellFrame(nsTableCellFrame* aFrame);
nsresult CalculateCellActualSize(nsIFrame* aRowFrame,
nscoord& aDesiredWidth,
nscoord& aDesiredHeight,
nscoord aAvailWidth);
nsresult CalculateCellActualSize(nsIFrame* aRowFrame,
nscoord& aDesiredWidth,
nscoord& aDesiredHeight,
nscoord aAvailWidth);
PRBool IsFirstInserted() const;
void SetFirstInserted(PRBool aValue);
PRBool NeedSpecialReflow() const;
void SetNeedSpecialReflow(PRBool aValue);
PRBool GetContentHeight() const;
void SetContentHeight(nscoord aTwipValue);
PRBool HasStyleHeight() const;
PRBool HasFixedHeight() const;
void SetHasFixedHeight(PRBool aValue);
PRBool HasPctHeight() const;
void SetHasPctHeight(PRBool aValue);
nscoord GetFixedHeight() const;
void SetFixedHeight(nscoord aValue);
float GetPctHeight() const;
void SetPctHeight(float aPctValue);
nscoord GetHeight(nscoord aBasis = 0) const;
nsTableRowFrame* GetNextRow() const;
protected:
/** protected constructor.
@ -262,10 +286,6 @@ protected:
// row-specific methods
void GetMinRowSpan(nsTableFrame *aTableFrame);
void FixMinCellHeight(nsTableFrame *aTableFrame);
nscoord ComputeCellXOffset(const nsHTMLReflowState& aState,
nsIFrame* aKidFrame,
const nsMargin& aKidMargin) const;
@ -280,19 +300,18 @@ protected:
nsReflowStatus& aStatus,
PRBool aDirtyOnly = PR_FALSE);
public:
struct RowBits {
int mRowIndex:20;
unsigned mMinRowSpan:11; // the smallest row span among all my child cells
unsigned mFirstInserted; // if true, then it was the top most newly inserted row
};
private:
union {
PRUint32 mAllBits;
RowBits mBits;
};
nscoord mTallestCell; // not my height, but the height of my tallest child
struct RowBits {
unsigned mRowIndex:29;
unsigned mHasFixedHeight:1; // set if the dominating style height on the row or any cell is pixel based
unsigned mHasPctHeight:1; // set if the dominating style height on the row or any cell is pct based
unsigned mFirstInserted:1; // if true, then it was the top most newly inserted row
} mBits;
nscoord mContentHeight; // the desired height based on the content of the tallest cell in the row
nscoord mStyleHeight; // the height based on a style pct on either the row or any cell if mHasPctHeight
// is set, otherwise the height based on a style pixel height on the row or any
// cell if mHasFixedHeight is set
// max-ascent and max-descent amongst all cells that have 'vertical-align: baseline'
nscoord mMaxCellAscent; // does include cells with rowspan > 1
@ -311,7 +330,6 @@ inline PRInt32 nsTableRowFrame::GetRowIndex() const
inline void nsTableRowFrame::SetRowIndex (int aRowIndex)
{
NS_PRECONDITION(aRowIndex < NS_TABLE_MAX_ROW_INDEX, "unexpected row index");
mBits.mRowIndex = aRowIndex;
}
@ -325,4 +343,68 @@ inline void nsTableRowFrame::SetFirstInserted(PRBool aValue)
mBits.mFirstInserted = aValue;
}
inline PRBool nsTableRowFrame::HasStyleHeight() const
{
return (PRBool)mBits.mHasFixedHeight || (PRBool)mBits.mHasPctHeight;
}
inline PRBool nsTableRowFrame::HasFixedHeight() const
{
return (PRBool)mBits.mHasFixedHeight;
}
inline void nsTableRowFrame::SetHasFixedHeight(PRBool aValue)
{
mBits.mHasFixedHeight = aValue;
}
inline PRBool nsTableRowFrame::HasPctHeight() const
{
return (PRBool)mBits.mHasPctHeight;
}
inline void nsTableRowFrame::SetHasPctHeight(PRBool aValue)
{
mBits.mHasPctHeight = aValue;
}
inline nscoord nsTableRowFrame::GetContentHeight() const
{
return mContentHeight;
}
inline void nsTableRowFrame::SetContentHeight(nscoord aValue)
{
mContentHeight = aValue;
}
inline nscoord nsTableRowFrame::GetFixedHeight() const
{
if (mBits.mHasFixedHeight && !mBits.mHasPctHeight)
return mStyleHeight;
else
return 0;
}
inline float nsTableRowFrame::GetPctHeight() const
{
if (mBits.mHasPctHeight)
return (float)mStyleHeight / 100.0f;
else
return 0.0f;
}
inline PRBool nsTableRowFrame::NeedSpecialReflow() const
{
return (mState & NS_ROW_NEED_SPECIAL_REFLOW) == NS_ROW_NEED_SPECIAL_REFLOW;
}
inline void nsTableRowFrame::SetNeedSpecialReflow(PRBool aValue)
{
if (aValue) {
mState |= NS_ROW_NEED_SPECIAL_REFLOW;
} else {
mState &= ~NS_ROW_NEED_SPECIAL_REFLOW;
}
}
#endif

View File

@ -105,6 +105,13 @@ nsTableRowGroupFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr)
}
}
NS_IMETHODIMP
nsTableRowGroupFrame::IsPercentageBase(PRBool& aBase) const
{
aBase = PR_TRUE;
return NS_OK;
}
PRInt32
nsTableRowGroupFrame::GetRowCount()
{
@ -362,6 +369,9 @@ nsTableRowGroupFrame::ReflowChildren(nsIPresContext* aPresContext,
nscoord cellSpacingY = tableFrame->GetCellSpacingY();
PRBool isPaginated;
aPresContext->IsPaginated(&isPaginated);
if (aFirstRowReflowed) {
*aFirstRowReflowed = nsnull;
}
@ -369,8 +379,11 @@ nsTableRowGroupFrame::ReflowChildren(nsIPresContext* aPresContext,
PRBool adjustSiblings = PR_TRUE;
nsIFrame* kidFrame = (aStartFrame) ? aStartFrame : mFrames.FirstChild();
for ( ; kidFrame; ) {
nsTableFrame* tableFirstInFlow = (nsTableFrame*)tableFrame->GetFirstInFlow();
for ( ; kidFrame; kidFrame->GetNextSibling(&kidFrame)) {
// Get the frame state bits
nsCOMPtr<nsIAtom> kidType;
kidFrame->GetFrameType(getter_AddRefs(kidType));
nsFrameState frameState;
kidFrame->GetFrameState(&frameState);
@ -379,6 +392,12 @@ nsTableRowGroupFrame::ReflowChildren(nsIPresContext* aPresContext,
if (aDirtyOnly && ((frameState & NS_FRAME_IS_DIRTY) == 0)) {
doReflowChild = PR_FALSE;
}
if (aReflowState.reflowState.mFlags.mSpecialTableReflow) {
if (!isPaginated && (nsLayoutAtoms::tableRowFrame == kidType.get() &&
!((nsTableRowFrame*)kidFrame)->NeedSpecialReflow())) {
doReflowChild = PR_FALSE;
}
}
// Reflow the row frame
if (doReflowChild) {
@ -413,9 +432,7 @@ nsTableRowGroupFrame::ReflowChildren(nsIPresContext* aPresContext,
lastReflowedRow = kidFrame;
if (aFirstRowReflowed && !*aFirstRowReflowed) {
nsCOMPtr<nsIAtom> fType;
kidFrame->GetFrameType(getter_AddRefs(fType));
if (nsLayoutAtoms::tableRowFrame == fType.get()) {
if (nsLayoutAtoms::tableRowFrame == kidType.get()) {
*aFirstRowReflowed = (nsTableRowFrame*)kidFrame;
}
}
@ -432,8 +449,6 @@ nsTableRowGroupFrame::ReflowChildren(nsIPresContext* aPresContext,
kidFrame->GetSize(kidSize);
aReflowState.y += kidSize.height + cellSpacingY;
}
kidFrame->GetNextSibling(&kidFrame); // Get the next child
}
// adjust the rows after the ones that were reflowed
@ -454,56 +469,82 @@ nsTableRowGroupFrame::ReflowChildren(nsIPresContext* aPresContext,
return rv;
}
void
nsTableRowGroupFrame::GetNextRowSibling(nsIFrame** aRowFrame)
nsTableRowFrame*
nsTableRowGroupFrame::GetFirstRow()
{
if (!*aRowFrame) return;
GetNextFrame(*aRowFrame, aRowFrame);
while(*aRowFrame) {
const nsStyleDisplay *display;
(*aRowFrame)->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)display));
if (NS_STYLE_DISPLAY_TABLE_ROW == display->mDisplay) {
return;
nsIFrame* childFrame = GetFirstFrame();
while (childFrame) {
nsCOMPtr<nsIAtom> frameType;
childFrame->GetFrameType(getter_AddRefs(frameType));
if (nsLayoutAtoms::tableRowFrame == frameType.get()) {
return (nsTableRowFrame*)childFrame;
}
GetNextFrame(*aRowFrame, aRowFrame);
childFrame->GetNextSibling(&childFrame);
}
return nsnull;
}
struct RowInfo {
unsigned height:30;
unsigned hasStyleHeight:1;
unsigned isSpecial:1; // there is no cell originating in the row with rowspan=1 and there are at
// least 2 cells spanning the row and there is no style height on the row
};
static void
UpdateHeights(RowInfo& aRowInfo,
nscoord aAdditionalHeight,
nscoord& aTotal,
nscoord& aUnconstrainedTotal)
{
aRowInfo.height += aAdditionalHeight;
aTotal += aAdditionalHeight;
if (!aRowInfo.hasStyleHeight) {
aUnconstrainedTotal += aAdditionalHeight;
}
}
// allocate the height of rows which have no cells originating in them
// except with cells with rowspan > 1. Store the height as negative
// to distinguish them from regular rows.
void
AllocateSpecialHeight(nsIPresContext* aPresContext,
nsTableFrame* aTableFrame,
nsIFrame* aRowFrame,
nscoord& aHeight)
nsTableRowGroupFrame::DidResizeRows(nsIPresContext& aPresContext,
const nsHTMLReflowState& aReflowState,
nsTableRowFrame* aStartRowFrameIn)
{
nsIFrame* cellFrame;
aRowFrame->FirstChild(aPresContext, nsnull, &cellFrame);
while (cellFrame) {
nsCOMPtr<nsIAtom> cellType;
cellFrame->GetFrameType(getter_AddRefs(cellType));
if (nsLayoutAtoms::tableCellFrame == cellType.get()) {
PRInt32 rowSpan = aTableFrame->GetEffectiveRowSpan((nsTableCellFrame&)*cellFrame);
if (rowSpan > 1) {
// use a simple average to allocate the special row. This is not exact,
// but much better than nothing.
nsSize cellDesSize = ((nsTableCellFrame*)cellFrame)->GetDesiredSize();
((nsTableRowFrame*)aRowFrame)->CalculateCellActualSize(cellFrame, cellDesSize.width,
cellDesSize.height, cellDesSize.width);
PRInt32 propHeight = NSToCoordRound((float)cellDesSize.height / (float)rowSpan);
// special rows store the largest negative value
aHeight = PR_MIN(aHeight, -propHeight);
}
}
cellFrame->GetNextSibling(&cellFrame);
// update the cells spanning rows with their new heights
// this is the place where all of the cells in the row get set to the height of the row
PRInt32 rowIndex;
nsTableRowFrame* rowFrame;
nsTableRowFrame* startRowFrame = (aStartRowFrameIn) ? aStartRowFrameIn: GetFirstRow();
for (rowFrame = startRowFrame, rowIndex = 0; rowFrame; rowFrame = rowFrame->GetNextRow(), rowIndex++) {
rowFrame->DidResize(&aPresContext, aReflowState);
}
}
/* CalculateRowHeights provides default heights for all rows in the rowgroup.
* Actual row heights are ultimately determined by the table, when the table
* height attribute is factored in.
*/
static PRBool
HasMoreThanOneCell(nsTableCellMap* aCellMap,
PRInt32 aRowIndex)
{
if (aCellMap) {
CellData* cellData;
PRInt32 colIndex = 0;
PRInt32 count = 0;
do {
cellData = aCellMap->GetCellAt(aRowIndex, colIndex);
if (cellData && (cellData->GetCellFrame() || cellData->IsRowSpan()))
count++;
if (count > 1)
return PR_TRUE;
colIndex++;
} while(cellData);
}
return PR_FALSE;
}
// This calculates the height of rows starting at aStartRowFrameIn and takes into account
// style height on the row group, style heights on rows and cells, style heights on rowspans.
// Actual row heights will be adjusted later if the table has a style height.
// Even if rows don't change height, this method must be called to set the heights of each
// cell in the row to the height of its row.
void
nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
@ -511,280 +552,259 @@ nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext,
nsTableRowFrame* aStartRowFrameIn)
{
nsTableFrame* tableFrame = nsnull;
nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame);
if (NS_FAILED(rv) || nsnull==tableFrame) return;
nsTableFrame::GetTableFrame(this, tableFrame);
if (!aPresContext || !tableFrame) return;
// all table cells have the same top and bottom margins, namely cellSpacingY
nscoord cellSpacingY = tableFrame->GetCellSpacingY();
float p2t;
aPresContext->GetPixelsToTwips(&p2t);
// find the nearest row to the starting row (including the starting row) that isn't spanned into
nsTableRowFrame* startRowFrame = nsnull;
nsIFrame* childFrame = GetFirstFrame();
PRBool foundFirstRow = PR_FALSE;
while (childFrame) {
nsCOMPtr<nsIAtom> frameType;
childFrame->GetFrameType(getter_AddRefs(frameType));
if (nsLayoutAtoms::tableRowFrame == frameType.get()) {
PRInt32 rowIndex = ((nsTableRowFrame*)childFrame)->GetRowIndex();
if (!foundFirstRow || !tableFrame->RowIsSpannedInto(rowIndex)) {
startRowFrame = (nsTableRowFrame*)childFrame;
if (!aStartRowFrameIn || (aStartRowFrameIn == startRowFrame)) break;
// find the nearest row at or before aStartRowFrameIn that isn't spanned into.
// If we have a computed height, then we can't compute the heights
// incrementally from aStartRowFrameIn, and we must start at the first row.
nsTableRowFrame* startRowFrame = GetFirstRow();
if (aStartRowFrameIn && (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedHeight)
&& (aReflowState.mComputedHeight > 0)) {
nsTableRowFrame* rowFrame = startRowFrame;
while (rowFrame) {
PRInt32 rowIndex = rowFrame->GetRowIndex();
if (!tableFrame->RowIsSpannedInto(rowIndex)) {
startRowFrame = rowFrame;
if (aStartRowFrameIn == startRowFrame)
break;
}
else if (aStartRowFrameIn == (nsTableRowFrame*)childFrame) break;
foundFirstRow = PR_TRUE;
else if (aStartRowFrameIn == rowFrame)
break;
rowFrame = rowFrame->GetNextRow();
}
childFrame->GetNextSibling(&childFrame);
}
if (!startRowFrame) return;
PRInt32 startRowIndex = startRowFrame->GetRowIndex();
nsRect startRowRect;
startRowFrame->GetRect(startRowRect);
nscoord rowGroupHeight = startRowRect.y;
// the current row group height is the y origin of the 1st row we are about to calculated a height for
nscoord startRowGroupHeight = startRowRect.y;
PRInt32 numRows = GetRowCount() - (startRowFrame->GetRowIndex() - GetStartRowIndex());
// collect the current height of each row. nscoord* rowHeights = nsnull;
RowInfo* rowInfo;
if (numRows > 0) {
rowInfo = new RowInfo[numRows];
if (!rowInfo) return;
nsCRT::memset (rowInfo, 0, numRows*sizeof(RowInfo));
}
else return;
PRBool hasRowSpanningCell = PR_FALSE;
PRInt32 numRows = GetRowCount() - (startRowFrame->GetRowIndex() - GetStartRowIndex());
// collect the current height of each row. rows which have 0 height because
// they have no cells originating in them without rowspans > 1, are referred to as
// special rows. The current height of a special row will be a negative number until
// it comes time to actually resize frames.
nscoord* rowHeights = nsnull;
if (numRows > 0) {
rowHeights = new nscoord[numRows];
if (!rowHeights) return;
nsCRT::memset (rowHeights, 0, numRows*sizeof(nscoord));
} // else - tree row groups need not have rows directly beneath them
nscoord heightOfRows = 0;
nscoord heightOfUnStyledRows = 0;
// Get the height of each row without considering rowspans. This will be the max of
// the largest desired height of each cell, the largest style height of each cell,
// the style height of the row.
nscoord pctHeightBasis = GetHeightBasis(aReflowState);
nsTableRowFrame* rowFrame;
PRInt32 rowIndex; // the index in rowInfo, not among the rows in the row group
for (rowFrame = startRowFrame, rowIndex = 0; rowFrame; rowFrame = rowFrame->GetNextRow(), rowIndex++) {
UpdateHeights(rowInfo[rowIndex], nsTableFrame::RoundToPixel(rowFrame->GetHeight(pctHeightBasis), p2t),
heightOfRows, heightOfUnStyledRows);
rowInfo[rowIndex].hasStyleHeight = rowFrame->HasStyleHeight();
// Step 1: get the height of the tallest cell in the row and save it for
// pass 2. This height is for table cells that originate in this
// row and that don't span into the rows that follow
nsIFrame* rowFrame = startRowFrame;
PRInt32 rowIndex = 0;
// For row groups that are split across pages, the first row frame won't
// necessarily be index 0
PRInt32 startRowIndex = -1;
while (rowFrame) {
nsCOMPtr<nsIAtom> frameType;
rowFrame->GetFrameType(getter_AddRefs(frameType));
if (nsLayoutAtoms::tableRowFrame == frameType.get()) {
if (startRowIndex == -1) {
startRowIndex = ((nsTableRowFrame*)rowFrame)->GetRowIndex();
}
// get the height of the tallest cell in the row (excluding cells that span rows)
rowHeights[rowIndex] = ((nsTableRowFrame*)rowFrame)->GetTallestCell();
// See if a cell spans into the row. If so we'll have to do step 2
if (!hasRowSpanningCell) {
if (tableFrame->RowIsSpannedInto(rowIndex + startRowIndex)) {
hasRowSpanningCell = PR_TRUE;
if (!rowInfo[rowIndex].hasStyleHeight) {
if (HasMoreThanOneCell(tableFrame->GetCellMap(), rowIndex)) {
rowInfo[rowIndex].isSpecial = PR_TRUE;
// iteratate the row's cell frames to see if any do not have rowspan > 1
nsTableCellFrame* cellFrame = rowFrame->GetFirstCell();
while (cellFrame) {
PRInt32 rowSpan = tableFrame->GetEffectiveRowSpan(rowIndex + startRowIndex, *cellFrame);
if (1 == rowSpan) {
rowInfo[rowIndex].isSpecial = PR_FALSE;
break;
}
cellFrame = cellFrame->GetNextCell();
}
}
// special rows need to have some values, so they will get allocations
// later. If left at 0, they would get nothing.
if (0 == rowHeights[rowIndex]) {
AllocateSpecialHeight(aPresContext, tableFrame, rowFrame, rowHeights[rowIndex]);
}
rowIndex++;
}
GetNextFrame(rowFrame, &rowFrame); // Get the next row
// See if a cell spans into the row. If so we'll have to do the next step
if (!hasRowSpanningCell) {
if (tableFrame->RowIsSpannedInto(rowIndex + startRowIndex)) {
hasRowSpanningCell = PR_TRUE;
}
}
}
// Step 2: Now account for cells that span rows. A spanning cell's height is the sum of the heights of the
// rows it spans, or it's own desired height, whichever is greater.
// If the cell's desired height is the larger value, resize the rows and contained
// cells by an equal percentage of the additional space.
// We go through this loop twice. The first time, we are adjusting cell heights
// on the fly. The second time through the loop, we're ensuring that subsequent
// row-spanning cells didn't change prior calculations. Since we are guaranteed
// to have found the max height spanners the first time through, we know we only
// need two passes, not an arbitrary number.
nscoord yOrigin = rowGroupHeight;
nscoord lastCount = (hasRowSpanningCell) ? 2 : 1;
for (PRInt32 counter = 0; counter <= lastCount; counter++) {
rowFrame = startRowFrame;
rowIndex = 0;
while (rowFrame) {
nsCOMPtr<nsIAtom> rowType;
rowFrame->GetFrameType(getter_AddRefs(rowType));
if (nsLayoutAtoms::tableRowFrame == rowType.get()) {
if (hasRowSpanningCell) {
// check this row for a cell with rowspans
nsIFrame* cellFrame;
rowFrame->FirstChild(aPresContext, nsnull, &cellFrame);
while (cellFrame) {
nsCOMPtr<nsIAtom> cellType;
cellFrame->GetFrameType(getter_AddRefs(cellType));
if (nsLayoutAtoms::tableCellFrame == cellType.get()) {
PRInt32 rowSpan = tableFrame->GetEffectiveRowSpan(rowIndex + startRowIndex,
(nsTableCellFrame&)*cellFrame);
if (rowSpan > 1) { // found a cell with rowspan > 1, determine the height
// of the rows it spans
nscoord heightOfRowsSpanned = 0;
nscoord cellSpacingOfRowsSpanned = 0;
PRInt32 spanX;
PRBool cellsOrigInSpan = PR_FALSE; // do any cells originate in the spanned rows
for (spanX = 0; spanX < rowSpan; spanX++) {
PRInt32 rIndex = rowIndex + spanX;
if (rowHeights[rIndex] > 0) {
// don't consider negative values of special rows
heightOfRowsSpanned += rowHeights[rowIndex + spanX];
cellsOrigInSpan = PR_TRUE;
}
if (0 != spanX) {
cellSpacingOfRowsSpanned += cellSpacingY;
}
}
nscoord availHeightOfRowsSpanned = heightOfRowsSpanned + cellSpacingOfRowsSpanned;
if (hasRowSpanningCell) {
// Get the height of cells with rowspans and allocate any extra space to the rows they span
// iteratate the child frames and process the row frames among them
for (rowFrame = startRowFrame, rowIndex = 0; rowFrame; rowFrame = rowFrame->GetNextRow(), rowIndex++) {
if (tableFrame->RowHasSpanningCells(startRowIndex + rowIndex)) {
nsTableCellFrame* cellFrame = rowFrame->GetFirstCell();
// iteratate the row's cell frames
while (cellFrame) {
PRInt32 rowSpan = tableFrame->GetEffectiveRowSpan(rowIndex + startRowIndex, *cellFrame);
if (rowSpan > 1) { // a cell with rowspan > 1, determine the height of the rows it spans
nscoord heightOfRowsSpanned = 0;
nscoord heightOfUnStyledRowsSpanned = 0;
nscoord numSpecialRowsSpanned = 0;
nscoord cellSpacingTotal = 0;
PRInt32 spanX;
for (spanX = 0; spanX < rowSpan; spanX++) {
heightOfRowsSpanned += rowInfo[rowIndex + spanX].height;
if (!rowInfo[rowIndex + spanX].hasStyleHeight) {
heightOfUnStyledRowsSpanned += rowInfo[rowIndex + spanX].height;
}
if (0 != spanX) {
cellSpacingTotal += cellSpacingY;
}
if (rowInfo[rowIndex + spanX].isSpecial) {
numSpecialRowsSpanned++;
}
}
nscoord heightOfAreaSpanned = heightOfRowsSpanned + cellSpacingTotal;
// get the height of the cell
nsSize cellFrameSize;
cellFrame->GetSize(cellFrameSize);
nsSize cellDesSize = cellFrame->GetDesiredSize();
rowFrame->CalculateCellActualSize(cellFrame, cellDesSize.width,
cellDesSize.height, cellDesSize.width);
cellFrameSize.height = cellDesSize.height;
if (cellFrame->HasVerticalAlignBaseline()) {
// to ensure that a spanning cell with a long descender doesn't
// collide with the next row, we need to take into account the shift
// that will be done to align the cell on the baseline of the row.
cellFrameSize.height += rowFrame->GetMaxCellAscent() - cellFrame->GetDesiredAscent();
}
// see if the cell's height fits within the rows it spans. If this is
// pass 1 then use the cell's desired height and not the current height
// of its frame. That way this works for incremental reflow, too
nsSize cellFrameSize;
cellFrame->GetSize(cellFrameSize);
if (0 == counter) {
nsSize cellDesSize = ((nsTableCellFrame*)cellFrame)->GetDesiredSize();
((nsTableRowFrame*)rowFrame)->CalculateCellActualSize(cellFrame, cellDesSize.width,
cellDesSize.height, cellDesSize.width);
cellFrameSize.height = cellDesSize.height;
// see if the cell has 'vertical-align: baseline'
if (((nsTableCellFrame*)cellFrame)->HasVerticalAlignBaseline()) {
// to ensure that a spanning cell with a long descender doesn't
// collide with the next row, we need to take into account the shift
// that will be done to align the cell on the baseline of the row.
cellFrameSize.height += ((nsTableRowFrame*)rowFrame)->GetMaxCellAscent()
- ((nsTableCellFrame*)cellFrame)->GetDesiredAscent();
}
}
if (availHeightOfRowsSpanned >= cellFrameSize.height) {
// the cell's height fits with the available space of the rows it
// spans. Set the cell frame's height
cellFrame->SizeTo(aPresContext, cellFrameSize.width, availHeightOfRowsSpanned);
// Realign cell content based on new height
((nsTableCellFrame*)cellFrame)->VerticallyAlignChild(aPresContext, aReflowState, ((nsTableRowFrame*)rowFrame)->GetMaxCellAscent());
}
else {
// the cell's height is larger than the available space of the rows it
// spans so distribute the excess height to the rows affected
nscoord excessAvail = cellFrameSize.height - availHeightOfRowsSpanned;
nscoord excessBasis = excessAvail;
nsTableRowFrame* rowFrameToBeResized = (nsTableRowFrame *)rowFrame;
// iterate every row starting at last row spanned and up to the row with
// the spanning cell. do this bottom up so that special rows can get a full
// allocation before other rows.
PRInt32 beginRowIndex = rowIndex + rowSpan - 1;
for (PRInt32 rowX = beginRowIndex; (rowX >= rowIndex) && (excessAvail > 0); rowX--) {
nscoord excessForRow = 0;
// special rows gets as much as they can
if (rowHeights[rowX] <= 0) {
if ((rowX == beginRowIndex) || (!cellsOrigInSpan)) {
if (0 == rowHeights[rowX]) {
// give it all since no cell originates in the row
excessForRow = excessBasis;
}
else { // don't let the allocation excced what it needs
excessForRow = (excessBasis > -rowHeights[rowX]) ? -rowHeights[rowX] : excessBasis;
}
rowHeights[rowX] = excessForRow;
excessBasis -= excessForRow;
excessAvail -= excessForRow;
if (heightOfAreaSpanned < cellFrameSize.height) {
// the cell's height is larger than the available space of the rows it
// spans so distribute the excess height to the rows affected
nscoord extra = cellFrameSize.height - heightOfAreaSpanned;
nscoord extraUsed = 0;
if (0 == numSpecialRowsSpanned) {
//NS_ASSERTION(heightOfRowsSpanned > 0, "invalid row span situation");
PRBool haveUnStyledRowsSpanned = (heightOfUnStyledRowsSpanned > 0);
nscoord divisor = (haveUnStyledRowsSpanned)
? heightOfUnStyledRowsSpanned : heightOfRowsSpanned;
if (divisor > 0) {
for (spanX = rowSpan - 1; spanX >= 0; spanX--) {
if (!haveUnStyledRowsSpanned || !rowInfo[rowIndex + spanX].hasStyleHeight) {
// The amount of additional space each row gets is proportional to its height
float percent = ((float)rowInfo[rowIndex + spanX].height) / ((float)divisor);
// give rows their percentage, except for the first row which gets the remainder
nscoord extraForRow = (0 == spanX) ? extra - extraUsed
: NSToCoordRound(((float)(extra)) * percent);
extraForRow = PR_MIN(nsTableFrame::RoundToPixel(extraForRow, p2t), extra - extraUsed);
// update the row height
UpdateHeights(rowInfo[rowIndex + spanX], extraForRow, heightOfRows, heightOfUnStyledRows);
extraUsed += extraForRow;
if (extraUsed >= extra) {
NS_ASSERTION((extraUsed == extra), "invalid row height calculation");
break;
}
}
else if (cellsOrigInSpan) { // normal rows
// The amount of additional space each normal row gets is based on the
// percentage of space it occupies, i.e. they don't all get the
// same amount of available space
float percent = ((float)rowHeights[rowX]) / ((float)heightOfRowsSpanned);
// give rows their percentage, except for the first row which gets
// the remainder
excessForRow = (rowX == rowIndex)
? excessAvail
: NSToCoordRound(((float)(excessBasis)) * percent);
// update the row height
rowHeights[rowX] += excessForRow;
excessAvail -= excessForRow;
}
// Get the next row frame
GetNextRowSibling((nsIFrame**)&rowFrameToBeResized);
}
// if excessAvail is > 0 it is because !cellsOrigInSpan and the
// allocation involving special rows couldn't allocate everything.
// just give the remainder to the last row spanned.
if (excessAvail > 0) {
if (rowHeights[beginRowIndex] >= 0) {
rowHeights[beginRowIndex] += excessAvail;
}
else {
rowHeights[beginRowIndex] = excessAvail;
}
else {
// put everything in the last row
UpdateHeights(rowInfo[rowIndex + rowSpan - 1], extra, heightOfRows, heightOfUnStyledRows);
}
}
else {
// give the extra to the special rows
nscoord numSpecialRowsAllocated = 0;
for (spanX = rowSpan - 1; spanX >= 0; spanX--) {
if (rowInfo[rowIndex + spanX].isSpecial) {
// The amount of additional space each degenerate row gets is proportional to the number of them
float percent = 1.0f / ((float)numSpecialRowsSpanned);
// give rows their percentage, except for the first row which gets the remainder
nscoord extraForRow = (numSpecialRowsSpanned - 1 == numSpecialRowsAllocated)
? extra - extraUsed
: NSToCoordRound(((float)(extra)) * percent);
extraForRow = PR_MIN(nsTableFrame::RoundToPixel(extraForRow, p2t), extra - extraUsed);
// update the row height
UpdateHeights(rowInfo[rowIndex + spanX], extraForRow, heightOfRows, heightOfUnStyledRows);
extraUsed += extraForRow;
if (extraUsed >= extra) {
NS_ASSERTION((extraUsed == extra), "invalid row height calculation");
break;
}
}
}
}
}
cellFrame->GetNextSibling(&cellFrame); // Get the next row child (cell frame)
}
}
// If this is the last pass then resize the row to its final size and move the
// row's position if the previous rows have caused a shift
if (lastCount == counter) {
nsRect rowBounds;
rowFrame->GetRect(rowBounds);
PRBool movedFrame = (rowBounds.y != yOrigin);
nscoord rowHeight = (rowHeights[rowIndex] > 0) ? rowHeights[rowIndex] : 0;
// Resize the row to its final size and position
rowBounds.y = yOrigin;
rowBounds.height = rowHeight;
rowFrame->SetRect(aPresContext, rowBounds);
if (movedFrame) {
nsTableFrame::RePositionViews(aPresContext, rowFrame);
}
// set the origin of the next row.
yOrigin += rowHeight + cellSpacingY;
}
rowIndex++;
}
GetNextFrame(rowFrame, &rowFrame); // Get the next rowgroup child (row frame)
}
}
} // if (rowSpan > 1)
cellFrame = cellFrame->GetNextCell();
} // while (cellFrame)
} // if (tableFrame->RowHasSpanningCells(startRowIndex + rowIndex) {
} // while (rowFrame)
}
// step 3: notify the rows of their new heights
rowFrame = startRowFrame;
rowIndex = 0;
while (rowFrame) {
if (NS_UNCONSTRAINEDSIZE != aReflowState.availableWidth) {
nsCOMPtr<nsIAtom> rowType;
rowFrame->GetFrameType(getter_AddRefs(rowType));
if (nsLayoutAtoms::tableRowFrame == rowType.get()) {
// Notify the row of the new size
((nsTableRowFrame *)rowFrame)->DidResize(aPresContext, aReflowState);
nscoord rowGroupHeight = startRowGroupHeight + heightOfRows + ((numRows - 1) * cellSpacingY);
nscoord extraComputedHeight = 0;
// if we have a style height, allocate the extra height to unconstrained rows
if ((aReflowState.mComputedHeight > rowGroupHeight) &&
(NS_UNCONSTRAINEDSIZE != aReflowState.mComputedHeight)) {
extraComputedHeight = aReflowState.mComputedHeight - rowGroupHeight;
nscoord extraUsed = 0;
PRBool haveUnStyledRows = (heightOfUnStyledRows > 0);
nscoord divisor = (haveUnStyledRows)
? heightOfUnStyledRows : heightOfRows;
if (divisor > 0) {
for (rowIndex = 0; rowIndex < numRows; rowIndex++) {
if (!haveUnStyledRows || !rowInfo[rowIndex].hasStyleHeight) {
// The amount of additional space each row gets is based on the
// percentage of space it occupies
float percent = ((float)rowInfo[rowIndex].height) / ((float)divisor);
// give rows their percentage, except for the last row which gets the remainder
nscoord extraForRow = (numRows - 1 == rowIndex)
? extraComputedHeight - extraUsed
: NSToCoordRound(((float)extraComputedHeight) * percent);
extraForRow = PR_MIN(nsTableFrame::RoundToPixel(extraForRow, p2t), extraComputedHeight - extraUsed);
// update the row height
UpdateHeights(rowInfo[rowIndex], extraForRow, heightOfRows, heightOfUnStyledRows);
extraUsed += extraForRow;
if (extraUsed >= extraComputedHeight) {
NS_ASSERTION((extraUsed == extraComputedHeight), "invalid row height calculation");
break;
}
}
}
}
// Update the running row group height. The height includes frames that
// aren't rows as well
nsSize rowSize;
rowFrame->GetSize(rowSize);
rowGroupHeight += rowSize.height;
if (0 != rowIndex) {
rowGroupHeight += cellSpacingY;
}
GetNextFrame(rowFrame, &rowFrame); // Get the next row
rowIndex++;
rowGroupHeight = aReflowState.mComputedHeight;
}
nscoord yOrigin = startRowGroupHeight;
// update the rows with their (potentially) new heights
for (rowFrame = startRowFrame, rowIndex = 0; rowFrame; rowFrame = rowFrame->GetNextRow(), rowIndex++) {
nsRect rowBounds;
rowFrame->GetRect(rowBounds);
PRBool movedFrame = (rowBounds.y != yOrigin);
nscoord rowHeight = (rowInfo[rowIndex].height > 0) ? rowInfo[rowIndex].height : 0;
if (movedFrame || (rowHeight != rowBounds.height)) {
// Resize the row to its final size and position
rowBounds.y = yOrigin;
rowBounds.height = rowHeight;
rowFrame->SetRect(aPresContext, rowBounds);
}
if (movedFrame) {
nsTableFrame::RePositionViews(aPresContext, rowFrame);
}
yOrigin += rowHeight + cellSpacingY;
}
DidResizeRows(*aPresContext, aReflowState, startRowFrame);
aDesiredSize.height = rowGroupHeight; // Adjust our desired size
delete [] rowHeights; // cleanup
delete [] rowInfo; // cleanup
}
// Called by IR_TargetIsChild() to adjust the sibling frames that follow
// after an incremental reflow of aKidFrame.
// This function is not used for paginated mode so we don't need to deal
@ -918,31 +938,6 @@ nsTableRowGroupFrame::SplitSpanningCells(nsIPresContext& aPresContext,
return tallestCell;
}
nsIFrame* GetNextRow(nsIFrame& aFrame)
{
nsIFrame* rowFrame;
for (aFrame.GetNextSibling(&rowFrame); rowFrame; rowFrame->GetNextSibling(&rowFrame)) {
nsCOMPtr<nsIAtom> fType;
rowFrame->GetFrameType(getter_AddRefs(fType));
if (nsLayoutAtoms::tableRowFrame == fType.get()) {
return rowFrame;
}
}
return nsnull;
}
nsIFrame* GetFirstRow(nsTableRowGroupFrame& aRowGroupFrame)
{
for (nsIFrame* rowFrame = aRowGroupFrame.GetFirstFrame(); rowFrame; rowFrame = GetNextRow(*rowFrame)) {
nsCOMPtr<nsIAtom> fType;
rowFrame->GetFrameType(getter_AddRefs(fType));
if (nsLayoutAtoms::tableRowFrame == fType.get()) {
return rowFrame;
}
}
return nsnull;
}
nsresult
nsTableRowGroupFrame::SplitRowGroup(nsIPresContext* aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
@ -971,7 +966,7 @@ nsTableRowGroupFrame::SplitRowGroup(nsIPresContext* aPresContext,
// Walk each of the row frames looking for the first row frame that
// doesn't fit in the available space
for (nsIFrame* rowFrame = GetFirstRow(*this); rowFrame; rowFrame = GetNextRow(*rowFrame)) {
for (nsTableRowFrame* rowFrame = GetFirstRow(); rowFrame; rowFrame = rowFrame->GetNextRow()) {
PRBool rowIsOnCurrentPage = PR_TRUE;
PRBool degenerateRow = PR_FALSE;
nsRect bounds;
@ -995,7 +990,7 @@ nsTableRowGroupFrame::SplitRowGroup(nsIPresContext* aPresContext,
0, 0, NS_FRAME_NO_MOVE_FRAME, aStatus);
rowFrame->SizeTo(aPresContext, desiredSize.width, desiredSize.height);
rowFrame->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED);
((nsTableRowFrame *)rowFrame)->DidResize(aPresContext, aReflowState);
rowFrame->DidResize(aPresContext, aReflowState);
if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) {
// the row frame is incomplete and all of the cells' block frames have split
@ -1043,7 +1038,7 @@ nsTableRowGroupFrame::SplitRowGroup(nsIPresContext* aPresContext,
if (prevRowFrame) {
nscoord tallestCell =
SplitSpanningCells(*aPresContext, aReflowState, *styleSet, *aTableFrame,
*(nsTableRowFrame*)rowFrame, aDesiredSize.height, (nsTableRowFrame*)contRowFrame);
*rowFrame, aDesiredSize.height, (nsTableRowFrame*)contRowFrame);
if (degenerateRow) {
aDesiredSize.height = lastDesiredHeight + aTableFrame->GetCellSpacingY() + tallestCell;
}
@ -1077,10 +1072,10 @@ nsTableRowGroupFrame::Reflow(nsIPresContext* aPresContext,
nsresult rv=NS_OK;
aStatus = NS_FRAME_COMPLETE;
nsTableFrame* tableFrame = nsnull;
rv = nsTableFrame::GetTableFrame(this, tableFrame);
if (!tableFrame) return NS_ERROR_NULL_POINTER;
if (!aPresContext || !tableFrame) return NS_ERROR_NULL_POINTER;
nsRowGroupReflowState state(aReflowState, tableFrame);
PRBool haveDesiredHeight = PR_FALSE;
@ -1111,9 +1106,12 @@ nsTableRowGroupFrame::Reflow(nsIPresContext* aPresContext,
// reflow, then we need to do this because the table will skip the pass 2 reflow,
// but we need to correctly calculate the row group height and we can't if there
// are row spans unless we do this step
if ((eReflowReason_Initial != aReflowState.reason) ||
isTableUnconstrainedReflow ||
isPaginated) {
if (aReflowState.mFlags.mSpecialTableReflow) {
DidResizeRows(*aPresContext, aReflowState);
}
else if ((eReflowReason_Initial != aReflowState.reason) ||
isTableUnconstrainedReflow ||
isPaginated) {
CalculateRowHeights(aPresContext, aDesiredSize, aReflowState);
haveDesiredHeight = PR_TRUE;
}
@ -1124,6 +1122,12 @@ nsTableRowGroupFrame::Reflow(nsIPresContext* aPresContext,
SplitRowGroup(aPresContext, aDesiredSize, aReflowState, tableFrame, aStatus);
}
}
SetHasStyleHeight((NS_UNCONSTRAINEDSIZE != aReflowState.mComputedHeight) &&
(aReflowState.mComputedHeight > 0));
if (aReflowState.mFlags.mSpecialTableReflow) {
SetNeedSpecialReflow(PR_FALSE);
}
// just set our width to what was available. The table will calculate the width and not use our value.
aDesiredSize.width = aReflowState.availableWidth;
@ -1318,6 +1322,21 @@ nsTableRowGroupFrame::IR_TargetIsMe(nsIPresContext* aPresContext,
return rv;
}
nscoord
nsTableRowGroupFrame::GetHeightBasis(const nsHTMLReflowState& aReflowState)
{
nscoord result = 0;
if ((aReflowState.mComputedHeight > 0) && (aReflowState.mComputedHeight < NS_UNCONSTRAINEDSIZE)) {
nsTableFrame* tableFrame = nsnull;
nsTableFrame::GetTableFrame((nsIFrame*)this, tableFrame);
if (tableFrame) {
nscoord cellSpacing = PR_MAX(0, GetRowCount() - 1) * tableFrame->GetCellSpacingY();
result -= cellSpacing;
}
}
return result;
}
nscoord
nsTableRowGroupFrame::GetHeightOfRows(nsIPresContext* aPresContext)
{

View File

@ -79,9 +79,13 @@ struct nsRowGroupReflowState {
{ 0xe940e7bc, 0xb534, 0x11d2, \
{ 0x95, 0xa2, 0x0, 0x60, 0xb0, 0xc3, 0x44, 0x14 } }
// use a bit from nsFrame's frame state bits to determine whether a
// use the following bits from nsFrame's frame state
// thead or tfoot should be repeated on every printed page
#define NS_ROWGROUP_REPEATABLE 0x80000000
#define NS_ROWGROUP_REPEATABLE 0x80000000
#define NS_ROWGROUP_HAS_STYLE_HEIGHT 0x40000000
// we need a 3rd pass reflow to deal with pct height nested tables
#define NS_ROWGROUP_NEED_SPECIAL_REFLOW 0x20000000
/**
* nsTableRowGroupFrame is the frame that maps row groups
* (HTML tags THEAD, TFOOT, and TBODY). This class cannot be reused
@ -176,6 +180,10 @@ public:
*/
NS_IMETHOD GetFrameType(nsIAtom** aType) const;
NS_IMETHOD IsPercentageBase(PRBool& aBase) const;
nsTableRowFrame* GetFirstRow();
#ifdef DEBUG
NS_IMETHOD GetFrameName(nsString& aResult) const;
NS_IMETHOD SizeOf(nsISizeOfHandler* aSizer, PRUint32* aResult) const;
@ -206,6 +214,7 @@ public:
* Get the total height of all the row rects
*/
nscoord GetHeightOfRows(nsIPresContext* aPresContext);
nscoord GetHeightBasis(const nsHTMLReflowState& aReflowState);
// nsILineIterator methods
public:
@ -255,6 +264,9 @@ protected:
const nsHTMLReflowState& aReflowState,
nsTableRowFrame* aStartRowFrameIn = nsnull);
void DidResizeRows(nsIPresContext& aPresContext,
const nsHTMLReflowState& aReflowState,
nsTableRowFrame* aStartRowFrameIn = nsnull);
/** Incremental Reflow attempts to do column balancing with the minimum number of reflow
* commands to child elements. This is done by processing the reflow command,
@ -337,8 +349,12 @@ public:
virtual nsIFrame* GetLastFrame() { return mFrames.LastChild(); };
virtual void GetNextFrame(nsIFrame* aFrame,
nsIFrame** aResult) { aFrame->GetNextSibling(aResult); };
PRBool IsRepeatable();
void SetRepeatable(PRBool aRepeatable);
PRBool IsRepeatable() const;
void SetRepeatable(PRBool aRepeatable);
PRBool HasStyleHeight() const;
void SetHasStyleHeight(PRBool aValue);
PRBool NeedSpecialReflow() const;
void SetNeedSpecialReflow(PRBool aValue);
#ifdef DEBUG_TABLE_REFLOW_TIMING
public:
@ -347,7 +363,7 @@ public:
};
inline PRBool nsTableRowGroupFrame::IsRepeatable()
inline PRBool nsTableRowGroupFrame::IsRepeatable() const
{
return (mState & NS_ROWGROUP_REPEATABLE) == NS_ROWGROUP_REPEATABLE;
}
@ -361,4 +377,31 @@ inline void nsTableRowGroupFrame::SetRepeatable(PRBool aRepeatable)
}
}
inline PRBool nsTableRowGroupFrame::NeedSpecialReflow() const
{
return (mState & NS_ROWGROUP_NEED_SPECIAL_REFLOW) == NS_ROWGROUP_NEED_SPECIAL_REFLOW;
}
inline void nsTableRowGroupFrame::SetNeedSpecialReflow(PRBool aValue)
{
if (aValue) {
mState |= NS_ROWGROUP_NEED_SPECIAL_REFLOW;
} else {
mState &= ~NS_ROWGROUP_NEED_SPECIAL_REFLOW;
}
}
inline PRBool nsTableRowGroupFrame::HasStyleHeight() const
{
return (mState & NS_ROWGROUP_HAS_STYLE_HEIGHT) == NS_ROWGROUP_HAS_STYLE_HEIGHT;
}
inline void nsTableRowGroupFrame::SetHasStyleHeight(PRBool aValue)
{
if (aValue) {
mState |= NS_ROWGROUP_HAS_STYLE_HEIGHT;
} else {
mState &= ~NS_ROWGROUP_HAS_STYLE_HEIGHT;
}
}
#endif