fune/layout/generic/nsPageSequenceFrame.cpp
L. David Baron c923b062b3 Bug 1547759 - Pass ReflowInput to FinishReflowChild in almost all cases. r=jfkthame
At first glance, it might look like this would change behavior, since
FinishReflowChild passes aReflowInput to DidReflow, which in turn
notifies aReflowInput's mPercentBSizeObserver.  However, if you examine
how the mPercentBSizeObserver is propagated, it can only be set for the
anonymous block wrapping the children of table cells, the children of
table cells, or additionally a child of a table wrapper frame that has
it set (i.e., a table or its caption, when logically a child of a table
cell).  Since all of the frames for which this is being changed are
either internal table elements that are inside of the table, or are
things that can never be a descendant of a table at all, there should be
no change in behavior.

Differential Revision: https://phabricator.services.mozilla.com/D40565

--HG--
extra : moz-landing-system : lando
2019-08-05 11:52:19 +00:00

733 lines
26 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsPageSequenceFrame.h"
#include "mozilla/PresShell.h"
#include "mozilla/dom/HTMLCanvasElement.h"
#include "DateTimeFormat.h"
#include "nsCOMPtr.h"
#include "nsDeviceContext.h"
#include "nsPresContext.h"
#include "gfxContext.h"
#include "nsGkAtoms.h"
#include "nsIPrintSettings.h"
#include "nsPageFrame.h"
#include "nsSubDocumentFrame.h"
#include "nsRegion.h"
#include "nsCSSFrameConstructor.h"
#include "nsContentUtils.h"
#include "nsDisplayList.h"
#include "nsHTMLCanvasFrame.h"
#include "nsICanvasRenderingContextInternal.h"
#include "nsServiceManagerUtils.h"
#include <algorithm>
#define OFFSET_NOT_SET -1
using namespace mozilla;
using namespace mozilla::dom;
#include "mozilla/Logging.h"
mozilla::LazyLogModule gLayoutPrintingLog("printing-layout");
#define PR_PL(_p1) MOZ_LOG(gLayoutPrintingLog, mozilla::LogLevel::Debug, _p1)
nsPageSequenceFrame* NS_NewPageSequenceFrame(PresShell* aPresShell,
ComputedStyle* aStyle) {
return new (aPresShell)
nsPageSequenceFrame(aStyle, aPresShell->GetPresContext());
}
NS_IMPL_FRAMEARENA_HELPERS(nsPageSequenceFrame)
nsPageSequenceFrame::nsPageSequenceFrame(ComputedStyle* aStyle,
nsPresContext* aPresContext)
: nsContainerFrame(aStyle, aPresContext, kClassID),
mTotalPages(-1),
mCalledBeginPage(false),
mCurrentCanvasListSetup(false) {
nscoord halfInch = PresContext()->CSSTwipsToAppUnits(NS_INCHES_TO_TWIPS(0.5));
mMargin.SizeTo(halfInch, halfInch, halfInch, halfInch);
mPageData = new nsSharedPageData();
mPageData->mHeadFootFont =
*PresContext()
->Document()
->GetFontPrefsForLang(aStyle->StyleFont()->mLanguage)
->GetDefaultFont(StyleGenericFontFamily::Serif);
mPageData->mHeadFootFont.size = nsPresContext::CSSPointsToAppUnits(10);
// Doing this here so we only have to go get these formats once
SetPageNumberFormat("pagenumber", "%1$d", true);
SetPageNumberFormat("pageofpages", "%1$d of %2$d", false);
}
nsPageSequenceFrame::~nsPageSequenceFrame() {
delete mPageData;
ResetPrintCanvasList();
}
NS_QUERYFRAME_HEAD(nsPageSequenceFrame)
NS_QUERYFRAME_ENTRY(nsPageSequenceFrame)
NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
//----------------------------------------------------------------------
void nsPageSequenceFrame::SetDesiredSize(ReflowOutput& aDesiredSize,
const ReflowInput& aReflowInput,
nscoord aWidth, nscoord aHeight) {
// Aim to fill the whole size of the document, not only so we
// can act as a background in print preview but also handle overflow
// in child page frames correctly.
// Use availableISize so we don't cause a needless horizontal scrollbar.
WritingMode wm = aReflowInput.GetWritingMode();
nscoord scaledWidth = aWidth * PresContext()->GetPrintPreviewScale();
nscoord scaledHeight = aHeight * PresContext()->GetPrintPreviewScale();
nscoord scaledISize = (wm.IsVertical() ? scaledHeight : scaledWidth);
nscoord scaledBSize = (wm.IsVertical() ? scaledWidth : scaledHeight);
aDesiredSize.ISize(wm) = std::max(scaledISize, aReflowInput.AvailableISize());
aDesiredSize.BSize(wm) = std::max(scaledBSize, aReflowInput.ComputedBSize());
}
// Helper function to compute the offset needed to center a child
// page-frame's margin-box inside our content-box.
nscoord nsPageSequenceFrame::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);
}
/*
* Note: we largely position/size out our children (page frames) using
* \*physical\* x/y/width/height values, because the print preview UI is always
* arranged in the same orientation, regardless of writing mode.
*/
void nsPageSequenceFrame::Reflow(nsPresContext* aPresContext,
ReflowOutput& aDesiredSize,
const ReflowInput& aReflowInput,
nsReflowStatus& aStatus) {
MarkInReflow();
MOZ_ASSERT(aPresContext->IsRootPaginatedDocument(),
"A Page Sequence is only for real pages");
DO_GLOBAL_REFLOW_COUNT("nsPageSequenceFrame");
DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
NS_FRAME_TRACE_REFLOW_IN("nsPageSequenceFrame::Reflow");
// 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, aReflowInput, 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(aReflowInput.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();
}
// now get out margins & edges
if (mPageData->mPrintSettings) {
nsIntMargin unwriteableTwips;
mPageData->mPrintSettings->GetUnwriteableMarginInTwips(unwriteableTwips);
NS_ASSERTION(unwriteableTwips.left >= 0 && unwriteableTwips.top >= 0 &&
unwriteableTwips.right >= 0 &&
unwriteableTwips.bottom >= 0,
"Unwriteable twips should be non-negative");
nsIntMargin marginTwips;
mPageData->mPrintSettings->GetMarginInTwips(marginTwips);
mMargin = nsPresContext::CSSTwipsToAppUnits(marginTwips + unwriteableTwips);
int16_t printType;
mPageData->mPrintSettings->GetPrintRange(&printType);
mPrintRangeType = printType;
nsIntMargin edgeTwips;
mPageData->mPrintSettings->GetEdgeInTwips(edgeTwips);
// sanity check the values. three inches are sometimes needed
int32_t inchInTwips = NS_INCHES_TO_INT_TWIPS(3.0);
edgeTwips.top = clamped(edgeTwips.top, 0, inchInTwips);
edgeTwips.bottom = clamped(edgeTwips.bottom, 0, inchInTwips);
edgeTwips.left = clamped(edgeTwips.left, 0, inchInTwips);
edgeTwips.right = clamped(edgeTwips.right, 0, inchInTwips);
mPageData->mEdgePaperMargin =
nsPresContext::CSSTwipsToAppUnits(edgeTwips + unwriteableTwips);
}
// *** Special Override ***
// If this is a sub-sdoc (meaning it doesn't take the whole page)
// and if this Document is in the upper left hand corner
// we need to suppress the top margin or it will reflow too small
nsSize pageSize = aPresContext->GetPageSize();
mPageData->mReflowSize = pageSize;
mPageData->mReflowMargin = mMargin;
// 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;
// Tile the pages vertically
ReflowOutput kidSize(aReflowInput);
for (nsFrameList::Enumerator e(mFrames); !e.AtEnd(); e.Next()) {
nsIFrame* kidFrame = e.get();
// Set the shared data into the page frame before reflow
nsPageFrame* pf = static_cast<nsPageFrame*>(kidFrame);
pf->SetSharedPageData(mPageData);
// Reflow the page
ReflowInput kidReflowInput(
aPresContext, aReflowInput, kidFrame,
LogicalSize(kidFrame->GetWritingMode(), pageSize));
nsReflowStatus status;
kidReflowInput.SetComputedISize(kidReflowInput.AvailableISize());
// kidReflowInput.SetComputedHeight(kidReflowInput.AvailableHeight());
PR_PL(("AV ISize: %d BSize: %d\n", kidReflowInput.AvailableISize(),
kidReflowInput.AvailableBSize()));
nsMargin pageCSSMargin = kidReflowInput.ComputedPhysicalMargin();
y += pageCSSMargin.top;
nscoord x = pageCSSMargin.left;
// Place and size the page.
ReflowChild(kidFrame, aPresContext, kidSize, kidReflowInput, x, y,
ReflowChildFlags::Default, status);
// If the page is narrower than our width, then center it horizontally:
x += ComputeCenteringMargin(aReflowInput.ComputedWidth(), kidSize.Width(),
pageCSSMargin);
FinishReflowChild(kidFrame, aPresContext, kidSize, &kidReflowInput, x, y,
ReflowChildFlags::Default);
y += kidSize.Height();
y += pageCSSMargin.bottom;
maxXMost = std::max(maxXMost, x + kidSize.Width() + pageCSSMargin.right);
// Is the page complete?
nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow();
if (status.IsFullyComplete()) {
NS_ASSERTION(!kidNextInFlow, "bad child flow list");
} else if (!kidNextInFlow) {
// The page isn't complete and it doesn't have a next-in-flow, so
// create a continuing page.
nsIFrame* continuingPage =
aPresContext->PresShell()->FrameConstructor()->CreateContinuingFrame(
aPresContext, kidFrame, this);
// Add it to our child list
mFrames.InsertFrame(nullptr, kidFrame, continuingPage);
}
}
// Get Total Page Count
// XXXdholbert technically we could calculate this in the loop above,
// instead of needing a separate walk.
int32_t pageTot = mFrames.GetLength();
// Set Page Number Info
int32_t pageNum = 1;
for (nsFrameList::Enumerator e(mFrames); !e.AtEnd(); e.Next()) {
MOZ_ASSERT(e.get()->IsPageFrame(),
"only expecting nsPageFrame children. Other children will make "
"this static_cast bogus & probably violate other assumptions");
nsPageFrame* pf = static_cast<nsPageFrame*>(e.get());
pf->SetPageNumInfo(pageNum, pageTot);
pageNum++;
}
nsAutoString formattedDateString;
PRTime now = PR_Now();
if (NS_SUCCEEDED(DateTimeFormat::FormatPRTime(
kDateFormatShort, kTimeFormatNoSeconds, now, formattedDateString))) {
SetDateTimeStr(formattedDateString);
}
// Return our desired size
// Adjust the reflow size by PrintPreviewScale so the scrollbars end up the
// correct size
SetDesiredSize(aDesiredSize, aReflowInput, maxXMost, y);
aDesiredSize.SetOverflowAreasToDesiredBounds();
FinishAndStoreOverflow(&aDesiredSize);
// cache the size so we can set the desired size
// for the other reflows that happen
mSize.width = maxXMost;
mSize.height = y;
NS_FRAME_TRACE_REFLOW_OUT("nsPageSequenceFrame::Reflow", aStatus);
NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
}
//----------------------------------------------------------------------
#ifdef DEBUG_FRAME_DUMP
nsresult nsPageSequenceFrame::GetFrameName(nsAString& aResult) const {
return MakeFrameName(NS_LITERAL_STRING("PageSequence"), aResult);
}
#endif
//====================================================================
//== Asynch Printing
//====================================================================
void nsPageSequenceFrame::GetPrintRange(int32_t* aFromPage,
int32_t* aToPage) const {
*aFromPage = mFromPageNum;
*aToPage = mToPageNum;
}
// Helper Function
void nsPageSequenceFrame::SetPageNumberFormat(const char* aPropName,
const char* aDefPropVal,
bool aPageNumOnly) {
// Doing this here so we only have to go get these formats once
nsAutoString pageNumberFormat;
// Now go get the Localized Page Formating String
nsresult rv = nsContentUtils::GetLocalizedString(
nsContentUtils::ePRINTING_PROPERTIES, aPropName, pageNumberFormat);
if (NS_FAILED(rv)) { // back stop formatting
pageNumberFormat.AssignASCII(aDefPropVal);
}
SetPageNumberFormat(pageNumberFormat, aPageNumOnly);
}
nsresult nsPageSequenceFrame::StartPrint(nsPresContext* aPresContext,
nsIPrintSettings* aPrintSettings,
const nsAString& aDocTitle,
const nsAString& aDocURL) {
NS_ENSURE_ARG_POINTER(aPresContext);
NS_ENSURE_ARG_POINTER(aPrintSettings);
if (!mPageData->mPrintSettings) {
mPageData->mPrintSettings = aPrintSettings;
}
if (!aDocTitle.IsEmpty()) {
mPageData->mDocTitle = aDocTitle;
}
if (!aDocURL.IsEmpty()) {
mPageData->mDocURL = aDocURL;
}
aPrintSettings->GetStartPageRange(&mFromPageNum);
aPrintSettings->GetEndPageRange(&mToPageNum);
aPrintSettings->GetPageRanges(mPageRanges);
mDoingPageRange =
nsIPrintSettings::kRangeSpecifiedPageRange == mPrintRangeType;
// If printing a range of pages make sure at least the starting page
// number is valid
mTotalPages = mFrames.GetLength();
if (mDoingPageRange) {
if (mFromPageNum > mTotalPages) {
return NS_ERROR_INVALID_ARG;
}
}
// Begin printing of the document
nsresult rv = NS_OK;
mPageNum = 1;
return rv;
}
static void GetPrintCanvasElementsInFrame(
nsIFrame* aFrame, nsTArray<RefPtr<HTMLCanvasElement> >* aArr) {
if (!aFrame) {
return;
}
for (nsIFrame::ChildListIterator childLists(aFrame); !childLists.IsDone();
childLists.Next()) {
nsFrameList children = childLists.CurrentList();
for (nsFrameList::Enumerator e(children); !e.AtEnd(); e.Next()) {
nsIFrame* child = e.get();
// Check if child is a nsHTMLCanvasFrame.
nsHTMLCanvasFrame* canvasFrame = do_QueryFrame(child);
// If there is a canvasFrame, try to get actual canvas element.
if (canvasFrame) {
HTMLCanvasElement* canvas =
HTMLCanvasElement::FromNodeOrNull(canvasFrame->GetContent());
if (canvas && canvas->GetMozPrintCallback()) {
aArr->AppendElement(canvas);
continue;
}
}
if (!child->PrincipalChildList().FirstChild()) {
nsSubDocumentFrame* subdocumentFrame = do_QueryFrame(child);
if (subdocumentFrame) {
// Descend into the subdocument
nsIFrame* root = subdocumentFrame->GetSubdocumentRootFrame();
child = root;
}
}
// The current child is not a nsHTMLCanvasFrame OR it is but there is
// no HTMLCanvasElement on it. Check if children of `child` might
// contain a HTMLCanvasElement.
GetPrintCanvasElementsInFrame(child, aArr);
}
}
}
void nsPageSequenceFrame::DetermineWhetherToPrintPage() {
// See whether we should print this page
mPrintThisPage = true;
bool printEvenPages, printOddPages;
mPageData->mPrintSettings->GetPrintOptions(nsIPrintSettings::kPrintEvenPages,
&printEvenPages);
mPageData->mPrintSettings->GetPrintOptions(nsIPrintSettings::kPrintOddPages,
&printOddPages);
// If printing a range of pages check whether the page number is in the
// range of pages to print
if (mDoingPageRange) {
if (mPageNum < mFromPageNum) {
mPrintThisPage = false;
} else if (mPageNum > mToPageNum) {
mPageNum++;
mPrintThisPage = false;
return;
} else {
int32_t length = mPageRanges.Length();
// Page ranges are pairs (start, end)
if (length && (length % 2 == 0)) {
mPrintThisPage = false;
int32_t i;
for (i = 0; i < length; i += 2) {
if (mPageRanges[i] <= mPageNum && mPageNum <= mPageRanges[i + 1]) {
mPrintThisPage = true;
break;
}
}
}
}
}
// Check for printing of odd and even pages
if (mPageNum & 0x1) {
if (!printOddPages) {
mPrintThisPage = false; // don't print odd numbered page
}
} else {
if (!printEvenPages) {
mPrintThisPage = false; // don't print even numbered page
}
}
}
nsIFrame* nsPageSequenceFrame::GetCurrentPageFrame() {
int32_t i = 1;
for (nsFrameList::Enumerator childFrames(mFrames); !childFrames.AtEnd();
childFrames.Next()) {
if (i == mPageNum) {
return childFrames.get();
}
++i;
}
return nullptr;
}
nsresult nsPageSequenceFrame::PrePrintNextPage(nsITimerCallback* aCallback,
bool* aDone) {
nsIFrame* currentPage = GetCurrentPageFrame();
if (!currentPage) {
*aDone = true;
return NS_ERROR_FAILURE;
}
DetermineWhetherToPrintPage();
// Nothing to do if the current page doesn't get printed OR rendering to
// preview. For preview, the `CallPrintCallback` is called from within the
// HTMLCanvasElement::HandlePrintCallback.
if (!mPrintThisPage || !PresContext()->IsRootPaginatedDocument()) {
*aDone = true;
return NS_OK;
}
// If the canvasList is null, then generate it and start the render
// process for all the canvas.
if (!mCurrentCanvasListSetup) {
mCurrentCanvasListSetup = true;
GetPrintCanvasElementsInFrame(currentPage, &mCurrentCanvasList);
if (mCurrentCanvasList.Length() != 0) {
nsresult rv = NS_OK;
// Begin printing of the document
nsDeviceContext* dc = PresContext()->DeviceContext();
PR_PL(("\n"));
PR_PL(("***************** BeginPage *****************\n"));
rv = dc->BeginPage();
NS_ENSURE_SUCCESS(rv, rv);
mCalledBeginPage = true;
RefPtr<gfxContext> renderingContext = dc->CreateRenderingContext();
NS_ENSURE_TRUE(renderingContext, NS_ERROR_OUT_OF_MEMORY);
DrawTarget* drawTarget = renderingContext->GetDrawTarget();
if (NS_WARN_IF(!drawTarget)) {
return NS_ERROR_FAILURE;
}
for (int32_t i = mCurrentCanvasList.Length() - 1; i >= 0; i--) {
HTMLCanvasElement* canvas = mCurrentCanvasList[i];
nsIntSize size = canvas->GetSize();
RefPtr<DrawTarget> canvasTarget =
drawTarget->CreateSimilarDrawTarget(size, drawTarget->GetFormat());
if (!canvasTarget) {
continue;
}
nsICanvasRenderingContextInternal* ctx = canvas->GetContextAtIndex(0);
if (!ctx) {
continue;
}
// Initialize the context with the new DrawTarget.
ctx->InitializeWithDrawTarget(nullptr, WrapNotNull(canvasTarget));
// Start the rendering process.
// Note: Other than drawing to our CanvasRenderingContext2D, the
// callback cannot access or mutate our static clone document. It is
// evaluated in its original context (the window of the original
// document) of course, and our canvas has a strong ref to the
// original HTMLCanvasElement (in mOriginalCanvas) so that if the
// callback calls GetCanvas() on our CanvasRenderingContext2D (passed
// to it via a MozCanvasPrintState argument) it will be given the
// original 'canvas' element.
AutoWeakFrame weakFrame = this;
canvas->DispatchPrintCallback(aCallback);
NS_ENSURE_STATE(weakFrame.IsAlive());
}
}
}
uint32_t doneCounter = 0;
for (int32_t i = mCurrentCanvasList.Length() - 1; i >= 0; i--) {
HTMLCanvasElement* canvas = mCurrentCanvasList[i];
if (canvas->IsPrintCallbackDone()) {
doneCounter++;
}
}
// If all canvas have finished rendering, return true, otherwise false.
*aDone = doneCounter == mCurrentCanvasList.Length();
return NS_OK;
}
void nsPageSequenceFrame::ResetPrintCanvasList() {
for (int32_t i = mCurrentCanvasList.Length() - 1; i >= 0; i--) {
HTMLCanvasElement* canvas = mCurrentCanvasList[i];
canvas->ResetPrintCallback();
}
mCurrentCanvasList.Clear();
mCurrentCanvasListSetup = false;
}
nsresult nsPageSequenceFrame::PrintNextPage() {
// Note: When print al the pages or a page range the printed page shows the
// actual page number, when printing selection it prints the page number
// starting with the first page of the selection. For example if the user has
// a selection that starts on page 2 and ends on page 3, the page numbers when
// print are 1 and then two (which is different than printing a page range,
// where the page numbers would have been 2 and then 3)
nsIFrame* currentPageFrame = GetCurrentPageFrame();
if (!currentPageFrame) {
return NS_ERROR_FAILURE;
}
nsresult rv = NS_OK;
DetermineWhetherToPrintPage();
if (mPrintThisPage) {
nsDeviceContext* dc = PresContext()->DeviceContext();
if (PresContext()->IsRootPaginatedDocument()) {
if (!mCalledBeginPage) {
// We must make sure BeginPage() has been called since some printing
// backends can't give us a valid rendering context for a [physical]
// page otherwise.
PR_PL(("\n"));
PR_PL(("***************** BeginPage *****************\n"));
rv = dc->BeginPage();
NS_ENSURE_SUCCESS(rv, rv);
}
}
PR_PL(
("SeqFr::PrintNextPage -> %p PageNo: %d", currentPageFrame, mPageNum));
// CreateRenderingContext can fail
RefPtr<gfxContext> gCtx = dc->CreateRenderingContext();
NS_ENSURE_TRUE(gCtx, NS_ERROR_OUT_OF_MEMORY);
nsRect drawingRect(nsPoint(0, 0), currentPageFrame->GetSize());
nsRegion drawingRegion(drawingRect);
nsLayoutUtils::PaintFrame(gCtx, currentPageFrame, drawingRegion,
NS_RGBA(0, 0, 0, 0),
nsDisplayListBuilderMode::Painting,
nsLayoutUtils::PaintFrameFlags::SyncDecodeImages);
}
return rv;
}
nsresult nsPageSequenceFrame::DoPageEnd() {
nsresult rv = NS_OK;
if (PresContext()->IsRootPaginatedDocument() && mPrintThisPage) {
PR_PL(("***************** End Page (DoPageEnd) *****************\n"));
rv = PresContext()->DeviceContext()->EndPage();
NS_ENSURE_SUCCESS(rv, rv);
}
ResetPrintCanvasList();
mCalledBeginPage = false;
mPageNum++;
return rv;
}
inline gfx::Matrix4x4 ComputePageSequenceTransform(nsIFrame* aFrame,
float aAppUnitsPerPixel) {
float scale = aFrame->PresContext()->GetPrintPreviewScale();
return gfx::Matrix4x4::Scaling(scale, scale, 1);
}
void nsPageSequenceFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsDisplayListSet& aLists) {
aBuilder->SetInPageSequence(true);
aBuilder->SetDisablePartialUpdates(true);
DisplayBorderBackgroundOutline(aBuilder, aLists);
nsDisplayList content;
{
// Clear clip state while we construct the children of the
// nsDisplayTransform, since they'll be in a different coordinate system.
DisplayListClipState::AutoSaveRestore clipState(aBuilder);
clipState.Clear();
nsIFrame* child = PrincipalChildList().FirstChild();
nsRect visible = aBuilder->GetVisibleRect();
visible.ScaleInverseRoundOut(PresContext()->GetPrintPreviewScale());
while (child) {
if (child->GetVisualOverflowRectRelativeToParent().Intersects(visible)) {
nsDisplayListBuilder::AutoBuildingDisplayList buildingForChild(
aBuilder, child, visible - child->GetPosition(),
visible - child->GetPosition());
child->BuildDisplayListForStackingContext(aBuilder, &content);
aBuilder->ResetMarkedFramesForDisplayList(this);
}
child = child->GetNextSibling();
}
}
content.AppendNewToTop<nsDisplayTransform>(aBuilder, this, &content,
content.GetBuildingRect(), 0,
::ComputePageSequenceTransform);
aLists.Content()->AppendToTop(&content);
aBuilder->SetInPageSequence(false);
}
//------------------------------------------------------------------------------
void nsPageSequenceFrame::SetPageNumberFormat(const nsAString& aFormatStr,
bool aForPageNumOnly) {
NS_ASSERTION(mPageData != nullptr, "mPageData string cannot be null!");
if (aForPageNumOnly) {
mPageData->mPageNumFormat = aFormatStr;
} else {
mPageData->mPageNumAndTotalsFormat = aFormatStr;
}
}
//------------------------------------------------------------------------------
void nsPageSequenceFrame::SetDateTimeStr(const nsAString& aDateTimeStr) {
NS_ASSERTION(mPageData != nullptr, "mPageData string cannot be null!");
mPageData->mDateTimeStr = aDateTimeStr;
}
void nsPageSequenceFrame::AppendDirectlyOwnedAnonBoxes(
nsTArray<OwnedAnonBox>& aResult) {
if (mFrames.NotEmpty()) {
aResult.AppendElement(mFrames.FirstChild());
}
}