Bug 978044: Center print-previewed pages inside the viewport. r=mats
--- a/layout/generic/nsSimplePageSequenceFrame.cpp
+++ b/layout/generic/nsSimplePageSequenceFrame.cpp
@@ -112,16 +112,53 @@ nsSimplePageSequenceFrame::SetDesiredSiz
// in child page frames correctly.
// Use availableWidth so we don't cause a needless horizontal scrollbar.
aDesiredSize.Width() = std::max(aReflowState.AvailableWidth(),
nscoord(aWidth * PresContext()->GetPrintPreviewScale()));
aDesiredSize.Height() = std::max(aReflowState.ComputedHeight(),
nscoord(aHeight * PresContext()->GetPrintPreviewScale()));
}
+// Helper function to compute the offset needed to center a child
+// page-frame's margin-box inside our content-box.
+nscoord
+nsSimplePageSequenceFrame::ComputeCenteringMargin(
+ nscoord aContainerContentBoxWidth,
+ nscoord aChildPaddingBoxWidth,
+ const nsMargin& aChildPhysicalMargin)
+{
+ // We'll be centering our child's margin-box, so get the size of that:
+ nscoord childMarginBoxWidth =
+ aChildPaddingBoxWidth + aChildPhysicalMargin.LeftRight();
+
+ // When rendered, our child's rect will actually be scaled up by the
+ // print-preview scale factor, via ComputePageSequenceTransform().
+ // We really want to center *that scaled-up rendering* inside of
+ // aContainerContentBoxWidth. So, we scale up its margin-box here...
+ auto ppScale = PresContext()->GetPrintPreviewScale();
+ nscoord scaledChildMarginBoxWidth =
+ NSToCoordRound(childMarginBoxWidth * ppScale);
+
+ // ...and see we how much space is left over, when we subtract that scaled-up
+ // size from the container width:
+ nscoord scaledExtraSpace =
+ aContainerContentBoxWidth - scaledChildMarginBoxWidth;
+
+ if (scaledExtraSpace <= 0) {
+ // (Don't bother centering if there's zero/negative space.)
+ return 0;
+ }
+
+ // To center the child, we want to give it an additional left-margin of half
+ // of the extra space. And then, we have to scale that space back down, so
+ // that it'll produce the correct scaled-up amount when we render (because
+ // rendering will scale it back up):
+ return NSToCoordRound(scaledExtraSpace * 0.5 / ppScale);
+}
+
void
nsSimplePageSequenceFrame::Reflow(nsPresContext* aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus)
{
NS_PRECONDITION(aPresContext->IsRootPaginatedDocument(),
"A Page Sequence is only for real pages");
@@ -133,16 +170,32 @@ nsSimplePageSequenceFrame::Reflow(nsPres
// Don't do incremental reflow until we've taught tables how to do
// it right in paginated mode.
if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
// Return our desired size
SetDesiredSize(aDesiredSize, aReflowState, mSize.width, mSize.height);
aDesiredSize.SetOverflowAreasToDesiredBounds();
FinishAndStoreOverflow(&aDesiredSize);
+
+ if (GetRect().Width() != aDesiredSize.Width()) {
+ // Our width is changing; we need to re-center our children (our pages).
+ for (nsFrameList::Enumerator e(mFrames); !e.AtEnd(); e.Next()) {
+ nsIFrame* child = e.get();
+ nsMargin pageCSSMargin = child->GetUsedMargin();
+ nscoord centeringMargin =
+ ComputeCenteringMargin(aReflowState.ComputedWidth(),
+ child->GetRect().width,
+ pageCSSMargin);
+ nscoord newX = pageCSSMargin.left + centeringMargin;
+
+ // Adjust the child's x-position:
+ child->MovePositionBy(nsPoint(newX - child->GetNormalPosition().x, 0));
+ }
+ }
return;
}
// See if we can get a Print Settings from the Context
if (!mPageData->mPrintSettings &&
aPresContext->Medium() == nsGkAtoms::print) {
mPageData->mPrintSettings = aPresContext->GetPrintSettings();
}
@@ -214,22 +267,26 @@ nsSimplePageSequenceFrame::Reflow(nsPres
nsReflowStatus status;
kidReflowState.SetComputedWidth(kidReflowState.AvailableWidth());
//kidReflowState.SetComputedHeight(kidReflowState.AvailableHeight());
PR_PL(("AV W: %d H: %d\n", kidReflowState.AvailableWidth(), kidReflowState.AvailableHeight()));
nsMargin pageCSSMargin = kidReflowState.ComputedPhysicalMargin();
y += pageCSSMargin.top;
- const nscoord x = pageCSSMargin.left;
+
+ nscoord x = pageCSSMargin.left;
- // Place and size the page. If the page is narrower than our
- // max width then center it horizontally
+ // Place and size the page.
ReflowChild(kidFrame, aPresContext, kidSize, kidReflowState, x, y, 0, status);
+ // If the page is narrower than our width, then center it horizontally:
+ x += ComputeCenteringMargin(aReflowState.ComputedWidth(),
+ kidSize.Width(), pageCSSMargin);
+
FinishReflowChild(kidFrame, aPresContext, kidSize, nullptr, x, y, 0);
y += kidSize.Height();
y += pageCSSMargin.bottom;
maxXMost = std::max(maxXMost, x + kidSize.Width() + pageCSSMargin.right);
// Is the page complete?
nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow();
@@ -758,17 +815,17 @@ nsSimplePageSequenceFrame::DoPageEnd()
ResetPrintCanvasList();
mPageNum++;
return rv;
}
-static gfx::Matrix4x4
+inline gfx::Matrix4x4
ComputePageSequenceTransform(nsIFrame* aFrame, float aAppUnitsPerPixel)
{
float scale = aFrame->PresContext()->GetPrintPreviewScale();
return gfx::Matrix4x4().Scale(scale, scale, 1);
}
void
nsSimplePageSequenceFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
--- a/layout/generic/nsSimplePageSequenceFrame.h
+++ b/layout/generic/nsSimplePageSequenceFrame.h
@@ -124,16 +124,23 @@ protected:
void SetPageNumberFormat(const nsAString& aFormatStr, bool aForPageNumOnly);
// Sets the frame desired size to the size of the viewport, or the given
// nscoords, whichever is larger. Print scaling is applied in this function.
void SetDesiredSize(nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nscoord aWidth, nscoord aHeight);
+ // Helper function to compute the offset needed to center a child
+ // page-frame's margin-box inside our content-box.
+ nscoord ComputeCenteringMargin(nscoord aContainerContentBoxWidth,
+ nscoord aChildPaddingBoxWidth,
+ const nsMargin& aChildPhysicalMargin);
+
+
void DetermineWhetherToPrintPage();
nsIFrame* GetCurrentPageFrame();
nsMargin mMargin;
// I18N date formatter service which we'll want to cache locally.
nsCOMPtr<nsIDateTimeFormat> mDateFormatter;