Title: [173894] trunk/Source/WebCore
Revision
173894
Author
bfulg...@apple.com
Date
2014-09-23 15:16:25 -0700 (Tue, 23 Sep 2014)

Log Message

Implement snapping behavior for Mac overflow scrolling
https://bugs.webkit.org/show_bug.cgi?id=135774

Patch by Wenson Hsieh <wenson_hs...@apple.com> on 2014-09-22
Reviewed by Beth Dakin.

Hooks into AxisScrollSnapAnimator to implement overflow scroll snapping on Mac.

We need to find a way to test this!

* dom/Element.cpp:
(WebCore::Element::dispatchWheelEvent):
* page/EventHandler.cpp:
(WebCore::handleWheelEventInAppropriateEnclosingBoxForSingleAxis):
* platform/ScrollAnimator.cpp:
(WebCore::ScrollAnimator::handleWheelEvent):
(WebCore::ScrollAnimator::updateScrollAnimatorsAndTimers):
(WebCore::ScrollAnimator::scrollOffsetInAxis):
(WebCore::ScrollAnimator::immediateScrollInAxis):
(WebCore::ScrollAnimator::startScrollSnapTimer):
(WebCore::ScrollAnimator::stopScrollSnapTimer):
(WebCore::ScrollAnimator::horizontalScrollSnapTimerFired):
(WebCore::ScrollAnimator::verticalScrollSnapTimerFired):
* platform/ScrollAnimator.h:
* platform/mac/AxisScrollSnapAnimator.h:
* platform/mac/AxisScrollSnapAnimator.mm:
(WebCore::AxisScrollSnapAnimator::AxisScrollSnapAnimator):
(WebCore::AxisScrollSnapAnimator::beginScrollSnapAnimation):
(WebCore::AxisScrollSnapAnimator::endScrollSnapAnimation):
(WebCore::AxisScrollSnapAnimator::initializeGlideParameters):
* rendering/RenderLayer.cpp:
(WebCore::RenderLayer::updateScrollInfoAfterLayout):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (173893 => 173894)


--- trunk/Source/WebCore/ChangeLog	2014-09-23 22:03:15 UTC (rev 173893)
+++ trunk/Source/WebCore/ChangeLog	2014-09-23 22:16:25 UTC (rev 173894)
@@ -1,3 +1,37 @@
+2014-09-22  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        Implement snapping behavior for Mac overflow scrolling
+        https://bugs.webkit.org/show_bug.cgi?id=135774
+
+        Reviewed by Beth Dakin.
+
+        Hooks into AxisScrollSnapAnimator to implement overflow scroll snapping on Mac.
+
+        We need to find a way to test this!
+
+        * dom/Element.cpp:
+        (WebCore::Element::dispatchWheelEvent):
+        * page/EventHandler.cpp:
+        (WebCore::handleWheelEventInAppropriateEnclosingBoxForSingleAxis):
+        * platform/ScrollAnimator.cpp:
+        (WebCore::ScrollAnimator::handleWheelEvent):
+        (WebCore::ScrollAnimator::updateScrollAnimatorsAndTimers):
+        (WebCore::ScrollAnimator::scrollOffsetInAxis):
+        (WebCore::ScrollAnimator::immediateScrollInAxis):
+        (WebCore::ScrollAnimator::startScrollSnapTimer):
+        (WebCore::ScrollAnimator::stopScrollSnapTimer):
+        (WebCore::ScrollAnimator::horizontalScrollSnapTimerFired):
+        (WebCore::ScrollAnimator::verticalScrollSnapTimerFired):
+        * platform/ScrollAnimator.h:
+        * platform/mac/AxisScrollSnapAnimator.h:
+        * platform/mac/AxisScrollSnapAnimator.mm:
+        (WebCore::AxisScrollSnapAnimator::AxisScrollSnapAnimator):
+        (WebCore::AxisScrollSnapAnimator::beginScrollSnapAnimation):
+        (WebCore::AxisScrollSnapAnimator::endScrollSnapAnimation):
+        (WebCore::AxisScrollSnapAnimator::initializeGlideParameters):
+        * rendering/RenderLayer.cpp:
+        (WebCore::RenderLayer::updateScrollInfoAfterLayout):
+
 2014-09-23  Chris Dumez  <cdu...@apple.com>
 
         Use downcast<HTML*Element>() instead of toHTML*Element()

Modified: trunk/Source/WebCore/platform/ScrollAnimator.cpp (173893 => 173894)


--- trunk/Source/WebCore/platform/ScrollAnimator.cpp	2014-09-23 22:03:15 UTC (rev 173893)
+++ trunk/Source/WebCore/platform/ScrollAnimator.cpp	2014-09-23 22:16:25 UTC (rev 173894)
@@ -82,6 +82,18 @@
 
 bool ScrollAnimator::handleWheelEvent(const PlatformWheelEvent& e)
 {
+#if ENABLE(CSS_SCROLL_SNAP) && PLATFORM(MAC)
+    if (m_verticalScrollSnapAnimator) {
+        m_verticalScrollSnapAnimator->handleWheelEvent(e);
+        if (m_verticalScrollSnapAnimator->shouldOverrideWheelEvent(e))
+            return false;
+    }
+    if (m_horizontalScrollSnapAnimator) {
+        m_horizontalScrollSnapAnimator->handleWheelEvent(e);
+        if (m_horizontalScrollSnapAnimator->shouldOverrideWheelEvent(e))
+            return false;
+    }
+#endif
 #if PLATFORM(COCOA)
     // Events in the PlatformWheelEventPhaseMayBegin phase have no deltas, and therefore never passes through the scroll handling logic below.
     // This causes us to return with an 'unhandled' return state, even though this event was successfully processed.
@@ -158,4 +170,64 @@
     m_scrollableArea->setScrollOffsetFromAnimation(IntPoint(m_currentPosX, m_currentPosY));
 }
 
+#if ENABLE(CSS_SCROLL_SNAP) && PLATFORM(MAC)
+void ScrollAnimator::updateScrollAnimatorsAndTimers()
+{
+    // FIXME: Currently, scroll snap animators are recreated even though the snap offsets alone can be updated.
+    if (m_scrollableArea->horizontalSnapOffsets()) {
+        m_horizontalScrollSnapAnimator = std::make_unique<AxisScrollSnapAnimator>(this, m_scrollableArea->horizontalSnapOffsets(), ScrollEventAxis::Horizontal);
+        m_horizontalScrollSnapTimer = std::make_unique<Timer<ScrollAnimator>>(this, &ScrollAnimator::horizontalScrollSnapTimerFired);
+    } else if (m_horizontalScrollSnapAnimator) {
+        m_horizontalScrollSnapAnimator = nullptr;
+        m_horizontalScrollSnapTimer = nullptr;
+    }
+    if (m_scrollableArea->verticalSnapOffsets()) {
+        m_verticalScrollSnapAnimator = std::make_unique<AxisScrollSnapAnimator>(this, m_scrollableArea->verticalSnapOffsets(), ScrollEventAxis::Vertical);
+        m_verticalScrollSnapTimer = std::make_unique<Timer<ScrollAnimator>>(this, &ScrollAnimator::verticalScrollSnapTimerFired);
+    } else if (m_verticalScrollSnapAnimator) {
+        m_verticalScrollSnapAnimator = nullptr;
+        m_verticalScrollSnapTimer = nullptr;
+    }
+}
+
+LayoutUnit ScrollAnimator::scrollOffsetInAxis(ScrollEventAxis axis)
+{
+    FloatPoint currentPosition = this->currentPosition();
+    return axis == ScrollEventAxis::Horizontal ? currentPosition.x() : currentPosition.y();
+}
+
+void ScrollAnimator::immediateScrollInAxis(ScrollEventAxis axis, float delta)
+{
+    FloatPoint currentPosition = this->currentPosition();
+    if (axis == ScrollEventAxis::Horizontal)
+        scrollToOffsetWithoutAnimation(FloatPoint(currentPosition.x() + delta, currentPosition.y()));
+    else
+        scrollToOffsetWithoutAnimation(FloatPoint(currentPosition.x(), currentPosition.y() + delta));
+}
+
+void ScrollAnimator::startScrollSnapTimer(ScrollEventAxis axis)
+{
+    Timer<ScrollAnimator>* scrollSnapTimer = axis == ScrollEventAxis::Horizontal ? m_horizontalScrollSnapTimer.get() : m_verticalScrollSnapTimer.get();
+    if (!scrollSnapTimer->isActive())
+        scrollSnapTimer->startRepeating(1.0 / 60.0);
+}
+
+void ScrollAnimator::stopScrollSnapTimer(ScrollEventAxis axis)
+{
+    Timer<ScrollAnimator>* scrollSnapTimer = axis == ScrollEventAxis::Horizontal ? m_horizontalScrollSnapTimer.get() : m_verticalScrollSnapTimer.get();
+    if (scrollSnapTimer->isActive())
+        scrollSnapTimer->stop();
+}
+
+void ScrollAnimator::horizontalScrollSnapTimerFired(Timer<ScrollAnimator>&)
+{
+    m_horizontalScrollSnapAnimator->scrollSnapAnimationUpdate();
+}
+
+void ScrollAnimator::verticalScrollSnapTimerFired(Timer<ScrollAnimator>&)
+{
+    m_verticalScrollSnapAnimator->scrollSnapAnimationUpdate();
+}
+#endif
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/platform/ScrollAnimator.h (173893 => 173894)


--- trunk/Source/WebCore/platform/ScrollAnimator.h	2014-09-23 22:03:15 UTC (rev 173893)
+++ trunk/Source/WebCore/platform/ScrollAnimator.h	2014-09-23 22:16:25 UTC (rev 173894)
@@ -37,6 +37,11 @@
 #include <wtf/FastMalloc.h>
 #include <wtf/Forward.h>
 
+#if ENABLE(CSS_SCROLL_SNAP) && PLATFORM(MAC)
+#include "AxisScrollSnapAnimator.h"
+#include "Timer.h"
+#endif
+
 namespace WebCore {
 
 class FloatPoint;
@@ -44,7 +49,11 @@
 class ScrollableArea;
 class Scrollbar;
 
+#if ENABLE(CSS_SCROLL_SNAP) && PLATFORM(MAC)
+class ScrollAnimator : public AxisScrollSnapAnimatorClient {
+#else
 class ScrollAnimator {
+#endif
     WTF_MAKE_FAST_ALLOCATED;
 public:
     static PassOwnPtr<ScrollAnimator> create(ScrollableArea*);
@@ -106,14 +115,35 @@
 
     virtual bool isRubberBandInProgress() const { return false; }
 
+#if ENABLE(CSS_SCROLL_SNAP) && PLATFORM(MAC)
+    void updateScrollAnimatorsAndTimers();
+    virtual LayoutUnit scrollOffsetInAxis(ScrollEventAxis) override;
+    virtual void immediateScrollInAxis(ScrollEventAxis, float delta) override;
+    virtual void startScrollSnapTimer(ScrollEventAxis) override;
+    virtual void stopScrollSnapTimer(ScrollEventAxis) override;
+#endif
+
 protected:
     explicit ScrollAnimator(ScrollableArea*);
 
     virtual void notifyPositionChanged(const FloatSize& delta);
 
+#if ENABLE(CSS_SCROLL_SNAP) && PLATFORM(MAC)
+    // Trivial wrappers around the actual update loop in AxisScrollSnapAnimator, since WebCore Timer requires a Timer argument.
+    void horizontalScrollSnapTimerFired(Timer<ScrollAnimator>&);
+    void verticalScrollSnapTimerFired(Timer<ScrollAnimator>&);
+#endif
+
     ScrollableArea* m_scrollableArea;
     float m_currentPosX; // We avoid using a FloatPoint in order to reduce
     float m_currentPosY; // subclass code complexity.
+#if ENABLE(CSS_SCROLL_SNAP) && PLATFORM(MAC)
+    std::unique_ptr<AxisScrollSnapAnimator> m_horizontalScrollSnapAnimator;
+    std::unique_ptr<Timer<ScrollAnimator>> m_horizontalScrollSnapTimer;
+    // FIXME: Find a way to consolidate both timers into one variable.
+    std::unique_ptr<AxisScrollSnapAnimator> m_verticalScrollSnapAnimator;
+    std::unique_ptr<Timer<ScrollAnimator>> m_verticalScrollSnapTimer;
+#endif
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/platform/mac/AxisScrollSnapAnimator.h (173893 => 173894)


--- trunk/Source/WebCore/platform/mac/AxisScrollSnapAnimator.h	2014-09-23 22:03:15 UTC (rev 173893)
+++ trunk/Source/WebCore/platform/mac/AxisScrollSnapAnimator.h	2014-09-23 22:16:25 UTC (rev 173894)
@@ -59,13 +59,13 @@
 public:
     virtual LayoutUnit scrollOffsetInAxis(ScrollEventAxis) = 0;
     virtual void immediateScrollInAxis(ScrollEventAxis, float velocity) = 0;
-    virtual void startScrollSnapTimer() = 0;
-    virtual void stopScrollSnapTimer() = 0;
+    virtual void startScrollSnapTimer(ScrollEventAxis) = 0;
+    virtual void stopScrollSnapTimer(ScrollEventAxis) = 0;
 };
 
 class AxisScrollSnapAnimator {
 public:
-    AxisScrollSnapAnimator(AxisScrollSnapAnimatorClient*, Vector<LayoutUnit>* snapOffsets, ScrollEventAxis);
+    AxisScrollSnapAnimator(AxisScrollSnapAnimatorClient*, const Vector<LayoutUnit>* snapOffsets, ScrollEventAxis);
     void handleWheelEvent(const PlatformWheelEvent&);
     bool shouldOverrideWheelEvent(const PlatformWheelEvent&) const;
     void scrollSnapAnimationUpdate();
@@ -85,7 +85,7 @@
     static const int wheelDeltaWindowSize = 3;
 
     AxisScrollSnapAnimatorClient* m_client;
-    Vector<LayoutUnit>* m_snapOffsets;
+    const Vector<LayoutUnit>* m_snapOffsets;
     ScrollEventAxis m_axis;
     // Used to track both snapping and gliding behaviors.
     ScrollSnapState m_currentState;

Modified: trunk/Source/WebCore/platform/mac/AxisScrollSnapAnimator.mm (173893 => 173894)


--- trunk/Source/WebCore/platform/mac/AxisScrollSnapAnimator.mm	2014-09-23 22:03:15 UTC (rev 173893)
+++ trunk/Source/WebCore/platform/mac/AxisScrollSnapAnimator.mm	2014-09-23 22:16:25 UTC (rev 173894)
@@ -82,7 +82,7 @@
     return inertialScrollPredictionFactor * initialWheelDelta;
 }
 
-AxisScrollSnapAnimator::AxisScrollSnapAnimator(AxisScrollSnapAnimatorClient* client, Vector<LayoutUnit>* snapOffsets, ScrollEventAxis axis)
+AxisScrollSnapAnimator::AxisScrollSnapAnimator(AxisScrollSnapAnimatorClient* client, const Vector<LayoutUnit>* snapOffsets, ScrollEventAxis axis)
     : m_client(client)
     , m_snapOffsets(snapOffsets)
     , m_axis(axis)
@@ -184,7 +184,7 @@
         initializeGlideParameters(glideRequiresBoost);
         clearInitialWheelDeltaWindow();
     }
-    m_client->startScrollSnapTimer();
+    m_client->startScrollSnapTimer(m_axis);
 }
 
 void AxisScrollSnapAnimator::endScrollSnapAnimation(ScrollSnapState newState)
@@ -194,7 +194,7 @@
         clearInitialWheelDeltaWindow();
 
     m_currentState = newState;
-    m_client->stopScrollSnapTimer();
+    m_client->stopScrollSnapTimer(m_axis);
 }
 
 // Computes the amount to scroll by when performing a "snap" operation, i.e. when a user releases the trackpad without flicking. The snap delta

Modified: trunk/Source/WebCore/rendering/RenderLayer.cpp (173893 => 173894)


--- trunk/Source/WebCore/rendering/RenderLayer.cpp	2014-09-23 22:03:15 UTC (rev 173893)
+++ trunk/Source/WebCore/rendering/RenderLayer.cpp	2014-09-23 22:16:25 UTC (rev 173894)
@@ -3382,7 +3382,11 @@
     // FIXME: Ensure that offsets are also updated in case of programmatic style changes.
     // https://bugs.webkit.org/show_bug.cgi?id=135964
     updateSnapOffsets();
+#if PLATFORM(MAC)
+    if (existingScrollAnimator())
+        scrollAnimator()->updateScrollAnimatorsAndTimers();
 #endif
+#endif
 }
 
 bool RenderLayer::overflowControlsIntersectRect(const IntRect& localRect) const
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to