From 5b3485bfc6a3b56a3b8028bb7a5afa21a154dd3d Mon Sep 17 00:00:00 2001 From: Bernd Date: Thu, 13 May 2010 16:15:49 +0200 Subject: [PATCH] bug 558574 - fix issues with table footer placement and missed page breaks inside of row groups r=roc --- layout/tables/nsTableFrame.cpp | 82 +++++++++++++++++--------- layout/tables/nsTableFrame.h | 5 +- layout/tables/nsTableRowGroupFrame.cpp | 25 +++++++- layout/tables/nsTableRowGroupFrame.h | 2 + 4 files changed, 82 insertions(+), 32 deletions(-) diff --git a/layout/tables/nsTableFrame.cpp b/layout/tables/nsTableFrame.cpp index 9fd39a3f87f3..55d0423a9077 100644 --- a/layout/tables/nsTableFrame.cpp +++ b/layout/tables/nsTableFrame.cpp @@ -286,20 +286,25 @@ IsRepeatedFrame(nsIFrame* kidFrame) } PRBool -nsTableFrame::PageBreakAfter(nsIFrame& aSourceFrame, +nsTableFrame::PageBreakAfter(nsIFrame* aSourceFrame, nsIFrame* aNextFrame) { - const nsStyleDisplay* display = aSourceFrame.GetStyleDisplay(); + const nsStyleDisplay* display = aSourceFrame->GetStyleDisplay(); + nsTableRowGroupFrame* prevRg = do_QueryFrame(aSourceFrame); // don't allow a page break after a repeated element ... - if (display->mBreakAfter && !IsRepeatedFrame(&aSourceFrame)) { + if (display->mBreakAfter || (prevRg && prevRg->HasInternalBreakAfter()) && + !IsRepeatedFrame(aSourceFrame)) { return !(aNextFrame && IsRepeatedFrame(aNextFrame)); // or before } if (aNextFrame) { display = aNextFrame->GetStyleDisplay(); // don't allow a page break before a repeated element ... - if (display->mBreakBefore && !IsRepeatedFrame(aNextFrame)) { - return !IsRepeatedFrame(&aSourceFrame); // or after + nsTableRowGroupFrame* nextRg = do_QueryFrame(aNextFrame); + if (display->mBreakBefore || + (nextRg && nextRg->HasInternalBreakBefore()) && + !IsRepeatedFrame(aNextFrame)) { + return !IsRepeatedFrame(aSourceFrame); // or after } } return PR_FALSE; @@ -2613,6 +2618,34 @@ nsTableFrame::SetupHeaderFooterChild(const nsTableReflowState& aReflowState, return NS_OK; } +void +nsTableFrame::PlaceRepeatedFooter(nsTableReflowState& aReflowState, + nsTableRowGroupFrame *aTfoot, + nscoord aFooterHeight) +{ + nsPresContext* presContext = PresContext(); + nsSize kidAvailSize(aReflowState.availSize); + kidAvailSize.height = aFooterHeight; + nsHTMLReflowState footerReflowState(presContext, + aReflowState.reflowState, + aTfoot, kidAvailSize, + -1, -1, PR_FALSE); + InitChildReflowState(footerReflowState); + aReflowState.y += GetCellSpacingY(); + + nsRect origTfootRect = aTfoot->GetRect(); + nsRect origTfootOverflowRect = aTfoot->GetOverflowRect(); + + nsReflowStatus footerStatus; + nsHTMLReflowMetrics desiredSize; + desiredSize.width = desiredSize.height = 0; + ReflowChild(aTfoot, presContext, desiredSize, footerReflowState, + aReflowState.x, aReflowState.y, + NS_FRAME_INVALIDATE_ON_MOVE, footerStatus); + PlaceChild(aReflowState, aTfoot, desiredSize, origTfootRect, + origTfootOverflowRect); +} + // Reflow the children based on the avail size and reason in aReflowState // update aReflowMetrics a aStatus NS_METHOD @@ -2630,7 +2663,8 @@ nsTableFrame::ReflowChildren(nsTableReflowState& aReflowState, nsPresContext* presContext = PresContext(); // XXXldb Should we be checking constrained height instead? - PRBool isPaginated = presContext->IsPaginated(); + PRBool isPaginated = presContext->IsPaginated() && + NS_UNCONSTRAINEDSIZE != aReflowState.availSize.height; aOverflowArea = nsRect (0, 0, 0, 0); @@ -2665,7 +2699,8 @@ nsTableFrame::ReflowChildren(nsTableReflowState& aReflowState, return rv; } } - + // if the child is a tbody in paginated mode reduce the height by a repeated footer + PRBool allowRepeatedFooter = PR_FALSE; for (PRUint32 childX = 0; childX < rowGroups.Length(); childX++) { nsIFrame* kidFrame = rowGroups[childX]; // Get the frame state bits @@ -2677,13 +2712,15 @@ nsTableFrame::ReflowChildren(nsTableReflowState& aReflowState, NS_FRAME_CONTAINS_RELATIVE_HEIGHT)))) { if (pageBreak) { PushChildren(rowGroups, childX); + if (allowRepeatedFooter) { + PlaceRepeatedFooter(aReflowState, tfoot, footerHeight); + } aStatus = NS_FRAME_NOT_COMPLETE; break; } nsSize kidAvailSize(aReflowState.availSize); - // if the child is a tbody in paginated mode reduce the height by a repeated footer - PRBool allowRepeatedFooter = PR_FALSE; + allowRepeatedFooter = PR_FALSE; if (isPaginated && (NS_UNCONSTRAINEDSIZE != kidAvailSize.height)) { nsTableRowGroupFrame* kidRG = static_cast(kidFrame); @@ -2754,6 +2791,9 @@ nsTableFrame::ReflowChildren(nsTableReflowState& aReflowState, if (nextRowGroupFrame) { PlaceChild(aReflowState, kidFrame, desiredSize, oldKidRect, oldKidOverflowRect); + if (allowRepeatedFooter) { + PlaceRepeatedFooter(aReflowState, tfoot, footerHeight); + } aStatus = NS_FRAME_NOT_COMPLETE; PushChildren(rowGroups, childX + 1); aLastChildReflowed = kidFrame; @@ -2763,7 +2803,9 @@ nsTableFrame::ReflowChildren(nsTableReflowState& aReflowState, } else { // we are not on top, push this rowgroup onto the next page if (prevKidFrame) { // we had a rowgroup before so push this - // XXXroc shouldn't we add a repeated footer here? + if (allowRepeatedFooter) { + PlaceRepeatedFooter(aReflowState, tfoot, footerHeight); + } aStatus = NS_FRAME_NOT_COMPLETE; PushChildren(rowGroups, childX); aLastChildReflowed = prevKidFrame; @@ -2780,7 +2822,7 @@ nsTableFrame::ReflowChildren(nsTableReflowState& aReflowState, (NS_UNCONSTRAINEDSIZE != kidReflowState.availableHeight)) { nsIFrame* nextKid = (childX + 1 < rowGroups.Length()) ? rowGroups[childX + 1] : nsnull; - pageBreak = PageBreakAfter(*kidFrame, nextKid); + pageBreak = PageBreakAfter(kidFrame, nextKid); } // Place the child @@ -2823,23 +2865,7 @@ nsTableFrame::ReflowChildren(nsTableReflowState& aReflowState, PushChildren(rowGroups, childX + 1); } if (allowRepeatedFooter) { - kidAvailSize.height = footerHeight; - nsHTMLReflowState footerReflowState(presContext, - aReflowState.reflowState, - tfoot, kidAvailSize, - -1, -1, PR_FALSE); - InitChildReflowState(footerReflowState); - aReflowState.y += cellSpacingY; - - nsRect origTfootRect = tfoot->GetRect(); - nsRect origTfootOverflowRect = tfoot->GetOverflowRect(); - - nsReflowStatus footerStatus; - rv = ReflowChild(tfoot, presContext, desiredSize, footerReflowState, - aReflowState.x, aReflowState.y, - NS_FRAME_INVALIDATE_ON_MOVE, footerStatus); - PlaceChild(aReflowState, tfoot, desiredSize, origTfootRect, - origTfootOverflowRect); + PlaceRepeatedFooter(aReflowState, tfoot, footerHeight); } break; } diff --git a/layout/tables/nsTableFrame.h b/layout/tables/nsTableFrame.h index 714281ce4230..706749f5519a 100644 --- a/layout/tables/nsTableFrame.h +++ b/layout/tables/nsTableFrame.h @@ -177,7 +177,7 @@ public: static void RePositionViews(nsIFrame* aFrame); - static PRBool PageBreakAfter(nsIFrame& aSourceFrame, + static PRBool PageBreakAfter(nsIFrame* aSourceFrame, nsIFrame* aNextFrame); nsPoint GetFirstSectionOrigin(const nsHTMLReflowState& aReflowState) const; @@ -607,6 +607,9 @@ protected: nsHTMLReflowMetrics& aKidDesiredSize, const nsRect& aOriginalKidRect, const nsRect& aOriginalKidOverflowRect); + void PlaceRepeatedFooter(nsTableReflowState& aReflowState, + nsTableRowGroupFrame *aTfoot, + nscoord aFooterHeight); nsIFrame* GetFirstBodyRowGroupFrame(); public: diff --git a/layout/tables/nsTableRowGroupFrame.cpp b/layout/tables/nsTableRowGroupFrame.cpp index aa613720f7d7..804e154931f8 100644 --- a/layout/tables/nsTableRowGroupFrame.cpp +++ b/layout/tables/nsTableRowGroupFrame.cpp @@ -363,7 +363,8 @@ nsTableRowGroupFrame::ReflowChildren(nsPresContext* aPresContext, // XXXldb Should we really be checking this rather than available height? // (Think about multi-column layout!) - PRBool isPaginated = aPresContext->IsPaginated(); + PRBool isPaginated = aPresContext->IsPaginated() && + NS_UNCONSTRAINEDSIZE != aReflowState.availSize.height; PRBool haveRow = PR_FALSE; PRBool reflowAllKids = aReflowState.reflowState.ShouldReflowAllKids() || @@ -459,7 +460,7 @@ nsTableRowGroupFrame::ReflowChildren(nsPresContext* aPresContext, if (isPaginated && aPageBreakBeforeEnd && !*aPageBreakBeforeEnd) { nsTableRowFrame* nextRow = rowFrame->GetNextRow(); if (nextRow) { - *aPageBreakBeforeEnd = nsTableFrame::PageBreakAfter(*kidFrame, nextRow); + *aPageBreakBeforeEnd = nsTableFrame::PageBreakAfter(kidFrame, nextRow); } } } else { @@ -1268,7 +1269,7 @@ nsTableRowGroupFrame::SplitRowGroup(nsPresContext* aPresContext, prevRowFrame = rowFrame; // see if there is a page break after the row nsTableRowFrame* nextRow = rowFrame->GetNextRow(); - if (nextRow && nsTableFrame::PageBreakAfter(*rowFrame, nextRow)) { + if (nextRow && nsTableFrame::PageBreakAfter(rowFrame, nextRow)) { PushChildren(aPresContext, nextRow, rowFrame); aStatus = NS_FRAME_NOT_COMPLETE; break; @@ -1569,7 +1570,25 @@ nsTableRowGroupFrame::GetType() const return nsGkAtoms::tableRowGroupFrame; } +/** find page break before the first row **/ +PRBool +nsTableRowGroupFrame::HasInternalBreakBefore() const +{ + nsIFrame* firstChild = mFrames.FirstChild(); + if (!firstChild) + return PR_FALSE; + return firstChild->GetStyleDisplay()->mBreakBefore; +} +/** find page break after the last row **/ +PRBool +nsTableRowGroupFrame::HasInternalBreakAfter() const +{ + nsIFrame* lastChild = mFrames.LastChild(); + if (!lastChild) + return PR_FALSE; + return lastChild->GetStyleDisplay()->mBreakAfter; +} /* ----- global methods ----- */ nsIFrame* diff --git a/layout/tables/nsTableRowGroupFrame.h b/layout/tables/nsTableRowGroupFrame.h index 985a6eb8335e..c7376165e655 100644 --- a/layout/tables/nsTableRowGroupFrame.h +++ b/layout/tables/nsTableRowGroupFrame.h @@ -436,6 +436,8 @@ public: void SetRepeatable(PRBool aRepeatable); PRBool HasStyleHeight() const; void SetHasStyleHeight(PRBool aValue); + PRBool HasInternalBreakBefore() const; + PRBool HasInternalBreakAfter() const; };