Bug 1601185. Add a function that returns if a user can scroll on a given scroll frame in either direction and use it in EventStateManager::ComputeScrollTargetAndMayAdjustWheelEvent. r?botond draft
authorTimothy Nikkel <tnikkel@gmail.com>
Wed, 04 Dec 2019 21:05:25 -0600
changeset 2517417 83f36cf4a9d89a525bbb3a1773179f2844a2c612
parent 2517416 b3c0fb9928dab79dd15c570fa7a13d3136f3b41d
child 2517418 58ff44087045637de7a0b3ed9b2a1e1789d1c05b
push id460520
push usertnikkel@gmail.com
push dateThu, 05 Dec 2019 03:12:35 +0000
treeherdertry@58ff44087045 [default view] [failures only]
reviewersbotond
bugs1601185
milestone73.0a1
Bug 1601185. Add a function that returns if a user can scroll on a given scroll frame in either direction and use it in EventStateManager::ComputeScrollTargetAndMayAdjustWheelEvent. r?botond Previously we were just checking overflow hidden here, which is not enough because we can scroll overflow hidden if we are zoomed in.
dom/events/EventStateManager.cpp
layout/generic/nsGfxScrollFrame.cpp
layout/generic/nsGfxScrollFrame.h
layout/generic/nsIScrollableFrame.h
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -2636,22 +2636,24 @@ nsIFrame* EventStateManager::ComputeScro
         case layers::ScrollDirection::eVertical:
           if (checkIfScrollableY) {
             continue;
           }
           break;
       }
     }
 
-    ScrollStyles ss = scrollableFrame->GetScrollStyles();
-    bool hiddenForV = (StyleOverflow::Hidden == ss.mVertical);
-    bool hiddenForH = (StyleOverflow::Hidden == ss.mHorizontal);
-    if ((hiddenForV && hiddenForH) ||
-        (checkIfScrollableY && !checkIfScrollableX && hiddenForV) ||
-        (checkIfScrollableX && !checkIfScrollableY && hiddenForH)) {
+    uint32_t directions =
+        scrollableFrame->GetAvailableScrollingDirectionsForUserInputEvents();
+    if ((!(directions & nsIScrollableFrame::VERTICAL) &&
+         !(directions & nsIScrollableFrame::HORIZONTAL)) ||
+        (checkIfScrollableY && !checkIfScrollableX &&
+         !(directions & nsIScrollableFrame::VERTICAL)) ||
+        (checkIfScrollableX && !checkIfScrollableY &&
+         !(directions & nsIScrollableFrame::HORIZONTAL))) {
       continue;
     }
 
     // Computes whether the currently checked frame is scrollable by this wheel
     // event.
     bool canScroll = false;
     if (isAutoDir) {
       ESMAutoDirWheelDeltaAdjuster adjuster(*aEvent, *scrollFrame, honoursRoot);
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -6663,16 +6663,49 @@ uint32_t nsIScrollableFrame::GetAvailabl
     directions |= HORIZONTAL;
   }
   if (scrollRange.height >= oneDevPixel) {
     directions |= VERTICAL;
   }
   return directions;
 }
 
+uint32_t ScrollFrameHelper::GetAvailableScrollingDirectionsForUserInputEvents()
+    const {
+  // This function basically computes a scroll range based on a scrolled rect
+  // and scroll port defined as follows:
+  //   scrollable rect = overflow:hidden ? layout viewport : scrollable rect
+  //   scroll port = have visual viewport ? visual viewport : layout viewport
+
+  ScrollStyles ss = GetScrollStylesFromFrame();
+
+  nsRect scrolledRect = GetScrolledRect();
+  if (StyleOverflow::Hidden == ss.mHorizontal) {
+    scrolledRect.width = mScrollPort.width;
+  }
+  if (StyleOverflow::Hidden == ss.mVertical) {
+    scrolledRect.height = mScrollPort.height;
+  }
+
+  nsSize scrollPort = GetVisualViewportSize();
+
+  nsSize scrollRange;
+  scrollRange.width = std::max(scrolledRect.width - scrollPort.width, 0);
+  scrollRange.height = std::max(scrolledRect.height - scrollPort.height, 0);
+
+  uint32_t directions = 0;
+  if (scrollRange.width > 0) {
+    directions |= nsIScrollableFrame::HORIZONTAL;
+  }
+  if (scrollRange.height > 0) {
+    directions |= nsIScrollableFrame::VERTICAL;
+  }
+  return directions;
+}
+
 static nsRect InflateByScrollMargin(const nsRect& aTargetRect,
                                     const nsMargin& aScrollMargin,
                                     const nsRect& aScrolledRect) {
   // Inflate the rect by scroll-margin.
   nsRect result = aTargetRect;
   result.Inflate(aScrollMargin);
 
   // But don't be beyond the limit boundary.
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -327,16 +327,18 @@ class ScrollFrameHelper : public nsIRefl
    * Currently it allows scrolling down and to the right for
    * nsHTMLScrollFrames with LTR directionality and for all
    * nsXULScrollFrames, and allows scrolling down and to the left for
    * nsHTMLScrollFrames with RTL directionality.
    */
   nsRect GetUnsnappedScrolledRectInternal(const nsRect& aScrolledOverflowArea,
                                           const nsSize& aScrollPortSize) const;
 
+  uint32_t GetAvailableScrollingDirectionsForUserInputEvents() const;
+
   uint32_t GetScrollbarVisibility() const {
     return (mHasVerticalScrollbar ? nsIScrollableFrame::VERTICAL : 0) |
            (mHasHorizontalScrollbar ? nsIScrollableFrame::HORIZONTAL : 0);
   }
   nsMargin GetActualScrollbarSizes() const;
   nsMargin GetDesiredScrollbarSizes(nsBoxLayoutState* aState);
   nscoord GetNondisappearingScrollbarWidth(nsBoxLayoutState* aState,
                                            mozilla::WritingMode aVerticalWM);
@@ -857,16 +859,19 @@ class nsHTMLScrollFrame : public nsConta
   }
   mozilla::ScrollStyles GetScrollStyles() const override {
     return mHelper.GetScrollStylesFromFrame();
   }
   mozilla::layers::OverscrollBehaviorInfo GetOverscrollBehaviorInfo()
       const final {
     return mHelper.GetOverscrollBehaviorInfo();
   }
+  uint32_t GetAvailableScrollingDirectionsForUserInputEvents() const final {
+    return mHelper.GetAvailableScrollingDirectionsForUserInputEvents();
+  }
   uint32_t GetScrollbarVisibility() const final {
     return mHelper.GetScrollbarVisibility();
   }
   nsMargin GetActualScrollbarSizes() const final {
     return mHelper.GetActualScrollbarSizes();
   }
   nsMargin GetDesiredScrollbarSizes(nsBoxLayoutState* aState) final {
     return mHelper.GetDesiredScrollbarSizes(aState);
@@ -1319,16 +1324,19 @@ class nsXULScrollFrame final : public ns
   }
   mozilla::ScrollStyles GetScrollStyles() const final {
     return mHelper.GetScrollStylesFromFrame();
   }
   mozilla::layers::OverscrollBehaviorInfo GetOverscrollBehaviorInfo()
       const final {
     return mHelper.GetOverscrollBehaviorInfo();
   }
+  uint32_t GetAvailableScrollingDirectionsForUserInputEvents() const final {
+    return mHelper.GetAvailableScrollingDirectionsForUserInputEvents();
+  }
   uint32_t GetScrollbarVisibility() const final {
     return mHelper.GetScrollbarVisibility();
   }
   nsMargin GetActualScrollbarSizes() const final {
     return mHelper.GetActualScrollbarSizes();
   }
   nsMargin GetDesiredScrollbarSizes(nsBoxLayoutState* aState) final {
     return mHelper.GetDesiredScrollbarSizes(aState);
--- a/layout/generic/nsIScrollableFrame.h
+++ b/layout/generic/nsIScrollableFrame.h
@@ -96,16 +96,23 @@ class nsIScrollableFrame : public nsIScr
   uint32_t GetAvailableScrollingDirections() const;
   /**
    * Returns the directions in which scrolling is allowed (if the scroll range
    * is at least one device pixel in that direction) when taking into account
    * the visual viewport size.
    */
   uint32_t GetAvailableVisualScrollingDirections() const;
   /**
+   * Returns the directions in which scrolling is allowed when taking into
+   * account the visual viewport size and overflow hidden. (An (apz) zoomed in
+   * overflow hidden scrollframe is actually user scrollable.)
+   */
+  virtual uint32_t GetAvailableScrollingDirectionsForUserInputEvents()
+      const = 0;
+  /**
    * Return the actual sizes of all possible scrollbars. Returns 0 for scrollbar
    * positions that don't have a scrollbar or where the scrollbar is not
    * visible. Do not call this while this frame's descendants are being
    * reflowed, it won't be accurate.
    */
   virtual nsMargin GetActualScrollbarSizes() const = 0;
   /**
    * Return the sizes of all scrollbars assuming that any scrollbars that could