michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsPagePrintTimer.h" michael@0: #include "nsIContentViewer.h" michael@0: #include "nsIServiceManager.h" michael@0: #include "nsPrintEngine.h" michael@0: michael@0: NS_IMPL_ISUPPORTS_INHERITED(nsPagePrintTimer, nsRunnable, nsITimerCallback) michael@0: michael@0: nsPagePrintTimer::~nsPagePrintTimer() michael@0: { michael@0: // "Destroy" the document viewer; this normally doesn't actually michael@0: // destroy it because of the IncrementDestroyRefCount call below michael@0: // XXX This is messy; the document viewer should use a single approach michael@0: // to keep itself alive during printing michael@0: nsCOMPtr cv(do_QueryInterface(mDocViewerPrint)); michael@0: if (cv) { michael@0: cv->Destroy(); michael@0: } michael@0: } michael@0: michael@0: nsresult michael@0: nsPagePrintTimer::StartTimer(bool aUseDelay) michael@0: { michael@0: nsresult result; michael@0: mTimer = do_CreateInstance("@mozilla.org/timer;1", &result); michael@0: if (NS_FAILED(result)) { michael@0: NS_WARNING("unable to start the timer"); michael@0: } else { michael@0: uint32_t delay = 0; michael@0: if (aUseDelay) { michael@0: if (mFiringCount < 10) { michael@0: // Longer delay for the few first pages. michael@0: delay = mDelay + ((10 - mFiringCount) * 100); michael@0: } else { michael@0: delay = mDelay; michael@0: } michael@0: } michael@0: mTimer->InitWithCallback(this, delay, nsITimer::TYPE_ONE_SHOT); michael@0: } michael@0: return result; michael@0: } michael@0: michael@0: nsresult michael@0: nsPagePrintTimer::StartWatchDogTimer() michael@0: { michael@0: nsresult result; michael@0: if (mWatchDogTimer) { michael@0: mWatchDogTimer->Cancel(); michael@0: } michael@0: mWatchDogTimer = do_CreateInstance("@mozilla.org/timer;1", &result); michael@0: if (NS_FAILED(result)) { michael@0: NS_WARNING("unable to start the timer"); michael@0: } else { michael@0: // Instead of just doing one timer for a long period do multiple so we michael@0: // can check if the user cancelled the printing. michael@0: mWatchDogTimer->InitWithCallback(this, WATCH_DOG_INTERVAL, michael@0: nsITimer::TYPE_ONE_SHOT); michael@0: } michael@0: return result; michael@0: } michael@0: michael@0: void michael@0: nsPagePrintTimer::StopWatchDogTimer() michael@0: { michael@0: if (mWatchDogTimer) { michael@0: mWatchDogTimer->Cancel(); michael@0: mWatchDogTimer = nullptr; michael@0: } michael@0: } michael@0: michael@0: //nsRunnable michael@0: NS_IMETHODIMP michael@0: nsPagePrintTimer::Run() michael@0: { michael@0: bool initNewTimer = true; michael@0: // Check to see if we are done michael@0: // inRange will be true if a page is actually printed michael@0: bool inRange; michael@0: bool donePrinting; michael@0: michael@0: // donePrinting will be true if it completed successfully or michael@0: // if the printing was cancelled michael@0: donePrinting = mPrintEngine->PrintPage(mPrintObj, inRange); michael@0: if (donePrinting) { michael@0: // now clean up print or print the next webshell michael@0: if (mPrintEngine->DonePrintingPages(mPrintObj, NS_OK)) { michael@0: initNewTimer = false; michael@0: mDone = true; michael@0: } michael@0: } michael@0: michael@0: // Note that the Stop() destroys this after the print job finishes michael@0: // (The PrintEngine stops holding a reference when DonePrintingPages michael@0: // returns true.) michael@0: Stop(); michael@0: if (initNewTimer) { michael@0: ++mFiringCount; michael@0: nsresult result = StartTimer(inRange); michael@0: if (NS_FAILED(result)) { michael@0: mDone = true; // had a failure.. we are finished.. michael@0: mPrintEngine->SetIsPrinting(false); michael@0: } michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: // nsITimerCallback michael@0: NS_IMETHODIMP michael@0: nsPagePrintTimer::Notify(nsITimer *timer) michael@0: { michael@0: // When finished there may be still pending notifications, which we can just michael@0: // ignore. michael@0: if (mDone) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: // There are three things that call Notify with different values for timer: michael@0: // 1) the delay between pages (timer == mTimer) michael@0: // 2) canvasPrintState done (timer == null) michael@0: // 3) the watch dog timer (timer == mWatchDogTimer) michael@0: if (timer && timer == mWatchDogTimer) { michael@0: mWatchDogCount++; michael@0: if (mWatchDogCount > WATCH_DOG_MAX_COUNT) { michael@0: Fail(); michael@0: return NS_OK; michael@0: } michael@0: } else if(!timer) { michael@0: // Reset the counter since a mozPrintCallback has finished. michael@0: mWatchDogCount = 0; michael@0: } michael@0: michael@0: if (mDocViewerPrint) { michael@0: bool donePrePrint = mPrintEngine->PrePrintPage(); michael@0: michael@0: if (donePrePrint) { michael@0: StopWatchDogTimer(); michael@0: NS_DispatchToMainThread(this); michael@0: } else { michael@0: // Start the watch dog if we're waiting for preprint to ensure that if any michael@0: // mozPrintCallbacks take to long we error out. michael@0: StartWatchDogTimer(); michael@0: } michael@0: michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsPagePrintTimer::Start(nsPrintObject* aPO) michael@0: { michael@0: mPrintObj = aPO; michael@0: mWatchDogCount = 0; michael@0: mDone = false; michael@0: return StartTimer(false); michael@0: } michael@0: michael@0: michael@0: void michael@0: nsPagePrintTimer::Stop() michael@0: { michael@0: if (mTimer) { michael@0: mTimer->Cancel(); michael@0: mTimer = nullptr; michael@0: } michael@0: StopWatchDogTimer(); michael@0: } michael@0: michael@0: void michael@0: nsPagePrintTimer::Fail() michael@0: { michael@0: mDone = true; michael@0: Stop(); michael@0: if (mPrintEngine) { michael@0: mPrintEngine->CleanupOnFailure(NS_OK, false); michael@0: } michael@0: }