summaryrefslogtreecommitdiffstats
path: root/gfx/layers/apz/src/OverscrollHandoffState.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--gfx/layers/apz/src/OverscrollHandoffState.cpp228
1 files changed, 228 insertions, 0 deletions
diff --git a/gfx/layers/apz/src/OverscrollHandoffState.cpp b/gfx/layers/apz/src/OverscrollHandoffState.cpp
new file mode 100644
index 0000000000..ed38f6fa7a
--- /dev/null
+++ b/gfx/layers/apz/src/OverscrollHandoffState.cpp
@@ -0,0 +1,228 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "OverscrollHandoffState.h"
+
+#include <algorithm> // for std::stable_sort
+#include "mozilla/Assertions.h"
+#include "mozilla/FloatingPoint.h"
+#include "AsyncPanZoomController.h"
+
+namespace mozilla {
+namespace layers {
+
+OverscrollHandoffChain::~OverscrollHandoffChain() = default;
+
+void OverscrollHandoffChain::Add(AsyncPanZoomController* aApzc) {
+ mChain.push_back(aApzc);
+}
+
+struct CompareByScrollPriority {
+ bool operator()(const RefPtr<AsyncPanZoomController>& a,
+ const RefPtr<AsyncPanZoomController>& b) const {
+ return a->HasScrollgrab() && !b->HasScrollgrab();
+ }
+};
+
+void OverscrollHandoffChain::SortByScrollPriority() {
+ // The sorting being stable ensures that the relative order between
+ // non-scrollgrabbing APZCs remains child -> parent.
+ // (The relative order between scrollgrabbing APZCs will also remain
+ // child -> parent, though that's just an artefact of the implementation
+ // and users of 'scrollgrab' should not rely on this.)
+ std::stable_sort(mChain.begin(), mChain.end(), CompareByScrollPriority());
+}
+
+const RefPtr<AsyncPanZoomController>& OverscrollHandoffChain::GetApzcAtIndex(
+ uint32_t aIndex) const {
+ MOZ_ASSERT(aIndex < Length());
+ return mChain[aIndex];
+}
+
+uint32_t OverscrollHandoffChain::IndexOf(
+ const AsyncPanZoomController* aApzc) const {
+ uint32_t i;
+ for (i = 0; i < Length(); ++i) {
+ if (mChain[i] == aApzc) {
+ break;
+ }
+ }
+ return i;
+}
+
+void OverscrollHandoffChain::ForEachApzc(APZCMethod aMethod) const {
+ for (uint32_t i = 0; i < Length(); ++i) {
+ (mChain[i]->*aMethod)();
+ }
+}
+
+bool OverscrollHandoffChain::AnyApzc(APZCPredicate aPredicate) const {
+ MOZ_ASSERT(Length() > 0);
+ for (uint32_t i = 0; i < Length(); ++i) {
+ if ((mChain[i]->*aPredicate)()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void OverscrollHandoffChain::FlushRepaints() const {
+ ForEachApzc(&AsyncPanZoomController::FlushRepaintForOverscrollHandoff);
+}
+
+void OverscrollHandoffChain::CancelAnimations(
+ CancelAnimationFlags aFlags) const {
+ MOZ_ASSERT(Length() > 0);
+ for (uint32_t i = 0; i < Length(); ++i) {
+ mChain[i]->CancelAnimation(aFlags);
+ }
+}
+
+void OverscrollHandoffChain::ClearOverscroll() const {
+ ForEachApzc(&AsyncPanZoomController::ClearOverscroll);
+}
+
+void OverscrollHandoffChain::SnapBackOverscrolledApzc(
+ const AsyncPanZoomController* aStart) const {
+ uint32_t i = IndexOf(aStart);
+ for (; i < Length(); ++i) {
+ AsyncPanZoomController* apzc = mChain[i];
+ if (!apzc->IsDestroyed()) {
+ apzc->SnapBackIfOverscrolled();
+ }
+ }
+}
+
+void OverscrollHandoffChain::SnapBackOverscrolledApzcForMomentum(
+ const AsyncPanZoomController* aStart,
+ const ParentLayerPoint& aVelocity) const {
+ uint32_t i = IndexOf(aStart);
+ for (; i < Length(); ++i) {
+ AsyncPanZoomController* apzc = mChain[i];
+ if (!apzc->IsDestroyed()) {
+ apzc->SnapBackIfOverscrolledForMomentum(aVelocity);
+ }
+ }
+}
+
+bool OverscrollHandoffChain::CanBePanned(
+ const AsyncPanZoomController* aApzc) const {
+ // Find |aApzc| in the handoff chain.
+ uint32_t i = IndexOf(aApzc);
+
+ // See whether any APZC in the handoff chain starting from |aApzc|
+ // has room to be panned.
+ for (uint32_t j = i; j < Length(); ++j) {
+ if (mChain[j]->IsPannable()) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool OverscrollHandoffChain::CanScrollInDirection(
+ const AsyncPanZoomController* aApzc, ScrollDirection aDirection) const {
+ // Find |aApzc| in the handoff chain.
+ uint32_t i = IndexOf(aApzc);
+
+ // See whether any APZC in the handoff chain starting from |aApzc|
+ // has room to scroll in the given direction.
+ for (uint32_t j = i; j < Length(); ++j) {
+ if (mChain[j]->CanScroll(aDirection)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool OverscrollHandoffChain::HasOverscrolledApzc() const {
+ return AnyApzc(&AsyncPanZoomController::IsOverscrolled);
+}
+
+bool OverscrollHandoffChain::HasFastFlungApzc() const {
+ return AnyApzc(&AsyncPanZoomController::IsFlingingFast);
+}
+
+bool OverscrollHandoffChain::HasAutoscrollApzc() const {
+ return AnyApzc(&AsyncPanZoomController::IsAutoscroll);
+}
+
+RefPtr<AsyncPanZoomController> OverscrollHandoffChain::FindFirstScrollable(
+ const InputData& aInput, ScrollDirections* aOutAllowedScrollDirections,
+ IncludeOverscroll aIncludeOverscroll) const {
+ // Start by allowing scrolling in both directions. As we do handoff
+ // overscroll-behavior may restrict one or both of the directions.
+ *aOutAllowedScrollDirections += ScrollDirection::eVertical;
+ *aOutAllowedScrollDirections += ScrollDirection::eHorizontal;
+
+ for (size_t i = 0; i < Length(); i++) {
+ if (mChain[i]->CanScroll(aInput)) {
+ return mChain[i];
+ }
+
+ // If there is any directions we allow overscroll effects on the root
+ // content APZC (i.e. the overscroll-behavior of the root one is not
+ // `none`), we consider the APZC can be scrollable in terms of pan gestures
+ // because it causes overscrolling even if it's not able to scroll to the
+ // direction.
+ if (StaticPrefs::apz_overscroll_enabled() && bool(aIncludeOverscroll) &&
+ // FIXME: Bug 1707491: Drop this pan gesture input check.
+ aInput.mInputType == PANGESTURE_INPUT && mChain[i]->IsRootContent()) {
+ // Check whether the root content APZC is also overscrollable governed by
+ // overscroll-behavior in the same directions where we allow scrolling
+ // handoff and where we are going to scroll, if it matches we do handoff
+ // to the root content APZC.
+ // In other words, if the root content is not scrollable, we don't
+ // handoff.
+ ScrollDirections allowedOverscrollDirections =
+ mChain[i]->GetOverscrollableDirections();
+ ParentLayerPoint delta = mChain[i]->GetDeltaForEvent(aInput);
+ if (mChain[i]->IsZero(delta.x)) {
+ allowedOverscrollDirections -= ScrollDirection::eHorizontal;
+ }
+ if (mChain[i]->IsZero(delta.y)) {
+ allowedOverscrollDirections -= ScrollDirection::eVertical;
+ }
+
+ allowedOverscrollDirections &= *aOutAllowedScrollDirections;
+ if (!allowedOverscrollDirections.isEmpty()) {
+ *aOutAllowedScrollDirections = allowedOverscrollDirections;
+ return mChain[i];
+ }
+ }
+
+ *aOutAllowedScrollDirections &= mChain[i]->GetAllowedHandoffDirections();
+ if (aOutAllowedScrollDirections->isEmpty()) {
+ return nullptr;
+ }
+ }
+ return nullptr;
+}
+
+std::tuple<bool, const AsyncPanZoomController*>
+OverscrollHandoffChain::ScrollingDownWillMoveDynamicToolbar(
+ const AsyncPanZoomController* aApzc) const {
+ MOZ_ASSERT(aApzc && !aApzc->IsRootContent(),
+ "Should be used for non-root APZC");
+
+ for (uint32_t i = IndexOf(aApzc); i < Length(); i++) {
+ if (mChain[i]->IsRootContent()) {
+ bool scrollable = mChain[i]->CanVerticalScrollWithDynamicToolbar();
+ return {scrollable, scrollable ? mChain[i].get() : nullptr};
+ }
+
+ if (mChain[i]->CanScrollDownwards()) {
+ return {false, nullptr};
+ }
+ }
+
+ return {false, nullptr};
+}
+
+} // namespace layers
+} // namespace mozilla