Bug 1328275 - Refactor and comment nsSimplePageSequenceFrame::PrintNextPage to make it easier to understand. r=bobowen
authorJonathan Watt <jwatt@jwatt.org>
Wed, 28 Dec 2016 11:26:31 +0000
changeset 356454 f43e221412b3d91d9d9ee350cdbccb0e246a9621
parent 356453 f9743055774c27b098664b700135b65cf40041f1
child 356455 55441ae91e84fdf2d511a2847d9ef95d04ad7f48
push id10621
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 16:02:43 +0000
treeherdermozilla-aurora@dca7b42e6c67 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbobowen
bugs1328275
milestone53.0a1
Bug 1328275 - Refactor and comment nsSimplePageSequenceFrame::PrintNextPage to make it easier to understand. r=bobowen
layout/generic/nsSimplePageSequenceFrame.cpp
--- a/layout/generic/nsSimplePageSequenceFrame.cpp
+++ b/layout/generic/nsSimplePageSequenceFrame.cpp
@@ -675,106 +675,124 @@ nsSimplePageSequenceFrame::ResetPrintCan
   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
+  // This method would be very straightforward except that the
+  // "Print Selection Only" functionality (which is a broken mess) is
+  // integrated here.  The thing to understand is that if we're printing a
+  // selection (which may contain multiple ranges) then we only enter this
+  // function once since the content to print is laid out as one arbitrarily
+  // long nsPageFrame instead of multiple nsPageFrames that are sized to fit
+  // the printer paper size(!).  Each of the "pages" between the start and end
+  // of the selection are printed by offsetting the nsPageContentFrame by the
+  // index of the page being printed and then drawing the nsPageContentFrame.
+  // This does not work for IFrames.
   //
-  // 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) {
+  nsIFrame* currentPageFrame = GetCurrentPageFrame();
+  if (!currentPageFrame) {
     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->PrincipalChildList().FirstChild();
-    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);
+    nsPageFrame * pf = static_cast<nsPageFrame*>(currentPageFrame);
     pf->SetPageNumInfo(mPageNum, mTotalPages);
     pf->SetSharedPageData(mPageData);
 
-    int32_t printedPageNum = 1;
-    while (continuePrinting) {
+    // Only used if we're printing a selection:
+    nsIFrame* selectionContentFrame = nullptr;
+    nscoord pageContentHeight =
+      PresContext()->GetPageSize().height - (mMargin.top + mMargin.bottom);
+    nscoord selectionY = pageContentHeight;
+    int32_t selectionCurrentPageNum = 1;
+    bool haveUnfinishedSelectionToPrint = false;
+
+    if (mSelectionHeight >= 0) {
+      selectionContentFrame = currentPageFrame->PrincipalChildList().FirstChild();
+      MOZ_ASSERT(selectionContentFrame->GetType() == nsGkAtoms::pageContentFrame &&
+                 !selectionContentFrame->GetNextSibling(),
+                 "Unexpected frame tree");
+      // To print a selection we reposition the page content frame for each
+      // page.  We can do this (and not have to bother resetting the position
+      // after we're done) because we are printing from a static clone document
+      // that is thrown away after we finish printing.
+      selectionContentFrame->SetPosition(selectionContentFrame->GetPosition() +
+                                         nsPoint(0, -mYSelOffset));
+      nsContainerFrame::PositionChildViews(selectionContentFrame);
+    }
+
+    do {
       if (PresContext()->IsRootPaginatedDocument()) {
         if (!mCalledBeginPage) {
+          // We must make sure BeginPage() has been called since some printing
+          // backends can't give us a valid rendering context for a [physical]
+          // page otherwise.
           PR_PL(("\n"));
           PR_PL(("***************** BeginPage *****************\n"));
           rv = dc->BeginPage();
           NS_ENSURE_SUCCESS(rv, rv);
-        } else {
-          mCalledBeginPage = false;
         }
+
+        // Reset this flag. We reset it early here because if we loop around to
+        // print another page's worth of selection we need to call BeginPage
+        // again:
+        mCalledBeginPage = false;
       }
 
       PR_PL(("SeqFr::PrintNextPage -> %p PageNo: %d", pf, mPageNum));
 
       // CreateRenderingContext can fail
       RefPtr<gfxContext> gCtx = dc->CreateRenderingContext();
       NS_ENSURE_TRUE(gCtx, NS_ERROR_OUT_OF_MEMORY);
 
       nsRenderingContext renderingContext(gCtx);
 
-      nsRect drawingRect(nsPoint(0, 0), currentPage->GetSize());
+      nsRect drawingRect(nsPoint(0, 0), currentPageFrame->GetSize());
       nsRegion drawingRegion(drawingRect);
-      nsLayoutUtils::PaintFrame(&renderingContext, currentPage,
+      nsLayoutUtils::PaintFrame(&renderingContext, currentPageFrame,
                                 drawingRegion, NS_RGBA(0,0,0,0),
                                 nsDisplayListBuilderMode::PAINTING,
                                 nsLayoutUtils::PaintFrameFlags::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);
+      if (mSelectionHeight >= 0) {
+        haveUnfinishedSelectionToPrint = (selectionY < mSelectionHeight);
+        if (haveUnfinishedSelectionToPrint) {
+          selectionY += pageContentHeight;
+          selectionCurrentPageNum++;
+          pf->SetPageNumInfo(selectionCurrentPageNum, mTotalPages);
+          selectionContentFrame->SetPosition(selectionContentFrame->GetPosition() +
+                                             nsPoint(0, -pageContentHeight));
+          nsContainerFrame::PositionChildViews(selectionContentFrame);
 
-        PR_PL(("***************** End Page (PrintNextPage) *****************\n"));
-        rv = dc->EndPage();
-        NS_ENSURE_SUCCESS(rv, rv);
-      } else {
-        continuePrinting = false;
+          // We're going to loop and call BeginPage to print another page's worth
+          // of selection so we need to call EndPage first.  (Otherwise, EndPage
+          // is called in DoEndPage.)
+          PR_PL(("***************** End Page (PrintNextPage) *****************\n"));
+          rv = dc->EndPage();
+          NS_ENSURE_SUCCESS(rv, rv);
+        }
       }
-    }
+    } while (haveUnfinishedSelectionToPrint);
   }
   return rv;
 }
 
 NS_IMETHODIMP
 nsSimplePageSequenceFrame::DoPageEnd()
 {
   nsresult rv = NS_OK;