Implement "proximity" scroll snapping
[WebKit-https.git] / Source / WebCore / page / scrolling / ScrollingCoordinator.h
1 /*
2  * Copyright (C) 2011, 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 #pragma once
27
28 #include "EventTrackingRegions.h"
29 #include "IntRect.h"
30 #include "LayoutRect.h"
31 #include "PlatformWheelEvent.h"
32 #include "ScrollSnapOffsetsInfo.h"
33 #include "ScrollTypes.h"
34 #include <wtf/Forward.h>
35 #include <wtf/ThreadSafeRefCounted.h>
36 #include <wtf/TypeCasts.h>
37 #include <wtf/Variant.h>
38
39 #if ENABLE(ASYNC_SCROLLING)
40 #include <wtf/HashMap.h>
41 #include <wtf/ThreadSafeRefCounted.h>
42 #include <wtf/Threading.h>
43 #endif
44
45 #if ENABLE(CSS_SCROLL_SNAP)
46 #include "AxisScrollSnapOffsets.h"
47 #endif
48
49 namespace WebCore {
50
51 typedef unsigned SynchronousScrollingReasons;
52 typedef uint64_t ScrollingNodeID;
53
54 enum ScrollingNodeType { FrameScrollingNode, OverflowScrollingNode, FixedNode, StickyNode };
55
56 class Document;
57 class Frame;
58 class FrameView;
59 class GraphicsLayer;
60 class Page;
61 class Region;
62 class ScrollableArea;
63 class TextStream;
64 class ViewportConstraints;
65
66 #if ENABLE(ASYNC_SCROLLING)
67 class ScrollingTree;
68 #endif
69
70 enum class ScrollingLayerPositionAction {
71     Set,
72     SetApproximate,
73     Sync
74 };
75
76 struct ScrollableAreaParameters {
77     ScrollElasticity horizontalScrollElasticity;
78     ScrollElasticity verticalScrollElasticity;
79
80     ScrollbarMode horizontalScrollbarMode;
81     ScrollbarMode verticalScrollbarMode;
82
83     bool hasEnabledHorizontalScrollbar;
84     bool hasEnabledVerticalScrollbar;
85     
86     ScrollableAreaParameters()
87         : horizontalScrollElasticity(ScrollElasticityNone)
88         , verticalScrollElasticity(ScrollElasticityNone)
89         , horizontalScrollbarMode(ScrollbarAuto)
90         , verticalScrollbarMode(ScrollbarAuto)
91         , hasEnabledHorizontalScrollbar(false)
92         , hasEnabledVerticalScrollbar(false)
93     {
94     }
95
96     bool operator==(const ScrollableAreaParameters& other) const
97     {
98         return horizontalScrollElasticity == other.horizontalScrollElasticity
99             && verticalScrollElasticity == other.verticalScrollElasticity
100             && horizontalScrollbarMode == other.horizontalScrollbarMode
101             && verticalScrollbarMode == other.verticalScrollbarMode
102             && hasEnabledHorizontalScrollbar == other.hasEnabledHorizontalScrollbar
103             && hasEnabledVerticalScrollbar == other.hasEnabledVerticalScrollbar;
104     }
105 };
106
107 class ScrollingCoordinator : public ThreadSafeRefCounted<ScrollingCoordinator> {
108 public:
109     static Ref<ScrollingCoordinator> create(Page*);
110     virtual ~ScrollingCoordinator();
111
112     WEBCORE_EXPORT virtual void pageDestroyed();
113     
114     virtual bool isAsyncScrollingCoordinator() const { return false; }
115     virtual bool isRemoteScrollingCoordinator() const { return false; }
116
117     // Return whether this scrolling coordinator handles scrolling for the given frame view.
118     virtual bool coordinatesScrollingForFrameView(const FrameView&) const;
119
120     // Should be called whenever the given frame view has been laid out.
121     virtual void frameViewLayoutUpdated(FrameView&) { }
122
123     using LayoutViewportOriginOrOverrideRect = WTF::Variant<std::optional<FloatPoint>, std::optional<FloatRect>>;
124     virtual void reconcileScrollingState(FrameView&, const FloatPoint&, const LayoutViewportOriginOrOverrideRect&, bool /* programmaticScroll */, bool /* inStableState*/, ScrollingLayerPositionAction) { }
125
126     // Should be called whenever the slow repaint objects counter changes between zero and one.
127     void frameViewHasSlowRepaintObjectsDidChange(FrameView&);
128
129     // Should be called whenever the set of fixed objects changes.
130     void frameViewFixedObjectsDidChange(FrameView&);
131
132     // Called whenever the non-fast scrollable region changes for reasons other than layout.
133     virtual void frameViewEventTrackingRegionsChanged(FrameView&) { }
134
135     // Should be called whenever the root layer for the given frame view changes.
136     virtual void frameViewRootLayerDidChange(FrameView&);
137
138     // Return whether this scrolling coordinator can keep fixed position layers fixed to their
139     // containers while scrolling.
140     virtual bool supportsFixedPositionLayers() const { return false; }
141
142 #if PLATFORM(COCOA)
143     // Dispatched by the scrolling tree during handleWheelEvent. This is required as long as scrollbars are painted on the main thread.
144     void handleWheelEventPhase(PlatformWheelEventPhase);
145 #endif
146
147 #if ENABLE(WEB_REPLAY)
148     // Called when the page transitions between executing normally and deterministically.
149     void replaySessionStateDidChange();
150 #endif
151
152     // Force all scroll layer position updates to happen on the main thread.
153     WEBCORE_EXPORT void setForceSynchronousScrollLayerPositionUpdates(bool);
154
155     // These virtual functions are currently unique to the threaded scrolling architecture. 
156     // Their meaningful implementations are in ScrollingCoordinatorMac.
157     virtual void commitTreeStateIfNeeded() { }
158     virtual bool requestScrollPositionUpdate(FrameView&, const IntPoint&) { return false; }
159     virtual bool handleWheelEvent(FrameView&, const PlatformWheelEvent&) { return true; }
160     virtual ScrollingNodeID attachToStateTree(ScrollingNodeType, ScrollingNodeID newNodeID, ScrollingNodeID /*parentID*/) { return newNodeID; }
161     virtual void detachFromStateTree(ScrollingNodeID) { }
162     virtual void clearStateTree() { }
163     virtual void updateViewportConstrainedNode(ScrollingNodeID, const ViewportConstraints&, GraphicsLayer*) { }
164
165     struct ScrollingGeometry {
166         FloatSize scrollableAreaSize;
167         FloatSize contentSize;
168         FloatSize reachableContentSize; // Smaller than contentSize when overflow is hidden on one axis.
169         FloatPoint scrollPosition;
170         IntPoint scrollOrigin;
171 #if ENABLE(CSS_SCROLL_SNAP)
172         Vector<LayoutUnit> horizontalSnapOffsets;
173         Vector<LayoutUnit> verticalSnapOffsets;
174         Vector<ScrollOffsetRange<LayoutUnit>> horizontalSnapOffsetRanges;
175         Vector<ScrollOffsetRange<LayoutUnit>> verticalSnapOffsetRanges;
176         unsigned currentHorizontalSnapPointIndex;
177         unsigned currentVerticalSnapPointIndex;
178 #endif
179     };
180
181     virtual void updateFrameScrollingNode(ScrollingNodeID, GraphicsLayer* /*scrollLayer*/, GraphicsLayer* /*scrolledContentsLayer*/, GraphicsLayer* /*counterScrollingLayer*/, GraphicsLayer* /*insetClipLayer*/, const ScrollingGeometry* = nullptr) { }
182     virtual void updateOverflowScrollingNode(ScrollingNodeID, GraphicsLayer* /*scrollLayer*/, GraphicsLayer* /*scrolledContentsLayer*/, const ScrollingGeometry* = nullptr) { }
183     virtual void reconcileViewportConstrainedLayerPositions(const LayoutRect&, ScrollingLayerPositionAction) { }
184     virtual String scrollingStateTreeAsText() const;
185     virtual bool isRubberBandInProgress() const { return false; }
186     virtual bool isScrollSnapInProgress() const { return false; }
187     virtual void updateScrollSnapPropertiesWithFrameView(const FrameView&) { }
188     virtual void setScrollPinningBehavior(ScrollPinningBehavior) { }
189
190     // Generated a unique id for scroll layers.
191     ScrollingNodeID uniqueScrollLayerID();
192
193     enum MainThreadScrollingReasonFlags {
194         ForcedOnMainThread                                          = 1 << 0,
195         HasSlowRepaintObjects                                       = 1 << 1,
196         HasViewportConstrainedObjectsWithoutSupportingFixedLayers   = 1 << 2,
197         HasNonLayerViewportConstrainedObjects                       = 1 << 3,
198         IsImageDocument                                             = 1 << 4
199     };
200
201     SynchronousScrollingReasons synchronousScrollingReasons(const FrameView&) const;
202     bool shouldUpdateScrollLayerPositionSynchronously(const FrameView&) const;
203
204     virtual void willDestroyScrollableArea(ScrollableArea&) { }
205     virtual void scrollableAreaScrollLayerDidChange(ScrollableArea&) { }
206     virtual void scrollableAreaScrollbarLayerDidChange(ScrollableArea&, ScrollbarOrientation) { }
207
208     static String synchronousScrollingReasonsAsText(SynchronousScrollingReasons);
209     String synchronousScrollingReasonsAsText() const;
210
211     EventTrackingRegions absoluteEventTrackingRegions() const;
212     virtual void updateExpectsWheelEventTestTriggerWithFrameView(const FrameView&) { }
213
214 protected:
215     explicit ScrollingCoordinator(Page*);
216
217     static GraphicsLayer* scrollLayerForScrollableArea(ScrollableArea&);
218
219     GraphicsLayer* scrollLayerForFrameView(FrameView&);
220     GraphicsLayer* counterScrollingLayerForFrameView(FrameView&);
221     GraphicsLayer* insetClipLayerForFrameView(FrameView&);
222     GraphicsLayer* rootContentLayerForFrameView(FrameView&);
223     GraphicsLayer* contentShadowLayerForFrameView(FrameView&);
224     GraphicsLayer* headerLayerForFrameView(FrameView&);
225     GraphicsLayer* footerLayerForFrameView(FrameView&);
226
227     virtual void willCommitTree() { }
228
229     Page* m_page; // FIXME: ideally this would be a reference but it gets nulled on async teardown.
230
231 private:
232     virtual void setSynchronousScrollingReasons(SynchronousScrollingReasons) { }
233
234     virtual bool hasVisibleSlowRepaintViewportConstrainedObjects(const FrameView&) const;
235     void updateSynchronousScrollingReasons(const FrameView&);
236
237     EventTrackingRegions absoluteEventTrackingRegionsForFrame(const Frame&) const;
238     
239     bool m_forceSynchronousScrollLayerPositionUpdates { false };
240 };
241
242 WEBCORE_EXPORT TextStream& operator<<(TextStream&, ScrollingNodeType);
243 WEBCORE_EXPORT TextStream& operator<<(TextStream&, ScrollingLayerPositionAction);
244
245 } // namespace WebCore
246
247 #define SPECIALIZE_TYPE_TRAITS_SCROLLING_COORDINATOR(ToValueTypeName, predicate) \
248 SPECIALIZE_TYPE_TRAITS_BEGIN(ToValueTypeName) \
249     static bool isType(const WebCore::ScrollingCoordinator& value) { return value.predicate; } \
250 SPECIALIZE_TYPE_TRAITS_END()