Bug 1358017 - Part 2: Introduces the concept of auto-dir wheel scrolling and adds two new related prefs. r?masayuki, kats draft
authorZhang Junzhi <zjz@zjz.name>
Thu, 15 Mar 2018 21:57:19 +0800
changeset 780966 f082822071c1cb8f1fd7daf307be29c1dc465764
parent 780965 e9f269cc89888d18c0854fde5984ac9cb32551c9
child 780967 1a81b8af2b0feca350597e3b0376972b9ac9d695
push id106174
push userbmo:zjz@zjz.name
push dateThu, 12 Apr 2018 10:18:30 +0000
reviewersmasayuki, kats
bugs1358017
milestone61.0a1
Bug 1358017 - Part 2: Introduces the concept of auto-dir wheel scrolling and adds two new related prefs. r?masayuki, kats This commit only introduces the concept and the functionality of retrieving the values from the two new related prefs. Still no actual functionality change is involved. MozReview-Commit-ID: 2Gl3Wqdo6jL
dom/events/EventStateManager.cpp
dom/events/EventStateManager.h
dom/events/WheelHandlingHelper.h
modules/libpref/init/all.js
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -279,16 +279,22 @@ nsWeakPtr EventStateManager::sPointerLoc
 nsWeakPtr EventStateManager::sPointerLockedDoc;
 nsCOMPtr<nsIContent> EventStateManager::sDragOverContent = nullptr;
 TimeStamp EventStateManager::sLatestUserInputStart;
 TimeStamp EventStateManager::sHandlingInputStart;
 
 EventStateManager::WheelPrefs*
   EventStateManager::WheelPrefs::sInstance = nullptr;
 bool EventStateManager::WheelPrefs::sWheelEventsEnabledOnPlugins = true;
+#ifdef EARLY_BETA_OR_EARLIER
+bool EventStateManager::WheelPrefs::sIsAutoDirEnabled = true;
+#else
+bool EventStateManager::WheelPrefs::sIsAutoDirEnabled = false;
+#endif
+bool EventStateManager::WheelPrefs::sHonoursRootForAutoDir = false;
 EventStateManager::DeltaAccumulator*
   EventStateManager::DeltaAccumulator::sInstance = nullptr;
 
 EventStateManager::EventStateManager()
   : mLockCursor(0)
   , mLastFrameConsumedSetCursor(false)
   , mCurrentTarget(nullptr)
   // init d&d gesture state machine variables
@@ -5821,16 +5827,22 @@ EventStateManager::WheelPrefs::OnPrefCha
 
 EventStateManager::WheelPrefs::WheelPrefs()
 {
   Reset();
   Preferences::RegisterPrefixCallback(OnPrefChanged, "mousewheel.");
   Preferences::AddBoolVarCache(&sWheelEventsEnabledOnPlugins,
                                "plugin.mousewheel.enabled",
                                true);
+  Preferences::AddBoolVarCache(&sIsAutoDirEnabled,
+                               "mousewheel.autodir.enabled",
+                               true);
+  Preferences::AddBoolVarCache(&sHonoursRootForAutoDir,
+                               "mousewheel.autodir.honourroot",
+                               false);
 }
 
 EventStateManager::WheelPrefs::~WheelPrefs()
 {
   Preferences::UnregisterPrefixCallback(OnPrefChanged, "mousewheel.");
 }
 
 void
@@ -6092,16 +6104,36 @@ EventStateManager::WheelPrefs::WheelEven
   if (!sInstance) {
     GetInstance(); // initializing sWheelEventsEnabledOnPlugins
   }
   return sWheelEventsEnabledOnPlugins;
 }
 
 // static
 bool
+EventStateManager::WheelPrefs::IsAutoDirEnabled()
+{
+  if (!sInstance) {
+    GetInstance(); // initializing sIsAutoDirEnabled
+  }
+  return sIsAutoDirEnabled;
+}
+
+// static
+bool
+EventStateManager::WheelPrefs::HonoursRootForAutoDir()
+{
+  if (!sInstance) {
+    GetInstance(); // initializing sHonoursRootForAutoDir
+  }
+  return sHonoursRootForAutoDir;
+}
+
+// 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 ||
@@ -6112,19 +6144,26 @@ EventStateManager::WheelEventIsScrollAct
 WheelDeltaAdjustmentStrategy
 EventStateManager::GetWheelDeltaAdjustmentStrategy(
                      const WidgetWheelEvent& aEvent)
 {
   if (aEvent.mMessage != eWheel) {
     return WheelDeltaAdjustmentStrategy::eNone;
   }
   switch (WheelPrefs::GetInstance()->ComputeActionFor(&aEvent)) {
+    case WheelPrefs::ACTION_SCROLL:
+      if (WheelPrefs::IsAutoDirEnabled() && 0 == aEvent.mDeltaZ) {
+        if (WheelPrefs::HonoursRootForAutoDir()) {
+          return WheelDeltaAdjustmentStrategy::eAutoDirWithRootHonour;
+        }
+        return WheelDeltaAdjustmentStrategy::eAutoDir;
+      }
+      return WheelDeltaAdjustmentStrategy::eNone;
     case WheelPrefs::ACTION_HORIZONTALIZED_SCROLL:
       return WheelDeltaAdjustmentStrategy::eHorizontalize;
-    // TODO Auto-dir scrolling is going to be handled here while implementing it
     default:
       // Prevent compilation errors generated by -Werror=switch
       break;
   }
   return WheelDeltaAdjustmentStrategy::eNone;
 }
 
 void
--- a/dom/events/EventStateManager.h
+++ b/dom/events/EventStateManager.h
@@ -308,20 +308,25 @@ public:
 
   // Returns true if the given WidgetWheelEvent will resolve to a scroll action.
   static bool WheelEventIsScrollAction(const WidgetWheelEvent* aEvent);
 
   // For some kinds of scrollings, the delta values of WidgetWheelEvent are
   // possbile to be adjusted. This function is used to detect such scrollings
   // and returns a wheel delta adjustment strategy to use, which is corresponded
   // to the kind of the scrolling.
+  // It returns WheelDeltaAdjustmentStrategy::eAutoDir if the current default
+  // action is auto-dir scrolling which honours the scrolling target(The
+  // comments in WheelDeltaAdjustmentStrategy describes the concept in detail).
+  // It returns WheelDeltaAdjustmentStrategy::eAutoDirWithRootHonour if the
+  // current action is auto-dir scrolling which honours the root element in the
+  // document where the scrolling target is(The comments in
+  // WheelDeltaAdjustmentStrategy describes the concept in detail).
   // It returns WheelDeltaAdjustmentStrategy::eHorizontalize if the current
   // default action is horizontalized scrolling.
-  // TODO Insert new comment words about the returned value for auto-dir
-  // scrolling while implementing it.
   // It returns WheelDeltaAdjustmentStrategy::eNone to mean no delta adjustment
   // strategy should be used if the scrolling is just a tranditional scrolling
   // whose delta values are never possible to be adjusted.
   static WheelDeltaAdjustmentStrategy
   GetWheelDeltaAdjustmentStrategy(const WidgetWheelEvent& aEvent);
 
   // Returns user-set multipliers for a wheel event.
   static void GetUserPrefsForWheelEvent(const WidgetWheelEvent* aEvent,
@@ -602,16 +607,30 @@ protected:
     bool IsOverOnePageScrollAllowedY(const WidgetWheelEvent* aEvent);
 
     /**
      * WheelEventsEnabledOnPlugins() returns true if user wants to use mouse
      * wheel on plugins.
      */
     static bool WheelEventsEnabledOnPlugins();
 
+    /**
+     * Returns whether the auto-dir feature is enabled for wheel scrolling. For
+     * detailed information on auto-dir,
+     * @see mozilla::WheelDeltaAdjustmentStrategy.
+     */
+    static bool IsAutoDirEnabled();
+
+    /**
+     * Returns whether auto-dir scrolling honours root elements instead of the
+     * scrolling targets. For detailed information on auto-dir,
+     * @see mozilla::WheelDeltaAdjustmentStrategy.
+     */
+    static bool HonoursRootForAutoDir();
+
   private:
     WheelPrefs();
     ~WheelPrefs();
 
     static void OnPrefChanged(const char* aPrefName, void* aClosure);
 
     enum Index
     {
@@ -678,18 +697,19 @@ protected:
     /**
      * action values overridden by .override_x pref.
      * If an .override_x value is -1, same as the
      * corresponding mActions value.
      */
     Action mOverriddenActionsX[COUNT_OF_MULTIPLIERS];
 
     static WheelPrefs* sInstance;
-
     static bool sWheelEventsEnabledOnPlugins;
+    static bool sIsAutoDirEnabled;
+    static bool sHonoursRootForAutoDir;
   };
 
   /**
    * DeltaDirection is used for specifying whether the called method should
    * handle vertical delta or horizontal delta.
    * This is clearer than using bool.
    */
   enum DeltaDirection
--- a/dom/events/WheelHandlingHelper.h
+++ b/dom/events/WheelHandlingHelper.h
@@ -226,18 +226,43 @@ enum class WheelDeltaAdjustmentStrategy 
   // horizontal scrolling by adjusting delta values.
   // It's important to keep in mind with the percise concept of horizontalized
   // scrolling: Delta values are *ONLY* going to be adjusted during the process
   // of its default action handling; in views of any programmes other than the
   // default action handler, such as a DOM event listener or a plugin, delta
   // values are never going to be adjusted, they will still retrive original
   // delta values when horizontalization occured for default actions.
   eHorizontalize,
-  // TODO A new value for auto-dir scrolling is going to be added while
-  // implementing such scrolling.
+  // The following two strategies mean we're receving an auto-dir scroll, so we
+  // should apply auto-dir adjustment to the delta of the wheel event if needed.
+  // Auto-dir is a feature which treats any single-wheel scroll as a scroll in
+  // the only one scrollable direction if the target has only one scrollable
+  // direction. For example, if the user scrolls a vertical wheel inside a
+  // target which is horizontally scrollable but vertical unscrollable, then the
+  // vertical scroll is converted to a horizontal scroll for that target.
+  // So why do we need two different strategies for auto-dir scrolling? That's
+  // because when a wheel scroll is converted due to auto-dir, there is one
+  // thing called "honoured target" which decides which side the converted
+  // scroll goes towards. If the content of the honoured target horizontally
+  // is RTL content, then an upward scroll maps to a rightward scroll and a
+  // downward scroll maps to a leftward scroll; otherwise, an upward scroll maps
+  // to a leftward scroll and a downward scroll maps to a rightward scroll.
+  // |eAutoDir| considers the scrolling target as the honoured target.
+  // |eAutoDirWithRootHonour| takes the root element of the document with the
+  // scrolling element, and considers that as the honoured target. But note that
+  // there's one exception: for targets in an HTML document, the real root
+  // element(I.e. the <html> element) is typically not considered as a root
+  // element, but the <body> element is typically considered as a root element.
+  // If there is no <body> element, then consider the <html> element instead.
+  // And also note that like |eHorizontalize|, delta values are *ONLY* going to
+  // be adjusted during the process of its default action handling; in views of
+  // any programmes other than the default action handler, such as a DOM event
+  // listener or a plugin, delta values are never going to be adjusted.
+  eAutoDir,
+  eAutoDirWithRootHonour,
 };
 
 /**
  * When a *pure* vertical wheel event should be treated as if it was a
  * horizontal scroll because the user wants to horizontalize the wheel scroll,
  * an instance of this class will adjust the delta values upon calling
  * Horizontalize(). And the horizontalized delta values will be restored
  * automatically when the instance of this class is being destructed. Or you can
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -2737,16 +2737,44 @@ pref("mousewheel.with_shift.delta_multip
 pref("mousewheel.with_win.delta_multiplier_x", 100);
 pref("mousewheel.with_win.delta_multiplier_y", 100);
 pref("mousewheel.with_win.delta_multiplier_z", 100);
 
 // If line-height is lower than this value (in device pixels), 1 line scroll
 // scrolls this height.
 pref("mousewheel.min_line_scroll_amount", 5);
 
+// Auto-dir is a feature which treats any single-wheel scroll as a scroll in the
+// only one scrollable direction if the target has only one scrollable
+// direction. For example, if the user scrolls a vertical wheel inside a target
+// which is horizontally scrollable but vertical unscrollable, then the vertical
+// scroll is converted to a horizontal scroll for that target.
+// Note that auto-dir only takes effect for |mousewheel.*.action|s and
+// |mousewheel.*.action.override_x|s whose values are 1.
+#ifdef EARLY_BETA_OR_EARLIER
+pref("mousewheel.autodir.enabled", true);
+#else
+pref("mousewheel.autodir.enabled", false);
+#endif
+// When a wheel scroll is converted due to auto-dir, which side the converted
+// scroll goes towards is decided by one thing called "honoured target". If the
+// content of the honoured target horizontally starts from right to left, then
+// an upward scroll maps to a rightward scroll and a downward scroll maps to a
+// leftward scroll; otherwise, an upward scroll maps to a leftward scroll and a
+// downward scroll maps to a rightward scroll.
+// If this pref is set to false, then consider the scrolling target as the
+// honoured target.
+// If set to true, then consider the root element in the document where the
+// scrolling target is as the honoured target. But note that there's one
+// exception: for targets in an HTML document, the real root element(I.e. the
+// <html> element) is typically not considered as a root element, but the <body>
+// element is typically considered as a root element. If there is no <body>
+// element, then consider the <html> element instead.
+pref("mousewheel.autodir.honourroot", false);
+
 // These define the smooth scroll behavior (min ms, max ms) for different triggers
 // Some triggers:
 // mouseWheel: Discrete mouse wheel events, Synaptics touchpads on windows (generate wheel events)
 // Lines:  Up/Down/Left/Right KB arrows
 // Pages:  Page up/down, Space
 // Scrollbars: Clicking scrollbars arrows, clicking scrollbars tracks
 // Note: Currently OS X trackpad and magic mouse don't use our smooth scrolling
 // Note: These are relevant only when "general.smoothScroll" is enabled