- 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