layout/generic/nsSimplePageSequenceFrame.cpp

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:b42ad8b290ff
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "nsSimplePageSequenceFrame.h"
7
8 #include "nsCOMPtr.h"
9 #include "nsPresContext.h"
10 #include "gfxContext.h"
11 #include "nsRenderingContext.h"
12 #include "nsGkAtoms.h"
13 #include "nsIPresShell.h"
14 #include "nsIPrintSettings.h"
15 #include "nsPageFrame.h"
16 #include "nsSubDocumentFrame.h"
17 #include "nsRegion.h"
18 #include "nsCSSFrameConstructor.h"
19 #include "nsContentUtils.h"
20 #include "nsDisplayList.h"
21 #include "nsHTMLCanvasFrame.h"
22 #include "mozilla/dom/HTMLCanvasElement.h"
23 #include "nsICanvasRenderingContextInternal.h"
24 #include "nsIDateTimeFormat.h"
25 #include "nsServiceManagerUtils.h"
26 #include <algorithm>
27
28 // DateTime Includes
29 #include "nsDateTimeFormatCID.h"
30
31 #define OFFSET_NOT_SET -1
32
33 // Print Options
34 #include "nsIPrintOptions.h"
35
36 using namespace mozilla;
37 using namespace mozilla::dom;
38
39 static const char sPrintOptionsContractID[] = "@mozilla.org/gfx/printsettings-service;1";
40
41 //
42
43 #include "prlog.h"
44 #ifdef PR_LOGGING
45 PRLogModuleInfo *
46 GetLayoutPrintingLog()
47 {
48 static PRLogModuleInfo *sLog;
49 if (!sLog)
50 sLog = PR_NewLogModule("printing-layout");
51 return sLog;
52 }
53 #define PR_PL(_p1) PR_LOG(GetLayoutPrintingLog(), PR_LOG_DEBUG, _p1)
54 #else
55 #define PR_PL(_p1)
56 #endif
57
58 nsIFrame*
59 NS_NewSimplePageSequenceFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
60 {
61 return new (aPresShell) nsSimplePageSequenceFrame(aContext);
62 }
63
64 NS_IMPL_FRAMEARENA_HELPERS(nsSimplePageSequenceFrame)
65
66 nsSimplePageSequenceFrame::nsSimplePageSequenceFrame(nsStyleContext* aContext) :
67 nsContainerFrame(aContext),
68 mTotalPages(-1),
69 mSelectionHeight(-1),
70 mYSelOffset(0),
71 mCalledBeginPage(false),
72 mCurrentCanvasListSetup(false)
73 {
74 nscoord halfInch = PresContext()->CSSTwipsToAppUnits(NS_INCHES_TO_TWIPS(0.5));
75 mMargin.SizeTo(halfInch, halfInch, halfInch, halfInch);
76
77 // XXX Unsafe to assume successful allocation
78 mPageData = new nsSharedPageData();
79 mPageData->mHeadFootFont =
80 *PresContext()->GetDefaultFont(kGenericFont_serif,
81 aContext->StyleFont()->mLanguage);
82 mPageData->mHeadFootFont.size = nsPresContext::CSSPointsToAppUnits(10);
83
84 nsresult rv;
85 mPageData->mPrintOptions = do_GetService(sPrintOptionsContractID, &rv);
86
87 // Doing this here so we only have to go get these formats once
88 SetPageNumberFormat("pagenumber", "%1$d", true);
89 SetPageNumberFormat("pageofpages", "%1$d of %2$d", false);
90 }
91
92 nsSimplePageSequenceFrame::~nsSimplePageSequenceFrame()
93 {
94 delete mPageData;
95 ResetPrintCanvasList();
96 }
97
98 NS_QUERYFRAME_HEAD(nsSimplePageSequenceFrame)
99 NS_QUERYFRAME_ENTRY(nsIPageSequenceFrame)
100 NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
101
102 //----------------------------------------------------------------------
103
104 void
105 nsSimplePageSequenceFrame::SetDesiredSize(nsHTMLReflowMetrics& aDesiredSize,
106 const nsHTMLReflowState& aReflowState,
107 nscoord aWidth,
108 nscoord aHeight)
109 {
110 // Aim to fill the whole size of the document, not only so we
111 // can act as a background in print preview but also handle overflow
112 // in child page frames correctly.
113 // Use availableWidth so we don't cause a needless horizontal scrollbar.
114 aDesiredSize.Width() = std::max(aReflowState.AvailableWidth(),
115 nscoord(aWidth * PresContext()->GetPrintPreviewScale()));
116 aDesiredSize.Height() = std::max(aReflowState.ComputedHeight(),
117 nscoord(aHeight * PresContext()->GetPrintPreviewScale()));
118 }
119
120 nsresult
121 nsSimplePageSequenceFrame::Reflow(nsPresContext* aPresContext,
122 nsHTMLReflowMetrics& aDesiredSize,
123 const nsHTMLReflowState& aReflowState,
124 nsReflowStatus& aStatus)
125 {
126 NS_PRECONDITION(aPresContext->IsRootPaginatedDocument(),
127 "A Page Sequence is only for real pages");
128 DO_GLOBAL_REFLOW_COUNT("nsSimplePageSequenceFrame");
129 DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
130 NS_FRAME_TRACE_REFLOW_IN("nsSimplePageSequenceFrame::Reflow");
131
132 aStatus = NS_FRAME_COMPLETE; // we're always complete
133
134 // Don't do incremental reflow until we've taught tables how to do
135 // it right in paginated mode.
136 if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
137 // Return our desired size
138 SetDesiredSize(aDesiredSize, aReflowState, mSize.width, mSize.height);
139 aDesiredSize.SetOverflowAreasToDesiredBounds();
140 FinishAndStoreOverflow(&aDesiredSize);
141 return NS_OK;
142 }
143
144 // See if we can get a Print Settings from the Context
145 if (!mPageData->mPrintSettings &&
146 aPresContext->Medium() == nsGkAtoms::print) {
147 mPageData->mPrintSettings = aPresContext->GetPrintSettings();
148 }
149
150 // now get out margins & edges
151 if (mPageData->mPrintSettings) {
152 nsIntMargin unwriteableTwips;
153 mPageData->mPrintSettings->GetUnwriteableMarginInTwips(unwriteableTwips);
154 NS_ASSERTION(unwriteableTwips.left >= 0 && unwriteableTwips.top >= 0 &&
155 unwriteableTwips.right >= 0 && unwriteableTwips.bottom >= 0,
156 "Unwriteable twips should be non-negative");
157
158 nsIntMargin marginTwips;
159 mPageData->mPrintSettings->GetMarginInTwips(marginTwips);
160 mMargin = aPresContext->CSSTwipsToAppUnits(marginTwips + unwriteableTwips);
161
162 int16_t printType;
163 mPageData->mPrintSettings->GetPrintRange(&printType);
164 mPrintRangeType = printType;
165
166 nsIntMargin edgeTwips;
167 mPageData->mPrintSettings->GetEdgeInTwips(edgeTwips);
168
169 // sanity check the values. three inches are sometimes needed
170 int32_t inchInTwips = NS_INCHES_TO_INT_TWIPS(3.0);
171 edgeTwips.top = clamped(edgeTwips.top, 0, inchInTwips);
172 edgeTwips.bottom = clamped(edgeTwips.bottom, 0, inchInTwips);
173 edgeTwips.left = clamped(edgeTwips.left, 0, inchInTwips);
174 edgeTwips.right = clamped(edgeTwips.right, 0, inchInTwips);
175
176 mPageData->mEdgePaperMargin =
177 aPresContext->CSSTwipsToAppUnits(edgeTwips + unwriteableTwips);
178 }
179
180 // *** Special Override ***
181 // If this is a sub-sdoc (meaning it doesn't take the whole page)
182 // and if this Document is in the upper left hand corner
183 // we need to suppress the top margin or it will reflow too small
184
185 nsSize pageSize = aPresContext->GetPageSize();
186
187 mPageData->mReflowSize = pageSize;
188 // If we're printing a selection, we need to reflow with
189 // unconstrained height, to make sure we'll get to the selection
190 // even if it's beyond the first page of content.
191 if (nsIPrintSettings::kRangeSelection == mPrintRangeType) {
192 mPageData->mReflowSize.height = NS_UNCONSTRAINEDSIZE;
193 }
194 mPageData->mReflowMargin = mMargin;
195
196 // We use the CSS "margin" property on the -moz-page pseudoelement
197 // to determine the space between each page in print preview.
198 // Keep a running y-offset for each page.
199 nscoord y = 0;
200 nscoord maxXMost = 0;
201
202 // Tile the pages vertically
203 nsHTMLReflowMetrics kidSize(aReflowState);
204 for (nsIFrame* kidFrame = mFrames.FirstChild(); nullptr != kidFrame; ) {
205 // Set the shared data into the page frame before reflow
206 nsPageFrame * pf = static_cast<nsPageFrame*>(kidFrame);
207 pf->SetSharedPageData(mPageData);
208
209 // Reflow the page
210 nsHTMLReflowState kidReflowState(aPresContext, aReflowState, kidFrame,
211 pageSize);
212 nsReflowStatus status;
213
214 kidReflowState.SetComputedWidth(kidReflowState.AvailableWidth());
215 //kidReflowState.SetComputedHeight(kidReflowState.AvailableHeight());
216 PR_PL(("AV W: %d H: %d\n", kidReflowState.AvailableWidth(), kidReflowState.AvailableHeight()));
217
218 nsMargin pageCSSMargin = kidReflowState.ComputedPhysicalMargin();
219 y += pageCSSMargin.top;
220 const nscoord x = pageCSSMargin.left;
221
222 // Place and size the page. If the page is narrower than our
223 // max width then center it horizontally
224 ReflowChild(kidFrame, aPresContext, kidSize, kidReflowState, x, y, 0, status);
225
226 FinishReflowChild(kidFrame, aPresContext, kidSize, nullptr, x, y, 0);
227 y += kidSize.Height();
228 y += pageCSSMargin.bottom;
229
230 maxXMost = std::max(maxXMost, x + kidSize.Width() + pageCSSMargin.right);
231
232 // Is the page complete?
233 nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow();
234
235 if (NS_FRAME_IS_FULLY_COMPLETE(status)) {
236 NS_ASSERTION(!kidNextInFlow, "bad child flow list");
237 } else if (!kidNextInFlow) {
238 // The page isn't complete and it doesn't have a next-in-flow, so
239 // create a continuing page.
240 nsIFrame* continuingPage = aPresContext->PresShell()->FrameConstructor()->
241 CreateContinuingFrame(aPresContext, kidFrame, this);
242
243 // Add it to our child list
244 mFrames.InsertFrame(nullptr, kidFrame, continuingPage);
245 }
246
247 // Get the next page
248 kidFrame = kidFrame->GetNextSibling();
249 }
250
251 // Get Total Page Count
252 nsIFrame* page;
253 int32_t pageTot = 0;
254 for (page = mFrames.FirstChild(); page; page = page->GetNextSibling()) {
255 pageTot++;
256 }
257
258 // Set Page Number Info
259 int32_t pageNum = 1;
260 for (page = mFrames.FirstChild(); page; page = page->GetNextSibling()) {
261 nsPageFrame * pf = static_cast<nsPageFrame*>(page);
262 if (pf != nullptr) {
263 pf->SetPageNumInfo(pageNum, pageTot);
264 }
265 pageNum++;
266 }
267
268 // Create current Date/Time String
269 if (!mDateFormatter)
270 mDateFormatter = do_CreateInstance(NS_DATETIMEFORMAT_CONTRACTID);
271
272 NS_ENSURE_TRUE(mDateFormatter, NS_ERROR_FAILURE);
273
274 nsAutoString formattedDateString;
275 time_t ltime;
276 time( &ltime );
277 if (NS_SUCCEEDED(mDateFormatter->FormatTime(nullptr /* nsILocale* locale */,
278 kDateFormatShort,
279 kTimeFormatNoSeconds,
280 ltime,
281 formattedDateString))) {
282 SetDateTimeStr(formattedDateString);
283 }
284
285 // Return our desired size
286 // Adjust the reflow size by PrintPreviewScale so the scrollbars end up the
287 // correct size
288 SetDesiredSize(aDesiredSize, aReflowState, maxXMost, y);
289
290 aDesiredSize.SetOverflowAreasToDesiredBounds();
291 FinishAndStoreOverflow(&aDesiredSize);
292
293 // cache the size so we can set the desired size
294 // for the other reflows that happen
295 mSize.width = maxXMost;
296 mSize.height = y;
297
298 NS_FRAME_TRACE_REFLOW_OUT("nsSimplePageSequeceFrame::Reflow", aStatus);
299 NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
300 return NS_OK;
301 }
302
303 //----------------------------------------------------------------------
304
305 #ifdef DEBUG_FRAME_DUMP
306 nsresult
307 nsSimplePageSequenceFrame::GetFrameName(nsAString& aResult) const
308 {
309 return MakeFrameName(NS_LITERAL_STRING("SimplePageSequence"), aResult);
310 }
311 #endif
312
313 //====================================================================
314 //== Asynch Printing
315 //====================================================================
316 NS_IMETHODIMP
317 nsSimplePageSequenceFrame::GetCurrentPageNum(int32_t* aPageNum)
318 {
319 NS_ENSURE_ARG_POINTER(aPageNum);
320
321 *aPageNum = mPageNum;
322 return NS_OK;
323 }
324
325 NS_IMETHODIMP
326 nsSimplePageSequenceFrame::GetNumPages(int32_t* aNumPages)
327 {
328 NS_ENSURE_ARG_POINTER(aNumPages);
329
330 *aNumPages = mTotalPages;
331 return NS_OK;
332 }
333
334 NS_IMETHODIMP
335 nsSimplePageSequenceFrame::IsDoingPrintRange(bool* aDoing)
336 {
337 NS_ENSURE_ARG_POINTER(aDoing);
338
339 *aDoing = mDoingPageRange;
340 return NS_OK;
341 }
342
343 NS_IMETHODIMP
344 nsSimplePageSequenceFrame::GetPrintRange(int32_t* aFromPage, int32_t* aToPage)
345 {
346 NS_ENSURE_ARG_POINTER(aFromPage);
347 NS_ENSURE_ARG_POINTER(aToPage);
348
349 *aFromPage = mFromPageNum;
350 *aToPage = mToPageNum;
351 return NS_OK;
352 }
353
354 // Helper Function
355 void
356 nsSimplePageSequenceFrame::SetPageNumberFormat(const char* aPropName, const char* aDefPropVal, bool aPageNumOnly)
357 {
358 // Doing this here so we only have to go get these formats once
359 nsXPIDLString pageNumberFormat;
360 // Now go get the Localized Page Formating String
361 nsresult rv =
362 nsContentUtils::GetLocalizedString(nsContentUtils::ePRINTING_PROPERTIES,
363 aPropName, pageNumberFormat);
364 if (NS_FAILED(rv)) { // back stop formatting
365 pageNumberFormat.AssignASCII(aDefPropVal);
366 }
367
368 SetPageNumberFormat(pageNumberFormat, aPageNumOnly);
369 }
370
371 NS_IMETHODIMP
372 nsSimplePageSequenceFrame::StartPrint(nsPresContext* aPresContext,
373 nsIPrintSettings* aPrintSettings,
374 const nsAString& aDocTitle,
375 const nsAString& aDocURL)
376 {
377 NS_ENSURE_ARG_POINTER(aPresContext);
378 NS_ENSURE_ARG_POINTER(aPrintSettings);
379
380 if (!mPageData->mPrintSettings) {
381 mPageData->mPrintSettings = aPrintSettings;
382 }
383
384 if (!aDocTitle.IsEmpty()) {
385 mPageData->mDocTitle = aDocTitle;
386 }
387 if (!aDocURL.IsEmpty()) {
388 mPageData->mDocURL = aDocURL;
389 }
390
391 aPrintSettings->GetStartPageRange(&mFromPageNum);
392 aPrintSettings->GetEndPageRange(&mToPageNum);
393 aPrintSettings->GetPageRanges(mPageRanges);
394
395 mDoingPageRange = nsIPrintSettings::kRangeSpecifiedPageRange == mPrintRangeType ||
396 nsIPrintSettings::kRangeSelection == mPrintRangeType;
397
398 // If printing a range of pages make sure at least the starting page
399 // number is valid
400 int32_t totalPages = mFrames.GetLength();
401
402 if (mDoingPageRange) {
403 if (mFromPageNum > totalPages) {
404 return NS_ERROR_INVALID_ARG;
405 }
406 }
407
408 // Begin printing of the document
409 nsresult rv = NS_OK;
410
411 // Determine if we are rendering only the selection
412 aPresContext->SetIsRenderingOnlySelection(nsIPrintSettings::kRangeSelection == mPrintRangeType);
413
414
415 if (mDoingPageRange) {
416 // XXX because of the hack for making the selection all print on one page
417 // we must make sure that the page is sized correctly before printing.
418 nscoord height = aPresContext->GetPageSize().height;
419
420 int32_t pageNum = 1;
421 nscoord y = 0;//mMargin.top;
422
423 for (nsIFrame* page = mFrames.FirstChild(); page;
424 page = page->GetNextSibling()) {
425 if (pageNum >= mFromPageNum && pageNum <= mToPageNum) {
426 nsRect rect = page->GetRect();
427 rect.y = y;
428 rect.height = height;
429 page->SetRect(rect);
430 y += rect.height + mMargin.top + mMargin.bottom;
431 }
432 pageNum++;
433 }
434
435 // adjust total number of pages
436 if (nsIPrintSettings::kRangeSelection != mPrintRangeType) {
437 totalPages = pageNum - 1;
438 }
439 }
440
441 mPageNum = 1;
442
443 if (mTotalPages == -1) {
444 mTotalPages = totalPages;
445 }
446
447 return rv;
448 }
449
450 void
451 GetPrintCanvasElementsInFrame(nsIFrame* aFrame, nsTArray<nsRefPtr<HTMLCanvasElement> >* aArr)
452 {
453 if (!aFrame) {
454 return;
455 }
456 for (nsIFrame::ChildListIterator childLists(aFrame);
457 !childLists.IsDone(); childLists.Next()) {
458
459 nsFrameList children = childLists.CurrentList();
460 for (nsFrameList::Enumerator e(children); !e.AtEnd(); e.Next()) {
461 nsIFrame* child = e.get();
462
463 // Check if child is a nsHTMLCanvasFrame.
464 nsHTMLCanvasFrame* canvasFrame = do_QueryFrame(child);
465
466 // If there is a canvasFrame, try to get actual canvas element.
467 if (canvasFrame) {
468 HTMLCanvasElement* canvas =
469 HTMLCanvasElement::FromContentOrNull(canvasFrame->GetContent());
470 if (canvas && canvas->GetMozPrintCallback()) {
471 aArr->AppendElement(canvas);
472 continue;
473 }
474 }
475
476 if (!child->GetFirstPrincipalChild()) {
477 nsSubDocumentFrame* subdocumentFrame = do_QueryFrame(child);
478 if (subdocumentFrame) {
479 // Descend into the subdocument
480 nsIFrame* root = subdocumentFrame->GetSubdocumentRootFrame();
481 child = root;
482 }
483 }
484 // The current child is not a nsHTMLCanvasFrame OR it is but there is
485 // no HTMLCanvasElement on it. Check if children of `child` might
486 // contain a HTMLCanvasElement.
487 GetPrintCanvasElementsInFrame(child, aArr);
488 }
489 }
490 }
491
492 void
493 nsSimplePageSequenceFrame::DetermineWhetherToPrintPage()
494 {
495 // See whether we should print this page
496 mPrintThisPage = true;
497 bool printEvenPages, printOddPages;
498 mPageData->mPrintSettings->GetPrintOptions(nsIPrintSettings::kPrintEvenPages, &printEvenPages);
499 mPageData->mPrintSettings->GetPrintOptions(nsIPrintSettings::kPrintOddPages, &printOddPages);
500
501 // If printing a range of pages check whether the page number is in the
502 // range of pages to print
503 if (mDoingPageRange) {
504 if (mPageNum < mFromPageNum) {
505 mPrintThisPage = false;
506 } else if (mPageNum > mToPageNum) {
507 mPageNum++;
508 mPrintThisPage = false;
509 return;
510 } else {
511 int32_t length = mPageRanges.Length();
512
513 // Page ranges are pairs (start, end)
514 if (length && (length % 2 == 0)) {
515 mPrintThisPage = false;
516
517 int32_t i;
518 for (i = 0; i < length; i += 2) {
519 if (mPageRanges[i] <= mPageNum && mPageNum <= mPageRanges[i+1]) {
520 mPrintThisPage = true;
521 break;
522 }
523 }
524 }
525 }
526 }
527
528 // Check for printing of odd and even pages
529 if (mPageNum & 0x1) {
530 if (!printOddPages) {
531 mPrintThisPage = false; // don't print odd numbered page
532 }
533 } else {
534 if (!printEvenPages) {
535 mPrintThisPage = false; // don't print even numbered page
536 }
537 }
538
539 if (nsIPrintSettings::kRangeSelection == mPrintRangeType) {
540 mPrintThisPage = true;
541 }
542 }
543
544 nsIFrame*
545 nsSimplePageSequenceFrame::GetCurrentPageFrame()
546 {
547 int32_t i = 1;
548 for (nsFrameList::Enumerator childFrames(mFrames); !childFrames.AtEnd();
549 childFrames.Next()) {
550 if (i == mPageNum) {
551 return childFrames.get();
552 }
553 ++i;
554 }
555 return nullptr;
556 }
557
558 NS_IMETHODIMP
559 nsSimplePageSequenceFrame::PrePrintNextPage(nsITimerCallback* aCallback, bool* aDone)
560 {
561 nsIFrame* currentPage = GetCurrentPageFrame();
562 if (!currentPage) {
563 *aDone = true;
564 return NS_ERROR_FAILURE;
565 }
566
567 DetermineWhetherToPrintPage();
568 // Nothing to do if the current page doesn't get printed OR rendering to
569 // preview. For preview, the `CallPrintCallback` is called from within the
570 // HTMLCanvasElement::HandlePrintCallback.
571 if (!mPrintThisPage || !PresContext()->IsRootPaginatedDocument()) {
572 *aDone = true;
573 return NS_OK;
574 }
575
576 // If the canvasList is null, then generate it and start the render
577 // process for all the canvas.
578 if (!mCurrentCanvasListSetup) {
579 mCurrentCanvasListSetup = true;
580 GetPrintCanvasElementsInFrame(currentPage, &mCurrentCanvasList);
581
582 if (mCurrentCanvasList.Length() != 0) {
583 nsresult rv = NS_OK;
584
585 // Begin printing of the document
586 nsDeviceContext *dc = PresContext()->DeviceContext();
587 PR_PL(("\n"));
588 PR_PL(("***************** BeginPage *****************\n"));
589 rv = dc->BeginPage();
590 NS_ENSURE_SUCCESS(rv, rv);
591
592 mCalledBeginPage = true;
593
594 nsRefPtr<nsRenderingContext> renderingContext =
595 dc->CreateRenderingContext();
596
597 nsRefPtr<gfxASurface> renderingSurface =
598 renderingContext->ThebesContext()->CurrentSurface();
599 NS_ENSURE_TRUE(renderingSurface, NS_ERROR_OUT_OF_MEMORY);
600
601 for (int32_t i = mCurrentCanvasList.Length() - 1; i >= 0 ; i--) {
602 HTMLCanvasElement* canvas = mCurrentCanvasList[i];
603 nsIntSize size = canvas->GetSize();
604
605 nsRefPtr<gfxASurface> printSurface = renderingSurface->
606 CreateSimilarSurface(
607 gfxContentType::COLOR_ALPHA,
608 size
609 );
610
611 if (!printSurface) {
612 continue;
613 }
614
615 nsICanvasRenderingContextInternal* ctx = canvas->GetContextAtIndex(0);
616
617 if (!ctx) {
618 continue;
619 }
620
621 // Initialize the context with the new printSurface.
622 ctx->InitializeWithSurface(nullptr, printSurface, size.width, size.height);
623
624 // Start the rendering process.
625 nsWeakFrame weakFrame = this;
626 canvas->DispatchPrintCallback(aCallback);
627 NS_ENSURE_STATE(weakFrame.IsAlive());
628 }
629 }
630 }
631 uint32_t doneCounter = 0;
632 for (int32_t i = mCurrentCanvasList.Length() - 1; i >= 0 ; i--) {
633 HTMLCanvasElement* canvas = mCurrentCanvasList[i];
634
635 if (canvas->IsPrintCallbackDone()) {
636 doneCounter++;
637 }
638 }
639 // If all canvas have finished rendering, return true, otherwise false.
640 *aDone = doneCounter == mCurrentCanvasList.Length();
641
642 return NS_OK;
643 }
644
645 NS_IMETHODIMP
646 nsSimplePageSequenceFrame::ResetPrintCanvasList()
647 {
648 for (int32_t i = mCurrentCanvasList.Length() - 1; i >= 0 ; i--) {
649 HTMLCanvasElement* canvas = mCurrentCanvasList[i];
650 canvas->ResetPrintCallback();
651 }
652
653 mCurrentCanvasList.Clear();
654 mCurrentCanvasListSetup = false;
655 return NS_OK;
656 }
657
658 NS_IMETHODIMP
659 nsSimplePageSequenceFrame::PrintNextPage()
660 {
661 // Print each specified page
662 // pageNum keeps track of the current page and what pages are printing
663 //
664 // printedPageNum keeps track of the current page number to be printed
665 // Note: When print al the pages or a page range the printed page shows the
666 // actual page number, when printing selection it prints the page number starting
667 // with the first page of the selection. For example if the user has a
668 // selection that starts on page 2 and ends on page 3, the page numbers when
669 // print are 1 and then two (which is different than printing a page range, where
670 // the page numbers would have been 2 and then 3)
671
672 nsIFrame* currentPage = GetCurrentPageFrame();
673 if (!currentPage) {
674 return NS_ERROR_FAILURE;
675 }
676
677 nsresult rv = NS_OK;
678
679 DetermineWhetherToPrintPage();
680
681 if (mPrintThisPage) {
682 // Begin printing of the document
683 nsDeviceContext* dc = PresContext()->DeviceContext();
684
685 // XXX This is temporary fix for printing more than one page of a selection
686 // This does a poor man's "dump" pagination (see Bug 89353)
687 // It has laid out as one long page and now we are just moving or view up/down
688 // one page at a time and printing the contents of what is exposed by the rect.
689 // currently this does not work for IFrames
690 // I will soon improve this to work with IFrames
691 bool continuePrinting = true;
692 nscoord width, height;
693 width = PresContext()->GetPageSize().width;
694 height = PresContext()->GetPageSize().height;
695 height -= mMargin.top + mMargin.bottom;
696 width -= mMargin.left + mMargin.right;
697 nscoord selectionY = height;
698 nsIFrame* conFrame = currentPage->GetFirstPrincipalChild();
699 if (mSelectionHeight >= 0) {
700 conFrame->SetPosition(conFrame->GetPosition() + nsPoint(0, -mYSelOffset));
701 nsContainerFrame::PositionChildViews(conFrame);
702 }
703
704 // cast the frame to be a page frame
705 nsPageFrame * pf = static_cast<nsPageFrame*>(currentPage);
706 pf->SetPageNumInfo(mPageNum, mTotalPages);
707 pf->SetSharedPageData(mPageData);
708
709 int32_t printedPageNum = 1;
710 while (continuePrinting) {
711 if (PresContext()->IsRootPaginatedDocument()) {
712 if (!mCalledBeginPage) {
713 PR_PL(("\n"));
714 PR_PL(("***************** BeginPage *****************\n"));
715 rv = dc->BeginPage();
716 NS_ENSURE_SUCCESS(rv, rv);
717 } else {
718 mCalledBeginPage = false;
719 }
720 }
721
722 PR_PL(("SeqFr::PrintNextPage -> %p PageNo: %d", pf, mPageNum));
723
724 nsRefPtr<nsRenderingContext> renderingContext =
725 dc->CreateRenderingContext();
726
727 nsRect drawingRect(nsPoint(0, 0), currentPage->GetSize());
728 nsRegion drawingRegion(drawingRect);
729 nsLayoutUtils::PaintFrame(renderingContext, currentPage,
730 drawingRegion, NS_RGBA(0,0,0,0),
731 nsLayoutUtils::PAINT_SYNC_DECODE_IMAGES);
732
733 if (mSelectionHeight >= 0 && selectionY < mSelectionHeight) {
734 selectionY += height;
735 printedPageNum++;
736 pf->SetPageNumInfo(printedPageNum, mTotalPages);
737 conFrame->SetPosition(conFrame->GetPosition() + nsPoint(0, -height));
738 nsContainerFrame::PositionChildViews(conFrame);
739
740 PR_PL(("***************** End Page (PrintNextPage) *****************\n"));
741 rv = dc->EndPage();
742 NS_ENSURE_SUCCESS(rv, rv);
743 } else {
744 continuePrinting = false;
745 }
746 }
747 }
748 return rv;
749 }
750
751 NS_IMETHODIMP
752 nsSimplePageSequenceFrame::DoPageEnd()
753 {
754 nsresult rv = NS_OK;
755 if (PresContext()->IsRootPaginatedDocument() && mPrintThisPage) {
756 PR_PL(("***************** End Page (DoPageEnd) *****************\n"));
757 rv = PresContext()->DeviceContext()->EndPage();
758 NS_ENSURE_SUCCESS(rv, rv);
759 }
760
761 ResetPrintCanvasList();
762
763 mPageNum++;
764
765 return rv;
766 }
767
768 static gfx3DMatrix
769 ComputePageSequenceTransform(nsIFrame* aFrame, float aAppUnitsPerPixel)
770 {
771 float scale = aFrame->PresContext()->GetPrintPreviewScale();
772 return gfx3DMatrix::ScalingMatrix(scale, scale, 1);
773 }
774
775 void
776 nsSimplePageSequenceFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
777 const nsRect& aDirtyRect,
778 const nsDisplayListSet& aLists)
779 {
780 DisplayBorderBackgroundOutline(aBuilder, aLists);
781
782 nsDisplayList content;
783
784 {
785 // Clear clip state while we construct the children of the
786 // nsDisplayTransform, since they'll be in a different coordinate system.
787 DisplayListClipState::AutoSaveRestore clipState(aBuilder);
788 clipState.Clear();
789
790 nsIFrame* child = GetFirstPrincipalChild();
791 while (child) {
792 child->BuildDisplayListForStackingContext(aBuilder,
793 child->GetVisualOverflowRectRelativeToSelf(), &content);
794 aBuilder->ResetMarkedFramesForDisplayList();
795 child = child->GetNextSibling();
796 }
797 }
798
799 content.AppendNewToTop(new (aBuilder)
800 nsDisplayTransform(aBuilder, this, &content, ::ComputePageSequenceTransform));
801
802 aLists.Content()->AppendToTop(&content);
803 }
804
805 nsIAtom*
806 nsSimplePageSequenceFrame::GetType() const
807 {
808 return nsGkAtoms::sequenceFrame;
809 }
810
811 //------------------------------------------------------------------------------
812 void
813 nsSimplePageSequenceFrame::SetPageNumberFormat(const nsAString& aFormatStr, bool aForPageNumOnly)
814 {
815 NS_ASSERTION(mPageData != nullptr, "mPageData string cannot be null!");
816
817 if (aForPageNumOnly) {
818 mPageData->mPageNumFormat = aFormatStr;
819 } else {
820 mPageData->mPageNumAndTotalsFormat = aFormatStr;
821 }
822 }
823
824 //------------------------------------------------------------------------------
825 void
826 nsSimplePageSequenceFrame::SetDateTimeStr(const nsAString& aDateTimeStr)
827 {
828 NS_ASSERTION(mPageData != nullptr, "mPageData string cannot be null!");
829
830 mPageData->mDateTimeStr = aDateTimeStr;
831 }
832
833 //------------------------------------------------------------------------------
834 // For Shrink To Fit
835 //
836 // Return the percentage that the page needs to shrink to
837 //
838 NS_IMETHODIMP
839 nsSimplePageSequenceFrame::GetSTFPercent(float& aSTFPercent)
840 {
841 NS_ENSURE_TRUE(mPageData, NS_ERROR_UNEXPECTED);
842 aSTFPercent = mPageData->mShrinkToFitRatio;
843 return NS_OK;
844 }

mercurial