Bug 115199 - CSS2 @page rule rendering support. r=roc

This commit is contained in:
Brendan Dahl 2012-08-31 14:20:56 -07:00
parent cf3b64d2eb
commit 3b71cbe23b
11 changed files with 169 additions and 64 deletions

View File

@ -24,19 +24,6 @@ NS_NewPageContentFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
NS_IMPL_FRAMEARENA_HELPERS(nsPageContentFrame)
/* virtual */ nsSize
nsPageContentFrame::ComputeSize(nsRenderingContext *aRenderingContext,
nsSize aCBSize, nscoord aAvailableWidth,
nsSize aMargin, nsSize aBorder, nsSize aPadding,
uint32_t aFlags)
{
NS_ASSERTION(mPD, "Pages are supposed to have page data");
nscoord height = (!mPD || mPD->mReflowSize.height == NS_UNCONSTRAINEDSIZE)
? NS_UNCONSTRAINEDSIZE
: (mPD->mReflowSize.height - mPD->mReflowMargin.TopBottom());
return nsSize(aAvailableWidth, height);
}
NS_IMETHODIMP
nsPageContentFrame::Reflow(nsPresContext* aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
@ -57,18 +44,19 @@ nsPageContentFrame::Reflow(nsPresContext* aPresContext,
// Set our size up front, since some parts of reflow depend on it
// being already set. Note that the computed height may be
// unconstrained; that's ok. Consumers should watch out for that.
SetSize(nsSize(aReflowState.availableWidth, aReflowState.availableHeight));
nsSize maxSize(aReflowState.ComputedWidth(),
aReflowState.ComputedHeight());
SetSize(maxSize);
// A PageContentFrame must always have one child: the canvas frame.
// Resize our frame allowing it only to be as big as we are
// XXX Pay attention to the page's border and padding...
if (mFrames.NotEmpty()) {
nsIFrame* frame = mFrames.FirstChild();
nsSize maxSize(aReflowState.availableWidth, aReflowState.availableHeight);
nsHTMLReflowState kidReflowState(aPresContext, aReflowState, frame, maxSize);
kidReflowState.SetComputedHeight(aReflowState.availableHeight);
kidReflowState.SetComputedHeight(maxSize.height);
mPD->mPageContentSize = aReflowState.availableWidth;
mPD->mPageContentSize = maxSize.width;
// Reflow the page content area
rv = ReflowChild(frame, aPresContext, aDesiredSize, kidReflowState, 0, 0, 0, aStatus);
@ -112,9 +100,9 @@ nsPageContentFrame::Reflow(nsPresContext* aPresContext,
NS_ASSERTION(NS_FRAME_IS_COMPLETE(fixedStatus), "fixed frames can be truncated, but not incomplete");
// Return our desired size
aDesiredSize.width = aReflowState.availableWidth;
if (aReflowState.availableHeight != NS_UNCONSTRAINEDSIZE) {
aDesiredSize.height = aReflowState.availableHeight;
aDesiredSize.width = aReflowState.ComputedWidth();
if (aReflowState.ComputedHeight() != NS_UNCONSTRAINEDSIZE) {
aDesiredSize.height = aReflowState.ComputedHeight();
}
FinishAndStoreOverflow(&aDesiredSize);

View File

@ -33,15 +33,6 @@ public:
virtual void SetSharedPageData(nsSharedPageData* aPD) { mPD = aPD; }
/**
* Computes page size based on shared page data; SetSharedPageData must be
* given valid data first.
*/
virtual nsSize ComputeSize(nsRenderingContext *aRenderingContext,
nsSize aCBSize, nscoord aAvailableWidth,
nsSize aMargin, nsSize aBorder, nsSize aPadding,
uint32_t aFlags) MOZ_OVERRIDE;
virtual bool HasTransformGetter() const MOZ_OVERRIDE { return true; }
/**

View File

@ -72,10 +72,9 @@ NS_IMETHODIMP nsPageFrame::Reflow(nsPresContext* aPresContext,
if (mPD->mReflowSize.height == NS_UNCONSTRAINEDSIZE) {
avHeight = NS_UNCONSTRAINEDSIZE;
} else {
avHeight = mPD->mReflowSize.height - mPD->mReflowMargin.TopBottom();
avHeight = mPD->mReflowSize.height;
}
nsSize maxSize(mPD->mReflowSize.width - mPD->mReflowMargin.LeftRight(),
avHeight);
nsSize maxSize(mPD->mReflowSize.width, avHeight);
float scale = aPresContext->GetPageScale();
maxSize.width = NSToCoordCeil(maxSize.width / scale);
if (maxSize.height != NS_UNCONSTRAINEDSIZE) {
@ -97,9 +96,46 @@ NS_IMETHODIMP nsPageFrame::Reflow(nsPresContext* aPresContext,
kidReflowState.mFlags.mIsTopOfPage = true;
kidReflowState.mFlags.mTableIsSplittable = true;
// Use the margins given in the @page rule.
// If a margin is 'auto', use the margin from the print settings for that side.
nsMargin pageContentMargin;
const nsStyleSides& marginStyle = kidReflowState.mStyleMargin->mMargin;
NS_FOR_CSS_SIDES(side) {
if (marginStyle.GetUnit(side) == eStyleUnit_Auto) {
pageContentMargin.Side(side) = mPD->mReflowMargin.Side(side);
} else {
pageContentMargin.Side(side) = kidReflowState.mComputedMargin.Side(side);
}
}
nscoord maxWidth = maxSize.width - pageContentMargin.LeftRight() / scale;
nscoord maxHeight;
if (maxSize.height == NS_UNCONSTRAINEDSIZE) {
maxHeight = NS_UNCONSTRAINEDSIZE;
} else {
maxHeight = maxSize.height - pageContentMargin.TopBottom() / scale;
}
// Check the width and height, if they're too small we reset the margins
// back to the default.
if (maxWidth < onePixelInTwips ||
(maxHeight != NS_UNCONSTRAINEDSIZE && maxHeight < onePixelInTwips)) {
NS_FOR_CSS_SIDES(side) {
pageContentMargin.Side(side) = mPD->mReflowMargin.Side(side);
}
maxWidth = maxSize.width - pageContentMargin.LeftRight() / scale;
if (maxHeight != NS_UNCONSTRAINEDSIZE) {
maxHeight = maxSize.height - pageContentMargin.TopBottom() / scale;
}
}
kidReflowState.SetComputedWidth(maxWidth);
kidReflowState.SetComputedHeight(maxHeight);
// calc location of frame
nscoord xc = mPD->mReflowMargin.left + mPD->mExtraMargin.left;
nscoord yc = mPD->mReflowMargin.top + mPD->mExtraMargin.top;
nscoord xc = pageContentMargin.left;
nscoord yc = pageContentMargin.top;
// Get the child's desired size
ReflowChild(frame, aPresContext, aDesiredSize, kidReflowState, xc, yc, 0, aStatus);
@ -220,7 +256,7 @@ nscoord nsPageFrame::GetXPosition(nsRenderingContext& aRenderingContext,
nscoord x = aRect.x;
switch (aJust) {
case nsIPrintSettings::kJustLeft:
x += mPD->mExtraMargin.left + mPD->mEdgePaperMargin.left;
x += mPD->mEdgePaperMargin.left;
break;
case nsIPrintSettings::kJustCenter:
@ -228,7 +264,7 @@ nscoord nsPageFrame::GetXPosition(nsRenderingContext& aRenderingContext,
break;
case nsIPrintSettings::kJustRight:
x += aRect.width - width - mPD->mExtraMargin.right - mPD->mEdgePaperMargin.right;
x += aRect.width - width - mPD->mEdgePaperMargin.right;
break;
} // switch
@ -345,9 +381,9 @@ nsPageFrame::DrawHeaderFooter(nsRenderingContext& aRenderingContext,
nscoord x = GetXPosition(aRenderingContext, aRect, aJust, str);
nscoord y;
if (aHeaderFooter == eHeader) {
y = aRect.y + mPD->mExtraMargin.top + mPD->mEdgePaperMargin.top;
y = aRect.y + mPD->mEdgePaperMargin.top;
} else {
y = aRect.YMost() - aHeight - mPD->mExtraMargin.bottom - mPD->mEdgePaperMargin.bottom;
y = aRect.YMost() - aHeight - mPD->mEdgePaperMargin.bottom;
}
// set up new clip and draw the text
@ -511,8 +547,7 @@ nsPageFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
nsRect clipRect(nsPoint(0, 0), child->GetSize());
// Note: this computation matches how we compute maxSize.height
// in nsPageFrame::Reflow
nscoord expectedPageContentHeight =
NSToCoordCeil((GetSize().height - mPD->mReflowMargin.TopBottom()) / scale);
nscoord expectedPageContentHeight = NSToCoordCeil(GetSize().height / scale);
if (clipRect.height > expectedPageContentHeight) {
// We're doing print-selection, with one long page-content frame.
// Clip to the appropriate page-content slice for the current page.

View File

@ -65,7 +65,6 @@ nsSharedPageData::nsSharedPageData() :
mDocURL(nullptr),
mReflowSize(0,0),
mReflowMargin(0,0,0,0),
mExtraMargin(0,0,0,0),
mEdgePaperMargin(0,0,0,0),
mPageContentXMost(0),
mPageContentSize(0)
@ -220,31 +219,12 @@ nsSimplePageSequenceFrame::Reflow(nsPresContext* aPresContext,
}
mPageData->mReflowMargin = mMargin;
// Compute the size of each page and the x coordinate that each page will
// be placed at
nscoord extraThreshold = NS_MAX(pageSize.width, pageSize.height)/10;
int32_t gapInTwips = Preferences::GetInt("print.print_extra_margin");
gapInTwips = NS_MAX(0, gapInTwips);
nscoord extraGap = aPresContext->CSSTwipsToAppUnits(gapInTwips);
extraGap = NS_MIN(extraGap, extraThreshold); // clamp to 1/10 of the largest dim of the page
nsMargin extraMargin(0,0,0,0);
if (aPresContext->IsScreen()) {
extraMargin.SizeTo(extraGap, extraGap, extraGap, extraGap);
}
mPageData->mExtraMargin = extraMargin;
// We use the CSS "margin" property on the -moz-page pseudoelement
// to determine the space between each page in print preview.
// Keep a running y-offset for each page.
nscoord y = 0;
nscoord maxXMost = 0;
nsSize availSize(pageSize.width + extraMargin.LeftRight(),
pageSize.height + extraMargin.TopBottom());
// Tile the pages vertically
nsHTMLReflowMetrics kidSize;
for (nsIFrame* kidFrame = mFrames.FirstChild(); nullptr != kidFrame; ) {
@ -254,7 +234,7 @@ nsSimplePageSequenceFrame::Reflow(nsPresContext* aPresContext,
// Reflow the page
nsHTMLReflowState kidReflowState(aPresContext, aReflowState, kidFrame,
availSize);
pageSize);
nsReflowStatus status;
kidReflowState.SetComputedWidth(kidReflowState.availableWidth);

View File

@ -31,9 +31,6 @@ public:
nsSize mReflowSize;
nsMargin mReflowMargin;
// Extra Margin between the device area and the edge of the page;
// approximates unprintable area
nsMargin mExtraMargin;
// Margin for headers and footers; it defaults to 4/100 of an inch on UNIX
// and 0 elsewhere; I think it has to do with some inconsistency in page size
// computations

View File

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html class="reftest-print">
<head>
<style>
* {
margin: 0;
padding: 0;
}
body {
margin: 0.1in 0.1in;
}
div {
border: 0.25in solid green;
}
</style>
</head>
<body>
<div></div>
</body>
</html>

View File

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html class="reftest-print">
<head>
<style>
@page {
/*
* Default page margins are .5in and the reference file adds .1inch margin
* to the body hence we do .6in to match this.
*/
margin: 0.6in;
}
* {
margin: 0;
padding: 0;
}
div {
width: 100%;
border: 0.25in solid green;
}
</style>
</head>
<body>
<div></div>
</body>
</html>

View File

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html class="reftest-print">
<head>
<style>
* {
margin: 0;
padding: 0;
}
div {
width: 100%;
border: 0.25in solid green;
}
</style>
</head>
<body>
<div></div>
</body>
</html>

View File

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html class="reftest-print">
<head>
<style>
@page {
/*
* Test a margin that causes the page to have zero width.
*/
margin: 0 2.5in;
}
* {
margin: 0;
padding: 0;
}
div {
width: 100%;
border: 0.25in solid green;
}
</style>
</head>
<body>
<div></div>
</body>
</html>

View File

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html class="reftest-print">
<head>
<style>
@page {
/*
* Test huge margins, they should be reset back the default margin size.
*/
margin: 10in;
}
* {
margin: 0;
padding: 0;
}
div {
width: 100%;
border: 0.25in solid green;
}
</style>
</head>
<body>
<div></div>
</body>
</html>

View File

@ -20,5 +20,8 @@
== 626395-2c.html 626395-2-ref.html
== 626395-2d.html 626395-2-ref.html
== 652178-1.html 652178-1-ref.html
== 115199-1.html 115199-1-ref.html
== 115199-2a.html 115199-2-ref.html
== 115199-2b.html 115199-2-ref.html
== 652178-1.html 652178-1-ref2.html
== 745025-1.html 745025-1-ref.html