Files
tubestation/layout/generic/nsSimplePageSequenceFrame.cpp
Ryan VanderMeulen c55b45acd3 Backed out 46 changesets (bug 1022612) for B2G mochitest permafails on a CLOSED TREE.
Backed out changeset 34b3014a3112 (bug 1022612)
Backed out changeset 6ae9316fd909 (bug 1022612)
Backed out changeset b8f3749c95eb (bug 1022612)
Backed out changeset caab10bf6ca3 (bug 1022612)
Backed out changeset 0c57c620c898 (bug 1022612)
Backed out changeset fac64141a00a (bug 1022612)
Backed out changeset bf0df1c9d68b (bug 1022612)
Backed out changeset b42054800020 (bug 1022612)
Backed out changeset 667793b21194 (bug 1022612)
Backed out changeset f14ada64fe1b (bug 1022612)
Backed out changeset 75b837686bdf (bug 1022612)
Backed out changeset 66de53183a22 (bug 1022612)
Backed out changeset 0ff86ced4d46 (bug 1022612)
Backed out changeset 18eecc5b1ef7 (bug 1022612)
Backed out changeset 2763c4878de5 (bug 1022612)
Backed out changeset b72413ecc385 (bug 1022612)
Backed out changeset b23f1081afb8 (bug 1022612)
Backed out changeset f7e2c6a72043 (bug 1022612)
Backed out changeset 959917c9027d (bug 1022612)
Backed out changeset 0268a46f4880 (bug 1022612)
Backed out changeset 3388856a80ad (bug 1022612)
Backed out changeset e4b17cf0f806 (bug 1022612)
Backed out changeset 2f4e9da0e4b6 (bug 1022612)
Backed out changeset 489f6a7c0c03 (bug 1022612)
Backed out changeset 8369d9ad7ad3 (bug 1022612)
Backed out changeset 0758d2a06002 (bug 1022612)
Backed out changeset f2ae9cb22edb (bug 1022612)
Backed out changeset 9c48c6ee5dc2 (bug 1022612)
Backed out changeset fe7134400f08 (bug 1022612)
Backed out changeset cc2c5397ca8b (bug 1022612)
Backed out changeset a3d1a3e8b39d (bug 1022612)
Backed out changeset 8974b74b0eb0 (bug 1022612)
Backed out changeset 75f7dbb5a2a6 (bug 1022612)
Backed out changeset 2aa04a071e60 (bug 1022612)
Backed out changeset f2ab1bcd4c39 (bug 1022612)
Backed out changeset da9152b6ea29 (bug 1022612)
Backed out changeset 58abf5b0e148 (bug 1022612)
Backed out changeset 797058a09ad2 (bug 1022612)
Backed out changeset ea3e99a92ff0 (bug 1022612)
Backed out changeset adc4a4a7aa73 (bug 1022612)
Backed out changeset 7b18dedd1505 (bug 1022612)
Backed out changeset 055dd1921e8e (bug 1022612)
Backed out changeset 42fa2c97e989 (bug 1022612)
Backed out changeset cd594236388f (bug 1022612)
Backed out changeset 9eadc5fee43d (bug 1022612)
Backed out changeset 5cc8d30ff7c9 (bug 1022612)
2014-07-17 11:24:47 -04:00

845 lines
26 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 "nsSimplePageSequenceFrame.h"
#include "nsCOMPtr.h"
#include "nsPresContext.h"
#include "gfxContext.h"
#include "nsRenderingContext.h"
#include "nsGkAtoms.h"
#include "nsIPresShell.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 "mozilla/dom/HTMLCanvasElement.h"
#include "nsICanvasRenderingContextInternal.h"
#include "nsIDateTimeFormat.h"
#include "nsServiceManagerUtils.h"
#include <algorithm>
// DateTime Includes
#include "nsDateTimeFormatCID.h"
#define OFFSET_NOT_SET -1
// Print Options
#include "nsIPrintOptions.h"
using namespace mozilla;
using namespace mozilla::dom;
static const char sPrintOptionsContractID[] = "@mozilla.org/gfx/printsettings-service;1";
//
#include "prlog.h"
#ifdef PR_LOGGING
PRLogModuleInfo *
GetLayoutPrintingLog()
{
static PRLogModuleInfo *sLog;
if (!sLog)
sLog = PR_NewLogModule("printing-layout");
return sLog;
}
#define PR_PL(_p1) PR_LOG(GetLayoutPrintingLog(), PR_LOG_DEBUG, _p1)
#else
#define PR_PL(_p1)
#endif
nsSimplePageSequenceFrame*
NS_NewSimplePageSequenceFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
{
return new (aPresShell) nsSimplePageSequenceFrame(aContext);
}
NS_IMPL_FRAMEARENA_HELPERS(nsSimplePageSequenceFrame)
nsSimplePageSequenceFrame::nsSimplePageSequenceFrame(nsStyleContext* aContext) :
nsContainerFrame(aContext),
mTotalPages(-1),
mSelectionHeight(-1),
mYSelOffset(0),
mCalledBeginPage(false),
mCurrentCanvasListSetup(false)
{
nscoord halfInch = PresContext()->CSSTwipsToAppUnits(NS_INCHES_TO_TWIPS(0.5));
mMargin.SizeTo(halfInch, halfInch, halfInch, halfInch);
// XXX Unsafe to assume successful allocation
mPageData = new nsSharedPageData();
mPageData->mHeadFootFont =
*PresContext()->GetDefaultFont(kGenericFont_serif,
aContext->StyleFont()->mLanguage);
mPageData->mHeadFootFont.size = nsPresContext::CSSPointsToAppUnits(10);
nsresult rv;
mPageData->mPrintOptions = do_GetService(sPrintOptionsContractID, &rv);
// 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);
}
nsSimplePageSequenceFrame::~nsSimplePageSequenceFrame()
{
delete mPageData;
ResetPrintCanvasList();
}
NS_QUERYFRAME_HEAD(nsSimplePageSequenceFrame)
NS_QUERYFRAME_ENTRY(nsIPageSequenceFrame)
NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
//----------------------------------------------------------------------
void
nsSimplePageSequenceFrame::SetDesiredSize(nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
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 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()));
}
void
nsSimplePageSequenceFrame::Reflow(nsPresContext* aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus)
{
NS_PRECONDITION(aPresContext->IsRootPaginatedDocument(),
"A Page Sequence is only for real pages");
DO_GLOBAL_REFLOW_COUNT("nsSimplePageSequenceFrame");
DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
NS_FRAME_TRACE_REFLOW_IN("nsSimplePageSequenceFrame::Reflow");
aStatus = NS_FRAME_COMPLETE; // we're always complete
// 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);
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 = aPresContext->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 =
aPresContext->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;
// If we're printing a selection, we need to reflow with
// unconstrained height, to make sure we'll get to the selection
// even if it's beyond the first page of content.
if (nsIPrintSettings::kRangeSelection == mPrintRangeType) {
mPageData->mReflowSize.height = NS_UNCONSTRAINEDSIZE;
}
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
nsHTMLReflowMetrics kidSize(aReflowState);
for (nsIFrame* kidFrame = mFrames.FirstChild(); nullptr != kidFrame; ) {
// Set the shared data into the page frame before reflow
nsPageFrame * pf = static_cast<nsPageFrame*>(kidFrame);
pf->SetSharedPageData(mPageData);
// Reflow the page
nsHTMLReflowState kidReflowState(aPresContext, aReflowState, kidFrame,
pageSize);
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;
// Place and size the page. If the page is narrower than our
// max width then center it horizontally
ReflowChild(kidFrame, aPresContext, kidSize, kidReflowState, x, y, 0, status);
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();
if (NS_FRAME_IS_FULLY_COMPLETE(status)) {
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 the next page
kidFrame = kidFrame->GetNextSibling();
}
// Get Total Page Count
nsIFrame* page;
int32_t pageTot = 0;
for (page = mFrames.FirstChild(); page; page = page->GetNextSibling()) {
pageTot++;
}
// Set Page Number Info
int32_t pageNum = 1;
for (page = mFrames.FirstChild(); page; page = page->GetNextSibling()) {
nsPageFrame * pf = static_cast<nsPageFrame*>(page);
if (pf != nullptr) {
pf->SetPageNumInfo(pageNum, pageTot);
}
pageNum++;
}
// Create current Date/Time String
if (!mDateFormatter) {
mDateFormatter = do_CreateInstance(NS_DATETIMEFORMAT_CONTRACTID);
}
if (!mDateFormatter) {
return;
}
nsAutoString formattedDateString;
time_t ltime;
time( &ltime );
if (NS_SUCCEEDED(mDateFormatter->FormatTime(nullptr /* nsILocale* locale */,
kDateFormatShort,
kTimeFormatNoSeconds,
ltime,
formattedDateString))) {
SetDateTimeStr(formattedDateString);
}
// Return our desired size
// Adjust the reflow size by PrintPreviewScale so the scrollbars end up the
// correct size
SetDesiredSize(aDesiredSize, aReflowState, 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("nsSimplePageSequeceFrame::Reflow", aStatus);
NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
}
//----------------------------------------------------------------------
#ifdef DEBUG_FRAME_DUMP
nsresult
nsSimplePageSequenceFrame::GetFrameName(nsAString& aResult) const
{
return MakeFrameName(NS_LITERAL_STRING("SimplePageSequence"), aResult);
}
#endif
//====================================================================
//== Asynch Printing
//====================================================================
NS_IMETHODIMP
nsSimplePageSequenceFrame::GetCurrentPageNum(int32_t* aPageNum)
{
NS_ENSURE_ARG_POINTER(aPageNum);
*aPageNum = mPageNum;
return NS_OK;
}
NS_IMETHODIMP
nsSimplePageSequenceFrame::GetNumPages(int32_t* aNumPages)
{
NS_ENSURE_ARG_POINTER(aNumPages);
*aNumPages = mTotalPages;
return NS_OK;
}
NS_IMETHODIMP
nsSimplePageSequenceFrame::IsDoingPrintRange(bool* aDoing)
{
NS_ENSURE_ARG_POINTER(aDoing);
*aDoing = mDoingPageRange;
return NS_OK;
}
NS_IMETHODIMP
nsSimplePageSequenceFrame::GetPrintRange(int32_t* aFromPage, int32_t* aToPage)
{
NS_ENSURE_ARG_POINTER(aFromPage);
NS_ENSURE_ARG_POINTER(aToPage);
*aFromPage = mFromPageNum;
*aToPage = mToPageNum;
return NS_OK;
}
// Helper Function
void
nsSimplePageSequenceFrame::SetPageNumberFormat(const char* aPropName, const char* aDefPropVal, bool aPageNumOnly)
{
// Doing this here so we only have to go get these formats once
nsXPIDLString 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);
}
NS_IMETHODIMP
nsSimplePageSequenceFrame::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 ||
nsIPrintSettings::kRangeSelection == mPrintRangeType;
// If printing a range of pages make sure at least the starting page
// number is valid
int32_t totalPages = mFrames.GetLength();
if (mDoingPageRange) {
if (mFromPageNum > totalPages) {
return NS_ERROR_INVALID_ARG;
}
}
// Begin printing of the document
nsresult rv = NS_OK;
// Determine if we are rendering only the selection
aPresContext->SetIsRenderingOnlySelection(nsIPrintSettings::kRangeSelection == mPrintRangeType);
if (mDoingPageRange) {
// XXX because of the hack for making the selection all print on one page
// we must make sure that the page is sized correctly before printing.
nscoord height = aPresContext->GetPageSize().height;
int32_t pageNum = 1;
nscoord y = 0;//mMargin.top;
for (nsIFrame* page = mFrames.FirstChild(); page;
page = page->GetNextSibling()) {
if (pageNum >= mFromPageNum && pageNum <= mToPageNum) {
nsRect rect = page->GetRect();
rect.y = y;
rect.height = height;
page->SetRect(rect);
y += rect.height + mMargin.top + mMargin.bottom;
}
pageNum++;
}
// adjust total number of pages
if (nsIPrintSettings::kRangeSelection != mPrintRangeType) {
totalPages = pageNum - 1;
}
}
mPageNum = 1;
if (mTotalPages == -1) {
mTotalPages = totalPages;
}
return rv;
}
void
GetPrintCanvasElementsInFrame(nsIFrame* aFrame, nsTArray<nsRefPtr<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::FromContentOrNull(canvasFrame->GetContent());
if (canvas && canvas->GetMozPrintCallback()) {
aArr->AppendElement(canvas);
continue;
}
}
if (!child->GetFirstPrincipalChild()) {
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
nsSimplePageSequenceFrame::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
}
}
if (nsIPrintSettings::kRangeSelection == mPrintRangeType) {
mPrintThisPage = true;
}
}
nsIFrame*
nsSimplePageSequenceFrame::GetCurrentPageFrame()
{
int32_t i = 1;
for (nsFrameList::Enumerator childFrames(mFrames); !childFrames.AtEnd();
childFrames.Next()) {
if (i == mPageNum) {
return childFrames.get();
}
++i;
}
return nullptr;
}
NS_IMETHODIMP
nsSimplePageSequenceFrame::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;
nsRefPtr<nsRenderingContext> renderingContext =
dc->CreateRenderingContext();
nsRefPtr<gfxASurface> renderingSurface =
renderingContext->ThebesContext()->CurrentSurface();
NS_ENSURE_TRUE(renderingSurface, NS_ERROR_OUT_OF_MEMORY);
for (int32_t i = mCurrentCanvasList.Length() - 1; i >= 0 ; i--) {
HTMLCanvasElement* canvas = mCurrentCanvasList[i];
nsIntSize size = canvas->GetSize();
nsRefPtr<gfxASurface> printSurface = renderingSurface->
CreateSimilarSurface(
gfxContentType::COLOR_ALPHA,
size
);
if (!printSurface) {
continue;
}
nsICanvasRenderingContextInternal* ctx = canvas->GetContextAtIndex(0);
if (!ctx) {
continue;
}
// Initialize the context with the new printSurface.
ctx->InitializeWithSurface(nullptr, printSurface, size.width, size.height);
// Start the rendering process.
nsWeakFrame 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;
}
NS_IMETHODIMP
nsSimplePageSequenceFrame::ResetPrintCanvasList()
{
for (int32_t i = mCurrentCanvasList.Length() - 1; i >= 0 ; i--) {
HTMLCanvasElement* canvas = mCurrentCanvasList[i];
canvas->ResetPrintCallback();
}
mCurrentCanvasList.Clear();
mCurrentCanvasListSetup = false;
return NS_OK;
}
NS_IMETHODIMP
nsSimplePageSequenceFrame::PrintNextPage()
{
// Print each specified page
// pageNum keeps track of the current page and what pages are printing
//
// printedPageNum keeps track of the current page number to be printed
// 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* currentPage = GetCurrentPageFrame();
if (!currentPage) {
return NS_ERROR_FAILURE;
}
nsresult rv = NS_OK;
DetermineWhetherToPrintPage();
if (mPrintThisPage) {
// Begin printing of the document
nsDeviceContext* dc = PresContext()->DeviceContext();
// XXX This is temporary fix for printing more than one page of a selection
// This does a poor man's "dump" pagination (see Bug 89353)
// It has laid out as one long page and now we are just moving or view up/down
// one page at a time and printing the contents of what is exposed by the rect.
// currently this does not work for IFrames
// I will soon improve this to work with IFrames
bool continuePrinting = true;
nscoord width, height;
width = PresContext()->GetPageSize().width;
height = PresContext()->GetPageSize().height;
height -= mMargin.top + mMargin.bottom;
width -= mMargin.left + mMargin.right;
nscoord selectionY = height;
nsIFrame* conFrame = currentPage->GetFirstPrincipalChild();
if (mSelectionHeight >= 0) {
conFrame->SetPosition(conFrame->GetPosition() + nsPoint(0, -mYSelOffset));
nsContainerFrame::PositionChildViews(conFrame);
}
// cast the frame to be a page frame
nsPageFrame * pf = static_cast<nsPageFrame*>(currentPage);
pf->SetPageNumInfo(mPageNum, mTotalPages);
pf->SetSharedPageData(mPageData);
int32_t printedPageNum = 1;
while (continuePrinting) {
if (PresContext()->IsRootPaginatedDocument()) {
if (!mCalledBeginPage) {
PR_PL(("\n"));
PR_PL(("***************** BeginPage *****************\n"));
rv = dc->BeginPage();
NS_ENSURE_SUCCESS(rv, rv);
} else {
mCalledBeginPage = false;
}
}
PR_PL(("SeqFr::PrintNextPage -> %p PageNo: %d", pf, mPageNum));
nsRefPtr<nsRenderingContext> renderingContext =
dc->CreateRenderingContext();
nsRect drawingRect(nsPoint(0, 0), currentPage->GetSize());
nsRegion drawingRegion(drawingRect);
nsLayoutUtils::PaintFrame(renderingContext, currentPage,
drawingRegion, NS_RGBA(0,0,0,0),
nsLayoutUtils::PAINT_SYNC_DECODE_IMAGES);
if (mSelectionHeight >= 0 && selectionY < mSelectionHeight) {
selectionY += height;
printedPageNum++;
pf->SetPageNumInfo(printedPageNum, mTotalPages);
conFrame->SetPosition(conFrame->GetPosition() + nsPoint(0, -height));
nsContainerFrame::PositionChildViews(conFrame);
PR_PL(("***************** End Page (PrintNextPage) *****************\n"));
rv = dc->EndPage();
NS_ENSURE_SUCCESS(rv, rv);
} else {
continuePrinting = false;
}
}
}
return rv;
}
NS_IMETHODIMP
nsSimplePageSequenceFrame::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();
mPageNum++;
return rv;
}
static gfx3DMatrix
ComputePageSequenceTransform(nsIFrame* aFrame, float aAppUnitsPerPixel)
{
float scale = aFrame->PresContext()->GetPrintPreviewScale();
return gfx3DMatrix::ScalingMatrix(scale, scale, 1);
}
void
nsSimplePageSequenceFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsRect& aDirtyRect,
const nsDisplayListSet& aLists)
{
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 = GetFirstPrincipalChild();
while (child) {
child->BuildDisplayListForStackingContext(aBuilder,
child->GetVisualOverflowRectRelativeToSelf(), &content);
aBuilder->ResetMarkedFramesForDisplayList();
child = child->GetNextSibling();
}
}
content.AppendNewToTop(new (aBuilder)
nsDisplayTransform(aBuilder, this, &content, ::ComputePageSequenceTransform));
aLists.Content()->AppendToTop(&content);
}
nsIAtom*
nsSimplePageSequenceFrame::GetType() const
{
return nsGkAtoms::sequenceFrame;
}
//------------------------------------------------------------------------------
void
nsSimplePageSequenceFrame::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
nsSimplePageSequenceFrame::SetDateTimeStr(const nsAString& aDateTimeStr)
{
NS_ASSERTION(mPageData != nullptr, "mPageData string cannot be null!");
mPageData->mDateTimeStr = aDateTimeStr;
}
//------------------------------------------------------------------------------
// For Shrink To Fit
//
// Return the percentage that the page needs to shrink to
//
NS_IMETHODIMP
nsSimplePageSequenceFrame::GetSTFPercent(float& aSTFPercent)
{
NS_ENSURE_TRUE(mPageData, NS_ERROR_UNEXPECTED);
aSTFPercent = mPageData->mShrinkToFitRatio;
return NS_OK;
}