tor-browser

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

APZTaskRunnable.cpp (6177B)


      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 "APZTaskRunnable.h"
      8 
      9 #include "mozilla/PresShell.h"
     10 #include "nsRefreshDriver.h"
     11 
     12 namespace mozilla::layers {
     13 
     14 NS_IMETHODIMP
     15 APZTaskRunnable::Run() {
     16  if (!mController) {
     17    mRegisteredPresShellId = 0;
     18    return NS_OK;
     19  }
     20 
     21  // Move these variables first since below RequestContentPaint and
     22  // NotifyFlushComplete might spin event loop so that any new incoming requests
     23  // will be properly queued and run in the next refresh driver's tick.
     24  const bool needsFlushCompleteNotification = mNeedsFlushCompleteNotification;
     25  auto requests = std::move(mPendingRequestQueue);
     26  mPendingRepaintRequestMap.clear();
     27  mNeedsFlushCompleteNotification = false;
     28  mRegisteredPresShellId = 0;
     29  RefPtr<GeckoContentController> controller = mController;
     30 
     31  // We need to process pending RepaintRequests first.
     32  while (!requests.empty()) {
     33    struct RequestProcessor {
     34      GeckoContentController* mController;
     35      void operator()(const RepaintRequest& aRequest) {
     36        mController->RequestContentRepaint(aRequest);
     37      }
     38      void operator()(const APZStateChangeRequest& aRequest) {
     39        mController->NotifyAPZStateChange(aRequest.mGuid, aRequest.mChange,
     40                                          aRequest.mArg,
     41                                          aRequest.mInputBlockId);
     42      }
     43    };
     44    requests.front().match(RequestProcessor{controller.get()});
     45    requests.pop_front();
     46  }
     47 
     48  if (needsFlushCompleteNotification) {
     49    // Then notify "apz-repaints-flushed" so that we can ensure that all pending
     50    // scroll position updates have finished when the "apz-repaints-flushed"
     51    // arrives.
     52    controller->NotifyFlushComplete();
     53  }
     54 
     55  return NS_OK;
     56 }
     57 
     58 void APZTaskRunnable::QueueRequest(const RepaintRequest& aRequest) {
     59  // If we are in test-controlled refreshes mode, process this |aRequest|
     60  // synchronously.
     61  if (IsTestControllingRefreshesEnabled()) {
     62    // Flush all pending requests and notification just in case the refresh
     63    // driver mode was changed before flushing them.
     64    RefPtr<GeckoContentController> controller = mController;
     65    Run();
     66    controller->RequestContentRepaint(aRequest);
     67    return;
     68  }
     69  EnsureRegisterAsEarlyRunner();
     70 
     71  RepaintRequestKey key{aRequest.GetScrollId(), aRequest.GetScrollUpdateType()};
     72 
     73  auto lastDiscardableRequest = mPendingRepaintRequestMap.find(key);
     74  // If there's an existing request with the same key, we can discard it and we
     75  // push the incoming one into the queue's tail so that we can ensure the order
     76  // of processing requests.
     77  if (lastDiscardableRequest != mPendingRepaintRequestMap.end()) {
     78    for (auto it = mPendingRequestQueue.begin();
     79         it != mPendingRequestQueue.end(); it++) {
     80      if (it->is<RepaintRequest>()) {
     81        const RepaintRequest& request = it->as<RepaintRequest>();
     82        if (RepaintRequestKey{request.GetScrollId(),
     83                              request.GetScrollUpdateType()} == key) {
     84          mPendingRequestQueue.erase(it);
     85          break;
     86        }
     87      }
     88    }
     89  }
     90  mPendingRepaintRequestMap.insert(key);
     91  mPendingRequestQueue.push_back(AsVariant(aRequest));
     92 }
     93 
     94 void APZTaskRunnable::QueueAPZStateChange(const ScrollableLayerGuid& aGuid,
     95                                          const APZStateChange& aChange,
     96                                          const int& aArg,
     97                                          Maybe<uint64_t> aInputBlockId) {
     98  // If we are in test-controlled refreshes mode, process this |aRequest|
     99  // synchronously.
    100  if (IsTestControllingRefreshesEnabled()) {
    101    // Flush all pending requests and notification just in case the refresh
    102    // driver mode was changed before flushing them.
    103    RefPtr<GeckoContentController> controller = mController;
    104    Run();
    105    controller->NotifyAPZStateChange(aGuid, aChange, aArg, aInputBlockId);
    106    return;
    107  }
    108  EnsureRegisterAsEarlyRunner();
    109 
    110  mPendingRequestQueue.push_back(
    111      AsVariant(APZStateChangeRequest{aGuid, aChange, aArg, aInputBlockId}));
    112 }
    113 
    114 void APZTaskRunnable::QueueFlushCompleteNotification() {
    115  // If we are in test-controlled refreshes mode, notify apz-repaints-flushed
    116  // synchronously.
    117  if (IsTestControllingRefreshesEnabled()) {
    118    // Flush all pending requests and notification just in case the refresh
    119    // driver mode was changed before flushing them.
    120    RefPtr<GeckoContentController> controller = mController;
    121    Run();
    122    controller->NotifyFlushComplete();
    123    return;
    124  }
    125 
    126  EnsureRegisterAsEarlyRunner();
    127 
    128  mNeedsFlushCompleteNotification = true;
    129 }
    130 
    131 bool APZTaskRunnable::IsRegisteredWithCurrentPresShell() const {
    132  MOZ_ASSERT(mController);
    133 
    134  uint32_t current = 0;
    135  if (PresShell* presShell = mController->GetTopLevelPresShell()) {
    136    current = presShell->GetPresShellId();
    137  }
    138  return mRegisteredPresShellId == current;
    139 }
    140 
    141 void APZTaskRunnable::EnsureRegisterAsEarlyRunner() {
    142  if (IsRegisteredWithCurrentPresShell()) {
    143    return;
    144  }
    145 
    146  // If the registered presshell id has been changed, we need to discard pending
    147  // requests and notification since all of them are for documents which
    148  // have been torn down.
    149  if (mRegisteredPresShellId) {
    150    mPendingRepaintRequestMap.clear();
    151    mPendingRequestQueue.clear();
    152    mNeedsFlushCompleteNotification = false;
    153  }
    154 
    155  if (PresShell* presShell = mController->GetTopLevelPresShell()) {
    156    if (nsRefreshDriver* driver = presShell->GetRefreshDriver()) {
    157      driver->AddEarlyRunner(this);
    158      mRegisteredPresShellId = presShell->GetPresShellId();
    159    }
    160  }
    161 }
    162 
    163 bool APZTaskRunnable::IsTestControllingRefreshesEnabled() const {
    164  if (!mController) {
    165    return false;
    166  }
    167 
    168  if (PresShell* presShell = mController->GetTopLevelPresShell()) {
    169    if (nsRefreshDriver* driver = presShell->GetRefreshDriver()) {
    170      return driver->IsTestControllingRefreshesEnabled();
    171    }
    172  }
    173  return false;
    174 }
    175 
    176 }  // namespace mozilla::layers