Moved shrink wrap code from table frame to table row group frame

This commit is contained in:
troy 1998-06-30 02:11:07 +00:00
Родитель 5dddac8d3a
Коммит add97af1d2
8 изменённых файлов: 500 добавлений и 552 удалений

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

@ -1054,7 +1054,6 @@ PRBool nsTableFrame::NeedsReflow(const nsSize& aMaxSize)
if pass is 1,
set pass to 2
use column widths to ResizeReflow cells
shrinkWrap Cells in each row to tallest, realigning contents within the cell
*/
/* Layout the entire inner table. */
@ -1409,12 +1408,8 @@ nsReflowStatus nsTableFrame::ResizeReflowPass2(nsIPresContext* aPresContext,
}
// Return our desired rect
//NS_ASSERTION(0<state.y, "illegal height after reflow");
aDesiredSize.width = aReflowState.maxSize.width;
aDesiredSize.height = state.y;
// shrink wrap rows to height of tallest cell in that row
ShrinkWrapChildren(aPresContext, aDesiredSize, aDesiredSize.maxElementSize);
aDesiredSize.height = state.y + myBorderPadding.top + myBorderPadding.bottom;
if (gsDebugNT==PR_TRUE)
{
@ -2246,259 +2241,6 @@ void nsTableFrame::SetTableWidth(nsIPresContext* aPresContext)
SetRect(tableSize);
}
/**
*/
void nsTableFrame::ShrinkWrapChildren(nsIPresContext* aPresContext,
nsReflowMetrics& aDesiredSize,
nsSize* aMaxElementSize)
{
#ifdef NS_DEBUG
PRBool gsDebugWas = gsDebug;
//gsDebug = PR_TRUE; // turn on debug in this method
#endif
// iterate children, tell all row groups to ShrinkWrap
PRBool atLeastOneRowSpanningCell = PR_FALSE;
PRInt32 rowIndex;
PRInt32 tableHeight = 0;
const nsStyleSpacing* spacing = (const nsStyleSpacing*)
mStyleContext->GetStyleData(eStyleStruct_Spacing);
nsMargin borderPadding;
spacing->CalcBorderPaddingFor(this, borderPadding);
tableHeight += borderPadding.top + borderPadding.bottom;
PRInt32 childCount = mChildCount;
nsIFrame * kidFrame;
for (PRInt32 i = 0; i < childCount; i++)
{
PRInt32 childHeight=0;
// for every child that is a rowFrame, set the row frame height = sum of row heights
if (0==i)
ChildAt(i, kidFrame); // frames are not ref counted
else
kidFrame->GetNextSibling(kidFrame);
NS_ASSERTION(nsnull != kidFrame, "bad kid frame");
nscoord topInnerMargin = 0;
nscoord bottomInnerMargin = 0;
const nsStyleDisplay *childDisplay;
kidFrame->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay));
if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == childDisplay->mDisplay ||
NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == childDisplay->mDisplay ||
NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == childDisplay->mDisplay )
{
/* Step 1: set the row height to the height of the tallest cell,
* and resize all cells in that row to that height (except cells with rowspan>1)
*/
PRInt32 rowGroupHeight = 0;
nsTableRowGroupFrame * rowGroupFrame = (nsTableRowGroupFrame *)kidFrame;
PRInt32 numRows;
rowGroupFrame->ChildCount(numRows);
PRInt32 *rowHeights = new PRInt32[numRows];
nsCRT::memset (rowHeights, 0, numRows*sizeof(PRInt32));
if (gsDebug==PR_TRUE) printf("Height Step 1...\n");
for (rowIndex = 0; rowIndex < numRows; rowIndex++)
{
// get the height of the tallest cell in the row (excluding cells that span rows)
nsTableRowFrame *rowFrame;
rowGroupFrame->ChildAt(rowIndex, (nsIFrame*&)rowFrame);
NS_ASSERTION(nsnull != rowFrame, "bad row frame");
nscoord maxCellHeight = rowFrame->GetTallestChild();
nscoord maxCellTopMargin = rowFrame->GetChildMaxTopMargin();
nscoord maxCellBottomMargin = rowFrame->GetChildMaxBottomMargin();
nscoord maxRowHeight = maxCellHeight + maxCellTopMargin + maxCellBottomMargin;
rowHeights[rowIndex] = maxRowHeight;
if (rowIndex == 0)
topInnerMargin = maxCellTopMargin;
if (rowIndex+1 == numRows)
bottomInnerMargin = maxCellBottomMargin;
nsSize rowFrameSize(0,0);
rowFrame->GetSize(rowFrameSize);
rowFrame->SizeTo(rowFrameSize.width, maxRowHeight);
rowGroupHeight += maxRowHeight;
// resize all the cells based on the rowHeight
PRInt32 numCells;
rowFrame->ChildCount(numCells);
for (PRInt32 cellIndex = 0; cellIndex < numCells; cellIndex++)
{
nsTableCellFrame *cellFrame;
rowFrame->ChildAt(cellIndex, (nsIFrame*&)cellFrame);
PRInt32 rowSpan = GetEffectiveRowSpan(rowIndex, cellFrame);//cellFrame->GetRowSpan();
if (1==rowSpan)
{
if (gsDebug==PR_TRUE) printf(" setting cell[%d,%d] height to %d\n", rowIndex, cellIndex, rowHeights[rowIndex]);
nsSize cellFrameSize(0,0);
cellFrame->GetSize(cellFrameSize);
cellFrame->SizeTo(cellFrameSize.width, maxCellHeight);
// Realign cell content based on new height
cellFrame->VerticallyAlignChild(aPresContext);
}
else
{
if (gsDebug==PR_TRUE) printf(" skipping cell[%d,%d]\n", rowIndex, cellIndex);
atLeastOneRowSpanningCell = 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.
*/
/* TODO
* 1. optimization, if (PR_TRUE==atLeastOneRowSpanningCell) ... otherwise skip this step entirely
* 2. find cases where spanning cells effect other spanning cells that began in rows above themselves.
* I think in this case, we have to make another pass through step 2.
* There should be a "rational" check to terminate that kind of loop after n passes, probably 3 or 4.
*/
if (gsDebug==PR_TRUE) printf("Height Step 2...\n");
rowGroupHeight=0;
nsTableRowFrame *rowFrame=nsnull;
for (rowIndex = 0; rowIndex < numRows; rowIndex++)
{
// get the next row
if (0==rowIndex)
rowGroupFrame->ChildAt(rowIndex, (nsIFrame*&)rowFrame);
else
rowFrame->GetNextSibling((nsIFrame*&)rowFrame);
PRInt32 numCells;
rowFrame->ChildCount(numCells);
// check this row for a cell with rowspans
for (PRInt32 cellIndex = 0; cellIndex < numCells; cellIndex++)
{
// get the next cell
nsTableCellFrame *cellFrame;
rowFrame->ChildAt(cellIndex, (nsIFrame*&)cellFrame);
PRInt32 rowSpan = GetEffectiveRowSpan(rowIndex, cellFrame);//cellFrame->GetRowSpan();
if (1<rowSpan)
{ // found a cell with rowspan > 1, determine it's height
if (gsDebug==PR_TRUE) printf(" cell[%d,%d] has a rowspan = %d\n", rowIndex, cellIndex, rowSpan);
nscoord heightOfRowsSpanned = 0;
for (PRInt32 i=0; i<rowSpan; i++)
heightOfRowsSpanned += rowHeights[i+rowIndex];
heightOfRowsSpanned -= topInnerMargin + bottomInnerMargin;
/* if the cell height fits in the rows, expand the spanning cell's height and slap it in */
nsSize cellFrameSize(0,0);
cellFrame->GetSize(cellFrameSize);
if (heightOfRowsSpanned>cellFrameSize.height)
{
if (gsDebug==PR_TRUE) printf(" cell[%d,%d] fits, setting height to %d\n", rowIndex, cellIndex, heightOfRowsSpanned);
cellFrame->SizeTo(cellFrameSize.width, heightOfRowsSpanned);
// Realign cell content based on new height
cellFrame->VerticallyAlignChild(aPresContext);
}
/* otherwise, distribute the excess height to the rows effected, and to the cells in those rows
* push all subsequent rows down by the total change in height of all the rows above it
*/
else
{
PRInt32 excessHeight = cellFrameSize.height - heightOfRowsSpanned;
PRInt32 excessHeightPerRow = excessHeight/rowSpan;
if (gsDebug==PR_TRUE) printf(" cell[%d,%d] does not fit, excessHeight = %d, excessHeightPerRow = %d\n",
rowIndex, cellIndex, excessHeight, excessHeightPerRow);
// for every row starting at the row with the spanning cell...
for (i=rowIndex; i<numRows; i++)
{
nsTableRowFrame *rowFrameToBeResized;
rowGroupFrame->ChildAt(i, (nsIFrame*&)rowFrameToBeResized);
// if the row is within the spanned range, resize the row and it's cells
if (i<rowIndex+rowSpan)
{
rowHeights[i] += excessHeightPerRow;
if (gsDebug==PR_TRUE) printf(" rowHeight[%d] set to %d\n", i, rowHeights[i]);
nsSize rowFrameSize(0,0);
rowFrameToBeResized->GetSize(rowFrameSize);
rowFrameToBeResized->SizeTo(rowFrameSize.width, rowHeights[i]);
PRInt32 cellCount;
rowFrameToBeResized->ChildCount(cellCount);
for (PRInt32 j=0; j<cellCount; j++)
{
if (i==rowIndex && j==cellIndex)
{
if (gsDebug==PR_TRUE) printf(" cell[%d, %d] skipping self\n", i, j);
continue; // don't do math on myself, only the other cells I effect
}
nsTableCellFrame *frame;
rowFrameToBeResized->ChildAt(j, (nsIFrame*&)frame);
PRInt32 frameRowSpan = GetEffectiveRowSpan(i, frame);
if (frameRowSpan==1)
{
nsSize frameSize(0,0);
frame->GetSize(frameSize);
if (gsDebug==PR_TRUE) printf(" cell[%d, %d] set height to %d\n", i, j, frameSize.height+excessHeightPerRow);
frame->SizeTo(frameSize.width, frameSize.height+excessHeightPerRow);
// Realign cell content based on new height
frame->VerticallyAlignChild(aPresContext);
}
}
}
// if we're dealing with a row below the row containing the spanning cell,
// push that row down by the amount we've expanded the cell heights by
if (i>=rowIndex && i!=0)
{
nsRect rowRect;
rowFrameToBeResized->GetRect(rowRect);
nscoord delta = excessHeightPerRow*(i-rowIndex);
if (delta > excessHeight)
delta = excessHeight;
rowFrameToBeResized->MoveTo(rowRect.x, rowRect.y + delta);
if (gsDebug==PR_TRUE) printf(" row %d (%p) moved by %d to y-offset %d\n",
i, rowFrameToBeResized, delta, rowRect.y + delta);
}
}
}
}
}
rowGroupHeight += rowHeights[rowIndex];
}
if (gsDebug==PR_TRUE) printf("row group height set to %d\n", rowGroupHeight);
nsSize rowGroupFrameSize(0,0);
rowGroupFrame->GetSize(rowGroupFrameSize);
rowGroupFrame->SizeTo(rowGroupFrameSize.width, rowGroupHeight);
tableHeight += rowGroupHeight;
if (nsnull!=rowHeights)
delete [] rowHeights;
}
}
if (0!=tableHeight)
{
if (gsDebug==PR_TRUE) printf("table desired height set to %d\n", tableHeight);
aDesiredSize.height = tableHeight;
}
#ifdef NS_DEBUG
gsDebug = gsDebugWas;
#endif
}
void nsTableFrame::VerticallyAlignChildren(nsIPresContext* aPresContext,
nscoord* aAscents,
nscoord aMaxAscent,

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

@ -96,7 +96,6 @@ public:
* set mFirstPassValid to true
* do pass 2
* use column widths to Reflow cells
* shrinkWrap Cells in each row to tallest, realigning contents within the cell
* </pre>
*
* @see ResizeReflowPass1
@ -115,21 +114,6 @@ public:
nsIStyleContext* aStyleContext,
nsIFrame*& aContinuingFrame);
/** resize myself and my children according to the arcane rules of cell height magic.
* By default, the height of a cell is the max (height of cells in its row)
* In the case of a cell with rowspan>1 (lets call this C),
* if the sum of the height of the rows spanned (excluding C in the calculation)
* is greater than or equal to the height of C,
* the cells in the rows are sized normally and
* the height of C is set to the sum of the heights (taking into account borders, padding, and margins)
* else
* the height of each row is expanded by a percentage of the difference between
* the row's desired height and the height of C
*/
virtual void ShrinkWrapChildren(nsIPresContext* aPresContext,
nsReflowMetrics& aDesiredSize,
nsSize* aMaxElementSize);
/** allow the cell and row attributes to effect the column frame
* currently, the only reason this exists is to support the HTML "rule"
* that a width attribute on a cell in the first column sets the column width.

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

@ -827,6 +827,240 @@ nsTableRowGroupFrame::ReflowUnmappedChildren(nsIPresContext* aPresContext,
return result;
}
/**
* Called by ShrinkWrapChildren() to set the height of a table row. Resizes
* the table row, each of the row's table cells, and then realigns the cell
* content based on the new height
*/
void nsTableRowGroupFrame::SetRowHeight(nsIPresContext* aPresContext,
nsIFrame* aRowFrame,
PRInt32 aRowIndex,
nscoord aRowHeight,
nscoord aMaxCellHeight,
PRBool& aHasRowSpanningCell)
{
// initialize out parameter
aHasRowSpanningCell = PR_FALSE;
// set the row's height
nsSize rowFrameSize;
aRowFrame->GetSize(rowFrameSize);
aRowFrame->SizeTo(rowFrameSize.width, aRowHeight);
// resize all the cells based on the max cell height
// XXX It would be better to just inform the row of the new size and have
// it resize and re-align its cells...
nsTableCellFrame *cellFrame;
aRowFrame->FirstChild((nsIFrame*&)cellFrame);
while (nsnull != cellFrame)
{
PRInt32 rowSpan = ((nsTableFrame*)mGeometricParent)->GetEffectiveRowSpan(aRowIndex,
cellFrame);
if (1==rowSpan)
{
// resize the cell's height
nsSize cellFrameSize;
cellFrame->GetSize(cellFrameSize);
cellFrame->SizeTo(cellFrameSize.width, aMaxCellHeight);
// realign cell content based on the new height
cellFrame->VerticallyAlignChild(aPresContext);
}
else
{
aHasRowSpanningCell = PR_TRUE;
}
// Get the next cell
cellFrame->GetNextSibling((nsIFrame*&)cellFrame);
}
}
/**
*/
void nsTableRowGroupFrame::ShrinkWrapChildren(nsIPresContext* aPresContext,
nsReflowMetrics& aDesiredSize,
nsSize* aMaxElementSize)
{
// iterate children, tell all rows to shrink wrap
PRBool atLeastOneRowSpanningCell = PR_FALSE;
PRInt32 rowGroupHeight = 0;
nscoord topInnerMargin = 0;
nscoord bottomInnerMargin = 0;
PRInt32 numRows;
ChildCount(numRows);
PRInt32 *rowHeights = new PRInt32[numRows];
nsCRT::memset (rowHeights, 0, numRows*sizeof(PRInt32));
/* Step 1: set the row height to the height of the tallest cell,
* and resize all cells in that row to that height (except cells with rowspan>1)
*/
nsTableRowFrame* rowFrame = (nsTableRowFrame*)mFirstChild;
PRInt32 rowIndex = 0;
while (nsnull != rowFrame)
{
// get the height of the tallest cell in the row (excluding cells that span rows)
nscoord maxCellHeight = rowFrame->GetTallestChild();
nscoord maxCellTopMargin = rowFrame->GetChildMaxTopMargin();
nscoord maxCellBottomMargin = rowFrame->GetChildMaxBottomMargin();
nscoord maxRowHeight = maxCellHeight + maxCellTopMargin + maxCellBottomMargin;
// save the row height for pass 2 below
rowHeights[rowIndex] = maxRowHeight;
// resize the row
PRBool hasRowSpanningCell;
SetRowHeight(aPresContext, rowFrame, rowIndex, maxRowHeight, maxCellHeight,
hasRowSpanningCell);
if (hasRowSpanningCell) {
atLeastOneRowSpanningCell = PR_TRUE;
}
// Update the running row group height
rowGroupHeight += maxRowHeight;
// Update top and bottom inner margin if applicable
if (0 == rowIndex) {
topInnerMargin = maxCellTopMargin;
}
if ((rowIndex + 1) == numRows) {
bottomInnerMargin = maxCellBottomMargin;
}
// Get the next row
rowFrame->GetNextSibling((nsIFrame*&)rowFrame);
rowIndex++;
}
/* 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.
*/
/* TODO
* 1. optimization, if (PR_TRUE==atLeastOneRowSpanningCell) ... otherwise skip this step entirely
* 2. find cases where spanning cells effect other spanning cells that began in rows above themselves.
* I think in this case, we have to make another pass through step 2.
* There should be a "rational" check to terminate that kind of loop after n passes, probably 3 or 4.
*/
rowGroupHeight = 0;
rowFrame = (nsTableRowFrame*)mFirstChild;
rowIndex = 0;
while (nsnull != rowFrame)
{
// check this row for a cell with rowspans
nsTableCellFrame* cellFrame;
rowFrame->FirstChild((nsIFrame*&)cellFrame);
while (nsnull != cellFrame)
{
PRInt32 rowSpan = ((nsTableFrame*)mGeometricParent)->GetEffectiveRowSpan(rowIndex,
cellFrame);
if (rowSpan > 1)
{ // found a cell with rowspan > 1, determine it's height
nscoord heightOfRowsSpanned = 0;
for (PRInt32 i = 0; i < rowSpan; i++)
heightOfRowsSpanned += rowHeights[rowIndex + i];
heightOfRowsSpanned -= topInnerMargin + bottomInnerMargin;
/* if the cell height fits in the rows, expand the spanning cell's height and slap it in */
nsSize cellFrameSize;
cellFrame->GetSize(cellFrameSize);
if (heightOfRowsSpanned > cellFrameSize.height)
{
cellFrame->SizeTo(cellFrameSize.width, heightOfRowsSpanned);
// Realign cell content based on new height
cellFrame->VerticallyAlignChild(aPresContext);
}
/* otherwise, distribute the excess height to the rows effected, and to the cells in those rows
* push all subsequent rows down by the total change in height of all the rows above it
*/
else
{
PRInt32 excessHeight = cellFrameSize.height - heightOfRowsSpanned;
PRInt32 excessHeightPerRow = excessHeight/rowSpan;
// for every row starting at the row with the spanning cell...
nsTableRowFrame *rowFrameToBeResized = rowFrame;
for (i = rowIndex; i < numRows; i++)
{
// if the row is within the spanned range, resize the row and it's cells
// XXX Why do this now? Let's wait until we're done and we know the
// final height of each row. Then resize the row and its cells and
// re-align the cells...
if (i < (rowIndex + rowSpan))
{
// update the row height
rowHeights[i] += excessHeightPerRow;
// adjust the height of the row
nsSize rowFrameSize;
rowFrameToBeResized->GetSize(rowFrameSize);
rowFrameToBeResized->SizeTo(rowFrameSize.width, rowHeights[i]);
// adjust the height of each of the cells, and re-align the cell
nsTableCellFrame *cellFrame;
rowFrameToBeResized->FirstChild((nsIFrame*&)cellFrame);
while (nsnull != cellFrame)
{
PRInt32 frameRowSpan = ((nsTableFrame*)mGeometricParent)->GetEffectiveRowSpan(i,
cellFrame);
if (1 == frameRowSpan)
{
// Resize the cell's height
nsSize cellFrameSize;
cellFrame->GetSize(cellFrameSize);
cellFrame->SizeTo(cellFrameSize.width, cellFrameSize.height +
excessHeightPerRow);
// Realign cell content based on new height
cellFrame->VerticallyAlignChild(aPresContext);
}
// Get the next cell
cellFrame->GetNextSibling((nsIFrame*&)cellFrame);
}
}
// if we're dealing with a row below the row containing the spanning cell,
// push that row down by the amount we've expanded the cell heights by
if ((i >= rowIndex) && (i != 0))
{
nsRect rowRect;
rowFrameToBeResized->GetRect(rowRect);
nscoord delta = excessHeightPerRow * (i - rowIndex);
if (delta > excessHeight)
delta = excessHeight;
rowFrameToBeResized->MoveTo(rowRect.x, rowRect.y + delta);
}
// Get the next row frame
rowFrameToBeResized->GetNextSibling((nsIFrame*&)rowFrameToBeResized);
}
}
}
// Get the next cell frame
cellFrame->GetNextSibling((nsIFrame*&)cellFrame);
}
// Update the running row group height
rowGroupHeight += rowHeights[rowIndex];
// Get the next row
rowFrame->GetNextSibling((nsIFrame*&)rowFrame);
rowIndex++;
}
// Adjust our desired size
aDesiredSize.height = rowGroupHeight;
// cleanup
delete []rowHeights;
}
/** Layout the entire row group.
* This method stacks rows vertically according to HTML 4.0 rules.
@ -927,7 +1161,10 @@ nsTableRowGroupFrame::Reflow(nsIPresContext* aPresContext,
//NS_ASSERTION(0<state.firstRowHeight, "illegal firstRowHeight after reflow");
//NS_ASSERTION(0<state.y, "illegal height after reflow");
aDesiredSize.width = aReflowState.maxSize.width;
aDesiredSize.height = state.y;
aDesiredSize.height = state.y;
// shrink wrap rows to height of tallest cell in that row
ShrinkWrapChildren(aPresContext, aDesiredSize, aDesiredSize.maxElementSize);
}
#ifdef NS_DEBUG

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

@ -119,6 +119,17 @@ protected:
nsSize* aMaxElementSize,
nsSize& aKidMaxElementSize);
void ShrinkWrapChildren(nsIPresContext* aPresContext,
nsReflowMetrics& aDesiredSize,
nsSize* aMaxElementSize);
void SetRowHeight(nsIPresContext* aPresContext,
nsIFrame* aRowFrame,
PRInt32 aRowIndex,
nscoord aRowHeight,
nscoord aMaxCellHeight,
PRBool& aHasRowSpanningCell);
/**
* Reflow the frames we've already created
*

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

@ -1054,7 +1054,6 @@ PRBool nsTableFrame::NeedsReflow(const nsSize& aMaxSize)
if pass is 1,
set pass to 2
use column widths to ResizeReflow cells
shrinkWrap Cells in each row to tallest, realigning contents within the cell
*/
/* Layout the entire inner table. */
@ -1409,12 +1408,8 @@ nsReflowStatus nsTableFrame::ResizeReflowPass2(nsIPresContext* aPresContext,
}
// Return our desired rect
//NS_ASSERTION(0<state.y, "illegal height after reflow");
aDesiredSize.width = aReflowState.maxSize.width;
aDesiredSize.height = state.y;
// shrink wrap rows to height of tallest cell in that row
ShrinkWrapChildren(aPresContext, aDesiredSize, aDesiredSize.maxElementSize);
aDesiredSize.height = state.y + myBorderPadding.top + myBorderPadding.bottom;
if (gsDebugNT==PR_TRUE)
{
@ -2246,259 +2241,6 @@ void nsTableFrame::SetTableWidth(nsIPresContext* aPresContext)
SetRect(tableSize);
}
/**
*/
void nsTableFrame::ShrinkWrapChildren(nsIPresContext* aPresContext,
nsReflowMetrics& aDesiredSize,
nsSize* aMaxElementSize)
{
#ifdef NS_DEBUG
PRBool gsDebugWas = gsDebug;
//gsDebug = PR_TRUE; // turn on debug in this method
#endif
// iterate children, tell all row groups to ShrinkWrap
PRBool atLeastOneRowSpanningCell = PR_FALSE;
PRInt32 rowIndex;
PRInt32 tableHeight = 0;
const nsStyleSpacing* spacing = (const nsStyleSpacing*)
mStyleContext->GetStyleData(eStyleStruct_Spacing);
nsMargin borderPadding;
spacing->CalcBorderPaddingFor(this, borderPadding);
tableHeight += borderPadding.top + borderPadding.bottom;
PRInt32 childCount = mChildCount;
nsIFrame * kidFrame;
for (PRInt32 i = 0; i < childCount; i++)
{
PRInt32 childHeight=0;
// for every child that is a rowFrame, set the row frame height = sum of row heights
if (0==i)
ChildAt(i, kidFrame); // frames are not ref counted
else
kidFrame->GetNextSibling(kidFrame);
NS_ASSERTION(nsnull != kidFrame, "bad kid frame");
nscoord topInnerMargin = 0;
nscoord bottomInnerMargin = 0;
const nsStyleDisplay *childDisplay;
kidFrame->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay));
if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == childDisplay->mDisplay ||
NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == childDisplay->mDisplay ||
NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == childDisplay->mDisplay )
{
/* Step 1: set the row height to the height of the tallest cell,
* and resize all cells in that row to that height (except cells with rowspan>1)
*/
PRInt32 rowGroupHeight = 0;
nsTableRowGroupFrame * rowGroupFrame = (nsTableRowGroupFrame *)kidFrame;
PRInt32 numRows;
rowGroupFrame->ChildCount(numRows);
PRInt32 *rowHeights = new PRInt32[numRows];
nsCRT::memset (rowHeights, 0, numRows*sizeof(PRInt32));
if (gsDebug==PR_TRUE) printf("Height Step 1...\n");
for (rowIndex = 0; rowIndex < numRows; rowIndex++)
{
// get the height of the tallest cell in the row (excluding cells that span rows)
nsTableRowFrame *rowFrame;
rowGroupFrame->ChildAt(rowIndex, (nsIFrame*&)rowFrame);
NS_ASSERTION(nsnull != rowFrame, "bad row frame");
nscoord maxCellHeight = rowFrame->GetTallestChild();
nscoord maxCellTopMargin = rowFrame->GetChildMaxTopMargin();
nscoord maxCellBottomMargin = rowFrame->GetChildMaxBottomMargin();
nscoord maxRowHeight = maxCellHeight + maxCellTopMargin + maxCellBottomMargin;
rowHeights[rowIndex] = maxRowHeight;
if (rowIndex == 0)
topInnerMargin = maxCellTopMargin;
if (rowIndex+1 == numRows)
bottomInnerMargin = maxCellBottomMargin;
nsSize rowFrameSize(0,0);
rowFrame->GetSize(rowFrameSize);
rowFrame->SizeTo(rowFrameSize.width, maxRowHeight);
rowGroupHeight += maxRowHeight;
// resize all the cells based on the rowHeight
PRInt32 numCells;
rowFrame->ChildCount(numCells);
for (PRInt32 cellIndex = 0; cellIndex < numCells; cellIndex++)
{
nsTableCellFrame *cellFrame;
rowFrame->ChildAt(cellIndex, (nsIFrame*&)cellFrame);
PRInt32 rowSpan = GetEffectiveRowSpan(rowIndex, cellFrame);//cellFrame->GetRowSpan();
if (1==rowSpan)
{
if (gsDebug==PR_TRUE) printf(" setting cell[%d,%d] height to %d\n", rowIndex, cellIndex, rowHeights[rowIndex]);
nsSize cellFrameSize(0,0);
cellFrame->GetSize(cellFrameSize);
cellFrame->SizeTo(cellFrameSize.width, maxCellHeight);
// Realign cell content based on new height
cellFrame->VerticallyAlignChild(aPresContext);
}
else
{
if (gsDebug==PR_TRUE) printf(" skipping cell[%d,%d]\n", rowIndex, cellIndex);
atLeastOneRowSpanningCell = 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.
*/
/* TODO
* 1. optimization, if (PR_TRUE==atLeastOneRowSpanningCell) ... otherwise skip this step entirely
* 2. find cases where spanning cells effect other spanning cells that began in rows above themselves.
* I think in this case, we have to make another pass through step 2.
* There should be a "rational" check to terminate that kind of loop after n passes, probably 3 or 4.
*/
if (gsDebug==PR_TRUE) printf("Height Step 2...\n");
rowGroupHeight=0;
nsTableRowFrame *rowFrame=nsnull;
for (rowIndex = 0; rowIndex < numRows; rowIndex++)
{
// get the next row
if (0==rowIndex)
rowGroupFrame->ChildAt(rowIndex, (nsIFrame*&)rowFrame);
else
rowFrame->GetNextSibling((nsIFrame*&)rowFrame);
PRInt32 numCells;
rowFrame->ChildCount(numCells);
// check this row for a cell with rowspans
for (PRInt32 cellIndex = 0; cellIndex < numCells; cellIndex++)
{
// get the next cell
nsTableCellFrame *cellFrame;
rowFrame->ChildAt(cellIndex, (nsIFrame*&)cellFrame);
PRInt32 rowSpan = GetEffectiveRowSpan(rowIndex, cellFrame);//cellFrame->GetRowSpan();
if (1<rowSpan)
{ // found a cell with rowspan > 1, determine it's height
if (gsDebug==PR_TRUE) printf(" cell[%d,%d] has a rowspan = %d\n", rowIndex, cellIndex, rowSpan);
nscoord heightOfRowsSpanned = 0;
for (PRInt32 i=0; i<rowSpan; i++)
heightOfRowsSpanned += rowHeights[i+rowIndex];
heightOfRowsSpanned -= topInnerMargin + bottomInnerMargin;
/* if the cell height fits in the rows, expand the spanning cell's height and slap it in */
nsSize cellFrameSize(0,0);
cellFrame->GetSize(cellFrameSize);
if (heightOfRowsSpanned>cellFrameSize.height)
{
if (gsDebug==PR_TRUE) printf(" cell[%d,%d] fits, setting height to %d\n", rowIndex, cellIndex, heightOfRowsSpanned);
cellFrame->SizeTo(cellFrameSize.width, heightOfRowsSpanned);
// Realign cell content based on new height
cellFrame->VerticallyAlignChild(aPresContext);
}
/* otherwise, distribute the excess height to the rows effected, and to the cells in those rows
* push all subsequent rows down by the total change in height of all the rows above it
*/
else
{
PRInt32 excessHeight = cellFrameSize.height - heightOfRowsSpanned;
PRInt32 excessHeightPerRow = excessHeight/rowSpan;
if (gsDebug==PR_TRUE) printf(" cell[%d,%d] does not fit, excessHeight = %d, excessHeightPerRow = %d\n",
rowIndex, cellIndex, excessHeight, excessHeightPerRow);
// for every row starting at the row with the spanning cell...
for (i=rowIndex; i<numRows; i++)
{
nsTableRowFrame *rowFrameToBeResized;
rowGroupFrame->ChildAt(i, (nsIFrame*&)rowFrameToBeResized);
// if the row is within the spanned range, resize the row and it's cells
if (i<rowIndex+rowSpan)
{
rowHeights[i] += excessHeightPerRow;
if (gsDebug==PR_TRUE) printf(" rowHeight[%d] set to %d\n", i, rowHeights[i]);
nsSize rowFrameSize(0,0);
rowFrameToBeResized->GetSize(rowFrameSize);
rowFrameToBeResized->SizeTo(rowFrameSize.width, rowHeights[i]);
PRInt32 cellCount;
rowFrameToBeResized->ChildCount(cellCount);
for (PRInt32 j=0; j<cellCount; j++)
{
if (i==rowIndex && j==cellIndex)
{
if (gsDebug==PR_TRUE) printf(" cell[%d, %d] skipping self\n", i, j);
continue; // don't do math on myself, only the other cells I effect
}
nsTableCellFrame *frame;
rowFrameToBeResized->ChildAt(j, (nsIFrame*&)frame);
PRInt32 frameRowSpan = GetEffectiveRowSpan(i, frame);
if (frameRowSpan==1)
{
nsSize frameSize(0,0);
frame->GetSize(frameSize);
if (gsDebug==PR_TRUE) printf(" cell[%d, %d] set height to %d\n", i, j, frameSize.height+excessHeightPerRow);
frame->SizeTo(frameSize.width, frameSize.height+excessHeightPerRow);
// Realign cell content based on new height
frame->VerticallyAlignChild(aPresContext);
}
}
}
// if we're dealing with a row below the row containing the spanning cell,
// push that row down by the amount we've expanded the cell heights by
if (i>=rowIndex && i!=0)
{
nsRect rowRect;
rowFrameToBeResized->GetRect(rowRect);
nscoord delta = excessHeightPerRow*(i-rowIndex);
if (delta > excessHeight)
delta = excessHeight;
rowFrameToBeResized->MoveTo(rowRect.x, rowRect.y + delta);
if (gsDebug==PR_TRUE) printf(" row %d (%p) moved by %d to y-offset %d\n",
i, rowFrameToBeResized, delta, rowRect.y + delta);
}
}
}
}
}
rowGroupHeight += rowHeights[rowIndex];
}
if (gsDebug==PR_TRUE) printf("row group height set to %d\n", rowGroupHeight);
nsSize rowGroupFrameSize(0,0);
rowGroupFrame->GetSize(rowGroupFrameSize);
rowGroupFrame->SizeTo(rowGroupFrameSize.width, rowGroupHeight);
tableHeight += rowGroupHeight;
if (nsnull!=rowHeights)
delete [] rowHeights;
}
}
if (0!=tableHeight)
{
if (gsDebug==PR_TRUE) printf("table desired height set to %d\n", tableHeight);
aDesiredSize.height = tableHeight;
}
#ifdef NS_DEBUG
gsDebug = gsDebugWas;
#endif
}
void nsTableFrame::VerticallyAlignChildren(nsIPresContext* aPresContext,
nscoord* aAscents,
nscoord aMaxAscent,

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

@ -96,7 +96,6 @@ public:
* set mFirstPassValid to true
* do pass 2
* use column widths to Reflow cells
* shrinkWrap Cells in each row to tallest, realigning contents within the cell
* </pre>
*
* @see ResizeReflowPass1
@ -115,21 +114,6 @@ public:
nsIStyleContext* aStyleContext,
nsIFrame*& aContinuingFrame);
/** resize myself and my children according to the arcane rules of cell height magic.
* By default, the height of a cell is the max (height of cells in its row)
* In the case of a cell with rowspan>1 (lets call this C),
* if the sum of the height of the rows spanned (excluding C in the calculation)
* is greater than or equal to the height of C,
* the cells in the rows are sized normally and
* the height of C is set to the sum of the heights (taking into account borders, padding, and margins)
* else
* the height of each row is expanded by a percentage of the difference between
* the row's desired height and the height of C
*/
virtual void ShrinkWrapChildren(nsIPresContext* aPresContext,
nsReflowMetrics& aDesiredSize,
nsSize* aMaxElementSize);
/** allow the cell and row attributes to effect the column frame
* currently, the only reason this exists is to support the HTML "rule"
* that a width attribute on a cell in the first column sets the column width.

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

@ -827,6 +827,240 @@ nsTableRowGroupFrame::ReflowUnmappedChildren(nsIPresContext* aPresContext,
return result;
}
/**
* Called by ShrinkWrapChildren() to set the height of a table row. Resizes
* the table row, each of the row's table cells, and then realigns the cell
* content based on the new height
*/
void nsTableRowGroupFrame::SetRowHeight(nsIPresContext* aPresContext,
nsIFrame* aRowFrame,
PRInt32 aRowIndex,
nscoord aRowHeight,
nscoord aMaxCellHeight,
PRBool& aHasRowSpanningCell)
{
// initialize out parameter
aHasRowSpanningCell = PR_FALSE;
// set the row's height
nsSize rowFrameSize;
aRowFrame->GetSize(rowFrameSize);
aRowFrame->SizeTo(rowFrameSize.width, aRowHeight);
// resize all the cells based on the max cell height
// XXX It would be better to just inform the row of the new size and have
// it resize and re-align its cells...
nsTableCellFrame *cellFrame;
aRowFrame->FirstChild((nsIFrame*&)cellFrame);
while (nsnull != cellFrame)
{
PRInt32 rowSpan = ((nsTableFrame*)mGeometricParent)->GetEffectiveRowSpan(aRowIndex,
cellFrame);
if (1==rowSpan)
{
// resize the cell's height
nsSize cellFrameSize;
cellFrame->GetSize(cellFrameSize);
cellFrame->SizeTo(cellFrameSize.width, aMaxCellHeight);
// realign cell content based on the new height
cellFrame->VerticallyAlignChild(aPresContext);
}
else
{
aHasRowSpanningCell = PR_TRUE;
}
// Get the next cell
cellFrame->GetNextSibling((nsIFrame*&)cellFrame);
}
}
/**
*/
void nsTableRowGroupFrame::ShrinkWrapChildren(nsIPresContext* aPresContext,
nsReflowMetrics& aDesiredSize,
nsSize* aMaxElementSize)
{
// iterate children, tell all rows to shrink wrap
PRBool atLeastOneRowSpanningCell = PR_FALSE;
PRInt32 rowGroupHeight = 0;
nscoord topInnerMargin = 0;
nscoord bottomInnerMargin = 0;
PRInt32 numRows;
ChildCount(numRows);
PRInt32 *rowHeights = new PRInt32[numRows];
nsCRT::memset (rowHeights, 0, numRows*sizeof(PRInt32));
/* Step 1: set the row height to the height of the tallest cell,
* and resize all cells in that row to that height (except cells with rowspan>1)
*/
nsTableRowFrame* rowFrame = (nsTableRowFrame*)mFirstChild;
PRInt32 rowIndex = 0;
while (nsnull != rowFrame)
{
// get the height of the tallest cell in the row (excluding cells that span rows)
nscoord maxCellHeight = rowFrame->GetTallestChild();
nscoord maxCellTopMargin = rowFrame->GetChildMaxTopMargin();
nscoord maxCellBottomMargin = rowFrame->GetChildMaxBottomMargin();
nscoord maxRowHeight = maxCellHeight + maxCellTopMargin + maxCellBottomMargin;
// save the row height for pass 2 below
rowHeights[rowIndex] = maxRowHeight;
// resize the row
PRBool hasRowSpanningCell;
SetRowHeight(aPresContext, rowFrame, rowIndex, maxRowHeight, maxCellHeight,
hasRowSpanningCell);
if (hasRowSpanningCell) {
atLeastOneRowSpanningCell = PR_TRUE;
}
// Update the running row group height
rowGroupHeight += maxRowHeight;
// Update top and bottom inner margin if applicable
if (0 == rowIndex) {
topInnerMargin = maxCellTopMargin;
}
if ((rowIndex + 1) == numRows) {
bottomInnerMargin = maxCellBottomMargin;
}
// Get the next row
rowFrame->GetNextSibling((nsIFrame*&)rowFrame);
rowIndex++;
}
/* 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.
*/
/* TODO
* 1. optimization, if (PR_TRUE==atLeastOneRowSpanningCell) ... otherwise skip this step entirely
* 2. find cases where spanning cells effect other spanning cells that began in rows above themselves.
* I think in this case, we have to make another pass through step 2.
* There should be a "rational" check to terminate that kind of loop after n passes, probably 3 or 4.
*/
rowGroupHeight = 0;
rowFrame = (nsTableRowFrame*)mFirstChild;
rowIndex = 0;
while (nsnull != rowFrame)
{
// check this row for a cell with rowspans
nsTableCellFrame* cellFrame;
rowFrame->FirstChild((nsIFrame*&)cellFrame);
while (nsnull != cellFrame)
{
PRInt32 rowSpan = ((nsTableFrame*)mGeometricParent)->GetEffectiveRowSpan(rowIndex,
cellFrame);
if (rowSpan > 1)
{ // found a cell with rowspan > 1, determine it's height
nscoord heightOfRowsSpanned = 0;
for (PRInt32 i = 0; i < rowSpan; i++)
heightOfRowsSpanned += rowHeights[rowIndex + i];
heightOfRowsSpanned -= topInnerMargin + bottomInnerMargin;
/* if the cell height fits in the rows, expand the spanning cell's height and slap it in */
nsSize cellFrameSize;
cellFrame->GetSize(cellFrameSize);
if (heightOfRowsSpanned > cellFrameSize.height)
{
cellFrame->SizeTo(cellFrameSize.width, heightOfRowsSpanned);
// Realign cell content based on new height
cellFrame->VerticallyAlignChild(aPresContext);
}
/* otherwise, distribute the excess height to the rows effected, and to the cells in those rows
* push all subsequent rows down by the total change in height of all the rows above it
*/
else
{
PRInt32 excessHeight = cellFrameSize.height - heightOfRowsSpanned;
PRInt32 excessHeightPerRow = excessHeight/rowSpan;
// for every row starting at the row with the spanning cell...
nsTableRowFrame *rowFrameToBeResized = rowFrame;
for (i = rowIndex; i < numRows; i++)
{
// if the row is within the spanned range, resize the row and it's cells
// XXX Why do this now? Let's wait until we're done and we know the
// final height of each row. Then resize the row and its cells and
// re-align the cells...
if (i < (rowIndex + rowSpan))
{
// update the row height
rowHeights[i] += excessHeightPerRow;
// adjust the height of the row
nsSize rowFrameSize;
rowFrameToBeResized->GetSize(rowFrameSize);
rowFrameToBeResized->SizeTo(rowFrameSize.width, rowHeights[i]);
// adjust the height of each of the cells, and re-align the cell
nsTableCellFrame *cellFrame;
rowFrameToBeResized->FirstChild((nsIFrame*&)cellFrame);
while (nsnull != cellFrame)
{
PRInt32 frameRowSpan = ((nsTableFrame*)mGeometricParent)->GetEffectiveRowSpan(i,
cellFrame);
if (1 == frameRowSpan)
{
// Resize the cell's height
nsSize cellFrameSize;
cellFrame->GetSize(cellFrameSize);
cellFrame->SizeTo(cellFrameSize.width, cellFrameSize.height +
excessHeightPerRow);
// Realign cell content based on new height
cellFrame->VerticallyAlignChild(aPresContext);
}
// Get the next cell
cellFrame->GetNextSibling((nsIFrame*&)cellFrame);
}
}
// if we're dealing with a row below the row containing the spanning cell,
// push that row down by the amount we've expanded the cell heights by
if ((i >= rowIndex) && (i != 0))
{
nsRect rowRect;
rowFrameToBeResized->GetRect(rowRect);
nscoord delta = excessHeightPerRow * (i - rowIndex);
if (delta > excessHeight)
delta = excessHeight;
rowFrameToBeResized->MoveTo(rowRect.x, rowRect.y + delta);
}
// Get the next row frame
rowFrameToBeResized->GetNextSibling((nsIFrame*&)rowFrameToBeResized);
}
}
}
// Get the next cell frame
cellFrame->GetNextSibling((nsIFrame*&)cellFrame);
}
// Update the running row group height
rowGroupHeight += rowHeights[rowIndex];
// Get the next row
rowFrame->GetNextSibling((nsIFrame*&)rowFrame);
rowIndex++;
}
// Adjust our desired size
aDesiredSize.height = rowGroupHeight;
// cleanup
delete []rowHeights;
}
/** Layout the entire row group.
* This method stacks rows vertically according to HTML 4.0 rules.
@ -927,7 +1161,10 @@ nsTableRowGroupFrame::Reflow(nsIPresContext* aPresContext,
//NS_ASSERTION(0<state.firstRowHeight, "illegal firstRowHeight after reflow");
//NS_ASSERTION(0<state.y, "illegal height after reflow");
aDesiredSize.width = aReflowState.maxSize.width;
aDesiredSize.height = state.y;
aDesiredSize.height = state.y;
// shrink wrap rows to height of tallest cell in that row
ShrinkWrapChildren(aPresContext, aDesiredSize, aDesiredSize.maxElementSize);
}
#ifdef NS_DEBUG

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

@ -119,6 +119,17 @@ protected:
nsSize* aMaxElementSize,
nsSize& aKidMaxElementSize);
void ShrinkWrapChildren(nsIPresContext* aPresContext,
nsReflowMetrics& aDesiredSize,
nsSize* aMaxElementSize);
void SetRowHeight(nsIPresContext* aPresContext,
nsIFrame* aRowFrame,
PRInt32 aRowIndex,
nscoord aRowHeight,
nscoord aMaxCellHeight,
PRBool& aHasRowSpanningCell);
/**
* Reflow the frames we've already created
*