Bug 1412643 - Part 3 - fixed print selection; r?bobowen
When printing a selection, we treat all pages in a selection as a single 'page'
internally. Before this patch we handled this in a single iteration, thereby
bypassing the control flow normally applied to the IPC. With this patch, we
don't attempt to print additional pages until IPC related to the former page has
completed.
MozReview-Commit-ID: 1Oi2ZFMLP8D
--- a/layout/generic/nsIPageSequenceFrame.h
+++ b/layout/generic/nsIPageSequenceFrame.h
@@ -51,13 +51,13 @@ public:
NS_IMETHOD DoPageEnd() = 0;
NS_IMETHOD SetSelectionHeight(nscoord aYOffset, nscoord aHeight) = 0;
NS_IMETHOD SetTotalNumPages(int32_t aTotal) = 0;
// For Shrink To Fit
NS_IMETHOD GetSTFPercent(float& aSTFPercent) = 0;
+
+ NS_IMETHOD IsInSelection(bool* aInSelection) = 0;
};
#endif /* nsIPageSequenceFrame_h___ */
-
-
--- a/layout/generic/nsSimplePageSequenceFrame.cpp
+++ b/layout/generic/nsSimplePageSequenceFrame.cpp
@@ -382,16 +382,23 @@ nsSimplePageSequenceFrame::GetPrintRange
NS_ENSURE_ARG_POINTER(aFromPage);
NS_ENSURE_ARG_POINTER(aToPage);
*aFromPage = mFromPageNum;
*aToPage = mToPageNum;
return NS_OK;
}
+NS_IMETHODIMP
+nsSimplePageSequenceFrame::IsInSelection(bool* aInSelection)
+{
+ *aInSelection = mCurrentSelection.isSome();
+ return NS_OK;
+}
+
// Helper Function
void
nsSimplePageSequenceFrame::SetPageNumberFormat(const char* aPropName, const char* aDefPropVal, bool aPageNumOnly)
{
// Doing this here so we only have to go get these formats once
nsAutoString pageNumberFormat;
// Now go get the Localized Page Formating String
nsresult rv =
@@ -710,114 +717,127 @@ nsSimplePageSequenceFrame::PrintNextPage
nsIFrame* currentPageFrame = GetCurrentPageFrame();
if (!currentPageFrame) {
return NS_ERROR_FAILURE;
}
nsresult rv = NS_OK;
- DetermineWhetherToPrintPage();
+ if (!mCurrentSelection) {
+ DetermineWhetherToPrintPage();
+ }
if (mPrintThisPage) {
nsDeviceContext* dc = PresContext()->DeviceContext();
- nsPageFrame * pf = static_cast<nsPageFrame*>(currentPageFrame);
- pf->SetPageNumInfo(mPageNum, mTotalPages);
- pf->SetSharedPageData(mPageData);
+ nsPageFrame* pf = static_cast<nsPageFrame*>(currentPageFrame);
+ if (!mCurrentSelection) {
+ pf->SetPageNumInfo(mPageNum, mTotalPages);
+ pf->SetSharedPageData(mPageData);
+ }
// 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;
+ if (mCurrentSelection) {
+ selectionY = mCurrentSelection->mSelectionY;
+ selectionCurrentPageNum = mCurrentSelection->mCurrentPageNum;
+ }
bool haveUnfinishedSelectionToPrint = false;
if (mSelectionHeight >= 0) {
selectionContentFrame = currentPageFrame->PrincipalChildList().FirstChild();
MOZ_ASSERT(selectionContentFrame->IsPageContentFrame() &&
!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);
- }
-
- // 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;
+ 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);
}
- 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);
+ // 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;
+ }
- nsRect drawingRect(nsPoint(0, 0), currentPageFrame->GetSize());
- nsRegion drawingRegion(drawingRect);
- nsLayoutUtils::PaintFrame(gCtx, currentPageFrame,
- drawingRegion, NS_RGBA(0,0,0,0),
- nsDisplayListBuilderMode::PAINTING,
- nsLayoutUtils::PaintFrameFlags::PAINT_SYNC_DECODE_IMAGES);
+ 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);
- 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);
+ nsRect drawingRect(nsPoint(0, 0), currentPageFrame->GetSize());
+ nsRegion drawingRegion(drawingRect);
+ nsLayoutUtils::PaintFrame(
+ gCtx,
+ currentPageFrame,
+ drawingRegion,
+ NS_RGBA(0, 0, 0, 0),
+ nsDisplayListBuilderMode::PAINTING,
+ nsLayoutUtils::PaintFrameFlags::PAINT_SYNC_DECODE_IMAGES);
- // 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);
- }
+ 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);
+
+ mCurrentSelection =
+ Some(CurrentSelection(selectionY, selectionCurrentPageNum));
+ } else {
+ mCurrentSelection = Nothing();
}
- } while (haveUnfinishedSelectionToPrint);
+ } else {
+ mCurrentSelection = Nothing();
+ }
}
return rv;
}
NS_IMETHODIMP
nsSimplePageSequenceFrame::DoPageEnd()
{
nsresult rv = NS_OK;
if (PresContext()->IsRootPaginatedDocument() && mPrintThisPage) {
PR_PL(("***************** End Page (DoPageEnd) *****************\n"));
rv = PresContext()->DeviceContext()->EndPage();
NS_ENSURE_SUCCESS(rv, rv);
}
- ResetPrintCanvasList();
+ if (!mCurrentSelection) {
+ ResetPrintCanvasList();
- mPageNum++;
+ mPageNum++;
+ }
return rv;
}
inline gfx::Matrix4x4
ComputePageSequenceTransform(nsIFrame* aFrame, float aAppUnitsPerPixel)
{
float scale = aFrame->PresContext()->GetPrintPreviewScale();
--- a/layout/generic/nsSimplePageSequenceFrame.h
+++ b/layout/generic/nsSimplePageSequenceFrame.h
@@ -88,16 +88,17 @@ public:
NS_IMETHOD PrePrintNextPage(nsITimerCallback* aCallback, bool* aDone) override;
NS_IMETHOD PrintNextPage() override;
NS_IMETHOD ResetPrintCanvasList() override;
NS_IMETHOD GetCurrentPageNum(int32_t* aPageNum) override;
NS_IMETHOD GetNumPages(int32_t* aNumPages) override;
NS_IMETHOD IsDoingPrintRange(bool* aDoing) override;
NS_IMETHOD GetPrintRange(int32_t* aFromPage, int32_t* aToPage) override;
NS_IMETHOD DoPageEnd() override;
+ NS_IMETHOD IsInSelection(bool* aInSelection) override;
// We must allow Print Preview UI to have a background, no matter what the
// user's settings
bool HonorPrintBackgroundSettings() override { return false; }
bool HasTransformGetter() const override { return true; }
/**
@@ -144,16 +145,27 @@ protected:
int32_t mPageNum;
int32_t mTotalPages;
int32_t mPrintRangeType;
int32_t mFromPageNum;
int32_t mToPageNum;
nsTArray<int32_t> mPageRanges;
nsTArray<RefPtr<mozilla::dom::HTMLCanvasElement> > mCurrentCanvasList;
+ struct CurrentSelection
+ {
+ explicit CurrentSelection(nscoord aSelectionY, int32_t aCurrentPageNum)
+ : mSelectionY(aSelectionY)
+ , mCurrentPageNum(aCurrentPageNum){};
+
+ nscoord mSelectionY;
+ int32_t mCurrentPageNum;
+ };
+ mozilla::Maybe<CurrentSelection> mCurrentSelection;
+
// Selection Printing Info
nscoord mSelectionHeight;
nscoord mYSelOffset;
// Asynch Printing
bool mPrintThisPage;
bool mDoingPageRange;
--- a/layout/printing/nsPrintEngine.cpp
+++ b/layout/printing/nsPrintEngine.cpp
@@ -2864,43 +2864,61 @@ nsPrintEngine::PrintPage(nsPrintObject*
}
// XXX This is wrong, but the actual behavior in the presence of a print
// range sucks.
if (printData->mPrintFrameType == nsIPrintSettings::kEachFrameSep) {
endPage = printData->mNumPrintablePages;
}
- printData->DoOnProgressChange(++printData->mNumPagesPrinted,
- endPage, false, 0);
- if (NS_WARN_IF(mPrt != printData)) {
- // If current printing is canceled or new print is started, let's return
- // true to notify the caller of current printing is done.
+ bool isInSelection = false;
+ nsresult rv = pageSeqFrame->IsInSelection(&isInSelection);
+ if (NS_FAILED(rv)) {
+ FirePrintingErrorEvent(rv);
+ printData->mIsAborted = true;
return true;
}
+ if (!isInSelection) {
+ printData->DoOnProgressChange(
+ ++printData->mNumPagesPrinted, endPage, false, 0);
+ if (NS_WARN_IF(mPrt != printData)) {
+ // If current printing is canceled or new print is started, let's return
+ // true to notify the caller of current printing is done.
+ return true;
+ }
+ }
// Print the Page
// if a print job was cancelled externally, an EndPage or BeginPage may
// fail and the failure is passed back here.
// Returning true means we are done printing.
//
// When rv == NS_ERROR_ABORT, it means we want out of the
// print job without displaying any error messages
- nsresult rv = pageSeqFrame->PrintNextPage();
+ rv = pageSeqFrame->PrintNextPage();
if (NS_FAILED(rv)) {
if (rv != NS_ERROR_ABORT) {
FirePrintingErrorEvent(rv);
printData->mIsAborted = true;
}
return true;
}
pageSeqFrame->DoPageEnd();
- return donePrinting;
+ rv = pageSeqFrame->IsInSelection(&isInSelection);
+ if (NS_FAILED(rv)) {
+ FirePrintingErrorEvent(rv);
+ printData->mIsAborted = true;
+ return true;
+ }
+
+ // If we're in a selection, we're not actually done until that whole selection
+ // is done.
+ return donePrinting && !isInSelection;
}
/** ---------------------------------------------------
* Find by checking frames type
*/
nsresult
nsPrintEngine::FindSelectionBoundsWithList(nsFrameList::Enumerator& aChildFrames,
nsIFrame * aParentFrame,