1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/generic/nsSimplePageSequenceFrame.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,844 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsSimplePageSequenceFrame.h" 1.10 + 1.11 +#include "nsCOMPtr.h" 1.12 +#include "nsPresContext.h" 1.13 +#include "gfxContext.h" 1.14 +#include "nsRenderingContext.h" 1.15 +#include "nsGkAtoms.h" 1.16 +#include "nsIPresShell.h" 1.17 +#include "nsIPrintSettings.h" 1.18 +#include "nsPageFrame.h" 1.19 +#include "nsSubDocumentFrame.h" 1.20 +#include "nsRegion.h" 1.21 +#include "nsCSSFrameConstructor.h" 1.22 +#include "nsContentUtils.h" 1.23 +#include "nsDisplayList.h" 1.24 +#include "nsHTMLCanvasFrame.h" 1.25 +#include "mozilla/dom/HTMLCanvasElement.h" 1.26 +#include "nsICanvasRenderingContextInternal.h" 1.27 +#include "nsIDateTimeFormat.h" 1.28 +#include "nsServiceManagerUtils.h" 1.29 +#include <algorithm> 1.30 + 1.31 +// DateTime Includes 1.32 +#include "nsDateTimeFormatCID.h" 1.33 + 1.34 +#define OFFSET_NOT_SET -1 1.35 + 1.36 +// Print Options 1.37 +#include "nsIPrintOptions.h" 1.38 + 1.39 +using namespace mozilla; 1.40 +using namespace mozilla::dom; 1.41 + 1.42 +static const char sPrintOptionsContractID[] = "@mozilla.org/gfx/printsettings-service;1"; 1.43 + 1.44 +// 1.45 + 1.46 +#include "prlog.h" 1.47 +#ifdef PR_LOGGING 1.48 +PRLogModuleInfo * 1.49 +GetLayoutPrintingLog() 1.50 +{ 1.51 + static PRLogModuleInfo *sLog; 1.52 + if (!sLog) 1.53 + sLog = PR_NewLogModule("printing-layout"); 1.54 + return sLog; 1.55 +} 1.56 +#define PR_PL(_p1) PR_LOG(GetLayoutPrintingLog(), PR_LOG_DEBUG, _p1) 1.57 +#else 1.58 +#define PR_PL(_p1) 1.59 +#endif 1.60 + 1.61 +nsIFrame* 1.62 +NS_NewSimplePageSequenceFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) 1.63 +{ 1.64 + return new (aPresShell) nsSimplePageSequenceFrame(aContext); 1.65 +} 1.66 + 1.67 +NS_IMPL_FRAMEARENA_HELPERS(nsSimplePageSequenceFrame) 1.68 + 1.69 +nsSimplePageSequenceFrame::nsSimplePageSequenceFrame(nsStyleContext* aContext) : 1.70 + nsContainerFrame(aContext), 1.71 + mTotalPages(-1), 1.72 + mSelectionHeight(-1), 1.73 + mYSelOffset(0), 1.74 + mCalledBeginPage(false), 1.75 + mCurrentCanvasListSetup(false) 1.76 +{ 1.77 + nscoord halfInch = PresContext()->CSSTwipsToAppUnits(NS_INCHES_TO_TWIPS(0.5)); 1.78 + mMargin.SizeTo(halfInch, halfInch, halfInch, halfInch); 1.79 + 1.80 + // XXX Unsafe to assume successful allocation 1.81 + mPageData = new nsSharedPageData(); 1.82 + mPageData->mHeadFootFont = 1.83 + *PresContext()->GetDefaultFont(kGenericFont_serif, 1.84 + aContext->StyleFont()->mLanguage); 1.85 + mPageData->mHeadFootFont.size = nsPresContext::CSSPointsToAppUnits(10); 1.86 + 1.87 + nsresult rv; 1.88 + mPageData->mPrintOptions = do_GetService(sPrintOptionsContractID, &rv); 1.89 + 1.90 + // Doing this here so we only have to go get these formats once 1.91 + SetPageNumberFormat("pagenumber", "%1$d", true); 1.92 + SetPageNumberFormat("pageofpages", "%1$d of %2$d", false); 1.93 +} 1.94 + 1.95 +nsSimplePageSequenceFrame::~nsSimplePageSequenceFrame() 1.96 +{ 1.97 + delete mPageData; 1.98 + ResetPrintCanvasList(); 1.99 +} 1.100 + 1.101 +NS_QUERYFRAME_HEAD(nsSimplePageSequenceFrame) 1.102 + NS_QUERYFRAME_ENTRY(nsIPageSequenceFrame) 1.103 +NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame) 1.104 + 1.105 +//---------------------------------------------------------------------- 1.106 + 1.107 +void 1.108 +nsSimplePageSequenceFrame::SetDesiredSize(nsHTMLReflowMetrics& aDesiredSize, 1.109 + const nsHTMLReflowState& aReflowState, 1.110 + nscoord aWidth, 1.111 + nscoord aHeight) 1.112 +{ 1.113 + // Aim to fill the whole size of the document, not only so we 1.114 + // can act as a background in print preview but also handle overflow 1.115 + // in child page frames correctly. 1.116 + // Use availableWidth so we don't cause a needless horizontal scrollbar. 1.117 + aDesiredSize.Width() = std::max(aReflowState.AvailableWidth(), 1.118 + nscoord(aWidth * PresContext()->GetPrintPreviewScale())); 1.119 + aDesiredSize.Height() = std::max(aReflowState.ComputedHeight(), 1.120 + nscoord(aHeight * PresContext()->GetPrintPreviewScale())); 1.121 +} 1.122 + 1.123 +nsresult 1.124 +nsSimplePageSequenceFrame::Reflow(nsPresContext* aPresContext, 1.125 + nsHTMLReflowMetrics& aDesiredSize, 1.126 + const nsHTMLReflowState& aReflowState, 1.127 + nsReflowStatus& aStatus) 1.128 +{ 1.129 + NS_PRECONDITION(aPresContext->IsRootPaginatedDocument(), 1.130 + "A Page Sequence is only for real pages"); 1.131 + DO_GLOBAL_REFLOW_COUNT("nsSimplePageSequenceFrame"); 1.132 + DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); 1.133 + NS_FRAME_TRACE_REFLOW_IN("nsSimplePageSequenceFrame::Reflow"); 1.134 + 1.135 + aStatus = NS_FRAME_COMPLETE; // we're always complete 1.136 + 1.137 + // Don't do incremental reflow until we've taught tables how to do 1.138 + // it right in paginated mode. 1.139 + if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) { 1.140 + // Return our desired size 1.141 + SetDesiredSize(aDesiredSize, aReflowState, mSize.width, mSize.height); 1.142 + aDesiredSize.SetOverflowAreasToDesiredBounds(); 1.143 + FinishAndStoreOverflow(&aDesiredSize); 1.144 + return NS_OK; 1.145 + } 1.146 + 1.147 + // See if we can get a Print Settings from the Context 1.148 + if (!mPageData->mPrintSettings && 1.149 + aPresContext->Medium() == nsGkAtoms::print) { 1.150 + mPageData->mPrintSettings = aPresContext->GetPrintSettings(); 1.151 + } 1.152 + 1.153 + // now get out margins & edges 1.154 + if (mPageData->mPrintSettings) { 1.155 + nsIntMargin unwriteableTwips; 1.156 + mPageData->mPrintSettings->GetUnwriteableMarginInTwips(unwriteableTwips); 1.157 + NS_ASSERTION(unwriteableTwips.left >= 0 && unwriteableTwips.top >= 0 && 1.158 + unwriteableTwips.right >= 0 && unwriteableTwips.bottom >= 0, 1.159 + "Unwriteable twips should be non-negative"); 1.160 + 1.161 + nsIntMargin marginTwips; 1.162 + mPageData->mPrintSettings->GetMarginInTwips(marginTwips); 1.163 + mMargin = aPresContext->CSSTwipsToAppUnits(marginTwips + unwriteableTwips); 1.164 + 1.165 + int16_t printType; 1.166 + mPageData->mPrintSettings->GetPrintRange(&printType); 1.167 + mPrintRangeType = printType; 1.168 + 1.169 + nsIntMargin edgeTwips; 1.170 + mPageData->mPrintSettings->GetEdgeInTwips(edgeTwips); 1.171 + 1.172 + // sanity check the values. three inches are sometimes needed 1.173 + int32_t inchInTwips = NS_INCHES_TO_INT_TWIPS(3.0); 1.174 + edgeTwips.top = clamped(edgeTwips.top, 0, inchInTwips); 1.175 + edgeTwips.bottom = clamped(edgeTwips.bottom, 0, inchInTwips); 1.176 + edgeTwips.left = clamped(edgeTwips.left, 0, inchInTwips); 1.177 + edgeTwips.right = clamped(edgeTwips.right, 0, inchInTwips); 1.178 + 1.179 + mPageData->mEdgePaperMargin = 1.180 + aPresContext->CSSTwipsToAppUnits(edgeTwips + unwriteableTwips); 1.181 + } 1.182 + 1.183 + // *** Special Override *** 1.184 + // If this is a sub-sdoc (meaning it doesn't take the whole page) 1.185 + // and if this Document is in the upper left hand corner 1.186 + // we need to suppress the top margin or it will reflow too small 1.187 + 1.188 + nsSize pageSize = aPresContext->GetPageSize(); 1.189 + 1.190 + mPageData->mReflowSize = pageSize; 1.191 + // If we're printing a selection, we need to reflow with 1.192 + // unconstrained height, to make sure we'll get to the selection 1.193 + // even if it's beyond the first page of content. 1.194 + if (nsIPrintSettings::kRangeSelection == mPrintRangeType) { 1.195 + mPageData->mReflowSize.height = NS_UNCONSTRAINEDSIZE; 1.196 + } 1.197 + mPageData->mReflowMargin = mMargin; 1.198 + 1.199 + // We use the CSS "margin" property on the -moz-page pseudoelement 1.200 + // to determine the space between each page in print preview. 1.201 + // Keep a running y-offset for each page. 1.202 + nscoord y = 0; 1.203 + nscoord maxXMost = 0; 1.204 + 1.205 + // Tile the pages vertically 1.206 + nsHTMLReflowMetrics kidSize(aReflowState); 1.207 + for (nsIFrame* kidFrame = mFrames.FirstChild(); nullptr != kidFrame; ) { 1.208 + // Set the shared data into the page frame before reflow 1.209 + nsPageFrame * pf = static_cast<nsPageFrame*>(kidFrame); 1.210 + pf->SetSharedPageData(mPageData); 1.211 + 1.212 + // Reflow the page 1.213 + nsHTMLReflowState kidReflowState(aPresContext, aReflowState, kidFrame, 1.214 + pageSize); 1.215 + nsReflowStatus status; 1.216 + 1.217 + kidReflowState.SetComputedWidth(kidReflowState.AvailableWidth()); 1.218 + //kidReflowState.SetComputedHeight(kidReflowState.AvailableHeight()); 1.219 + PR_PL(("AV W: %d H: %d\n", kidReflowState.AvailableWidth(), kidReflowState.AvailableHeight())); 1.220 + 1.221 + nsMargin pageCSSMargin = kidReflowState.ComputedPhysicalMargin(); 1.222 + y += pageCSSMargin.top; 1.223 + const nscoord x = pageCSSMargin.left; 1.224 + 1.225 + // Place and size the page. If the page is narrower than our 1.226 + // max width then center it horizontally 1.227 + ReflowChild(kidFrame, aPresContext, kidSize, kidReflowState, x, y, 0, status); 1.228 + 1.229 + FinishReflowChild(kidFrame, aPresContext, kidSize, nullptr, x, y, 0); 1.230 + y += kidSize.Height(); 1.231 + y += pageCSSMargin.bottom; 1.232 + 1.233 + maxXMost = std::max(maxXMost, x + kidSize.Width() + pageCSSMargin.right); 1.234 + 1.235 + // Is the page complete? 1.236 + nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow(); 1.237 + 1.238 + if (NS_FRAME_IS_FULLY_COMPLETE(status)) { 1.239 + NS_ASSERTION(!kidNextInFlow, "bad child flow list"); 1.240 + } else if (!kidNextInFlow) { 1.241 + // The page isn't complete and it doesn't have a next-in-flow, so 1.242 + // create a continuing page. 1.243 + nsIFrame* continuingPage = aPresContext->PresShell()->FrameConstructor()-> 1.244 + CreateContinuingFrame(aPresContext, kidFrame, this); 1.245 + 1.246 + // Add it to our child list 1.247 + mFrames.InsertFrame(nullptr, kidFrame, continuingPage); 1.248 + } 1.249 + 1.250 + // Get the next page 1.251 + kidFrame = kidFrame->GetNextSibling(); 1.252 + } 1.253 + 1.254 + // Get Total Page Count 1.255 + nsIFrame* page; 1.256 + int32_t pageTot = 0; 1.257 + for (page = mFrames.FirstChild(); page; page = page->GetNextSibling()) { 1.258 + pageTot++; 1.259 + } 1.260 + 1.261 + // Set Page Number Info 1.262 + int32_t pageNum = 1; 1.263 + for (page = mFrames.FirstChild(); page; page = page->GetNextSibling()) { 1.264 + nsPageFrame * pf = static_cast<nsPageFrame*>(page); 1.265 + if (pf != nullptr) { 1.266 + pf->SetPageNumInfo(pageNum, pageTot); 1.267 + } 1.268 + pageNum++; 1.269 + } 1.270 + 1.271 + // Create current Date/Time String 1.272 + if (!mDateFormatter) 1.273 + mDateFormatter = do_CreateInstance(NS_DATETIMEFORMAT_CONTRACTID); 1.274 + 1.275 + NS_ENSURE_TRUE(mDateFormatter, NS_ERROR_FAILURE); 1.276 + 1.277 + nsAutoString formattedDateString; 1.278 + time_t ltime; 1.279 + time( <ime ); 1.280 + if (NS_SUCCEEDED(mDateFormatter->FormatTime(nullptr /* nsILocale* locale */, 1.281 + kDateFormatShort, 1.282 + kTimeFormatNoSeconds, 1.283 + ltime, 1.284 + formattedDateString))) { 1.285 + SetDateTimeStr(formattedDateString); 1.286 + } 1.287 + 1.288 + // Return our desired size 1.289 + // Adjust the reflow size by PrintPreviewScale so the scrollbars end up the 1.290 + // correct size 1.291 + SetDesiredSize(aDesiredSize, aReflowState, maxXMost, y); 1.292 + 1.293 + aDesiredSize.SetOverflowAreasToDesiredBounds(); 1.294 + FinishAndStoreOverflow(&aDesiredSize); 1.295 + 1.296 + // cache the size so we can set the desired size 1.297 + // for the other reflows that happen 1.298 + mSize.width = maxXMost; 1.299 + mSize.height = y; 1.300 + 1.301 + NS_FRAME_TRACE_REFLOW_OUT("nsSimplePageSequeceFrame::Reflow", aStatus); 1.302 + NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); 1.303 + return NS_OK; 1.304 +} 1.305 + 1.306 +//---------------------------------------------------------------------- 1.307 + 1.308 +#ifdef DEBUG_FRAME_DUMP 1.309 +nsresult 1.310 +nsSimplePageSequenceFrame::GetFrameName(nsAString& aResult) const 1.311 +{ 1.312 + return MakeFrameName(NS_LITERAL_STRING("SimplePageSequence"), aResult); 1.313 +} 1.314 +#endif 1.315 + 1.316 +//==================================================================== 1.317 +//== Asynch Printing 1.318 +//==================================================================== 1.319 +NS_IMETHODIMP 1.320 +nsSimplePageSequenceFrame::GetCurrentPageNum(int32_t* aPageNum) 1.321 +{ 1.322 + NS_ENSURE_ARG_POINTER(aPageNum); 1.323 + 1.324 + *aPageNum = mPageNum; 1.325 + return NS_OK; 1.326 +} 1.327 + 1.328 +NS_IMETHODIMP 1.329 +nsSimplePageSequenceFrame::GetNumPages(int32_t* aNumPages) 1.330 +{ 1.331 + NS_ENSURE_ARG_POINTER(aNumPages); 1.332 + 1.333 + *aNumPages = mTotalPages; 1.334 + return NS_OK; 1.335 +} 1.336 + 1.337 +NS_IMETHODIMP 1.338 +nsSimplePageSequenceFrame::IsDoingPrintRange(bool* aDoing) 1.339 +{ 1.340 + NS_ENSURE_ARG_POINTER(aDoing); 1.341 + 1.342 + *aDoing = mDoingPageRange; 1.343 + return NS_OK; 1.344 +} 1.345 + 1.346 +NS_IMETHODIMP 1.347 +nsSimplePageSequenceFrame::GetPrintRange(int32_t* aFromPage, int32_t* aToPage) 1.348 +{ 1.349 + NS_ENSURE_ARG_POINTER(aFromPage); 1.350 + NS_ENSURE_ARG_POINTER(aToPage); 1.351 + 1.352 + *aFromPage = mFromPageNum; 1.353 + *aToPage = mToPageNum; 1.354 + return NS_OK; 1.355 +} 1.356 + 1.357 +// Helper Function 1.358 +void 1.359 +nsSimplePageSequenceFrame::SetPageNumberFormat(const char* aPropName, const char* aDefPropVal, bool aPageNumOnly) 1.360 +{ 1.361 + // Doing this here so we only have to go get these formats once 1.362 + nsXPIDLString pageNumberFormat; 1.363 + // Now go get the Localized Page Formating String 1.364 + nsresult rv = 1.365 + nsContentUtils::GetLocalizedString(nsContentUtils::ePRINTING_PROPERTIES, 1.366 + aPropName, pageNumberFormat); 1.367 + if (NS_FAILED(rv)) { // back stop formatting 1.368 + pageNumberFormat.AssignASCII(aDefPropVal); 1.369 + } 1.370 + 1.371 + SetPageNumberFormat(pageNumberFormat, aPageNumOnly); 1.372 +} 1.373 + 1.374 +NS_IMETHODIMP 1.375 +nsSimplePageSequenceFrame::StartPrint(nsPresContext* aPresContext, 1.376 + nsIPrintSettings* aPrintSettings, 1.377 + const nsAString& aDocTitle, 1.378 + const nsAString& aDocURL) 1.379 +{ 1.380 + NS_ENSURE_ARG_POINTER(aPresContext); 1.381 + NS_ENSURE_ARG_POINTER(aPrintSettings); 1.382 + 1.383 + if (!mPageData->mPrintSettings) { 1.384 + mPageData->mPrintSettings = aPrintSettings; 1.385 + } 1.386 + 1.387 + if (!aDocTitle.IsEmpty()) { 1.388 + mPageData->mDocTitle = aDocTitle; 1.389 + } 1.390 + if (!aDocURL.IsEmpty()) { 1.391 + mPageData->mDocURL = aDocURL; 1.392 + } 1.393 + 1.394 + aPrintSettings->GetStartPageRange(&mFromPageNum); 1.395 + aPrintSettings->GetEndPageRange(&mToPageNum); 1.396 + aPrintSettings->GetPageRanges(mPageRanges); 1.397 + 1.398 + mDoingPageRange = nsIPrintSettings::kRangeSpecifiedPageRange == mPrintRangeType || 1.399 + nsIPrintSettings::kRangeSelection == mPrintRangeType; 1.400 + 1.401 + // If printing a range of pages make sure at least the starting page 1.402 + // number is valid 1.403 + int32_t totalPages = mFrames.GetLength(); 1.404 + 1.405 + if (mDoingPageRange) { 1.406 + if (mFromPageNum > totalPages) { 1.407 + return NS_ERROR_INVALID_ARG; 1.408 + } 1.409 + } 1.410 + 1.411 + // Begin printing of the document 1.412 + nsresult rv = NS_OK; 1.413 + 1.414 + // Determine if we are rendering only the selection 1.415 + aPresContext->SetIsRenderingOnlySelection(nsIPrintSettings::kRangeSelection == mPrintRangeType); 1.416 + 1.417 + 1.418 + if (mDoingPageRange) { 1.419 + // XXX because of the hack for making the selection all print on one page 1.420 + // we must make sure that the page is sized correctly before printing. 1.421 + nscoord height = aPresContext->GetPageSize().height; 1.422 + 1.423 + int32_t pageNum = 1; 1.424 + nscoord y = 0;//mMargin.top; 1.425 + 1.426 + for (nsIFrame* page = mFrames.FirstChild(); page; 1.427 + page = page->GetNextSibling()) { 1.428 + if (pageNum >= mFromPageNum && pageNum <= mToPageNum) { 1.429 + nsRect rect = page->GetRect(); 1.430 + rect.y = y; 1.431 + rect.height = height; 1.432 + page->SetRect(rect); 1.433 + y += rect.height + mMargin.top + mMargin.bottom; 1.434 + } 1.435 + pageNum++; 1.436 + } 1.437 + 1.438 + // adjust total number of pages 1.439 + if (nsIPrintSettings::kRangeSelection != mPrintRangeType) { 1.440 + totalPages = pageNum - 1; 1.441 + } 1.442 + } 1.443 + 1.444 + mPageNum = 1; 1.445 + 1.446 + if (mTotalPages == -1) { 1.447 + mTotalPages = totalPages; 1.448 + } 1.449 + 1.450 + return rv; 1.451 +} 1.452 + 1.453 +void 1.454 +GetPrintCanvasElementsInFrame(nsIFrame* aFrame, nsTArray<nsRefPtr<HTMLCanvasElement> >* aArr) 1.455 +{ 1.456 + if (!aFrame) { 1.457 + return; 1.458 + } 1.459 + for (nsIFrame::ChildListIterator childLists(aFrame); 1.460 + !childLists.IsDone(); childLists.Next()) { 1.461 + 1.462 + nsFrameList children = childLists.CurrentList(); 1.463 + for (nsFrameList::Enumerator e(children); !e.AtEnd(); e.Next()) { 1.464 + nsIFrame* child = e.get(); 1.465 + 1.466 + // Check if child is a nsHTMLCanvasFrame. 1.467 + nsHTMLCanvasFrame* canvasFrame = do_QueryFrame(child); 1.468 + 1.469 + // If there is a canvasFrame, try to get actual canvas element. 1.470 + if (canvasFrame) { 1.471 + HTMLCanvasElement* canvas = 1.472 + HTMLCanvasElement::FromContentOrNull(canvasFrame->GetContent()); 1.473 + if (canvas && canvas->GetMozPrintCallback()) { 1.474 + aArr->AppendElement(canvas); 1.475 + continue; 1.476 + } 1.477 + } 1.478 + 1.479 + if (!child->GetFirstPrincipalChild()) { 1.480 + nsSubDocumentFrame* subdocumentFrame = do_QueryFrame(child); 1.481 + if (subdocumentFrame) { 1.482 + // Descend into the subdocument 1.483 + nsIFrame* root = subdocumentFrame->GetSubdocumentRootFrame(); 1.484 + child = root; 1.485 + } 1.486 + } 1.487 + // The current child is not a nsHTMLCanvasFrame OR it is but there is 1.488 + // no HTMLCanvasElement on it. Check if children of `child` might 1.489 + // contain a HTMLCanvasElement. 1.490 + GetPrintCanvasElementsInFrame(child, aArr); 1.491 + } 1.492 + } 1.493 +} 1.494 + 1.495 +void 1.496 +nsSimplePageSequenceFrame::DetermineWhetherToPrintPage() 1.497 +{ 1.498 + // See whether we should print this page 1.499 + mPrintThisPage = true; 1.500 + bool printEvenPages, printOddPages; 1.501 + mPageData->mPrintSettings->GetPrintOptions(nsIPrintSettings::kPrintEvenPages, &printEvenPages); 1.502 + mPageData->mPrintSettings->GetPrintOptions(nsIPrintSettings::kPrintOddPages, &printOddPages); 1.503 + 1.504 + // If printing a range of pages check whether the page number is in the 1.505 + // range of pages to print 1.506 + if (mDoingPageRange) { 1.507 + if (mPageNum < mFromPageNum) { 1.508 + mPrintThisPage = false; 1.509 + } else if (mPageNum > mToPageNum) { 1.510 + mPageNum++; 1.511 + mPrintThisPage = false; 1.512 + return; 1.513 + } else { 1.514 + int32_t length = mPageRanges.Length(); 1.515 + 1.516 + // Page ranges are pairs (start, end) 1.517 + if (length && (length % 2 == 0)) { 1.518 + mPrintThisPage = false; 1.519 + 1.520 + int32_t i; 1.521 + for (i = 0; i < length; i += 2) { 1.522 + if (mPageRanges[i] <= mPageNum && mPageNum <= mPageRanges[i+1]) { 1.523 + mPrintThisPage = true; 1.524 + break; 1.525 + } 1.526 + } 1.527 + } 1.528 + } 1.529 + } 1.530 + 1.531 + // Check for printing of odd and even pages 1.532 + if (mPageNum & 0x1) { 1.533 + if (!printOddPages) { 1.534 + mPrintThisPage = false; // don't print odd numbered page 1.535 + } 1.536 + } else { 1.537 + if (!printEvenPages) { 1.538 + mPrintThisPage = false; // don't print even numbered page 1.539 + } 1.540 + } 1.541 + 1.542 + if (nsIPrintSettings::kRangeSelection == mPrintRangeType) { 1.543 + mPrintThisPage = true; 1.544 + } 1.545 +} 1.546 + 1.547 +nsIFrame* 1.548 +nsSimplePageSequenceFrame::GetCurrentPageFrame() 1.549 +{ 1.550 + int32_t i = 1; 1.551 + for (nsFrameList::Enumerator childFrames(mFrames); !childFrames.AtEnd(); 1.552 + childFrames.Next()) { 1.553 + if (i == mPageNum) { 1.554 + return childFrames.get(); 1.555 + } 1.556 + ++i; 1.557 + } 1.558 + return nullptr; 1.559 +} 1.560 + 1.561 +NS_IMETHODIMP 1.562 +nsSimplePageSequenceFrame::PrePrintNextPage(nsITimerCallback* aCallback, bool* aDone) 1.563 +{ 1.564 + nsIFrame* currentPage = GetCurrentPageFrame(); 1.565 + if (!currentPage) { 1.566 + *aDone = true; 1.567 + return NS_ERROR_FAILURE; 1.568 + } 1.569 + 1.570 + DetermineWhetherToPrintPage(); 1.571 + // Nothing to do if the current page doesn't get printed OR rendering to 1.572 + // preview. For preview, the `CallPrintCallback` is called from within the 1.573 + // HTMLCanvasElement::HandlePrintCallback. 1.574 + if (!mPrintThisPage || !PresContext()->IsRootPaginatedDocument()) { 1.575 + *aDone = true; 1.576 + return NS_OK; 1.577 + } 1.578 + 1.579 + // If the canvasList is null, then generate it and start the render 1.580 + // process for all the canvas. 1.581 + if (!mCurrentCanvasListSetup) { 1.582 + mCurrentCanvasListSetup = true; 1.583 + GetPrintCanvasElementsInFrame(currentPage, &mCurrentCanvasList); 1.584 + 1.585 + if (mCurrentCanvasList.Length() != 0) { 1.586 + nsresult rv = NS_OK; 1.587 + 1.588 + // Begin printing of the document 1.589 + nsDeviceContext *dc = PresContext()->DeviceContext(); 1.590 + PR_PL(("\n")); 1.591 + PR_PL(("***************** BeginPage *****************\n")); 1.592 + rv = dc->BeginPage(); 1.593 + NS_ENSURE_SUCCESS(rv, rv); 1.594 + 1.595 + mCalledBeginPage = true; 1.596 + 1.597 + nsRefPtr<nsRenderingContext> renderingContext = 1.598 + dc->CreateRenderingContext(); 1.599 + 1.600 + nsRefPtr<gfxASurface> renderingSurface = 1.601 + renderingContext->ThebesContext()->CurrentSurface(); 1.602 + NS_ENSURE_TRUE(renderingSurface, NS_ERROR_OUT_OF_MEMORY); 1.603 + 1.604 + for (int32_t i = mCurrentCanvasList.Length() - 1; i >= 0 ; i--) { 1.605 + HTMLCanvasElement* canvas = mCurrentCanvasList[i]; 1.606 + nsIntSize size = canvas->GetSize(); 1.607 + 1.608 + nsRefPtr<gfxASurface> printSurface = renderingSurface-> 1.609 + CreateSimilarSurface( 1.610 + gfxContentType::COLOR_ALPHA, 1.611 + size 1.612 + ); 1.613 + 1.614 + if (!printSurface) { 1.615 + continue; 1.616 + } 1.617 + 1.618 + nsICanvasRenderingContextInternal* ctx = canvas->GetContextAtIndex(0); 1.619 + 1.620 + if (!ctx) { 1.621 + continue; 1.622 + } 1.623 + 1.624 + // Initialize the context with the new printSurface. 1.625 + ctx->InitializeWithSurface(nullptr, printSurface, size.width, size.height); 1.626 + 1.627 + // Start the rendering process. 1.628 + nsWeakFrame weakFrame = this; 1.629 + canvas->DispatchPrintCallback(aCallback); 1.630 + NS_ENSURE_STATE(weakFrame.IsAlive()); 1.631 + } 1.632 + } 1.633 + } 1.634 + uint32_t doneCounter = 0; 1.635 + for (int32_t i = mCurrentCanvasList.Length() - 1; i >= 0 ; i--) { 1.636 + HTMLCanvasElement* canvas = mCurrentCanvasList[i]; 1.637 + 1.638 + if (canvas->IsPrintCallbackDone()) { 1.639 + doneCounter++; 1.640 + } 1.641 + } 1.642 + // If all canvas have finished rendering, return true, otherwise false. 1.643 + *aDone = doneCounter == mCurrentCanvasList.Length(); 1.644 + 1.645 + return NS_OK; 1.646 +} 1.647 + 1.648 +NS_IMETHODIMP 1.649 +nsSimplePageSequenceFrame::ResetPrintCanvasList() 1.650 +{ 1.651 + for (int32_t i = mCurrentCanvasList.Length() - 1; i >= 0 ; i--) { 1.652 + HTMLCanvasElement* canvas = mCurrentCanvasList[i]; 1.653 + canvas->ResetPrintCallback(); 1.654 + } 1.655 + 1.656 + mCurrentCanvasList.Clear(); 1.657 + mCurrentCanvasListSetup = false; 1.658 + return NS_OK; 1.659 +} 1.660 + 1.661 +NS_IMETHODIMP 1.662 +nsSimplePageSequenceFrame::PrintNextPage() 1.663 +{ 1.664 + // Print each specified page 1.665 + // pageNum keeps track of the current page and what pages are printing 1.666 + // 1.667 + // printedPageNum keeps track of the current page number to be printed 1.668 + // Note: When print al the pages or a page range the printed page shows the 1.669 + // actual page number, when printing selection it prints the page number starting 1.670 + // with the first page of the selection. For example if the user has a 1.671 + // selection that starts on page 2 and ends on page 3, the page numbers when 1.672 + // print are 1 and then two (which is different than printing a page range, where 1.673 + // the page numbers would have been 2 and then 3) 1.674 + 1.675 + nsIFrame* currentPage = GetCurrentPageFrame(); 1.676 + if (!currentPage) { 1.677 + return NS_ERROR_FAILURE; 1.678 + } 1.679 + 1.680 + nsresult rv = NS_OK; 1.681 + 1.682 + DetermineWhetherToPrintPage(); 1.683 + 1.684 + if (mPrintThisPage) { 1.685 + // Begin printing of the document 1.686 + nsDeviceContext* dc = PresContext()->DeviceContext(); 1.687 + 1.688 + // XXX This is temporary fix for printing more than one page of a selection 1.689 + // This does a poor man's "dump" pagination (see Bug 89353) 1.690 + // It has laid out as one long page and now we are just moving or view up/down 1.691 + // one page at a time and printing the contents of what is exposed by the rect. 1.692 + // currently this does not work for IFrames 1.693 + // I will soon improve this to work with IFrames 1.694 + bool continuePrinting = true; 1.695 + nscoord width, height; 1.696 + width = PresContext()->GetPageSize().width; 1.697 + height = PresContext()->GetPageSize().height; 1.698 + height -= mMargin.top + mMargin.bottom; 1.699 + width -= mMargin.left + mMargin.right; 1.700 + nscoord selectionY = height; 1.701 + nsIFrame* conFrame = currentPage->GetFirstPrincipalChild(); 1.702 + if (mSelectionHeight >= 0) { 1.703 + conFrame->SetPosition(conFrame->GetPosition() + nsPoint(0, -mYSelOffset)); 1.704 + nsContainerFrame::PositionChildViews(conFrame); 1.705 + } 1.706 + 1.707 + // cast the frame to be a page frame 1.708 + nsPageFrame * pf = static_cast<nsPageFrame*>(currentPage); 1.709 + pf->SetPageNumInfo(mPageNum, mTotalPages); 1.710 + pf->SetSharedPageData(mPageData); 1.711 + 1.712 + int32_t printedPageNum = 1; 1.713 + while (continuePrinting) { 1.714 + if (PresContext()->IsRootPaginatedDocument()) { 1.715 + if (!mCalledBeginPage) { 1.716 + PR_PL(("\n")); 1.717 + PR_PL(("***************** BeginPage *****************\n")); 1.718 + rv = dc->BeginPage(); 1.719 + NS_ENSURE_SUCCESS(rv, rv); 1.720 + } else { 1.721 + mCalledBeginPage = false; 1.722 + } 1.723 + } 1.724 + 1.725 + PR_PL(("SeqFr::PrintNextPage -> %p PageNo: %d", pf, mPageNum)); 1.726 + 1.727 + nsRefPtr<nsRenderingContext> renderingContext = 1.728 + dc->CreateRenderingContext(); 1.729 + 1.730 + nsRect drawingRect(nsPoint(0, 0), currentPage->GetSize()); 1.731 + nsRegion drawingRegion(drawingRect); 1.732 + nsLayoutUtils::PaintFrame(renderingContext, currentPage, 1.733 + drawingRegion, NS_RGBA(0,0,0,0), 1.734 + nsLayoutUtils::PAINT_SYNC_DECODE_IMAGES); 1.735 + 1.736 + if (mSelectionHeight >= 0 && selectionY < mSelectionHeight) { 1.737 + selectionY += height; 1.738 + printedPageNum++; 1.739 + pf->SetPageNumInfo(printedPageNum, mTotalPages); 1.740 + conFrame->SetPosition(conFrame->GetPosition() + nsPoint(0, -height)); 1.741 + nsContainerFrame::PositionChildViews(conFrame); 1.742 + 1.743 + PR_PL(("***************** End Page (PrintNextPage) *****************\n")); 1.744 + rv = dc->EndPage(); 1.745 + NS_ENSURE_SUCCESS(rv, rv); 1.746 + } else { 1.747 + continuePrinting = false; 1.748 + } 1.749 + } 1.750 + } 1.751 + return rv; 1.752 +} 1.753 + 1.754 +NS_IMETHODIMP 1.755 +nsSimplePageSequenceFrame::DoPageEnd() 1.756 +{ 1.757 + nsresult rv = NS_OK; 1.758 + if (PresContext()->IsRootPaginatedDocument() && mPrintThisPage) { 1.759 + PR_PL(("***************** End Page (DoPageEnd) *****************\n")); 1.760 + rv = PresContext()->DeviceContext()->EndPage(); 1.761 + NS_ENSURE_SUCCESS(rv, rv); 1.762 + } 1.763 + 1.764 + ResetPrintCanvasList(); 1.765 + 1.766 + mPageNum++; 1.767 + 1.768 + return rv; 1.769 +} 1.770 + 1.771 +static gfx3DMatrix 1.772 +ComputePageSequenceTransform(nsIFrame* aFrame, float aAppUnitsPerPixel) 1.773 +{ 1.774 + float scale = aFrame->PresContext()->GetPrintPreviewScale(); 1.775 + return gfx3DMatrix::ScalingMatrix(scale, scale, 1); 1.776 +} 1.777 + 1.778 +void 1.779 +nsSimplePageSequenceFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, 1.780 + const nsRect& aDirtyRect, 1.781 + const nsDisplayListSet& aLists) 1.782 +{ 1.783 + DisplayBorderBackgroundOutline(aBuilder, aLists); 1.784 + 1.785 + nsDisplayList content; 1.786 + 1.787 + { 1.788 + // Clear clip state while we construct the children of the 1.789 + // nsDisplayTransform, since they'll be in a different coordinate system. 1.790 + DisplayListClipState::AutoSaveRestore clipState(aBuilder); 1.791 + clipState.Clear(); 1.792 + 1.793 + nsIFrame* child = GetFirstPrincipalChild(); 1.794 + while (child) { 1.795 + child->BuildDisplayListForStackingContext(aBuilder, 1.796 + child->GetVisualOverflowRectRelativeToSelf(), &content); 1.797 + aBuilder->ResetMarkedFramesForDisplayList(); 1.798 + child = child->GetNextSibling(); 1.799 + } 1.800 + } 1.801 + 1.802 + content.AppendNewToTop(new (aBuilder) 1.803 + nsDisplayTransform(aBuilder, this, &content, ::ComputePageSequenceTransform)); 1.804 + 1.805 + aLists.Content()->AppendToTop(&content); 1.806 +} 1.807 + 1.808 +nsIAtom* 1.809 +nsSimplePageSequenceFrame::GetType() const 1.810 +{ 1.811 + return nsGkAtoms::sequenceFrame; 1.812 +} 1.813 + 1.814 +//------------------------------------------------------------------------------ 1.815 +void 1.816 +nsSimplePageSequenceFrame::SetPageNumberFormat(const nsAString& aFormatStr, bool aForPageNumOnly) 1.817 +{ 1.818 + NS_ASSERTION(mPageData != nullptr, "mPageData string cannot be null!"); 1.819 + 1.820 + if (aForPageNumOnly) { 1.821 + mPageData->mPageNumFormat = aFormatStr; 1.822 + } else { 1.823 + mPageData->mPageNumAndTotalsFormat = aFormatStr; 1.824 + } 1.825 +} 1.826 + 1.827 +//------------------------------------------------------------------------------ 1.828 +void 1.829 +nsSimplePageSequenceFrame::SetDateTimeStr(const nsAString& aDateTimeStr) 1.830 +{ 1.831 + NS_ASSERTION(mPageData != nullptr, "mPageData string cannot be null!"); 1.832 + 1.833 + mPageData->mDateTimeStr = aDateTimeStr; 1.834 +} 1.835 + 1.836 +//------------------------------------------------------------------------------ 1.837 +// For Shrink To Fit 1.838 +// 1.839 +// Return the percentage that the page needs to shrink to 1.840 +// 1.841 +NS_IMETHODIMP 1.842 +nsSimplePageSequenceFrame::GetSTFPercent(float& aSTFPercent) 1.843 +{ 1.844 + NS_ENSURE_TRUE(mPageData, NS_ERROR_UNEXPECTED); 1.845 + aSTFPercent = mPageData->mShrinkToFitRatio; 1.846 + return NS_OK; 1.847 +}