Changeset 217971 in webkit


Ignore:
Timestamp:
Jun 9, 2017 1:58:30 AM (7 years ago)
Author:
Yusuke Suzuki
Message:

[GTK] Add kinetic scrolling
https://bugs.webkit.org/show_bug.cgi?id=155750

Patch by Adrien Plazas <aplazas@igalia.com> on 2017-06-09
Reviewed by Carlos Garcia Campos.

Patch by Adrien Plazas and Yusuke Suzuki.

Source/WebCore:

Add the ScrollAnimationKinetic scrolling animation allowing to perform momentum scrolling; it is based on GTK+'s
GtkKineticScrolling type.

Add the notion of phase, momentum phase and swipe velocity to PlatformWheelEvent.

Depending on whether the scrolling ended normally or triggered a swipe, the scroll animator will either compute
the swipe velocity from the previous scrolling events or use the one from the swipe gesture to initiate the
momentum scrolling.

  • PlatformGTK.cmake:
  • platform/PlatformWheelEvent.h:

(WebCore::PlatformWheelEvent::setHasPreciseScrollingDeltas):
(WebCore::PlatformWheelEvent::phase):
(WebCore::PlatformWheelEvent::momentumPhase):
(WebCore::PlatformWheelEvent::isTransitioningToMomentumScroll):

  • platform/ScrollAnimation.h:

(WebCore::ScrollAnimation::scroll):
(WebCore::ScrollAnimation::updateVisibleLengths):
(WebCore::ScrollAnimation::setCurrentPosition):

  • platform/ScrollAnimationKinetic.cpp: Added.

(WebCore::ScrollAnimationKinetic::PerAxisData::PerAxisData):
(WebCore::ScrollAnimationKinetic::PerAxisData::animateScroll):
(WebCore::ScrollAnimationKinetic::ScrollAnimationKinetic):
(WebCore::ScrollAnimationKinetic::~ScrollAnimationKinetic):
(WebCore::ScrollAnimationKinetic::stop):
(WebCore::ScrollAnimationKinetic::start):
(WebCore::ScrollAnimationKinetic::animationTimerFired):

  • platform/ScrollAnimationKinetic.h: Copied from Source/WebCore/platform/ScrollAnimation.h.
  • platform/gtk/PlatformWheelEventGtk.cpp:

(WebCore::PlatformWheelEvent::PlatformWheelEvent):
(WebCore::PlatformWheelEvent::swipeVelocity):

  • platform/gtk/ScrollAnimatorGtk.cpp:

(WebCore::ScrollAnimatorGtk::ScrollAnimatorGtk):
(WebCore::ScrollAnimatorGtk::ensureSmoothScrollingAnimation):
(WebCore::ScrollAnimatorGtk::scroll):
(WebCore::ScrollAnimatorGtk::scrollToOffsetWithoutAnimation):
(WebCore::ScrollAnimatorGtk::computeVelocity):
(WebCore::ScrollAnimatorGtk::handleWheelEvent):
(WebCore::ScrollAnimatorGtk::willEndLiveResize):
(WebCore::ScrollAnimatorGtk::updatePosition):
(WebCore::ScrollAnimatorGtk::didAddVerticalScrollbar):
(WebCore::ScrollAnimatorGtk::didAddHorizontalScrollbar):

  • platform/gtk/ScrollAnimatorGtk.h:

Source/WebKit2:

Add the notion of phase and momentum phase to WebWheelEvent.

Make WebWheelEvent manage the 'is_stop' attribute of GdkEventScroll to create the corresponding WebWheelEvent
with the correct phases and deltas.

Make GestureController manage swipes to create the corresponding WebWheelEvent with the correct phases and
deltas.

  • Shared/NativeWebWheelEvent.h:
  • Shared/WebEvent.h:
  • Shared/WebEventConversion.cpp:

(WebKit::WebKit2PlatformWheelEvent::WebKit2PlatformWheelEvent):

  • Shared/WebWheelEvent.cpp:

(WebKit::WebWheelEvent::WebWheelEvent):
(WebKit::WebWheelEvent::encode):
(WebKit::WebWheelEvent::decode):

  • Shared/gtk/NativeWebWheelEventGtk.cpp:

(WebKit::NativeWebWheelEvent::NativeWebWheelEvent):

  • Shared/gtk/WebEventFactory.cpp:

(WebKit::WebEventFactory::createWebWheelEvent):

  • Shared/gtk/WebEventFactory.h:
  • UIProcess/WebPageProxy.cpp:

(WebKit::WebPageProxy::handleWheelEvent):
(WebKit::WebPageProxy::shouldProcessWheelEventNow):

  • UIProcess/WebPageProxy.h:
  • UIProcess/gtk/GestureController.cpp:

(WebKit::GestureController::GestureController):
(WebKit::GestureController::handleEvent):
(WebKit::GestureController::isProcessingGestures):
(WebKit::createScrollEvent):
(WebKit::GestureController::DragGesture::startDrag):
(WebKit::GestureController::DragGesture::handleDrag):
(WebKit::GestureController::DragGesture::begin):
(WebKit::GestureController::DragGesture::end):
(WebKit::GestureController::SwipeGesture::startMomentumScroll):
(WebKit::GestureController::SwipeGesture::swipe):
(WebKit::GestureController::SwipeGesture::SwipeGesture):

  • UIProcess/gtk/GestureController.h:
Location:
trunk/Source
Files:
1 added
19 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r217969 r217971  
     12017-06-09  Adrien Plazas  <aplazas@igalia.com>
     2
     3        [GTK] Add kinetic scrolling
     4        https://bugs.webkit.org/show_bug.cgi?id=155750
     5
     6        Reviewed by Carlos Garcia Campos.
     7
     8        Patch by Adrien Plazas and Yusuke Suzuki.
     9
     10        Add the ScrollAnimationKinetic scrolling animation allowing to perform momentum scrolling; it is based on GTK+'s
     11        GtkKineticScrolling type.
     12
     13        Add the notion of phase, momentum phase and swipe velocity to PlatformWheelEvent.
     14
     15        Depending on whether the scrolling ended normally or triggered a swipe, the scroll animator will either compute
     16        the swipe velocity from the previous scrolling events or use the one from the swipe gesture to initiate the
     17        momentum scrolling.
     18
     19        * PlatformGTK.cmake:
     20        * platform/PlatformWheelEvent.h:
     21        (WebCore::PlatformWheelEvent::setHasPreciseScrollingDeltas):
     22        (WebCore::PlatformWheelEvent::phase):
     23        (WebCore::PlatformWheelEvent::momentumPhase):
     24        (WebCore::PlatformWheelEvent::isTransitioningToMomentumScroll):
     25        * platform/ScrollAnimation.h:
     26        (WebCore::ScrollAnimation::scroll):
     27        (WebCore::ScrollAnimation::updateVisibleLengths):
     28        (WebCore::ScrollAnimation::setCurrentPosition):
     29        * platform/ScrollAnimationKinetic.cpp: Added.
     30        (WebCore::ScrollAnimationKinetic::PerAxisData::PerAxisData):
     31        (WebCore::ScrollAnimationKinetic::PerAxisData::animateScroll):
     32        (WebCore::ScrollAnimationKinetic::ScrollAnimationKinetic):
     33        (WebCore::ScrollAnimationKinetic::~ScrollAnimationKinetic):
     34        (WebCore::ScrollAnimationKinetic::stop):
     35        (WebCore::ScrollAnimationKinetic::start):
     36        (WebCore::ScrollAnimationKinetic::animationTimerFired):
     37        * platform/ScrollAnimationKinetic.h: Copied from Source/WebCore/platform/ScrollAnimation.h.
     38        * platform/gtk/PlatformWheelEventGtk.cpp:
     39        (WebCore::PlatformWheelEvent::PlatformWheelEvent):
     40        (WebCore::PlatformWheelEvent::swipeVelocity):
     41        * platform/gtk/ScrollAnimatorGtk.cpp:
     42        (WebCore::ScrollAnimatorGtk::ScrollAnimatorGtk):
     43        (WebCore::ScrollAnimatorGtk::ensureSmoothScrollingAnimation):
     44        (WebCore::ScrollAnimatorGtk::scroll):
     45        (WebCore::ScrollAnimatorGtk::scrollToOffsetWithoutAnimation):
     46        (WebCore::ScrollAnimatorGtk::computeVelocity):
     47        (WebCore::ScrollAnimatorGtk::handleWheelEvent):
     48        (WebCore::ScrollAnimatorGtk::willEndLiveResize):
     49        (WebCore::ScrollAnimatorGtk::updatePosition):
     50        (WebCore::ScrollAnimatorGtk::didAddVerticalScrollbar):
     51        (WebCore::ScrollAnimatorGtk::didAddHorizontalScrollbar):
     52        * platform/gtk/ScrollAnimatorGtk.h:
     53
    1542017-06-09  Zan Dobersek  <zdobersek@igalia.com>
    255
  • trunk/Source/WebCore/PlatformGTK.cmake

    r217877 r217971  
    6464
    6565    platform/KillRingNone.cpp
     66    platform/ScrollAnimationKinetic.cpp
    6667    platform/StaticPasteboard.cpp
    6768    platform/UserAgentQuirks.cpp
  • trunk/Source/WebCore/platform/PlatformWheelEvent.h

    r212484 r217971  
    4949};
    5050
    51 #if PLATFORM(COCOA)
     51#if PLATFORM(COCOA) || PLATFORM(GTK)
    5252
    5353enum PlatformWheelEventPhase : uint8_t {
     
    118118#if PLATFORM(GTK)
    119119    explicit PlatformWheelEvent(GdkEventScroll*);
     120    FloatPoint swipeVelocity() const;
    120121#endif
    121122
     
    123124    bool hasPreciseScrollingDeltas() const { return m_hasPreciseScrollingDeltas; }
    124125    void setHasPreciseScrollingDeltas(bool hasPreciseScrollingDeltas) { m_hasPreciseScrollingDeltas = hasPreciseScrollingDeltas; }
    125     PlatformWheelEventPhase phase() const { return m_phase; }
    126     PlatformWheelEventPhase momentumPhase() const { return m_momentumPhase; }
    127126    unsigned scrollCount() const { return m_scrollCount; }
    128127    float unacceleratedScrollingDeltaX() const { return m_unacceleratedScrollingDeltaX; }
     
    132131    bool shouldResetLatching() const;
    133132    bool isEndOfMomentumScroll() const;
     133#else
     134    bool useLatchedEventElement() const { return false; }
     135#endif
     136
     137#if PLATFORM(COCOA) || PLATFORM(GTK)
     138    PlatformWheelEventPhase phase() const { return m_phase; }
     139    PlatformWheelEventPhase momentumPhase() const { return m_momentumPhase; }
    134140    bool isEndOfNonMomentumScroll() const;
    135141    bool isTransitioningToMomentumScroll() const;
    136 #else
    137     bool useLatchedEventElement() const { return false; }
    138142#endif
    139143
     
    156160    FloatSize m_scrollingVelocity;
    157161
     162#if PLATFORM(COCOA) || PLATFORM(GTK)
     163    PlatformWheelEventPhase m_phase { PlatformWheelEventPhaseNone };
     164    PlatformWheelEventPhase m_momentumPhase { PlatformWheelEventPhaseNone };
     165#endif
    158166#if PLATFORM(COCOA)
    159167    bool m_hasPreciseScrollingDeltas { false };
    160     PlatformWheelEventPhase m_phase { PlatformWheelEventPhaseNone };
    161     PlatformWheelEventPhase m_momentumPhase { PlatformWheelEventPhaseNone };
    162168    unsigned m_scrollCount { 0 };
    163169    float m_unacceleratedScrollingDeltaX { 0 };
     
    192198}
    193199
     200#endif
     201
     202#if PLATFORM(COCOA) || PLATFORM(GTK)
     203
    194204inline bool PlatformWheelEvent::isEndOfNonMomentumScroll() const
    195205{
     
    201211    return m_phase == PlatformWheelEventPhaseNone && m_momentumPhase == PlatformWheelEventPhaseBegan;
    202212}
    203 
    204213#endif
    205214
  • trunk/Source/WebCore/platform/ScrollAnimation.h

    r196238 r217971  
    3737public:
    3838    virtual ~ScrollAnimation() { };
    39     virtual bool scroll(ScrollbarOrientation, ScrollGranularity, float step, float multiplier) = 0;
     39    virtual bool scroll(ScrollbarOrientation, ScrollGranularity, float /* step */, float /* multiplier */) { return true; };
    4040    virtual void stop() = 0;
    41     virtual void updateVisibleLengths() = 0;
    42     virtual void setCurrentPosition(const FloatPoint&) = 0;
     41    virtual void updateVisibleLengths() { };
     42    virtual void setCurrentPosition(const FloatPoint&) { };
    4343    virtual void serviceAnimation() { };
    4444
  • trunk/Source/WebCore/platform/ScrollAnimationKinetic.h

    r217970 r217971  
    2424 */
    2525
    26 #ifndef ScrollAnimation_h
    27 #define ScrollAnimation_h
     26#pragma once
    2827
    29 #include "ScrollTypes.h"
     28#include "FloatPoint.h"
     29#include "ScrollAnimation.h"
     30#include "Timer.h"
     31
     32#include <wtf/Optional.h>
    3033
    3134namespace WebCore {
    3235
    33 class FloatPoint;
    3436class ScrollableArea;
    3537
    36 class ScrollAnimation {
     38class ScrollAnimationKinetic final: public ScrollAnimation {
     39private:
     40    class PerAxisData {
     41    public:
     42        PerAxisData(double lower, double upper, double initialPosition, double initialVelocity);
     43
     44        double position() { return m_position; }
     45
     46        bool animateScroll(Seconds timeDelta);
     47
     48    private:
     49        double m_lower { 0 };
     50        double m_upper { 0 };
     51
     52        double m_coef1 { 0 };
     53        double m_coef2 { 0 };
     54
     55        Seconds m_elapsedTime;
     56        double m_position { 0 };
     57        double m_velocity { 0 };
     58    };
     59
    3760public:
    38     virtual ~ScrollAnimation() { };
    39     virtual bool scroll(ScrollbarOrientation, ScrollGranularity, float step, float multiplier) = 0;
    40     virtual void stop() = 0;
    41     virtual void updateVisibleLengths() = 0;
    42     virtual void setCurrentPosition(const FloatPoint&) = 0;
    43     virtual void serviceAnimation() { };
     61    ScrollAnimationKinetic(ScrollableArea&, std::function<void(FloatPoint&&)>&& notifyPositionChangedFunction);
     62    virtual ~ScrollAnimationKinetic();
    4463
    45 protected:
    46     ScrollAnimation(ScrollableArea& scrollableArea)
    47         : m_scrollableArea(scrollableArea)
    48     {
    49     }
     64    void start(const FloatPoint& initialPosition, const FloatPoint& velocity, bool mayHScroll, bool mayVScroll);
    5065
    51     ScrollableArea& m_scrollableArea;
     66private:
     67    void stop() override;
     68    void animationTimerFired();
     69
     70    std::function<void(FloatPoint&&)> m_notifyPositionChangedFunction;
     71
     72    std::optional<PerAxisData> m_horizontalData;
     73    std::optional<PerAxisData> m_verticalData;
     74
     75    MonotonicTime m_startTime;
     76    Timer m_animationTimer;
     77    FloatPoint m_position;
    5278};
    5379
    5480} // namespace WebCore
    55 
    56 #endif // ScrollAnimation_h
  • trunk/Source/WebCore/platform/gtk/PlatformWheelEventGtk.cpp

    r212205 r217971  
    2929#include "PlatformWheelEvent.h"
    3030
     31#include "FloatPoint.h"
    3132#include "PlatformKeyboardEvent.h"
    3233#include "Scrollbar.h"
     
    8687    m_wheelTicksY = m_deltaY;
    8788
     89#ifndef GTK_API_VERSION_2
     90#if GTK_CHECK_VERSION(3, 20, 0)
     91    m_phase = event->is_stop ?
     92        PlatformWheelEventPhaseEnded :
     93        PlatformWheelEventPhaseChanged;
     94#else
     95    m_phase = event->direction == GDK_SCROLL_SMOOTH && !m_deltaX && !m_deltaY ?
     96        PlatformWheelEventPhaseEnded :
     97        PlatformWheelEventPhaseChanged;
     98#endif
     99#else
     100    m_phase = PlatformWheelEventPhaseChanged;
     101#endif // GTK_API_VERSION_2
     102
    88103    m_position = IntPoint(static_cast<int>(event->x), static_cast<int>(event->y));
    89104    m_globalPosition = IntPoint(static_cast<int>(event->x_root), static_cast<int>(event->y_root));
     
    96111}
    97112
     113FloatPoint PlatformWheelEvent::swipeVelocity() const
     114{
     115    // The swiping velocity is stored in the deltas of the event declaring it.
     116    return isTransitioningToMomentumScroll() ? FloatPoint(m_wheelTicksX, m_wheelTicksY) : FloatPoint();
    98117}
     118
     119}
  • trunk/Source/WebCore/platform/gtk/ScrollAnimatorGtk.cpp

    r215173 r217971  
    3232#include "ScrollAnimatorGtk.h"
    3333
     34#include "ScrollAnimationKinetic.h"
    3435#include "ScrollAnimationSmooth.h"
    3536#include "ScrollableArea.h"
     
    4142static const Seconds overflowScrollbarsAnimationDuration { 1_s };
    4243static const Seconds overflowScrollbarsAnimationHideDelay { 2_s };
     44static const Seconds scrollCaptureThreshold { 150_ms };
    4345
    4446std::unique_ptr<ScrollAnimator> ScrollAnimator::create(ScrollableArea& scrollableArea)
     
    5153    , m_overlayScrollbarAnimationTimer(*this, &ScrollAnimatorGtk::overlayScrollbarAnimationTimerFired)
    5254{
     55    m_kineticAnimation = std::make_unique<ScrollAnimationKinetic>(m_scrollableArea, [this](FloatPoint&& position) {
     56#if ENABLE(SMOOTH_SCROLLING)
     57        if (m_smoothAnimation)
     58            m_smoothAnimation->setCurrentPosition(position);
     59#endif
     60        updatePosition(WTFMove(position));
     61    });
     62
    5363#if ENABLE(SMOOTH_SCROLLING)
    5464    if (scrollableArea.scrollAnimatorEnabled())
     
    6474void ScrollAnimatorGtk::ensureSmoothScrollingAnimation()
    6575{
    66     if (m_animation)
    67         return;
    68 
    69     m_animation = std::make_unique<ScrollAnimationSmooth>(m_scrollableArea, m_currentPosition, [this](FloatPoint&& position) {
    70         FloatSize delta = position - m_currentPosition;
    71         m_currentPosition = WTFMove(position);
    72         notifyPositionChanged(delta);
     76    if (m_smoothAnimation)
     77        return;
     78
     79    m_smoothAnimation = std::make_unique<ScrollAnimationSmooth>(m_scrollableArea, m_currentPosition, [this](FloatPoint&& position) {
     80        updatePosition(WTFMove(position));
    7381    });
    7482}
    75 
     83#endif
     84
     85#if ENABLE(SMOOTH_SCROLLING)
    7686bool ScrollAnimatorGtk::scroll(ScrollbarOrientation orientation, ScrollGranularity granularity, float step, float multiplier)
    7787{
     
    8090
    8191    ensureSmoothScrollingAnimation();
    82     return m_animation->scroll(orientation, granularity, step, multiplier);
    83 }
     92    return m_smoothAnimation->scroll(orientation, granularity, step, multiplier);
     93}
     94#endif
    8495
    8596void ScrollAnimatorGtk::scrollToOffsetWithoutAnimation(const FloatPoint& offset)
    8697{
    8798    FloatPoint position = ScrollableArea::scrollPositionFromOffset(offset, toFloatSize(m_scrollableArea.scrollOrigin()));
    88     if (m_animation)
    89         m_animation->setCurrentPosition(position);
    90 
     99    m_kineticAnimation->stop();
     100    m_scrollHistory.clear();
     101
     102#if ENABLE(SMOOTH_SCROLLING)
     103    if (m_smoothAnimation)
     104        m_smoothAnimation->setCurrentPosition(position);
     105#endif
     106
     107    updatePosition(WTFMove(position));
     108}
     109
     110FloatPoint ScrollAnimatorGtk::computeVelocity()
     111{
     112    if (m_scrollHistory.isEmpty())
     113        return { };
     114
     115    double first = m_scrollHistory[0].timestamp();
     116    double last = m_scrollHistory.rbegin()->timestamp();
     117
     118    if (last == first)
     119        return { };
     120
     121    FloatPoint accumDelta;
     122    for (const auto& scrollEvent : m_scrollHistory)
     123        accumDelta += FloatPoint(scrollEvent.deltaX(), scrollEvent.deltaY());
     124
     125    m_scrollHistory.clear();
     126
     127    return FloatPoint(accumDelta.x() * -1000 / (last - first), accumDelta.y() * -1000 / (last - first));
     128}
     129
     130bool ScrollAnimatorGtk::handleWheelEvent(const PlatformWheelEvent& event)
     131{
     132    m_kineticAnimation->stop();
     133
     134    m_scrollHistory.removeAllMatching([&event] (PlatformWheelEvent& otherEvent) -> bool {
     135        return Seconds::fromMilliseconds(event.timestamp() - otherEvent.timestamp()) > scrollCaptureThreshold;
     136    });
     137
     138    if (event.isEndOfNonMomentumScroll()) {
     139        // We don't need to add the event to the history as its delta will be (0, 0).
     140        static_cast<ScrollAnimationKinetic*>(m_kineticAnimation.get())->start(m_currentPosition, computeVelocity(), m_scrollableArea.horizontalScrollbar(), m_scrollableArea.verticalScrollbar());
     141        return true;
     142    }
     143    if (event.isTransitioningToMomentumScroll()) {
     144        m_scrollHistory.clear();
     145        static_cast<ScrollAnimationKinetic*>(m_kineticAnimation.get())->start(m_currentPosition, event.swipeVelocity(), m_scrollableArea.horizontalScrollbar(), m_scrollableArea.verticalScrollbar());
     146        return true;
     147    }
     148
     149    m_scrollHistory.append(event);
     150
     151    return ScrollAnimator::handleWheelEvent(event);
     152}
     153
     154void ScrollAnimatorGtk::willEndLiveResize()
     155{
     156    m_kineticAnimation->updateVisibleLengths();
     157
     158#if ENABLE(SMOOTH_SCROLLING)
     159    if (m_smoothAnimation)
     160        m_smoothAnimation->updateVisibleLengths();
     161#endif
     162}
     163
     164void ScrollAnimatorGtk::updatePosition(FloatPoint&& position)
     165{
    91166    FloatSize delta = position - m_currentPosition;
    92     m_currentPosition = position;
     167    m_currentPosition = WTFMove(position);
    93168    notifyPositionChanged(delta);
    94169}
    95170
    96 void ScrollAnimatorGtk::willEndLiveResize()
    97 {
    98     if (m_animation)
    99         m_animation->updateVisibleLengths();
    100 }
    101 #endif
    102 
    103171void ScrollAnimatorGtk::didAddVerticalScrollbar(Scrollbar* scrollbar)
    104172{
    105 #if ENABLE(SMOOTH_SCROLLING)
    106     if (m_animation)
    107         m_animation->updateVisibleLengths();
     173    m_kineticAnimation->updateVisibleLengths();
     174
     175#if ENABLE(SMOOTH_SCROLLING)
     176    if (m_smoothAnimation)
     177        m_smoothAnimation->updateVisibleLengths();
    108178#endif
    109179    if (!scrollbar->isOverlayScrollbar())
     
    118188void ScrollAnimatorGtk::didAddHorizontalScrollbar(Scrollbar* scrollbar)
    119189{
    120 #if ENABLE(SMOOTH_SCROLLING)
    121     if (m_animation)
    122         m_animation->updateVisibleLengths();
     190    m_kineticAnimation->updateVisibleLengths();
     191
     192#if ENABLE(SMOOTH_SCROLLING)
     193    if (m_smoothAnimation)
     194        m_smoothAnimation->updateVisibleLengths();
    123195#endif
    124196    if (!scrollbar->isOverlayScrollbar())
  • trunk/Source/WebCore/platform/gtk/ScrollAnimatorGtk.h

    r215173 r217971  
    4747#if ENABLE(SMOOTH_SCROLLING)
    4848    bool scroll(ScrollbarOrientation, ScrollGranularity, float step, float multiplier) override;
     49#endif
    4950    void scrollToOffsetWithoutAnimation(const FloatPoint&) override;
    5051    void willEndLiveResize() override;
    51 #endif
     52
     53    bool handleWheelEvent(const PlatformWheelEvent&) override;
    5254
    5355    void didAddVerticalScrollbar(Scrollbar*) override;
     
    6466    void lockOverlayScrollbarStateToHidden(bool) override;
    6567
     68    void updatePosition(FloatPoint&&);
     69
    6670    void overlayScrollbarAnimationTimerFired();
    6771    void showOverlayScrollbars();
     
    6973    void updateOverlayScrollbarsOpacity();
    7074
     75    FloatPoint computeVelocity();
     76
    7177#if ENABLE(SMOOTH_SCROLLING)
    7278    void ensureSmoothScrollingAnimation();
    7379
    74     std::unique_ptr<ScrollAnimation> m_animation;
     80    std::unique_ptr<ScrollAnimation> m_smoothAnimation;
    7581#endif
     82    std::unique_ptr<ScrollAnimation> m_kineticAnimation;
     83    Vector<PlatformWheelEvent> m_scrollHistory;
    7684    Scrollbar* m_horizontalOverlayScrollbar { nullptr };
    7785    Scrollbar* m_verticalOverlayScrollbar { nullptr };
  • trunk/Source/WebKit2/ChangeLog

    r217967 r217971  
     12017-06-09  Adrien Plazas  <aplazas@igalia.com>
     2
     3        [GTK] Add kinetic scrolling
     4        https://bugs.webkit.org/show_bug.cgi?id=155750
     5
     6        Reviewed by Carlos Garcia Campos.
     7
     8        Patch by Adrien Plazas and Yusuke Suzuki.
     9
     10        Add the notion of phase and momentum phase to WebWheelEvent.
     11
     12        Make WebWheelEvent manage the 'is_stop' attribute of GdkEventScroll to create the corresponding WebWheelEvent
     13        with the correct phases and deltas.
     14
     15        Make GestureController manage swipes to create the corresponding WebWheelEvent with the correct phases and
     16        deltas.
     17
     18        * Shared/NativeWebWheelEvent.h:
     19        * Shared/WebEvent.h:
     20        * Shared/WebEventConversion.cpp:
     21        (WebKit::WebKit2PlatformWheelEvent::WebKit2PlatformWheelEvent):
     22        * Shared/WebWheelEvent.cpp:
     23        (WebKit::WebWheelEvent::WebWheelEvent):
     24        (WebKit::WebWheelEvent::encode):
     25        (WebKit::WebWheelEvent::decode):
     26        * Shared/gtk/NativeWebWheelEventGtk.cpp:
     27        (WebKit::NativeWebWheelEvent::NativeWebWheelEvent):
     28        * Shared/gtk/WebEventFactory.cpp:
     29        (WebKit::WebEventFactory::createWebWheelEvent):
     30        * Shared/gtk/WebEventFactory.h:
     31        * UIProcess/WebPageProxy.cpp:
     32        (WebKit::WebPageProxy::handleWheelEvent):
     33        (WebKit::WebPageProxy::shouldProcessWheelEventNow):
     34        * UIProcess/WebPageProxy.h:
     35        * UIProcess/gtk/GestureController.cpp:
     36        (WebKit::GestureController::GestureController):
     37        (WebKit::GestureController::handleEvent):
     38        (WebKit::GestureController::isProcessingGestures):
     39        (WebKit::createScrollEvent):
     40        (WebKit::GestureController::DragGesture::startDrag):
     41        (WebKit::GestureController::DragGesture::handleDrag):
     42        (WebKit::GestureController::DragGesture::begin):
     43        (WebKit::GestureController::DragGesture::end):
     44        (WebKit::GestureController::SwipeGesture::startMomentumScroll):
     45        (WebKit::GestureController::SwipeGesture::swipe):
     46        (WebKit::GestureController::SwipeGesture::SwipeGesture):
     47        * UIProcess/gtk/GestureController.h:
     48
    1492017-06-09  Jer Noble  <jer.noble@apple.com>
    250
  • trunk/Source/WebKit2/Shared/NativeWebWheelEvent.h

    r216497 r217971  
    5252    NativeWebWheelEvent(const NativeWebWheelEvent&);
    5353    NativeWebWheelEvent(GdkEvent*);
     54    NativeWebWheelEvent(GdkEvent*, WebWheelEvent::Phase, WebWheelEvent::Phase momentumPhase);
    5455#elif PLATFORM(WPE)
    5556    NativeWebWheelEvent(struct wpe_input_axis_event*, float deviceScaleFactor);
  • trunk/Source/WebKit2/Shared/WebEvent.h

    r210668 r217971  
    184184    };
    185185
    186 #if PLATFORM(COCOA)
     186#if PLATFORM(COCOA) || PLATFORM(GTK)
    187187    enum Phase {
    188188        PhaseNone        = 0,
     
    201201#if PLATFORM(COCOA)
    202202    WebWheelEvent(Type, const WebCore::IntPoint& position, const WebCore::IntPoint& globalPosition, const WebCore::FloatSize& delta, const WebCore::FloatSize& wheelTicks, Granularity, bool directionInvertedFromDevice, Phase, Phase momentumPhase, bool hasPreciseScrollingDeltas, uint32_t scrollCount, const WebCore::FloatSize& unacceleratedScrollingDelta, Modifiers, double timestamp);
     203#elif PLATFORM(GTK)
     204    WebWheelEvent(Type, const WebCore::IntPoint& position, const WebCore::IntPoint& globalPosition, const WebCore::FloatSize& delta, const WebCore::FloatSize& wheelTicks, Phase, Phase momentumPhase, Granularity, Modifiers, double timestamp);
    203205#endif
    204206
     
    209211    Granularity granularity() const { return static_cast<Granularity>(m_granularity); }
    210212    bool directionInvertedFromDevice() const { return m_directionInvertedFromDevice; }
    211 #if PLATFORM(COCOA)
     213#if PLATFORM(COCOA) || PLATFORM(GTK)
    212214    Phase phase() const { return static_cast<Phase>(m_phase); }
    213215    Phase momentumPhase() const { return static_cast<Phase>(m_momentumPhase); }
     216#endif
     217#if PLATFORM(COCOA)
    214218    bool hasPreciseScrollingDeltas() const { return m_hasPreciseScrollingDeltas; }
    215219    uint32_t scrollCount() const { return m_scrollCount; }
     
    229233    uint32_t m_granularity; // Granularity
    230234    bool m_directionInvertedFromDevice;
     235#if PLATFORM(COCOA) || PLATFORM(GTK)
     236    uint32_t m_phase { Phase::PhaseNone };
     237    uint32_t m_momentumPhase { Phase::PhaseNone };
     238#endif
    231239#if PLATFORM(COCOA)
    232     uint32_t m_phase; // Phase
    233     uint32_t m_momentumPhase; // Phase
    234240    bool m_hasPreciseScrollingDeltas;
    235241    uint32_t m_scrollCount;
  • trunk/Source/WebKit2/Shared/WebEventConversion.cpp

    r215790 r217971  
    156156        m_granularity = (webEvent.granularity() == WebWheelEvent::ScrollByPageWheelEvent) ? WebCore::ScrollByPageWheelEvent : WebCore::ScrollByPixelWheelEvent;
    157157        m_directionInvertedFromDevice = webEvent.directionInvertedFromDevice();
    158 #if PLATFORM(COCOA)
     158#if PLATFORM(COCOA) || PLATFORM(GTK)
    159159        m_phase = static_cast<WebCore::PlatformWheelEventPhase>(webEvent.phase());
    160160        m_momentumPhase = static_cast<WebCore::PlatformWheelEventPhase>(webEvent.momentumPhase());
     161#endif
     162#if PLATFORM(COCOA)
    161163        m_hasPreciseScrollingDeltas = webEvent.hasPreciseScrollingDeltas();
    162164        m_scrollCount = webEvent.scrollCount();
  • trunk/Source/WebKit2/Shared/WebWheelEvent.cpp

    r204743 r217971  
    6767    ASSERT(isWheelEventType(type));
    6868}
     69#elif PLATFORM(GTK)
     70WebWheelEvent::WebWheelEvent(Type type, const IntPoint& position, const IntPoint& globalPosition, const FloatSize& delta, const FloatSize& wheelTicks, Phase phase, Phase momentumPhase, Granularity granularity, Modifiers modifiers, double timestamp)
     71    : WebEvent(type, modifiers, timestamp)
     72    , m_position(position)
     73    , m_globalPosition(globalPosition)
     74    , m_delta(delta)
     75    , m_wheelTicks(wheelTicks)
     76    , m_granularity(granularity)
     77    , m_directionInvertedFromDevice(false)
     78    , m_phase(phase)
     79    , m_momentumPhase(momentumPhase)
     80{
     81    ASSERT(isWheelEventType(type));
     82}
    6983#endif
    7084
     
    7993    encoder << m_granularity;
    8094    encoder << m_directionInvertedFromDevice;
    81 #if PLATFORM(COCOA)
     95#if PLATFORM(COCOA) || PLATFORM(GTK)
    8296    encoder << m_phase;
    8397    encoder << m_momentumPhase;
     98#endif
     99#if PLATFORM(COCOA)
    84100    encoder << m_hasPreciseScrollingDeltas;
    85101    encoder << m_scrollCount;
     
    104120    if (!decoder.decode(t.m_directionInvertedFromDevice))
    105121        return false;
    106 #if PLATFORM(COCOA)
     122#if PLATFORM(COCOA) || PLATFORM(GTK)
    107123    if (!decoder.decode(t.m_phase))
    108124        return false;
    109125    if (!decoder.decode(t.m_momentumPhase))
    110126        return false;
     127#endif
     128#if PLATFORM(COCOA)
    111129    if (!decoder.decode(t.m_hasPreciseScrollingDeltas))
    112130        return false;
  • trunk/Source/WebKit2/Shared/gtk/NativeWebWheelEventGtk.cpp

    r85856 r217971  
    3838}
    3939
     40NativeWebWheelEvent::NativeWebWheelEvent(GdkEvent* event, WebWheelEvent::Phase phase, WebWheelEvent::Phase momentumPhase)
     41    : WebWheelEvent(WebEventFactory::createWebWheelEvent(event, phase, momentumPhase))
     42    , m_nativeEvent(gdk_event_copy(event))
     43{
     44}
     45
    4046NativeWebWheelEvent::NativeWebWheelEvent(const NativeWebWheelEvent& event)
    41     : WebWheelEvent(WebEventFactory::createWebWheelEvent(event.nativeEvent()))
     47    : WebWheelEvent(WebEventFactory::createWebWheelEvent(event.nativeEvent(), event.phase(), event.momentumPhase()))
    4248    , m_nativeEvent(gdk_event_copy(event.nativeEvent()))
    4349{
  • trunk/Source/WebKit2/Shared/gtk/WebEventFactory.cpp

    r212205 r217971  
    146146WebWheelEvent WebEventFactory::createWebWheelEvent(const GdkEvent* event)
    147147{
     148#ifndef GTK_API_VERSION_2
     149#if GTK_CHECK_VERSION(3, 20, 0)
     150    WebWheelEvent::Phase phase = gdk_event_is_scroll_stop_event(event) ?
     151        WebWheelEvent::Phase::PhaseEnded :
     152        WebWheelEvent::Phase::PhaseChanged;
     153#else
     154    double deltaX, deltaY;
     155    gdk_event_get_scroll_deltas(event, &deltaX, &deltaY);
     156    WebWheelEvent::Phase phase = event->scroll.direction == GDK_SCROLL_SMOOTH && !deltaX && !deltaY ?
     157        WebWheelEvent::Phase::PhaseEnded :
     158        WebWheelEvent::Phase::PhaseChanged;
     159#endif
     160#else
     161    WebWheelEvent::Phase phase = WebWheelEvent::Phase::PhaseChanged;
     162#endif // GTK_API_VERSION_2
     163
     164    return createWebWheelEvent(event, phase, WebWheelEvent::Phase::PhaseNone);
     165}
     166
     167WebWheelEvent WebEventFactory::createWebWheelEvent(const GdkEvent* event, WebWheelEvent::Phase phase, WebWheelEvent::Phase momentumPhase)
     168{
    148169    double x, y, xRoot, yRoot;
    149170    gdk_event_get_coords(event, &x, &y);
     
    182203
    183204    return WebWheelEvent(WebEvent::Wheel,
    184                          IntPoint(x, y),
    185                          IntPoint(xRoot, yRoot),
    186                          delta,
    187                          wheelTicks,
    188                          WebWheelEvent::ScrollByPixelWheelEvent,
    189                          modifiersForEvent(event),
    190                          gdk_event_get_time(event));
     205        IntPoint(x, y),
     206        IntPoint(xRoot, yRoot),
     207        delta,
     208        wheelTicks,
     209        phase,
     210        momentumPhase,
     211        WebWheelEvent::ScrollByPixelWheelEvent,
     212        modifiersForEvent(event),
     213        gdk_event_get_time(event));
    191214}
    192215
  • trunk/Source/WebKit2/Shared/gtk/WebEventFactory.h

    r190987 r217971  
    3939    static WebMouseEvent createWebMouseEvent(const GdkEvent*, int);
    4040    static WebWheelEvent createWebWheelEvent(const GdkEvent*);
     41    static WebWheelEvent createWebWheelEvent(const GdkEvent*, WebWheelEvent::Phase, WebWheelEvent::Phase momentumPhase);
    4142    static WebKeyboardEvent createWebKeyboardEvent(const GdkEvent*, const WebCore::CompositionResults&, Vector<String>&& commands);
    4243#if ENABLE(TOUCH_EVENTS)
  • trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp

    r217951 r217971  
    18871887    if (!m_currentlyProcessedWheelEvents.isEmpty()) {
    18881888        m_wheelEventQueue.append(event);
    1889         if (m_wheelEventQueue.size() < wheelEventQueueSizeThreshold)
     1889        if (!shouldProcessWheelEventNow(event))
    18901890            return;
    18911891        // The queue has too many wheel events, so push a new event.
     
    19261926    // event will dispatch to a non-main thread, which always responds.
    19271927    m_process->isResponsive(nullptr);
     1928}
     1929
     1930bool WebPageProxy::shouldProcessWheelEventNow(const WebWheelEvent& event) const
     1931{
     1932#if PLATFORM(GTK)
     1933    // Don't queue events representing a non-trivial scrolling phase to
     1934    // avoid having them trapped in the queue, potentially preventing a
     1935    // scrolling session to beginning or end correctly.
     1936    // This is only needed by platforms whose WebWheelEvent has this phase
     1937    // information (Cocoa and GTK+) but Cocoa was fine without it.
     1938    if (event.phase() == WebWheelEvent::Phase::PhaseNone
     1939        || event.phase() == WebWheelEvent::Phase::PhaseChanged
     1940        || event.momentumPhase() == WebWheelEvent::Phase::PhaseNone
     1941        || event.momentumPhase() == WebWheelEvent::Phase::PhaseChanged)
     1942        return true;
     1943#else
     1944    UNUSED_PARAM(event);
     1945#endif
     1946    if (m_wheelEventQueue.size() >= wheelEventQueueSizeThreshold)
     1947        return true;
     1948    return false;
    19281949}
    19291950
  • trunk/Source/WebKit2/UIProcess/WebPageProxy.h

    r217951 r217971  
    15581558    void processNextQueuedWheelEvent();
    15591559    void sendWheelEvent(const WebWheelEvent&);
     1560    bool shouldProcessWheelEventNow(const WebWheelEvent&) const;
    15601561
    15611562#if ENABLE(TOUCH_EVENTS)
  • trunk/Source/WebKit2/UIProcess/gtk/GestureController.cpp

    r215173 r217971  
    4242GestureController::GestureController(WebPageProxy& page)
    4343    : m_dragGesture(page)
     44    , m_swipeGesture(page)
    4445    , m_zoomGesture(page)
    4546{
     
    5051    bool wasProcessingGestures = isProcessingGestures();
    5152    m_dragGesture.handleEvent(event);
     53    m_swipeGesture.handleEvent(event);
    5254    m_zoomGesture.handleEvent(event);
    5355    return event->type == GDK_TOUCH_END ? wasProcessingGestures : isProcessingGestures();
     
    5658bool GestureController::isProcessingGestures() const
    5759{
    58     return m_dragGesture.isActive() || m_zoomGesture.isActive();
     60    return m_dragGesture.isActive() || m_swipeGesture.isActive() || m_zoomGesture.isActive();
    5961}
    6062
     
    7678}
    7779
    78 void GestureController::DragGesture::handleDrag(const GdkEvent* event, double x, double y)
    79 {
    80     ASSERT(m_inDrag);
     80static GUniquePtr<GdkEvent> createScrollEvent(const GdkEvent* event, double x, double y, double deltaX, double deltaY, gboolean isStop)
     81{
    8182    GUniquePtr<GdkEvent> scrollEvent(gdk_event_new(GDK_SCROLL));
    8283    scrollEvent->scroll.time = event->touch.time;
    83     scrollEvent->scroll.x = m_start.x();
    84     scrollEvent->scroll.y = m_start.y();
     84    scrollEvent->scroll.x = x;
     85    scrollEvent->scroll.y = y;
    8586    scrollEvent->scroll.x_root = event->touch.x_root;
    8687    scrollEvent->scroll.y_root = event->touch.y_root;
    8788    scrollEvent->scroll.direction = GDK_SCROLL_SMOOTH;
    88     scrollEvent->scroll.delta_x = (m_offset.x() - x) / Scrollbar::pixelsPerLineStep();
    89     scrollEvent->scroll.delta_y = (m_offset.y() - y) / Scrollbar::pixelsPerLineStep();
     89    scrollEvent->scroll.delta_x = deltaX;
     90    scrollEvent->scroll.delta_y = deltaY;
    9091    scrollEvent->scroll.state = event->touch.state;
    91     m_page.handleWheelEvent(NativeWebWheelEvent(scrollEvent.get()));
     92#if GTK_CHECK_VERSION(3, 20, 0)
     93    scrollEvent->scroll.is_stop = isStop;
     94#endif
     95    return scrollEvent;
     96}
     97
     98void GestureController::DragGesture::startDrag(const GdkEvent* event)
     99{
     100    ASSERT(!m_inDrag);
     101    GUniquePtr<GdkEvent> scrollEvent = createScrollEvent(event, m_start.x(), m_start.y(), 0, 0, FALSE);
     102    m_page.handleWheelEvent(NativeWebWheelEvent(scrollEvent.get(), WebWheelEvent::Phase::PhaseBegan, WebWheelEvent::Phase::PhaseNone));
     103}
     104
     105void GestureController::DragGesture::handleDrag(const GdkEvent* event, double x, double y)
     106{
     107    ASSERT(m_inDrag);
     108    GUniquePtr<GdkEvent> scrollEvent = createScrollEvent(event,
     109        m_start.x(), m_start.y(),
     110        (m_offset.x() - x) / Scrollbar::pixelsPerLineStep(),
     111        (m_offset.y() - y) / Scrollbar::pixelsPerLineStep(),
     112        FALSE);
     113    m_page.handleWheelEvent(NativeWebWheelEvent(scrollEvent.get(), WebWheelEvent::Phase::PhaseChanged, WebWheelEvent::Phase::PhaseNone));
    92114}
    93115
     
    129151    g_object_get(gtk_widget_get_settings(widget), "gtk-long-press-time", &delay, nullptr);
    130152    dragGesture->m_longPressTimeout.startOneShot(1_ms * delay);
     153    dragGesture->startDrag(gtk_gesture_get_last_event(gesture, sequence));
    131154}
    132155
     
    150173{
    151174    dragGesture->m_longPressTimeout.stop();
     175    if (!gtk_gesture_handles_sequence(gesture, sequence)) {
     176        gtk_gesture_set_state(gesture, GTK_EVENT_SEQUENCE_DENIED);
     177        return;
     178    }
    152179    if (!dragGesture->m_inDrag) {
    153180        dragGesture->handleTap(gtk_gesture_get_last_event(gesture, sequence));
    154181        gtk_gesture_set_state(gesture, GTK_EVENT_SEQUENCE_DENIED);
    155     } else if (!gtk_gesture_handles_sequence(gesture, sequence))
    156         gtk_gesture_set_state(gesture, GTK_EVENT_SEQUENCE_DENIED);
     182    }
    157183}
    158184
     
    171197    g_signal_connect_swapped(m_gesture.get(), "drag-update", G_CALLBACK(update), this);
    172198    g_signal_connect_swapped(m_gesture.get(), "end", G_CALLBACK(end), this);
     199}
     200
     201void GestureController::SwipeGesture::startMomentumScroll(const GdkEvent* event, double velocityX, double velocityY)
     202{
     203    GUniquePtr<GdkEvent> scrollEvent = createScrollEvent(event, event->touch.x, event->touch.y, velocityX, velocityY, TRUE);
     204    m_page.handleWheelEvent(NativeWebWheelEvent(scrollEvent.get(), WebWheelEvent::Phase::PhaseNone, WebWheelEvent::Phase::PhaseBegan));
     205}
     206
     207void GestureController::SwipeGesture::swipe(SwipeGesture* swipeGesture, double velocityX, double velocityY, GtkGesture* gesture)
     208{
     209    GdkEventSequence* sequence = gtk_gesture_single_get_current_sequence(GTK_GESTURE_SINGLE(gesture));
     210    if (!gtk_gesture_handles_sequence(gesture, sequence))
     211        return;
     212
     213    gtk_gesture_set_sequence_state(gesture, sequence, GTK_EVENT_SEQUENCE_CLAIMED);
     214
     215    swipeGesture->startMomentumScroll(gtk_gesture_get_last_event(gesture, sequence), velocityX, velocityY);
     216}
     217
     218GestureController::SwipeGesture::SwipeGesture(WebPageProxy& page)
     219    : Gesture(gtk_gesture_swipe_new(page.viewWidget()), page)
     220{
     221    gtk_gesture_single_set_touch_only(GTK_GESTURE_SINGLE(m_gesture.get()), TRUE);
     222    g_signal_connect_swapped(m_gesture.get(), "swipe", G_CALLBACK(swipe), this);
    173223}
    174224
  • trunk/Source/WebKit2/UIProcess/gtk/GestureController.h

    r202611 r217971  
    6868
    6969    private:
     70        // Notify that a drag started, allowing to stop kinetic deceleration.
     71        void startDrag(const GdkEvent*);
    7072        void handleDrag(const GdkEvent*, double x, double y);
    7173        void handleTap(const GdkEvent*);
     
    8183        GRefPtr<GtkGesture> m_longPress;
    8284        bool m_inDrag;
     85    };
     86
     87    class SwipeGesture final : public Gesture {
     88    public:
     89        SwipeGesture(WebPageProxy&);
     90
     91    private:
     92        void startMomentumScroll(const GdkEvent*, double velocityX, double velocityY);
     93
     94        static void swipe(SwipeGesture*, double velocityX, double velocityY, GtkGesture*);
    8395    };
    8496
     
    102114
    103115    DragGesture m_dragGesture;
     116    SwipeGesture m_swipeGesture;
    104117    ZoomGesture m_zoomGesture;
    105118};
Note: See TracChangeset for help on using the changeset viewer.