From a34f7136a30eb6b2af38469804d888c154ffd2e7 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 1 Dec 2015 13:45:49 -0800 Subject: [PATCH] Add APZ support for mousewheel.acceleration prefs. (bug 1214170 part 1, r=kats) --- dom/events/WheelHandlingHelper.cpp | 12 ++++-------- dom/events/WheelHandlingHelper.h | 2 -- gfx/layers/apz/src/APZCTreeManager.cpp | 4 ++-- gfx/layers/apz/src/AsyncPanZoomController.cpp | 15 +++++++++++++++ gfx/layers/apz/src/InputBlockState.cpp | 16 +++++++++++++++- gfx/layers/apz/src/InputBlockState.h | 3 ++- gfx/layers/apz/src/InputQueue.cpp | 8 +++++--- gfx/thebes/gfxPrefs.h | 4 ++++ layout/generic/AsyncScrollBase.h | 13 +++++++++++++ widget/InputData.h | 5 +++++ 10 files changed, 65 insertions(+), 17 deletions(-) diff --git a/dom/events/WheelHandlingHelper.cpp b/dom/events/WheelHandlingHelper.cpp index 84093a82483..86e74de2f0b 100644 --- a/dom/events/WheelHandlingHelper.cpp +++ b/dom/events/WheelHandlingHelper.cpp @@ -21,6 +21,7 @@ #include "nsPresContext.h" #include "prtime.h" #include "Units.h" +#include "AsyncScrollBase.h" namespace mozilla { @@ -137,7 +138,7 @@ WheelTransaction::UpdateTransaction(WidgetWheelEvent* aEvent) SetTimeout(); - if (sScrollSeriesCounter != 0 && OutOfTime(sTime, kScrollSeriesTimeout)) { + if (sScrollSeriesCounter != 0 && OutOfTime(sTime, kScrollSeriesTimeoutMs)) { sScrollSeriesCounter = 0; } sScrollSeriesCounter++; @@ -383,14 +384,9 @@ WheelTransaction::AccelerateWheelDelta(WidgetWheelEvent* aEvent, } /* static */ double -WheelTransaction::ComputeAcceleratedWheelDelta(double aDelta, - int32_t aFactor) +WheelTransaction::ComputeAcceleratedWheelDelta(double aDelta, int32_t aFactor) { - if (aDelta == 0.0) { - return 0; - } - - return (aDelta * sScrollSeriesCounter * (double)aFactor / 10); + return mozilla::ComputeAcceleratedWheelDelta(aDelta, sScrollSeriesCounter, aFactor); } /* static */ int32_t diff --git a/dom/events/WheelHandlingHelper.h b/dom/events/WheelHandlingHelper.h index 62ee3c31b4f..b88aa23b2d4 100644 --- a/dom/events/WheelHandlingHelper.h +++ b/dom/events/WheelHandlingHelper.h @@ -151,8 +151,6 @@ public: bool aAllowScrollSpeedOverride); protected: - static const uint32_t kScrollSeriesTimeout = 80; // in milliseconds - static void BeginTransaction(nsIFrame* aTargetFrame, WidgetWheelEvent* aEvent); // Be careful, UpdateTransaction may fire a DOM event, therefore, the target diff --git a/gfx/layers/apz/src/APZCTreeManager.cpp b/gfx/layers/apz/src/APZCTreeManager.cpp index 918bd1d9610..4d7e7df26d5 100644 --- a/gfx/layers/apz/src/APZCTreeManager.cpp +++ b/gfx/layers/apz/src/APZCTreeManager.cpp @@ -625,8 +625,8 @@ static bool WillHandleWheelEvent(WidgetWheelEvent* aEvent) { return EventStateManager::WheelEventIsScrollAction(aEvent) && - (aEvent->deltaMode == nsIDOMWheelEvent::DOM_DELTA_LINE - || aEvent->deltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL) && + (aEvent->deltaMode == nsIDOMWheelEvent::DOM_DELTA_LINE || + aEvent->deltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL) && !EventStateManager::WheelEventNeedsDeltaMultipliers(aEvent); } diff --git a/gfx/layers/apz/src/AsyncPanZoomController.cpp b/gfx/layers/apz/src/AsyncPanZoomController.cpp index 52f5dc27e50..173ecdab1fb 100644 --- a/gfx/layers/apz/src/AsyncPanZoomController.cpp +++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp @@ -1616,6 +1616,21 @@ AsyncPanZoomController::GetScrollWheelDelta(const ScrollWheelInput& aEvent) cons } } + // If this is a line scroll, and this event was part of a scroll series, then + // it might need extra acceleration. See WheelHandlingHelper.cpp. + if (aEvent.mDeltaType == ScrollWheelInput::SCROLLDELTA_LINE && + aEvent.mScrollSeriesNumber > 0) + { + int32_t start = gfxPrefs::MouseWheelAccelerationStart(); + if (start >= 0 && aEvent.mScrollSeriesNumber >= uint32_t(start)) { + int32_t factor = gfxPrefs::MouseWheelAccelerationFactor(); + if (factor > 0) { + delta.x = ComputeAcceleratedWheelDelta(delta.x, aEvent.mScrollSeriesNumber, factor); + delta.y = ComputeAcceleratedWheelDelta(delta.y, aEvent.mScrollSeriesNumber, factor); + } + } + } + if (Abs(delta.x) > pageScrollSize.width) { delta.x = (delta.x >= 0) ? pageScrollSize.width diff --git a/gfx/layers/apz/src/InputBlockState.cpp b/gfx/layers/apz/src/InputBlockState.cpp index c6f60a9e359..58f3482514e 100644 --- a/gfx/layers/apz/src/InputBlockState.cpp +++ b/gfx/layers/apz/src/InputBlockState.cpp @@ -6,6 +6,7 @@ #include "InputBlockState.h" #include "AsyncPanZoomController.h" // for AsyncPanZoomController +#include "AsyncScrollBase.h" // for kScrollSeriesTimeoutMs #include "gfxPrefs.h" // for gfxPrefs #include "mozilla/MouseEvents.h" #include "mozilla/SizePrintfMacros.h" // for PRIuSIZE @@ -244,6 +245,7 @@ WheelBlockState::WheelBlockState(const RefPtr& aTargetAp bool aTargetConfirmed, const ScrollWheelInput& aInitialEvent) : CancelableBlockState(aTargetApzc, aTargetConfirmed) + , mScrollSeriesCounter(0) , mTransactionEnded(false) { sLastWheelBlockId = GetBlockId(); @@ -295,7 +297,7 @@ WheelBlockState::SetConfirmedTargetApzc(const RefPtr& aT } void -WheelBlockState::Update(const ScrollWheelInput& aEvent) +WheelBlockState::Update(ScrollWheelInput& aEvent) { // We might not be in a transaction if the block never started in a // transaction - for example, if nothing was scrollable. @@ -303,6 +305,18 @@ WheelBlockState::Update(const ScrollWheelInput& aEvent) return; } + // The current "scroll series" is a like a sub-transaction. It has a separate + // timeout of 80ms. Since we need to compute wheel deltas at different phases + // of a transaction (for example, when it is updated, and later when the + // event action is taken), we affix the scroll series counter to the event. + // This makes GetScrollWheelDelta() consistent. + if (!mLastEventTime.IsNull() && + (aEvent.mTimeStamp - mLastEventTime).ToMilliseconds() > kScrollSeriesTimeoutMs) + { + mScrollSeriesCounter = 0; + } + aEvent.mScrollSeriesNumber = ++mScrollSeriesCounter; + // If we can't scroll in the direction of the wheel event, we don't update // the last move time. This allows us to timeout a transaction even if the // mouse isn't moving. diff --git a/gfx/layers/apz/src/InputBlockState.h b/gfx/layers/apz/src/InputBlockState.h index 37e643d9e23..edcf92cc38d 100644 --- a/gfx/layers/apz/src/InputBlockState.h +++ b/gfx/layers/apz/src/InputBlockState.h @@ -244,7 +244,7 @@ public: /** * Update the wheel transaction state for a new event. */ - void Update(const ScrollWheelInput& aEvent); + void Update(ScrollWheelInput& aEvent); protected: void UpdateTargetApzc(const RefPtr& aTargetApzc) override; @@ -253,6 +253,7 @@ private: nsTArray mEvents; TimeStamp mLastEventTime; TimeStamp mLastMouseMove; + uint32_t mScrollSeriesCounter; bool mTransactionEnded; }; diff --git a/gfx/layers/apz/src/InputQueue.cpp b/gfx/layers/apz/src/InputQueue.cpp index 3db4391dd05..7b62a7ff000 100644 --- a/gfx/layers/apz/src/InputQueue.cpp +++ b/gfx/layers/apz/src/InputQueue.cpp @@ -277,15 +277,17 @@ InputQueue::ReceiveScrollWheelInput(const RefPtr& aTarge *aOutInputBlockId = block->GetBlockId(); } - block->Update(aEvent); + // Copy the event, since WheelBlockState needs to affix a counter. + ScrollWheelInput event(aEvent); + block->Update(event); // Note that the |aTarget| the APZCTM sent us may contradict the confirmed // target set on the block. In this case the confirmed target (which may be // null) should take priority. This is equivalent to just always using the // target (confirmed or not) from the block, which is what // MaybeHandleCurrentBlock() does. - if (!MaybeHandleCurrentBlock(block, aEvent)) { - block->AddEvent(aEvent.AsScrollWheelInput()); + if (!MaybeHandleCurrentBlock(block, event)) { + block->AddEvent(event); } return nsEventStatus_eConsumeDoDefault; diff --git a/gfx/thebes/gfxPrefs.h b/gfx/thebes/gfxPrefs.h index 80001421e97..ae8ad023b17 100644 --- a/gfx/thebes/gfxPrefs.h +++ b/gfx/thebes/gfxPrefs.h @@ -383,6 +383,10 @@ private: // This and code dependent on it should be removed once containerless scrolling looks stable. DECL_GFX_PREF(Once, "layout.scroll.root-frame-containers", LayoutUseContainersForRootFrames, bool, true); + // These affect how line scrolls from wheel events will be accelerated. + DECL_GFX_PREF(Live, "mousewheel.acceleration.factor", MouseWheelAccelerationFactor, int32_t, -1); + DECL_GFX_PREF(Live, "mousewheel.acceleration.start", MouseWheelAccelerationStart, int32_t, -1); + // This affects whether events will be routed through APZ or not. DECL_GFX_PREF(Live, "mousewheel.system_scroll_override_on_root_content.enabled", MouseWheelHasRootScrollDeltaOverride, bool, false); diff --git a/layout/generic/AsyncScrollBase.h b/layout/generic/AsyncScrollBase.h index 9a1725ba888..45e9d353037 100644 --- a/layout/generic/AsyncScrollBase.h +++ b/layout/generic/AsyncScrollBase.h @@ -87,6 +87,19 @@ protected: nsSMILKeySpline mTimingFunctionY; }; +// Helper for accelerated wheel deltas. This can be called from the main thread +// or the APZ Controller thread. +static inline double +ComputeAcceleratedWheelDelta(double aDelta, int32_t aCounter, int32_t aFactor) +{ + if (!aDelta) { + return aDelta; + } + return (aDelta * aCounter * double(aFactor) / 10); +} + +static const uint32_t kScrollSeriesTimeoutMs = 80; // in milliseconds + } // namespace mozilla #endif // mozilla_layout_AsyncScrollBase_h_ diff --git a/widget/InputData.h b/widget/InputData.h index 61d001aff11..0c1a4979468 100644 --- a/widget/InputData.h +++ b/widget/InputData.h @@ -582,6 +582,7 @@ public: mDeltaY(aDeltaY), mLineOrPageDeltaX(0), mLineOrPageDeltaY(0), + mScrollSeriesNumber(0), mIsMomentum(false) {} @@ -615,6 +616,10 @@ public: int32_t mLineOrPageDeltaX; int32_t mLineOrPageDeltaY; + // Indicates the order in which this event was added to a transaction. The + // first event is 1; if not a member of a transaction, this is 0. + uint32_t mScrollSeriesNumber; + bool mIsMomentum; };