Bug 789507 - Add watchdog for mozPrintCallbacks. r=smaug
authorBrendan Dahl <bdahl@mozilla.com>
Tue, 02 Oct 2012 10:42:21 -0700
changeset 112586 fe034183d766cabe18311f5dc1f8a290f67c823a
parent 112585 0ae09da96f63b1d283822be4de3f5a90e60e9ae7
child 112587 24b61485c945c35effea9278e54f8685ae9880f0
push idunknown
push userunknown
push dateunknown
reviewerssmaug
bugs789507
milestone18.0a1
Bug 789507 - Add watchdog for mozPrintCallbacks. r=smaug
layout/generic/nsSimplePageSequence.cpp
layout/printing/nsPagePrintTimer.cpp
layout/printing/nsPagePrintTimer.h
--- a/layout/generic/nsSimplePageSequence.cpp
+++ b/layout/generic/nsSimplePageSequence.cpp
@@ -107,16 +107,17 @@ nsSimplePageSequenceFrame::nsSimplePageS
   // Doing this here so we only have to go get these formats once
   SetPageNumberFormat("pagenumber",  "%1$d", true);
   SetPageNumberFormat("pageofpages", "%1$d of %2$d", false);
 }
 
 nsSimplePageSequenceFrame::~nsSimplePageSequenceFrame()
 {
   delete mPageData;
+  ResetPrintCanvasList();
 }
 
 NS_QUERYFRAME_HEAD(nsSimplePageSequenceFrame)
   NS_QUERYFRAME_ENTRY(nsIPageSequenceFrame)
 NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
 
 //----------------------------------------------------------------------
 
--- a/layout/printing/nsPagePrintTimer.cpp
+++ b/layout/printing/nsPagePrintTimer.cpp
@@ -39,16 +39,44 @@ nsPagePrintTimer::StartTimer(bool aUseDe
         delay = mDelay;
       }
     }
     mTimer->InitWithCallback(this, delay, nsITimer::TYPE_ONE_SHOT);
   }
   return result;
 }
 
+nsresult
+nsPagePrintTimer::StartWatchDogTimer()
+{
+  nsresult result;
+  if (mWatchDogTimer) {
+    mWatchDogTimer->Cancel();
+  }
+  mWatchDogTimer = do_CreateInstance("@mozilla.org/timer;1", &result);
+  if (NS_FAILED(result)) {
+    NS_WARNING("unable to start the timer");
+  } else {
+    // Instead of just doing one timer for a long period do multiple so we
+    // can check if the user cancelled the printing.
+    mWatchDogTimer->InitWithCallback(this, WATCH_DOG_INTERVAL,
+                                     nsITimer::TYPE_ONE_SHOT);
+  }
+  return result;
+}
+
+void
+nsPagePrintTimer::StopWatchDogTimer()
+{
+  if (mWatchDogTimer) {
+    mWatchDogTimer->Cancel();
+    mWatchDogTimer = nullptr;
+  }
+}
+
 //nsRunnable
 NS_IMETHODIMP
 nsPagePrintTimer::Run() 
 {
   bool initNewTimer = true;
   // Check to see if we are done
   // inRange will be true if a page is actually printed
   bool inRange;
@@ -56,57 +84,97 @@ nsPagePrintTimer::Run()
 
   // donePrinting will be true if it completed successfully or
   // if the printing was cancelled
   donePrinting = mPrintEngine->PrintPage(mPrintObj, inRange);
   if (donePrinting) {
     // now clean up print or print the next webshell
     if (mPrintEngine->DonePrintingPages(mPrintObj, NS_OK)) {
       initNewTimer = false;
+      mDone = true;
     }
   }
 
   // Note that the Stop() destroys this after the print job finishes
   // (The PrintEngine stops holding a reference when DonePrintingPages
   // returns true.)
   Stop(); 
   if (initNewTimer) {
     ++mFiringCount;
     nsresult result = StartTimer(inRange);
     if (NS_FAILED(result)) {
-      donePrinting = true;     // had a failure.. we are finished..
+      mDone = true;     // had a failure.. we are finished..
       mPrintEngine->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 three things that call Notify with different values for timer:
+  // 1) the delay between pages (timer == mTimer)
+  // 2) canvasPrintState done (timer == null)
+  // 3) the watch dog timer (timer == mWatchDogTimer)
+  if (timer && timer == mWatchDogTimer) {
+    mWatchDogCount++;
+    if (mWatchDogCount > WATCH_DOG_MAX_COUNT) {
+      Fail();
+      return NS_OK;
+    }
+  } else if(!timer) {
+    // Reset the counter since a mozPrintCallback has finished.
+    mWatchDogCount = 0;
+  }
+
   if (mDocViewerPrint) {
     bool donePrePrint = mPrintEngine->PrePrintPage();
 
     if (donePrePrint) {
+      StopWatchDogTimer();
       NS_DispatchToMainThread(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;
 }
 
 nsresult 
 nsPagePrintTimer::Start(nsPrintObject* aPO)
 {
   mPrintObj = aPO;
+  mWatchDogCount = 0;
+  mDone = false;
   return StartTimer(false);
 }
 
 
 void  
 nsPagePrintTimer::Stop()
 {
   if (mTimer) {
     mTimer->Cancel();
     mTimer = nullptr;
   }
+  StopWatchDogTimer();
 }
+
+void
+nsPagePrintTimer::Fail()
+{
+  mDone = true;
+  Stop();
+  if (mPrintEngine) {
+    mPrintEngine->CleanupOnFailure(NS_OK, false);
+  }
+}
--- a/layout/printing/nsPagePrintTimer.h
+++ b/layout/printing/nsPagePrintTimer.h
@@ -28,37 +28,48 @@ public:
   nsPagePrintTimer(nsPrintEngine* aPrintEngine,
                    nsIDocumentViewerPrint* aDocViewerPrint,
                    uint32_t aDelay)
     : mPrintEngine(aPrintEngine)
     , mDocViewerPrint(aDocViewerPrint)
     , mDelay(aDelay)
     , mFiringCount(0)
     , mPrintObj(nullptr)
+    , mWatchDogCount(0)
+    , mDone(false)
   {
     mDocViewerPrint->IncrementDestroyRefCount();
   }
   ~nsPagePrintTimer();
 
   NS_DECL_NSITIMERCALLBACK
 
   nsresult Start(nsPrintObject* aPO);
 
   NS_IMETHOD Run();
 
   void Stop();
 
 private:
   nsresult StartTimer(bool aUseDelay);
+  nsresult StartWatchDogTimer();
+  void     StopWatchDogTimer();
+  void     Fail();
 
   nsPrintEngine*             mPrintEngine;
   nsCOMPtr<nsIDocumentViewerPrint> mDocViewerPrint;
   nsCOMPtr<nsITimer>         mTimer;
+  nsCOMPtr<nsITimer>         mWatchDogTimer;
   uint32_t                   mDelay;
   uint32_t                   mFiringCount;
   nsPrintObject *            mPrintObj;
+  uint32_t                   mWatchDogCount;
+  bool                       mDone;
+
+  static const uint32_t WATCH_DOG_INTERVAL  = 1000;
+  static const uint32_t WATCH_DOG_MAX_COUNT = 10;
 };
 
 
 nsresult
 NS_NewPagePrintTimer(nsPagePrintTimer **aResult);
 
 #endif /* nsPagePrintTimer_h___ */