Bug 951793 - Obey overscroll-behavior for wheel and pan gesture events. r=kats

MozReview-Commit-ID: EmbsMu9Esww

--HG--
extra : rebase_source : f681f55f274757be4965e6c912e514e81e8b1c8f
This commit is contained in:
Botond Ballo 2017-11-17 18:52:58 -05:00
Родитель 15d10c1b0d
Коммит bfb1cd4ddd
8 изменённых файлов: 94 добавлений и 13 удалений

Просмотреть файл

@ -11,6 +11,7 @@
#include "LayersTypes.h"
#include "UnitTransforms.h"
#include "mozilla/gfx/Point.h"
#include "mozilla/EnumSet.h"
#include "mozilla/FloatingPoint.h"
namespace mozilla {
@ -42,6 +43,8 @@ operator|(CancelAnimationFlags a, CancelAnimationFlags b)
| static_cast<int>(b));
}
typedef EnumSet<ScrollDirection> ScrollDirections;
enum class ScrollSource {
// scrollTo() or something similar.
DOM,

Просмотреть файл

@ -1914,9 +1914,8 @@ AsyncPanZoomController::GetKeyboardDestination(const KeyboardScrollAction& aActi
return scrollDestination;
}
// Return whether or not the underlying layer can be scrolled on either axis.
bool
AsyncPanZoomController::CanScroll(const InputData& aEvent) const
ParentLayerPoint
AsyncPanZoomController::GetDeltaForEvent(const InputData& aEvent) const
{
ParentLayerPoint delta;
if (aEvent.mInputType == SCROLLWHEEL_INPUT) {
@ -1925,6 +1924,14 @@ AsyncPanZoomController::CanScroll(const InputData& aEvent) const
const PanGestureInput& panInput = aEvent.AsPanGestureInput();
delta = ToParentLayerCoordinates(panInput.UserMultipliedPanDisplacement(), panInput.mPanStartPoint);
}
return delta;
}
// Return whether or not the underlying layer can be scrolled on either axis.
bool
AsyncPanZoomController::CanScroll(const InputData& aEvent) const
{
ParentLayerPoint delta = GetDeltaForEvent(aEvent);
if (!delta.x && !delta.y) {
return false;
}
@ -1932,6 +1939,20 @@ AsyncPanZoomController::CanScroll(const InputData& aEvent) const
return CanScrollWithWheel(delta);
}
ScrollDirections
AsyncPanZoomController::GetAllowedHandoffDirections() const
{
ScrollDirections result;
RecursiveMutexAutoLock lock(mRecursiveMutex);
if (mX.OverscrollBehaviorAllowsHandoff()) {
result += ScrollDirection::eHorizontal;
}
if (mY.OverscrollBehaviorAllowsHandoff()) {
result += ScrollDirection::eVertical;
}
return result;
}
bool
AsyncPanZoomController::CanScrollWithWheel(const ParentLayerPoint& aDelta) const
{
@ -1999,6 +2020,19 @@ ScrollInputMethodForWheelDeltaType(ScrollWheelInput::ScrollDeltaType aDeltaType)
return ScrollInputMethod::ApzWheelLine;
}
static void
AdjustDeltaForAllowedScrollDirections(
ParentLayerPoint& aDelta,
const ScrollDirections& aAllowedScrollDirections)
{
if (!aAllowedScrollDirections.contains(ScrollDirection::eHorizontal)) {
aDelta.x = 0;
}
if (!aAllowedScrollDirections.contains(ScrollDirection::eVertical)) {
aDelta.y = 0;
}
}
nsEventStatus AsyncPanZoomController::OnScrollWheel(const ScrollWheelInput& aEvent)
{
ParentLayerPoint delta = GetScrollWheelDelta(aEvent);
@ -2017,6 +2051,10 @@ nsEventStatus AsyncPanZoomController::OnScrollWheel(const ScrollWheelInput& aEve
return nsEventStatus_eConsumeNoDefault;
}
MOZ_ASSERT(mInputQueue->GetCurrentWheelBlock());
AdjustDeltaForAllowedScrollDirections(delta,
mInputQueue->GetCurrentWheelBlock()->GetAllowedScrollDirections());
if (delta.x == 0 && delta.y == 0) {
// Avoid spurious state changes and unnecessary work
return nsEventStatus_eIgnore;
@ -2040,7 +2078,6 @@ nsEventStatus AsyncPanZoomController::OnScrollWheel(const ScrollWheelInput& aEve
CancelAnimation();
MOZ_ASSERT(mInputQueue->GetCurrentWheelBlock());
OverscrollHandoffState handoffState(
*mInputQueue->GetCurrentWheelBlock()->GetOverscrollHandoffChain(),
distance,
@ -2217,6 +2254,10 @@ nsEventStatus AsyncPanZoomController::OnPan(const PanGestureInput& aEvent, bool
ScreenPoint physicalPanDisplacement = aEvent.mPanDisplacement;
ParentLayerPoint logicalPanDisplacement = aEvent.UserMultipliedLocalPanDisplacement();
MOZ_ASSERT(GetCurrentPanGestureBlock());
AdjustDeltaForAllowedScrollDirections(logicalPanDisplacement,
GetCurrentPanGestureBlock()->GetAllowedScrollDirections());
// We need to update the axis velocity in order to get a useful display port
// size and position. We need to do so even if this is a momentum pan (i.e.
// aFingersOnTouchpad == false); in that case the "with touch" part is not
@ -2230,7 +2271,6 @@ nsEventStatus AsyncPanZoomController::OnPan(const PanGestureInput& aEvent, bool
(uint32_t) ScrollInputMethod::ApzPanGesture);
ScreenPoint panDistance(fabs(physicalPanDisplacement.x), fabs(physicalPanDisplacement.y));
MOZ_ASSERT(GetCurrentPanGestureBlock());
OverscrollHandoffState handoffState(
*GetCurrentPanGestureBlock()->GetOverscrollHandoffChain(),
panDistance,

Просмотреть файл

@ -420,6 +420,10 @@ public:
// direction.
bool CanScroll(const InputData& aEvent) const;
// Return the directions in which this APZC allows handoff (as governed by
// overscroll-behavior).
ScrollDirections GetAllowedHandoffDirections() const;
// Return whether or not a scroll delta will be able to scroll in either
// direction.
bool CanScrollWithWheel(const ParentLayerPoint& aDelta) const;
@ -1182,6 +1186,8 @@ private:
*/
void OverscrollBy(ParentLayerPoint& aOverscroll);
// Helper function for CanScroll().
ParentLayerPoint GetDeltaForEvent(const InputData& aEvent) const;
/* ===================================================================
* The functions and members in this section are used to maintain the

Просмотреть файл

@ -322,7 +322,8 @@ WheelBlockState::WheelBlockState(const RefPtr<AsyncPanZoomController>& aTargetAp
// content should have found a scrollable apzc, so we don't need to handle
// that case.
RefPtr<AsyncPanZoomController> apzc =
mOverscrollHandoffChain->FindFirstScrollable(aInitialEvent);
mOverscrollHandoffChain->FindFirstScrollable(
aInitialEvent, &mAllowedScrollDirections);
// If nothing is scrollable, we don't consider this block as starting a
// transaction.
@ -356,7 +357,8 @@ WheelBlockState::SetConfirmedTargetApzc(const RefPtr<AsyncPanZoomController>& aT
// one by looking for the first apzc the next pending event can scroll.
RefPtr<AsyncPanZoomController> apzc = aTargetApzc;
if (apzc && aFirstInput) {
apzc = apzc->BuildOverscrollHandoffChain()->FindFirstScrollable(*aFirstInput);
apzc = apzc->BuildOverscrollHandoffChain()->FindFirstScrollable(
*aFirstInput, &mAllowedScrollDirections);
}
InputBlockState::SetConfirmedTargetApzc(apzc, aState, aFirstInput);
@ -553,7 +555,8 @@ PanGestureBlockState::PanGestureBlockState(const RefPtr<AsyncPanZoomController>&
// content should have found a scrollable apzc, so we don't need to handle
// that case.
RefPtr<AsyncPanZoomController> apzc =
mOverscrollHandoffChain->FindFirstScrollable(aInitialEvent);
mOverscrollHandoffChain->FindFirstScrollable(
aInitialEvent, &mAllowedScrollDirections);
if (apzc && apzc != GetTargetApzc()) {
UpdateTargetApzc(apzc);
@ -572,7 +575,8 @@ PanGestureBlockState::SetConfirmedTargetApzc(const RefPtr<AsyncPanZoomController
RefPtr<AsyncPanZoomController> apzc = aTargetApzc;
if (apzc && aFirstInput) {
RefPtr<AsyncPanZoomController> scrollableApzc =
apzc->BuildOverscrollHandoffChain()->FindFirstScrollable(*aFirstInput);
apzc->BuildOverscrollHandoffChain()->FindFirstScrollable(
*aFirstInput, &mAllowedScrollDirections);
if (scrollableApzc) {
apzc = scrollableApzc;
}

Просмотреть файл

@ -282,6 +282,8 @@ public:
*/
void Update(ScrollWheelInput& aEvent);
ScrollDirections GetAllowedScrollDirections() const { return mAllowedScrollDirections; }
protected:
void UpdateTargetApzc(const RefPtr<AsyncPanZoomController>& aTargetApzc) override;
@ -290,6 +292,7 @@ private:
TimeStamp mLastMouseMove;
uint32_t mScrollSeriesCounter;
bool mTransactionEnded;
ScrollDirections mAllowedScrollDirections;
};
/**
@ -354,9 +357,12 @@ public:
void SetNeedsToWaitForContentResponse(bool aWaitForContentResponse);
ScrollDirections GetAllowedScrollDirections() const { return mAllowedScrollDirections; }
private:
bool mInterrupted;
bool mWaitingForContentResponse;
ScrollDirections mAllowedScrollDirections;
};
/**

Просмотреть файл

@ -318,9 +318,13 @@ CanScrollTargetHorizontally(const PanGestureInput& aInitialEvent,
{
PanGestureInput horizontalComponent = aInitialEvent;
horizontalComponent.mPanDisplacement.y = 0;
ScrollDirections allowedScrollDirections;
RefPtr<AsyncPanZoomController> horizontallyScrollableAPZC =
aBlock->GetOverscrollHandoffChain()->FindFirstScrollable(horizontalComponent);
return horizontallyScrollableAPZC && horizontallyScrollableAPZC == aBlock->GetTargetApzc();
aBlock->GetOverscrollHandoffChain()->FindFirstScrollable(
horizontalComponent, &allowedScrollDirections);
return horizontallyScrollableAPZC &&
horizontallyScrollableAPZC == aBlock->GetTargetApzc() &&
allowedScrollDirections.contains(ScrollDirection::eHorizontal);
}
nsEventStatus

Просмотреть файл

@ -161,12 +161,24 @@ OverscrollHandoffChain::HasFastFlungApzc() const
}
RefPtr<AsyncPanZoomController>
OverscrollHandoffChain::FindFirstScrollable(const InputData& aInput) const
OverscrollHandoffChain::FindFirstScrollable(
const InputData& aInput,
ScrollDirections* aOutAllowedScrollDirections) 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];
}
*aOutAllowedScrollDirections &= mChain[i]->GetAllowedHandoffDirections();
if (aOutAllowedScrollDirections->isEmpty()) {
return nullptr;
}
}
return nullptr;
}

Просмотреть файл

@ -89,7 +89,13 @@ public:
// Determine whether any APZC along this handoff chain has been flung fast.
bool HasFastFlungApzc() const;
RefPtr<AsyncPanZoomController> FindFirstScrollable(const InputData& aInput) const;
// Find the first APZC in this handoff chain that can be scrolled by |aInput|.
// Since overscroll-behavior can restrict handoff in some directions,
// |aOutAllowedScrollDirections| is populated with the scroll directions
// in which scrolling of the returned APZC is allowed.
RefPtr<AsyncPanZoomController> FindFirstScrollable(
const InputData& aInput,
ScrollDirections* aOutAllowedScrollDirections) const;
private:
std::vector<RefPtr<AsyncPanZoomController>> mChain;