diff --git a/mozilla/layout/html/table/src/nsTableCellFrame.cpp b/mozilla/layout/html/table/src/nsTableCellFrame.cpp index a454a90210c..9ada62184bf 100644 --- a/mozilla/layout/html/table/src/nsTableCellFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableCellFrame.cpp @@ -1098,8 +1098,10 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext, } else if (HadSpecialReflow() && ((eReflowReason_Incremental == aReflowState.reason) || (eReflowReason_Resize == aReflowState.reason))) { - // if the block height value hasn't changed, use the last height of the cell, otherwise ignore it - if (GetLastBlockHeight() == priorBlockHeight) { + // with an unconstrained height, if the block height value hasn't changed, + // use the last height of the cell. + if ((NS_UNCONSTRAINEDSIZE == aReflowState.availableHeight) && + (GetLastBlockHeight() == priorBlockHeight)) { aDesiredSize.height = mRect.height; } else { diff --git a/mozilla/layout/html/table/src/nsTableFrame.cpp b/mozilla/layout/html/table/src/nsTableFrame.cpp index 9c593670d77..680bb511dce 100644 --- a/mozilla/layout/html/table/src/nsTableFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableFrame.cpp @@ -2112,6 +2112,7 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext, #if defined DEBUG_TABLE_REFLOW_TIMING nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState, &aDesiredSize, aStatus); #endif + return rv; } @@ -3297,6 +3298,10 @@ nsTableFrame::ReflowChildren(nsIPresContext* aPresContext, // XXX fix up bad mComputedWidth for scroll frame kidReflowState.mComputedWidth = PR_MAX(kidReflowState.mComputedWidth, 0); + // If this isn't the first row group, then we can't be at the top of the page + if (childX > 0) { + kidReflowState.mFlags.mIsTopOfPage = PR_FALSE; + } aReflowState.y += cellSpacingY; // record the next in flow in case it gets destroyed and the row group array diff --git a/mozilla/layout/html/table/src/nsTableOuterFrame.cpp b/mozilla/layout/html/table/src/nsTableOuterFrame.cpp index 86536e5933a..36b85db32c2 100644 --- a/mozilla/layout/html/table/src/nsTableOuterFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableOuterFrame.cpp @@ -1011,6 +1011,15 @@ nsTableOuterFrame::OuterReflowChild(nsIPresContext* aPresContext, } } + // see if we need to reset top of page due to a caption + if (mCaptionFrame) { + PRUint8 captionSide = GetCaptionSide(); + if (((NS_SIDE_BOTTOM == captionSide) && (mCaptionFrame == aChildFrame)) || + ((NS_SIDE_TOP == captionSide) && (mInnerTableFrame == aChildFrame))) { + childRS.mFlags.mIsTopOfPage = PR_FALSE; + } + } + // use the current position as a best guess for placement nsRect childRect; aChildFrame->GetRect(childRect); diff --git a/mozilla/layout/html/table/src/nsTableRowFrame.cpp b/mozilla/layout/html/table/src/nsTableRowFrame.cpp index d81b50d1a33..85ce78ccdb2 100644 --- a/mozilla/layout/html/table/src/nsTableRowFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableRowFrame.cpp @@ -863,6 +863,24 @@ GetComputedWidth(const nsHTMLReflowState& aReflowState, return computedWidth; } +// subtract the heights of aRow's prev in flows from the unpaginated height +static +nscoord CalcHeightFromUnpaginatedHeight(nsIPresContext* aPresContext, + nsTableRowFrame& aRow) +{ + nscoord height = 0; + nsTableRowFrame* firstInFlow = (nsTableRowFrame*)aRow.GetFirstInFlow(); if (!firstInFlow) ABORT1(0); + if (firstInFlow->HasUnpaginatedHeight()) { + height = firstInFlow->GetUnpaginatedHeight(aPresContext); + for (nsIFrame* prevInFlow = aRow.GetPrevInFlow(); prevInFlow; prevInFlow->GetPrevInFlow(&prevInFlow)) { + nsRect rect; + prevInFlow->GetRect(rect); + height -= rect.height; + } + } + return PR_MAX(height, 0); +} + // Called for a dirty or resize reflow. Reflows all the existing table cell // frames unless aDirtyOnly is PR_TRUE in which case only reflow the dirty frames @@ -1063,22 +1081,23 @@ nsTableRowFrame::ReflowChildren(nsIPresContext* aPresContext, nsTableFrame::RePositionViews(aPresContext, kidFrame); } - if ((NS_UNCONSTRAINEDSIZE == aReflowState.availableHeight) && !mPrevInFlow) { - // 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(kidFrame, desiredSize.width, - desiredSize.height, availCellWidth); - + if (NS_UNCONSTRAINEDSIZE == aReflowState.availableHeight) { + if (!mPrevInFlow) { + // 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(kidFrame, desiredSize.width, + desiredSize.height, availCellWidth); + } // height may have changed, adjust descent to absorb any excess difference nscoord ascent = cellFrame->GetDesiredAscent(); nscoord descent = desiredSize.height - ascent; UpdateHeight(desiredSize.height, ascent, descent, &aTableFrame, cellFrame); } else { + paginatedHeight = PR_MAX(paginatedHeight, desiredSize.height); PRInt32 rowSpan = aTableFrame.GetEffectiveRowSpan((nsTableCellFrame&)*kidFrame); - if ((1 == rowSpan) && (desiredSize.height > paginatedHeight)) { - paginatedHeight = desiredSize.height; + if (1 == rowSpan) { SetContentHeight(paginatedHeight); } } @@ -1117,8 +1136,32 @@ nsTableRowFrame::ReflowChildren(nsIPresContext* aPresContext, // just set our width to what was available. The table will calculate the width and not use our value. aDesiredSize.width = aReflowState.availableWidth; - aDesiredSize.height = (NS_UNCONSTRAINEDSIZE == aReflowState.availableHeight) - ? CalcHeight(aReflowState) : paginatedHeight; + + if (NS_UNCONSTRAINEDSIZE == aReflowState.availableHeight) { + aDesiredSize.height = CalcHeight(aReflowState); + if (mPrevInFlow) { + nscoord height = CalcHeightFromUnpaginatedHeight(aPresContext, *this); + aDesiredSize.height = PR_MAX(aDesiredSize.height, height); + } + else { + if (isPaginated && HasStyleHeight()) { + // set the unpaginated height so next in flows can try to honor it + SetHasUnpaginatedHeight(PR_TRUE); + SetUnpaginatedHeight(aPresContext, aDesiredSize.height); + } + if (isPaginated && HasUnpaginatedHeight()) { + aDesiredSize.height = PR_MAX(aDesiredSize.height, GetUnpaginatedHeight(aPresContext)); + } + } + } + else { // constrained height, paginated + aDesiredSize.height = paginatedHeight; + if (aDesiredSize.height <= aReflowState.availableHeight) { + nscoord height = CalcHeightFromUnpaginatedHeight(aPresContext, *this); + aDesiredSize.height = PR_MAX(aDesiredSize.height, height); + aDesiredSize.height = PR_MIN(aDesiredSize.height, aReflowState.availableHeight); + } + } return rv; } @@ -1585,6 +1628,7 @@ void nsTableRowFrame::SetUnpaginatedHeight(nsIPresContext* aPresContext, nscoord aValue) { + NS_ASSERTION(!mPrevInFlow, "program error"); // Get the property nscoord* value = (nscoord*)nsTableFrame::GetProperty(aPresContext, this, nsLayoutAtoms::rowUnpaginatedHeightProperty, PR_TRUE); if (value) { @@ -1596,7 +1640,7 @@ nscoord nsTableRowFrame::GetUnpaginatedHeight(nsIPresContext* aPresContext) { // See if the property is set - nscoord* value = (nscoord*)nsTableFrame::GetProperty(aPresContext, this, nsLayoutAtoms::rowUnpaginatedHeightProperty); + nscoord* value = (nscoord*)nsTableFrame::GetProperty(aPresContext, GetFirstInFlow(), nsLayoutAtoms::rowUnpaginatedHeightProperty); if (value) return *value; else diff --git a/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp b/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp index 23024fc1e7f..bbd3a58c104 100644 --- a/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp @@ -437,8 +437,7 @@ nsTableRowGroupFrame::ReflowChildren(nsIPresContext* aPresContext, kidAvailSize, reason); InitChildReflowState(*aPresContext, borderCollapse, p2t, kidReflowState); - // If this isn't the first row frame, then we can't be at the top of - // the page anymore... + // If this isn't the first row, then we can't be at the top of the page if (kidFrame != GetFirstFrame()) { kidReflowState.mFlags.mIsTopOfPage = PR_FALSE; } @@ -571,6 +570,20 @@ HasMoreThanOneCell(nsTableCellMap* aCellMap, return PR_FALSE; } +static void +CacheRowHeightsForPrinting(nsIPresContext* aPresContext, + nsTableRowFrame* aFirstRow) +{ + for (nsTableRowFrame* row = aFirstRow; row; row = row->GetNextRow()) { + if (!row->GetPrevInFlow()) { + nsRect rect; + row->GetRect(rect); + row->SetHasUnpaginatedHeight(PR_TRUE); + row->SetUnpaginatedHeight(aPresContext, rect.height); + } + } +} + // This calculates the height of rows starting at aStartRowFrameIn and takes into account // style height on the row group, style heights on rows and cells, style heights on rowspans. // Actual row heights will be adjusted later if the table has a style height. @@ -586,6 +599,9 @@ nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, nsTableFrame::GetTableFrame(this, tableFrame); if (!aPresContext || !tableFrame) return; + PRBool isPaginated; + aPresContext->IsPaginated(&isPaginated); + // all table cells have the same top and bottom margins, namely cellSpacingY nscoord cellSpacingY = tableFrame->GetCellSpacingY(); float p2t; @@ -639,16 +655,24 @@ nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, PRInt32 rowIndex; // the index in rowInfo, not among the rows in the row group nsTableRowFrame* rowFrame; for (rowFrame = startRowFrame, rowIndex = 0; rowFrame; rowFrame = rowFrame->GetNextRow(), rowIndex++) { - if (rowFrame->HasPctHeight()) { - rowInfo[rowIndex].hasPctHeight = PR_TRUE; - rowInfo[rowIndex].pctHeight = nsTableFrame::RoundToPixel(rowFrame->GetHeight(pctHeightBasis), p2t); + nscoord nonPctHeight = rowFrame->GetContentHeight(); + if (isPaginated) { + nsRect rowRect; + rowFrame->GetRect(rowRect); + nonPctHeight = PR_MAX(nonPctHeight, rowRect.height); + } + if (!rowFrame->GetPrevInFlow()) { + if (rowFrame->HasPctHeight()) { + rowInfo[rowIndex].hasPctHeight = PR_TRUE; + rowInfo[rowIndex].pctHeight = nsTableFrame::RoundToPixel(rowFrame->GetHeight(pctHeightBasis), p2t); + } + rowInfo[rowIndex].hasStyleHeight = rowFrame->HasStyleHeight(); + nonPctHeight = PR_MAX(nonPctHeight, rowFrame->GetFixedHeight()); } - nscoord nonPctHeight = PR_MAX(rowFrame->GetContentHeight(), rowFrame->GetFixedHeight()); UpdateHeights(rowInfo[rowIndex], nonPctHeight, heightOfRows, heightOfUnStyledRows); - rowInfo[rowIndex].hasStyleHeight = rowFrame->HasStyleHeight(); if (!rowInfo[rowIndex].hasStyleHeight) { - if (HasMoreThanOneCell(tableFrame->GetCellMap(), rowIndex)) { + if (isPaginated || HasMoreThanOneCell(tableFrame->GetCellMap(), rowIndex + startRowIndex)) { rowInfo[rowIndex].isSpecial = PR_TRUE; // iteratate the row's cell frames to see if any do not have rowspan > 1 nsTableCellFrame* cellFrame = rowFrame->GetFirstCell(); @@ -674,7 +698,10 @@ nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, // Get the height of cells with rowspans and allocate any extra space to the rows they span // iteratate the child frames and process the row frames among them for (rowFrame = startRowFrame, rowIndex = 0; rowFrame; rowFrame = rowFrame->GetNextRow(), rowIndex++) { - if (tableFrame->RowHasSpanningCells(startRowIndex + rowIndex)) { + // See if the row has an originating cell with rowspan > 1. We cannot determine this for a row in a + // continued row group by calling RowHasSpanningCells, because the row's fif may not have any originating + // cells yet the row may have a continued cell which originates in it. + if (mPrevInFlow || tableFrame->RowHasSpanningCells(startRowIndex + rowIndex)) { nsTableCellFrame* cellFrame = rowFrame->GetFirstCell(); // iteratate the row's cell frames while (cellFrame) { @@ -790,6 +817,7 @@ nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, } } + PRBool styleHeightAllocation = PR_FALSE; nscoord rowGroupHeight = startRowGroupHeight + heightOfRows + ((numRows - 1) * cellSpacingY); // if we have a style height, allocate the extra height to unconstrained rows if ((aReflowState.mComputedHeight > rowGroupHeight) && @@ -800,6 +828,7 @@ nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, nscoord divisor = (haveUnStyledRows) ? heightOfUnStyledRows : heightOfRows; if (divisor > 0) { + styleHeightAllocation = PR_TRUE; for (rowIndex = 0; rowIndex < numRows; rowIndex++) { if (!haveUnStyledRows || !rowInfo[rowIndex].hasStyleHeight) { // The amount of additional space each row gets is based on the @@ -844,6 +873,11 @@ nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, yOrigin += rowHeight + cellSpacingY; } + if (isPaginated && styleHeightAllocation) { + // since the row group has a style height, cache the row heights, so next in flows can honor them + CacheRowHeightsForPrinting(aPresContext, GetFirstRow()); + } + DidResizeRows(*aPresContext, aReflowState, startRowFrame); aDesiredSize.height = rowGroupHeight; // Adjust our desired size @@ -902,6 +936,7 @@ nsTableRowGroupFrame::CreateContinuingRowFrame(nsIPresContext& aPresContext, nsIFrame& aRowFrame, nsIFrame** aContRowFrame) { + // XXX what is the row index? if (!aContRowFrame) {NS_ASSERTION(PR_FALSE, "bad call"); return;} // create the continuing frame which will create continuing cell frames aStyleSet.CreateContinuingFrame(&aPresContext, &aRowFrame, this, aContRowFrame); @@ -917,7 +952,7 @@ nsTableRowGroupFrame::CreateContinuingRowFrame(nsIPresContext& aPresContext, PushChildren(&aPresContext, *aContRowFrame, &aRowFrame); } -nscoord +void nsTableRowGroupFrame::SplitSpanningCells(nsIPresContext& aPresContext, const nsHTMLReflowState& aReflowState, nsIStyleSet& aStyleSet, @@ -929,9 +964,8 @@ nsTableRowGroupFrame::SplitSpanningCells(nsIPresContext& aPresContext, PRInt32 rowIndex = aRowFrame.GetRowIndex(); PRInt32 colCount = aTableFrame.GetColCount(); nsTableCellFrame* prevCellFrame = nsnull; + nsTableRowFrame* rowToMoveToNextPage = nsnull; - nscoord tallestCell = 0; - for (PRInt32 colX = 0; colX < colCount; colX++) { nsTableCellFrame* cellFrame = aTableFrame.GetCellInfoAt(rowIndex, colX); if (!cellFrame) continue; @@ -939,20 +973,19 @@ nsTableRowGroupFrame::SplitSpanningCells(nsIPresContext& aPresContext, cellFrame = (nsTableCellFrame*)cellFrame->GetLastInFlow(); // See if the cell frame is really in this row, or whether it's a cell spanning from a previous row - PRInt32 realRowIndex; - cellFrame->GetRowIndex(realRowIndex); - if (realRowIndex == rowIndex) { + PRInt32 cellRowIndex; + cellFrame->GetRowIndex(cellRowIndex); + if (cellRowIndex == rowIndex) { // cell originates in this row prevCellFrame = cellFrame; } - else { + else { // cell originates in a prior row nsTableRowFrame* parentFrame; nsPoint cellOrigin; nsReflowStatus status; // Ask the cell frame's parent to reflow it to the height of all the // rows it spans between its origin and aRowEndY - cellFrame->GetParent((nsIFrame**)&parentFrame); - if (!parentFrame) {NS_ASSERTION(PR_FALSE, "bad parent"); return 0;} + cellFrame->GetParent((nsIFrame**)&parentFrame); if (!parentFrame) ABORT0(); parentFrame->GetOrigin(cellOrigin); nscoord cellAvailHeight = aRowEndY - cellOrigin.y; nscoord cellHeight = parentFrame->ReflowCellFrame(&aPresContext, aReflowState, cellFrame, @@ -965,7 +998,7 @@ nsTableRowGroupFrame::SplitSpanningCells(nsIPresContext& aPresContext, if (contCellFrame) { if (aContRowFrame) { aContRowFrame->InsertCellFrame(contCellFrame, colX); - } + } else { aRowFrame.InsertCellFrame(contCellFrame, prevCellFrame); } @@ -978,10 +1011,8 @@ nsTableRowGroupFrame::SplitSpanningCells(nsIPresContext& aPresContext, aContRowFrame->InsertCellFrame(cellFrame, colX); prevCellFrame = cellFrame; } - tallestCell = PR_MAX(tallestCell, cellHeight); } } - return tallestCell; } nsresult @@ -1008,32 +1039,40 @@ nsTableRowGroupFrame::SplitRowGroup(nsIPresContext* aPresContext, nscoord availWidth = nsTableFrame::RoundToPixel(aReflowState.availableWidth, p2t); nscoord availHeight = nsTableFrame::RoundToPixel(aReflowState.availableHeight, p2t); - nscoord lastDesiredHeight = 0; + + // get the page height + nsRect actualRect; + nsRect adjRect; + aPresContext->GetPageDim(&actualRect, &adjRect); + nscoord pageHeight = actualRect.height; + + PRBool isTopOfPage = aReflowState.mFlags.mIsTopOfPage; + nscoord cellSpacingY = aTableFrame->GetCellSpacingY(); // Walk each of the row frames looking for the first row frame that // doesn't fit in the available space for (nsTableRowFrame* rowFrame = GetFirstRow(); rowFrame; rowFrame = rowFrame->GetNextRow()) { PRBool rowIsOnCurrentPage = PR_TRUE; - PRBool degenerateRow = PR_FALSE; nsRect bounds; rowFrame->GetRect(bounds); if (bounds.YMost() > availHeight) { - nsRect actualRect; - nsRect adjRect; - aPresContext->GetPageDim(&actualRect, &adjRect); nsIFrame* contRowFrame = nsnull; - nscoord pageHeight = actualRect.height; // reflow the row in the availabe space and have it split if it is the 1st // row or there is at least 5% of the current page available if (!prevRowFrame || (availHeight - aDesiredSize.height > pageHeight / 20)) { - // Reflow the row in the available space and have it split nsSize availSize(availWidth, PR_MAX(availHeight - bounds.y, 0)); + // don't let the available height exceed what CalculateRowHeights set for it + availSize.height = PR_MIN(availSize.height, bounds.height); + nsHTMLReflowState rowReflowState(aPresContext, aReflowState, rowFrame, availSize, eReflowReason_Resize); InitChildReflowState(*aPresContext, borderCollapse, p2t, rowReflowState); + rowReflowState.mFlags.mIsTopOfPage = isTopOfPage; // set top of page nsHTMLReflowMetrics desiredSize(nsnull); + // A row that has all originating cells with rowspan>1 will return a desired height + // of the largest cell (in contrast to an unconstrained height reflow which returns 0). rv = ReflowChild(rowFrame, aPresContext, desiredSize, rowReflowState, 0, 0, NS_FRAME_NO_MOVE_FRAME, aStatus); rowFrame->SizeTo(aPresContext, desiredSize.width, desiredSize.height); @@ -1042,27 +1081,26 @@ nsTableRowGroupFrame::SplitRowGroup(nsIPresContext* aPresContext, if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { // the row frame is incomplete and all of the cells' block frames have split - CreateContinuingRowFrame(*aPresContext, *styleSet.get(), *rowFrame, &contRowFrame); - aDesiredSize.height += desiredSize.height; - if (prevRowFrame) { - aDesiredSize.height += aTableFrame->GetCellSpacingY(); - } - } - else if (0 == desiredSize.height) { - // the row frame is complete because it had no cells originating in it. - CreateContinuingRowFrame(*aPresContext, *styleSet.get(), *rowFrame, &contRowFrame); - aStatus = NS_FRAME_NOT_COMPLETE; - aDesiredSize.height = availHeight; - degenerateRow = PR_TRUE; - } - else { - // the row frame is complete because it's minimum height was greater than the - // the available height we gave it - if (aDesiredSize.height > 0) { - // put the row on the next page since it needs more height than it was given - rowIsOnCurrentPage = PR_FALSE; + if ((desiredSize.height <= rowReflowState.availableHeight) || isTopOfPage) { + // the row stays on this page because either it split ok or we're on the top of page + // if top of page and the height exceeded the avail height,then there will be data loss + NS_WARN_IF_FALSE(desiredSize.height <= rowReflowState.availableHeight, + "data loss - incomplete row needed more height than available, on top of page"); + CreateContinuingRowFrame(*aPresContext, *styleSet.get(), *rowFrame, &contRowFrame); + aDesiredSize.height += desiredSize.height; + if (prevRowFrame) + aDesiredSize.height += cellSpacingY; } else { + // put the row on the next page to give it more height + rowIsOnCurrentPage = PR_FALSE; + } + } + else { + // The row frame is complete because it's minimum height was greater than the + // the available height we gave it. + if (isTopOfPage) { + // We're on top of the page, so keep the row on this page. There will be data loss. nsIFrame* nextRowFrame; // Push the row frame that follows @@ -1070,32 +1108,45 @@ nsTableRowGroupFrame::SplitRowGroup(nsIPresContext* aPresContext, if (nextRowFrame) { PushChildren(aPresContext, nextRowFrame, rowFrame); + aStatus = NS_FRAME_NOT_COMPLETE; } - aStatus = nextRowFrame ? NS_FRAME_NOT_COMPLETE : NS_FRAME_COMPLETE; - aDesiredSize.height = bounds.YMost(); + aDesiredSize.height += desiredSize.height; + if (prevRowFrame) + aDesiredSize.height += cellSpacingY; + NS_WARN_IF_FALSE(PR_FALSE, "data loss - complete row needed more height than available, on top of page"); + } + else { + // We're not on top of the page, so put the row on the next page to give it more height + rowIsOnCurrentPage = PR_FALSE; } } } - else rowIsOnCurrentPage = PR_FALSE; - - if (!rowIsOnCurrentPage) { - // Push this row frame and those that follow to the next-in-flow - PushChildren(aPresContext, rowFrame, prevRowFrame); - aStatus = NS_FRAME_NOT_COMPLETE; + else { + // put the row on the next page to give it more height + rowIsOnCurrentPage = PR_FALSE; } - if (prevRowFrame) { - nscoord tallestCell = - SplitSpanningCells(*aPresContext, aReflowState, *styleSet, *aTableFrame, - *rowFrame, aDesiredSize.height, (nsTableRowFrame*)contRowFrame); - if (degenerateRow) { - aDesiredSize.height = lastDesiredHeight + aTableFrame->GetCellSpacingY() + tallestCell; + + PRBool willGetAnotherReflow = PR_FALSE; + if (!rowIsOnCurrentPage) { + if (prevRowFrame) { + PushChildren(aPresContext, rowFrame, prevRowFrame); + aStatus = NS_FRAME_NOT_COMPLETE; } + else { + // We can't push children, so let our parent reflow us again with more space + aDesiredSize.height = bounds.YMost(); + willGetAnotherReflow = PR_TRUE; + } + } + + if (prevRowFrame && !willGetAnotherReflow) { + SplitSpanningCells(*aPresContext, aReflowState, *styleSet, *aTableFrame, + *rowFrame, aDesiredSize.height, (nsTableRowFrame*)contRowFrame); } break; } else { aDesiredSize.height = bounds.YMost(); - lastDesiredHeight = aDesiredSize.height; prevRowFrame = rowFrame; // see if there is a page break after the row nsTableRowFrame* nextRow = rowFrame->GetNextRow(); @@ -1105,22 +1156,11 @@ nsTableRowGroupFrame::SplitRowGroup(nsIPresContext* aPresContext, break; } } + isTopOfPage = PR_FALSE; // after the 1st row, we can't be on top of the page any more. } return NS_OK; } -static void -CacheRowHeightsForPrinting(nsIPresContext* aPresContext, - nsTableRowFrame* aFirstRow) -{ - for (nsTableRowFrame* row = aFirstRow; row; row = row->GetNextRow()) { - nsRect rect; - row->GetRect(rect); - row->SetHasUnpaginatedHeight(PR_TRUE); - row->SetUnpaginatedHeight(aPresContext, rect.height); - } -} - /** Layout the entire row group. * This method stacks rows vertically according to HTML 4.0 rules. * Rows are responsible for layout of their children. @@ -1157,10 +1197,6 @@ nsTableRowGroupFrame::Reflow(nsIPresContext* aPresContext, // Check for an overflow list MoveOverflowToChildList(aPresContext); - if (isPaginated && aReflowState.mFlags.mSpecialHeightReflow) { - // cache row height info for printing, now that row heights are known. - CacheRowHeightsForPrinting(aPresContext, GetFirstRow()); - } // Reflow the existing frames. PRBool splitDueToPageBreak = PR_FALSE; rv = ReflowChildren(aPresContext, aDesiredSize, state, aStatus, @@ -1181,6 +1217,9 @@ nsTableRowGroupFrame::Reflow(nsIPresContext* aPresContext, // are row spans unless we do this step if (aReflowState.mFlags.mSpecialHeightReflow) { DidResizeRows(*aPresContext, aReflowState); + if (isPaginated) { + CacheRowHeightsForPrinting(aPresContext, GetFirstRow()); + } } else if ((eReflowReason_Initial != aReflowState.reason) || isTableUnconstrainedReflow || diff --git a/mozilla/layout/html/table/src/nsTableRowGroupFrame.h b/mozilla/layout/html/table/src/nsTableRowGroupFrame.h index 789152b5a7e..489243c682d 100644 --- a/mozilla/layout/html/table/src/nsTableRowGroupFrame.h +++ b/mozilla/layout/html/table/src/nsTableRowGroupFrame.h @@ -334,13 +334,13 @@ protected: nsTableFrame* aTableFrame, nsReflowStatus& aStatus); - nscoord SplitSpanningCells(nsIPresContext& aPresContext, - const nsHTMLReflowState& aReflowState, - nsIStyleSet& aStyleSet, - nsTableFrame& aTableFrame, - nsTableRowFrame& aRowFrame, - nscoord aRowEndY, - nsTableRowFrame* aContRowFrame); + void SplitSpanningCells(nsIPresContext& aPresContext, + const nsHTMLReflowState& aReflowState, + nsIStyleSet& aStyleSet, + nsTableFrame& aTableFrame, + nsTableRowFrame& aRowFrame, + nscoord aRowEndY, + nsTableRowFrame* aContRowFrame); void CreateContinuingRowFrame(nsIPresContext& aPresContext, nsIStyleSet& aStyleSet, diff --git a/mozilla/layout/tables/nsTableCellFrame.cpp b/mozilla/layout/tables/nsTableCellFrame.cpp index a454a90210c..9ada62184bf 100644 --- a/mozilla/layout/tables/nsTableCellFrame.cpp +++ b/mozilla/layout/tables/nsTableCellFrame.cpp @@ -1098,8 +1098,10 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext, } else if (HadSpecialReflow() && ((eReflowReason_Incremental == aReflowState.reason) || (eReflowReason_Resize == aReflowState.reason))) { - // if the block height value hasn't changed, use the last height of the cell, otherwise ignore it - if (GetLastBlockHeight() == priorBlockHeight) { + // with an unconstrained height, if the block height value hasn't changed, + // use the last height of the cell. + if ((NS_UNCONSTRAINEDSIZE == aReflowState.availableHeight) && + (GetLastBlockHeight() == priorBlockHeight)) { aDesiredSize.height = mRect.height; } else { diff --git a/mozilla/layout/tables/nsTableFrame.cpp b/mozilla/layout/tables/nsTableFrame.cpp index 9c593670d77..680bb511dce 100644 --- a/mozilla/layout/tables/nsTableFrame.cpp +++ b/mozilla/layout/tables/nsTableFrame.cpp @@ -2112,6 +2112,7 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext, #if defined DEBUG_TABLE_REFLOW_TIMING nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState, &aDesiredSize, aStatus); #endif + return rv; } @@ -3297,6 +3298,10 @@ nsTableFrame::ReflowChildren(nsIPresContext* aPresContext, // XXX fix up bad mComputedWidth for scroll frame kidReflowState.mComputedWidth = PR_MAX(kidReflowState.mComputedWidth, 0); + // If this isn't the first row group, then we can't be at the top of the page + if (childX > 0) { + kidReflowState.mFlags.mIsTopOfPage = PR_FALSE; + } aReflowState.y += cellSpacingY; // record the next in flow in case it gets destroyed and the row group array diff --git a/mozilla/layout/tables/nsTableOuterFrame.cpp b/mozilla/layout/tables/nsTableOuterFrame.cpp index 86536e5933a..36b85db32c2 100644 --- a/mozilla/layout/tables/nsTableOuterFrame.cpp +++ b/mozilla/layout/tables/nsTableOuterFrame.cpp @@ -1011,6 +1011,15 @@ nsTableOuterFrame::OuterReflowChild(nsIPresContext* aPresContext, } } + // see if we need to reset top of page due to a caption + if (mCaptionFrame) { + PRUint8 captionSide = GetCaptionSide(); + if (((NS_SIDE_BOTTOM == captionSide) && (mCaptionFrame == aChildFrame)) || + ((NS_SIDE_TOP == captionSide) && (mInnerTableFrame == aChildFrame))) { + childRS.mFlags.mIsTopOfPage = PR_FALSE; + } + } + // use the current position as a best guess for placement nsRect childRect; aChildFrame->GetRect(childRect); diff --git a/mozilla/layout/tables/nsTableRowFrame.cpp b/mozilla/layout/tables/nsTableRowFrame.cpp index d81b50d1a33..85ce78ccdb2 100644 --- a/mozilla/layout/tables/nsTableRowFrame.cpp +++ b/mozilla/layout/tables/nsTableRowFrame.cpp @@ -863,6 +863,24 @@ GetComputedWidth(const nsHTMLReflowState& aReflowState, return computedWidth; } +// subtract the heights of aRow's prev in flows from the unpaginated height +static +nscoord CalcHeightFromUnpaginatedHeight(nsIPresContext* aPresContext, + nsTableRowFrame& aRow) +{ + nscoord height = 0; + nsTableRowFrame* firstInFlow = (nsTableRowFrame*)aRow.GetFirstInFlow(); if (!firstInFlow) ABORT1(0); + if (firstInFlow->HasUnpaginatedHeight()) { + height = firstInFlow->GetUnpaginatedHeight(aPresContext); + for (nsIFrame* prevInFlow = aRow.GetPrevInFlow(); prevInFlow; prevInFlow->GetPrevInFlow(&prevInFlow)) { + nsRect rect; + prevInFlow->GetRect(rect); + height -= rect.height; + } + } + return PR_MAX(height, 0); +} + // Called for a dirty or resize reflow. Reflows all the existing table cell // frames unless aDirtyOnly is PR_TRUE in which case only reflow the dirty frames @@ -1063,22 +1081,23 @@ nsTableRowFrame::ReflowChildren(nsIPresContext* aPresContext, nsTableFrame::RePositionViews(aPresContext, kidFrame); } - if ((NS_UNCONSTRAINEDSIZE == aReflowState.availableHeight) && !mPrevInFlow) { - // 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(kidFrame, desiredSize.width, - desiredSize.height, availCellWidth); - + if (NS_UNCONSTRAINEDSIZE == aReflowState.availableHeight) { + if (!mPrevInFlow) { + // 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(kidFrame, desiredSize.width, + desiredSize.height, availCellWidth); + } // height may have changed, adjust descent to absorb any excess difference nscoord ascent = cellFrame->GetDesiredAscent(); nscoord descent = desiredSize.height - ascent; UpdateHeight(desiredSize.height, ascent, descent, &aTableFrame, cellFrame); } else { + paginatedHeight = PR_MAX(paginatedHeight, desiredSize.height); PRInt32 rowSpan = aTableFrame.GetEffectiveRowSpan((nsTableCellFrame&)*kidFrame); - if ((1 == rowSpan) && (desiredSize.height > paginatedHeight)) { - paginatedHeight = desiredSize.height; + if (1 == rowSpan) { SetContentHeight(paginatedHeight); } } @@ -1117,8 +1136,32 @@ nsTableRowFrame::ReflowChildren(nsIPresContext* aPresContext, // just set our width to what was available. The table will calculate the width and not use our value. aDesiredSize.width = aReflowState.availableWidth; - aDesiredSize.height = (NS_UNCONSTRAINEDSIZE == aReflowState.availableHeight) - ? CalcHeight(aReflowState) : paginatedHeight; + + if (NS_UNCONSTRAINEDSIZE == aReflowState.availableHeight) { + aDesiredSize.height = CalcHeight(aReflowState); + if (mPrevInFlow) { + nscoord height = CalcHeightFromUnpaginatedHeight(aPresContext, *this); + aDesiredSize.height = PR_MAX(aDesiredSize.height, height); + } + else { + if (isPaginated && HasStyleHeight()) { + // set the unpaginated height so next in flows can try to honor it + SetHasUnpaginatedHeight(PR_TRUE); + SetUnpaginatedHeight(aPresContext, aDesiredSize.height); + } + if (isPaginated && HasUnpaginatedHeight()) { + aDesiredSize.height = PR_MAX(aDesiredSize.height, GetUnpaginatedHeight(aPresContext)); + } + } + } + else { // constrained height, paginated + aDesiredSize.height = paginatedHeight; + if (aDesiredSize.height <= aReflowState.availableHeight) { + nscoord height = CalcHeightFromUnpaginatedHeight(aPresContext, *this); + aDesiredSize.height = PR_MAX(aDesiredSize.height, height); + aDesiredSize.height = PR_MIN(aDesiredSize.height, aReflowState.availableHeight); + } + } return rv; } @@ -1585,6 +1628,7 @@ void nsTableRowFrame::SetUnpaginatedHeight(nsIPresContext* aPresContext, nscoord aValue) { + NS_ASSERTION(!mPrevInFlow, "program error"); // Get the property nscoord* value = (nscoord*)nsTableFrame::GetProperty(aPresContext, this, nsLayoutAtoms::rowUnpaginatedHeightProperty, PR_TRUE); if (value) { @@ -1596,7 +1640,7 @@ nscoord nsTableRowFrame::GetUnpaginatedHeight(nsIPresContext* aPresContext) { // See if the property is set - nscoord* value = (nscoord*)nsTableFrame::GetProperty(aPresContext, this, nsLayoutAtoms::rowUnpaginatedHeightProperty); + nscoord* value = (nscoord*)nsTableFrame::GetProperty(aPresContext, GetFirstInFlow(), nsLayoutAtoms::rowUnpaginatedHeightProperty); if (value) return *value; else diff --git a/mozilla/layout/tables/nsTableRowGroupFrame.cpp b/mozilla/layout/tables/nsTableRowGroupFrame.cpp index 23024fc1e7f..bbd3a58c104 100644 --- a/mozilla/layout/tables/nsTableRowGroupFrame.cpp +++ b/mozilla/layout/tables/nsTableRowGroupFrame.cpp @@ -437,8 +437,7 @@ nsTableRowGroupFrame::ReflowChildren(nsIPresContext* aPresContext, kidAvailSize, reason); InitChildReflowState(*aPresContext, borderCollapse, p2t, kidReflowState); - // If this isn't the first row frame, then we can't be at the top of - // the page anymore... + // If this isn't the first row, then we can't be at the top of the page if (kidFrame != GetFirstFrame()) { kidReflowState.mFlags.mIsTopOfPage = PR_FALSE; } @@ -571,6 +570,20 @@ HasMoreThanOneCell(nsTableCellMap* aCellMap, return PR_FALSE; } +static void +CacheRowHeightsForPrinting(nsIPresContext* aPresContext, + nsTableRowFrame* aFirstRow) +{ + for (nsTableRowFrame* row = aFirstRow; row; row = row->GetNextRow()) { + if (!row->GetPrevInFlow()) { + nsRect rect; + row->GetRect(rect); + row->SetHasUnpaginatedHeight(PR_TRUE); + row->SetUnpaginatedHeight(aPresContext, rect.height); + } + } +} + // This calculates the height of rows starting at aStartRowFrameIn and takes into account // style height on the row group, style heights on rows and cells, style heights on rowspans. // Actual row heights will be adjusted later if the table has a style height. @@ -586,6 +599,9 @@ nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, nsTableFrame::GetTableFrame(this, tableFrame); if (!aPresContext || !tableFrame) return; + PRBool isPaginated; + aPresContext->IsPaginated(&isPaginated); + // all table cells have the same top and bottom margins, namely cellSpacingY nscoord cellSpacingY = tableFrame->GetCellSpacingY(); float p2t; @@ -639,16 +655,24 @@ nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, PRInt32 rowIndex; // the index in rowInfo, not among the rows in the row group nsTableRowFrame* rowFrame; for (rowFrame = startRowFrame, rowIndex = 0; rowFrame; rowFrame = rowFrame->GetNextRow(), rowIndex++) { - if (rowFrame->HasPctHeight()) { - rowInfo[rowIndex].hasPctHeight = PR_TRUE; - rowInfo[rowIndex].pctHeight = nsTableFrame::RoundToPixel(rowFrame->GetHeight(pctHeightBasis), p2t); + nscoord nonPctHeight = rowFrame->GetContentHeight(); + if (isPaginated) { + nsRect rowRect; + rowFrame->GetRect(rowRect); + nonPctHeight = PR_MAX(nonPctHeight, rowRect.height); + } + if (!rowFrame->GetPrevInFlow()) { + if (rowFrame->HasPctHeight()) { + rowInfo[rowIndex].hasPctHeight = PR_TRUE; + rowInfo[rowIndex].pctHeight = nsTableFrame::RoundToPixel(rowFrame->GetHeight(pctHeightBasis), p2t); + } + rowInfo[rowIndex].hasStyleHeight = rowFrame->HasStyleHeight(); + nonPctHeight = PR_MAX(nonPctHeight, rowFrame->GetFixedHeight()); } - nscoord nonPctHeight = PR_MAX(rowFrame->GetContentHeight(), rowFrame->GetFixedHeight()); UpdateHeights(rowInfo[rowIndex], nonPctHeight, heightOfRows, heightOfUnStyledRows); - rowInfo[rowIndex].hasStyleHeight = rowFrame->HasStyleHeight(); if (!rowInfo[rowIndex].hasStyleHeight) { - if (HasMoreThanOneCell(tableFrame->GetCellMap(), rowIndex)) { + if (isPaginated || HasMoreThanOneCell(tableFrame->GetCellMap(), rowIndex + startRowIndex)) { rowInfo[rowIndex].isSpecial = PR_TRUE; // iteratate the row's cell frames to see if any do not have rowspan > 1 nsTableCellFrame* cellFrame = rowFrame->GetFirstCell(); @@ -674,7 +698,10 @@ nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, // Get the height of cells with rowspans and allocate any extra space to the rows they span // iteratate the child frames and process the row frames among them for (rowFrame = startRowFrame, rowIndex = 0; rowFrame; rowFrame = rowFrame->GetNextRow(), rowIndex++) { - if (tableFrame->RowHasSpanningCells(startRowIndex + rowIndex)) { + // See if the row has an originating cell with rowspan > 1. We cannot determine this for a row in a + // continued row group by calling RowHasSpanningCells, because the row's fif may not have any originating + // cells yet the row may have a continued cell which originates in it. + if (mPrevInFlow || tableFrame->RowHasSpanningCells(startRowIndex + rowIndex)) { nsTableCellFrame* cellFrame = rowFrame->GetFirstCell(); // iteratate the row's cell frames while (cellFrame) { @@ -790,6 +817,7 @@ nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, } } + PRBool styleHeightAllocation = PR_FALSE; nscoord rowGroupHeight = startRowGroupHeight + heightOfRows + ((numRows - 1) * cellSpacingY); // if we have a style height, allocate the extra height to unconstrained rows if ((aReflowState.mComputedHeight > rowGroupHeight) && @@ -800,6 +828,7 @@ nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, nscoord divisor = (haveUnStyledRows) ? heightOfUnStyledRows : heightOfRows; if (divisor > 0) { + styleHeightAllocation = PR_TRUE; for (rowIndex = 0; rowIndex < numRows; rowIndex++) { if (!haveUnStyledRows || !rowInfo[rowIndex].hasStyleHeight) { // The amount of additional space each row gets is based on the @@ -844,6 +873,11 @@ nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, yOrigin += rowHeight + cellSpacingY; } + if (isPaginated && styleHeightAllocation) { + // since the row group has a style height, cache the row heights, so next in flows can honor them + CacheRowHeightsForPrinting(aPresContext, GetFirstRow()); + } + DidResizeRows(*aPresContext, aReflowState, startRowFrame); aDesiredSize.height = rowGroupHeight; // Adjust our desired size @@ -902,6 +936,7 @@ nsTableRowGroupFrame::CreateContinuingRowFrame(nsIPresContext& aPresContext, nsIFrame& aRowFrame, nsIFrame** aContRowFrame) { + // XXX what is the row index? if (!aContRowFrame) {NS_ASSERTION(PR_FALSE, "bad call"); return;} // create the continuing frame which will create continuing cell frames aStyleSet.CreateContinuingFrame(&aPresContext, &aRowFrame, this, aContRowFrame); @@ -917,7 +952,7 @@ nsTableRowGroupFrame::CreateContinuingRowFrame(nsIPresContext& aPresContext, PushChildren(&aPresContext, *aContRowFrame, &aRowFrame); } -nscoord +void nsTableRowGroupFrame::SplitSpanningCells(nsIPresContext& aPresContext, const nsHTMLReflowState& aReflowState, nsIStyleSet& aStyleSet, @@ -929,9 +964,8 @@ nsTableRowGroupFrame::SplitSpanningCells(nsIPresContext& aPresContext, PRInt32 rowIndex = aRowFrame.GetRowIndex(); PRInt32 colCount = aTableFrame.GetColCount(); nsTableCellFrame* prevCellFrame = nsnull; + nsTableRowFrame* rowToMoveToNextPage = nsnull; - nscoord tallestCell = 0; - for (PRInt32 colX = 0; colX < colCount; colX++) { nsTableCellFrame* cellFrame = aTableFrame.GetCellInfoAt(rowIndex, colX); if (!cellFrame) continue; @@ -939,20 +973,19 @@ nsTableRowGroupFrame::SplitSpanningCells(nsIPresContext& aPresContext, cellFrame = (nsTableCellFrame*)cellFrame->GetLastInFlow(); // See if the cell frame is really in this row, or whether it's a cell spanning from a previous row - PRInt32 realRowIndex; - cellFrame->GetRowIndex(realRowIndex); - if (realRowIndex == rowIndex) { + PRInt32 cellRowIndex; + cellFrame->GetRowIndex(cellRowIndex); + if (cellRowIndex == rowIndex) { // cell originates in this row prevCellFrame = cellFrame; } - else { + else { // cell originates in a prior row nsTableRowFrame* parentFrame; nsPoint cellOrigin; nsReflowStatus status; // Ask the cell frame's parent to reflow it to the height of all the // rows it spans between its origin and aRowEndY - cellFrame->GetParent((nsIFrame**)&parentFrame); - if (!parentFrame) {NS_ASSERTION(PR_FALSE, "bad parent"); return 0;} + cellFrame->GetParent((nsIFrame**)&parentFrame); if (!parentFrame) ABORT0(); parentFrame->GetOrigin(cellOrigin); nscoord cellAvailHeight = aRowEndY - cellOrigin.y; nscoord cellHeight = parentFrame->ReflowCellFrame(&aPresContext, aReflowState, cellFrame, @@ -965,7 +998,7 @@ nsTableRowGroupFrame::SplitSpanningCells(nsIPresContext& aPresContext, if (contCellFrame) { if (aContRowFrame) { aContRowFrame->InsertCellFrame(contCellFrame, colX); - } + } else { aRowFrame.InsertCellFrame(contCellFrame, prevCellFrame); } @@ -978,10 +1011,8 @@ nsTableRowGroupFrame::SplitSpanningCells(nsIPresContext& aPresContext, aContRowFrame->InsertCellFrame(cellFrame, colX); prevCellFrame = cellFrame; } - tallestCell = PR_MAX(tallestCell, cellHeight); } } - return tallestCell; } nsresult @@ -1008,32 +1039,40 @@ nsTableRowGroupFrame::SplitRowGroup(nsIPresContext* aPresContext, nscoord availWidth = nsTableFrame::RoundToPixel(aReflowState.availableWidth, p2t); nscoord availHeight = nsTableFrame::RoundToPixel(aReflowState.availableHeight, p2t); - nscoord lastDesiredHeight = 0; + + // get the page height + nsRect actualRect; + nsRect adjRect; + aPresContext->GetPageDim(&actualRect, &adjRect); + nscoord pageHeight = actualRect.height; + + PRBool isTopOfPage = aReflowState.mFlags.mIsTopOfPage; + nscoord cellSpacingY = aTableFrame->GetCellSpacingY(); // Walk each of the row frames looking for the first row frame that // doesn't fit in the available space for (nsTableRowFrame* rowFrame = GetFirstRow(); rowFrame; rowFrame = rowFrame->GetNextRow()) { PRBool rowIsOnCurrentPage = PR_TRUE; - PRBool degenerateRow = PR_FALSE; nsRect bounds; rowFrame->GetRect(bounds); if (bounds.YMost() > availHeight) { - nsRect actualRect; - nsRect adjRect; - aPresContext->GetPageDim(&actualRect, &adjRect); nsIFrame* contRowFrame = nsnull; - nscoord pageHeight = actualRect.height; // reflow the row in the availabe space and have it split if it is the 1st // row or there is at least 5% of the current page available if (!prevRowFrame || (availHeight - aDesiredSize.height > pageHeight / 20)) { - // Reflow the row in the available space and have it split nsSize availSize(availWidth, PR_MAX(availHeight - bounds.y, 0)); + // don't let the available height exceed what CalculateRowHeights set for it + availSize.height = PR_MIN(availSize.height, bounds.height); + nsHTMLReflowState rowReflowState(aPresContext, aReflowState, rowFrame, availSize, eReflowReason_Resize); InitChildReflowState(*aPresContext, borderCollapse, p2t, rowReflowState); + rowReflowState.mFlags.mIsTopOfPage = isTopOfPage; // set top of page nsHTMLReflowMetrics desiredSize(nsnull); + // A row that has all originating cells with rowspan>1 will return a desired height + // of the largest cell (in contrast to an unconstrained height reflow which returns 0). rv = ReflowChild(rowFrame, aPresContext, desiredSize, rowReflowState, 0, 0, NS_FRAME_NO_MOVE_FRAME, aStatus); rowFrame->SizeTo(aPresContext, desiredSize.width, desiredSize.height); @@ -1042,27 +1081,26 @@ nsTableRowGroupFrame::SplitRowGroup(nsIPresContext* aPresContext, if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { // the row frame is incomplete and all of the cells' block frames have split - CreateContinuingRowFrame(*aPresContext, *styleSet.get(), *rowFrame, &contRowFrame); - aDesiredSize.height += desiredSize.height; - if (prevRowFrame) { - aDesiredSize.height += aTableFrame->GetCellSpacingY(); - } - } - else if (0 == desiredSize.height) { - // the row frame is complete because it had no cells originating in it. - CreateContinuingRowFrame(*aPresContext, *styleSet.get(), *rowFrame, &contRowFrame); - aStatus = NS_FRAME_NOT_COMPLETE; - aDesiredSize.height = availHeight; - degenerateRow = PR_TRUE; - } - else { - // the row frame is complete because it's minimum height was greater than the - // the available height we gave it - if (aDesiredSize.height > 0) { - // put the row on the next page since it needs more height than it was given - rowIsOnCurrentPage = PR_FALSE; + if ((desiredSize.height <= rowReflowState.availableHeight) || isTopOfPage) { + // the row stays on this page because either it split ok or we're on the top of page + // if top of page and the height exceeded the avail height,then there will be data loss + NS_WARN_IF_FALSE(desiredSize.height <= rowReflowState.availableHeight, + "data loss - incomplete row needed more height than available, on top of page"); + CreateContinuingRowFrame(*aPresContext, *styleSet.get(), *rowFrame, &contRowFrame); + aDesiredSize.height += desiredSize.height; + if (prevRowFrame) + aDesiredSize.height += cellSpacingY; } else { + // put the row on the next page to give it more height + rowIsOnCurrentPage = PR_FALSE; + } + } + else { + // The row frame is complete because it's minimum height was greater than the + // the available height we gave it. + if (isTopOfPage) { + // We're on top of the page, so keep the row on this page. There will be data loss. nsIFrame* nextRowFrame; // Push the row frame that follows @@ -1070,32 +1108,45 @@ nsTableRowGroupFrame::SplitRowGroup(nsIPresContext* aPresContext, if (nextRowFrame) { PushChildren(aPresContext, nextRowFrame, rowFrame); + aStatus = NS_FRAME_NOT_COMPLETE; } - aStatus = nextRowFrame ? NS_FRAME_NOT_COMPLETE : NS_FRAME_COMPLETE; - aDesiredSize.height = bounds.YMost(); + aDesiredSize.height += desiredSize.height; + if (prevRowFrame) + aDesiredSize.height += cellSpacingY; + NS_WARN_IF_FALSE(PR_FALSE, "data loss - complete row needed more height than available, on top of page"); + } + else { + // We're not on top of the page, so put the row on the next page to give it more height + rowIsOnCurrentPage = PR_FALSE; } } } - else rowIsOnCurrentPage = PR_FALSE; - - if (!rowIsOnCurrentPage) { - // Push this row frame and those that follow to the next-in-flow - PushChildren(aPresContext, rowFrame, prevRowFrame); - aStatus = NS_FRAME_NOT_COMPLETE; + else { + // put the row on the next page to give it more height + rowIsOnCurrentPage = PR_FALSE; } - if (prevRowFrame) { - nscoord tallestCell = - SplitSpanningCells(*aPresContext, aReflowState, *styleSet, *aTableFrame, - *rowFrame, aDesiredSize.height, (nsTableRowFrame*)contRowFrame); - if (degenerateRow) { - aDesiredSize.height = lastDesiredHeight + aTableFrame->GetCellSpacingY() + tallestCell; + + PRBool willGetAnotherReflow = PR_FALSE; + if (!rowIsOnCurrentPage) { + if (prevRowFrame) { + PushChildren(aPresContext, rowFrame, prevRowFrame); + aStatus = NS_FRAME_NOT_COMPLETE; } + else { + // We can't push children, so let our parent reflow us again with more space + aDesiredSize.height = bounds.YMost(); + willGetAnotherReflow = PR_TRUE; + } + } + + if (prevRowFrame && !willGetAnotherReflow) { + SplitSpanningCells(*aPresContext, aReflowState, *styleSet, *aTableFrame, + *rowFrame, aDesiredSize.height, (nsTableRowFrame*)contRowFrame); } break; } else { aDesiredSize.height = bounds.YMost(); - lastDesiredHeight = aDesiredSize.height; prevRowFrame = rowFrame; // see if there is a page break after the row nsTableRowFrame* nextRow = rowFrame->GetNextRow(); @@ -1105,22 +1156,11 @@ nsTableRowGroupFrame::SplitRowGroup(nsIPresContext* aPresContext, break; } } + isTopOfPage = PR_FALSE; // after the 1st row, we can't be on top of the page any more. } return NS_OK; } -static void -CacheRowHeightsForPrinting(nsIPresContext* aPresContext, - nsTableRowFrame* aFirstRow) -{ - for (nsTableRowFrame* row = aFirstRow; row; row = row->GetNextRow()) { - nsRect rect; - row->GetRect(rect); - row->SetHasUnpaginatedHeight(PR_TRUE); - row->SetUnpaginatedHeight(aPresContext, rect.height); - } -} - /** Layout the entire row group. * This method stacks rows vertically according to HTML 4.0 rules. * Rows are responsible for layout of their children. @@ -1157,10 +1197,6 @@ nsTableRowGroupFrame::Reflow(nsIPresContext* aPresContext, // Check for an overflow list MoveOverflowToChildList(aPresContext); - if (isPaginated && aReflowState.mFlags.mSpecialHeightReflow) { - // cache row height info for printing, now that row heights are known. - CacheRowHeightsForPrinting(aPresContext, GetFirstRow()); - } // Reflow the existing frames. PRBool splitDueToPageBreak = PR_FALSE; rv = ReflowChildren(aPresContext, aDesiredSize, state, aStatus, @@ -1181,6 +1217,9 @@ nsTableRowGroupFrame::Reflow(nsIPresContext* aPresContext, // are row spans unless we do this step if (aReflowState.mFlags.mSpecialHeightReflow) { DidResizeRows(*aPresContext, aReflowState); + if (isPaginated) { + CacheRowHeightsForPrinting(aPresContext, GetFirstRow()); + } } else if ((eReflowReason_Initial != aReflowState.reason) || isTableUnconstrainedReflow || diff --git a/mozilla/layout/tables/nsTableRowGroupFrame.h b/mozilla/layout/tables/nsTableRowGroupFrame.h index 789152b5a7e..489243c682d 100644 --- a/mozilla/layout/tables/nsTableRowGroupFrame.h +++ b/mozilla/layout/tables/nsTableRowGroupFrame.h @@ -334,13 +334,13 @@ protected: nsTableFrame* aTableFrame, nsReflowStatus& aStatus); - nscoord SplitSpanningCells(nsIPresContext& aPresContext, - const nsHTMLReflowState& aReflowState, - nsIStyleSet& aStyleSet, - nsTableFrame& aTableFrame, - nsTableRowFrame& aRowFrame, - nscoord aRowEndY, - nsTableRowFrame* aContRowFrame); + void SplitSpanningCells(nsIPresContext& aPresContext, + const nsHTMLReflowState& aReflowState, + nsIStyleSet& aStyleSet, + nsTableFrame& aTableFrame, + nsTableRowFrame& aRowFrame, + nscoord aRowEndY, + nsTableRowFrame* aContRowFrame); void CreateContinuingRowFrame(nsIPresContext& aPresContext, nsIStyleSet& aStyleSet,