diff --git a/mozilla/layout/html/table/src/nsTableRowFrame.cpp b/mozilla/layout/html/table/src/nsTableRowFrame.cpp index c2be22a45ce..a2fd24ab6a5 100644 --- a/mozilla/layout/html/table/src/nsTableRowFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableRowFrame.cpp @@ -239,8 +239,8 @@ nsTableRowFrame::DidResize(nsIPresContext* aPresContext, const nsHTMLReflowState& aReflowState) { // Resize and re-align the cell frames based on our row height - nscoord cellMaxTopMargin = GetChildMaxTopMargin(); - nscoord cellMaxBottomMargin = GetChildMaxBottomMargin(); + nscoord cellMaxTopMargin = GetTopMargin(); + nscoord cellMaxBottomMargin = GetBottomMargin(); nscoord rowCellHeight = mRect.height - cellMaxTopMargin - cellMaxBottomMargin; nsTableFrame* tableFrame; nsTableFrame::GetTableFrame(this, tableFrame); @@ -455,7 +455,7 @@ nscoord nsTableRowFrame::GetTallestChild() const return mTallestCell; } -nscoord nsTableRowFrame::GetChildMaxTopMargin() const +nscoord nsTableRowFrame::GetTopMargin() const { nsTableFrame *tableFrame; nsTableFrame::GetTableFrame((nsIFrame*)this, tableFrame); @@ -464,7 +464,7 @@ nscoord nsTableRowFrame::GetChildMaxTopMargin() const return (GetRowIndex() == 0) ? tableFrame->GetCellSpacingY() : 0; } -nscoord nsTableRowFrame::GetChildMaxBottomMargin() const +nscoord nsTableRowFrame::GetBottomMargin() const { nsTableFrame *tableFrame; nsTableFrame::GetTableFrame((nsIFrame*)this, tableFrame); @@ -594,11 +594,10 @@ void nsTableRowFrame::PlaceChild(nsIPresContext* aPresContext, // needed for backwards compatibility. // Modifies the desired width and height that are passed in. nsresult -nsTableRowFrame::CalculateCellActualSize(RowReflowState& aReflowState, - nsIFrame* aCellFrame, - nscoord& aDesiredWidth, - nscoord& aDesiredHeight, - nscoord aAvailWidth) +nsTableRowFrame::CalculateCellActualSize(nsIFrame* aCellFrame, + nscoord& aDesiredWidth, + nscoord& aDesiredHeight, + nscoord aAvailWidth) { nscoord specifiedHeight = 0; const nsStylePosition* position; @@ -820,7 +819,7 @@ NS_METHOD nsTableRowFrame::ResizeReflow(nsIPresContext* aPresContext, reason); nsReflowStatus status; rv = ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState, - aReflowState.x, GetChildMaxTopMargin(), 0, status); + aReflowState.x, GetTopMargin(), 0, status); #ifdef NS_DEBUG if (desiredSize.width > availWidth) { @@ -865,12 +864,12 @@ NS_METHOD nsTableRowFrame::ResizeReflow(nsIPresContext* aPresContext, // Calculate the cell's actual size given its pass2 size. This function // takes into account the specified height (in the style), and any special // logic needed for backwards compatibility - CalculateCellActualSize(aReflowState, kidFrame, desiredSize.width, + CalculateCellActualSize(kidFrame, desiredSize.width, desiredSize.height, availWidth); // Place the child PlaceChild(aPresContext, aReflowState, kidFrame, desiredSize, - aReflowState.x, GetChildMaxTopMargin(), + aReflowState.x, GetTopMargin(), aDesiredSize.maxElementSize, kidMaxElementSize); } @@ -1066,8 +1065,7 @@ NS_METHOD nsTableRowFrame::RecoverState(nsIPresContext* aPresContext, // See if it has a specified height that overrides the desired size. // Note: we don't care about the width so don't compute the column // width and just pass in the desired width for the available width - CalculateCellActualSize(aReflowState, frame, desiredSize.width, desiredSize.height, - desiredSize.width); + CalculateCellActualSize(frame, desiredSize.width, desiredSize.height, desiredSize.width); // Update maxCellHeight if (desiredSize.height > aReflowState.maxCellHeight) { @@ -1239,7 +1237,7 @@ NS_METHOD nsTableRowFrame::IR_TargetIsChild(nsIPresContext* aPresContext, // in a max width of NS_UNCONSTRAINEDSIZE, because the max width must match // the width of the previous reflow... rv = ReflowChild(aNextFrame, aPresContext, desiredSize, kidReflowState, - aReflowState.x, GetChildMaxTopMargin(), 0, aStatus); + aReflowState.x, GetTopMargin(), 0, aStatus); // Update the cell layout data.. If the cell's maximum width changed, // then inform the table that its maximum width needs to be recomputed @@ -1276,12 +1274,11 @@ NS_METHOD nsTableRowFrame::IR_TargetIsChild(nsIPresContext* aPresContext, // Calculate the cell's actual size given its pass2 size. This function // takes into account the specified height (in the style), and any special // logic needed for backwards compatibility - CalculateCellActualSize(aReflowState, aNextFrame, desiredSize.width, desiredSize.height, - cellAvailWidth); + CalculateCellActualSize(aNextFrame, desiredSize.width, desiredSize.height, cellAvailWidth); // Now place the child PlaceChild(aPresContext, aReflowState, aNextFrame, desiredSize, aReflowState.x, - GetChildMaxTopMargin(), aDesiredSize.maxElementSize, &kidMaxElementSize); + GetTopMargin(), aDesiredSize.maxElementSize, &kidMaxElementSize); SetMaxChildHeight(aReflowState.maxCellHeight); diff --git a/mozilla/layout/html/table/src/nsTableRowFrame.h b/mozilla/layout/html/table/src/nsTableRowFrame.h index 051c022fdba..d6812301f45 100644 --- a/mozilla/layout/html/table/src/nsTableRowFrame.h +++ b/mozilla/layout/html/table/src/nsTableRowFrame.h @@ -163,8 +163,8 @@ public: /** returns the tallest child in this row (ignoring any cell with rowspans) */ nscoord GetTallestChild() const; - nscoord GetChildMaxTopMargin() const; - nscoord GetChildMaxBottomMargin() const; + nscoord GetTopMargin() const; + nscoord GetBottomMargin() const; /** returns the ordinal position of this row in its table */ virtual PRInt32 GetRowIndex() const; @@ -184,6 +184,11 @@ public: nsReflowStatus& aStatus); void InsertCellFrame(nsTableCellFrame* aFrame, nsTableCellFrame* aPrevSibling); + nsresult CalculateCellActualSize(nsIFrame* aRowFrame, + nscoord& aDesiredWidth, + nscoord& aDesiredHeight, + nscoord aAvailWidth); + protected: /** protected constructor. @@ -273,12 +278,6 @@ protected: nsTableCellFrame * aStartFrame, PRBool aDoSiblings); - nsresult CalculateCellActualSize(RowReflowState& aReflowState, - nsIFrame* aRowFrame, - nscoord& aDesiredWidth, - nscoord& aDesiredHeight, - nscoord aAvailWidth); - nscoord CalculateCellAvailableWidth(nsTableFrame* aTableFrame, nsIFrame* aCellFrame, PRInt32 aCellColIndex, diff --git a/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp b/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp index 8360a0e946b..7ddc150876a 100644 --- a/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp @@ -551,6 +551,37 @@ void nsTableRowGroupFrame::GetNextRowSibling(nsIFrame** aRowFrame) } } +// 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) +{ + nsIFrame* cellFrame; + aRowFrame->FirstChild(aPresContext, nsnull, &cellFrame); + while (cellFrame) { + nsCOMPtr cellType; + cellFrame->GetFrameType(getter_AddRefs(cellType)); + if (nsLayoutAtoms::tableCellFrame == cellType) { + 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; + ((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); + } +} + /* 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. @@ -559,18 +590,20 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState) { - nsTableFrame *tableFrame=nsnull; + nsTableFrame* tableFrame = nsnull; nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame); - if (NS_FAILED(rv) || nsnull==tableFrame) - return; + if (NS_FAILED(rv) || nsnull==tableFrame) return; + // all table cells have the same top and bottom margins, namely cellSpacingY nscoord cellSpacingY = tableFrame->GetCellSpacingY(); - // iterate children and for each row get the height of the tallest cell. Keep - // track of whether any of the rows have a cell that spans into the row PRBool hasRowSpanningCell = PR_FALSE; PRInt32 numRows; GetRowCount(numRows, PR_FALSE); + // 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]; @@ -578,91 +611,81 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, nsCRT::memset (rowHeights, 0, numRows*sizeof(nscoord)); } // else - tree row groups need not have rows directly beneath them - /* 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 - */ + // 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 = GetFirstFrame(); PRInt32 rowIndex = 0; // For row groups that are split across pages, the first row frame won't // necessarily be index 0 PRInt32 startRowIndex = -1; - const nsStyleDisplay *childDisplay; - while (nsnull != rowFrame) - { - rowFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)childDisplay)); - if (NS_STYLE_DISPLAY_TABLE_ROW == childDisplay->mDisplay) - { + while (rowFrame) { + nsCOMPtr frameType; + rowFrame->GetFrameType(getter_AddRefs(frameType)); + if (nsLayoutAtoms::tableRowFrame == frameType) { if (startRowIndex == -1) { startRowIndex = ((nsTableRowFrame*)rowFrame)->GetRowIndex(); } - // get the height of the tallest cell in the row (excluding cells that span rows) - // XXX GetChildMaxTopMargin and GetChildMaxBottomMargin should be removed/simplified because - // according to CSS, all table cells must have the same top/bottom and left/right margins. - nscoord maxCellHeight = ((nsTableRowFrame*)rowFrame)->GetTallestChild(); - nscoord maxCellTopMargin = ((nsTableRowFrame*)rowFrame)->GetChildMaxTopMargin(); - nscoord maxCellBottomMargin = ((nsTableRowFrame*)rowFrame)->GetChildMaxBottomMargin(); - nscoord maxRowHeight = maxCellHeight + maxCellTopMargin + maxCellBottomMargin; - // only the top row has a top margin. Other rows start at the bottom of the prev row's bottom margin. - // save the row height for pass 2 below - rowHeights[rowIndex] = maxRowHeight; - + nscoord maxCellHeight = ((nsTableRowFrame*)rowFrame)->GetTallestChild(); + nscoord topMargin = ((nsTableRowFrame*)rowFrame)->GetTopMargin(); + nscoord bottomMargin = ((nsTableRowFrame*)rowFrame)->GetBottomMargin(); + nscoord maxRowHeight = maxCellHeight + topMargin + bottomMargin; + rowHeights[rowIndex] = maxRowHeight; // 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; } } + // 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++; } - // Get the next row - GetNextFrame(rowFrame, &rowFrame); + GetNextFrame(rowFrame, &rowFrame); // Get the next row } - /* Step 2: Now account for cells that span rows. We only do this if there are 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. - */ + // Step 2: Now account for cells that span rows. We only do this if there are 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. if (hasRowSpanningCell) { nscoord deltaY = 0; - for (PRInt32 counter=0; counter<2; counter++) - { + for (PRInt32 counter = 0; counter < 2; counter++) { rowFrame = GetFirstFrame(); rowIndex = 0; - while (nsnull != rowFrame) - { - rowFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)childDisplay)); - if (NS_STYLE_DISPLAY_TABLE_ROW == childDisplay->mDisplay) - { + while (rowFrame) { + nsCOMPtr rowType; + rowFrame->GetFrameType(getter_AddRefs(rowType)); + if (nsLayoutAtoms::tableRowFrame == rowType) { // check this row for a cell with rowspans - nsIFrame *cellFrame; + nsIFrame* cellFrame; rowFrame->FirstChild(aPresContext, nsnull, &cellFrame); - while (nsnull != cellFrame) - { - const nsStyleDisplay *cellChildDisplay; - cellFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)cellChildDisplay)); - if (NS_STYLE_DISPLAY_TABLE_CELL == cellChildDisplay->mDisplay) - { + while (cellFrame) { + nsCOMPtr cellType; + cellFrame->GetFrameType(getter_AddRefs(cellType)); + if (nsLayoutAtoms::tableCellFrame == cellType) { 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 + if (rowSpan > 1) { // found a cell with rowspan > 1, determine the height + // of the rows it spans nscoord heightOfRowsSpanned = 0; - PRInt32 i; - for (i = 0; i < rowSpan; i++) { - heightOfRowsSpanned += rowHeights[rowIndex + i]; + PRInt32 spanX; + for (spanX = 0; spanX < rowSpan; spanX++) { + if (rowHeights[rowIndex + spanX] > 0) { + // don't consider negative values of special rows + heightOfRowsSpanned += rowHeights[rowIndex + spanX]; + } } // reduce the height by top and bottom margins nscoord availHeightOfRowsSpanned = heightOfRowsSpanned - cellSpacingY - cellSpacingY; @@ -673,44 +696,60 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, nsSize cellFrameSize; cellFrame->GetSize(cellFrameSize); if (0 == counter) { - nsSize cellDesiredSize = ((nsTableCellFrame*)cellFrame)->GetDesiredSize(); - cellFrameSize.height = cellDesiredSize.height; + nsSize cellDesSize = ((nsTableCellFrame*)cellFrame)->GetDesiredSize(); + ((nsTableRowFrame*)rowFrame)->CalculateCellActualSize(cellFrame, cellDesSize.width, + cellDesSize.height, cellDesSize.width); + cellFrameSize.height = cellDesSize.height; } - if (availHeightOfRowsSpanned >= cellFrameSize.height) - { + if (availHeightOfRowsSpanned >= cellFrameSize.height) { // yes 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); } - else - { + 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 PRInt32 excessHeight = cellFrameSize.height - availHeightOfRowsSpanned; - // for every row starting at the row with the spanning cell and down - // to the last row spanned by the cell - nsTableRowFrame *rowFrameToBeResized = (nsTableRowFrame *)rowFrame; + nsTableRowFrame* rowFrameToBeResized = (nsTableRowFrame *)rowFrame; nscoord excessAllocated = 0; - for (i = rowIndex; i < (rowIndex + rowSpan); i++) { - // The amount of additional space each 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[i]) / ((float)heightOfRowsSpanned); + // 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. + for (PRInt32 rowX = (rowIndex + rowSpan) - 1; rowX >= rowIndex; rowX--) { + nscoord excessForRow; + // special rows get as much they can + if (rowHeights[rowX] < 0) { + nscoord excessAvail = excessHeight - excessAllocated; + if (excessAvail > 0) { + // don't let the allocation excced what it needs + excessForRow = (excessAvail > -rowHeights[rowX]) ? -rowHeights[rowX] : excessAvail; + rowHeights[rowX] = excessForRow; + } + else { + // nothing available so assign a zero allocation + excessForRow = rowHeights[rowX] = 0; + } + } + else { // 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 last row which gets - // the remainder - nscoord excessForRow = ((i + 1) == (rowIndex + rowSpan)) ? - excessHeight - excessAllocated : - NSToCoordRound(((float)(excessHeight)) * percent); + // give rows their percentage, except for the first row which gets + // the remainder + excessForRow = (rowX == rowIndex) + ? excessHeight - excessAllocated + : NSToCoordRound(((float)(excessHeight)) * percent); + // update the row height + rowHeights[rowX] += excessForRow; + } excessAllocated += excessForRow; - - // update the row height - rowHeights[i] += excessForRow; - + // Get the next row frame GetNextRowSibling((nsIFrame**)&rowFrameToBeResized); } @@ -718,8 +757,7 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, } } } - // Get the next row child (cell frame) - cellFrame->GetNextSibling(&cellFrame); + cellFrame->GetNextSibling(&cellFrame); // Get the next row child (cell frame) } // If this is pass 2 then resize the row to its final size and move the @@ -741,7 +779,7 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, if (movedFrame) { // Make sure any views are positioned properly - nsIView* view; + nsIView* view; rowFrame->GetView(aPresContext, &view); if (view) { nsContainerFrame::PositionFrameView(aPresContext, rowFrame, view); @@ -753,9 +791,7 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, rowIndex++; } - - // Get the next rowgroup child (row frame) - GetNextFrame(rowFrame, &rowFrame); + GetNextFrame(rowFrame, &rowFrame); // Get the next rowgroup child (row frame) } } } @@ -764,31 +800,26 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, nscoord rowGroupHeight = 0; rowFrame = GetFirstFrame(); rowIndex = 0; - while (nsnull != rowFrame) - { - rowFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)childDisplay)); - if (NS_STYLE_DISPLAY_TABLE_ROW == childDisplay->mDisplay) - { + while (rowFrame) { + nsCOMPtr rowType; + rowFrame->GetFrameType(getter_AddRefs(rowType)); + if (nsLayoutAtoms::tableRowFrame == rowType) { // Notify the row of the new size ((nsTableRowFrame *)rowFrame)->DidResize(aPresContext, aReflowState); } // Update the running row group height. The height includes frames that // aren't rows as well - nsSize rowSize; + nsSize rowSize; rowFrame->GetSize(rowSize); rowGroupHeight += rowSize.height; - // Get the next row - GetNextFrame(rowFrame, &rowFrame); + GetNextFrame(rowFrame, &rowFrame); // Get the next row rowIndex++; } - // Adjust our desired size - aDesiredSize.height = rowGroupHeight; - - // cleanup - delete []rowHeights; + aDesiredSize.height = rowGroupHeight; // Adjust our desired size + delete [] rowHeights; // cleanup } // Called by IR_TargetIsChild() to adjust the sibling frames that follow diff --git a/mozilla/layout/tables/nsTableRowFrame.cpp b/mozilla/layout/tables/nsTableRowFrame.cpp index c2be22a45ce..a2fd24ab6a5 100644 --- a/mozilla/layout/tables/nsTableRowFrame.cpp +++ b/mozilla/layout/tables/nsTableRowFrame.cpp @@ -239,8 +239,8 @@ nsTableRowFrame::DidResize(nsIPresContext* aPresContext, const nsHTMLReflowState& aReflowState) { // Resize and re-align the cell frames based on our row height - nscoord cellMaxTopMargin = GetChildMaxTopMargin(); - nscoord cellMaxBottomMargin = GetChildMaxBottomMargin(); + nscoord cellMaxTopMargin = GetTopMargin(); + nscoord cellMaxBottomMargin = GetBottomMargin(); nscoord rowCellHeight = mRect.height - cellMaxTopMargin - cellMaxBottomMargin; nsTableFrame* tableFrame; nsTableFrame::GetTableFrame(this, tableFrame); @@ -455,7 +455,7 @@ nscoord nsTableRowFrame::GetTallestChild() const return mTallestCell; } -nscoord nsTableRowFrame::GetChildMaxTopMargin() const +nscoord nsTableRowFrame::GetTopMargin() const { nsTableFrame *tableFrame; nsTableFrame::GetTableFrame((nsIFrame*)this, tableFrame); @@ -464,7 +464,7 @@ nscoord nsTableRowFrame::GetChildMaxTopMargin() const return (GetRowIndex() == 0) ? tableFrame->GetCellSpacingY() : 0; } -nscoord nsTableRowFrame::GetChildMaxBottomMargin() const +nscoord nsTableRowFrame::GetBottomMargin() const { nsTableFrame *tableFrame; nsTableFrame::GetTableFrame((nsIFrame*)this, tableFrame); @@ -594,11 +594,10 @@ void nsTableRowFrame::PlaceChild(nsIPresContext* aPresContext, // needed for backwards compatibility. // Modifies the desired width and height that are passed in. nsresult -nsTableRowFrame::CalculateCellActualSize(RowReflowState& aReflowState, - nsIFrame* aCellFrame, - nscoord& aDesiredWidth, - nscoord& aDesiredHeight, - nscoord aAvailWidth) +nsTableRowFrame::CalculateCellActualSize(nsIFrame* aCellFrame, + nscoord& aDesiredWidth, + nscoord& aDesiredHeight, + nscoord aAvailWidth) { nscoord specifiedHeight = 0; const nsStylePosition* position; @@ -820,7 +819,7 @@ NS_METHOD nsTableRowFrame::ResizeReflow(nsIPresContext* aPresContext, reason); nsReflowStatus status; rv = ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState, - aReflowState.x, GetChildMaxTopMargin(), 0, status); + aReflowState.x, GetTopMargin(), 0, status); #ifdef NS_DEBUG if (desiredSize.width > availWidth) { @@ -865,12 +864,12 @@ NS_METHOD nsTableRowFrame::ResizeReflow(nsIPresContext* aPresContext, // Calculate the cell's actual size given its pass2 size. This function // takes into account the specified height (in the style), and any special // logic needed for backwards compatibility - CalculateCellActualSize(aReflowState, kidFrame, desiredSize.width, + CalculateCellActualSize(kidFrame, desiredSize.width, desiredSize.height, availWidth); // Place the child PlaceChild(aPresContext, aReflowState, kidFrame, desiredSize, - aReflowState.x, GetChildMaxTopMargin(), + aReflowState.x, GetTopMargin(), aDesiredSize.maxElementSize, kidMaxElementSize); } @@ -1066,8 +1065,7 @@ NS_METHOD nsTableRowFrame::RecoverState(nsIPresContext* aPresContext, // See if it has a specified height that overrides the desired size. // Note: we don't care about the width so don't compute the column // width and just pass in the desired width for the available width - CalculateCellActualSize(aReflowState, frame, desiredSize.width, desiredSize.height, - desiredSize.width); + CalculateCellActualSize(frame, desiredSize.width, desiredSize.height, desiredSize.width); // Update maxCellHeight if (desiredSize.height > aReflowState.maxCellHeight) { @@ -1239,7 +1237,7 @@ NS_METHOD nsTableRowFrame::IR_TargetIsChild(nsIPresContext* aPresContext, // in a max width of NS_UNCONSTRAINEDSIZE, because the max width must match // the width of the previous reflow... rv = ReflowChild(aNextFrame, aPresContext, desiredSize, kidReflowState, - aReflowState.x, GetChildMaxTopMargin(), 0, aStatus); + aReflowState.x, GetTopMargin(), 0, aStatus); // Update the cell layout data.. If the cell's maximum width changed, // then inform the table that its maximum width needs to be recomputed @@ -1276,12 +1274,11 @@ NS_METHOD nsTableRowFrame::IR_TargetIsChild(nsIPresContext* aPresContext, // Calculate the cell's actual size given its pass2 size. This function // takes into account the specified height (in the style), and any special // logic needed for backwards compatibility - CalculateCellActualSize(aReflowState, aNextFrame, desiredSize.width, desiredSize.height, - cellAvailWidth); + CalculateCellActualSize(aNextFrame, desiredSize.width, desiredSize.height, cellAvailWidth); // Now place the child PlaceChild(aPresContext, aReflowState, aNextFrame, desiredSize, aReflowState.x, - GetChildMaxTopMargin(), aDesiredSize.maxElementSize, &kidMaxElementSize); + GetTopMargin(), aDesiredSize.maxElementSize, &kidMaxElementSize); SetMaxChildHeight(aReflowState.maxCellHeight); diff --git a/mozilla/layout/tables/nsTableRowFrame.h b/mozilla/layout/tables/nsTableRowFrame.h index 051c022fdba..d6812301f45 100644 --- a/mozilla/layout/tables/nsTableRowFrame.h +++ b/mozilla/layout/tables/nsTableRowFrame.h @@ -163,8 +163,8 @@ public: /** returns the tallest child in this row (ignoring any cell with rowspans) */ nscoord GetTallestChild() const; - nscoord GetChildMaxTopMargin() const; - nscoord GetChildMaxBottomMargin() const; + nscoord GetTopMargin() const; + nscoord GetBottomMargin() const; /** returns the ordinal position of this row in its table */ virtual PRInt32 GetRowIndex() const; @@ -184,6 +184,11 @@ public: nsReflowStatus& aStatus); void InsertCellFrame(nsTableCellFrame* aFrame, nsTableCellFrame* aPrevSibling); + nsresult CalculateCellActualSize(nsIFrame* aRowFrame, + nscoord& aDesiredWidth, + nscoord& aDesiredHeight, + nscoord aAvailWidth); + protected: /** protected constructor. @@ -273,12 +278,6 @@ protected: nsTableCellFrame * aStartFrame, PRBool aDoSiblings); - nsresult CalculateCellActualSize(RowReflowState& aReflowState, - nsIFrame* aRowFrame, - nscoord& aDesiredWidth, - nscoord& aDesiredHeight, - nscoord aAvailWidth); - nscoord CalculateCellAvailableWidth(nsTableFrame* aTableFrame, nsIFrame* aCellFrame, PRInt32 aCellColIndex, diff --git a/mozilla/layout/tables/nsTableRowGroupFrame.cpp b/mozilla/layout/tables/nsTableRowGroupFrame.cpp index 8360a0e946b..7ddc150876a 100644 --- a/mozilla/layout/tables/nsTableRowGroupFrame.cpp +++ b/mozilla/layout/tables/nsTableRowGroupFrame.cpp @@ -551,6 +551,37 @@ void nsTableRowGroupFrame::GetNextRowSibling(nsIFrame** aRowFrame) } } +// 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) +{ + nsIFrame* cellFrame; + aRowFrame->FirstChild(aPresContext, nsnull, &cellFrame); + while (cellFrame) { + nsCOMPtr cellType; + cellFrame->GetFrameType(getter_AddRefs(cellType)); + if (nsLayoutAtoms::tableCellFrame == cellType) { + 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; + ((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); + } +} + /* 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. @@ -559,18 +590,20 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState) { - nsTableFrame *tableFrame=nsnull; + nsTableFrame* tableFrame = nsnull; nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame); - if (NS_FAILED(rv) || nsnull==tableFrame) - return; + if (NS_FAILED(rv) || nsnull==tableFrame) return; + // all table cells have the same top and bottom margins, namely cellSpacingY nscoord cellSpacingY = tableFrame->GetCellSpacingY(); - // iterate children and for each row get the height of the tallest cell. Keep - // track of whether any of the rows have a cell that spans into the row PRBool hasRowSpanningCell = PR_FALSE; PRInt32 numRows; GetRowCount(numRows, PR_FALSE); + // 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]; @@ -578,91 +611,81 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, nsCRT::memset (rowHeights, 0, numRows*sizeof(nscoord)); } // else - tree row groups need not have rows directly beneath them - /* 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 - */ + // 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 = GetFirstFrame(); PRInt32 rowIndex = 0; // For row groups that are split across pages, the first row frame won't // necessarily be index 0 PRInt32 startRowIndex = -1; - const nsStyleDisplay *childDisplay; - while (nsnull != rowFrame) - { - rowFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)childDisplay)); - if (NS_STYLE_DISPLAY_TABLE_ROW == childDisplay->mDisplay) - { + while (rowFrame) { + nsCOMPtr frameType; + rowFrame->GetFrameType(getter_AddRefs(frameType)); + if (nsLayoutAtoms::tableRowFrame == frameType) { if (startRowIndex == -1) { startRowIndex = ((nsTableRowFrame*)rowFrame)->GetRowIndex(); } - // get the height of the tallest cell in the row (excluding cells that span rows) - // XXX GetChildMaxTopMargin and GetChildMaxBottomMargin should be removed/simplified because - // according to CSS, all table cells must have the same top/bottom and left/right margins. - nscoord maxCellHeight = ((nsTableRowFrame*)rowFrame)->GetTallestChild(); - nscoord maxCellTopMargin = ((nsTableRowFrame*)rowFrame)->GetChildMaxTopMargin(); - nscoord maxCellBottomMargin = ((nsTableRowFrame*)rowFrame)->GetChildMaxBottomMargin(); - nscoord maxRowHeight = maxCellHeight + maxCellTopMargin + maxCellBottomMargin; - // only the top row has a top margin. Other rows start at the bottom of the prev row's bottom margin. - // save the row height for pass 2 below - rowHeights[rowIndex] = maxRowHeight; - + nscoord maxCellHeight = ((nsTableRowFrame*)rowFrame)->GetTallestChild(); + nscoord topMargin = ((nsTableRowFrame*)rowFrame)->GetTopMargin(); + nscoord bottomMargin = ((nsTableRowFrame*)rowFrame)->GetBottomMargin(); + nscoord maxRowHeight = maxCellHeight + topMargin + bottomMargin; + rowHeights[rowIndex] = maxRowHeight; // 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; } } + // 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++; } - // Get the next row - GetNextFrame(rowFrame, &rowFrame); + GetNextFrame(rowFrame, &rowFrame); // Get the next row } - /* Step 2: Now account for cells that span rows. We only do this if there are 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. - */ + // Step 2: Now account for cells that span rows. We only do this if there are 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. if (hasRowSpanningCell) { nscoord deltaY = 0; - for (PRInt32 counter=0; counter<2; counter++) - { + for (PRInt32 counter = 0; counter < 2; counter++) { rowFrame = GetFirstFrame(); rowIndex = 0; - while (nsnull != rowFrame) - { - rowFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)childDisplay)); - if (NS_STYLE_DISPLAY_TABLE_ROW == childDisplay->mDisplay) - { + while (rowFrame) { + nsCOMPtr rowType; + rowFrame->GetFrameType(getter_AddRefs(rowType)); + if (nsLayoutAtoms::tableRowFrame == rowType) { // check this row for a cell with rowspans - nsIFrame *cellFrame; + nsIFrame* cellFrame; rowFrame->FirstChild(aPresContext, nsnull, &cellFrame); - while (nsnull != cellFrame) - { - const nsStyleDisplay *cellChildDisplay; - cellFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)cellChildDisplay)); - if (NS_STYLE_DISPLAY_TABLE_CELL == cellChildDisplay->mDisplay) - { + while (cellFrame) { + nsCOMPtr cellType; + cellFrame->GetFrameType(getter_AddRefs(cellType)); + if (nsLayoutAtoms::tableCellFrame == cellType) { 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 + if (rowSpan > 1) { // found a cell with rowspan > 1, determine the height + // of the rows it spans nscoord heightOfRowsSpanned = 0; - PRInt32 i; - for (i = 0; i < rowSpan; i++) { - heightOfRowsSpanned += rowHeights[rowIndex + i]; + PRInt32 spanX; + for (spanX = 0; spanX < rowSpan; spanX++) { + if (rowHeights[rowIndex + spanX] > 0) { + // don't consider negative values of special rows + heightOfRowsSpanned += rowHeights[rowIndex + spanX]; + } } // reduce the height by top and bottom margins nscoord availHeightOfRowsSpanned = heightOfRowsSpanned - cellSpacingY - cellSpacingY; @@ -673,44 +696,60 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, nsSize cellFrameSize; cellFrame->GetSize(cellFrameSize); if (0 == counter) { - nsSize cellDesiredSize = ((nsTableCellFrame*)cellFrame)->GetDesiredSize(); - cellFrameSize.height = cellDesiredSize.height; + nsSize cellDesSize = ((nsTableCellFrame*)cellFrame)->GetDesiredSize(); + ((nsTableRowFrame*)rowFrame)->CalculateCellActualSize(cellFrame, cellDesSize.width, + cellDesSize.height, cellDesSize.width); + cellFrameSize.height = cellDesSize.height; } - if (availHeightOfRowsSpanned >= cellFrameSize.height) - { + if (availHeightOfRowsSpanned >= cellFrameSize.height) { // yes 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); } - else - { + 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 PRInt32 excessHeight = cellFrameSize.height - availHeightOfRowsSpanned; - // for every row starting at the row with the spanning cell and down - // to the last row spanned by the cell - nsTableRowFrame *rowFrameToBeResized = (nsTableRowFrame *)rowFrame; + nsTableRowFrame* rowFrameToBeResized = (nsTableRowFrame *)rowFrame; nscoord excessAllocated = 0; - for (i = rowIndex; i < (rowIndex + rowSpan); i++) { - // The amount of additional space each 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[i]) / ((float)heightOfRowsSpanned); + // 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. + for (PRInt32 rowX = (rowIndex + rowSpan) - 1; rowX >= rowIndex; rowX--) { + nscoord excessForRow; + // special rows get as much they can + if (rowHeights[rowX] < 0) { + nscoord excessAvail = excessHeight - excessAllocated; + if (excessAvail > 0) { + // don't let the allocation excced what it needs + excessForRow = (excessAvail > -rowHeights[rowX]) ? -rowHeights[rowX] : excessAvail; + rowHeights[rowX] = excessForRow; + } + else { + // nothing available so assign a zero allocation + excessForRow = rowHeights[rowX] = 0; + } + } + else { // 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 last row which gets - // the remainder - nscoord excessForRow = ((i + 1) == (rowIndex + rowSpan)) ? - excessHeight - excessAllocated : - NSToCoordRound(((float)(excessHeight)) * percent); + // give rows their percentage, except for the first row which gets + // the remainder + excessForRow = (rowX == rowIndex) + ? excessHeight - excessAllocated + : NSToCoordRound(((float)(excessHeight)) * percent); + // update the row height + rowHeights[rowX] += excessForRow; + } excessAllocated += excessForRow; - - // update the row height - rowHeights[i] += excessForRow; - + // Get the next row frame GetNextRowSibling((nsIFrame**)&rowFrameToBeResized); } @@ -718,8 +757,7 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, } } } - // Get the next row child (cell frame) - cellFrame->GetNextSibling(&cellFrame); + cellFrame->GetNextSibling(&cellFrame); // Get the next row child (cell frame) } // If this is pass 2 then resize the row to its final size and move the @@ -741,7 +779,7 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, if (movedFrame) { // Make sure any views are positioned properly - nsIView* view; + nsIView* view; rowFrame->GetView(aPresContext, &view); if (view) { nsContainerFrame::PositionFrameView(aPresContext, rowFrame, view); @@ -753,9 +791,7 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, rowIndex++; } - - // Get the next rowgroup child (row frame) - GetNextFrame(rowFrame, &rowFrame); + GetNextFrame(rowFrame, &rowFrame); // Get the next rowgroup child (row frame) } } } @@ -764,31 +800,26 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, nscoord rowGroupHeight = 0; rowFrame = GetFirstFrame(); rowIndex = 0; - while (nsnull != rowFrame) - { - rowFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)childDisplay)); - if (NS_STYLE_DISPLAY_TABLE_ROW == childDisplay->mDisplay) - { + while (rowFrame) { + nsCOMPtr rowType; + rowFrame->GetFrameType(getter_AddRefs(rowType)); + if (nsLayoutAtoms::tableRowFrame == rowType) { // Notify the row of the new size ((nsTableRowFrame *)rowFrame)->DidResize(aPresContext, aReflowState); } // Update the running row group height. The height includes frames that // aren't rows as well - nsSize rowSize; + nsSize rowSize; rowFrame->GetSize(rowSize); rowGroupHeight += rowSize.height; - // Get the next row - GetNextFrame(rowFrame, &rowFrame); + GetNextFrame(rowFrame, &rowFrame); // Get the next row rowIndex++; } - // Adjust our desired size - aDesiredSize.height = rowGroupHeight; - - // cleanup - delete []rowHeights; + aDesiredSize.height = rowGroupHeight; // Adjust our desired size + delete [] rowHeights; // cleanup } // Called by IR_TargetIsChild() to adjust the sibling frames that follow