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