diff options
Diffstat (limited to 'layout/printing/nsPagePrintTimer.cpp')
-rw-r--r-- | layout/printing/nsPagePrintTimer.cpp | 224 |
1 files changed, 224 insertions, 0 deletions
diff --git a/layout/printing/nsPagePrintTimer.cpp b/layout/printing/nsPagePrintTimer.cpp new file mode 100644 index 0000000000..88f4deb3e5 --- /dev/null +++ b/layout/printing/nsPagePrintTimer.cpp @@ -0,0 +1,224 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsPagePrintTimer.h" + +#include "mozilla/dom/Document.h" +#include "mozilla/ProfilerMarkers.h" +#include "mozilla/Unused.h" +#include "nsPrintJob.h" +#include "nsPrintObject.h" + +using namespace mozilla; + +NS_IMPL_ISUPPORTS_INHERITED(nsPagePrintTimer, mozilla::Runnable, + nsITimerCallback) + +nsPagePrintTimer::nsPagePrintTimer(nsPrintJob* aPrintJob, + nsIDocumentViewerPrint* aDocViewerPrint, + mozilla::dom::Document* aDocument, + uint32_t aDelay) + : Runnable("nsPagePrintTimer"), + mPrintJob(aPrintJob), + mDocViewerPrint(aDocViewerPrint), + mDocument(aDocument), + mDelay(aDelay), + mFiringCount(0), + mPrintObj(nullptr), + mWatchDogCount(0), + mDone(false) { + MOZ_ASSERT(aDocViewerPrint && aDocument); + mDocViewerPrint->IncrementDestroyBlockedCount(); +} + +nsPagePrintTimer::~nsPagePrintTimer() { Disconnect(); } + +void nsPagePrintTimer::Disconnect() { + mPrintJob = nullptr; + mPrintObj = nullptr; + if (mDocViewerPrint) { + // This matches the IncrementDestroyBlockedCount call in the constructor. + mDocViewerPrint->DecrementDestroyBlockedCount(); + mDocViewerPrint = nullptr; + } +} + +nsresult nsPagePrintTimer::StartTimer(bool aUseDelay) { + uint32_t delay = 0; + if (aUseDelay) { + if (mFiringCount < 10) { + // Longer delay for the few first pages. + delay = mDelay + ((10 - mFiringCount) * 100); + } else { + delay = mDelay; + } + } + return NS_NewTimerWithCallback(getter_AddRefs(mTimer), this, delay, + nsITimer::TYPE_ONE_SHOT, + GetMainThreadSerialEventTarget()); +} + +nsresult nsPagePrintTimer::StartWatchDogTimer() { + if (mWatchDogTimer) { + mWatchDogTimer->Cancel(); + } + // Instead of just doing one timer for a long period do multiple so we + // can check if the user cancelled the printing. + return NS_NewTimerWithCallback(getter_AddRefs(mWatchDogTimer), this, + WATCH_DOG_INTERVAL, nsITimer::TYPE_ONE_SHOT, + GetMainThreadSerialEventTarget()); +} + +void nsPagePrintTimer::StopWatchDogTimer() { + if (mWatchDogTimer) { + mWatchDogTimer->Cancel(); + mWatchDogTimer = nullptr; + } +} + +// nsRunnable +NS_IMETHODIMP +nsPagePrintTimer::Run() { + bool initNewTimer = true; + bool donePrinting; + + // donePrinting will be true if it completed successfully or + // if the printing was cancelled + donePrinting = !mPrintJob || mPrintJob->PrintSheet(mPrintObj); + if (donePrinting) { + if (mWaitingForRemotePrint || + // If we are not waiting for the remote printing, it is the time to + // end printing task by calling DonePrintingSheets. + (!mPrintJob || mPrintJob->DonePrintingSheets(mPrintObj, NS_OK))) { + initNewTimer = false; + mDone = true; + } + } + + // Note that the Stop() destroys this after the print job finishes + // (The nsPrintJob stops holding a reference when DonePrintingSheets + // returns true.) + Stop(); + if (initNewTimer) { + ++mFiringCount; + nsresult result = StartTimer(/*aUseDelay*/ true); + if (NS_FAILED(result)) { + mDone = true; // had a failure.. we are finished.. + if (mPrintJob) { + mPrintJob->SetIsPrinting(false); + } + } + } + return NS_OK; +} + +// nsITimerCallback +NS_IMETHODIMP +nsPagePrintTimer::Notify(nsITimer* timer) { + // When finished there may be still pending notifications, which we can just + // ignore. + if (mDone) { + return NS_OK; + } + + // There are four things that call Notify with different values for timer: + // 1) the delay between sheets (timer == mTimer) + // 2) canvasPrintState done (timer == null) + // 3) the watch dog timer (timer == mWatchDogTimer) + // 4) the waiting for remote print "timer" (timer == mWaitingForRemotePrint) + if (!timer) { + // Reset the counter since a mozPrintCallback has finished. + mWatchDogCount = 0; + } else if (timer == mTimer) { + // Reset the watchdog timer before the start of every sheet. + mWatchDogCount = 0; + mTimer = nullptr; + } else if (timer == mWaitingForRemotePrint) { + mWaitingForRemotePrint = nullptr; + + // If we are still waiting for the sheet delay timer, don't let the + // notification from the remote print job trigger the next sheet. + if (mTimer) { + return NS_OK; + } + } else if (timer == mWatchDogTimer) { + mWatchDogCount++; + PROFILER_MARKER_TEXT( + "nsPagePrintTimer::Notify", LAYOUT_Printing, {}, + nsPrintfCString("Watchdog Timer Count %d", mWatchDogCount)); + + if (mWatchDogCount > WATCH_DOG_MAX_COUNT) { + Fail(); + return NS_OK; + } + } + + bool donePrePrint = true; + // Don't start to pre-print if we're waiting on the parent still. + if (mPrintJob && !mWaitingForRemotePrint) { + donePrePrint = mPrintJob->PrePrintSheet(); + } + + if (donePrePrint && !mWaitingForRemotePrint) { + StopWatchDogTimer(); + // Pass nullptr here since name already was set in constructor. + mDocument->Dispatch(do_AddRef(this)); + } else { + // Start the watch dog if we're waiting for preprint to ensure that if any + // mozPrintCallbacks take to long we error out. + StartWatchDogTimer(); + } + + return NS_OK; +} + +void nsPagePrintTimer::WaitForRemotePrint() { + mWaitingForRemotePrint = NS_NewTimer(); + if (!mWaitingForRemotePrint) { + NS_WARNING("Failed to wait for remote print, we might time-out."); + } +} + +void nsPagePrintTimer::RemotePrintFinished() { + if (!mWaitingForRemotePrint) { + return; + } + + // now clean up print or print the next webshell + if (mDone && mPrintJob) { + mDone = mPrintJob->DonePrintingSheets(mPrintObj, NS_OK); + } + + mWaitingForRemotePrint->SetTarget(GetMainThreadSerialEventTarget()); + mozilla::Unused << mWaitingForRemotePrint->InitWithCallback( + this, 0, nsITimer::TYPE_ONE_SHOT); +} + +nsresult nsPagePrintTimer::Start(nsPrintObject* aPO) { + mPrintObj = aPO; + mDone = false; + return StartTimer(false); +} + +void nsPagePrintTimer::Stop() { + if (mTimer) { + mTimer->Cancel(); + mTimer = nullptr; + } + StopWatchDogTimer(); +} + +void nsPagePrintTimer::Fail() { + NS_WARNING("nsPagePrintTimer::Fail called"); + PROFILER_MARKER_TEXT("nsPagePrintTimer", LAYOUT_Printing, {}, + "nsPagePrintTimer::Fail aborting print operation"_ns); + + mDone = true; + Stop(); + if (mPrintJob) { + mPrintJob->CleanupOnFailure(NS_OK, false); + } +} |