--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -619,20 +619,23 @@ pref("browser.gesture.twist.threshold",
pref("browser.gesture.twist.right", "cmd_gestureRotateRight");
pref("browser.gesture.twist.left", "cmd_gestureRotateLeft");
pref("browser.gesture.twist.end", "cmd_gestureRotateEnd");
pref("browser.gesture.tap", "cmd_fullZoomReset");
pref("browser.snapshots.limit", 0);
// 0: Nothing happens
-// 1: Scrolling contents
+// 1: Scrolling contents smartly, that is, you can scroll a target in the
+// direction orthogonal to the wheel if there's no scrollbar in the wheel's
+// direction but a scrollbar in the wheel's orthogonal direction
// 2: Go back or go forward, in your history
// 3: Zoom in or out.
// 4: Treat vertical wheel as horizontal scroll
+// 5: Scroll contents
#ifdef XP_MACOSX
// On macOS, if the wheel has one axis only, shift+wheel comes through as a
// horizontal scroll event. Thus, we can't assign anything other than normal
// scrolling to shift+wheel.
pref("mousewheel.with_shift.action", 1);
pref("mousewheel.with_alt.action", 2);
// On MacOS X, control+wheel is typically handled by system and we don't
// receive the event. So, command key which is the main modifier key for
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -3361,37 +3361,45 @@ EventStateManager::PostHandleEvent(nsPre
// When APZ is enabled, the actual scroll animation might be handled by
// the compositor.
WheelPrefs::Action action =
wheelEvent->mFlags.mHandledByAPZ ?
WheelPrefs::ACTION_NONE :
WheelPrefs::GetInstance()->ComputeActionFor(wheelEvent);
- // Make the wheel event a horizontal scroll event. I.e., deltaY values
+ Maybe<WheelDeltaAdjustmentStrategy> strategy =
+ GetWheelDeltaAdjustmentStrategy(*wheelEvent);
+ // Adjust the delta values of the wheel event if the current default
+ // action is to horizontalize a vertical wheel scroll. I.e., deltaY values
// are set to deltaX and deltaY and deltaZ values are set to 0.
- // When AutoWheelDeltaAdjuster instance is destroyed, the delta values
- // are restored and make overflow deltaX becomes 0.
- AutoWheelDeltaAdjuster adjuster(*wheelEvent);
+ // In case of a horizontalized scroll, the delta values will be restored
+ // and its overflow deltaX will become 0 when the WheelDeltaHorizontalizer
+ // instance is being destroyed.
+ WheelDeltaHorizontalizer horizontalizer(*wheelEvent);
+ if (strategy == Some(WheelDeltaAdjustmentStrategy::eHorizontalize)) {
+ horizontalizer.horizontalize();
+ }
// Check if the frame to scroll before checking the default action
// because if the scroll target is a plugin, the default action should be
// chosen by the plugin rather than by our prefs.
nsIFrame* frameToScroll =
ComputeScrollTarget(mCurrentTarget, wheelEvent,
COMPUTE_DEFAULT_ACTION_TARGET);
nsPluginFrame* pluginFrame = do_QueryFrame(frameToScroll);
if (pluginFrame) {
MOZ_ASSERT(pluginFrame->WantsToHandleWheelEventAsDefaultAction());
action = WheelPrefs::ACTION_SEND_TO_PLUGIN;
}
switch (action) {
- case WheelPrefs::ACTION_SCROLL:
- case WheelPrefs::ACTION_HORIZONTAL_SCROLL: {
+ case WheelPrefs::ACTION_SMART_SCROLL:
+ case WheelPrefs::ACTION_HORIZONTAL_SCROLL:
+ case WheelPrefs::ACTION_SCROLL: {
// For scrolling of default action, we should honor the mouse wheel
// transaction.
ScrollbarsForWheel::PrepareToScrollText(this, mCurrentTarget, wheelEvent);
if (aEvent->mMessage != eWheel ||
(!wheelEvent->mDeltaX && !wheelEvent->mDeltaY)) {
break;
@@ -5879,20 +5887,21 @@ EventStateManager::WheelPrefs::Init(Even
nsAutoCString prefNameZ(basePrefName);
prefNameZ.AppendLiteral("delta_multiplier_z");
mMultiplierZ[aIndex] =
static_cast<double>(Preferences::GetInt(prefNameZ.get(), 100)) / 100;
nsAutoCString prefNameAction(basePrefName);
prefNameAction.AppendLiteral("action");
- int32_t action = Preferences::GetInt(prefNameAction.get(), ACTION_SCROLL);
+ int32_t action = Preferences::GetInt(prefNameAction.get(),
+ ACTION_SMART_SCROLL);
if (action < int32_t(ACTION_NONE) || action > int32_t(ACTION_LAST)) {
NS_WARNING("Unsupported action pref value, replaced with 'Scroll'.");
- action = ACTION_SCROLL;
+ action = ACTION_SMART_SCROLL;
}
mActions[aIndex] = static_cast<Action>(action);
// Compute action values overridden by .override_x pref.
// At present, override is possible only for the x-direction
// because this pref is introduced mainly for tilt wheels.
// Note that ACTION_HORIZONTAL_SCROLL isn't a valid value for this pref
// because it affects only to deltaY.
@@ -5916,17 +5925,17 @@ EventStateManager::WheelPrefs::GetMultip
double* aMultiplierForDeltaY)
{
// If the event should be treated as horizontal wheel operation, deltaY
// should be multiplied by mMultiplierY, however, it might be moved to
// deltaX for handling default action. In such case, we need to treat
// mMultiplierX and mMultiplierY as swapped.
*aMultiplierForDeltaX = mMultiplierX[aIndex];
*aMultiplierForDeltaY = mMultiplierY[aIndex];
- if (aEvent->mDeltaValuesAdjustedForDefaultHandler &&
+ if (aEvent->mDeltaValuesHorizontalizedForDefaultHandler &&
ComputeActionFor(aEvent) == ACTION_HORIZONTAL_SCROLL) {
std::swap(*aMultiplierForDeltaX, *aMultiplierForDeltaY);
}
}
void
EventStateManager::WheelPrefs::ApplyUserPrefsToDelta(WidgetWheelEvent* aEvent)
{
@@ -5989,29 +5998,33 @@ EventStateManager::WheelPrefs::ComputeAc
{
Index index = GetIndexFor(aEvent);
Init(index);
bool deltaXPreferred =
(Abs(aEvent->mDeltaX) > Abs(aEvent->mDeltaY) &&
Abs(aEvent->mDeltaX) > Abs(aEvent->mDeltaZ));
Action* actions = deltaXPreferred ? mOverriddenActionsX : mActions;
- if (actions[index] == ACTION_NONE ||
- actions[index] == ACTION_SCROLL ||
- actions[index] == ACTION_HORIZONTAL_SCROLL) {
- return actions[index];
+ switch (actions[index]) {
+ case ACTION_NONE:
+ case ACTION_SMART_SCROLL:
+ case ACTION_HORIZONTAL_SCROLL:
+ case ACTION_SCROLL:
+ return actions[index];
}
// Momentum events shouldn't run special actions.
if (aEvent->mIsMomentum) {
// Use the default action. Note that user might kill the wheel scrolling.
Init(INDEX_DEFAULT);
- if (actions[INDEX_DEFAULT] == ACTION_SCROLL ||
- actions[INDEX_DEFAULT] == ACTION_HORIZONTAL_SCROLL) {
- return actions[INDEX_DEFAULT];
+ switch (actions[INDEX_DEFAULT]) {
+ case ACTION_SMART_SCROLL:
+ case ACTION_HORIZONTAL_SCROLL:
+ case ACTION_SCROLL:
+ return actions[INDEX_DEFAULT];
}
return ACTION_NONE;
}
return actions[index];
}
bool
@@ -6053,33 +6066,41 @@ EventStateManager::WheelPrefs::WheelEven
// static
bool
EventStateManager::WheelEventIsScrollAction(const WidgetWheelEvent* aEvent)
{
if (aEvent->mMessage != eWheel) {
return false;
}
- WheelPrefs::Action action =
- WheelPrefs::GetInstance()->ComputeActionFor(aEvent);
- return action == WheelPrefs::ACTION_SCROLL ||
- action == WheelPrefs::ACTION_HORIZONTAL_SCROLL;
+ switch (WheelPrefs::GetInstance()->ComputeActionFor(aEvent)) {
+ case WheelPrefs::ACTION_SMART_SCROLL:
+ case WheelPrefs::ACTION_HORIZONTAL_SCROLL:
+ case WheelPrefs::ACTION_SCROLL:
+ return true;
+ }
+ return false;
}
// static
-bool
-EventStateManager::WheelEventIsHorizontalScrollAction(
- const WidgetWheelEvent* aEvent)
+Maybe<WheelDeltaAdjustmentStrategy>
+EventStateManager::GetWheelDeltaAdjustmentStrategy(
+ const WidgetWheelEvent& aEvent)
{
- if (aEvent->mMessage != eWheel) {
- return false;
- }
- WheelPrefs::Action action =
- WheelPrefs::GetInstance()->ComputeActionFor(aEvent);
- return action == WheelPrefs::ACTION_HORIZONTAL_SCROLL;
+ if (aEvent.mMessage != eWheel) {
+ return Nothing();
+ }
+ switch (WheelPrefs::GetInstance()->ComputeActionFor(&aEvent)) {
+ case WheelPrefs::ACTION_HORIZONTAL_SCROLL:
+ return Some(WheelDeltaAdjustmentStrategy::eHorizontalize);
+ case WheelPrefs::ACTION_SMART_SCROLL:
+ if (0 == aEvent.mDeltaZ)
+ return Some(WheelDeltaAdjustmentStrategy::eSmartize);
+ }
+ return Nothing();
}
void
EventStateManager::GetUserPrefsForWheelEvent(const WidgetWheelEvent* aEvent,
double* aOutMultiplierX,
double* aOutMultiplierY)
{
WheelPrefs::GetInstance()->GetUserPrefsForEvent(
--- a/dom/events/EventStateManager.h
+++ b/dom/events/EventStateManager.h
@@ -12,16 +12,17 @@
#include "nsIObserver.h"
#include "nsWeakReference.h"
#include "nsCOMPtr.h"
#include "nsCOMArray.h"
#include "nsCycleCollectionParticipant.h"
#include "mozilla/TimeStamp.h"
#include "nsIFrame.h"
#include "Units.h"
+#include "WheelHandlingHelper.h" // for WheelDeltaAdjustmentStrategy
#define NS_USER_INTERACTION_INTERVAL 5000 // ms
class nsFrameLoader;
class nsIContent;
class nsIDocument;
class nsIDocShell;
class nsIDocShellTreeItem;
@@ -297,19 +298,20 @@ public:
// Sets the full-screen event state on aElement to aIsFullScreen.
static void SetFullScreenState(dom::Element* aElement, bool aIsFullScreen);
static bool IsRemoteTarget(nsIContent* aTarget);
// Returns true if the given WidgetWheelEvent will resolve to a scroll action.
static bool WheelEventIsScrollAction(const WidgetWheelEvent* aEvent);
- // Returns true if the given WidgetWheelEvent will resolve to a horizontal
- // scroll action but it's a vertical wheel operation.
- static bool WheelEventIsHorizontalScrollAction(const WidgetWheelEvent* aEvet);
+ // In some situations, the delta values of WidgetWheelEvent may be adjusted
+ // according to a wheel delta adjustment strategy.
+ static Maybe<WheelDeltaAdjustmentStrategy>
+ GetWheelDeltaAdjustmentStrategy(const WidgetWheelEvent& aEvent);
// Returns user-set multipliers for a wheel event.
static void GetUserPrefsForWheelEvent(const WidgetWheelEvent* aEvent,
double* aOutMultiplierX,
double* aOutMultiplierY);
// Holds the point in screen coords that a mouse event was dispatched to,
// before we went into pointer lock mode. This is constantly updated while
@@ -546,21 +548,22 @@ protected:
void CancelApplyingUserPrefsFromOverflowDelta(WidgetWheelEvent* aEvent);
/**
* Computes the default action for the aEvent with the prefs.
*/
enum Action : uint8_t
{
ACTION_NONE = 0,
- ACTION_SCROLL,
+ ACTION_SMART_SCROLL,
ACTION_HISTORY,
ACTION_ZOOM,
ACTION_HORIZONTAL_SCROLL,
- ACTION_LAST = ACTION_HORIZONTAL_SCROLL,
+ ACTION_SCROLL,
+ ACTION_LAST = ACTION_SCROLL,
// Following actions are used only by internal processing. So, cannot
// specified by prefs.
ACTION_SEND_TO_PLUGIN,
};
Action ComputeActionFor(const WidgetWheelEvent* aEvent);
/**
* NeedToComputeLineOrPageDelta() returns if the aEvent needs to be
--- a/dom/events/WheelHandlingHelper.cpp
+++ b/dom/events/WheelHandlingHelper.cpp
@@ -1,16 +1,18 @@
/* -*- 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 "WheelHandlingHelper.h"
+#include <utility> // for std::swap
+
#include "mozilla/EventDispatcher.h"
#include "mozilla/EventStateManager.h"
#include "mozilla/MouseEvents.h"
#include "mozilla/Preferences.h"
#include "nsCOMPtr.h"
#include "nsContentUtils.h"
#include "nsIContent.h"
#include "nsIDocument.h"
@@ -578,51 +580,167 @@ WheelTransaction::Prefs::InitializeStati
Preferences::AddUintVarCache(&sMouseWheelTransactionIgnoreMoveDelay,
"mousewheel.transaction.ignoremovedelay", 100);
Preferences::AddBoolVarCache(&sTestMouseScroll, "test.mousescroll", false);
sIsInitialized = true;
}
}
/******************************************************************/
-/* mozilla::AutoWheelDeltaAdjuster */
+/* mozilla::WheelDeltaHorizontalizer */
/******************************************************************/
-AutoWheelDeltaAdjuster::AutoWheelDeltaAdjuster(WidgetWheelEvent& aWheelEvent)
- : mWheelEvent(aWheelEvent)
- , mOldDeltaX(aWheelEvent.mDeltaX)
- , mOldDeltaZ(aWheelEvent.mDeltaZ)
- , mOldOverflowDeltaX(aWheelEvent.mOverflowDeltaX)
- , mOldLineOrPageDeltaX(aWheelEvent.mLineOrPageDeltaX)
- , mTreatedVerticalWheelAsHorizontalScroll(false)
+void
+WheelDeltaHorizontalizer::horizontalize()
{
- MOZ_ASSERT(!aWheelEvent.mDeltaValuesAdjustedForDefaultHandler);
+ MOZ_ASSERT(!aWheelEvent.mDeltaValuesHorizontalizedForDefaultHandler);
+
+ // Log the old values.
+ mOldDeltaX = mWheelEvent.mDeltaX;
+ mOldDeltaZ = mWheelEvent.mDeltaZ;
+ mOldOverflowDeltaX = mWheelEvent.mOverflowDeltaX;
+ mOldLineOrPageDeltaX = mWheelEvent.mLineOrPageDeltaX;
- if (EventStateManager::WheelEventIsHorizontalScrollAction(&aWheelEvent)) {
- // Move deltaY values to deltaX and set both deltaY and deltaZ to 0.
- mWheelEvent.mDeltaX = mWheelEvent.mDeltaY;
- mWheelEvent.mDeltaY = 0.0;
- mWheelEvent.mDeltaZ = 0.0;
- mWheelEvent.mOverflowDeltaX = mWheelEvent.mOverflowDeltaY;
- mWheelEvent.mOverflowDeltaY = 0.0;
- mWheelEvent.mLineOrPageDeltaX = mWheelEvent.mLineOrPageDeltaY;
- mWheelEvent.mLineOrPageDeltaY = 0;
- mWheelEvent.mDeltaValuesAdjustedForDefaultHandler = true;
- mTreatedVerticalWheelAsHorizontalScroll = true;
- }
+ // Move deltaY values to deltaX and set both deltaY and deltaZ to 0.
+ mWheelEvent.mDeltaX = mWheelEvent.mDeltaY;
+ mWheelEvent.mDeltaY = 0.0;
+ mWheelEvent.mDeltaZ = 0.0;
+ mWheelEvent.mOverflowDeltaX = mWheelEvent.mOverflowDeltaY;
+ mWheelEvent.mOverflowDeltaY = 0.0;
+ mWheelEvent.mLineOrPageDeltaX = mWheelEvent.mLineOrPageDeltaY;
+ mWheelEvent.mLineOrPageDeltaY = 0;
+ mWheelEvent.mDeltaValuesHorizontalizedForDefaultHandler = true;
+
+ // Mark it horizontalized in order to restore the delta values when this
+ // instance is being destroyed.
+ mHorizontalized = true;
}
-AutoWheelDeltaAdjuster::~AutoWheelDeltaAdjuster()
+WheelDeltaHorizontalizer::~WheelDeltaHorizontalizer()
{
- if (mTreatedVerticalWheelAsHorizontalScroll &&
- mWheelEvent.mDeltaValuesAdjustedForDefaultHandler) {
+ if (mHorizontalized &&
+ mWheelEvent.mDeltaValuesHorizontalizedForDefaultHandler) {
mWheelEvent.mDeltaY = mWheelEvent.mDeltaX;
mWheelEvent.mDeltaX = mOldDeltaX;
mWheelEvent.mDeltaZ = mOldDeltaZ;
mWheelEvent.mOverflowDeltaY = mWheelEvent.mOverflowDeltaX;
mWheelEvent.mOverflowDeltaX = mOldOverflowDeltaX;
mWheelEvent.mLineOrPageDeltaY = mWheelEvent.mLineOrPageDeltaX;
mWheelEvent.mLineOrPageDeltaX = mOldLineOrPageDeltaX;
- mWheelEvent.mDeltaValuesAdjustedForDefaultHandler = false;
+ mWheelEvent.mDeltaValuesHorizontalizedForDefaultHandler = false;
}
}
+/******************************************************************/
+/* mozilla::WheelDeltaSmartizer */
+/******************************************************************/
+
+bool
+WheelDeltaSmartizer::ShouldBeSmartized()
+{
+ // Sometimes, this function can be called more than one time. If we have
+ // already checked if the scroll should be smartized, there's no need to check
+ // it again.
+ if (mCheckedIfShouldBeSmartized) {
+ return mShouldBeSmartized;
+ }
+ mCheckedIfShouldBeSmartized = true;
+
+ // For a smart wheel scroll, if all the following conditions are met, we
+ // should switch X and Y values:
+ // 1. There is only one non-zero value between DeltaX and DeltaY.
+ // 2. There is only one direction for the target that overflows and is
+ // scrollable with wheel.
+ // 3. The direction described in Condition 1 is orthogonal to the one
+ // described in Condition 2.
+ if (0 != mDeltaX) {
+ if (0 == mDeltaY) {
+ if (!CanScrollAlongXAxis()) {
+ mIsHorizontalContentRightToLeft = IsHorizontalContentRightToLeft();
+ if (mIsHorizontalContentRightToLeft) {
+ mShouldBeSmartized = mDeltaX > 0 ? CanScrollUpwards()
+ : CanScrollDownwards();
+ } else {
+ mShouldBeSmartized = mDeltaX < 0 ? CanScrollUpwards()
+ : CanScrollDownwards();
+ }
+ return mShouldBeSmartized;
+ }
+ }
+ } else if (0 != mDeltaY) {
+ if (!CanScrollAlongYAxis()) {
+ mIsHorizontalContentRightToLeft = IsHorizontalContentRightToLeft();
+ if (mIsHorizontalContentRightToLeft) {
+ mShouldBeSmartized = mDeltaY > 0 ? CanScrollLeftwards()
+ : CanScrollRightwards();
+ } else {
+ mShouldBeSmartized = mDeltaY < 0 ? CanScrollLeftwards()
+ : CanScrollRightwards();
+ }
+ return mShouldBeSmartized;
+ }
+ }
+ mShouldBeSmartized = false;
+ return false;
+}
+
+void
+WheelDeltaSmartizer::smartize()
+{
+ if (!ShouldBeSmartized()) {
+ return;
+ }
+ std::swap(mDeltaX, mDeltaY);
+ std::swap(mDeltaMultiplierX, mDeltaMultiplierY);
+ if (mIsHorizontalContentRightToLeft) {
+ mDeltaX = -mDeltaX;
+ mDeltaY = -mDeltaY;
+ }
+ mShouldBeSmartized = false;
+}
+
+// Ideally, it's not necessary to define bodies for pure virtual functions,
+// However, we want this class to be exported to some other component(i.e. APZ).
+// If we don't define them, it will fail with undefined reference errors at
+// linking stage.
+// virtual
+bool WheelDeltaSmartizer::CanScrollAlongXAxis() const // = 0
+{
+ return false;
+}
+
+// virtual
+bool WheelDeltaSmartizer::CanScrollAlongYAxis() const // = 0
+{
+ return false;
+}
+
+// virtual
+bool WheelDeltaSmartizer::CanScrollUpwards() const // = 0
+{
+ return false;
+}
+
+// virtual
+bool WheelDeltaSmartizer::CanScrollDownwards() const // = 0
+{
+ return false;
+}
+
+// virtual
+bool WheelDeltaSmartizer::CanScrollLeftwards() const // = 0
+{
+ return false;
+}
+
+// virtual
+bool WheelDeltaSmartizer::CanScrollRightwards() const // = 0
+{
+ return false;
+}
+
+// virtual
+bool WheelDeltaSmartizer::IsHorizontalContentRightToLeft() const // = 0
+{
+ return false;
+}
+
} // namespace mozilla
--- a/dom/events/WheelHandlingHelper.h
+++ b/dom/events/WheelHandlingHelper.h
@@ -205,40 +205,138 @@ protected:
static int32_t sMouseWheelAccelerationStart;
static int32_t sMouseWheelAccelerationFactor;
static uint32_t sMouseWheelTransactionTimeout;
static uint32_t sMouseWheelTransactionIgnoreMoveDelay;
static bool sTestMouseScroll;
};
};
+enum class WheelDeltaAdjustmentStrategy
+{
+ // Treat a *pure* vertical wheel event as if it was a horizontal scroll.
+ eHorizontalize,
+ // If the target is only wheel-scrollable in vertical direction, treat it as
+ // if it was a vertical scroll; If the target is only wheel-scrollable in
+ // horizontal direction, treat it as if it was a horizontal scroll.
+ eSmartize,
+};
+
/**
- * When a wheel event should be treated as specially, e.g., it's a vertical
- * wheel operation but user wants to scroll the target horizontally, this
- * class adjust the delta values automatically. Then, restores the original
- * value when the instance is destroyed.
+ * When a *pure* vertical wheel event should be treated as if it was a
+ * horizontal scroll because the user wants to hozizontalize the wheel scroll,
+ * an instance of this class will adjust the delta values upon calling
+ * hozizontalize(). And if hozizontalized, it will automatically restore the
+ * original delta values when it is being destroyed.
*/
-class MOZ_STACK_CLASS AutoWheelDeltaAdjuster final
+class MOZ_STACK_CLASS WheelDeltaHorizontalizer final
{
public:
/**
- * @param aWheelEvent A wheel event. The delta values may be
- * modified for default handler.
- * Its mDeltaValuesAdjustedForDefaultHandler
- * must not be true because if it's true,
- * the event has already been adjusted the
- * delta values for default handler.
+ * @param aWheelEvent A wheel event whose delta values will be adjusted
+ * upon calling hozizontalize().
*/
- explicit AutoWheelDeltaAdjuster(WidgetWheelEvent& aWheelEvent);
- ~AutoWheelDeltaAdjuster();
+ explicit WheelDeltaHorizontalizer(WidgetWheelEvent& aWheelEvent)
+ : mWheelEvent(aWheelEvent)
+ , mHorizontalized(false)
+ {
+ }
+ // |mDeltaValuesHorizontalizedForDefaultHandler| of the associated wheel event
+ // must not be true before calling this function, because if it's true, the
+ // wheel event must have already been horizontalized. It's logically erroneous
+ // to horizontalize a wheel event a second time.
+ void horizontalize();
+ ~WheelDeltaHorizontalizer();
private:
WidgetWheelEvent& mWheelEvent;
double mOldDeltaX;
double mOldDeltaZ;
double mOldOverflowDeltaX;
int32_t mOldLineOrPageDeltaX;
- bool mTreatedVerticalWheelAsHorizontalScroll;
+ bool mHorizontalized;
+};
+
+/**
+ * For a smart wheel scroll, there's some situations where we should adjust a
+ * wheel event's delta values and their multiplier values. This class converts a
+ * regular delta and their multiplier values for smart scrolling. A smart wheel
+ * scroll lets the user scroll a frame with only one scrollbar, using either a
+ * vertical or a horzizontal wheel.
+ */
+class MOZ_STACK_CLASS WheelDeltaSmartizer
+{
+protected:
+ /**
+ * @param aDeltaX DeltaX for a wheel event whose delta values will
+ * be adjusted upon calling smartize() if
+ * mShouldBeSmartized is true.
+ * @param aDeltaY DeltaZ for a wheel event, like DeltaX.
+ * @param aDeltaMultiplierX The multiplier of DeltaX for a wheel event whose
+ * delta multiplier values will be adjusted upon
+ * calling smartize() if ShouldBeSmartized() returns
+ * true.
+ * @param aDeltaMultiplierY The multiplier of DeltaY for a wheel event, like
+ * aDeltaMultiplierX.
+ */
+ explicit WheelDeltaSmartizer(double& aDeltaX,
+ double& aDeltaY,
+ double& aDeltaMultiplierX,
+ double& aDeltaMultiplierY)
+ : mDeltaX(aDeltaX)
+ , mDeltaY(aDeltaY)
+ , mDeltaMultiplierX(aDeltaMultiplierX)
+ , mDeltaMultiplierY(aDeltaMultiplierY)
+ , mCheckedIfShouldBeSmartized(false)
+ {
+ }
+
+public:
+ /**
+ * Gets whether the values of the delta and its multiplier should be adjusted
+ * for smart scrolling.
+ *
+ * @return Returns true if the values of the delta and its multiplier should
+ * be adjusted for smart scrolling. Note that after calling
+ * smartize(), this function will return false, this ensures a wheel
+ * event won't be adjusted for smart scrolling a second time.
+ */
+ bool ShouldBeSmartized();
+ /**
+ * Adjusts the values of the scroll event's delta and multiplier for smart
+ * scrolling when ShouldBeSmartized() is true. If you call it when
+ * ShouldBeSmartized() returns false, it simply will do nothing.
+ */
+ void smartize();
+
+private:
+ virtual bool CanScrollAlongXAxis() const = 0;
+ virtual bool CanScrollAlongYAxis() const = 0;
+ virtual bool CanScrollUpwards() const = 0;
+ virtual bool CanScrollDownwards() const = 0;
+ virtual bool CanScrollLeftwards() const = 0;
+ virtual bool CanScrollRightwards() const = 0;
+ /*
+ * Gets whether the current frame's horizontal contents starts at rightside.
+ *
+ * @return If the frame is in vertical-RTL writing mode(E.g. "writing-mode:
+ * vertical-rl" in CSS), or if it's in horizontal-RTL writing-mode
+ * (E.g. "writing-mode: horizontal-tb; direction: rtl;" in CSS), then
+ * this function returns true. From the representation perspective,
+ * frames whose horizontal contents start at rightside also cause
+ * their horizontal scrollbars, if any, initially start at rightside.
+ * So we can also learn about the initial side of the horizontal
+ * scrollbar for the frame by calling this function.
+ */
+ virtual bool IsHorizontalContentRightToLeft() const = 0;
+
+ double& mDeltaX;
+ double& mDeltaY;
+ double& mDeltaMultiplierX;
+ double& mDeltaMultiplierY;
+ bool mCheckedIfShouldBeSmartized;
+ bool mIsHorizontalContentRightToLeft;
+ bool mShouldBeSmartized;
};
} // namespace mozilla
#endif // mozilla_WheelHandlingHelper_h_
--- a/gfx/layers/FrameMetrics.h
+++ b/gfx/layers/FrameMetrics.h
@@ -481,16 +481,27 @@ public:
return mScrollableRect;
}
void SetScrollableRect(const CSSRect& aScrollableRect)
{
mScrollableRect = aScrollableRect;
}
+ // If the frame is in vertical-RTL writing mode(E.g. "writing-mode:
+ // vertical-rl" in CSS), or if it's in horizontal-RTL writing-mode(E.g.
+ // "writing-mode: horizontal-tb; direction: rtl;" in CSS), then this function
+ // returns true. From the representation perspective, frames whose horizontal
+ // contents start at rightside also cause their horizontal scrollbars, if any,
+ // initially start at rightside. So we can also learn about the initial side
+ // of the horizontal scrollbar for the frame by calling this function.
+ bool IsHorizontalContentRightToLeft() {
+ return mScrollableRect.x < 0;
+ }
+
void SetPaintRequestTime(const TimeStamp& aTime) {
mPaintRequestTime = aTime;
}
const TimeStamp& GetPaintRequestTime() const {
return mPaintRequestTime;
}
void SetIsScrollInfoLayer(bool aIsScrollInfoLayer) {
--- a/gfx/layers/apz/public/IAPZCTreeManager.cpp
+++ b/gfx/layers/apz/public/IAPZCTreeManager.cpp
@@ -110,31 +110,42 @@ IAPZCTreeManager::ReceiveInputEvent(
((wheelEvent.mDeltaMode == nsIDOMWheelEvent::DOM_DELTA_LINE &&
gfxPrefs::WheelSmoothScrollEnabled()) ||
(wheelEvent.mDeltaMode == nsIDOMWheelEvent::DOM_DELTA_PAGE &&
gfxPrefs::PageSmoothScrollEnabled())))
{
scrollMode = ScrollWheelInput::SCROLLMODE_SMOOTH;
}
- // AutoWheelDeltaAdjuster may adjust the delta values for default
- // action hander. The delta values will be restored automatically
- // when its instance is destroyed.
- AutoWheelDeltaAdjuster adjuster(wheelEvent);
+ Maybe<WheelDeltaAdjustmentStrategy> strategy =
+ EventStateManager::GetWheelDeltaAdjustmentStrategy(wheelEvent);
+ // Adjust the delta values of the wheel event if the current default
+ // action is to horizontalize a vertical wheel scroll. I.e., deltaY
+ // values are set to deltaX and deltaY and deltaZ values are set to 0.
+ // In case of a horizontalized scroll, the delta values will be restored
+ // and its overflow deltaX will become 0 when the
+ // WheelDeltaHorizontalizer instance is being destroyed.
+ WheelDeltaHorizontalizer horizontalizer(wheelEvent);
+ if (strategy == Some(WheelDeltaAdjustmentStrategy::eHorizontalize)) {
+ horizontalizer.horizontalize();
+ }
// If the wheel event becomes no-op event, don't handle it as scroll.
if (wheelEvent.mDeltaX || wheelEvent.mDeltaY) {
ScreenPoint origin(wheelEvent.mRefPoint.x, wheelEvent.mRefPoint.y);
ScrollWheelInput input(wheelEvent.mTime, wheelEvent.mTimeStamp, 0,
scrollMode,
ScrollWheelInput::DeltaTypeForDeltaMode(
wheelEvent.mDeltaMode),
origin,
wheelEvent.mDeltaX, wheelEvent.mDeltaY,
- wheelEvent.mAllowToOverrideSystemScrollSpeed);
+ wheelEvent.mAllowToOverrideSystemScrollSpeed,
+ strategy ==
+ Some(WheelDeltaAdjustmentStrategy::eSmartize)
+ );
// We add the user multiplier as a separate field, rather than premultiplying
// it, because if the input is converted back to a WidgetWheelEvent, then
// EventStateManager would apply the delta a second time. We could in theory
// work around this by asking ESM to customize the event much sooner, and
// then save the "mCustomizedByUserPrefs" bit on ScrollWheelInput - but for
// now, this seems easier.
EventStateManager::GetUserPrefsForWheelEvent(&wheelEvent,
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -23,16 +23,18 @@
#include "HitTestingTreeNode.h" // for HitTestingTreeNode
#include "InputData.h" // for MultiTouchInput, etc
#include "InputBlockState.h" // for InputBlockState, TouchBlockState
#include "InputQueue.h" // for InputQueue
#include "Overscroll.h" // for OverscrollAnimation
#include "OverscrollHandoffState.h" // for OverscrollHandoffState
#include "Units.h" // for CSSRect, CSSPoint, etc
#include "UnitTransforms.h" // for TransformTo
+// for APZWheelDeltaSmartizer, WheelDeltaAndMultiplier
+#include "WheelDeltaSmartizer.h"
#include "base/message_loop.h" // for MessageLoop
#include "base/task.h" // for NewRunnableMethod, etc
#include "gfxPrefs.h" // for gfxPrefs
#include "gfxTypes.h" // for gfxFloat
#include "LayersLogging.h" // for print_stderr
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
#include "mozilla/BasicEvents.h" // for Modifiers, MODIFIER_*
#include "mozilla/ClearOnShutdown.h" // for ClearOnShutdown
@@ -1695,53 +1697,68 @@ static bool
AllowsScrollingMoreThanOnePage(double aMultiplier)
{
const int32_t kMinAllowPageScroll =
EventStateManager::MIN_MULTIPLIER_VALUE_ALLOWING_OVER_ONE_PAGE_SCROLL;
return Abs(aMultiplier) >= kMinAllowPageScroll;
}
ParentLayerPoint
-AsyncPanZoomController::GetScrollWheelDelta(const ScrollWheelInput& aEvent) const
+AsyncPanZoomController::GetScrollWheelDeltaInDevicePixels(
+ const ScrollWheelInput& aEvent) const
+{
+ WheelDeltaAndMultiplier wheelDeltaAndMultiplier(
+ aEvent.mDeltaX,
+ aEvent.mDeltaY,
+ aEvent.mUserDeltaMultiplierX,
+ aEvent.mUserDeltaMultiplierY);
+ return GetScrollWheelDeltaInDevicePixels(aEvent, wheelDeltaAndMultiplier);
+}
+
+ParentLayerPoint
+AsyncPanZoomController::GetScrollWheelDeltaInDevicePixels(
+ const ScrollWheelInput& aEvent,
+ const WheelDeltaAndMultiplier& aWheelDeltaAndMultiplier) const
{
ParentLayerSize scrollAmount;
ParentLayerSize pageScrollSize;
-
{
// Grab the lock to access the frame metrics.
RecursiveMutexAutoLock lock(mRecursiveMutex);
LayoutDeviceIntSize scrollAmountLD = mScrollMetadata.GetLineScrollAmount();
LayoutDeviceIntSize pageScrollSizeLD = mScrollMetadata.GetPageScrollAmount();
scrollAmount = scrollAmountLD /
mFrameMetrics.GetDevPixelsPerCSSPixel() * mFrameMetrics.GetZoom();
pageScrollSize = pageScrollSizeLD /
mFrameMetrics.GetDevPixelsPerCSSPixel() * mFrameMetrics.GetZoom();
}
ParentLayerPoint delta;
switch (aEvent.mDeltaType) {
case ScrollWheelInput::SCROLLDELTA_LINE: {
- delta.x = aEvent.mDeltaX * scrollAmount.width;
- delta.y = aEvent.mDeltaY * scrollAmount.height;
+ delta.x = aWheelDeltaAndMultiplier.mDeltaX * scrollAmount.width;
+ delta.y = aWheelDeltaAndMultiplier.mDeltaY * scrollAmount.height;
break;
}
case ScrollWheelInput::SCROLLDELTA_PAGE: {
- delta.x = aEvent.mDeltaX * pageScrollSize.width;
- delta.y = aEvent.mDeltaY * pageScrollSize.height;
+ delta.x = aWheelDeltaAndMultiplier.mDeltaX * pageScrollSize.width;
+ delta.y = aWheelDeltaAndMultiplier.mDeltaY * pageScrollSize.height;
break;
}
case ScrollWheelInput::SCROLLDELTA_PIXEL: {
- delta = ToParentLayerCoordinates(ScreenPoint(aEvent.mDeltaX, aEvent.mDeltaY), aEvent.mOrigin);
+ ScreenPoint pt(aWheelDeltaAndMultiplier.mDeltaX,
+ aWheelDeltaAndMultiplier.mDeltaY);
+ delta = ToParentLayerCoordinates(pt, aEvent.mOrigin);
break;
}
}
// Apply user-set multipliers.
- delta.x *= aEvent.mUserDeltaMultiplierX;
- delta.y *= aEvent.mUserDeltaMultiplierY;
+ delta.x *= aWheelDeltaAndMultiplier.mDeltaMultiplierX;
+ delta.y *= aWheelDeltaAndMultiplier.mDeltaMultiplierY;
// For the conditions under which we allow system scroll overrides, see
// EventStateManager::DeltaAccumulator::ComputeScrollAmountForDefaultAction
// and WheelTransaction::OverrideSystemScrollSpeed. Note that we do *not*
// restrict this to the root content, see bug 1217715 for discussion on this.
if (gfxPrefs::MouseWheelHasRootScrollDeltaOverride() &&
!aEvent.IsCustomizedByUserPrefs() &&
aEvent.mDeltaType == ScrollWheelInput::SCROLLDELTA_LINE &&
@@ -1933,34 +1950,54 @@ AsyncPanZoomController::GetKeyboardDesti
return scrollDestination;
}
ParentLayerPoint
AsyncPanZoomController::GetDeltaForEvent(const InputData& aEvent) const
{
ParentLayerPoint delta;
if (aEvent.mInputType == SCROLLWHEEL_INPUT) {
- delta = GetScrollWheelDelta(aEvent.AsScrollWheelInput());
+ delta = GetScrollWheelDeltaInDevicePixels(aEvent.AsScrollWheelInput());
} else if (aEvent.mInputType == PANGESTURE_INPUT) {
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;
}
-
- return CanScrollWithWheel(delta);
+ if (SCROLLWHEEL_INPUT == aEvent.mInputType) {
+ const ScrollWheelInput& scrollWheelInput = aEvent.AsScrollWheelInput();
+ WheelDeltaAndMultiplier smartDeltaAndMultiplier(
+ scrollWheelInput.mDeltaX,
+ scrollWheelInput.mDeltaY,
+ scrollWheelInput.mUserDeltaMultiplierX,
+ scrollWheelInput.mUserDeltaMultiplierY);
+ bool isRTL;
+ {
+ RecursiveMutexAutoLock lock(mRecursiveMutex);
+ isRTL = mFrameMetrics.IsHorizontalContentRightToLeft();
+ }
+ APZWheelDeltaSmartizer smartizer(smartDeltaAndMultiplier, mX, mY, isRTL);
+ if (smartizer.ShouldBeSmartized()) {
+ // If delta values are needed to be smartized for a smart wheel scroll,
+ // then it is impossible to be unscrollable, so there is no need to
+ // continue checking.
+ return true;
+ }
+ return CanScrollWithWheel(delta);
+ }
+ return CanScroll(delta);
}
ScrollDirections
AsyncPanZoomController::GetAllowedHandoffDirections() const
{
ScrollDirections result;
RecursiveMutexAutoLock lock(mRecursiveMutex);
if (mX.OverscrollBehaviorAllowsHandoff()) {
@@ -1968,16 +2005,22 @@ AsyncPanZoomController::GetAllowedHandof
}
if (mY.OverscrollBehaviorAllowsHandoff()) {
result += ScrollDirection::eVertical;
}
return result;
}
bool
+AsyncPanZoomController::CanScroll(const ParentLayerPoint& aDelta) const
+{
+ return mX.CanScroll(aDelta.x) || mY.CanScroll(aDelta.y);
+}
+
+bool
AsyncPanZoomController::CanScrollWithWheel(const ParentLayerPoint& aDelta) const
{
RecursiveMutexAutoLock lock(mRecursiveMutex);
// For more details about the concept of a disregarded direction, refer to the
// code in struct ScrollMetadata which defines mDisregardedDirection.
Maybe<ScrollDirection> disregardedDirection =
mScrollMetadata.GetDisregardedDirection();
@@ -2038,61 +2081,105 @@ AdjustDeltaForAllowedScrollDirections(
}
if (!aAllowedScrollDirections.contains(ScrollDirection::eVertical)) {
aDelta.y = 0;
}
}
nsEventStatus AsyncPanZoomController::OnScrollWheel(const ScrollWheelInput& aEvent)
{
- ParentLayerPoint delta = GetScrollWheelDelta(aEvent);
- APZC_LOG("%p got a scroll-wheel with delta %s\n", this, Stringify(delta).c_str());
-
- if ((delta.x || delta.y) && !CanScrollWithWheel(delta)) {
- // We can't scroll this apz anymore, so we simply drop the event.
+ // Get the scroll wheel's delta values in device pixels. But before getting
+ // the values, we need to check if it is a smart scroll and if it should be
+ // smartized, if both answers are yes, let's adjust X and Y values for a smart
+ // wheel scroll first, and then get the values in device pixels based on the
+ // smartized values.
+ bool isSmartized = false;
+ ParentLayerPoint deltaInDevicePixels;
+ if (aEvent.mIsSmart) {
+ WheelDeltaAndMultiplier smartDeltaAndMultiplier(
+ aEvent.mDeltaX,
+ aEvent.mDeltaY,
+ aEvent.mUserDeltaMultiplierX,
+ aEvent.mUserDeltaMultiplierY);
+ bool isRTL;
+ {
+ RecursiveMutexAutoLock lock(mRecursiveMutex);
+ isRTL = mFrameMetrics.IsHorizontalContentRightToLeft();
+ }
+ APZWheelDeltaSmartizer smartizer(smartDeltaAndMultiplier, mX, mY, isRTL);
+ if (smartizer.ShouldBeSmartized()) {
+ smartizer.smartize();
+ // If the original delta values are smartized, we pass them to replace the
+ // original delta values in |aEvent| so that the delta values in device
+ // pixels are caculated based on the smartized values, not the original
+ // ones.
+ deltaInDevicePixels = GetScrollWheelDeltaInDevicePixels(
+ aEvent, smartDeltaAndMultiplier);
+ isSmartized = true;
+ }
+ }
+ if (!isSmartized) {
+ // If the original delta values are not smartized, just pass the |aEvent|,
+ // Caculate the delta values in device pixels based on the original delta
+ // values from |aEvent|.
+ deltaInDevicePixels = GetScrollWheelDeltaInDevicePixels(aEvent);
+ }
+ APZC_LOG("%p got a scroll-wheel with delta in device pixels: %s\n", this,
+ Stringify(deltaInDevicePixels).c_str());
+
+ if (isSmartized) {
+ MOZ_ASSERT(deltaInDevicePixels.x || deltaInDevicePixels.y,
+ "Smartized delta values can never be all-zero.");
+ APZC_LOG("%p got a scroll-wheel with smartized delta values\n", this);
+ } else if ((deltaInDevicePixels.x || deltaInDevicePixels.y) &&
+ !CanScrollWithWheel(deltaInDevicePixels)) {
+ // If we can't scroll this apz anymore, simply drop the event.
if (mInputQueue->GetActiveWheelTransaction() &&
gfxPrefs::MouseScrollTestingEnabled()) {
if (RefPtr<GeckoContentController> controller = GetGeckoContentController()) {
controller->NotifyMozMouseScrollEvent(
mFrameMetrics.GetScrollId(),
NS_LITERAL_STRING("MozMouseScrollFailed"));
}
}
return nsEventStatus_eConsumeNoDefault;
}
MOZ_ASSERT(mInputQueue->GetCurrentWheelBlock());
- AdjustDeltaForAllowedScrollDirections(delta,
+ AdjustDeltaForAllowedScrollDirections(deltaInDevicePixels,
mInputQueue->GetCurrentWheelBlock()->GetAllowedScrollDirections());
- if (delta.x == 0 && delta.y == 0) {
+ if (deltaInDevicePixels.x == 0 && deltaInDevicePixels.y == 0) {
// Avoid spurious state changes and unnecessary work
return nsEventStatus_eIgnore;
}
switch (aEvent.mScrollMode) {
case ScrollWheelInput::SCROLLMODE_INSTANT: {
// Wheel events from "clicky" mouse wheels trigger scroll snapping to the
// next snap point. Check for this, and adjust the delta to take into
// account the snap point.
CSSPoint startPosition = mFrameMetrics.GetScrollOffset();
- MaybeAdjustDeltaForScrollSnapping(aEvent, delta, startPosition);
+ MaybeAdjustDeltaForScrollSnapping(aEvent, deltaInDevicePixels,
+ startPosition);
ScreenPoint distance = ToScreenCoordinates(
- ParentLayerPoint(fabs(delta.x), fabs(delta.y)), aEvent.mLocalOrigin);
+ ParentLayerPoint(fabs(deltaInDevicePixels.x),
+ fabs(deltaInDevicePixels.y)),
+ aEvent.mLocalOrigin);
CancelAnimation();
OverscrollHandoffState handoffState(
*mInputQueue->GetCurrentWheelBlock()->GetOverscrollHandoffChain(),
distance,
ScrollSource::Wheel);
ParentLayerPoint startPoint = aEvent.mLocalOrigin;
- ParentLayerPoint endPoint = aEvent.mLocalOrigin - delta;
+ ParentLayerPoint endPoint = aEvent.mLocalOrigin - deltaInDevicePixels;
CallDispatchScroll(startPoint, endPoint, handoffState);
SetState(NOTHING);
// The calls above handle their own locking; moreover,
// ToScreenCoordinates() and CallDispatchScroll() can grab the tree lock.
RecursiveMutexAutoLock lock(mRecursiveMutex);
RequestContentRepaint();
@@ -2113,17 +2200,18 @@ nsEventStatus AsyncPanZoomController::On
// scroll position. Take this into account when finding a snap point.
if (mState == WHEEL_SCROLL) {
startPosition = mAnimation->AsWheelScrollAnimation()->GetDestination();
} else if (mState == SMOOTH_SCROLL) {
startPosition = mAnimation->AsSmoothScrollAnimation()->GetDestination();
} else if (mState == KEYBOARD_SCROLL) {
startPosition = mAnimation->AsKeyboardScrollAnimation()->GetDestination();
}
- if (MaybeAdjustDeltaForScrollSnapping(aEvent, delta, startPosition)) {
+ if (MaybeAdjustDeltaForScrollSnapping(aEvent, deltaInDevicePixels,
+ startPosition)) {
// If we're scroll snapping, use a smooth scroll animation to get
// the desired physics. Note that SmoothScrollTo() will re-use an
// existing smooth scroll animation if there is one.
APZC_LOG("%p wheel scrolling to snap point %s\n", this, Stringify(startPosition).c_str());
SmoothScrollTo(startPosition);
break;
}
@@ -2133,17 +2221,17 @@ nsEventStatus AsyncPanZoomController::On
SetState(WHEEL_SCROLL);
nsPoint initialPosition = CSSPoint::ToAppUnits(mFrameMetrics.GetScrollOffset());
StartAnimation(new WheelScrollAnimation(
*this, initialPosition, aEvent.mDeltaType));
}
nsPoint deltaInAppUnits =
- CSSPoint::ToAppUnits(delta / mFrameMetrics.GetZoom());
+ CSSPoint::ToAppUnits(deltaInDevicePixels / mFrameMetrics.GetZoom());
// Convert velocity from ParentLayerPoints/ms to ParentLayerPoints/s and
// then to appunits/second.
nsPoint velocity =
CSSPoint::ToAppUnits(
ParentLayerPoint(mX.GetVelocity() * 1000.0f,
mY.GetVelocity() * 1000.0f) /
mFrameMetrics.GetZoom());
--- a/gfx/layers/apz/src/AsyncPanZoomController.h
+++ b/gfx/layers/apz/src/AsyncPanZoomController.h
@@ -58,16 +58,17 @@ class OverscrollHandoffChain;
struct OverscrollHandoffState;
class StateChangeNotificationBlocker;
class CheckerboardEvent;
class OverscrollEffectBase;
class WidgetOverscrollEffect;
class GenericOverscrollEffect;
class AndroidSpecificState;
struct KeyboardScrollAction;
+struct WheelDeltaAndMultiplier;
// Base class for grouping platform-specific APZC state variables.
class PlatformSpecificStateBase {
public:
virtual ~PlatformSpecificStateBase() {}
virtual AndroidSpecificState* AsAndroidSpecificState() { return nullptr; }
};
@@ -467,16 +468,20 @@ public:
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 CanScroll(const ParentLayerPoint& aDelta) const;
+
+ // Return whether or not a scroll delta will be able to scroll in either
+ // direction withe wheel.
bool CanScrollWithWheel(const ParentLayerPoint& aDelta) const;
// Return whether or not there is room to scroll this APZC
// in the given direction.
bool CanScroll(ScrollDirection aDirection) const;
/**
* Convert a point on the scrollbar from this APZC's ParentLayer coordinates
@@ -551,17 +556,34 @@ protected:
nsEventStatus OnPanMomentumEnd(const PanGestureInput& aEvent);
nsEventStatus HandleEndOfPan();
/**
* Helper methods for handling scroll wheel events.
*/
nsEventStatus OnScrollWheel(const ScrollWheelInput& aEvent);
- ParentLayerPoint GetScrollWheelDelta(const ScrollWheelInput& aEvent) const;
+ /**
+ * Gets the scroll wheel delta's values in device pixels from the original
+ * delta's value of a wheel input.
+ */
+ ParentLayerPoint GetScrollWheelDeltaInDevicePixels(
+ const ScrollWheelInput& aEvent) const;
+
+ /**
+ * This function is like GetScrollWheelDeltaInDevicePixels(aEvent).
+ * The difference is |aWheelDeltaAndMultiplier| provide values as alternatives
+ * to the original wheel input's values for caculating the delta's values in
+ * device pixels, so |aEvent|'s delta values are ignored, we only use some
+ * other member variables and functions of |aEvent|.
+ */
+ ParentLayerPoint
+ GetScrollWheelDeltaInDevicePixels(
+ const ScrollWheelInput& aEvent,
+ const WheelDeltaAndMultiplier& aWheelDeltaAndMultiplier) const;
/**
* Helper methods for handling keyboard events.
*/
nsEventStatus OnKeyboard(const KeyboardInput& aEvent);
CSSPoint GetKeyboardDestination(const KeyboardScrollAction& aAction) const;
--- a/gfx/layers/apz/src/Axis.cpp
+++ b/gfx/layers/apz/src/Axis.cpp
@@ -540,16 +540,29 @@ ScreenPoint AxisX::MakePoint(ScreenCoord
return ScreenPoint(aCoord, 0);
}
const char* AxisX::Name() const
{
return "X";
}
+bool AxisX::CanScrollTo(Side aSide) const
+{
+ switch (aSide) {
+ case Side::eLeft:
+ return CanScroll(-COORDINATE_EPSILON * 2);
+ case Side::eRight:
+ return CanScroll(COORDINATE_EPSILON * 2);
+ default:
+ MOZ_ASSERT_UNREACHABLE("aSide is out of range of enum");
+ return false;
+ }
+}
+
OverscrollBehavior AxisX::GetOverscrollBehavior() const
{
return GetScrollMetadata().GetOverscrollBehavior().mBehaviorX;
}
AxisY::AxisY(AsyncPanZoomController* aAsyncPanZoomController)
: Axis(aAsyncPanZoomController)
{
@@ -581,15 +594,28 @@ ScreenPoint AxisY::MakePoint(ScreenCoord
return ScreenPoint(0, aCoord);
}
const char* AxisY::Name() const
{
return "Y";
}
+bool AxisY::CanScrollTo(Side aSide) const
+{
+ switch (aSide) {
+ case Side::eTop:
+ return CanScroll(-COORDINATE_EPSILON * 2);
+ case Side::eBottom:
+ return CanScroll(COORDINATE_EPSILON * 2);
+ default:
+ MOZ_ASSERT_UNREACHABLE("aSide is out of range of enum");
+ return false;
+ }
+}
+
OverscrollBehavior AxisY::GetOverscrollBehavior() const
{
return GetScrollMetadata().GetOverscrollBehavior().mBehaviorY;
}
} // namespace layers
} // namespace mozilla
--- a/gfx/layers/apz/src/Axis.h
+++ b/gfx/layers/apz/src/Axis.h
@@ -308,29 +308,41 @@ class AxisX : public Axis {
public:
explicit AxisX(AsyncPanZoomController* mAsyncPanZoomController);
virtual ParentLayerCoord GetPointOffset(const ParentLayerPoint& aPoint) const override;
virtual ParentLayerCoord GetRectLength(const ParentLayerRect& aRect) const override;
virtual ParentLayerCoord GetRectOffset(const ParentLayerRect& aRect) const override;
virtual CSSToParentLayerScale GetScaleForAxis(const CSSToParentLayerScale2D& aScale) const override;
virtual ScreenPoint MakePoint(ScreenCoord aCoord) const override;
virtual const char* Name() const override;
+ enum class Side
+ {
+ eLeft,
+ eRight,
+ };
+ bool CanScrollTo(Side aSide) const;
private:
virtual OverscrollBehavior GetOverscrollBehavior() const override;
};
class AxisY : public Axis {
public:
explicit AxisY(AsyncPanZoomController* mAsyncPanZoomController);
virtual ParentLayerCoord GetPointOffset(const ParentLayerPoint& aPoint) const override;
virtual ParentLayerCoord GetRectLength(const ParentLayerRect& aRect) const override;
virtual ParentLayerCoord GetRectOffset(const ParentLayerRect& aRect) const override;
virtual CSSToParentLayerScale GetScaleForAxis(const CSSToParentLayerScale2D& aScale) const override;
virtual ScreenPoint MakePoint(ScreenCoord aCoord) const override;
virtual const char* Name() const override;
+ enum class Side
+ {
+ eTop,
+ eBottom,
+ };
+ bool CanScrollTo(Side aSide) const;
private:
virtual OverscrollBehavior GetOverscrollBehavior() const override;
};
} // namespace layers
} // namespace mozilla
#endif
new file mode 100644
--- /dev/null
+++ b/gfx/layers/apz/src/WheelDeltaSmartizer.h
@@ -0,0 +1,120 @@
+/* -*- 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/. */
+
+#ifndef __mozilla_layers_WheelDeltaSmartizer_h__
+#define __mozilla_layers_WheelDeltaSmartizer_h__
+
+#include "Axis.h" // for AxisX, AxisY
+#include "mozilla/WheelHandlingHelper.h" // for WheelDeltaSmartizer
+
+namespace mozilla {
+namespace layers {
+
+struct MOZ_STACK_CLASS WheelDeltaAndMultiplier final
+{
+ explicit
+ WheelDeltaAndMultiplier(double aDeltaX,
+ double aDeltaY,
+ double aDeltaMultiplierX,
+ double aDeltaMultiplierY)
+ : mDeltaX(aDeltaX)
+ , mDeltaY(aDeltaY)
+ , mDeltaMultiplierX(aDeltaMultiplierX)
+ , mDeltaMultiplierY(aDeltaMultiplierY)
+ {
+ }
+
+ double mDeltaX;
+ double mDeltaY;
+ double mDeltaMultiplierX;
+ double mDeltaMultiplierY;
+};
+
+/**
+ * About WheelDeltaSmartizer:
+ * For a smart wheel scroll, there's some situations where we should adjust a
+ * wheel event's delta values and their multiplier values. WheelDeltaSmartizer
+ * converts a regular delta and their multiplier values for smart scrolling. A
+ * smart wheel scroll lets the user scroll a frame with only one scrollbar,
+ * using either a vertical or a horzizontal wheel.
+ *
+ * This is the APZ implementation for WheelDeltaSmartizer.
+ */
+class MOZ_STACK_CLASS APZWheelDeltaSmartizer final: public WheelDeltaSmartizer
+{
+public:
+ /**
+ * @param aWheelDeltaAndMultiplier
+ * The delta and its multiplier for a wheel event
+ * whose delta values will be adjusted upon calling
+ * smartize() if ShouldBeSmartized() returns true.
+ * @param aAxisX The X axis information provider for the current
+ * frame, such as whether the frame can be scrolled
+ * horizontally, leftwards or rightwards.
+ * @param aAxisY The Y axis information provider for the current
+ * frame, such as whether the frame can be scrolled
+ * vertically, upwards or downwards.
+ * @param aIsHorizontalContentRightToLeft
+ * Indicats whether the current frame's horizontal
+ * contents starts at rightside. For more
+ * information, refer to the comment of
+ * IsHorizontalContentRightToLeft() for the base
+ * class WheelDeltaSmartizer.
+ */
+ explicit
+ APZWheelDeltaSmartizer(WheelDeltaAndMultiplier& aWheelDeltaAndMultiplier,
+ const AxisX& aAxisX,
+ const AxisY& aAxisY,
+ bool aIsHorizontalContentRightToLeft)
+ : WheelDeltaSmartizer(aWheelDeltaAndMultiplier.mDeltaX,
+ aWheelDeltaAndMultiplier.mDeltaY,
+ aWheelDeltaAndMultiplier.mDeltaMultiplierX,
+ aWheelDeltaAndMultiplier.mDeltaMultiplierY)
+ , mAxisX(aAxisX)
+ , mAxisY(aAxisY)
+ , mIsHorizontalContentRightToLeft(aIsHorizontalContentRightToLeft)
+ {
+ }
+
+private:
+ virtual bool CanScrollAlongXAxis() const override
+ {
+ return mAxisX.CanScroll();
+ }
+ virtual bool CanScrollAlongYAxis() const override
+ {
+ return mAxisY.CanScroll();
+ }
+ virtual bool CanScrollUpwards() const override
+ {
+ return mAxisY.CanScrollTo(AxisY::Side::eTop);
+ }
+ virtual bool CanScrollDownwards() const override
+ {
+ return mAxisY.CanScrollTo(AxisY::Side::eBottom);
+ }
+ virtual bool CanScrollLeftwards() const override
+ {
+ return mAxisX.CanScrollTo(AxisX::Side::eLeft);
+ }
+ virtual bool CanScrollRightwards() const override
+ {
+ return mAxisX.CanScrollTo(AxisX::Side::eRight);
+ }
+ virtual bool IsHorizontalContentRightToLeft() const override
+ {
+ return mIsHorizontalContentRightToLeft;
+ }
+
+ const AxisX& mAxisX;
+ const AxisY& mAxisY;
+ bool mIsHorizontalContentRightToLeft;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // __mozilla_layers_WheelDeltaSmartizer_h__
--- a/gfx/layers/apz/test/gtest/InputUtils.h
+++ b/gfx/layers/apz/test/gtest/InputUtils.h
@@ -244,28 +244,28 @@ PinchWithTouchInputAndCheckStatus(const
template<class InputReceiver>
nsEventStatus
Wheel(const RefPtr<InputReceiver>& aTarget, const ScreenIntPoint& aPoint,
const ScreenPoint& aDelta, TimeStamp aTime, uint64_t* aOutInputBlockId = nullptr)
{
ScrollWheelInput input(MillisecondsSinceStartup(aTime), aTime, 0,
ScrollWheelInput::SCROLLMODE_INSTANT, ScrollWheelInput::SCROLLDELTA_PIXEL,
- aPoint, aDelta.x, aDelta.y, false);
+ aPoint, aDelta.x, aDelta.y, false, false);
return aTarget->ReceiveInputEvent(input, nullptr, aOutInputBlockId);
}
template<class InputReceiver>
nsEventStatus
SmoothWheel(const RefPtr<InputReceiver>& aTarget, const ScreenIntPoint& aPoint,
const ScreenPoint& aDelta, TimeStamp aTime, uint64_t* aOutInputBlockId = nullptr)
{
ScrollWheelInput input(MillisecondsSinceStartup(aTime), aTime, 0,
ScrollWheelInput::SCROLLMODE_SMOOTH, ScrollWheelInput::SCROLLDELTA_LINE,
- aPoint, aDelta.x, aDelta.y, false);
+ aPoint, aDelta.x, aDelta.y, false, false);
return aTarget->ReceiveInputEvent(input, nullptr, aOutInputBlockId);
}
template<class InputReceiver>
nsEventStatus
MouseDown(const RefPtr<InputReceiver>& aTarget, const ScreenIntPoint& aPoint,
TimeStamp aTime, uint64_t* aOutInputBlockId = nullptr)
{
--- a/gfx/layers/apz/test/gtest/TestHitTesting.cpp
+++ b/gfx/layers/apz/test/gtest/TestHitTesting.cpp
@@ -470,17 +470,17 @@ TEST_F(APZHitTestingTester, TestRepaintF
manager->UpdateHitTestingTree(0, root, false, 0, 0);
TestAsyncPanZoomController* apzcroot = ApzcOf(root);
EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(AtLeast(3));
ScreenPoint origin(100, 50);
for (int i = 0; i < 3; i++) {
ScrollWheelInput swi(MillisecondsSinceStartup(mcc->Time()), mcc->Time(), 0,
ScrollWheelInput::SCROLLMODE_INSTANT, ScrollWheelInput::SCROLLDELTA_PIXEL,
- origin, 0, 10, false);
+ origin, 0, 10, false, false);
EXPECT_EQ(nsEventStatus_eConsumeDoDefault, manager->ReceiveInputEvent(swi, nullptr, nullptr));
EXPECT_EQ(origin, swi.mOrigin);
AsyncTransform viewTransform;
ParentLayerPoint point;
apzcroot->SampleContentTransformForFrame(&viewTransform, point);
EXPECT_EQ(0, point.x);
EXPECT_EQ((i + 1) * 10, point.y);
@@ -496,17 +496,17 @@ TEST_F(APZHitTestingTester, TestForceDis
DisableApzOn(root);
ScopedLayerTreeRegistration registration(manager, 0, root, mcc);
manager->UpdateHitTestingTree(0, root, false, 0, 0);
TestAsyncPanZoomController* apzcroot = ApzcOf(root);
ScreenPoint origin(100, 50);
ScrollWheelInput swi(MillisecondsSinceStartup(mcc->Time()), mcc->Time(), 0,
ScrollWheelInput::SCROLLMODE_INSTANT, ScrollWheelInput::SCROLLDELTA_PIXEL,
- origin, 0, 10, false);
+ origin, 0, 10, false, false);
EXPECT_EQ(nsEventStatus_eConsumeDoDefault, manager->ReceiveInputEvent(swi, nullptr, nullptr));
EXPECT_EQ(origin, swi.mOrigin);
AsyncTransform viewTransform;
ParentLayerPoint point;
apzcroot->SampleContentTransformForFrame(&viewTransform, point);
// Since APZ is force-disabled, we expect to see the async transform via
// the NORMAL AsyncMode, but not via the RESPECT_FORCE_DISABLE AsyncMode.
@@ -523,17 +523,17 @@ TEST_F(APZHitTestingTester, TestForceDis
mcc->AdvanceByMillis(10);
// With untransforming events we should get normal behaviour (in this case,
// no noticeable untransform, because the repaint request already got
// flushed).
swi = ScrollWheelInput(MillisecondsSinceStartup(mcc->Time()), mcc->Time(), 0,
ScrollWheelInput::SCROLLMODE_INSTANT, ScrollWheelInput::SCROLLDELTA_PIXEL,
- origin, 0, 0, false);
+ origin, 0, 0, false, false);
EXPECT_EQ(nsEventStatus_eConsumeDoDefault, manager->ReceiveInputEvent(swi, nullptr, nullptr));
EXPECT_EQ(origin, swi.mOrigin);
}
TEST_F(APZHitTestingTester, Bug1148350) {
CreateBug1148350LayerTree();
ScopedLayerTreeRegistration registration(manager, 0, root, mcc);
manager->UpdateHitTestingTree(0, root, false, 0, 0);
--- a/gfx/layers/apz/test/gtest/TestTreeManager.cpp
+++ b/gfx/layers/apz/test/gtest/TestTreeManager.cpp
@@ -99,14 +99,14 @@ TEST_F(APZCTreeManagerTester, Bug1198900
// crash.
CreateSimpleDTCScrollingLayer();
ScopedLayerTreeRegistration registration(manager, 0, root, mcc);
manager->UpdateHitTestingTree(0, root, false, 0, 0);
ScreenPoint origin(100, 50);
ScrollWheelInput swi(MillisecondsSinceStartup(mcc->Time()), mcc->Time(), 0,
ScrollWheelInput::SCROLLMODE_INSTANT, ScrollWheelInput::SCROLLDELTA_PIXEL,
- origin, 0, 10, false);
+ origin, 0, 10, false, false);
uint64_t blockId;
manager->ReceiveInputEvent(swi, nullptr, &blockId);
manager->ContentReceivedInputBlock(blockId, /* preventDefault= */ true);
}
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -2782,34 +2782,37 @@ pref("mousewheel.acceleration.factor", 1
// settings, the override isn't executed.
pref("mousewheel.system_scroll_override_on_root_content.vertical.factor", 200);
pref("mousewheel.system_scroll_override_on_root_content.horizontal.factor", 200);
// mousewheel.*.action can specify the action when you use mosue wheel.
// When no modifier keys are pressed or two or more modifires are pressed,
// .default is used.
// 0: Nothing happens
-// 1: Scrolling contents
+// 1: Scrolling contents smartly, that is, you can scroll a target in the
+// direction orthogonal to the wheel if there's no scrollbar in the wheel's
+// direction but a scrollbar in the wheel's orthogonal direction
// 2: Go back or go forward, in your history
// 3: Zoom in or out.
// 4: Treat vertical wheel as horizontal scroll
// This treats vertical wheel operation (i.e., deltaY) as horizontal
// scroll. deltaX and deltaZ are always ignored. So, only
// "delta_multiplier_y" pref affects the scroll speed.
+// 5: Scroll contents
pref("mousewheel.default.action", 1);
pref("mousewheel.with_alt.action", 2);
pref("mousewheel.with_control.action", 3);
pref("mousewheel.with_meta.action", 1); // command key on Mac
pref("mousewheel.with_shift.action", 4);
pref("mousewheel.with_win.action", 1);
// mousewheel.*.action.override_x will override the action
// when the mouse wheel is rotated along the x direction.
// -1: Don't override the action.
-// 0 to 3: Override the action with the specified value.
+// 0 to 3, or 5: Override the action with the specified value.
// Note that 4 isn't available because it doesn't make sense to apply the
// default action only for y direction to this pref.
pref("mousewheel.default.action.override_x", -1);
pref("mousewheel.with_alt.action.override_x", -1);
pref("mousewheel.with_control.action.override_x", -1);
pref("mousewheel.with_meta.action.override_x", -1); // command key on Mac
pref("mousewheel.with_shift.action.override_x", -1);
pref("mousewheel.with_win.action.override_x", -1);
--- a/widget/InputData.cpp
+++ b/widget/InputData.cpp
@@ -666,32 +666,34 @@ ScrollWheelInput::ScrollWheelInput()
{
}
ScrollWheelInput::ScrollWheelInput(uint32_t aTime, TimeStamp aTimeStamp,
Modifiers aModifiers, ScrollMode aScrollMode,
ScrollDeltaType aDeltaType,
const ScreenPoint& aOrigin, double aDeltaX,
double aDeltaY,
- bool aAllowToOverrideSystemScrollSpeed)
+ bool aAllowToOverrideSystemScrollSpeed,
+ bool aIsSmart)
: InputData(SCROLLWHEEL_INPUT, aTime, aTimeStamp, aModifiers)
, mDeltaType(aDeltaType)
, mScrollMode(aScrollMode)
, mOrigin(aOrigin)
, mHandledByAPZ(false)
, mDeltaX(aDeltaX)
, mDeltaY(aDeltaY)
, mLineOrPageDeltaX(0)
, mLineOrPageDeltaY(0)
, mScrollSeriesNumber(0)
, mUserDeltaMultiplierX(1.0)
, mUserDeltaMultiplierY(1.0)
, mMayHaveMomentum(false)
, mIsMomentum(false)
, mAllowToOverrideSystemScrollSpeed(aAllowToOverrideSystemScrollSpeed)
+ , mIsSmart(aIsSmart)
{
}
ScrollWheelInput::ScrollWheelInput(const WidgetWheelEvent& aWheelEvent)
: InputData(SCROLLWHEEL_INPUT, aWheelEvent.mTime, aWheelEvent.mTimeStamp,
aWheelEvent.mModifiers)
, mDeltaType(DeltaTypeForDeltaMode(aWheelEvent.mDeltaMode))
, mScrollMode(SCROLLMODE_INSTANT)
@@ -702,16 +704,17 @@ ScrollWheelInput::ScrollWheelInput(const
, mLineOrPageDeltaY(aWheelEvent.mLineOrPageDeltaY)
, mScrollSeriesNumber(0)
, mUserDeltaMultiplierX(1.0)
, mUserDeltaMultiplierY(1.0)
, mMayHaveMomentum(aWheelEvent.mMayHaveMomentum)
, mIsMomentum(aWheelEvent.mIsMomentum)
, mAllowToOverrideSystemScrollSpeed(
aWheelEvent.mAllowToOverrideSystemScrollSpeed)
+ , mIsSmart(false)
{
mOrigin =
ScreenPoint(ViewAs<ScreenPixel>(aWheelEvent.mRefPoint,
PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
}
ScrollWheelInput::ScrollDeltaType
ScrollWheelInput::DeltaTypeForDeltaMode(uint32_t aDeltaMode)
--- a/widget/InputData.h
+++ b/widget/InputData.h
@@ -528,17 +528,17 @@ public:
SCROLLMODE_INSTANT,
SCROLLMODE_SMOOTH
)
);
ScrollWheelInput(uint32_t aTime, TimeStamp aTimeStamp, Modifiers aModifiers,
ScrollMode aScrollMode, ScrollDeltaType aDeltaType,
const ScreenPoint& aOrigin, double aDeltaX, double aDeltaY,
- bool aAllowToOverrideSystemScrollSpeed);
+ bool aAllowToOverrideSystemScrollSpeed, bool aIsSmart);
explicit ScrollWheelInput(const WidgetWheelEvent& aEvent);
static ScrollDeltaType DeltaTypeForDeltaMode(uint32_t aDeltaMode);
static uint32_t DeltaModeForDeltaType(ScrollDeltaType aDeltaType);
static nsIScrollableFrame::ScrollUnit ScrollUnitForDeltaType(ScrollDeltaType aDeltaType);
WidgetWheelEvent ToWidgetWheelEvent(nsIWidget* aWidget) const;
bool TransformToLocal(const ScreenToParentLayerMatrix4x4& aTransform);
@@ -578,16 +578,18 @@ public:
// User-set delta multipliers.
double mUserDeltaMultiplierX;
double mUserDeltaMultiplierY;
bool mMayHaveMomentum;
bool mIsMomentum;
bool mAllowToOverrideSystemScrollSpeed;
+
+ bool mIsSmart;
};
class KeyboardInput : public InputData
{
public:
typedef mozilla::layers::KeyboardScrollAction KeyboardScrollAction;
enum KeyboardEventType
--- a/widget/MouseEvents.h
+++ b/widget/MouseEvents.h
@@ -508,17 +508,17 @@ private:
, mLineOrPageDeltaY(0)
, mScrollType(SCROLL_DEFAULT)
, mCustomizedByUserPrefs(false)
, mIsMomentum(false)
, mIsNoLineOrPageDelta(false)
, mViewPortIsOverscrolled(false)
, mCanTriggerSwipe(false)
, mAllowToOverrideSystemScrollSpeed(false)
- , mDeltaValuesAdjustedForDefaultHandler(false)
+ , mDeltaValuesHorizontalizedForDefaultHandler(false)
{
}
public:
virtual WidgetWheelEvent* AsWheelEvent() override { return this; }
WidgetWheelEvent(bool aIsTrusted, EventMessage aMessage, nsIWidget* aWidget)
: WidgetMouseEventBase(aIsTrusted, aMessage, aWidget, eWheelEventClass)
@@ -533,17 +533,17 @@ public:
, mScrollType(SCROLL_DEFAULT)
, mCustomizedByUserPrefs(false)
, mMayHaveMomentum(false)
, mIsMomentum(false)
, mIsNoLineOrPageDelta(false)
, mViewPortIsOverscrolled(false)
, mCanTriggerSwipe(false)
, mAllowToOverrideSystemScrollSpeed(true)
- , mDeltaValuesAdjustedForDefaultHandler(false)
+ , mDeltaValuesHorizontalizedForDefaultHandler(false)
{
}
virtual WidgetEvent* Duplicate() const override
{
MOZ_ASSERT(mClass == eWheelEventClass,
"Duplicate() must be overridden by sub class");
// Not copying widget, it is a weak reference.
@@ -651,19 +651,19 @@ public:
// viewport.
bool mCanTriggerSwipe;
// If mAllowToOverrideSystemScrollSpeed is true, the scroll speed may be
// overridden. Otherwise, the scroll speed won't be overridden even if
// it's enabled by the pref.
bool mAllowToOverrideSystemScrollSpeed;
- // While default handler handles a wheel event specially (e.g., treating
- // mDeltaY as horizontal scroll), this is set to true.
- bool mDeltaValuesAdjustedForDefaultHandler;
+ // While default handler handles a *pure* vertical wheel event by treating
+ // mDeltaY as horizontal scroll, this is set to true.
+ bool mDeltaValuesHorizontalizedForDefaultHandler;
void AssignWheelEventData(const WidgetWheelEvent& aEvent, bool aCopyTargets)
{
AssignMouseEventBaseData(aEvent, aCopyTargets);
mDeltaX = aEvent.mDeltaX;
mDeltaY = aEvent.mDeltaY;
mDeltaZ = aEvent.mDeltaZ;
@@ -676,18 +676,18 @@ public:
mLineOrPageDeltaY = aEvent.mLineOrPageDeltaY;
mScrollType = aEvent.mScrollType;
mOverflowDeltaX = aEvent.mOverflowDeltaX;
mOverflowDeltaY = aEvent.mOverflowDeltaY;
mViewPortIsOverscrolled = aEvent.mViewPortIsOverscrolled;
mCanTriggerSwipe = aEvent.mCanTriggerSwipe;
mAllowToOverrideSystemScrollSpeed =
aEvent.mAllowToOverrideSystemScrollSpeed;
- mDeltaValuesAdjustedForDefaultHandler =
- aEvent.mDeltaValuesAdjustedForDefaultHandler;
+ mDeltaValuesHorizontalizedForDefaultHandler =
+ aEvent.mDeltaValuesHorizontalizedForDefaultHandler;
}
// System scroll speed settings may be too slow at using Gecko. In such
// case, we should override the scroll speed computed with system settings.
// Following methods return preferred delta values which are multiplied by
// factors specified by prefs. If system scroll speed shouldn't be
// overridden (e.g., this feature is disabled by pref), they return raw
// delta values.
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -478,16 +478,22 @@ public:
aVScroll = -aVScroll;
}
ScrollWheelInput input(aTime, GetEventTimeStamp(aTime), GetModifiers(aMetaState),
ScrollWheelInput::SCROLLMODE_SMOOTH,
ScrollWheelInput::SCROLLDELTA_PIXEL,
origin,
aHScroll, aVScroll,
+ false,
+ // XXX Do we need to support smart scroll for
+ // Android widgets with a wheel device?
+ // Currently, I just keep it unimplemented. If we
+ // need to implement it, what's the extra work we
+ // should do?
false);
ScrollableLayerGuid guid;
uint64_t blockId;
nsEventStatus status = controller->ReceiveInputEvent(input, &guid, &blockId);
if (status == nsEventStatus_eConsumeNoDefault) {
return true;
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -5029,32 +5029,44 @@ GetIntegerDeltaForEvent(NSEvent* aEvent)
} else if (usePreciseDeltas) {
// This is on 10.6 or old touchpads that don't have any phase information.
ScrollWheelInput wheelEvent(eventIntervalTime, eventTimeStamp, modifiers,
ScrollWheelInput::SCROLLMODE_INSTANT,
ScrollWheelInput::SCROLLDELTA_PIXEL,
position,
preciseDelta.x,
preciseDelta.y,
+ false,
+ // XXX Do we need to support smart scrolling for
+ // iOS widgets with a wheel device? Currently, I
+ // just keep it unimplemented. If we need to
+ // implement it, what's the extra work we should
+ // do?
false);
wheelEvent.mLineOrPageDeltaX = lineOrPageDelta.x;
wheelEvent.mLineOrPageDeltaY = lineOrPageDelta.y;
wheelEvent.mIsMomentum = nsCocoaUtils::IsMomentumScrollEvent(theEvent);
geckoChildDeathGrip->DispatchAPZWheelInputEvent(wheelEvent, false);
} else {
ScrollWheelInput::ScrollMode scrollMode = ScrollWheelInput::SCROLLMODE_INSTANT;
if (gfxPrefs::SmoothScrollEnabled() && gfxPrefs::WheelSmoothScrollEnabled()) {
scrollMode = ScrollWheelInput::SCROLLMODE_SMOOTH;
}
ScrollWheelInput wheelEvent(eventIntervalTime, eventTimeStamp, modifiers,
scrollMode,
ScrollWheelInput::SCROLLDELTA_LINE,
position,
lineOrPageDelta.x,
lineOrPageDelta.y,
+ false,
+ // XXX Do we need to support smart scrolling for
+ // iOS widgets with a wheel device? Currently, I
+ // just keep it unimplemented. If we need to
+ // implement it, what's the extra work we should
+ // do?
false);
wheelEvent.mLineOrPageDeltaX = lineOrPageDelta.x;
wheelEvent.mLineOrPageDeltaY = lineOrPageDelta.y;
geckoChildDeathGrip->DispatchAPZWheelInputEvent(wheelEvent, false);
}
NS_OBJC_END_TRY_ABORT_BLOCK;
}
--- a/widget/nsGUIEventIPC.h
+++ b/widget/nsGUIEventIPC.h
@@ -182,17 +182,17 @@ struct ParamTraits<mozilla::WidgetWheelE
WriteParam(aMsg, aParam.mLineOrPageDeltaX);
WriteParam(aMsg, aParam.mLineOrPageDeltaY);
WriteParam(aMsg, static_cast<uint8_t>(aParam.mScrollType));
WriteParam(aMsg, aParam.mOverflowDeltaX);
WriteParam(aMsg, aParam.mOverflowDeltaY);
WriteParam(aMsg, aParam.mViewPortIsOverscrolled);
WriteParam(aMsg, aParam.mCanTriggerSwipe);
WriteParam(aMsg, aParam.mAllowToOverrideSystemScrollSpeed);
- WriteParam(aMsg, aParam.mDeltaValuesAdjustedForDefaultHandler);
+ WriteParam(aMsg, aParam.mDeltaValuesHorizontalizedForDefaultHandler);
}
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
{
uint8_t scrollType = 0;
bool rv =
ReadParam(aMsg, aIter,
static_cast<mozilla::WidgetMouseEventBase*>(aResult)) &&
@@ -207,17 +207,18 @@ struct ParamTraits<mozilla::WidgetWheelE
ReadParam(aMsg, aIter, &aResult->mLineOrPageDeltaX) &&
ReadParam(aMsg, aIter, &aResult->mLineOrPageDeltaY) &&
ReadParam(aMsg, aIter, &scrollType) &&
ReadParam(aMsg, aIter, &aResult->mOverflowDeltaX) &&
ReadParam(aMsg, aIter, &aResult->mOverflowDeltaY) &&
ReadParam(aMsg, aIter, &aResult->mViewPortIsOverscrolled) &&
ReadParam(aMsg, aIter, &aResult->mCanTriggerSwipe) &&
ReadParam(aMsg, aIter, &aResult->mAllowToOverrideSystemScrollSpeed) &&
- ReadParam(aMsg, aIter, &aResult->mDeltaValuesAdjustedForDefaultHandler);
+ ReadParam(aMsg, aIter,
+ &aResult->mDeltaValuesHorizontalizedForDefaultHandler);
aResult->mScrollType =
static_cast<mozilla::WidgetWheelEvent::ScrollType>(scrollType);
return rv;
}
};
template<>
struct ParamTraits<mozilla::WidgetPointerHelper>
@@ -1333,16 +1334,17 @@ struct ParamTraits<mozilla::ScrollWheelI
WriteParam(aMsg, aParam.mLineOrPageDeltaX);
WriteParam(aMsg, aParam.mLineOrPageDeltaY);
WriteParam(aMsg, aParam.mScrollSeriesNumber);
WriteParam(aMsg, aParam.mUserDeltaMultiplierX);
WriteParam(aMsg, aParam.mUserDeltaMultiplierY);
WriteParam(aMsg, aParam.mMayHaveMomentum);
WriteParam(aMsg, aParam.mIsMomentum);
WriteParam(aMsg, aParam.mAllowToOverrideSystemScrollSpeed);
+ WriteParam(aMsg, aParam.mIsSmart);
}
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
{
return ReadParam(aMsg, aIter, static_cast<mozilla::InputData*>(aResult)) &&
ReadParam(aMsg, aIter, &aResult->mDeltaType) &&
ReadParam(aMsg, aIter, &aResult->mScrollMode) &&
ReadParam(aMsg, aIter, &aResult->mOrigin) &&
@@ -1353,16 +1355,17 @@ struct ParamTraits<mozilla::ScrollWheelI
ReadParam(aMsg, aIter, &aResult->mLineOrPageDeltaX) &&
ReadParam(aMsg, aIter, &aResult->mLineOrPageDeltaY) &&
ReadParam(aMsg, aIter, &aResult->mScrollSeriesNumber) &&
ReadParam(aMsg, aIter, &aResult->mUserDeltaMultiplierX) &&
ReadParam(aMsg, aIter, &aResult->mUserDeltaMultiplierY) &&
ReadParam(aMsg, aIter, &aResult->mMayHaveMomentum) &&
ReadParam(aMsg, aIter, &aResult->mIsMomentum) &&
ReadParam(aMsg, aIter, &aResult->mAllowToOverrideSystemScrollSpeed);
+ ReadParam(aMsg, aIter, &aResult->mIsSmart);
}
};
template <>
struct ParamTraits<mozilla::KeyboardInput::KeyboardEventType>
: public ContiguousEnumSerializer<
mozilla::KeyboardInput::KeyboardEventType,
mozilla::KeyboardInput::KeyboardEventType::KEY_DOWN,