зеркало из https://github.com/mozilla/gecko-dev.git
Moved shrink wrap code from table frame to table row group frame
This commit is contained in:
Родитель
5dddac8d3a
Коммит
add97af1d2
|
@ -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
|
||||
*
|
||||
|
|
Загрузка…
Ссылка в новой задаче