layout/generic/nsSimplePageSequenceFrame.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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/. */
     6 #include "nsSimplePageSequenceFrame.h"
     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>
    28 // DateTime Includes
    29 #include "nsDateTimeFormatCID.h"
    31 #define OFFSET_NOT_SET -1
    33 // Print Options
    34 #include "nsIPrintOptions.h"
    36 using namespace mozilla;
    37 using namespace mozilla::dom;
    39 static const char sPrintOptionsContractID[] = "@mozilla.org/gfx/printsettings-service;1";
    41 //
    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
    58 nsIFrame*
    59 NS_NewSimplePageSequenceFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
    60 {
    61   return new (aPresShell) nsSimplePageSequenceFrame(aContext);
    62 }
    64 NS_IMPL_FRAMEARENA_HELPERS(nsSimplePageSequenceFrame)
    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);
    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);
    84   nsresult rv;
    85   mPageData->mPrintOptions = do_GetService(sPrintOptionsContractID, &rv);
    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 }
    92 nsSimplePageSequenceFrame::~nsSimplePageSequenceFrame()
    93 {
    94   delete mPageData;
    95   ResetPrintCanvasList();
    96 }
    98 NS_QUERYFRAME_HEAD(nsSimplePageSequenceFrame)
    99   NS_QUERYFRAME_ENTRY(nsIPageSequenceFrame)
   100 NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
   102 //----------------------------------------------------------------------
   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 }
   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");
   132   aStatus = NS_FRAME_COMPLETE;  // we're always complete
   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   }
   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   }
   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");
   158     nsIntMargin marginTwips;
   159     mPageData->mPrintSettings->GetMarginInTwips(marginTwips);
   160     mMargin = aPresContext->CSSTwipsToAppUnits(marginTwips + unwriteableTwips);
   162     int16_t printType;
   163     mPageData->mPrintSettings->GetPrintRange(&printType);
   164     mPrintRangeType = printType;
   166     nsIntMargin edgeTwips;
   167     mPageData->mPrintSettings->GetEdgeInTwips(edgeTwips);
   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);
   176     mPageData->mEdgePaperMargin =
   177       aPresContext->CSSTwipsToAppUnits(edgeTwips + unwriteableTwips);
   178   }
   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
   185   nsSize pageSize = aPresContext->GetPageSize();
   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;
   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;
   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);
   209     // Reflow the page
   210     nsHTMLReflowState kidReflowState(aPresContext, aReflowState, kidFrame,
   211                                      pageSize);
   212     nsReflowStatus  status;
   214     kidReflowState.SetComputedWidth(kidReflowState.AvailableWidth());
   215     //kidReflowState.SetComputedHeight(kidReflowState.AvailableHeight());
   216     PR_PL(("AV W: %d   H: %d\n", kidReflowState.AvailableWidth(), kidReflowState.AvailableHeight()));
   218     nsMargin pageCSSMargin = kidReflowState.ComputedPhysicalMargin();
   219     y += pageCSSMargin.top;
   220     const nscoord x = pageCSSMargin.left;
   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);
   226     FinishReflowChild(kidFrame, aPresContext, kidSize, nullptr, x, y, 0);
   227     y += kidSize.Height();
   228     y += pageCSSMargin.bottom;
   230     maxXMost = std::max(maxXMost, x + kidSize.Width() + pageCSSMargin.right);
   232     // Is the page complete?
   233     nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow();
   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);
   243       // Add it to our child list
   244       mFrames.InsertFrame(nullptr, kidFrame, continuingPage);
   245     }
   247     // Get the next page
   248     kidFrame = kidFrame->GetNextSibling();
   249   }
   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   }
   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   }
   268   // Create current Date/Time String
   269   if (!mDateFormatter)
   270     mDateFormatter = do_CreateInstance(NS_DATETIMEFORMAT_CONTRACTID);
   272   NS_ENSURE_TRUE(mDateFormatter, NS_ERROR_FAILURE);
   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   }
   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);
   290   aDesiredSize.SetOverflowAreasToDesiredBounds();
   291   FinishAndStoreOverflow(&aDesiredSize);
   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;
   298   NS_FRAME_TRACE_REFLOW_OUT("nsSimplePageSequeceFrame::Reflow", aStatus);
   299   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
   300   return NS_OK;
   301 }
   303 //----------------------------------------------------------------------
   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
   313 //====================================================================
   314 //== Asynch Printing
   315 //====================================================================
   316 NS_IMETHODIMP
   317 nsSimplePageSequenceFrame::GetCurrentPageNum(int32_t* aPageNum)
   318 {
   319   NS_ENSURE_ARG_POINTER(aPageNum);
   321   *aPageNum = mPageNum;
   322   return NS_OK;
   323 }
   325 NS_IMETHODIMP
   326 nsSimplePageSequenceFrame::GetNumPages(int32_t* aNumPages)
   327 {
   328   NS_ENSURE_ARG_POINTER(aNumPages);
   330   *aNumPages = mTotalPages;
   331   return NS_OK;
   332 }
   334 NS_IMETHODIMP
   335 nsSimplePageSequenceFrame::IsDoingPrintRange(bool* aDoing)
   336 {
   337   NS_ENSURE_ARG_POINTER(aDoing);
   339   *aDoing = mDoingPageRange;
   340   return NS_OK;
   341 }
   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);
   349   *aFromPage = mFromPageNum;
   350   *aToPage   = mToPageNum;
   351   return NS_OK;
   352 }
   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   }
   368   SetPageNumberFormat(pageNumberFormat, aPageNumOnly);
   369 }
   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);
   380   if (!mPageData->mPrintSettings) {
   381     mPageData->mPrintSettings = aPrintSettings;
   382   }
   384   if (!aDocTitle.IsEmpty()) {
   385     mPageData->mDocTitle = aDocTitle;
   386   }
   387   if (!aDocURL.IsEmpty()) {
   388     mPageData->mDocURL = aDocURL;
   389   }
   391   aPrintSettings->GetStartPageRange(&mFromPageNum);
   392   aPrintSettings->GetEndPageRange(&mToPageNum);
   393   aPrintSettings->GetPageRanges(mPageRanges);
   395   mDoingPageRange = nsIPrintSettings::kRangeSpecifiedPageRange == mPrintRangeType ||
   396                     nsIPrintSettings::kRangeSelection == mPrintRangeType;
   398   // If printing a range of pages make sure at least the starting page
   399   // number is valid
   400   int32_t totalPages = mFrames.GetLength();
   402   if (mDoingPageRange) {
   403     if (mFromPageNum > totalPages) {
   404       return NS_ERROR_INVALID_ARG;
   405     }
   406   }
   408   // Begin printing of the document
   409   nsresult rv = NS_OK;
   411   // Determine if we are rendering only the selection
   412   aPresContext->SetIsRenderingOnlySelection(nsIPrintSettings::kRangeSelection == mPrintRangeType);
   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;
   420     int32_t pageNum = 1;
   421     nscoord y = 0;//mMargin.top;
   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     }
   435     // adjust total number of pages
   436     if (nsIPrintSettings::kRangeSelection != mPrintRangeType) {
   437       totalPages = pageNum - 1;
   438     }
   439   }
   441   mPageNum = 1;
   443   if (mTotalPages == -1) {
   444     mTotalPages = totalPages;
   445   }
   447   return rv;
   448 }
   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()) {
   459     nsFrameList children = childLists.CurrentList();
   460     for (nsFrameList::Enumerator e(children); !e.AtEnd(); e.Next()) {
   461       nsIFrame* child = e.get();
   463       // Check if child is a nsHTMLCanvasFrame.
   464       nsHTMLCanvasFrame* canvasFrame = do_QueryFrame(child);
   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       }
   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 }
   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);
   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();
   513       // Page ranges are pairs (start, end)
   514       if (length && (length % 2 == 0)) {
   515         mPrintThisPage = false;
   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   }
   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   }
   539   if (nsIPrintSettings::kRangeSelection == mPrintRangeType) {
   540     mPrintThisPage = true;
   541   }
   542 }
   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 }
   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   }
   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   }
   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);
   582     if (mCurrentCanvasList.Length() != 0) {
   583       nsresult rv = NS_OK;
   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);
   592       mCalledBeginPage = true;
   594       nsRefPtr<nsRenderingContext> renderingContext =
   595         dc->CreateRenderingContext();
   597       nsRefPtr<gfxASurface> renderingSurface =
   598           renderingContext->ThebesContext()->CurrentSurface();
   599       NS_ENSURE_TRUE(renderingSurface, NS_ERROR_OUT_OF_MEMORY);
   601       for (int32_t i = mCurrentCanvasList.Length() - 1; i >= 0 ; i--) {
   602         HTMLCanvasElement* canvas = mCurrentCanvasList[i];
   603         nsIntSize size = canvas->GetSize();
   605         nsRefPtr<gfxASurface> printSurface = renderingSurface->
   606            CreateSimilarSurface(
   607              gfxContentType::COLOR_ALPHA,
   608              size
   609            );
   611         if (!printSurface) {
   612           continue;
   613         }
   615         nsICanvasRenderingContextInternal* ctx = canvas->GetContextAtIndex(0);
   617         if (!ctx) {
   618           continue;
   619         }
   621           // Initialize the context with the new printSurface.
   622         ctx->InitializeWithSurface(nullptr, printSurface, size.width, size.height);
   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];
   635     if (canvas->IsPrintCallbackDone()) {
   636       doneCounter++;
   637     }
   638   }
   639   // If all canvas have finished rendering, return true, otherwise false.
   640   *aDone = doneCounter == mCurrentCanvasList.Length();
   642   return NS_OK;
   643 }
   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   }
   653   mCurrentCanvasList.Clear();
   654   mCurrentCanvasListSetup = false; 
   655   return NS_OK;
   656 } 
   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)
   672   nsIFrame* currentPage = GetCurrentPageFrame();
   673   if (!currentPage) {
   674     return NS_ERROR_FAILURE;
   675   }
   677   nsresult rv = NS_OK;
   679   DetermineWhetherToPrintPage();
   681   if (mPrintThisPage) {
   682     // Begin printing of the document
   683     nsDeviceContext* dc = PresContext()->DeviceContext();
   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     }
   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);
   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       }
   722       PR_PL(("SeqFr::PrintNextPage -> %p PageNo: %d", pf, mPageNum));
   724       nsRefPtr<nsRenderingContext> renderingContext =
   725         dc->CreateRenderingContext();
   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);
   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);
   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 }
   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   }
   761   ResetPrintCanvasList();
   763   mPageNum++;
   765   return rv;
   766 }
   768 static gfx3DMatrix
   769 ComputePageSequenceTransform(nsIFrame* aFrame, float aAppUnitsPerPixel)
   770 {
   771   float scale = aFrame->PresContext()->GetPrintPreviewScale();
   772   return gfx3DMatrix::ScalingMatrix(scale, scale, 1);
   773 }
   775 void
   776 nsSimplePageSequenceFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
   777                                             const nsRect&           aDirtyRect,
   778                                             const nsDisplayListSet& aLists)
   779 {
   780   DisplayBorderBackgroundOutline(aBuilder, aLists);
   782   nsDisplayList content;
   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();
   790     nsIFrame* child = GetFirstPrincipalChild();
   791     while (child) {
   792       child->BuildDisplayListForStackingContext(aBuilder,
   793           child->GetVisualOverflowRectRelativeToSelf(), &content);
   794       aBuilder->ResetMarkedFramesForDisplayList();
   795       child = child->GetNextSibling();
   796     }
   797   }
   799   content.AppendNewToTop(new (aBuilder)
   800       nsDisplayTransform(aBuilder, this, &content, ::ComputePageSequenceTransform));
   802   aLists.Content()->AppendToTop(&content);
   803 }
   805 nsIAtom*
   806 nsSimplePageSequenceFrame::GetType() const
   807 {
   808   return nsGkAtoms::sequenceFrame; 
   809 }
   811 //------------------------------------------------------------------------------
   812 void
   813 nsSimplePageSequenceFrame::SetPageNumberFormat(const nsAString& aFormatStr, bool aForPageNumOnly)
   814 { 
   815   NS_ASSERTION(mPageData != nullptr, "mPageData string cannot be null!");
   817   if (aForPageNumOnly) {
   818     mPageData->mPageNumFormat = aFormatStr;
   819   } else {
   820     mPageData->mPageNumAndTotalsFormat = aFormatStr;
   821   }
   822 }
   824 //------------------------------------------------------------------------------
   825 void
   826 nsSimplePageSequenceFrame::SetDateTimeStr(const nsAString& aDateTimeStr)
   827 { 
   828   NS_ASSERTION(mPageData != nullptr, "mPageData string cannot be null!");
   830   mPageData->mDateTimeStr = aDateTimeStr;
   831 }
   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