tor-browser

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

OverscrollHandoffState.cpp (7225B)


      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 "OverscrollHandoffState.h"
      8 
      9 #include <algorithm>  // for std::stable_sort
     10 #include "mozilla/Assertions.h"
     11 #include "AsyncPanZoomController.h"
     12 
     13 namespace mozilla {
     14 namespace layers {
     15 
     16 OverscrollHandoffChain::~OverscrollHandoffChain() = default;
     17 
     18 void OverscrollHandoffChain::Add(AsyncPanZoomController* aApzc) {
     19  mChain.push_back(aApzc);
     20 }
     21 
     22 const RefPtr<AsyncPanZoomController>& OverscrollHandoffChain::GetApzcAtIndex(
     23    uint32_t aIndex) const {
     24  MOZ_ASSERT(aIndex < Length());
     25  return mChain[aIndex];
     26 }
     27 
     28 uint32_t OverscrollHandoffChain::IndexOf(
     29    const AsyncPanZoomController* aApzc) const {
     30  uint32_t i;
     31  for (i = 0; i < Length(); ++i) {
     32    if (mChain[i] == aApzc) {
     33      break;
     34    }
     35  }
     36  return i;
     37 }
     38 
     39 void OverscrollHandoffChain::ForEachApzc(APZCMethod aMethod) const {
     40  for (uint32_t i = 0; i < Length(); ++i) {
     41    (mChain[i]->*aMethod)();
     42  }
     43 }
     44 
     45 bool OverscrollHandoffChain::AnyApzc(APZCPredicate aPredicate) const {
     46  MOZ_ASSERT(Length() > 0);
     47  for (uint32_t i = 0; i < Length(); ++i) {
     48    if ((mChain[i]->*aPredicate)()) {
     49      return true;
     50    }
     51  }
     52  return false;
     53 }
     54 
     55 void OverscrollHandoffChain::FlushRepaints() const {
     56  ForEachApzc(&AsyncPanZoomController::FlushRepaintForOverscrollHandoff);
     57 }
     58 
     59 void OverscrollHandoffChain::CancelAnimations(
     60    CancelAnimationFlags aFlags) const {
     61  MOZ_ASSERT(Length() > 0);
     62  for (uint32_t i = 0; i < Length(); ++i) {
     63    mChain[i]->CancelAnimation(aFlags);
     64  }
     65 }
     66 
     67 void OverscrollHandoffChain::ClearOverscroll() const {
     68  ForEachApzc(&AsyncPanZoomController::ClearOverscroll);
     69 }
     70 
     71 void OverscrollHandoffChain::SnapBackOverscrolledApzc(
     72    const AsyncPanZoomController* aStart) const {
     73  uint32_t i = IndexOf(aStart);
     74  for (; i < Length(); ++i) {
     75    AsyncPanZoomController* apzc = mChain[i];
     76    if (!apzc->IsDestroyed()) {
     77      apzc->SnapBackIfOverscrolled();
     78    }
     79  }
     80 }
     81 
     82 void OverscrollHandoffChain::SnapBackOverscrolledApzcForMomentum(
     83    const AsyncPanZoomController* aStart,
     84    const ParentLayerPoint& aVelocity) const {
     85  uint32_t i = IndexOf(aStart);
     86  for (; i < Length(); ++i) {
     87    AsyncPanZoomController* apzc = mChain[i];
     88    if (!apzc->IsDestroyed()) {
     89      apzc->SnapBackIfOverscrolledForMomentum(aVelocity);
     90    }
     91  }
     92 }
     93 
     94 bool OverscrollHandoffChain::CanBePanned(
     95    const AsyncPanZoomController* aApzc) const {
     96  // Find |aApzc| in the handoff chain.
     97  uint32_t i = IndexOf(aApzc);
     98 
     99  // See whether any APZC in the handoff chain starting from |aApzc|
    100  // has room to be panned.
    101  for (uint32_t j = i; j < Length(); ++j) {
    102    if (mChain[j]->IsPannable()) {
    103      return true;
    104    }
    105  }
    106 
    107  return false;
    108 }
    109 
    110 bool OverscrollHandoffChain::CanScrollInDirection(
    111    const AsyncPanZoomController* aApzc, ScrollDirection aDirection) const {
    112  // Find |aApzc| in the handoff chain.
    113  uint32_t i = IndexOf(aApzc);
    114 
    115  // See whether any APZC in the handoff chain starting from |aApzc|
    116  // has room to scroll in the given direction.
    117  for (uint32_t j = i; j < Length(); ++j) {
    118    if (mChain[j]->CanScroll(aDirection)) {
    119      return true;
    120    }
    121  }
    122 
    123  return false;
    124 }
    125 
    126 bool OverscrollHandoffChain::HasOverscrolledApzc() const {
    127  return AnyApzc(&AsyncPanZoomController::IsOverscrolled);
    128 }
    129 
    130 bool OverscrollHandoffChain::HasFastFlungApzc() const {
    131  return AnyApzc(&AsyncPanZoomController::IsFlingingFast);
    132 }
    133 
    134 bool OverscrollHandoffChain::HasAutoscrollApzc() const {
    135  return AnyApzc(&AsyncPanZoomController::IsAutoscroll);
    136 }
    137 
    138 RefPtr<AsyncPanZoomController> OverscrollHandoffChain::FindFirstScrollable(
    139    const InputData& aInput, ScrollDirections* aOutAllowedScrollDirections,
    140    IncludeOverscroll aIncludeOverscroll) const {
    141  // Start by allowing scrolling in both directions. As we do handoff
    142  // overscroll-behavior may restrict one or both of the directions.
    143  *aOutAllowedScrollDirections += ScrollDirection::eVertical;
    144  *aOutAllowedScrollDirections += ScrollDirection::eHorizontal;
    145 
    146  for (size_t i = 0; i < Length(); i++) {
    147    if (mChain[i]->CanScroll(aInput)) {
    148      return mChain[i];
    149    }
    150 
    151    // If there is any directions we allow overscroll effects on the root
    152    // content APZC (i.e. the overscroll-behavior of the root one is not
    153    // `none`), we consider the APZC can be scrollable in terms of pan gestures
    154    // because it causes overscrolling even if it's not able to scroll to the
    155    // direction.
    156    if (StaticPrefs::apz_overscroll_enabled() && bool(aIncludeOverscroll) &&
    157        // FIXME: Bug 1707491: Drop this pan gesture input check.
    158        aInput.mInputType == PANGESTURE_INPUT && mChain[i]->IsRootContent()) {
    159      // Check whether the root content APZC is also overscrollable governed by
    160      // overscroll-behavior in the same directions where we allow scrolling
    161      // handoff and where we are going to scroll, if it matches we do handoff
    162      // to the root content APZC.
    163      // In other words, if the root content is not scrollable, we don't
    164      // handoff.
    165      ScrollDirections allowedOverscrollDirections =
    166          mChain[i]->GetOverscrollableDirections();
    167      ParentLayerPoint delta = mChain[i]->GetDeltaForEvent(aInput);
    168      if (mChain[i]->IsZero(delta.x)) {
    169        allowedOverscrollDirections -= ScrollDirection::eHorizontal;
    170      }
    171      if (mChain[i]->IsZero(delta.y)) {
    172        allowedOverscrollDirections -= ScrollDirection::eVertical;
    173      }
    174 
    175      allowedOverscrollDirections &= *aOutAllowedScrollDirections;
    176      if (!allowedOverscrollDirections.isEmpty()) {
    177        *aOutAllowedScrollDirections = allowedOverscrollDirections;
    178        return mChain[i];
    179      }
    180    }
    181 
    182    *aOutAllowedScrollDirections &= mChain[i]->GetAllowedHandoffDirections();
    183    if (aOutAllowedScrollDirections->isEmpty()) {
    184      return nullptr;
    185    }
    186  }
    187  return nullptr;
    188 }
    189 
    190 std::tuple<bool, const AsyncPanZoomController*>
    191 OverscrollHandoffChain::ScrollingDownWillMoveDynamicToolbar(
    192    const AsyncPanZoomController* aApzc) const {
    193  MOZ_ASSERT(aApzc && !aApzc->IsRootContent(),
    194             "Should be used for non-root APZC");
    195 
    196  for (uint32_t i = IndexOf(aApzc); i < Length(); i++) {
    197    if (mChain[i]->IsRootContent()) {
    198      bool scrollable = mChain[i]->CanVerticalScrollWithDynamicToolbar();
    199      return {scrollable, scrollable ? mChain[i].get() : nullptr};
    200    }
    201 
    202    if (mChain[i]->CanScrollDownwards()) {
    203      return {false, nullptr};
    204    }
    205  }
    206 
    207  return {false, nullptr};
    208 }
    209 
    210 bool OverscrollHandoffChain::ScrollingUpWillTriggerPullToRefresh(
    211    const AsyncPanZoomController* aApzc) const {
    212  MOZ_ASSERT(aApzc && !aApzc->IsRootContent(),
    213             "Should be used for non-root APZC");
    214 
    215  for (uint32_t i = IndexOf(aApzc); i < Length(); i++) {
    216    if (mChain[i]->IsRootContent()) {
    217      return mChain[i]->CanOverscrollUpwards(HandoffConsumer::PullToRefresh);
    218    }
    219 
    220    if (!mChain[i]->CanOverscrollUpwards(HandoffConsumer::PullToRefresh)) {
    221      return false;
    222    }
    223  }
    224  return false;
    225 }
    226 
    227 }  // namespace layers
    228 }  // namespace mozilla