Scroll snapping on Mac should use AppKit animations
[WebKit-https.git] / Source / WebCore / platform / cocoa / ScrollController.h
1 /*
2  * Copyright (C) 2011, 2014-2015 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #ifndef ScrollController_h
27 #define ScrollController_h
28
29 #if ENABLE(RUBBER_BANDING) || ENABLE(CSS_SCROLL_SNAP)
30
31 #include "FloatPoint.h"
32 #include "FloatSize.h"
33 #include "ScrollTypes.h"
34 #include "WheelEventTestTrigger.h"
35 #include <wtf/Noncopyable.h>
36 #include <wtf/RunLoop.h>
37
38 #if ENABLE(CSS_SCROLL_SNAP)
39 #include "ScrollSnapAnimatorState.h"
40 #endif
41
42 namespace WebCore {
43
44 class LayoutSize;
45 class PlatformWheelEvent;
46 class ScrollableArea;
47 class WheelEventTestTrigger;
48
49 class ScrollControllerClient {
50 protected:
51     virtual ~ScrollControllerClient() { }
52
53 public:
54 #if ENABLE(RUBBER_BANDING)
55     virtual bool allowsHorizontalStretching(const PlatformWheelEvent&) = 0;
56     virtual bool allowsVerticalStretching(const PlatformWheelEvent&) = 0;
57     virtual IntSize stretchAmount() = 0;
58     virtual bool pinnedInDirection(const FloatSize&) = 0;
59     virtual bool canScrollHorizontally() = 0;
60     virtual bool canScrollVertically() = 0;
61     virtual bool shouldRubberBandInDirection(ScrollDirection) = 0;
62
63     virtual void immediateScrollBy(const FloatSize&) = 0;
64     virtual void immediateScrollByWithoutContentEdgeConstraints(const FloatSize&) = 0;
65     virtual void startSnapRubberbandTimer()
66     {
67         // Override to perform client-specific snap start logic
68     }
69
70     virtual void stopSnapRubberbandTimer()
71     {
72         // Override to perform client-specific snap end logic
73     }
74     
75     // If the current scroll position is within the overhang area, this function will cause
76     // the page to scroll to the nearest boundary point.
77     virtual void adjustScrollPositionToBoundsIfNecessary() = 0;
78 #endif
79
80     virtual void deferTestsForReason(WheelEventTestTrigger::ScrollableAreaIdentifier, WheelEventTestTrigger::DeferTestTriggerReason) const { /* Do nothing */ }
81     virtual void removeTestDeferralForReason(WheelEventTestTrigger::ScrollableAreaIdentifier, WheelEventTestTrigger::DeferTestTriggerReason) const { /* Do nothing */ }
82
83 #if ENABLE(CSS_SCROLL_SNAP)
84     virtual FloatPoint scrollOffset() const = 0;
85     virtual void immediateScrollOnAxis(ScrollEventAxis, float delta) = 0;
86     virtual void startScrollSnapTimer()
87     {
88         // Override to perform client-specific scroll snap point start logic
89     }
90
91     virtual void stopScrollSnapTimer()
92     {
93         // Override to perform client-specific scroll snap point end logic
94     }
95
96     virtual float pageScaleFactor() const
97     {
98         return 1.0f;
99     }
100
101     virtual unsigned activeScrollOffsetIndex(ScrollEventAxis) const
102     {
103         return 0;
104     }
105
106     virtual LayoutSize scrollExtent() const = 0;
107     virtual FloatSize viewportSize() const = 0;
108 #endif
109 };
110
111 enum class WheelEventStatus {
112     UserScrollBegin,
113     UserScrolling,
114     UserScrollEnd,
115     InertialScrollBegin,
116     InertialScrolling,
117     InertialScrollEnd,
118     StatelessScrollEvent,
119     Unknown
120 };
121
122 class ScrollController {
123     WTF_MAKE_NONCOPYABLE(ScrollController);
124
125 public:
126     explicit ScrollController(ScrollControllerClient&);
127
128 #if PLATFORM(MAC)
129     bool handleWheelEvent(const PlatformWheelEvent&);
130 #endif
131
132     bool isRubberBandInProgress() const;
133     bool isScrollSnapInProgress() const;
134
135 #if ENABLE(CSS_SCROLL_SNAP)
136     void updateScrollSnapPoints(ScrollEventAxis, const Vector<LayoutUnit>&);
137     void setActiveScrollSnapIndexForAxis(ScrollEventAxis, unsigned);
138     void setActiveScrollSnapIndicesForOffset(int x, int y);
139     bool activeScrollSnapIndexDidChange() const { return m_activeScrollSnapIndexDidChange; }
140     void setScrollSnapIndexDidChange(bool state) { m_activeScrollSnapIndexDidChange = state; }
141     unsigned activeScrollSnapIndexForAxis(ScrollEventAxis) const;
142     void updateScrollSnapState(const ScrollableArea&);
143 #if PLATFORM(MAC)
144     bool processWheelEventForScrollSnap(const PlatformWheelEvent&);
145 #endif
146 #endif
147
148 private:
149 #if ENABLE(RUBBER_BANDING)
150     void startSnapRubberbandTimer();
151     void stopSnapRubberbandTimer();
152     void snapRubberBand();
153     void snapRubberBandTimerFired();
154
155     bool shouldRubberBandInHorizontalDirection(const PlatformWheelEvent&);
156 #endif
157
158 #if ENABLE(CSS_SCROLL_SNAP)
159     void setNearestScrollSnapIndexForAxisAndOffset(ScrollEventAxis, int);
160 #if PLATFORM(MAC)
161     void scrollSnapTimerFired();
162     void startScrollSnapTimer();
163     void stopScrollSnapTimer();
164
165     bool shouldOverrideInertialScrolling() const;
166     void statelessSnapTransitionTimerFired();
167     void startDeferringTestsDueToScrollSnapping();
168     void stopDeferringTestsDueToScrollSnapping();
169     void scheduleStatelessScrollSnap();
170 #endif
171 #endif
172
173     ScrollControllerClient& m_client;
174
175 #if PLATFORM(MAC)
176     CFTimeInterval m_lastMomentumScrollTimestamp { 0 };
177 #endif
178     FloatSize m_overflowScrollDelta;
179     FloatSize m_stretchScrollForce;
180     FloatSize m_momentumVelocity;
181
182 #if ENABLE(RUBBER_BANDING)
183     // Rubber band state.
184     CFTimeInterval m_startTime { 0 };
185     FloatSize m_startStretch;
186     FloatSize m_origVelocity;
187     RunLoop::Timer<ScrollController> m_snapRubberbandTimer;
188 #endif
189
190 #if ENABLE(CSS_SCROLL_SNAP)
191     std::unique_ptr<ScrollSnapAnimatorState> m_scrollSnapState;
192 #if PLATFORM(MAC)
193     FloatPoint m_dragEndedScrollingVelocity;
194     RunLoop::Timer<ScrollController> m_statelessSnapTransitionTimer;
195     RunLoop::Timer<ScrollController> m_scrollSnapTimer;
196 #endif
197 #endif
198
199 #if PLATFORM(MAC)
200     bool m_inScrollGesture { false };
201     bool m_momentumScrollInProgress { false };
202     bool m_ignoreMomentumScrolls { false };
203     bool m_snapRubberbandTimerIsActive { false };
204 #endif
205
206     bool m_activeScrollSnapIndexDidChange { false };
207 };
208     
209 } // namespace WebCore
210
211 #endif // ENABLE(RUBBER_BANDING)
212
213 #endif // ScrollController_h