From 773d4220731f45d4129b9a3fd90df688a5e772d3 Mon Sep 17 00:00:00 2001 From: "karnaze%netscape.com" Date: Sun, 17 Mar 2002 21:35:08 +0000 Subject: [PATCH] bug 24000 - implement page-break-before/after:always using new nsPageBreakFrame. Tables handle page breaks internally. a=asa, sr=attinasi, r=alexsavulov --- content/base/src/nsRuleNode.cpp | 13 ++- content/html/style/src/nsCSSDeclaration.cpp | 98 +++++++++++----- content/html/style/src/nsCSSDeclaration.h | 4 + content/html/style/src/nsCSSStruct.cpp | 98 +++++++++++----- content/html/style/src/nsCSSStruct.h | 4 + content/html/style/src/nsCSSStyleRule.cpp | 7 ++ content/shared/public/nsCSSKeywordList.h | 1 + content/shared/public/nsLayoutAtomList.h | 2 + content/shared/src/nsCSSProps.cpp | 1 + layout/base/nsCSSFrameConstructor.cpp | 109 +++++++++++++++--- layout/base/nsCSSFrameConstructor.h | 19 +++ layout/base/nsLayoutAtomList.h | 2 + layout/base/nsStyleConsts.h | 1 + layout/base/public/nsStyleConsts.h | 1 + layout/generic/nsHTMLParts.h | 1 + layout/generic/nsPageFrame.cpp | 87 ++++++++++++++ layout/generic/nsPageFrame.h | 24 ++++ layout/html/base/src/nsHTMLParts.h | 1 + layout/html/base/src/nsPageFrame.cpp | 87 ++++++++++++++ layout/html/base/src/nsPageFrame.h | 24 ++++ layout/html/document/src/html.css | 6 + .../html/style/src/nsCSSFrameConstructor.cpp | 109 +++++++++++++++--- layout/html/style/src/nsCSSFrameConstructor.h | 19 +++ layout/html/table/src/nsTableFrame.cpp | 49 +++++++- layout/html/table/src/nsTableFrame.h | 3 + .../html/table/src/nsTableRowGroupFrame.cpp | 29 ++++- layout/html/table/src/nsTableRowGroupFrame.h | 3 +- layout/style/html.css | 6 + layout/style/nsCSSDeclaration.cpp | 98 +++++++++++----- layout/style/nsCSSDeclaration.h | 4 + layout/style/nsCSSKeywordList.h | 1 + layout/style/nsCSSProps.cpp | 1 + layout/style/nsCSSStruct.cpp | 98 +++++++++++----- layout/style/nsCSSStruct.h | 4 + layout/style/nsCSSStyleRule.cpp | 7 ++ layout/style/nsRuleNode.cpp | 13 ++- layout/tables/nsTableFrame.cpp | 49 +++++++- layout/tables/nsTableFrame.h | 3 + layout/tables/nsTableRowGroupFrame.cpp | 29 ++++- layout/tables/nsTableRowGroupFrame.h | 3 +- 40 files changed, 946 insertions(+), 172 deletions(-) diff --git a/content/base/src/nsRuleNode.cpp b/content/base/src/nsRuleNode.cpp index a7163fdbc573..966ba320f4ad 100644 --- a/content/base/src/nsRuleNode.cpp +++ b/content/base/src/nsRuleNode.cpp @@ -783,7 +783,9 @@ static const PropertyCheckData DisplayCheckProperties[] = { CHECKDATA_PROP(nsCSSDisplay, mPosition, CHECKDATA_VALUE, PR_FALSE), CHECKDATA_PROP(nsCSSDisplay, mFloat, CHECKDATA_VALUE, PR_FALSE), CHECKDATA_PROP(nsCSSDisplay, mClear, CHECKDATA_VALUE, PR_FALSE), - CHECKDATA_PROP(nsCSSDisplay, mOverflow, CHECKDATA_VALUE, PR_FALSE) + CHECKDATA_PROP(nsCSSDisplay, mOverflow, CHECKDATA_VALUE, PR_FALSE), + CHECKDATA_PROP(nsCSSDisplay, mBreakBefore, CHECKDATA_VALUE, PR_FALSE), // temp fix for bug 2400 + CHECKDATA_PROP(nsCSSDisplay, mBreakAfter, CHECKDATA_VALUE, PR_FALSE) // temp fix for bug 2400 }; static const PropertyCheckData VisibilityCheckProperties[] = { @@ -2824,6 +2826,15 @@ nsRuleNode::ComputeDisplayData(nsStyleStruct* aStartStruct, const nsCSSStruct& a display->mBreakType = parentDisplay->mBreakType; } + // temp fix for bug 24000 + if (eCSSUnit_Enumerated == displayData.mBreakBefore.GetUnit()) { + display->mBreakBefore = (NS_STYLE_PAGE_BREAK_ALWAYS == displayData.mBreakBefore.GetIntValue()); + } + if (eCSSUnit_Enumerated == displayData.mBreakAfter.GetUnit()) { + display->mBreakAfter = (NS_STYLE_PAGE_BREAK_ALWAYS == displayData.mBreakAfter.GetIntValue()); + } + // end temp fix + // float: enum, none, inherit if (eCSSUnit_Enumerated == displayData.mFloat.GetUnit()) { display->mFloats = displayData.mFloat.GetIntValue(); diff --git a/content/html/style/src/nsCSSDeclaration.cpp b/content/html/style/src/nsCSSDeclaration.cpp index 5c2a754be8c8..cd2584b1116d 100644 --- a/content/html/style/src/nsCSSDeclaration.cpp +++ b/content/html/style/src/nsCSSDeclaration.cpp @@ -379,6 +379,10 @@ nsCSSDisplay::nsCSSDisplay(const nsCSSDisplay& aCopy) mPosition(aCopy.mPosition), mFloat(aCopy.mFloat), mClear(aCopy.mClear), + // temp fix for bug 24000 + mBreakBefore(aCopy.mBreakBefore), + mBreakAfter(aCopy.mBreakAfter), + // end temp mClip(nsnull), mOverflow(aCopy.mOverflow), mVisibility(aCopy.mVisibility), @@ -1794,18 +1798,26 @@ nsCSSDeclaration::AppendValue(nsCSSProperty aProperty, const nsCSSValue& aValue) // nsCSSBreaks case eCSSProperty_orphans: case eCSSProperty_widows: - case eCSSProperty_page: - case eCSSProperty_page_break_after: - case eCSSProperty_page_break_before: - case eCSSProperty_page_break_inside: { + case eCSSProperty_page: { CSS_ENSURE(Breaks) { switch (aProperty) { case eCSSProperty_orphans: theBreaks->mOrphans = aValue; break; case eCSSProperty_widows: theBreaks->mWidows = aValue; break; case eCSSProperty_page: theBreaks->mPage = aValue; break; - case eCSSProperty_page_break_after: theBreaks->mPageBreakAfter = aValue; break; - case eCSSProperty_page_break_before: theBreaks->mPageBreakBefore = aValue; break; - case eCSSProperty_page_break_inside: theBreaks->mPageBreakInside = aValue; break; + CSS_BOGUS_DEFAULT; // make compiler happy + } + } + break; + } + case eCSSProperty_page_break_after: + case eCSSProperty_page_break_before: + case eCSSProperty_page_break_inside: { + // temp fix for bug 24000 + CSS_ENSURE(Display) { + switch (aProperty) { + case eCSSProperty_page_break_after: theDisplay->mBreakAfter = aValue; break; + case eCSSProperty_page_break_before: theDisplay->mBreakBefore = aValue; break; + case eCSSProperty_page_break_inside: break; CSS_BOGUS_DEFAULT; // make compiler happy } } @@ -2739,10 +2751,7 @@ nsCSSDeclaration::SetValueImportant(nsCSSProperty aProperty) // nsCSSBreaks case eCSSProperty_orphans: case eCSSProperty_widows: - case eCSSProperty_page: - case eCSSProperty_page_break_after: - case eCSSProperty_page_break_before: - case eCSSProperty_page_break_inside: { + case eCSSProperty_page: { CSS_VARONSTACK_GET(Breaks); if (nsnull != theBreaks) { CSS_ENSURE_IMPORTANT(Breaks) { @@ -2750,9 +2759,22 @@ nsCSSDeclaration::SetValueImportant(nsCSSProperty aProperty) CSS_CASE_IMPORTANT(eCSSProperty_orphans, Breaks, mOrphans); CSS_CASE_IMPORTANT(eCSSProperty_widows, Breaks, mWidows); CSS_CASE_IMPORTANT(eCSSProperty_page, Breaks, mPage); - CSS_CASE_IMPORTANT(eCSSProperty_page_break_after, Breaks, mPageBreakAfter); - CSS_CASE_IMPORTANT(eCSSProperty_page_break_before, Breaks, mPageBreakBefore); - CSS_CASE_IMPORTANT(eCSSProperty_page_break_inside, Breaks, mPageBreakInside); + CSS_BOGUS_DEFAULT; // make compiler happy + } + } + } + break; + } + case eCSSProperty_page_break_after: + case eCSSProperty_page_break_before: + case eCSSProperty_page_break_inside: { + // temp fix for bug 24000 + CSS_VARONSTACK_GET(Display); + if (theDisplay) { + CSS_ENSURE_IMPORTANT(Display) { + switch (aProperty) { + CSS_CASE_IMPORTANT(eCSSProperty_page_break_after, Display, mBreakAfter); + CSS_CASE_IMPORTANT(eCSSProperty_page_break_before, Display, mBreakBefore); CSS_BOGUS_DEFAULT; // make compiler happy } } @@ -3593,24 +3615,30 @@ nsCSSDeclaration::RemoveProperty(nsCSSProperty aProperty) // nsCSSBreaks case eCSSProperty_orphans: case eCSSProperty_widows: - case eCSSProperty_page: - case eCSSProperty_page_break_after: - case eCSSProperty_page_break_before: - case eCSSProperty_page_break_inside: { + case eCSSProperty_page: { CSS_CHECK(Breaks) { switch (aProperty) { case eCSSProperty_orphans: theBreaks->mOrphans.Reset(); break; case eCSSProperty_widows: theBreaks->mWidows.Reset(); break; case eCSSProperty_page: theBreaks->mPage.Reset(); break; - case eCSSProperty_page_break_after: theBreaks->mPageBreakAfter.Reset(); break; - case eCSSProperty_page_break_before: theBreaks->mPageBreakBefore.Reset(); break; - case eCSSProperty_page_break_inside: theBreaks->mPageBreakInside.Reset(); break; CSS_BOGUS_DEFAULT; // make compiler happy } } break; } - + case eCSSProperty_page_break_after: + case eCSSProperty_page_break_before: + case eCSSProperty_page_break_inside: { + // temp fix for bug 24000 + CSS_CHECK(Display) { + switch (aProperty) { + case eCSSProperty_page_break_after: theDisplay->mBreakAfter.Reset(); break; + case eCSSProperty_page_break_before: theDisplay->mBreakBefore.Reset(); break; + case eCSSProperty_page_break_inside: break; + } + } + break; + } // nsCSSPage case eCSSProperty_marks: case eCSSProperty_size_width: @@ -4432,19 +4460,31 @@ nsCSSDeclaration::GetValue(nsCSSProperty aProperty, nsCSSValue& aValue) // nsCSSBreaks case eCSSProperty_orphans: case eCSSProperty_widows: - case eCSSProperty_page: - case eCSSProperty_page_break_after: - case eCSSProperty_page_break_before: - case eCSSProperty_page_break_inside: { + case eCSSProperty_page: { CSS_VARONSTACK_GET(Breaks); if (nsnull != theBreaks) { switch (aProperty) { case eCSSProperty_orphans: aValue = theBreaks->mOrphans; break; case eCSSProperty_widows: aValue = theBreaks->mWidows; break; case eCSSProperty_page: aValue = theBreaks->mPage; break; - case eCSSProperty_page_break_after: aValue = theBreaks->mPageBreakAfter; break; - case eCSSProperty_page_break_before: aValue = theBreaks->mPageBreakBefore; break; - case eCSSProperty_page_break_inside: aValue = theBreaks->mPageBreakInside; break; + CSS_BOGUS_DEFAULT; // make compiler happy + } + } + else { + aValue.Reset(); + } + break; + } + case eCSSProperty_page_break_after: + case eCSSProperty_page_break_before: + case eCSSProperty_page_break_inside: { + // temp fix for bug 24000 + CSS_VARONSTACK_GET(Display); + if (theDisplay) { + switch (aProperty) { + case eCSSProperty_page_break_inside: aValue.Reset(); break; + case eCSSProperty_page_break_after: aValue = theDisplay->mBreakAfter; break; + case eCSSProperty_page_break_before: aValue = theDisplay->mBreakBefore; break; CSS_BOGUS_DEFAULT; // make compiler happy } } diff --git a/content/html/style/src/nsCSSDeclaration.h b/content/html/style/src/nsCSSDeclaration.h index a0e37a90b500..16070e5a6114 100644 --- a/content/html/style/src/nsCSSDeclaration.h +++ b/content/html/style/src/nsCSSDeclaration.h @@ -240,6 +240,10 @@ struct nsCSSDisplay : public nsCSSStruct { // in nsCSSDeclaration objects but because it's needed on the // stack when the struct is used in WalkRuleTree. nsCSSValue mLang; + // temp fix for bug 24000 + nsCSSValue mBreakBefore; + nsCSSValue mBreakAfter; + // end temp fix }; struct nsCSSMargin : public nsCSSStruct { diff --git a/content/html/style/src/nsCSSStruct.cpp b/content/html/style/src/nsCSSStruct.cpp index 5c2a754be8c8..cd2584b1116d 100644 --- a/content/html/style/src/nsCSSStruct.cpp +++ b/content/html/style/src/nsCSSStruct.cpp @@ -379,6 +379,10 @@ nsCSSDisplay::nsCSSDisplay(const nsCSSDisplay& aCopy) mPosition(aCopy.mPosition), mFloat(aCopy.mFloat), mClear(aCopy.mClear), + // temp fix for bug 24000 + mBreakBefore(aCopy.mBreakBefore), + mBreakAfter(aCopy.mBreakAfter), + // end temp mClip(nsnull), mOverflow(aCopy.mOverflow), mVisibility(aCopy.mVisibility), @@ -1794,18 +1798,26 @@ nsCSSDeclaration::AppendValue(nsCSSProperty aProperty, const nsCSSValue& aValue) // nsCSSBreaks case eCSSProperty_orphans: case eCSSProperty_widows: - case eCSSProperty_page: - case eCSSProperty_page_break_after: - case eCSSProperty_page_break_before: - case eCSSProperty_page_break_inside: { + case eCSSProperty_page: { CSS_ENSURE(Breaks) { switch (aProperty) { case eCSSProperty_orphans: theBreaks->mOrphans = aValue; break; case eCSSProperty_widows: theBreaks->mWidows = aValue; break; case eCSSProperty_page: theBreaks->mPage = aValue; break; - case eCSSProperty_page_break_after: theBreaks->mPageBreakAfter = aValue; break; - case eCSSProperty_page_break_before: theBreaks->mPageBreakBefore = aValue; break; - case eCSSProperty_page_break_inside: theBreaks->mPageBreakInside = aValue; break; + CSS_BOGUS_DEFAULT; // make compiler happy + } + } + break; + } + case eCSSProperty_page_break_after: + case eCSSProperty_page_break_before: + case eCSSProperty_page_break_inside: { + // temp fix for bug 24000 + CSS_ENSURE(Display) { + switch (aProperty) { + case eCSSProperty_page_break_after: theDisplay->mBreakAfter = aValue; break; + case eCSSProperty_page_break_before: theDisplay->mBreakBefore = aValue; break; + case eCSSProperty_page_break_inside: break; CSS_BOGUS_DEFAULT; // make compiler happy } } @@ -2739,10 +2751,7 @@ nsCSSDeclaration::SetValueImportant(nsCSSProperty aProperty) // nsCSSBreaks case eCSSProperty_orphans: case eCSSProperty_widows: - case eCSSProperty_page: - case eCSSProperty_page_break_after: - case eCSSProperty_page_break_before: - case eCSSProperty_page_break_inside: { + case eCSSProperty_page: { CSS_VARONSTACK_GET(Breaks); if (nsnull != theBreaks) { CSS_ENSURE_IMPORTANT(Breaks) { @@ -2750,9 +2759,22 @@ nsCSSDeclaration::SetValueImportant(nsCSSProperty aProperty) CSS_CASE_IMPORTANT(eCSSProperty_orphans, Breaks, mOrphans); CSS_CASE_IMPORTANT(eCSSProperty_widows, Breaks, mWidows); CSS_CASE_IMPORTANT(eCSSProperty_page, Breaks, mPage); - CSS_CASE_IMPORTANT(eCSSProperty_page_break_after, Breaks, mPageBreakAfter); - CSS_CASE_IMPORTANT(eCSSProperty_page_break_before, Breaks, mPageBreakBefore); - CSS_CASE_IMPORTANT(eCSSProperty_page_break_inside, Breaks, mPageBreakInside); + CSS_BOGUS_DEFAULT; // make compiler happy + } + } + } + break; + } + case eCSSProperty_page_break_after: + case eCSSProperty_page_break_before: + case eCSSProperty_page_break_inside: { + // temp fix for bug 24000 + CSS_VARONSTACK_GET(Display); + if (theDisplay) { + CSS_ENSURE_IMPORTANT(Display) { + switch (aProperty) { + CSS_CASE_IMPORTANT(eCSSProperty_page_break_after, Display, mBreakAfter); + CSS_CASE_IMPORTANT(eCSSProperty_page_break_before, Display, mBreakBefore); CSS_BOGUS_DEFAULT; // make compiler happy } } @@ -3593,24 +3615,30 @@ nsCSSDeclaration::RemoveProperty(nsCSSProperty aProperty) // nsCSSBreaks case eCSSProperty_orphans: case eCSSProperty_widows: - case eCSSProperty_page: - case eCSSProperty_page_break_after: - case eCSSProperty_page_break_before: - case eCSSProperty_page_break_inside: { + case eCSSProperty_page: { CSS_CHECK(Breaks) { switch (aProperty) { case eCSSProperty_orphans: theBreaks->mOrphans.Reset(); break; case eCSSProperty_widows: theBreaks->mWidows.Reset(); break; case eCSSProperty_page: theBreaks->mPage.Reset(); break; - case eCSSProperty_page_break_after: theBreaks->mPageBreakAfter.Reset(); break; - case eCSSProperty_page_break_before: theBreaks->mPageBreakBefore.Reset(); break; - case eCSSProperty_page_break_inside: theBreaks->mPageBreakInside.Reset(); break; CSS_BOGUS_DEFAULT; // make compiler happy } } break; } - + case eCSSProperty_page_break_after: + case eCSSProperty_page_break_before: + case eCSSProperty_page_break_inside: { + // temp fix for bug 24000 + CSS_CHECK(Display) { + switch (aProperty) { + case eCSSProperty_page_break_after: theDisplay->mBreakAfter.Reset(); break; + case eCSSProperty_page_break_before: theDisplay->mBreakBefore.Reset(); break; + case eCSSProperty_page_break_inside: break; + } + } + break; + } // nsCSSPage case eCSSProperty_marks: case eCSSProperty_size_width: @@ -4432,19 +4460,31 @@ nsCSSDeclaration::GetValue(nsCSSProperty aProperty, nsCSSValue& aValue) // nsCSSBreaks case eCSSProperty_orphans: case eCSSProperty_widows: - case eCSSProperty_page: - case eCSSProperty_page_break_after: - case eCSSProperty_page_break_before: - case eCSSProperty_page_break_inside: { + case eCSSProperty_page: { CSS_VARONSTACK_GET(Breaks); if (nsnull != theBreaks) { switch (aProperty) { case eCSSProperty_orphans: aValue = theBreaks->mOrphans; break; case eCSSProperty_widows: aValue = theBreaks->mWidows; break; case eCSSProperty_page: aValue = theBreaks->mPage; break; - case eCSSProperty_page_break_after: aValue = theBreaks->mPageBreakAfter; break; - case eCSSProperty_page_break_before: aValue = theBreaks->mPageBreakBefore; break; - case eCSSProperty_page_break_inside: aValue = theBreaks->mPageBreakInside; break; + CSS_BOGUS_DEFAULT; // make compiler happy + } + } + else { + aValue.Reset(); + } + break; + } + case eCSSProperty_page_break_after: + case eCSSProperty_page_break_before: + case eCSSProperty_page_break_inside: { + // temp fix for bug 24000 + CSS_VARONSTACK_GET(Display); + if (theDisplay) { + switch (aProperty) { + case eCSSProperty_page_break_inside: aValue.Reset(); break; + case eCSSProperty_page_break_after: aValue = theDisplay->mBreakAfter; break; + case eCSSProperty_page_break_before: aValue = theDisplay->mBreakBefore; break; CSS_BOGUS_DEFAULT; // make compiler happy } } diff --git a/content/html/style/src/nsCSSStruct.h b/content/html/style/src/nsCSSStruct.h index a0e37a90b500..16070e5a6114 100644 --- a/content/html/style/src/nsCSSStruct.h +++ b/content/html/style/src/nsCSSStruct.h @@ -240,6 +240,10 @@ struct nsCSSDisplay : public nsCSSStruct { // in nsCSSDeclaration objects but because it's needed on the // stack when the struct is used in WalkRuleTree. nsCSSValue mLang; + // temp fix for bug 24000 + nsCSSValue mBreakBefore; + nsCSSValue mBreakAfter; + // end temp fix }; struct nsCSSMargin : public nsCSSStruct { diff --git a/content/html/style/src/nsCSSStyleRule.cpp b/content/html/style/src/nsCSSStyleRule.cpp index dd331b927301..870e3afec960 100644 --- a/content/html/style/src/nsCSSStyleRule.cpp +++ b/content/html/style/src/nsCSSStyleRule.cpp @@ -2306,6 +2306,13 @@ MapDisplayForDeclaration(nsCSSDeclaration* aDecl, const nsStyleStructID& aID, ns if (aDisplay.mClear.GetUnit() == eCSSUnit_Null && ourDisplay->mClear.GetUnit() != eCSSUnit_Null) aDisplay.mClear = ourDisplay->mClear; + // temp fix for bug 24000 + if (aDisplay.mBreakBefore.GetUnit() == eCSSUnit_Null && ourDisplay->mBreakBefore.GetUnit() != eCSSUnit_Null) + aDisplay.mBreakBefore = ourDisplay->mBreakBefore; + if (aDisplay.mBreakAfter.GetUnit() == eCSSUnit_Null && ourDisplay->mBreakAfter.GetUnit() != eCSSUnit_Null) + aDisplay.mBreakAfter = ourDisplay->mBreakAfter; + // end temp fix + // float: enum, none, inherit if (aDisplay.mFloat.GetUnit() == eCSSUnit_Null && ourDisplay->mFloat.GetUnit() != eCSSUnit_Null) aDisplay.mFloat = ourDisplay->mFloat; diff --git a/content/shared/public/nsCSSKeywordList.h b/content/shared/public/nsCSSKeywordList.h index ae3a4dffda9a..2cdca3c9476e 100644 --- a/content/shared/public/nsCSSKeywordList.h +++ b/content/shared/public/nsCSSKeywordList.h @@ -99,6 +99,7 @@ CSS_KEY(-moz-inline-grid, _moz_inline_grid) CSS_KEY(-moz-grid-group, _moz_grid_group) CSS_KEY(-moz-grid-line, _moz_grid_line) CSS_KEY(-moz-groupbox, _moz_groupbox) +CSS_KEY(-moz-page-break, _moz_page_break) CSS_KEY(-moz-popup, _moz_popup) CSS_KEY(-moz-stack, _moz_stack) CSS_KEY(-moz-inline-stack, _moz_inline_stack) diff --git a/content/shared/public/nsLayoutAtomList.h b/content/shared/public/nsLayoutAtomList.h index e9d8760ee788..da4ee21d3966 100644 --- a/content/shared/public/nsLayoutAtomList.h +++ b/content/shared/public/nsLayoutAtomList.h @@ -88,6 +88,7 @@ LAYOUT_ATOM(canvasPseudo, ":canvas") LAYOUT_ATOM(commentTagName, "__moz_comment") LAYOUT_ATOM(dummyOptionPseudo, ":-moz-dummy-option") LAYOUT_ATOM(textTagName, "__moz_text") +LAYOUT_ATOM(pageBreakPseudo, ":-moz-pagebreak") LAYOUT_ATOM(pagePseudo, ":-moz-page") LAYOUT_ATOM(pageContentPseudo, ":-moz-pagecontent") LAYOUT_ATOM(pageSequencePseudo, ":-moz-page-sequence") @@ -116,6 +117,7 @@ LAYOUT_ATOM(lineFrame, "LineFrame") LAYOUT_ATOM(listControlFrame,"ListControlFrame") LAYOUT_ATOM(objectFrame, "ObjectFrame") LAYOUT_ATOM(pageFrame, "PageFrame") +LAYOUT_ATOM(pageBreakFrame, "PageBreakFrame") LAYOUT_ATOM(pageContentFrame, "PageContentFrame") LAYOUT_ATOM(placeholderFrame, "PlaceholderFrame") LAYOUT_ATOM(positionedInlineFrame, "PositionedInlineFrame") diff --git a/content/shared/src/nsCSSProps.cpp b/content/shared/src/nsCSSProps.cpp index c1ebc1bfe649..1cd859550fa6 100644 --- a/content/shared/src/nsCSSProps.cpp +++ b/content/shared/src/nsCSSProps.cpp @@ -409,6 +409,7 @@ const PRInt32 nsCSSProps::kDisplayKTable[] = { eCSSKeyword__moz_bulletinboard, NS_STYLE_DISPLAY_BULLETINBOARD, eCSSKeyword__moz_popup, NS_STYLE_DISPLAY_POPUP, eCSSKeyword__moz_groupbox, NS_STYLE_DISPLAY_GROUPBOX, + eCSSKeyword__moz_page_break, NS_STYLE_DISPLAY_PAGE_BREAK, -1,-1 }; diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index ef8f91b9bbf7..ff870025414f 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -2281,6 +2281,9 @@ nsCSSFrameConstructor::GetParentFrame(nsIPresShell* aPresShell, } // Construct the outer, inner table frames and the children frames for the table. +// XXX Page break frames for pseudo table frames are not constructed to avoid the risk +// associated with revising the pseudo frame mechanism. The long term solution +// of having frames handle page-break-before/after will solve the problem. nsresult nsCSSFrameConstructor::ConstructTableFrame(nsIPresShell* aPresShell, nsIPresContext* aPresContext, @@ -2923,10 +2926,27 @@ nsCSSFrameConstructor::TableProcessChild(nsIPresShell* aPresShell, switch (styleDisplay->mDisplay) { case NS_STYLE_DISPLAY_TABLE: - nsIFrame* innerTableFrame; - rv = ConstructTableFrame(aPresShell, aPresContext, aState, aChildContent, aParentFrame, - childStyleContext, aTableCreator, PR_FALSE, aChildItems, - childFrame, innerTableFrame, isPseudoParent); + { + PRBool pageBreakAfter = PR_FALSE; + PRBool paginated; + aPresContext->IsPaginated(&paginated); + + if (paginated) { + // See if there is a page break before, if so construct one. Also see if there is one after + pageBreakAfter = PageBreakBefore(aPresShell, aPresContext, aState, aChildContent, + aParentFrame, childStyleContext, aChildItems); + } + // construct the table frame + nsIFrame* innerTableFrame; + rv = ConstructTableFrame(aPresShell, aPresContext, aState, aChildContent, aParentFrame, + childStyleContext, aTableCreator, PR_FALSE, aChildItems, + childFrame, innerTableFrame, isPseudoParent); + if (NS_SUCCEEDED(rv) && pageBreakAfter) { + // Construct the page break after + ConstructPageBreakFrame(aPresShell, aPresContext, aState, aChildContent, + aParentFrame, childStyleContext, aChildItems); + } + } break; case NS_STYLE_DISPLAY_TABLE_CAPTION: @@ -6975,8 +6995,56 @@ nsCSSFrameConstructor::ConstructSVGFrame(nsIPresShell* aPresShell, } #endif // MOZ_SVG +PRBool +nsCSSFrameConstructor::PageBreakBefore(nsIPresShell* aPresShell, + nsIPresContext* aPresContext, + nsFrameConstructorState& aState, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsIStyleContext* aStyleContext, + nsFrameItems& aFrameItems) +{ + const nsStyleDisplay* display = (const nsStyleDisplay*) + aStyleContext->GetStyleData(eStyleStruct_Display); + + // See if page-break-before is set for all elements except row groups, rows, cells + // (these are handled internally by tables) and construct a page break frame if so. + if (display && ((NS_STYLE_DISPLAY_TABLE == display->mDisplay) || + (!IsTableRelated(display->mDisplay, PR_TRUE)))) { + if (display->mBreakBefore) { + ConstructPageBreakFrame(aPresShell, aPresContext, aState, aContent, + aParentFrame, aStyleContext, aFrameItems); + } + return display->mBreakAfter; + } + return PR_FALSE; +} + nsresult -nsCSSFrameConstructor::ConstructFrame(nsIPresShell* aPresShell, +nsCSSFrameConstructor::ConstructPageBreakFrame(nsIPresShell* aPresShell, + nsIPresContext* aPresContext, + nsFrameConstructorState& aState, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsIStyleContext* aStyleContext, + nsFrameItems& aFrameItems) +{ + nsCOMPtr pseudoStyle; + aPresContext->ResolvePseudoStyleContextFor(nsnull, nsLayoutAtoms::pageBreakPseudo, + aStyleContext, PR_FALSE, + getter_AddRefs(pseudoStyle)); + nsIFrame* pageBreakFrame; + nsresult rv = NS_NewPageBreakFrame(aPresShell, &pageBreakFrame); + if (NS_SUCCEEDED(rv)) { + InitAndRestoreFrame(aPresContext, aState, aContent, aParentFrame, + pseudoStyle, nsnull, pageBreakFrame); + aFrameItems.AddChild(pageBreakFrame); + } + return rv; +} + +nsresult +nsCSSFrameConstructor::ConstructFrame(nsIPresShell* aPresShell, nsIPresContext* aPresContext, nsFrameConstructorState& aState, nsIContent* aContent, @@ -7006,20 +7074,27 @@ nsCSSFrameConstructor::ConstructFrame(nsIPresShell* aPresShell, rv = ResolveStyleContext(aPresContext, aParentFrame, aContent, getter_AddRefs(styleContext)); - if (NS_SUCCEEDED(rv)) { - + if (NS_SUCCEEDED(rv)) { PRInt32 nameSpaceID; aContent->GetNameSpaceID(nameSpaceID); - rv = ConstructFrameInternal(aPresShell, - aPresContext, - aState, - aContent, - aParentFrame, - tag, - nameSpaceID, - styleContext, - aFrameItems, - PR_FALSE); + + PRBool pageBreakAfter = PR_FALSE; + PRBool paginated; + aPresContext->IsPaginated(&paginated); + + if (paginated) { + // See if there is a page break before, if so construct one. Also see if there is one after + pageBreakAfter = PageBreakBefore(aPresShell, aPresContext, aState, aContent, + aParentFrame, styleContext, aFrameItems); + } + // construct the frame + rv = ConstructFrameInternal(aPresShell, aPresContext, aState, aContent, aParentFrame, + tag, nameSpaceID, styleContext, aFrameItems, PR_FALSE); + if (NS_SUCCEEDED(rv) && pageBreakAfter) { + // Construct the page break after + ConstructPageBreakFrame(aPresShell, aPresContext, aState, aContent, + aParentFrame, styleContext, aFrameItems); + } } return rv; diff --git a/layout/base/nsCSSFrameConstructor.h b/layout/base/nsCSSFrameConstructor.h index 9bcaa23f84e9..135d6121f8ed 100644 --- a/layout/base/nsCSSFrameConstructor.h +++ b/layout/base/nsCSSFrameConstructor.h @@ -535,6 +535,25 @@ protected: nsIStyleContext* aStyleContext, nsFrameItems& aFrameItems); + nsresult ConstructPageBreakFrame(nsIPresShell* aPresShell, + nsIPresContext* aPresContext, + nsFrameConstructorState& aState, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsIStyleContext* aStyleContext, + nsFrameItems& aFrameItems); + + // Construct a page break frame if page-break-before:always is set in aStyleContext + // and add it to aFrameItems. Return true if page-break-after:always is set on aStyleContext. + // Don't do this for row groups, rows or cell, because tables handle those internally. + PRBool PageBreakBefore(nsIPresShell* aPresShell, + nsIPresContext* aPresContext, + nsFrameConstructorState& aState, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsIStyleContext* aStyleContext, + nsFrameItems& aFrameItems); + nsresult ConstructHTMLFrame(nsIPresShell* aPresShell, nsIPresContext* aPresContext, nsFrameConstructorState& aState, diff --git a/layout/base/nsLayoutAtomList.h b/layout/base/nsLayoutAtomList.h index e9d8760ee788..da4ee21d3966 100644 --- a/layout/base/nsLayoutAtomList.h +++ b/layout/base/nsLayoutAtomList.h @@ -88,6 +88,7 @@ LAYOUT_ATOM(canvasPseudo, ":canvas") LAYOUT_ATOM(commentTagName, "__moz_comment") LAYOUT_ATOM(dummyOptionPseudo, ":-moz-dummy-option") LAYOUT_ATOM(textTagName, "__moz_text") +LAYOUT_ATOM(pageBreakPseudo, ":-moz-pagebreak") LAYOUT_ATOM(pagePseudo, ":-moz-page") LAYOUT_ATOM(pageContentPseudo, ":-moz-pagecontent") LAYOUT_ATOM(pageSequencePseudo, ":-moz-page-sequence") @@ -116,6 +117,7 @@ LAYOUT_ATOM(lineFrame, "LineFrame") LAYOUT_ATOM(listControlFrame,"ListControlFrame") LAYOUT_ATOM(objectFrame, "ObjectFrame") LAYOUT_ATOM(pageFrame, "PageFrame") +LAYOUT_ATOM(pageBreakFrame, "PageBreakFrame") LAYOUT_ATOM(pageContentFrame, "PageContentFrame") LAYOUT_ATOM(placeholderFrame, "PlaceholderFrame") LAYOUT_ATOM(positionedInlineFrame, "PositionedInlineFrame") diff --git a/layout/base/nsStyleConsts.h b/layout/base/nsStyleConsts.h index 888a2eb9c228..ff0dbc10ffca 100644 --- a/layout/base/nsStyleConsts.h +++ b/layout/base/nsStyleConsts.h @@ -336,6 +336,7 @@ #define NS_STYLE_DISPLAY_BULLETINBOARD 27 #define NS_STYLE_DISPLAY_POPUP 28 #define NS_STYLE_DISPLAY_GROUPBOX 29 +#define NS_STYLE_DISPLAY_PAGE_BREAK 30 // See nsStyleDisplay #define NS_STYLE_FLOAT_NONE 0 diff --git a/layout/base/public/nsStyleConsts.h b/layout/base/public/nsStyleConsts.h index 888a2eb9c228..ff0dbc10ffca 100644 --- a/layout/base/public/nsStyleConsts.h +++ b/layout/base/public/nsStyleConsts.h @@ -336,6 +336,7 @@ #define NS_STYLE_DISPLAY_BULLETINBOARD 27 #define NS_STYLE_DISPLAY_POPUP 28 #define NS_STYLE_DISPLAY_GROUPBOX 29 +#define NS_STYLE_DISPLAY_PAGE_BREAK 30 // See nsStyleDisplay #define NS_STYLE_FLOAT_NONE 0 diff --git a/layout/generic/nsHTMLParts.h b/layout/generic/nsHTMLParts.h index 0e07379bbee3..5b4277dcd3cd 100644 --- a/layout/generic/nsHTMLParts.h +++ b/layout/generic/nsHTMLParts.h @@ -170,6 +170,7 @@ extern nsresult NS_NewScrollFrame(nsIPresShell* aPresShell, nsIFrame** aResult); extern nsresult NS_NewSimplePageSequenceFrame(nsIPresShell* aPresShell, nsIFrame** aResult); extern nsresult NS_NewPageFrame(nsIPresShell* aPresShell, nsIFrame** aResult); extern nsresult NS_NewPageContentFrame(nsIPresShell* aPresShell, nsIFrame** aResult); +extern nsresult NS_NewPageBreakFrame(nsIPresShell* aPresShell, nsIFrame** aResult); extern nsresult NS_NewFirstLetterFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame); extern nsresult NS_NewFirstLineFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame); diff --git a/layout/generic/nsPageFrame.cpp b/layout/generic/nsPageFrame.cpp index 65ab958103dd..28c99e61a011 100644 --- a/layout/generic/nsPageFrame.cpp +++ b/layout/generic/nsPageFrame.cpp @@ -759,3 +759,90 @@ nsPageFrame::DrawBackground(nsIPresContext* aPresContext, } } +nsresult +NS_NewPageBreakFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame) +{ + NS_PRECONDITION(aPresShell && aNewFrame, "null PresShell or OUT ptr"); +#ifdef DEBUG + //check that we are only creating page break frames when printing + nsCOMPtr presContext; + aPresShell->GetPresContext(getter_AddRefs(presContext)); + PRBool isPaginated; + presContext->IsPaginated(&isPaginated); + NS_ASSERTION(isPaginated, "created a page break frame while not printing"); +#endif + + nsPageBreakFrame* it = new (aPresShell) nsPageBreakFrame; + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + *aNewFrame = it; + return NS_OK; +} + +nsPageBreakFrame::nsPageBreakFrame() +: mHaveReflowed(PR_FALSE) +{ +} + +nsPageBreakFrame::~nsPageBreakFrame() +{ +} + +void +nsPageBreakFrame::GetDesiredSize(nsIPresContext* aPresContext, + const nsHTMLReflowState& aReflowState, + nsHTMLReflowMetrics& aDesiredSize) +{ + NS_PRECONDITION(aPresContext, "null pres context"); + float p2t; + aPresContext->GetScaledPixelsToTwips(&p2t); + nscoord onePixel = NSToCoordRound(p2t); + + aDesiredSize.width = onePixel; + if (mHaveReflowed) { + // If blocks reflow us a 2nd time trying to put us on a new page, then return + // a desired height of 0 to avoid an extra page break. + aDesiredSize.height = 0; + } + else { + aDesiredSize.height = aReflowState.availableHeight; + // round the height down to the nearest pixel + aDesiredSize.height -= aDesiredSize.height % onePixel; + } + + if (aDesiredSize.maxElementSize) { + aDesiredSize.maxElementSize->width = onePixel; + aDesiredSize.maxElementSize->height = aDesiredSize.height; + } + aDesiredSize.ascent = 0; + aDesiredSize.descent = 0; +} + +nsresult +nsPageBreakFrame::Reflow(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus) +{ + NS_PRECONDITION(aPresContext, "null pres context"); + DO_GLOBAL_REFLOW_COUNT("nsTableFrame", aReflowState.reason); + DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); + + aStatus = NS_FRAME_COMPLETE; + GetDesiredSize(aPresContext, aReflowState, aDesiredSize); + mHaveReflowed = PR_TRUE; + + return NS_OK; +} + +NS_IMETHODIMP +nsPageBreakFrame::GetFrameType(nsIAtom** aType) const +{ + NS_PRECONDITION(nsnull != aType, "null OUT parameter pointer"); + *aType = nsLayoutAtoms::pageBreakFrame; + NS_ADDREF(*aType); + return NS_OK; +} + + diff --git a/layout/generic/nsPageFrame.h b/layout/generic/nsPageFrame.h index 7d1d4aa26bb7..4e02f66d3087 100644 --- a/layout/generic/nsPageFrame.h +++ b/layout/generic/nsPageFrame.h @@ -39,6 +39,7 @@ #include "nsContainerFrame.h" #include "nsIPrintSettings.h" +#include "nsLeafFrame.h" class nsSharedPageData; @@ -152,5 +153,28 @@ private: const nsRect& aDirtyRect); }; + +class nsPageBreakFrame : public nsLeafFrame { + + nsPageBreakFrame(); + ~nsPageBreakFrame(); + + NS_IMETHOD Reflow(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus); + + NS_IMETHOD GetFrameType(nsIAtom** aType) const; + +protected: + + virtual void GetDesiredSize(nsIPresContext* aPresContext, + const nsHTMLReflowState& aReflowState, + nsHTMLReflowMetrics& aDesiredSize); + PRBool mHaveReflowed; + + friend nsresult NS_NewPageBreakFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame); +}; + #endif /* nsPageFrame_h___ */ diff --git a/layout/html/base/src/nsHTMLParts.h b/layout/html/base/src/nsHTMLParts.h index 0e07379bbee3..5b4277dcd3cd 100644 --- a/layout/html/base/src/nsHTMLParts.h +++ b/layout/html/base/src/nsHTMLParts.h @@ -170,6 +170,7 @@ extern nsresult NS_NewScrollFrame(nsIPresShell* aPresShell, nsIFrame** aResult); extern nsresult NS_NewSimplePageSequenceFrame(nsIPresShell* aPresShell, nsIFrame** aResult); extern nsresult NS_NewPageFrame(nsIPresShell* aPresShell, nsIFrame** aResult); extern nsresult NS_NewPageContentFrame(nsIPresShell* aPresShell, nsIFrame** aResult); +extern nsresult NS_NewPageBreakFrame(nsIPresShell* aPresShell, nsIFrame** aResult); extern nsresult NS_NewFirstLetterFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame); extern nsresult NS_NewFirstLineFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame); diff --git a/layout/html/base/src/nsPageFrame.cpp b/layout/html/base/src/nsPageFrame.cpp index 65ab958103dd..28c99e61a011 100644 --- a/layout/html/base/src/nsPageFrame.cpp +++ b/layout/html/base/src/nsPageFrame.cpp @@ -759,3 +759,90 @@ nsPageFrame::DrawBackground(nsIPresContext* aPresContext, } } +nsresult +NS_NewPageBreakFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame) +{ + NS_PRECONDITION(aPresShell && aNewFrame, "null PresShell or OUT ptr"); +#ifdef DEBUG + //check that we are only creating page break frames when printing + nsCOMPtr presContext; + aPresShell->GetPresContext(getter_AddRefs(presContext)); + PRBool isPaginated; + presContext->IsPaginated(&isPaginated); + NS_ASSERTION(isPaginated, "created a page break frame while not printing"); +#endif + + nsPageBreakFrame* it = new (aPresShell) nsPageBreakFrame; + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + *aNewFrame = it; + return NS_OK; +} + +nsPageBreakFrame::nsPageBreakFrame() +: mHaveReflowed(PR_FALSE) +{ +} + +nsPageBreakFrame::~nsPageBreakFrame() +{ +} + +void +nsPageBreakFrame::GetDesiredSize(nsIPresContext* aPresContext, + const nsHTMLReflowState& aReflowState, + nsHTMLReflowMetrics& aDesiredSize) +{ + NS_PRECONDITION(aPresContext, "null pres context"); + float p2t; + aPresContext->GetScaledPixelsToTwips(&p2t); + nscoord onePixel = NSToCoordRound(p2t); + + aDesiredSize.width = onePixel; + if (mHaveReflowed) { + // If blocks reflow us a 2nd time trying to put us on a new page, then return + // a desired height of 0 to avoid an extra page break. + aDesiredSize.height = 0; + } + else { + aDesiredSize.height = aReflowState.availableHeight; + // round the height down to the nearest pixel + aDesiredSize.height -= aDesiredSize.height % onePixel; + } + + if (aDesiredSize.maxElementSize) { + aDesiredSize.maxElementSize->width = onePixel; + aDesiredSize.maxElementSize->height = aDesiredSize.height; + } + aDesiredSize.ascent = 0; + aDesiredSize.descent = 0; +} + +nsresult +nsPageBreakFrame::Reflow(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus) +{ + NS_PRECONDITION(aPresContext, "null pres context"); + DO_GLOBAL_REFLOW_COUNT("nsTableFrame", aReflowState.reason); + DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); + + aStatus = NS_FRAME_COMPLETE; + GetDesiredSize(aPresContext, aReflowState, aDesiredSize); + mHaveReflowed = PR_TRUE; + + return NS_OK; +} + +NS_IMETHODIMP +nsPageBreakFrame::GetFrameType(nsIAtom** aType) const +{ + NS_PRECONDITION(nsnull != aType, "null OUT parameter pointer"); + *aType = nsLayoutAtoms::pageBreakFrame; + NS_ADDREF(*aType); + return NS_OK; +} + + diff --git a/layout/html/base/src/nsPageFrame.h b/layout/html/base/src/nsPageFrame.h index 7d1d4aa26bb7..4e02f66d3087 100644 --- a/layout/html/base/src/nsPageFrame.h +++ b/layout/html/base/src/nsPageFrame.h @@ -39,6 +39,7 @@ #include "nsContainerFrame.h" #include "nsIPrintSettings.h" +#include "nsLeafFrame.h" class nsSharedPageData; @@ -152,5 +153,28 @@ private: const nsRect& aDirtyRect); }; + +class nsPageBreakFrame : public nsLeafFrame { + + nsPageBreakFrame(); + ~nsPageBreakFrame(); + + NS_IMETHOD Reflow(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus); + + NS_IMETHOD GetFrameType(nsIAtom** aType) const; + +protected: + + virtual void GetDesiredSize(nsIPresContext* aPresContext, + const nsHTMLReflowState& aReflowState, + nsHTMLReflowMetrics& aDesiredSize); + PRBool mHaveReflowed; + + friend nsresult NS_NewPageBreakFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame); +}; + #endif /* nsPageFrame_h___ */ diff --git a/layout/html/document/src/html.css b/layout/html/document/src/html.css index c8843d43e932..fe51cb90ff48 100644 --- a/layout/html/document/src/html.css +++ b/layout/html/document/src/html.css @@ -196,6 +196,8 @@ table[rules] { background: inherit; border: inherit; -moz-opacity: inherit; + page-break-before: inherit; + page-break-after: inherit; } /* make sure backgrounds are inherited in tables -- see bug 4510*/ @@ -509,6 +511,10 @@ noembed, noscript, param { display: block; } +*|*:-moz-pagebreak { + display: -moz-page-break; +} + *|*:-moz-anonymous-positioned-block { display: block; position: relative; diff --git a/layout/html/style/src/nsCSSFrameConstructor.cpp b/layout/html/style/src/nsCSSFrameConstructor.cpp index ef8f91b9bbf7..ff870025414f 100644 --- a/layout/html/style/src/nsCSSFrameConstructor.cpp +++ b/layout/html/style/src/nsCSSFrameConstructor.cpp @@ -2281,6 +2281,9 @@ nsCSSFrameConstructor::GetParentFrame(nsIPresShell* aPresShell, } // Construct the outer, inner table frames and the children frames for the table. +// XXX Page break frames for pseudo table frames are not constructed to avoid the risk +// associated with revising the pseudo frame mechanism. The long term solution +// of having frames handle page-break-before/after will solve the problem. nsresult nsCSSFrameConstructor::ConstructTableFrame(nsIPresShell* aPresShell, nsIPresContext* aPresContext, @@ -2923,10 +2926,27 @@ nsCSSFrameConstructor::TableProcessChild(nsIPresShell* aPresShell, switch (styleDisplay->mDisplay) { case NS_STYLE_DISPLAY_TABLE: - nsIFrame* innerTableFrame; - rv = ConstructTableFrame(aPresShell, aPresContext, aState, aChildContent, aParentFrame, - childStyleContext, aTableCreator, PR_FALSE, aChildItems, - childFrame, innerTableFrame, isPseudoParent); + { + PRBool pageBreakAfter = PR_FALSE; + PRBool paginated; + aPresContext->IsPaginated(&paginated); + + if (paginated) { + // See if there is a page break before, if so construct one. Also see if there is one after + pageBreakAfter = PageBreakBefore(aPresShell, aPresContext, aState, aChildContent, + aParentFrame, childStyleContext, aChildItems); + } + // construct the table frame + nsIFrame* innerTableFrame; + rv = ConstructTableFrame(aPresShell, aPresContext, aState, aChildContent, aParentFrame, + childStyleContext, aTableCreator, PR_FALSE, aChildItems, + childFrame, innerTableFrame, isPseudoParent); + if (NS_SUCCEEDED(rv) && pageBreakAfter) { + // Construct the page break after + ConstructPageBreakFrame(aPresShell, aPresContext, aState, aChildContent, + aParentFrame, childStyleContext, aChildItems); + } + } break; case NS_STYLE_DISPLAY_TABLE_CAPTION: @@ -6975,8 +6995,56 @@ nsCSSFrameConstructor::ConstructSVGFrame(nsIPresShell* aPresShell, } #endif // MOZ_SVG +PRBool +nsCSSFrameConstructor::PageBreakBefore(nsIPresShell* aPresShell, + nsIPresContext* aPresContext, + nsFrameConstructorState& aState, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsIStyleContext* aStyleContext, + nsFrameItems& aFrameItems) +{ + const nsStyleDisplay* display = (const nsStyleDisplay*) + aStyleContext->GetStyleData(eStyleStruct_Display); + + // See if page-break-before is set for all elements except row groups, rows, cells + // (these are handled internally by tables) and construct a page break frame if so. + if (display && ((NS_STYLE_DISPLAY_TABLE == display->mDisplay) || + (!IsTableRelated(display->mDisplay, PR_TRUE)))) { + if (display->mBreakBefore) { + ConstructPageBreakFrame(aPresShell, aPresContext, aState, aContent, + aParentFrame, aStyleContext, aFrameItems); + } + return display->mBreakAfter; + } + return PR_FALSE; +} + nsresult -nsCSSFrameConstructor::ConstructFrame(nsIPresShell* aPresShell, +nsCSSFrameConstructor::ConstructPageBreakFrame(nsIPresShell* aPresShell, + nsIPresContext* aPresContext, + nsFrameConstructorState& aState, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsIStyleContext* aStyleContext, + nsFrameItems& aFrameItems) +{ + nsCOMPtr pseudoStyle; + aPresContext->ResolvePseudoStyleContextFor(nsnull, nsLayoutAtoms::pageBreakPseudo, + aStyleContext, PR_FALSE, + getter_AddRefs(pseudoStyle)); + nsIFrame* pageBreakFrame; + nsresult rv = NS_NewPageBreakFrame(aPresShell, &pageBreakFrame); + if (NS_SUCCEEDED(rv)) { + InitAndRestoreFrame(aPresContext, aState, aContent, aParentFrame, + pseudoStyle, nsnull, pageBreakFrame); + aFrameItems.AddChild(pageBreakFrame); + } + return rv; +} + +nsresult +nsCSSFrameConstructor::ConstructFrame(nsIPresShell* aPresShell, nsIPresContext* aPresContext, nsFrameConstructorState& aState, nsIContent* aContent, @@ -7006,20 +7074,27 @@ nsCSSFrameConstructor::ConstructFrame(nsIPresShell* aPresShell, rv = ResolveStyleContext(aPresContext, aParentFrame, aContent, getter_AddRefs(styleContext)); - if (NS_SUCCEEDED(rv)) { - + if (NS_SUCCEEDED(rv)) { PRInt32 nameSpaceID; aContent->GetNameSpaceID(nameSpaceID); - rv = ConstructFrameInternal(aPresShell, - aPresContext, - aState, - aContent, - aParentFrame, - tag, - nameSpaceID, - styleContext, - aFrameItems, - PR_FALSE); + + PRBool pageBreakAfter = PR_FALSE; + PRBool paginated; + aPresContext->IsPaginated(&paginated); + + if (paginated) { + // See if there is a page break before, if so construct one. Also see if there is one after + pageBreakAfter = PageBreakBefore(aPresShell, aPresContext, aState, aContent, + aParentFrame, styleContext, aFrameItems); + } + // construct the frame + rv = ConstructFrameInternal(aPresShell, aPresContext, aState, aContent, aParentFrame, + tag, nameSpaceID, styleContext, aFrameItems, PR_FALSE); + if (NS_SUCCEEDED(rv) && pageBreakAfter) { + // Construct the page break after + ConstructPageBreakFrame(aPresShell, aPresContext, aState, aContent, + aParentFrame, styleContext, aFrameItems); + } } return rv; diff --git a/layout/html/style/src/nsCSSFrameConstructor.h b/layout/html/style/src/nsCSSFrameConstructor.h index 9bcaa23f84e9..135d6121f8ed 100644 --- a/layout/html/style/src/nsCSSFrameConstructor.h +++ b/layout/html/style/src/nsCSSFrameConstructor.h @@ -535,6 +535,25 @@ protected: nsIStyleContext* aStyleContext, nsFrameItems& aFrameItems); + nsresult ConstructPageBreakFrame(nsIPresShell* aPresShell, + nsIPresContext* aPresContext, + nsFrameConstructorState& aState, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsIStyleContext* aStyleContext, + nsFrameItems& aFrameItems); + + // Construct a page break frame if page-break-before:always is set in aStyleContext + // and add it to aFrameItems. Return true if page-break-after:always is set on aStyleContext. + // Don't do this for row groups, rows or cell, because tables handle those internally. + PRBool PageBreakBefore(nsIPresShell* aPresShell, + nsIPresContext* aPresContext, + nsFrameConstructorState& aState, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsIStyleContext* aStyleContext, + nsFrameItems& aFrameItems); + nsresult ConstructHTMLFrame(nsIPresShell* aPresShell, nsIPresContext* aPresContext, nsFrameConstructorState& aState, diff --git a/layout/html/table/src/nsTableFrame.cpp b/layout/html/table/src/nsTableFrame.cpp index 2b8dfeb6618c..dc89afa710cd 100644 --- a/layout/html/table/src/nsTableFrame.cpp +++ b/layout/html/table/src/nsTableFrame.cpp @@ -421,6 +421,32 @@ nsTableFrame::RePositionViews(nsIPresContext* aPresContext, nsContainerFrame::PositionChildViews(aPresContext, aFrame); } +PRBool +nsTableFrame::PageBreakAfter(nsIFrame& aSourceFrame, + nsIFrame* aNextFrame) +{ + nsCOMPtr sourceContext; + aSourceFrame.GetStyleContext(getter_AddRefs(sourceContext)); NS_ENSURE_TRUE(sourceContext, PR_FALSE); + const nsStyleDisplay* display = (const nsStyleDisplay*) + sourceContext->GetStyleData(eStyleStruct_Display); NS_ENSURE_TRUE(display, PR_FALSE); + // don't allow a page break after a repeated header + if (display->mBreakAfter && (NS_STYLE_DISPLAY_TABLE_HEADER_GROUP != display->mDisplay)) { + return PR_TRUE; + } + + if (aNextFrame) { + nsCOMPtr nextContext; + aNextFrame->GetStyleContext(getter_AddRefs(nextContext)); NS_ENSURE_TRUE(nextContext, PR_FALSE); + display = (const nsStyleDisplay*) + nextContext->GetStyleData(eStyleStruct_Display); NS_ENSURE_TRUE(display, PR_FALSE); + // don't allow a page break before a repeated footer + if (display->mBreakBefore && (NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP != display->mDisplay)) { + return PR_TRUE; + } + } + return PR_FALSE; +} + nsIPresShell* nsTableFrame::GetPresShellNoAddref(nsIPresContext* aPresContext) { @@ -1894,6 +1920,9 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext, nsReflowReason nextReason = aReflowState.reason; + // Check for an overflow list, and append any row group frames being pushed + MoveOverflowToChildList(aPresContext); + // Processes an initial (except when there is mPrevInFlow), incremental, or style // change reflow 1st. resize reflows are processed in the next phase. switch (aReflowState.reason) { @@ -1904,9 +1933,6 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext, // NS_ASSERTION(PR_FALSE, "intial reflow called twice"); } else { - // Check for an overflow list, and append any row group frames being pushed - MoveOverflowToChildList(aPresContext); - if (!mPrevInFlow) { // only do pass1 on a first in flow if (IsAutoLayout()) { // only do pass1 reflow on an auto layout table @@ -3203,7 +3229,7 @@ nsTableFrame::ReflowChildren(nsIPresContext* aPresContext, nsTableRowGroupFrame *thead, *tfoot; OrderRowGroups(rowGroups, numRowGroups, &aReflowState.firstBodySection, &thead, &tfoot); PRBool haveReflowedRowGroup = PR_FALSE; - + PRBool pageBreak = PR_FALSE; for (PRUint32 childX = 0; ((PRInt32)childX) < rowGroups.Count(); childX++) { nsIFrame* kidFrame = (nsIFrame*)rowGroups.ElementAt(childX); // Get the frame state bits @@ -3217,6 +3243,12 @@ nsTableFrame::ReflowChildren(nsIPresContext* aPresContext, } if (doReflowChild) { + if (pageBreak) { + PushChildren(aPresContext, kidFrame, prevKidFrame); + 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 nsIFrame* repeatedFooter = nsnull; @@ -3264,12 +3296,19 @@ nsTableFrame::ReflowChildren(nsIPresContext* aPresContext, haveReflowedRowGroup = PR_TRUE; aLastChildReflowed = kidFrame; + pageBreak = PR_FALSE; + // see if there is a page break after this row group or before the next one + if (NS_FRAME_IS_COMPLETE(aStatus) && isPaginated && + (NS_UNCONSTRAINEDSIZE != kidReflowState.availableHeight)) { + nsIFrame* nextKid = (childX + 1 < numRowGroups) ? (nsIFrame*)rowGroups.ElementAt(childX + 1) : nsnull; + pageBreak = PageBreakAfter(*kidFrame, nextKid); + } // Place the child PlaceChild(aPresContext, aReflowState, kidFrame, desiredSize); // Remember where we just were in case we end up pushing children prevKidFrame = kidFrame; - + // Special handling for incomplete children if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { kidFrame->GetNextInFlow(&kidNextInFlow); diff --git a/layout/html/table/src/nsTableFrame.h b/layout/html/table/src/nsTableFrame.h index fbdfd7d00550..14de0c5fdf24 100644 --- a/layout/html/table/src/nsTableFrame.h +++ b/layout/html/table/src/nsTableFrame.h @@ -229,6 +229,9 @@ public: static void RePositionViews(nsIPresContext* aPresContext, nsIFrame* aFrame); + static PRBool PageBreakAfter(nsIFrame& aSourceFrame, + nsIFrame* aNextFrame); + nsPoint GetFirstSectionOrigin(const nsHTMLReflowState& aReflowState) const; /* * Notification that aAttribute has changed for content inside a table (cell, row, etc) diff --git a/layout/html/table/src/nsTableRowGroupFrame.cpp b/layout/html/table/src/nsTableRowGroupFrame.cpp index e5abe5f17ac7..23024fc1e7f4 100644 --- a/layout/html/table/src/nsTableRowGroupFrame.cpp +++ b/layout/html/table/src/nsTableRowGroupFrame.cpp @@ -359,8 +359,12 @@ nsTableRowGroupFrame::ReflowChildren(nsIPresContext* aPresContext, nsReflowStatus& aStatus, nsTableRowFrame* aStartFrame, PRBool aDirtyOnly, - nsTableRowFrame** aFirstRowReflowed) + nsTableRowFrame** aFirstRowReflowed, + PRBool* aPageBreakBeforeEnd) { + if (aPageBreakBeforeEnd) + *aPageBreakBeforeEnd = PR_FALSE; + nsTableFrame* tableFrame = nsnull; nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame); if (!tableFrame) ABORT1(rv); @@ -452,6 +456,14 @@ nsTableRowGroupFrame::ReflowChildren(nsIPresContext* aPresContext, *aFirstRowReflowed = (nsTableRowFrame*)kidFrame; } } + if (isPaginated && aPageBreakBeforeEnd && !*aPageBreakBeforeEnd && + (nsLayoutAtoms::tableRowFrame == kidType.get())) { + nsTableRowFrame* nextRow = ((nsTableRowFrame*)kidFrame)->GetNextRow(); + if (nextRow) { + *aPageBreakBeforeEnd = nsTableFrame::PageBreakAfter(*kidFrame, nextRow); + } + } + } else { // were done reflowing, so see if we need to reposition the rows that follow if (lastReflowedRow) { @@ -1015,7 +1027,7 @@ nsTableRowGroupFrame::SplitRowGroup(nsIPresContext* aPresContext, // 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, availHeight - bounds.y); + nsSize availSize(availWidth, PR_MAX(availHeight - bounds.y, 0)); nsHTMLReflowState rowReflowState(aPresContext, aReflowState, rowFrame, availSize, eReflowReason_Resize); InitChildReflowState(*aPresContext, borderCollapse, p2t, rowReflowState); @@ -1085,6 +1097,13 @@ nsTableRowGroupFrame::SplitRowGroup(nsIPresContext* aPresContext, aDesiredSize.height = bounds.YMost(); lastDesiredHeight = aDesiredSize.height; prevRowFrame = rowFrame; + // see if there is a page break after the row + nsTableRowFrame* nextRow = rowFrame->GetNextRow(); + if (nextRow && nsTableFrame::PageBreakAfter(*rowFrame, nextRow)) { + PushChildren(aPresContext, nextRow, rowFrame); + aStatus = NS_FRAME_NOT_COMPLETE; + break; + } } } return NS_OK; @@ -1143,8 +1162,9 @@ nsTableRowGroupFrame::Reflow(nsIPresContext* aPresContext, CacheRowHeightsForPrinting(aPresContext, GetFirstRow()); } // Reflow the existing frames. + PRBool splitDueToPageBreak = PR_FALSE; rv = ReflowChildren(aPresContext, aDesiredSize, state, aStatus, - nsnull, PR_FALSE); + nsnull, PR_FALSE, nsnull, &splitDueToPageBreak); // Return our desired rect aDesiredSize.width = aReflowState.availableWidth; @@ -1170,7 +1190,8 @@ nsTableRowGroupFrame::Reflow(nsIPresContext* aPresContext, } // See if all the frames fit - if ((NS_FRAME_NOT_COMPLETE == aStatus) || (aDesiredSize.height > aReflowState.availableHeight)) { + if ((NS_FRAME_NOT_COMPLETE == aStatus) || splitDueToPageBreak || + (aDesiredSize.height > aReflowState.availableHeight)) { // Nope, find a place to split the row group PRBool specialReflow = (PRBool)aReflowState.mFlags.mSpecialHeightReflow; ((nsHTMLReflowState::ReflowStateFlags&)aReflowState.mFlags).mSpecialHeightReflow = PR_FALSE; diff --git a/layout/html/table/src/nsTableRowGroupFrame.h b/layout/html/table/src/nsTableRowGroupFrame.h index d259a63bdfb7..789152b5a7eb 100644 --- a/layout/html/table/src/nsTableRowGroupFrame.h +++ b/layout/html/table/src/nsTableRowGroupFrame.h @@ -325,7 +325,8 @@ protected: nsReflowStatus& aStatus, nsTableRowFrame* aStartFrame, PRBool aDirtyOnly, - nsTableRowFrame** aFirstRowReflowed = nsnull); + nsTableRowFrame** aFirstRowReflowed = nsnull, + PRBool* aPageBreakBeforeEnd = nsnull); nsresult SplitRowGroup(nsIPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, diff --git a/layout/style/html.css b/layout/style/html.css index c8843d43e932..fe51cb90ff48 100644 --- a/layout/style/html.css +++ b/layout/style/html.css @@ -196,6 +196,8 @@ table[rules] { background: inherit; border: inherit; -moz-opacity: inherit; + page-break-before: inherit; + page-break-after: inherit; } /* make sure backgrounds are inherited in tables -- see bug 4510*/ @@ -509,6 +511,10 @@ noembed, noscript, param { display: block; } +*|*:-moz-pagebreak { + display: -moz-page-break; +} + *|*:-moz-anonymous-positioned-block { display: block; position: relative; diff --git a/layout/style/nsCSSDeclaration.cpp b/layout/style/nsCSSDeclaration.cpp index 5c2a754be8c8..cd2584b1116d 100644 --- a/layout/style/nsCSSDeclaration.cpp +++ b/layout/style/nsCSSDeclaration.cpp @@ -379,6 +379,10 @@ nsCSSDisplay::nsCSSDisplay(const nsCSSDisplay& aCopy) mPosition(aCopy.mPosition), mFloat(aCopy.mFloat), mClear(aCopy.mClear), + // temp fix for bug 24000 + mBreakBefore(aCopy.mBreakBefore), + mBreakAfter(aCopy.mBreakAfter), + // end temp mClip(nsnull), mOverflow(aCopy.mOverflow), mVisibility(aCopy.mVisibility), @@ -1794,18 +1798,26 @@ nsCSSDeclaration::AppendValue(nsCSSProperty aProperty, const nsCSSValue& aValue) // nsCSSBreaks case eCSSProperty_orphans: case eCSSProperty_widows: - case eCSSProperty_page: - case eCSSProperty_page_break_after: - case eCSSProperty_page_break_before: - case eCSSProperty_page_break_inside: { + case eCSSProperty_page: { CSS_ENSURE(Breaks) { switch (aProperty) { case eCSSProperty_orphans: theBreaks->mOrphans = aValue; break; case eCSSProperty_widows: theBreaks->mWidows = aValue; break; case eCSSProperty_page: theBreaks->mPage = aValue; break; - case eCSSProperty_page_break_after: theBreaks->mPageBreakAfter = aValue; break; - case eCSSProperty_page_break_before: theBreaks->mPageBreakBefore = aValue; break; - case eCSSProperty_page_break_inside: theBreaks->mPageBreakInside = aValue; break; + CSS_BOGUS_DEFAULT; // make compiler happy + } + } + break; + } + case eCSSProperty_page_break_after: + case eCSSProperty_page_break_before: + case eCSSProperty_page_break_inside: { + // temp fix for bug 24000 + CSS_ENSURE(Display) { + switch (aProperty) { + case eCSSProperty_page_break_after: theDisplay->mBreakAfter = aValue; break; + case eCSSProperty_page_break_before: theDisplay->mBreakBefore = aValue; break; + case eCSSProperty_page_break_inside: break; CSS_BOGUS_DEFAULT; // make compiler happy } } @@ -2739,10 +2751,7 @@ nsCSSDeclaration::SetValueImportant(nsCSSProperty aProperty) // nsCSSBreaks case eCSSProperty_orphans: case eCSSProperty_widows: - case eCSSProperty_page: - case eCSSProperty_page_break_after: - case eCSSProperty_page_break_before: - case eCSSProperty_page_break_inside: { + case eCSSProperty_page: { CSS_VARONSTACK_GET(Breaks); if (nsnull != theBreaks) { CSS_ENSURE_IMPORTANT(Breaks) { @@ -2750,9 +2759,22 @@ nsCSSDeclaration::SetValueImportant(nsCSSProperty aProperty) CSS_CASE_IMPORTANT(eCSSProperty_orphans, Breaks, mOrphans); CSS_CASE_IMPORTANT(eCSSProperty_widows, Breaks, mWidows); CSS_CASE_IMPORTANT(eCSSProperty_page, Breaks, mPage); - CSS_CASE_IMPORTANT(eCSSProperty_page_break_after, Breaks, mPageBreakAfter); - CSS_CASE_IMPORTANT(eCSSProperty_page_break_before, Breaks, mPageBreakBefore); - CSS_CASE_IMPORTANT(eCSSProperty_page_break_inside, Breaks, mPageBreakInside); + CSS_BOGUS_DEFAULT; // make compiler happy + } + } + } + break; + } + case eCSSProperty_page_break_after: + case eCSSProperty_page_break_before: + case eCSSProperty_page_break_inside: { + // temp fix for bug 24000 + CSS_VARONSTACK_GET(Display); + if (theDisplay) { + CSS_ENSURE_IMPORTANT(Display) { + switch (aProperty) { + CSS_CASE_IMPORTANT(eCSSProperty_page_break_after, Display, mBreakAfter); + CSS_CASE_IMPORTANT(eCSSProperty_page_break_before, Display, mBreakBefore); CSS_BOGUS_DEFAULT; // make compiler happy } } @@ -3593,24 +3615,30 @@ nsCSSDeclaration::RemoveProperty(nsCSSProperty aProperty) // nsCSSBreaks case eCSSProperty_orphans: case eCSSProperty_widows: - case eCSSProperty_page: - case eCSSProperty_page_break_after: - case eCSSProperty_page_break_before: - case eCSSProperty_page_break_inside: { + case eCSSProperty_page: { CSS_CHECK(Breaks) { switch (aProperty) { case eCSSProperty_orphans: theBreaks->mOrphans.Reset(); break; case eCSSProperty_widows: theBreaks->mWidows.Reset(); break; case eCSSProperty_page: theBreaks->mPage.Reset(); break; - case eCSSProperty_page_break_after: theBreaks->mPageBreakAfter.Reset(); break; - case eCSSProperty_page_break_before: theBreaks->mPageBreakBefore.Reset(); break; - case eCSSProperty_page_break_inside: theBreaks->mPageBreakInside.Reset(); break; CSS_BOGUS_DEFAULT; // make compiler happy } } break; } - + case eCSSProperty_page_break_after: + case eCSSProperty_page_break_before: + case eCSSProperty_page_break_inside: { + // temp fix for bug 24000 + CSS_CHECK(Display) { + switch (aProperty) { + case eCSSProperty_page_break_after: theDisplay->mBreakAfter.Reset(); break; + case eCSSProperty_page_break_before: theDisplay->mBreakBefore.Reset(); break; + case eCSSProperty_page_break_inside: break; + } + } + break; + } // nsCSSPage case eCSSProperty_marks: case eCSSProperty_size_width: @@ -4432,19 +4460,31 @@ nsCSSDeclaration::GetValue(nsCSSProperty aProperty, nsCSSValue& aValue) // nsCSSBreaks case eCSSProperty_orphans: case eCSSProperty_widows: - case eCSSProperty_page: - case eCSSProperty_page_break_after: - case eCSSProperty_page_break_before: - case eCSSProperty_page_break_inside: { + case eCSSProperty_page: { CSS_VARONSTACK_GET(Breaks); if (nsnull != theBreaks) { switch (aProperty) { case eCSSProperty_orphans: aValue = theBreaks->mOrphans; break; case eCSSProperty_widows: aValue = theBreaks->mWidows; break; case eCSSProperty_page: aValue = theBreaks->mPage; break; - case eCSSProperty_page_break_after: aValue = theBreaks->mPageBreakAfter; break; - case eCSSProperty_page_break_before: aValue = theBreaks->mPageBreakBefore; break; - case eCSSProperty_page_break_inside: aValue = theBreaks->mPageBreakInside; break; + CSS_BOGUS_DEFAULT; // make compiler happy + } + } + else { + aValue.Reset(); + } + break; + } + case eCSSProperty_page_break_after: + case eCSSProperty_page_break_before: + case eCSSProperty_page_break_inside: { + // temp fix for bug 24000 + CSS_VARONSTACK_GET(Display); + if (theDisplay) { + switch (aProperty) { + case eCSSProperty_page_break_inside: aValue.Reset(); break; + case eCSSProperty_page_break_after: aValue = theDisplay->mBreakAfter; break; + case eCSSProperty_page_break_before: aValue = theDisplay->mBreakBefore; break; CSS_BOGUS_DEFAULT; // make compiler happy } } diff --git a/layout/style/nsCSSDeclaration.h b/layout/style/nsCSSDeclaration.h index a0e37a90b500..16070e5a6114 100644 --- a/layout/style/nsCSSDeclaration.h +++ b/layout/style/nsCSSDeclaration.h @@ -240,6 +240,10 @@ struct nsCSSDisplay : public nsCSSStruct { // in nsCSSDeclaration objects but because it's needed on the // stack when the struct is used in WalkRuleTree. nsCSSValue mLang; + // temp fix for bug 24000 + nsCSSValue mBreakBefore; + nsCSSValue mBreakAfter; + // end temp fix }; struct nsCSSMargin : public nsCSSStruct { diff --git a/layout/style/nsCSSKeywordList.h b/layout/style/nsCSSKeywordList.h index ae3a4dffda9a..2cdca3c9476e 100644 --- a/layout/style/nsCSSKeywordList.h +++ b/layout/style/nsCSSKeywordList.h @@ -99,6 +99,7 @@ CSS_KEY(-moz-inline-grid, _moz_inline_grid) CSS_KEY(-moz-grid-group, _moz_grid_group) CSS_KEY(-moz-grid-line, _moz_grid_line) CSS_KEY(-moz-groupbox, _moz_groupbox) +CSS_KEY(-moz-page-break, _moz_page_break) CSS_KEY(-moz-popup, _moz_popup) CSS_KEY(-moz-stack, _moz_stack) CSS_KEY(-moz-inline-stack, _moz_inline_stack) diff --git a/layout/style/nsCSSProps.cpp b/layout/style/nsCSSProps.cpp index c1ebc1bfe649..1cd859550fa6 100644 --- a/layout/style/nsCSSProps.cpp +++ b/layout/style/nsCSSProps.cpp @@ -409,6 +409,7 @@ const PRInt32 nsCSSProps::kDisplayKTable[] = { eCSSKeyword__moz_bulletinboard, NS_STYLE_DISPLAY_BULLETINBOARD, eCSSKeyword__moz_popup, NS_STYLE_DISPLAY_POPUP, eCSSKeyword__moz_groupbox, NS_STYLE_DISPLAY_GROUPBOX, + eCSSKeyword__moz_page_break, NS_STYLE_DISPLAY_PAGE_BREAK, -1,-1 }; diff --git a/layout/style/nsCSSStruct.cpp b/layout/style/nsCSSStruct.cpp index 5c2a754be8c8..cd2584b1116d 100644 --- a/layout/style/nsCSSStruct.cpp +++ b/layout/style/nsCSSStruct.cpp @@ -379,6 +379,10 @@ nsCSSDisplay::nsCSSDisplay(const nsCSSDisplay& aCopy) mPosition(aCopy.mPosition), mFloat(aCopy.mFloat), mClear(aCopy.mClear), + // temp fix for bug 24000 + mBreakBefore(aCopy.mBreakBefore), + mBreakAfter(aCopy.mBreakAfter), + // end temp mClip(nsnull), mOverflow(aCopy.mOverflow), mVisibility(aCopy.mVisibility), @@ -1794,18 +1798,26 @@ nsCSSDeclaration::AppendValue(nsCSSProperty aProperty, const nsCSSValue& aValue) // nsCSSBreaks case eCSSProperty_orphans: case eCSSProperty_widows: - case eCSSProperty_page: - case eCSSProperty_page_break_after: - case eCSSProperty_page_break_before: - case eCSSProperty_page_break_inside: { + case eCSSProperty_page: { CSS_ENSURE(Breaks) { switch (aProperty) { case eCSSProperty_orphans: theBreaks->mOrphans = aValue; break; case eCSSProperty_widows: theBreaks->mWidows = aValue; break; case eCSSProperty_page: theBreaks->mPage = aValue; break; - case eCSSProperty_page_break_after: theBreaks->mPageBreakAfter = aValue; break; - case eCSSProperty_page_break_before: theBreaks->mPageBreakBefore = aValue; break; - case eCSSProperty_page_break_inside: theBreaks->mPageBreakInside = aValue; break; + CSS_BOGUS_DEFAULT; // make compiler happy + } + } + break; + } + case eCSSProperty_page_break_after: + case eCSSProperty_page_break_before: + case eCSSProperty_page_break_inside: { + // temp fix for bug 24000 + CSS_ENSURE(Display) { + switch (aProperty) { + case eCSSProperty_page_break_after: theDisplay->mBreakAfter = aValue; break; + case eCSSProperty_page_break_before: theDisplay->mBreakBefore = aValue; break; + case eCSSProperty_page_break_inside: break; CSS_BOGUS_DEFAULT; // make compiler happy } } @@ -2739,10 +2751,7 @@ nsCSSDeclaration::SetValueImportant(nsCSSProperty aProperty) // nsCSSBreaks case eCSSProperty_orphans: case eCSSProperty_widows: - case eCSSProperty_page: - case eCSSProperty_page_break_after: - case eCSSProperty_page_break_before: - case eCSSProperty_page_break_inside: { + case eCSSProperty_page: { CSS_VARONSTACK_GET(Breaks); if (nsnull != theBreaks) { CSS_ENSURE_IMPORTANT(Breaks) { @@ -2750,9 +2759,22 @@ nsCSSDeclaration::SetValueImportant(nsCSSProperty aProperty) CSS_CASE_IMPORTANT(eCSSProperty_orphans, Breaks, mOrphans); CSS_CASE_IMPORTANT(eCSSProperty_widows, Breaks, mWidows); CSS_CASE_IMPORTANT(eCSSProperty_page, Breaks, mPage); - CSS_CASE_IMPORTANT(eCSSProperty_page_break_after, Breaks, mPageBreakAfter); - CSS_CASE_IMPORTANT(eCSSProperty_page_break_before, Breaks, mPageBreakBefore); - CSS_CASE_IMPORTANT(eCSSProperty_page_break_inside, Breaks, mPageBreakInside); + CSS_BOGUS_DEFAULT; // make compiler happy + } + } + } + break; + } + case eCSSProperty_page_break_after: + case eCSSProperty_page_break_before: + case eCSSProperty_page_break_inside: { + // temp fix for bug 24000 + CSS_VARONSTACK_GET(Display); + if (theDisplay) { + CSS_ENSURE_IMPORTANT(Display) { + switch (aProperty) { + CSS_CASE_IMPORTANT(eCSSProperty_page_break_after, Display, mBreakAfter); + CSS_CASE_IMPORTANT(eCSSProperty_page_break_before, Display, mBreakBefore); CSS_BOGUS_DEFAULT; // make compiler happy } } @@ -3593,24 +3615,30 @@ nsCSSDeclaration::RemoveProperty(nsCSSProperty aProperty) // nsCSSBreaks case eCSSProperty_orphans: case eCSSProperty_widows: - case eCSSProperty_page: - case eCSSProperty_page_break_after: - case eCSSProperty_page_break_before: - case eCSSProperty_page_break_inside: { + case eCSSProperty_page: { CSS_CHECK(Breaks) { switch (aProperty) { case eCSSProperty_orphans: theBreaks->mOrphans.Reset(); break; case eCSSProperty_widows: theBreaks->mWidows.Reset(); break; case eCSSProperty_page: theBreaks->mPage.Reset(); break; - case eCSSProperty_page_break_after: theBreaks->mPageBreakAfter.Reset(); break; - case eCSSProperty_page_break_before: theBreaks->mPageBreakBefore.Reset(); break; - case eCSSProperty_page_break_inside: theBreaks->mPageBreakInside.Reset(); break; CSS_BOGUS_DEFAULT; // make compiler happy } } break; } - + case eCSSProperty_page_break_after: + case eCSSProperty_page_break_before: + case eCSSProperty_page_break_inside: { + // temp fix for bug 24000 + CSS_CHECK(Display) { + switch (aProperty) { + case eCSSProperty_page_break_after: theDisplay->mBreakAfter.Reset(); break; + case eCSSProperty_page_break_before: theDisplay->mBreakBefore.Reset(); break; + case eCSSProperty_page_break_inside: break; + } + } + break; + } // nsCSSPage case eCSSProperty_marks: case eCSSProperty_size_width: @@ -4432,19 +4460,31 @@ nsCSSDeclaration::GetValue(nsCSSProperty aProperty, nsCSSValue& aValue) // nsCSSBreaks case eCSSProperty_orphans: case eCSSProperty_widows: - case eCSSProperty_page: - case eCSSProperty_page_break_after: - case eCSSProperty_page_break_before: - case eCSSProperty_page_break_inside: { + case eCSSProperty_page: { CSS_VARONSTACK_GET(Breaks); if (nsnull != theBreaks) { switch (aProperty) { case eCSSProperty_orphans: aValue = theBreaks->mOrphans; break; case eCSSProperty_widows: aValue = theBreaks->mWidows; break; case eCSSProperty_page: aValue = theBreaks->mPage; break; - case eCSSProperty_page_break_after: aValue = theBreaks->mPageBreakAfter; break; - case eCSSProperty_page_break_before: aValue = theBreaks->mPageBreakBefore; break; - case eCSSProperty_page_break_inside: aValue = theBreaks->mPageBreakInside; break; + CSS_BOGUS_DEFAULT; // make compiler happy + } + } + else { + aValue.Reset(); + } + break; + } + case eCSSProperty_page_break_after: + case eCSSProperty_page_break_before: + case eCSSProperty_page_break_inside: { + // temp fix for bug 24000 + CSS_VARONSTACK_GET(Display); + if (theDisplay) { + switch (aProperty) { + case eCSSProperty_page_break_inside: aValue.Reset(); break; + case eCSSProperty_page_break_after: aValue = theDisplay->mBreakAfter; break; + case eCSSProperty_page_break_before: aValue = theDisplay->mBreakBefore; break; CSS_BOGUS_DEFAULT; // make compiler happy } } diff --git a/layout/style/nsCSSStruct.h b/layout/style/nsCSSStruct.h index a0e37a90b500..16070e5a6114 100644 --- a/layout/style/nsCSSStruct.h +++ b/layout/style/nsCSSStruct.h @@ -240,6 +240,10 @@ struct nsCSSDisplay : public nsCSSStruct { // in nsCSSDeclaration objects but because it's needed on the // stack when the struct is used in WalkRuleTree. nsCSSValue mLang; + // temp fix for bug 24000 + nsCSSValue mBreakBefore; + nsCSSValue mBreakAfter; + // end temp fix }; struct nsCSSMargin : public nsCSSStruct { diff --git a/layout/style/nsCSSStyleRule.cpp b/layout/style/nsCSSStyleRule.cpp index dd331b927301..870e3afec960 100644 --- a/layout/style/nsCSSStyleRule.cpp +++ b/layout/style/nsCSSStyleRule.cpp @@ -2306,6 +2306,13 @@ MapDisplayForDeclaration(nsCSSDeclaration* aDecl, const nsStyleStructID& aID, ns if (aDisplay.mClear.GetUnit() == eCSSUnit_Null && ourDisplay->mClear.GetUnit() != eCSSUnit_Null) aDisplay.mClear = ourDisplay->mClear; + // temp fix for bug 24000 + if (aDisplay.mBreakBefore.GetUnit() == eCSSUnit_Null && ourDisplay->mBreakBefore.GetUnit() != eCSSUnit_Null) + aDisplay.mBreakBefore = ourDisplay->mBreakBefore; + if (aDisplay.mBreakAfter.GetUnit() == eCSSUnit_Null && ourDisplay->mBreakAfter.GetUnit() != eCSSUnit_Null) + aDisplay.mBreakAfter = ourDisplay->mBreakAfter; + // end temp fix + // float: enum, none, inherit if (aDisplay.mFloat.GetUnit() == eCSSUnit_Null && ourDisplay->mFloat.GetUnit() != eCSSUnit_Null) aDisplay.mFloat = ourDisplay->mFloat; diff --git a/layout/style/nsRuleNode.cpp b/layout/style/nsRuleNode.cpp index a7163fdbc573..966ba320f4ad 100644 --- a/layout/style/nsRuleNode.cpp +++ b/layout/style/nsRuleNode.cpp @@ -783,7 +783,9 @@ static const PropertyCheckData DisplayCheckProperties[] = { CHECKDATA_PROP(nsCSSDisplay, mPosition, CHECKDATA_VALUE, PR_FALSE), CHECKDATA_PROP(nsCSSDisplay, mFloat, CHECKDATA_VALUE, PR_FALSE), CHECKDATA_PROP(nsCSSDisplay, mClear, CHECKDATA_VALUE, PR_FALSE), - CHECKDATA_PROP(nsCSSDisplay, mOverflow, CHECKDATA_VALUE, PR_FALSE) + CHECKDATA_PROP(nsCSSDisplay, mOverflow, CHECKDATA_VALUE, PR_FALSE), + CHECKDATA_PROP(nsCSSDisplay, mBreakBefore, CHECKDATA_VALUE, PR_FALSE), // temp fix for bug 2400 + CHECKDATA_PROP(nsCSSDisplay, mBreakAfter, CHECKDATA_VALUE, PR_FALSE) // temp fix for bug 2400 }; static const PropertyCheckData VisibilityCheckProperties[] = { @@ -2824,6 +2826,15 @@ nsRuleNode::ComputeDisplayData(nsStyleStruct* aStartStruct, const nsCSSStruct& a display->mBreakType = parentDisplay->mBreakType; } + // temp fix for bug 24000 + if (eCSSUnit_Enumerated == displayData.mBreakBefore.GetUnit()) { + display->mBreakBefore = (NS_STYLE_PAGE_BREAK_ALWAYS == displayData.mBreakBefore.GetIntValue()); + } + if (eCSSUnit_Enumerated == displayData.mBreakAfter.GetUnit()) { + display->mBreakAfter = (NS_STYLE_PAGE_BREAK_ALWAYS == displayData.mBreakAfter.GetIntValue()); + } + // end temp fix + // float: enum, none, inherit if (eCSSUnit_Enumerated == displayData.mFloat.GetUnit()) { display->mFloats = displayData.mFloat.GetIntValue(); diff --git a/layout/tables/nsTableFrame.cpp b/layout/tables/nsTableFrame.cpp index 2b8dfeb6618c..dc89afa710cd 100644 --- a/layout/tables/nsTableFrame.cpp +++ b/layout/tables/nsTableFrame.cpp @@ -421,6 +421,32 @@ nsTableFrame::RePositionViews(nsIPresContext* aPresContext, nsContainerFrame::PositionChildViews(aPresContext, aFrame); } +PRBool +nsTableFrame::PageBreakAfter(nsIFrame& aSourceFrame, + nsIFrame* aNextFrame) +{ + nsCOMPtr sourceContext; + aSourceFrame.GetStyleContext(getter_AddRefs(sourceContext)); NS_ENSURE_TRUE(sourceContext, PR_FALSE); + const nsStyleDisplay* display = (const nsStyleDisplay*) + sourceContext->GetStyleData(eStyleStruct_Display); NS_ENSURE_TRUE(display, PR_FALSE); + // don't allow a page break after a repeated header + if (display->mBreakAfter && (NS_STYLE_DISPLAY_TABLE_HEADER_GROUP != display->mDisplay)) { + return PR_TRUE; + } + + if (aNextFrame) { + nsCOMPtr nextContext; + aNextFrame->GetStyleContext(getter_AddRefs(nextContext)); NS_ENSURE_TRUE(nextContext, PR_FALSE); + display = (const nsStyleDisplay*) + nextContext->GetStyleData(eStyleStruct_Display); NS_ENSURE_TRUE(display, PR_FALSE); + // don't allow a page break before a repeated footer + if (display->mBreakBefore && (NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP != display->mDisplay)) { + return PR_TRUE; + } + } + return PR_FALSE; +} + nsIPresShell* nsTableFrame::GetPresShellNoAddref(nsIPresContext* aPresContext) { @@ -1894,6 +1920,9 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext, nsReflowReason nextReason = aReflowState.reason; + // Check for an overflow list, and append any row group frames being pushed + MoveOverflowToChildList(aPresContext); + // Processes an initial (except when there is mPrevInFlow), incremental, or style // change reflow 1st. resize reflows are processed in the next phase. switch (aReflowState.reason) { @@ -1904,9 +1933,6 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext, // NS_ASSERTION(PR_FALSE, "intial reflow called twice"); } else { - // Check for an overflow list, and append any row group frames being pushed - MoveOverflowToChildList(aPresContext); - if (!mPrevInFlow) { // only do pass1 on a first in flow if (IsAutoLayout()) { // only do pass1 reflow on an auto layout table @@ -3203,7 +3229,7 @@ nsTableFrame::ReflowChildren(nsIPresContext* aPresContext, nsTableRowGroupFrame *thead, *tfoot; OrderRowGroups(rowGroups, numRowGroups, &aReflowState.firstBodySection, &thead, &tfoot); PRBool haveReflowedRowGroup = PR_FALSE; - + PRBool pageBreak = PR_FALSE; for (PRUint32 childX = 0; ((PRInt32)childX) < rowGroups.Count(); childX++) { nsIFrame* kidFrame = (nsIFrame*)rowGroups.ElementAt(childX); // Get the frame state bits @@ -3217,6 +3243,12 @@ nsTableFrame::ReflowChildren(nsIPresContext* aPresContext, } if (doReflowChild) { + if (pageBreak) { + PushChildren(aPresContext, kidFrame, prevKidFrame); + 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 nsIFrame* repeatedFooter = nsnull; @@ -3264,12 +3296,19 @@ nsTableFrame::ReflowChildren(nsIPresContext* aPresContext, haveReflowedRowGroup = PR_TRUE; aLastChildReflowed = kidFrame; + pageBreak = PR_FALSE; + // see if there is a page break after this row group or before the next one + if (NS_FRAME_IS_COMPLETE(aStatus) && isPaginated && + (NS_UNCONSTRAINEDSIZE != kidReflowState.availableHeight)) { + nsIFrame* nextKid = (childX + 1 < numRowGroups) ? (nsIFrame*)rowGroups.ElementAt(childX + 1) : nsnull; + pageBreak = PageBreakAfter(*kidFrame, nextKid); + } // Place the child PlaceChild(aPresContext, aReflowState, kidFrame, desiredSize); // Remember where we just were in case we end up pushing children prevKidFrame = kidFrame; - + // Special handling for incomplete children if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { kidFrame->GetNextInFlow(&kidNextInFlow); diff --git a/layout/tables/nsTableFrame.h b/layout/tables/nsTableFrame.h index fbdfd7d00550..14de0c5fdf24 100644 --- a/layout/tables/nsTableFrame.h +++ b/layout/tables/nsTableFrame.h @@ -229,6 +229,9 @@ public: static void RePositionViews(nsIPresContext* aPresContext, nsIFrame* aFrame); + static PRBool PageBreakAfter(nsIFrame& aSourceFrame, + nsIFrame* aNextFrame); + nsPoint GetFirstSectionOrigin(const nsHTMLReflowState& aReflowState) const; /* * Notification that aAttribute has changed for content inside a table (cell, row, etc) diff --git a/layout/tables/nsTableRowGroupFrame.cpp b/layout/tables/nsTableRowGroupFrame.cpp index e5abe5f17ac7..23024fc1e7f4 100644 --- a/layout/tables/nsTableRowGroupFrame.cpp +++ b/layout/tables/nsTableRowGroupFrame.cpp @@ -359,8 +359,12 @@ nsTableRowGroupFrame::ReflowChildren(nsIPresContext* aPresContext, nsReflowStatus& aStatus, nsTableRowFrame* aStartFrame, PRBool aDirtyOnly, - nsTableRowFrame** aFirstRowReflowed) + nsTableRowFrame** aFirstRowReflowed, + PRBool* aPageBreakBeforeEnd) { + if (aPageBreakBeforeEnd) + *aPageBreakBeforeEnd = PR_FALSE; + nsTableFrame* tableFrame = nsnull; nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame); if (!tableFrame) ABORT1(rv); @@ -452,6 +456,14 @@ nsTableRowGroupFrame::ReflowChildren(nsIPresContext* aPresContext, *aFirstRowReflowed = (nsTableRowFrame*)kidFrame; } } + if (isPaginated && aPageBreakBeforeEnd && !*aPageBreakBeforeEnd && + (nsLayoutAtoms::tableRowFrame == kidType.get())) { + nsTableRowFrame* nextRow = ((nsTableRowFrame*)kidFrame)->GetNextRow(); + if (nextRow) { + *aPageBreakBeforeEnd = nsTableFrame::PageBreakAfter(*kidFrame, nextRow); + } + } + } else { // were done reflowing, so see if we need to reposition the rows that follow if (lastReflowedRow) { @@ -1015,7 +1027,7 @@ nsTableRowGroupFrame::SplitRowGroup(nsIPresContext* aPresContext, // 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, availHeight - bounds.y); + nsSize availSize(availWidth, PR_MAX(availHeight - bounds.y, 0)); nsHTMLReflowState rowReflowState(aPresContext, aReflowState, rowFrame, availSize, eReflowReason_Resize); InitChildReflowState(*aPresContext, borderCollapse, p2t, rowReflowState); @@ -1085,6 +1097,13 @@ nsTableRowGroupFrame::SplitRowGroup(nsIPresContext* aPresContext, aDesiredSize.height = bounds.YMost(); lastDesiredHeight = aDesiredSize.height; prevRowFrame = rowFrame; + // see if there is a page break after the row + nsTableRowFrame* nextRow = rowFrame->GetNextRow(); + if (nextRow && nsTableFrame::PageBreakAfter(*rowFrame, nextRow)) { + PushChildren(aPresContext, nextRow, rowFrame); + aStatus = NS_FRAME_NOT_COMPLETE; + break; + } } } return NS_OK; @@ -1143,8 +1162,9 @@ nsTableRowGroupFrame::Reflow(nsIPresContext* aPresContext, CacheRowHeightsForPrinting(aPresContext, GetFirstRow()); } // Reflow the existing frames. + PRBool splitDueToPageBreak = PR_FALSE; rv = ReflowChildren(aPresContext, aDesiredSize, state, aStatus, - nsnull, PR_FALSE); + nsnull, PR_FALSE, nsnull, &splitDueToPageBreak); // Return our desired rect aDesiredSize.width = aReflowState.availableWidth; @@ -1170,7 +1190,8 @@ nsTableRowGroupFrame::Reflow(nsIPresContext* aPresContext, } // See if all the frames fit - if ((NS_FRAME_NOT_COMPLETE == aStatus) || (aDesiredSize.height > aReflowState.availableHeight)) { + if ((NS_FRAME_NOT_COMPLETE == aStatus) || splitDueToPageBreak || + (aDesiredSize.height > aReflowState.availableHeight)) { // Nope, find a place to split the row group PRBool specialReflow = (PRBool)aReflowState.mFlags.mSpecialHeightReflow; ((nsHTMLReflowState::ReflowStateFlags&)aReflowState.mFlags).mSpecialHeightReflow = PR_FALSE; diff --git a/layout/tables/nsTableRowGroupFrame.h b/layout/tables/nsTableRowGroupFrame.h index d259a63bdfb7..789152b5a7eb 100644 --- a/layout/tables/nsTableRowGroupFrame.h +++ b/layout/tables/nsTableRowGroupFrame.h @@ -325,7 +325,8 @@ protected: nsReflowStatus& aStatus, nsTableRowFrame* aStartFrame, PRBool aDirtyOnly, - nsTableRowFrame** aFirstRowReflowed = nsnull); + nsTableRowFrame** aFirstRowReflowed = nsnull, + PRBool* aPageBreakBeforeEnd = nsnull); nsresult SplitRowGroup(nsIPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize,