author | Masayuki Nakano <masayuki@d-toybox.com> |
Thu, 05 Oct 2017 01:12:35 +0900 | |
changeset 386886 | 63b547bb4078856412876ffa40117a669ab20fde |
parent 386885 | 4d48f13d3d7f6a0921f3df09235812c858728782 |
child 386887 | c05495fc2b5144f1580f123bbf2d412f24172952 |
push id | 32704 |
push user | archaeopteryx@coole-files.de |
push date | Wed, 18 Oct 2017 22:05:23 +0000 |
treeherder | mozilla-central@a04860cd9c88 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | smaug |
bugs | 143038 |
milestone | 58.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -615,35 +615,42 @@ pref("browser.gesture.twist.end", "cmd_g pref("browser.gesture.tap", "cmd_fullZoomReset"); pref("browser.snapshots.limit", 0); // 0: Nothing happens // 1: Scrolling contents // 2: Go back or go forward, in your history // 3: Zoom in or out. +// 4: Treat vertical wheel as horizontal scroll #ifdef XP_MACOSX -// On OS X, if the wheel has one axis only, shift+wheel comes through as a +// 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); -pref("mousewheel.with_shift.action", 1); // 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 // acceleration is the best modifier for zoom-in/out. However, we should keep // the control key setting for backward compatibility. pref("mousewheel.with_meta.action", 3); // command key on Mac -// Disable control-/meta-modified horizontal mousewheel events, since -// those are used on Mac as part of modified swipe gestures (e.g. -// Left swipe+Cmd = go back in a new tab). +// Disable control-/meta-modified horizontal wheel events, since those are +// used on Mac as part of modified swipe gestures (e.g. Left swipe+Cmd is +// "go back" in a new tab). pref("mousewheel.with_control.action.override_x", 0); pref("mousewheel.with_meta.action.override_x", 0); #else -pref("mousewheel.with_alt.action", 1); -pref("mousewheel.with_shift.action", 2); +// On the other platforms (non-macOS), user may use legacy mouse which supports +// only vertical wheel but want to scroll horizontally. For such users, we +// should provide horizontal scroll with shift+wheel (same as Chrome). +// However, shift+wheel was used for navigating history. For users who want +// to keep using this feature, let's enable it with alt+wheel. This is better +// for consistency with macOS users. +pref("mousewheel.with_shift.action", 4); +pref("mousewheel.with_alt.action", 2); pref("mousewheel.with_meta.action", 1); // win key on Win, Super/Hyper on Linux #endif pref("mousewheel.with_control.action",3); pref("mousewheel.with_win.action", 1); pref("browser.xul.error_pages.enabled", true); pref("browser.xul.error_pages.expert_bad_cert", false);
--- a/dom/events/EventStateManager.cpp +++ b/dom/events/EventStateManager.cpp @@ -3260,38 +3260,46 @@ EventStateManager::PostHandleEvent(nsPre MOZ_ASSERT(aEvent->IsTrusted()); if (*aStatus == nsEventStatus_eConsumeNoDefault) { ScrollbarsForWheel::Inactivate(); break; } WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent(); + MOZ_ASSERT(wheelEvent); + + // 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 + // 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); // 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); - - // When APZ is enabled, the actual scroll animation might be handled by - // the compositor. - WheelPrefs::Action action; if (pluginFrame) { MOZ_ASSERT(pluginFrame->WantsToHandleWheelEventAsDefaultAction()); action = WheelPrefs::ACTION_SEND_TO_PLUGIN; - } else if (wheelEvent->mFlags.mHandledByAPZ) { - action = WheelPrefs::ACTION_NONE; - } else { - action = WheelPrefs::GetInstance()->ComputeActionFor(wheelEvent); } + switch (action) { - case WheelPrefs::ACTION_SCROLL: { + case WheelPrefs::ACTION_SCROLL: + case WheelPrefs::ACTION_HORIZONTAL_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; @@ -5652,21 +5660,20 @@ EventStateManager::WheelPrefs::~WheelPre { Preferences::UnregisterPrefixCallback(OnPrefChanged, "mousewheel."); } void EventStateManager::WheelPrefs::Reset() { memset(mInit, 0, sizeof(mInit)); - } EventStateManager::WheelPrefs::Index -EventStateManager::WheelPrefs::GetIndexFor(WidgetWheelEvent* aEvent) +EventStateManager::WheelPrefs::GetIndexFor(const WidgetWheelEvent* aEvent) { if (!aEvent) { return INDEX_DEFAULT; } Modifiers modifiers = (aEvent->mModifiers & (MODIFIER_ALT | MODIFIER_CONTROL | @@ -5754,47 +5761,72 @@ EventStateManager::WheelPrefs::Init(Even NS_WARNING("Unsupported action pref value, replaced with 'Scroll'."); action = ACTION_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. prefNameAction.AppendLiteral(".override_x"); int32_t actionOverrideX = Preferences::GetInt(prefNameAction.get(), -1); - if (actionOverrideX < -1 || actionOverrideX > int32_t(ACTION_LAST)) { + if (actionOverrideX < -1 || actionOverrideX > int32_t(ACTION_LAST) || + actionOverrideX == ACTION_HORIZONTAL_SCROLL) { NS_WARNING("Unsupported action override pref value, didn't override."); actionOverrideX = -1; } mOverriddenActionsX[aIndex] = (actionOverrideX == -1) ? static_cast<Action>(action) : static_cast<Action>(actionOverrideX); } void +EventStateManager::WheelPrefs::GetMultiplierForDeltaXAndY( + const WidgetWheelEvent* aEvent, + Index aIndex, + double* aMultiplierForDeltaX, + 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 && + ComputeActionFor(aEvent) == ACTION_HORIZONTAL_SCROLL) { + std::swap(*aMultiplierForDeltaX, *aMultiplierForDeltaY); + } +} + +void EventStateManager::WheelPrefs::ApplyUserPrefsToDelta(WidgetWheelEvent* aEvent) { if (aEvent->mCustomizedByUserPrefs) { return; } Index index = GetIndexFor(aEvent); Init(index); - aEvent->mDeltaX *= mMultiplierX[index]; - aEvent->mDeltaY *= mMultiplierY[index]; + double multiplierForDeltaX = 1.0, multiplierForDeltaY = 1.0; + GetMultiplierForDeltaXAndY(aEvent, index, + &multiplierForDeltaX, &multiplierForDeltaY); + aEvent->mDeltaX *= multiplierForDeltaX; + aEvent->mDeltaY *= multiplierForDeltaY; aEvent->mDeltaZ *= mMultiplierZ[index]; // If the multiplier is 1.0 or -1.0, i.e., it doesn't change the absolute // value, we should use lineOrPageDelta values which were set by widget. // Otherwise, we need to compute them from accumulated delta values. if (!NeedToComputeLineOrPageDelta(aEvent)) { - aEvent->mLineOrPageDeltaX *= static_cast<int32_t>(mMultiplierX[index]); - aEvent->mLineOrPageDeltaY *= static_cast<int32_t>(mMultiplierY[index]); + aEvent->mLineOrPageDeltaX *= static_cast<int32_t>(multiplierForDeltaX); + aEvent->mLineOrPageDeltaY *= static_cast<int32_t>(multiplierForDeltaY); } else { aEvent->mLineOrPageDeltaX = 0; aEvent->mLineOrPageDeltaY = 0; } aEvent->mCustomizedByUserPrefs = ((mMultiplierX[index] != 1.0) || (mMultiplierY[index] != 1.0) || (mMultiplierZ[index] != 1.0)); @@ -5808,111 +5840,142 @@ EventStateManager::WheelPrefs::CancelApp Init(index); // XXX If the multiplier pref value is negative, the scroll direction was // changed and caused to scroll different direction. In such case, // this method reverts the sign of overflowDelta. Does it make widget // happy? Although, widget can know the pref applied delta values by // referrencing the deltaX and deltaY of the event. - if (mMultiplierX[index]) { - aEvent->mOverflowDeltaX /= mMultiplierX[index]; - } - if (mMultiplierY[index]) { - aEvent->mOverflowDeltaY /= mMultiplierY[index]; + double multiplierForDeltaX = 1.0, multiplierForDeltaY = 1.0; + GetMultiplierForDeltaXAndY(aEvent, index, + &multiplierForDeltaX, &multiplierForDeltaY); + if (multiplierForDeltaX) { + aEvent->mOverflowDeltaX /= multiplierForDeltaX; + } + if (multiplierForDeltaY) { + aEvent->mOverflowDeltaY /= multiplierForDeltaY; } } EventStateManager::WheelPrefs::Action -EventStateManager::WheelPrefs::ComputeActionFor(WidgetWheelEvent* aEvent) +EventStateManager::WheelPrefs::ComputeActionFor(const WidgetWheelEvent* aEvent) { 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) { + if (actions[index] == ACTION_NONE || + actions[index] == ACTION_SCROLL || + actions[index] == ACTION_HORIZONTAL_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); - return (actions[INDEX_DEFAULT] == ACTION_SCROLL) ? ACTION_SCROLL : - ACTION_NONE; + if (actions[INDEX_DEFAULT] == ACTION_SCROLL || + actions[INDEX_DEFAULT] == ACTION_HORIZONTAL_SCROLL) { + return actions[INDEX_DEFAULT]; + } + return ACTION_NONE; } return actions[index]; } bool EventStateManager::WheelPrefs::NeedToComputeLineOrPageDelta( - WidgetWheelEvent* aEvent) + const WidgetWheelEvent* aEvent) { Index index = GetIndexFor(aEvent); Init(index); return (mMultiplierX[index] != 1.0 && mMultiplierX[index] != -1.0) || (mMultiplierY[index] != 1.0 && mMultiplierY[index] != -1.0); } void -EventStateManager::WheelPrefs::GetUserPrefsForEvent(WidgetWheelEvent* aEvent, - double* aOutMultiplierX, - double* aOutMultiplierY) +EventStateManager::WheelPrefs::GetUserPrefsForEvent( + const WidgetWheelEvent* aEvent, + double* aOutMultiplierX, + double* aOutMultiplierY) { Index index = GetIndexFor(aEvent); Init(index); - *aOutMultiplierX = mMultiplierX[index]; - *aOutMultiplierY = mMultiplierY[index]; + double multiplierForDeltaX = 1.0, multiplierForDeltaY = 1.0; + GetMultiplierForDeltaXAndY(aEvent, index, + &multiplierForDeltaX, &multiplierForDeltaY); + *aOutMultiplierX = multiplierForDeltaX; + *aOutMultiplierY = multiplierForDeltaY; } // static bool EventStateManager::WheelPrefs::WheelEventsEnabledOnPlugins() { if (!sInstance) { GetInstance(); // initializing sWheelEventsEnabledOnPlugins } return sWheelEventsEnabledOnPlugins; } +// static bool -EventStateManager::WheelEventIsScrollAction(WidgetWheelEvent* aEvent) +EventStateManager::WheelEventIsScrollAction(const WidgetWheelEvent* aEvent) { - return aEvent->mMessage == eWheel && - WheelPrefs::GetInstance()->ComputeActionFor(aEvent) == WheelPrefs::ACTION_SCROLL; + if (aEvent->mMessage != eWheel) { + return false; + } + WheelPrefs::Action action = + WheelPrefs::GetInstance()->ComputeActionFor(aEvent); + return action == WheelPrefs::ACTION_SCROLL || + action == WheelPrefs::ACTION_HORIZONTAL_SCROLL; +} + +// static +bool +EventStateManager::WheelEventIsHorizontalScrollAction( + const WidgetWheelEvent* aEvent) +{ + if (aEvent->mMessage != eWheel) { + return false; + } + WheelPrefs::Action action = + WheelPrefs::GetInstance()->ComputeActionFor(aEvent); + return action == WheelPrefs::ACTION_HORIZONTAL_SCROLL; } void -EventStateManager::GetUserPrefsForWheelEvent(WidgetWheelEvent* aEvent, +EventStateManager::GetUserPrefsForWheelEvent(const WidgetWheelEvent* aEvent, double* aOutMultiplierX, double* aOutMultiplierY) { WheelPrefs::GetInstance()->GetUserPrefsForEvent( aEvent, aOutMultiplierX, aOutMultiplierY); } bool EventStateManager::WheelPrefs::IsOverOnePageScrollAllowedX( - WidgetWheelEvent* aEvent) + const WidgetWheelEvent* aEvent) { Index index = GetIndexFor(aEvent); Init(index); return Abs(mMultiplierX[index]) >= MIN_MULTIPLIER_VALUE_ALLOWING_OVER_ONE_PAGE_SCROLL; } bool EventStateManager::WheelPrefs::IsOverOnePageScrollAllowedY( - WidgetWheelEvent* aEvent) + const WidgetWheelEvent* aEvent) { Index index = GetIndexFor(aEvent); Init(index); return Abs(mMultiplierY[index]) >= MIN_MULTIPLIER_VALUE_ALLOWING_OVER_ONE_PAGE_SCROLL; } /******************************************************************/
--- a/dom/events/EventStateManager.h +++ b/dom/events/EventStateManager.h @@ -299,20 +299,24 @@ public: nsIContent* aContent); // 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(WidgetWheelEvent* aEvent); + 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); // Returns user-set multipliers for a wheel event. - static void GetUserPrefsForWheelEvent(WidgetWheelEvent* aEvent, + static void GetUserPrefsForWheelEvent(const WidgetWheelEvent* aEvent, double* aOutMultiplierX, double* aOutMultiplierY); // Returns whether or not a frame can be vertically scrolled with a mouse // wheel (as opposed to, say, a selection or touch scroll). static bool CanVerticallyScrollFrameWithWheel(nsIFrame* aFrame); // Holds the point in screen coords that a mouse event was dispatched to, @@ -533,17 +537,17 @@ protected: * user prefs. */ void ApplyUserPrefsToDelta(WidgetWheelEvent* aEvent); /** * Returns whether or not ApplyUserPrefsToDelta() would change the delta * values of an event. */ - void GetUserPrefsForEvent(WidgetWheelEvent* aEvent, + void GetUserPrefsForEvent(const WidgetWheelEvent* aEvent, double* aOutMultiplierX, double* aOutMultiplierY); /** * If ApplyUserPrefsToDelta() changed the delta values with customized * prefs, the overflowDelta values would be inflated. * CancelApplyingUserPrefsFromOverflowDelta() cancels the inflation. */ @@ -553,35 +557,36 @@ protected: * Computes the default action for the aEvent with the prefs. */ enum Action : uint8_t { ACTION_NONE = 0, ACTION_SCROLL, ACTION_HISTORY, ACTION_ZOOM, - ACTION_LAST = ACTION_ZOOM, + ACTION_HORIZONTAL_SCROLL, + ACTION_LAST = ACTION_HORIZONTAL_SCROLL, // Following actions are used only by internal processing. So, cannot // specified by prefs. - ACTION_SEND_TO_PLUGIN + ACTION_SEND_TO_PLUGIN, }; - Action ComputeActionFor(WidgetWheelEvent* aEvent); + Action ComputeActionFor(const WidgetWheelEvent* aEvent); /** * NeedToComputeLineOrPageDelta() returns if the aEvent needs to be * computed the lineOrPageDelta values. */ - bool NeedToComputeLineOrPageDelta(WidgetWheelEvent* aEvent); + bool NeedToComputeLineOrPageDelta(const WidgetWheelEvent* aEvent); /** * IsOverOnePageScrollAllowed*() checks whether wheel scroll amount should * be rounded down to the page width/height (false) or not (true). */ - bool IsOverOnePageScrollAllowedX(WidgetWheelEvent* aEvent); - bool IsOverOnePageScrollAllowedY(WidgetWheelEvent* aEvent); + bool IsOverOnePageScrollAllowedX(const WidgetWheelEvent* aEvent); + bool IsOverOnePageScrollAllowedY(const WidgetWheelEvent* aEvent); /** * WheelEventsEnabledOnPlugins() returns true if user wants to use mouse * wheel on plugins. */ static bool WheelEventsEnabledOnPlugins(); private: @@ -604,32 +609,51 @@ protected: /** * GetIndexFor() returns the index of the members which should be used for * the aEvent. When only one modifier key of MODIFIER_ALT, * MODIFIER_CONTROL, MODIFIER_META, MODIFIER_SHIFT or MODIFIER_OS is * pressed, returns the index for the modifier. Otherwise, this return the * default index which is used at either no modifier key is pressed or * two or modifier keys are pressed. */ - Index GetIndexFor(WidgetWheelEvent* aEvent); + Index GetIndexFor(const WidgetWheelEvent* aEvent); /** * GetPrefNameBase() returns the base pref name for aEvent. * It's decided by GetModifierForPref() which modifier should be used for * the aEvent. * * @param aBasePrefName The result, must be "mousewheel.with_*." or * "mousewheel.default.". */ void GetBasePrefName(Index aIndex, nsACString& aBasePrefName); void Init(Index aIndex); void Reset(); + /** + * Retrieve multiplier for aEvent->mDeltaX and aEvent->mDeltaY. + * If the default action is ACTION_HORIZONTAL_SCROLL and the delta values + * are adjusted by AutoWheelDeltaAdjuster(), this treats mMultiplierX as + * multiplier for deltaY and mMultiplierY as multiplier for deltaY. + * + * @param aEvent The event which is being handled. + * @param aIndex The index of mMultiplierX and mMultiplierY. + * Should be result of GetIndexFor(aEvent). + * @param aMultiplierForDeltaX Will be set to multiplier for + * aEvent->mDeltaX. + * @param aMultiplierForDeltaY Will be set to multiplier for + * aEvent->mDeltaY. + */ + void GetMultiplierForDeltaXAndY(const WidgetWheelEvent* aEvent, + Index aIndex, + double* aMultiplierForDeltaX, + double* aMultiplierForDeltaY); + bool mInit[COUNT_OF_MULTIPLIERS]; double mMultiplierX[COUNT_OF_MULTIPLIERS]; double mMultiplierY[COUNT_OF_MULTIPLIERS]; double mMultiplierZ[COUNT_OF_MULTIPLIERS]; Action mActions[COUNT_OF_MULTIPLIERS]; /** * action values overridden by .override_x pref. * If an .override_x value is -1, same as the
--- a/dom/events/WheelHandlingHelper.cpp +++ b/dom/events/WheelHandlingHelper.cpp @@ -524,18 +524,19 @@ ScrollbarsForWheel::DeactivateAllTempora scrollbarMediator->ScrollbarActivityStopped(); } *scrollTarget = nullptr; } } } /******************************************************************/ -/* mozilla::WheelTransaction */ +/* mozilla::WheelTransaction::Prefs */ /******************************************************************/ + int32_t WheelTransaction::Prefs::sMouseWheelAccelerationStart = -1; int32_t WheelTransaction::Prefs::sMouseWheelAccelerationFactor = -1; uint32_t WheelTransaction::Prefs::sMouseWheelTransactionTimeout = 1500; uint32_t WheelTransaction::Prefs::sMouseWheelTransactionIgnoreMoveDelay = 100; bool WheelTransaction::Prefs::sTestMouseScroll = false; /* static */ void WheelTransaction::Prefs::InitializeStatics() @@ -550,9 +551,52 @@ WheelTransaction::Prefs::InitializeStati "mousewheel.transaction.timeout", 1500); Preferences::AddUintVarCache(&sMouseWheelTransactionIgnoreMoveDelay, "mousewheel.transaction.ignoremovedelay", 100); Preferences::AddBoolVarCache(&sTestMouseScroll, "test.mousescroll", false); sIsInitialized = true; } } +/******************************************************************/ +/* mozilla::AutoWheelDeltaAdjuster */ +/******************************************************************/ + +AutoWheelDeltaAdjuster::AutoWheelDeltaAdjuster(WidgetWheelEvent& aWheelEvent) + : mWheelEvent(aWheelEvent) + , mOldDeltaX(aWheelEvent.mDeltaX) + , mOldDeltaZ(aWheelEvent.mDeltaZ) + , mOldOverflowDeltaX(aWheelEvent.mOverflowDeltaX) + , mOldLineOrPageDeltaX(aWheelEvent.mLineOrPageDeltaX) + , mTreatedVerticalWheelAsHorizontalScroll(false) +{ + MOZ_ASSERT(!aWheelEvent.mDeltaValuesAdjustedForDefaultHandler); + + 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; + } +} + +AutoWheelDeltaAdjuster::~AutoWheelDeltaAdjuster() +{ + if (mTreatedVerticalWheelAsHorizontalScroll && + mWheelEvent.mDeltaValuesAdjustedForDefaultHandler) { + 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; + } +} + } // namespace mozilla
--- a/dom/events/WheelHandlingHelper.h +++ b/dom/events/WheelHandlingHelper.h @@ -199,11 +199,40 @@ protected: static int32_t sMouseWheelAccelerationStart; static int32_t sMouseWheelAccelerationFactor; static uint32_t sMouseWheelTransactionTimeout; static uint32_t sMouseWheelTransactionIgnoreMoveDelay; static bool sTestMouseScroll; }; }; +/** + * 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. + */ +class MOZ_STACK_CLASS AutoWheelDeltaAdjuster 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. + */ + explicit AutoWheelDeltaAdjuster(WidgetWheelEvent& aWheelEvent); + ~AutoWheelDeltaAdjuster(); + +private: + WidgetWheelEvent& mWheelEvent; + double mOldDeltaX; + double mOldDeltaZ; + double mOldOverflowDeltaX; + int32_t mOldLineOrPageDeltaX; + bool mTreatedVerticalWheelAsHorizontalScroll; +}; + } // namespace mozilla #endif // mozilla_WheelHandlingHelper_h_
--- a/dom/events/moz.build +++ b/dom/events/moz.build @@ -31,16 +31,17 @@ EXPORTS.mozilla += [ 'EventStates.h', 'IMEStateManager.h', 'InternalMutationEvent.h', 'JSEventHandler.h', 'KeyNameList.h', 'PhysicalKeyCodeNameList.h', 'TextComposition.h', 'VirtualKeyCodeList.h', + 'WheelHandlingHelper.h', ] EXPORTS.mozilla.dom += [ 'AnimationEvent.h', 'BeforeUnloadEvent.h', 'ClipboardEvent.h', 'CommandEvent.h', 'CompositionEvent.h',
--- a/dom/events/test/window_wheel_default_action.html +++ b/dom/events/test/window_wheel_default_action.html @@ -73,16 +73,28 @@ SimpleTest.requestFlakyTimeout("untriage var winUtils = SpecialPowers.getDOMWindowUtils(window); // grab refresh driver winUtils.advanceTimeAndRefresh(100); var gScrollableElement = document.getElementById("scrollable"); var gScrolledElement = document.getElementById("scrolled"); var gSpacerForBodyElement = document.getElementById("spacerForBody"); +const kDefaultActionNone = 0; +const kDefaultActionScroll = 1; +const kDefaultActionHistory = 2; +const kDefaultActionZoom = 3; +const kDefaultActionHorizontalScroll = 4; + +const kDefaultActionOverrideXNoOverride = -1; +const kDefaultActionOverrideXNone = kDefaultActionNone; +const kDefaultActionOverrideXScroll = kDefaultActionScroll; +const kDefaultActionOverrideXHistory = kDefaultActionHistory; +const kDefaultActionOverrideXZoom = kDefaultActionZoom; + function is() { window.opener.is.apply(window.opener, arguments); } function ok() { window.opener.ok.apply(window.opener, arguments); @@ -533,108 +545,108 @@ function doTestScroll(aSettings, aCallba // momentum scroll should cause scroll even if the action is history, but if the default action is none, // shouldn't do it. { description: "Scroll to bottom by momentum pixel scroll when lineOrPageDelta is 0, even if the action is history", event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL, deltaX: 0.0, deltaY: 8.0, deltaZ: 0.0, lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: true, expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, - shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + shiftKey: false, ctrlKey: false, altKey: true, metaKey: false, osKey: false }, expected: kScrollDown }, { description: "Scroll to bottom by momentum pixel scroll when lineOrPageDelta is 1, even if the action is history", event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL, deltaX: 0.0, deltaY: 8.0, deltaZ: 0.0, lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isMomentum: true, expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, - shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + shiftKey: false, ctrlKey: false, altKey: true, metaKey: false, osKey: false }, expected: kScrollDown }, { description: "Scroll to top by momentum pixel scroll when lineOrPageDelta is 0, even if the action is history", event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL, deltaX: 0.0, deltaY: -8.0, deltaZ: 0.0, lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: true, expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, - shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + shiftKey: false, ctrlKey: false, altKey: true, metaKey: false, osKey: false }, expected: kScrollUp }, { description: "Scroll to top by momentum pixel scroll when lineOrPageDelta is -1, even if the action is history", event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL, deltaX: 0.0, deltaY: -8.0, deltaZ: 0.0, lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isMomentum: true, expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, - shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + shiftKey: false, ctrlKey: false, altKey: true, metaKey: false, osKey: false }, expected: kScrollUp }, { description: "Scroll to right by momentum pixel scroll when lineOrPageDelta is 0, even if the action is history", event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL, deltaX: 8.0, deltaY: 0.0, deltaZ: 0.0, lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: true, expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, - shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + shiftKey: false, ctrlKey: false, altKey: true, metaKey: false, osKey: false }, expected: kScrollRight }, { description: "Scroll to right by momentum pixel scroll when lineOrPageDelta is 1, even if the action is history", event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL, deltaX: 8.0, deltaY: 0.0, deltaZ: 0.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isMomentum: true, expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, - shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + shiftKey: false, ctrlKey: false, altKey: true, metaKey: false, osKey: false }, expected: kScrollRight }, { description: "Scroll to left by momentum pixel scroll when lineOrPageDelta is 0, even if the action is history", event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL, deltaX: -8.0, deltaY: 0.0, deltaZ: 0.0, lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: true, expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, - shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + shiftKey: false, ctrlKey: false, altKey: true, metaKey: false, osKey: false }, expected: kScrollLeft }, { description: "Scroll to left by momentum pixel scroll when lineOrPageDelta is -1, even if the action is history", event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL, deltaX: -8.0, deltaY: 0.0, deltaZ: 0.0, lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isMomentum: true, expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, - shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + shiftKey: false, ctrlKey: false, altKey: true, metaKey: false, osKey: false }, expected: kScrollLeft }, { description: "Scroll to bottom-right by momentum pixel scroll even if the action is history", event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL, deltaX: 8.0, deltaY: 8.0, deltaZ: 0.0, lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: true, expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, - shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + shiftKey: false, ctrlKey: false, altKey: true, metaKey: false, osKey: false }, expected: kScrollDown | kScrollRight }, { description: "Scroll to bottom-left by momentum pixel scroll even if the action is history", event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL, deltaX: -8.0, deltaY: 8.0, deltaZ: 0.0, lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: true, expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, - shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + shiftKey: false, ctrlKey: false, altKey: true, metaKey: false, osKey: false }, expected: kScrollDown | kScrollLeft }, { description: "Scroll to top-left by momentum pixel scroll even if the action is history", event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL, deltaX: -8.0, deltaY: -8.0, deltaZ: 0.0, lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: true, expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, - shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + shiftKey: false, ctrlKey: false, altKey: true, metaKey: false, osKey: false }, expected: kScrollUp | kScrollLeft }, { description: "Scroll to top-right by momentum pixel scroll even if the action is history", event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL, deltaX: 8.0, deltaY: -8.0, deltaZ: 0.0, lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: true, expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, - shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + shiftKey: false, ctrlKey: false, altKey: true, metaKey: false, osKey: false }, expected: kScrollUp | kScrollRight }, { description: "Not Scroll by momentum pixel scroll for z (action is history)", event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL, deltaX: 0.0, deltaY: 0.0, deltaZ: 1.0, lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: true, expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, - shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + shiftKey: false, ctrlKey: false, altKey: true, metaKey: false, osKey: false }, expected: kNoScroll }, { description: "Not Scroll by momentum pixel scroll if default action is none (action is history)", event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL, deltaX: 0.0, deltaY: 0.0, deltaZ: 1.0, lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: true, expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, - shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + shiftKey: false, ctrlKey: false, altKey: true, metaKey: false, osKey: false }, expected: kNoScroll, prepare: function (cb) { SpecialPowers.pushPrefEnv({"set": [["mousewheel.default.action", 0]]}, cb); }, cleanup: function (cb) { SpecialPowers.pushPrefEnv({"set": [["mousewheel.default.action", 1]]}, cb); } }, // Don't scroll along axis whose overflow style is hidden. { description: "Scroll to only bottom by oblique pixel wheel event with overflow-x: hidden", event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL, deltaX: 16.0, deltaY: 16.0, deltaZ: 0.0, @@ -941,16 +953,360 @@ function doTestScroll(aSettings, aCallba winUtils.advanceTimeAndRefresh(100); doNextTest(); } }); } doNextTest(); } +function doTestHorizontalScroll(aSettings, aCallback) +{ + const kNoScroll = 0x00; + const kScrollLeft = 0x01; + const kScrollRight = 0x02; + + const kTests = [ + { description: "Scroll to right by pixel scroll even if lineOrPageDelta is 0", + event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL, + deltaX: 0.0, deltaY: 8.0, deltaZ: 0.0, + lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false, + expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, + shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + expected: kScrollRight }, + { description: "Scroll to right by pixel scroll when lineOrPageDelta is 1", + event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL, + deltaX: 0.0, deltaY: 8.0, deltaZ: 0.0, + lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isMomentum: false, + expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, + shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + expected: kScrollRight }, + { description: "Scroll to left by pixel scroll even if lineOrPageDelta is 0", + event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL, + deltaX: 0.0, deltaY: -8.0, deltaZ: 0.0, + lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false, + expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, + shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + expected: kScrollLeft }, + { description: "Scroll to left by pixel scroll when lineOrPageDelta is -1", + event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL, + deltaX: 0.0, deltaY: -8.0, deltaZ: 0.0, + lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isMomentum: false, + expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, + shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + expected: kScrollLeft }, + { description: "Don't scroll by deltaX (pixel scroll, lineOrPageDelta is 0)", + event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL, + deltaX: 8.0, deltaY: 0.0, deltaZ: 0.0, + lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false, + expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, + shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + expected: kNoScroll }, + { description: "Don't scroll by deltaX (pixel scroll, lineOrPageDelta is 1)", + event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL, + deltaX: 8.0, deltaY: 0.0, deltaZ: 0.0, + lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isMomentum: false, + expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, + shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + expected: kNoScroll }, + { description: "Don't scroll by negative deltaX (pixel scroll, lineOrPageDelta is 0)", + event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL, + deltaX: -8.0, deltaY: 0.0, deltaZ: 0.0, + lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false, + expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, + shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + expected: kNoScroll }, + { description: "Don't scroll by negative deltaX (pixel scroll, lineOrPageDelta is -1)", + event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL, + deltaX: -8.0, deltaY: 0.0, deltaZ: 0.0, + lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isMomentum: false, + expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, + shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + expected: kNoScroll }, + { description: "Scroll only to right by diagonal pixel scroll (to bottom-right)", + event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL, + deltaX: 8.0, deltaY: 8.0, deltaZ: 0.0, + lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false, + expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, + shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + expected: kScrollRight }, + { description: "Scroll only to right by diagonal pixel scroll (to bottom-left)", + event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL, + deltaX: -8.0, deltaY: 8.0, deltaZ: 0.0, + lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false, + expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, + shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + expected: kScrollRight }, + { description: "Scroll only to left by diagonal pixel scroll (to top-left)", + event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL, + deltaX: -8.0, deltaY: -8.0, deltaZ: 0.0, + lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false, + expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, + shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + expected: kScrollLeft }, + { description: "Scroll only to left by pixel scroll (to bottom-right)", + event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL, + deltaX: 8.0, deltaY: -8.0, deltaZ: 0.0, + lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false, + expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, + shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + expected: kScrollLeft }, + { description: "Don't scroll by pixel scroll for z-axis", + event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL, + deltaX: 0.0, deltaY: 0.0, deltaZ: 1.0, + lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false, + expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, + shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + expected: kNoScroll }, + + { description: "Scroll to right by line scroll even if lineOrPageDelta is 0", + event: { deltaMode: WheelEvent.DOM_DELTA_LINE, + deltaX: 0.0, deltaY: 0.5, deltaZ: 0.0, + lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isMomentum: false, + expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, + shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + expected: kScrollRight }, + { description: "Scroll to right by line scroll when lineOrPageDelta is 1", + event: { deltaMode: WheelEvent.DOM_DELTA_LINE, + deltaX: 0.0, deltaY: 0.5, deltaZ: 0.0, + lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isMomentum: false, + expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, + shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + expected: kScrollRight }, + { description: "Scroll to left by line scroll even if lineOrPageDelta is 0", + event: { deltaMode: WheelEvent.DOM_DELTA_LINE, + deltaX: 0.0, deltaY: -0.5, deltaZ: 0.0, + lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false, + expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, + shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + expected: kScrollLeft }, + { description: "Scroll to left by line scroll when lineOrPageDelta is -1", + event: { deltaMode: WheelEvent.DOM_DELTA_LINE, + deltaX: 0.0, deltaY: -0.5, deltaZ: 0.0, + lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isMomentum: false, + expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, + shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + expected: kScrollLeft }, + { description: "Don't scroll by deltaX (line scroll, lineOrPageDelta is 0)", + event: { deltaMode: WheelEvent.DOM_DELTA_LINE, + deltaX: 0.5, deltaY: 0.0, deltaZ: 0.0, + lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false, + expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, + shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + expected: kNoScroll }, + { description: "Don't scroll by deltaX (line scroll, lineOrPageDelta is 1)", + event: { deltaMode: WheelEvent.DOM_DELTA_LINE, + deltaX: 0.5, deltaY: 0.0, deltaZ: 0.0, + lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isMomentum: false, + expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, + shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + expected: kNoScroll }, + { description: "Don't scroll by negative deltaX (line scroll, lineOrPageDelta is 0)", + event: { deltaMode: WheelEvent.DOM_DELTA_LINE, + deltaX: -0.5, deltaY: 0.0, deltaZ: 0.0, + lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false, + expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, + shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + expected: kNoScroll }, + { description: "Don't scroll by negative deltaY (line scroll, lineOrPageDelta is -1)", + event: { deltaMode: WheelEvent.DOM_DELTA_LINE, + deltaX: -0.5, deltaY: 0.0, deltaZ: 0.0, + lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isMomentum: false, + expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, + shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + expected: kNoScroll }, + { description: "Scroll only to right by diagonal line scroll (to bottom-right)", + event: { deltaMode: WheelEvent.DOM_DELTA_LINE, + deltaX: 0.5, deltaY: 0.5, deltaZ: 0.0, + lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false, + expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, + shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + expected: kScrollRight }, + { description: "Scroll only to right by diagonal line scroll (to bottom-left)", + event: { deltaMode: WheelEvent.DOM_DELTA_LINE, + deltaX: -0.5, deltaY: 0.5, deltaZ: 0.0, + lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false, + expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, + shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + expected: kScrollRight }, + { description: "Scroll only to left by diagonal line scroll (to top-left)", + event: { deltaMode: WheelEvent.DOM_DELTA_LINE, + deltaX: -0.5, deltaY: -0.5, deltaZ: 0.0, + lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false, + expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, + shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + expected: kScrollLeft }, + { description: "Scroll only to left by line scroll (to top-right)", + event: { deltaMode: WheelEvent.DOM_DELTA_LINE, + deltaX: 0.5, deltaY: -0.5, deltaZ: 0.0, + lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false, + expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, + shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + expected: kScrollLeft }, + { description: "Don't scroll by line scroll for z-axis", + event: { deltaMode: WheelEvent.DOM_DELTA_LINE, + deltaX: 0.0, deltaY: 0.0, deltaZ: 1.0, + lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false, + expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, + shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + expected: kNoScroll }, + + { description: "Scroll to right by page scroll even if lineOrPageDelta is 0", + event: { deltaMode: WheelEvent.DOM_DELTA_PAGE, + deltaX: 0.0, deltaY: 0.5, deltaZ: 0.0, + lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isMomentum: false, + expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, + shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + expected: kScrollRight }, + { description: "Scroll to right by page scroll when lineOrPageDelta is 1", + event: { deltaMode: WheelEvent.DOM_DELTA_PAGE, + deltaX: 0.0, deltaY: 0.5, deltaZ: 0.0, + lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isMomentum: false, + expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, + shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + expected: kScrollRight }, + { description: "Scroll to left by page scroll even if lineOrPageDelta is 0", + event: { deltaMode: WheelEvent.DOM_DELTA_LINE, + deltaX: 0.0, deltaY: -0.5, deltaZ: 0.0, + lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false, + expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, + shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + expected: kScrollLeft }, + { description: "Scroll to left by page scroll when lineOrPageDelta is -1", + event: { deltaMode: WheelEvent.DOM_DELTA_PAGE, + deltaX: 0.0, deltaY: -0.5, deltaZ: 0.0, + lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isMomentum: false, + expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, + shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + expected: kScrollLeft }, + { description: "Don't scroll by deltaX (page scroll, lineOrPageDelta is 0)", + event: { deltaMode: WheelEvent.DOM_DELTA_PAGE, + deltaX: 0.5, deltaY: 0.0, deltaZ: 0.0, + lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false, + expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, + shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + expected: kNoScroll }, + { description: "Don't scroll by deltaX (page scroll, lineOrPageDelta is 1)", + event: { deltaMode: WheelEvent.DOM_DELTA_PAGE, + deltaX: 0.5, deltaY: 0.0, deltaZ: 0.0, + lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isMomentum: false, + expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, + shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + expected: kNoScroll }, + { description: "Don't scroll by deltaX (page scroll, lineOrPageDelta is 0)", + event: { deltaMode: WheelEvent.DOM_DELTA_PAGE, + deltaX: -0.5, deltaY: 0.0, deltaZ: 0.0, + lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false, + expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, + shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + expected: kNoScroll }, + { description: "Don't scroll by deltaX (page scroll, lineOrPageDelta is -1)", + event: { deltaMode: WheelEvent.DOM_DELTA_PAGE, + deltaX: -0.5, deltaY: 0.0, deltaZ: 0.0, + lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isMomentum: false, + expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, + shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + expected: kNoScroll }, + { description: "Scroll only to right by diagonal page scroll (to bottom-right)", + event: { deltaMode: WheelEvent.DOM_DELTA_PAGE, + deltaX: 0.5, deltaY: 0.5, deltaZ: 0.0, + lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false, + expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, + shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + expected: kScrollRight }, + { description: "Scroll only to right by diagonal page scroll (to bottom-left)", + event: { deltaMode: WheelEvent.DOM_DELTA_PAGE, + deltaX: -0.5, deltaY: 0.5, deltaZ: 0.0, + lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false, + expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, + shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + expected: kScrollRight }, + { description: "Scroll only to left by diagonal page scroll (to top-left)", + event: { deltaMode: WheelEvent.DOM_DELTA_PAGE, + deltaX: -0.5, deltaY: -0.5, deltaZ: 0.0, + lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false, + expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, + shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + expected: kScrollLeft }, + { description: "Scroll only to left by diagonal page scroll (to top-right)", + event: { deltaMode: WheelEvent.DOM_DELTA_PAGE, + deltaX: 0.5, deltaY: -0.5, deltaZ: 0.0, + lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false, + expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, + shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + expected: kScrollLeft }, + { description: "Don't scroll by page scroll for z-axis", + event: { deltaMode: WheelEvent.DOM_DELTA_PAGE, + deltaX: 0.0, deltaY: 0.0, deltaZ: 1.0, + lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false, + expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0, + shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false }, + expected: kNoScroll }, + ]; + + var description; + + var currentTestIndex = -1; + // deltaY should cause horizontal scroll and affected by deltaMultiplierY. + // So, horizontal scroll amount and direction is affected by deltaMultiplierY. + var isXReverted = (aSettings.deltaMultiplierY < 0); + + function doNextTest() + { + if (++currentTestIndex >= kTests.length) { + SimpleTest.executeSoon(aCallback); + return; + } + + gScrollableElement.scrollTop = 1000; + gScrollableElement.scrollLeft = 1000; + + var currentTest = kTests[currentTestIndex]; + description = "doTestHorizontalScroll(aSettings=" + aSettings.description + "), " + currentTest.description + ": "; + if (currentTest.prepare) { + currentTest.prepare(doTestCurrentScroll); + } else { + doTestCurrentScroll(); + } + } + + function doTestCurrentScroll() { + var currentTest = kTests[currentTestIndex]; + sendWheelAndWait(10, 10, currentTest.event, function () { + is(gScrollableElement.scrollTop, 1000, description + "scrolled vertical"); + if (currentTest.expected == kNoScroll) { + is(gScrollableElement.scrollLeft, 1000, description + "scrolled horizontal"); + } else { + var scrollLeft = !isXReverted ? (currentTest.expected & kScrollLeft) : + (currentTest.expected & kScrollRight); + var scrollRight = !isXReverted ? (currentTest.expected & kScrollRight) : + (currentTest.expected & kScrollLeft); + if (scrollLeft) { + ok(gScrollableElement.scrollLeft < 1000, description + "not scrolled to left, got " + gScrollableElement.scrollLeft); + } else if (scrollRight) { + ok(gScrollableElement.scrollLeft > 1000, description + "not scrolled to right, got " + gScrollableElement.scrollLeft); + } else { + is(gScrollableElement.scrollLeft, 1000, description + "scrolled horizontal"); + } + } + if (currentTest.cleanup) { + currentTest.cleanup(nextStep); + } else { + nextStep(); + } + + function nextStep() { + winUtils.advanceTimeAndRefresh(100); + doNextTest(); + } + }); + } + doNextTest(); +} + function doTestZoom(aSettings, aCallback) { if ((aSettings.deltaMultiplierX != 1.0 && aSettings.deltaMultiplierX != -1.0) || (aSettings.deltaMultiplierY != 1.0 && aSettings.deltaMultiplierY != -1.0)) { todo(false, "doTestZoom doesn't support to test with aSettings=" + aSettings.description); SimpleTest.executeSoon(aCallback); return; } @@ -1654,119 +2010,119 @@ function doTestActionOverride(aCallback) { const kNoScroll = 0x00; const kScrollUp = 0x01; const kScrollDown = 0x02; const kScrollLeft = 0x04; const kScrollRight = 0x08; const kTests = [ - { action: 1, override_x: -1, + { action: kDefaultActionScroll, override_x: kDefaultActionOverrideXNoOverride, event: { deltaMode: WheelEvent.DOM_DELTA_LINE, deltaX: 1.0, deltaY: 1.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 }, expected: kScrollDown | kScrollRight }, - { action: 1, override_x: 0, + { action: kDefaultActionScroll, override_x: kDefaultActionOverrideXNone, event: { deltaMode: WheelEvent.DOM_DELTA_LINE, deltaX: 1.0, deltaY: 1.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 }, expected: kScrollDown | kScrollRight }, - { action: 1, override_x: 1, + { action: kDefaultActionScroll, override_x: kDefaultActionOverrideXScroll, event: { deltaMode: WheelEvent.DOM_DELTA_LINE, deltaX: 1.0, deltaY: 1.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 }, expected: kScrollDown | kScrollRight }, - { action: 0, override_x: -1, + { action: kDefaultActionNone, override_x: kDefaultActionOverrideXNoOverride, event: { deltaMode: WheelEvent.DOM_DELTA_LINE, deltaX: 1.0, deltaY: 1.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 }, expected: kNoScroll }, - { action: 0, override_x: 0, + { action: kDefaultActionNone, override_x: kDefaultActionOverrideXNone, event: { deltaMode: WheelEvent.DOM_DELTA_LINE, deltaX: 1.0, deltaY: 1.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 }, expected: kNoScroll }, - { action: 0, override_x: 1, + { action: kDefaultActionNone, override_x: kDefaultActionOverrideXScroll, event: { deltaMode: WheelEvent.DOM_DELTA_LINE, deltaX: 1.0, deltaY: 1.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 }, expected: kNoScroll }, - { action: 1, override_x: -1, + { action: kDefaultActionScroll, override_x: kDefaultActionOverrideXNoOverride, event: { deltaMode: WheelEvent.DOM_DELTA_LINE, deltaX: 1.0, deltaY: 0.5, lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 }, expected: kScrollDown | kScrollRight }, - { action: 1, override_x: 0, + { action: kDefaultActionScroll, override_x: kDefaultActionOverrideXNone, event: { deltaMode: WheelEvent.DOM_DELTA_LINE, deltaX: 1.0, deltaY: 0.5, lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 }, expected: kNoScroll }, - { action: 1, override_x: 1, + { action: kDefaultActionScroll, override_x: kDefaultActionOverrideXScroll, event: { deltaMode: WheelEvent.DOM_DELTA_LINE, deltaX: 1.0, deltaY: 0.5, lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 }, expected: kScrollDown | kScrollRight }, - { action: 0, override_x: -1, + { action: kDefaultActionNone, override_x: kDefaultActionOverrideXNoOverride, event: { deltaMode: WheelEvent.DOM_DELTA_LINE, deltaX: 1.0, deltaY: 0.5, lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 }, expected: kNoScroll }, - { action: 0, override_x: 0, + { action: kDefaultActionNone, override_x: kDefaultActionOverrideXNone, event: { deltaMode: WheelEvent.DOM_DELTA_LINE, deltaX: 1.0, deltaY: 0.5, lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 }, expected: kNoScroll }, - { action: 0, override_x: 1, + { action: kDefaultActionNone, override_x: kDefaultActionOverrideXScroll, event: { deltaMode: WheelEvent.DOM_DELTA_LINE, deltaX: 1.0, deltaY: 0.5, lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 }, expected: kScrollDown | kScrollRight }, - { action: 1, override_x: -1, + { action: kDefaultActionScroll, override_x: kDefaultActionOverrideXNoOverride, event: { deltaMode: WheelEvent.DOM_DELTA_LINE, deltaX: 0.5, deltaY: 1.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 }, expected: kScrollDown | kScrollRight }, - { action: 1, override_x: 0, + { action: kDefaultActionScroll, override_x: kDefaultActionOverrideXNone, event: { deltaMode: WheelEvent.DOM_DELTA_LINE, deltaX: 0.5, deltaY: 1.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 }, expected: kScrollDown | kScrollRight }, - { action: 1, override_x: 1, + { action: kDefaultActionScroll, override_x: kDefaultActionOverrideXScroll, event: { deltaMode: WheelEvent.DOM_DELTA_LINE, deltaX: 0.5, deltaY: 1.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 }, expected: kScrollDown | kScrollRight }, - { action: 0, override_x: -1, + { action: kDefaultActionNone, override_x: kDefaultActionOverrideXNoOverride, event: { deltaMode: WheelEvent.DOM_DELTA_LINE, deltaX: 0.5, deltaY: 1.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 }, expected: kNoScroll }, - { action: 0, override_x: 0, + { action: kDefaultActionNone, override_x: kDefaultActionOverrideXNone, event: { deltaMode: WheelEvent.DOM_DELTA_LINE, deltaX: 0.5, deltaY: 1.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 }, expected: kNoScroll }, - { action: 0, override_x: 1, + { action: kDefaultActionNone, override_x: kDefaultActionOverrideXScroll, event: { deltaMode: WheelEvent.DOM_DELTA_LINE, deltaX: 0.5, deltaY: 1.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 }, expected: kNoScroll }, ]; var index = 0; @@ -1815,22 +2171,24 @@ function doTestActionOverride(aCallback) doIt(); } function runTests() { SpecialPowers.pushPrefEnv({"set": [ ["test.events.async.enabled", true], ["general.smoothScroll", false], - ["mousewheel.default.action", 1], // scroll - ["mousewheel.default.action.override_x", -1], - ["mousewheel.with_shift.action", 2], // history - ["mousewheel.with_shift.action.override_x", -1], - ["mousewheel.with_control.action", 3], // zoom - ["mousewheel.with_control.action.override_x", -1]]}, + ["mousewheel.default.action", kDefaultActionScroll], + ["mousewheel.default.action.override_x", kDefaultActionOverrideXNoOverride], + ["mousewheel.with_shift.action", kDefaultActionHorizontalScroll], + ["mousewheel.with_shift.action.override_x", kDefaultActionOverrideXNoOverride], + ["mousewheel.with_control.action", kDefaultActionZoom], + ["mousewheel.with_control.action.override_x", kDefaultActionOverrideXNoOverride], + ["mousewheel.with_alt.action", kDefaultActionHistory], + ["mousewheel.with_alt.action.override_x", kDefaultActionOverrideXNoOverride]]}, runTests2); } function runTests2() { const kSettings = [ { description: "all delta values are not customized", deltaMultiplierX: 1.0, deltaMultiplierY: 1.0, deltaMultiplierZ: 1.0 }, @@ -1854,30 +2212,32 @@ function runTests2() deltaMultiplierX: 1.0, deltaMultiplierY: 1.0, deltaMultiplierZ: -2.0 }, ]; var index = 0; function doTest() { setDeltaMultiplierSettings(kSettings[index], function () { doTestScroll(kSettings[index], function () { - doTestZoom(kSettings[index], function() { - if (++index == kSettings.length) { - setDeltaMultiplierSettings(kSettings[0], function() { - doTestZoomedScroll(function() { - doTestWholeScroll(function() { - doTestActionOverride(function() { - finishTests(); + doTestHorizontalScroll(kSettings[index], function() { + doTestZoom(kSettings[index], function() { + if (++index == kSettings.length) { + setDeltaMultiplierSettings(kSettings[0], function() { + doTestZoomedScroll(function() { + doTestWholeScroll(function() { + doTestActionOverride(function() { + finishTests(); + }); }); }); }); - }); - } else { - doTest(); - } + } else { + doTest(); + } + }); }); }); }); } doTest(); } function finishTests()
--- a/gfx/layers/apz/public/IAPZCTreeManager.cpp +++ b/gfx/layers/apz/public/IAPZCTreeManager.cpp @@ -8,16 +8,17 @@ #include "gfxPrefs.h" // for gfxPrefs #include "InputData.h" // for InputData, etc #include "mozilla/EventStateManager.h" // for WheelPrefs #include "mozilla/layers/APZThreadUtils.h" // for AssertOnCompositorThread, etc #include "mozilla/MouseEvents.h" // for WidgetMouseEvent #include "mozilla/TextEvents.h" // for WidgetKeyboardEvent #include "mozilla/TouchEvents.h" // for WidgetTouchEvent +#include "mozilla/WheelHandlingHelper.h" // for AutoWheelDeltaAdjuster namespace mozilla { namespace layers { static bool WillHandleMouseEvent(const WidgetMouseEventBase& aEvent) { return aEvent.mMessage == eMouseMove || @@ -108,41 +109,49 @@ IAPZCTreeManager::ReceiveInputEvent( ((wheelEvent.mDeltaMode == nsIDOMWheelEvent::DOM_DELTA_LINE && gfxPrefs::WheelSmoothScrollEnabled()) || (wheelEvent.mDeltaMode == nsIDOMWheelEvent::DOM_DELTA_PAGE && gfxPrefs::PageSmoothScrollEnabled()))) { scrollMode = ScrollWheelInput::SCROLLMODE_SMOOTH; } - 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); + // 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); + + // 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); - // 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, - &input.mUserDeltaMultiplierX, - &input.mUserDeltaMultiplierY); + // 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, + &input.mUserDeltaMultiplierX, + &input.mUserDeltaMultiplierY); - nsEventStatus status = ReceiveInputEvent(input, aOutTargetGuid, aOutInputBlockId); - wheelEvent.mRefPoint.x = input.mOrigin.x; - wheelEvent.mRefPoint.y = input.mOrigin.y; - wheelEvent.mFlags.mHandledByAPZ = input.mHandledByAPZ; - wheelEvent.mFocusSequenceNumber = input.mFocusSequenceNumber; - return status; + nsEventStatus status = ReceiveInputEvent(input, aOutTargetGuid, aOutInputBlockId); + wheelEvent.mRefPoint.x = input.mOrigin.x; + wheelEvent.mRefPoint.y = input.mOrigin.y; + wheelEvent.mFlags.mHandledByAPZ = input.mHandledByAPZ; + wheelEvent.mFocusSequenceNumber = input.mFocusSequenceNumber; + return status; + } } UpdateWheelTransaction(aEvent.mRefPoint, aEvent.mMessage); ProcessUnhandledEvent(&aEvent.mRefPoint, aOutTargetGuid, &aEvent.mFocusSequenceNumber); return nsEventStatus_eIgnore; } case eKeyboardEventClass: {
--- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -2726,27 +2726,33 @@ pref("mousewheel.system_scroll_override_ // 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 // 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. 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", 1); +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. +// 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); // mousewheel.*.delta_multiplier_* can specify the value muliplied by the delta
--- a/widget/MouseEvents.h +++ b/widget/MouseEvents.h @@ -485,16 +485,17 @@ private: , mLineOrPageDeltaY(0) , mScrollType(SCROLL_DEFAULT) , mCustomizedByUserPrefs(false) , mIsMomentum(false) , mIsNoLineOrPageDelta(false) , mViewPortIsOverscrolled(false) , mCanTriggerSwipe(false) , mAllowToOverrideSystemScrollSpeed(false) + , mDeltaValuesAdjustedForDefaultHandler(false) { } public: virtual WidgetWheelEvent* AsWheelEvent() override { return this; } WidgetWheelEvent(bool aIsTrusted, EventMessage aMessage, nsIWidget* aWidget) : WidgetMouseEventBase(aIsTrusted, aMessage, aWidget, eWheelEventClass) @@ -509,16 +510,17 @@ public: , mScrollType(SCROLL_DEFAULT) , mCustomizedByUserPrefs(false) , mMayHaveMomentum(false) , mIsMomentum(false) , mIsNoLineOrPageDelta(false) , mViewPortIsOverscrolled(false) , mCanTriggerSwipe(false) , mAllowToOverrideSystemScrollSpeed(true) + , mDeltaValuesAdjustedForDefaultHandler(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. @@ -626,16 +628,20 @@ 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; + void AssignWheelEventData(const WidgetWheelEvent& aEvent, bool aCopyTargets) { AssignMouseEventBaseData(aEvent, aCopyTargets); mDeltaX = aEvent.mDeltaX; mDeltaY = aEvent.mDeltaY; mDeltaZ = aEvent.mDeltaZ; mDeltaMode = aEvent.mDeltaMode; @@ -647,16 +653,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; } // 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/nsGUIEventIPC.h +++ b/widget/nsGUIEventIPC.h @@ -194,16 +194,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); } static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) { uint8_t scrollType = 0; bool rv = ReadParam(aMsg, aIter, static_cast<mozilla::WidgetMouseEventBase*>(aResult)) && @@ -217,17 +218,18 @@ struct ParamTraits<mozilla::WidgetWheelE ReadParam(aMsg, aIter, &aResult->mIsNoLineOrPageDelta) && 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->mAllowToOverrideSystemScrollSpeed) && + ReadParam(aMsg, aIter, &aResult->mDeltaValuesAdjustedForDefaultHandler); aResult->mScrollType = static_cast<mozilla::WidgetWheelEvent::ScrollType>(scrollType); return rv; } }; template<> struct ParamTraits<mozilla::WidgetPointerHelper>