tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }