From ee1d452245090a4dd0eea02d32eccbcf1e4eef6e Mon Sep 17 00:00:00 2001 From: Hiroyuki Ikezoe Date: Mon, 26 Apr 2021 07:24:56 +0000 Subject: [PATCH] Bug 1705280 - Allow overscroll handoff to the root content APZC on pan gestures even if the root APZC is not scrollable to the given input directions. r=botond To be precise the root APZC should actually be scrollable in the opposed directions of the given input, it's checked in AsyncPanZoomController::GetOverscrollableDirections. Differential Revision: https://phabricator.services.mozilla.com/D113061 --- gfx/layers/apz/src/AsyncPanZoomController.h | 6 +-- gfx/layers/apz/src/OverscrollHandoffState.cpp | 14 ++++++ gfx/layers/apz/test/gtest/TestOverscroll.cpp | 44 ++++++++++++++++++- 3 files changed, 59 insertions(+), 5 deletions(-) diff --git a/gfx/layers/apz/src/AsyncPanZoomController.h b/gfx/layers/apz/src/AsyncPanZoomController.h index f3b9d1375e88..c549ae9f0647 100644 --- a/gfx/layers/apz/src/AsyncPanZoomController.h +++ b/gfx/layers/apz/src/AsyncPanZoomController.h @@ -514,6 +514,9 @@ class AsyncPanZoomController { // overscroll-behavior). ScrollDirections GetAllowedHandoffDirections() const; + // Return the directions in which this APZC allows overscrolling. + ScrollDirections GetOverscrollableDirections() const; + // Return whether or not a scroll delta will be able to scroll in either // direction. bool CanScroll(const ParentLayerPoint& aDelta) const; @@ -1471,9 +1474,6 @@ class AsyncPanZoomController { void StartOverscrollAnimation(const ParentLayerPoint& aVelocity, SideBits aOverscrollSideBits); - // Return the directions in which this APZC allows overscrolling. - ScrollDirections GetOverscrollableDirections() const; - // Start a smooth-scrolling animation to the given destination, with physics // based on the prefs for the indicated origin. void SmoothScrollTo(const CSSPoint& aDestination, diff --git a/gfx/layers/apz/src/OverscrollHandoffState.cpp b/gfx/layers/apz/src/OverscrollHandoffState.cpp index e6765e2cddb9..435311498752 100644 --- a/gfx/layers/apz/src/OverscrollHandoffState.cpp +++ b/gfx/layers/apz/src/OverscrollHandoffState.cpp @@ -152,6 +152,20 @@ RefPtr OverscrollHandoffChain::FindFirstScrollable( 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() && + // FIXME: Bug 1707491: Drop this pan gesture input check. + aInput.mInputType == PANGESTURE_INPUT && mChain[i]->IsRootContent()) { + *aOutAllowedScrollDirections &= mChain[i]->GetOverscrollableDirections(); + if (!aOutAllowedScrollDirections->isEmpty()) { + return mChain[i]; + } + } + *aOutAllowedScrollDirections &= mChain[i]->GetAllowedHandoffDirections(); if (aOutAllowedScrollDirections->isEmpty()) { return nullptr; diff --git a/gfx/layers/apz/test/gtest/TestOverscroll.cpp b/gfx/layers/apz/test/gtest/TestOverscroll.cpp index bf81c9b409f6..549a2eb220b9 100644 --- a/gfx/layers/apz/test/gtest/TestOverscroll.cpp +++ b/gfx/layers/apz/test/gtest/TestOverscroll.cpp @@ -5,6 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "APZCBasicTester.h" +#include "APZCTreeManagerTester.h" #include "APZTestCommon.h" #include "mozilla/layers/WebRenderScrollDataWrapper.h" @@ -87,8 +88,7 @@ class APZCOverscrollTester : public APZCBasicTester { rootLayerScrollData.AppendScrollMetadata(scrollData, metadata); scrollData.AddLayerData(rootLayerScrollData); - registration = - MakeUnique(guid.mLayersId, mcc); + registration = MakeUnique(guid.mLayersId, mcc); tm->UpdateHitTestingTree(WebRenderScrollDataWrapper(*updater, &scrollData), false, guid.mLayersId, 0); return guid; @@ -1318,3 +1318,43 @@ TEST_F(APZCOverscrollTester, OverscrollByPanGesturesInterruptedByReflowZoom) { EXPECT_TRUE(!apzc->IsOverscrolled()); } #endif + +class APZCOverscrollTesterForLayersOnly : public APZCTreeManagerTester { + public: + APZCOverscrollTesterForLayersOnly() { mLayersOnly = true; } + + UniquePtr registration; + TestAsyncPanZoomController* rootApzc; +}; + +TEST_F(APZCOverscrollTesterForLayersOnly, OverscrollHandoff) { + SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); + + const char* layerTreeSyntax = "c(c)"; + nsIntRegion layerVisibleRegion[] = {nsIntRegion(IntRect(0, 0, 100, 100)), + nsIntRegion(IntRect(0, 0, 100, 50))}; + root = + CreateLayerTree(layerTreeSyntax, layerVisibleRegion, nullptr, lm, layers); + SetScrollableFrameMetrics(root, ScrollableLayerGuid::START_SCROLL_ID, + CSSRect(0, 0, 200, 200)); + SetScrollableFrameMetrics(layers[1], ScrollableLayerGuid::START_SCROLL_ID + 1, + // same size as the visible region so that + // the container is not scrollable in any directions + // actually. This is simulating overflow: hidden + // iframe document in Fission, though we don't set + // a different layers id. + CSSRect(0, 0, 100, 50)); + + SetScrollHandoff(layers[1], root); + + registration = + MakeUnique(LayersId{0}, root, mcc); + UpdateHitTestingTree(); + rootApzc = ApzcOf(root); + rootApzc->GetFrameMetrics().SetIsRootContent(true); + + // A pan gesture on the child scroller (which is not scrollable though). + PanGesture(PanGestureInput::PANGESTURE_START, manager, ScreenIntPoint(50, 20), + ScreenPoint(0, -2), mcc->Time()); + EXPECT_TRUE(rootApzc->IsOverscrolled()); +}