nsPagePrintTimer.cpp (6786B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "nsPagePrintTimer.h" 8 9 #include "mozilla/ProfilerMarkers.h" 10 #include "mozilla/dom/Document.h" 11 #include "nsPrintJob.h" 12 #include "nsPrintObject.h" 13 14 using namespace mozilla; 15 16 NS_IMPL_ISUPPORTS_INHERITED(nsPagePrintTimer, mozilla::Runnable, 17 nsITimerCallback) 18 19 nsPagePrintTimer::nsPagePrintTimer(nsPrintJob* aPrintJob, 20 nsIDocumentViewerPrint* aDocViewerPrint, 21 mozilla::dom::Document* aDocument, 22 uint32_t aDelay) 23 : Runnable("nsPagePrintTimer"), 24 mPrintJob(aPrintJob), 25 mDocViewerPrint(aDocViewerPrint), 26 mDocument(aDocument), 27 mDelay(aDelay), 28 mFiringCount(0), 29 mPrintObj(nullptr), 30 mWatchDogCount(0), 31 mDone(false) { 32 MOZ_ASSERT(aDocViewerPrint && aDocument); 33 mDocViewerPrint->IncrementDestroyBlockedCount(); 34 } 35 36 nsPagePrintTimer::~nsPagePrintTimer() { Disconnect(); } 37 38 void nsPagePrintTimer::Disconnect() { 39 mPrintJob = nullptr; 40 mPrintObj = nullptr; 41 if (mDocViewerPrint) { 42 // This matches the IncrementDestroyBlockedCount call in the constructor. 43 mDocViewerPrint->DecrementDestroyBlockedCount(); 44 mDocViewerPrint = nullptr; 45 } 46 } 47 48 nsresult nsPagePrintTimer::StartTimer(bool aUseDelay) { 49 uint32_t delay = 0; 50 if (aUseDelay) { 51 if (mFiringCount < 10) { 52 // Longer delay for the few first pages. 53 delay = mDelay + ((10 - mFiringCount) * 100); 54 } else { 55 delay = mDelay; 56 } 57 } 58 return NS_NewTimerWithCallback(getter_AddRefs(mTimer), this, delay, 59 nsITimer::TYPE_ONE_SHOT, 60 GetMainThreadSerialEventTarget()); 61 } 62 63 nsresult nsPagePrintTimer::StartWatchDogTimer() { 64 if (mWatchDogTimer) { 65 mWatchDogTimer->Cancel(); 66 } 67 // Instead of just doing one timer for a long period do multiple so we 68 // can check if the user cancelled the printing. 69 return NS_NewTimerWithCallback(getter_AddRefs(mWatchDogTimer), this, 70 WATCH_DOG_INTERVAL, nsITimer::TYPE_ONE_SHOT, 71 GetMainThreadSerialEventTarget()); 72 } 73 74 void nsPagePrintTimer::StopWatchDogTimer() { 75 if (mWatchDogTimer) { 76 mWatchDogTimer->Cancel(); 77 mWatchDogTimer = nullptr; 78 } 79 } 80 81 // nsRunnable 82 NS_IMETHODIMP 83 nsPagePrintTimer::Run() { 84 bool initNewTimer = true; 85 bool donePrinting; 86 87 // donePrinting will be true if it completed successfully or 88 // if the printing was cancelled 89 donePrinting = !mPrintJob || mPrintJob->PrintSheet(mPrintObj); 90 if (donePrinting) { 91 if (mWaitingForRemotePrint || 92 // If we are not waiting for the remote printing, it is the time to 93 // end printing task by calling DonePrintingSheets. 94 (!mPrintJob || mPrintJob->DonePrintingSheets(mPrintObj, NS_OK))) { 95 initNewTimer = false; 96 mDone = true; 97 } 98 } 99 100 // Note that the Stop() destroys this after the print job finishes 101 // (The nsPrintJob stops holding a reference when DonePrintingSheets 102 // returns true.) 103 Stop(); 104 if (initNewTimer) { 105 ++mFiringCount; 106 nsresult result = StartTimer(/*aUseDelay*/ true); 107 if (NS_FAILED(result)) { 108 mDone = true; // had a failure.. we are finished.. 109 if (mPrintJob) { 110 mPrintJob->SetIsPrinting(false); 111 } 112 } 113 } 114 return NS_OK; 115 } 116 117 // nsITimerCallback 118 NS_IMETHODIMP 119 nsPagePrintTimer::Notify(nsITimer* timer) { 120 // When finished there may be still pending notifications, which we can just 121 // ignore. 122 if (mDone) { 123 return NS_OK; 124 } 125 126 // There are four things that call Notify with different values for timer: 127 // 1) the delay between sheets (timer == mTimer) 128 // 2) canvasPrintState done (timer == null) 129 // 3) the watch dog timer (timer == mWatchDogTimer) 130 // 4) the waiting for remote print "timer" (timer == mWaitingForRemotePrint) 131 if (!timer) { 132 // Reset the counter since a mozPrintCallback has finished. 133 mWatchDogCount = 0; 134 } else if (timer == mTimer) { 135 // Reset the watchdog timer before the start of every sheet. 136 mWatchDogCount = 0; 137 mTimer = nullptr; 138 } else if (timer == mWaitingForRemotePrint) { 139 mWaitingForRemotePrint = nullptr; 140 141 // If we are still waiting for the sheet delay timer, don't let the 142 // notification from the remote print job trigger the next sheet. 143 if (mTimer) { 144 return NS_OK; 145 } 146 } else if (timer == mWatchDogTimer) { 147 mWatchDogCount++; 148 PROFILER_MARKER_TEXT( 149 "nsPagePrintTimer::Notify", LAYOUT_Printing, {}, 150 nsPrintfCString("Watchdog Timer Count %d", mWatchDogCount)); 151 152 if (mWatchDogCount > WATCH_DOG_MAX_COUNT) { 153 Fail(); 154 return NS_OK; 155 } 156 } 157 158 bool donePrePrint = true; 159 // Don't start to pre-print if we're waiting on the parent still. 160 if (mPrintJob && !mWaitingForRemotePrint) { 161 donePrePrint = mPrintJob->PrePrintSheet(); 162 } 163 164 if (donePrePrint && !mWaitingForRemotePrint) { 165 StopWatchDogTimer(); 166 // Pass nullptr here since name already was set in constructor. 167 mDocument->Dispatch(do_AddRef(this)); 168 } else { 169 // Start the watch dog if we're waiting for preprint to ensure that if any 170 // mozPrintCallbacks take to long we error out. 171 StartWatchDogTimer(); 172 } 173 174 return NS_OK; 175 } 176 177 void nsPagePrintTimer::WaitForRemotePrint() { 178 mWaitingForRemotePrint = NS_NewTimer(); 179 if (!mWaitingForRemotePrint) { 180 NS_WARNING("Failed to wait for remote print, we might time-out."); 181 } 182 } 183 184 void nsPagePrintTimer::RemotePrintFinished() { 185 if (!mWaitingForRemotePrint) { 186 return; 187 } 188 189 // now clean up print or print the next webshell 190 if (mDone && mPrintJob) { 191 mDone = mPrintJob->DonePrintingSheets(mPrintObj, NS_OK); 192 } 193 194 mWaitingForRemotePrint->SetTarget(GetMainThreadSerialEventTarget()); 195 (void)mWaitingForRemotePrint->InitWithCallback(this, 0, 196 nsITimer::TYPE_ONE_SHOT); 197 } 198 199 nsresult nsPagePrintTimer::Start(nsPrintObject* aPO) { 200 mPrintObj = aPO; 201 mDone = false; 202 return StartTimer(false); 203 } 204 205 void nsPagePrintTimer::Stop() { 206 if (mTimer) { 207 mTimer->Cancel(); 208 mTimer = nullptr; 209 } 210 StopWatchDogTimer(); 211 } 212 213 void nsPagePrintTimer::Fail() { 214 NS_WARNING("nsPagePrintTimer::Fail called"); 215 PROFILER_MARKER_TEXT("nsPagePrintTimer", LAYOUT_Printing, {}, 216 "nsPagePrintTimer::Fail aborting print operation"_ns); 217 218 mDone = true; 219 Stop(); 220 if (mPrintJob) { 221 mPrintJob->CleanupOnFailure(NS_OK, false); 222 } 223 }