Bug 789507 - Add watchdog for mozPrintCallbacks. r=smaug
authorBrendan Dahl <bdahl@mozilla.com>
Tue, 02 Oct 2012 10:42:21 -0700
changeset 108990 fe034183d766cabe18311f5dc1f8a290f67c823a
parent 108989 0ae09da96f63b1d283822be4de3f5a90e60e9ae7
child 108991 24b61485c945c35effea9278e54f8685ae9880f0
push id23602
push useremorley@mozilla.com
push dateWed, 03 Oct 2012 12:57:12 +0000
treeherdermozilla-central@5ac283a12f02 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs789507
milestone18.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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___ */