Bug 1358017 - Part 3: Defines a common interface of the auto-dir scrolling delta adjuster. r?masayuki, kats draft
authorZhang Junzhi <zjz@zjz.name>
Fri, 16 Mar 2018 00:48:35 +0800
changeset 774635 1553f54e54f60c2cfc327341bbb346ac89147792
parent 774634 d5e96e8bc71c2e695689941e2f86dd1747580253
child 774636 97479cdba49c443b3c66c901b8515582e11b2f57
push id104460
push userbmo:zjz@zjz.name
push dateThu, 29 Mar 2018 08:46:31 +0000
reviewersmasayuki, kats
bugs1358017
milestone61.0a1
Bug 1358017 - Part 3: Defines a common interface of the auto-dir scrolling delta adjuster. r?masayuki, kats This commit defines a common interface of the auto-dir scrolling functionality. In future commits, it will be implemented in both the APZ and non-APZ parts. MozReview-Commit-ID: 8fApuHwsbrv
dom/events/WheelHandlingHelper.cpp
dom/events/WheelHandlingHelper.h
--- 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 "mozilla/dom/WheelEventBinding.h"
 #include "nsCOMPtr.h"
 #include "nsContentUtils.h"
 #include "nsIContent.h"
@@ -632,9 +634,76 @@ void WheelDeltaHorizontalizer::CancelHor
   }
 }
 
 WheelDeltaHorizontalizer::~WheelDeltaHorizontalizer()
 {
   CancelHorizontalization();
 }
 
+/******************************************************************/
+/* mozilla::AutoDirWheelDeltaAdjuster                             */
+/******************************************************************/
+
+bool
+AutoDirWheelDeltaAdjuster::ShouldBeAdjusted()
+{
+  // Sometimes, this function can be called more than one time. If we have
+  // already checked if the scroll should be adjusted, there's no need to check
+  // it again.
+  if (mCheckedIfShouldBeAdjusted) {
+    return mShouldBeAdjusted;
+  }
+  mCheckedIfShouldBeAdjusted = true;
+
+  // For an auto-dir wheel scroll, if all the following conditions are met, we
+  // should adjust 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 && 0 != mDeltaY) || (0 == mDeltaX && 0 == mDeltaY)) {
+    return false;
+  }
+  if (0 != mDeltaX) {
+    if (CanScrollAlongXAxis()) {
+      return false;
+    }
+    if (IsHorizontalContentRightToLeft()) {
+      mShouldBeAdjusted = mDeltaX > 0 ? CanScrollUpwards()
+                                      : CanScrollDownwards();
+    } else {
+      mShouldBeAdjusted = mDeltaX < 0 ? CanScrollUpwards()
+                                      : CanScrollDownwards();
+    }
+    return mShouldBeAdjusted;
+  }
+  MOZ_ASSERT(0 != mDeltaY);
+  if (CanScrollAlongYAxis()) {
+    return false;
+  }
+  if (IsHorizontalContentRightToLeft()) {
+    mShouldBeAdjusted = mDeltaY > 0 ? CanScrollLeftwards()
+                                    : CanScrollRightwards();
+  } else {
+    mShouldBeAdjusted = mDeltaY < 0 ? CanScrollLeftwards()
+                                    : CanScrollRightwards();
+  }
+  return mShouldBeAdjusted;
+}
+
+void
+AutoDirWheelDeltaAdjuster::Adjust()
+{
+  if (!ShouldBeAdjusted()) {
+    return;
+  }
+  std::swap(mDeltaX, mDeltaY);
+  if (IsHorizontalContentRightToLeft()) {
+    mDeltaX *= -1;
+    mDeltaY *= -1;
+  }
+  mShouldBeAdjusted = false;
+  OnAdjusted();
+}
+
 } // namespace mozilla
--- a/dom/events/WheelHandlingHelper.h
+++ b/dom/events/WheelHandlingHelper.h
@@ -292,11 +292,93 @@ private:
   WidgetWheelEvent& mWheelEvent;
   double mOldDeltaX;
   double mOldDeltaZ;
   double mOldOverflowDeltaX;
   int32_t mOldLineOrPageDeltaX;
   bool mHorizontalized;
 };
 
+/**
+ * This class is used to adjust the delta values for wheel scrolling with the
+ * auto-dir functionality.
+ * A traditional wheel scroll only allows the user use the wheel in the same
+ * scrollable direction as that of the scrolling target to scroll the target,
+ * whereas an auto-dir scroll lets the user use any wheel(either a vertical
+ * wheel or a horizontal tilt wheel) to scroll a frame which is scrollable in
+ * only one direction. For detailed information on auto-dir scrolling,
+ * @see mozilla::WheelDeltaAdjustmentStrategy.
+ */
+class MOZ_STACK_CLASS AutoDirWheelDeltaAdjuster
+{
+protected:
+  /**
+   * @param aDeltaX            DeltaX for a wheel event whose delta values will
+   *                           be adjusted upon calling Adjust() when
+   *                           ShouldBeAdjusted() returns true.
+   * @param aDeltaY            DeltaY for a wheel event, like DeltaX.
+   */
+  AutoDirWheelDeltaAdjuster(double& aDeltaX,
+                            double& aDeltaY)
+    : mDeltaX(aDeltaX)
+    , mDeltaY(aDeltaY)
+    , mCheckedIfShouldBeAdjusted(false)
+    , mShouldBeAdjusted(false)
+  {
+  }
+
+public:
+  /**
+   * Gets whether the values of the delta should be adjusted for auto-dir
+   * scrolling. Note that if Adjust() has been called, this function simply
+   * returns false.
+   *
+   * @return true if the delta should be adjusted; otherwise false.
+   */
+  bool ShouldBeAdjusted();
+  /**
+   * Adjusts the values of the delta values for auto-dir scrolling when
+   * ShouldBeAdjusted() returns true. If you call it when ShouldBeAdjusted()
+   * returns false, this function will simply do nothing.
+   */
+  void Adjust();
+
+private:
+  /**
+   * Called by Adjust() if Adjust() successfully adjusted the delta values.
+   */
+  virtual void OnAdjusted()
+  {
+  }
+
+  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 horizontal content starts at rightside.
+   *
+   * @return If the content 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;
+
+protected:
+  double& mDeltaX;
+  double& mDeltaY;
+
+private:
+  bool mCheckedIfShouldBeAdjusted;
+  bool mShouldBeAdjusted;
+};
+
 } // namespace mozilla
 
 #endif // mozilla_WheelHandlingHelper_h_