REGRESSION (r260276): Scrolling through shelves on music.apple.com is not smooth
[WebKit-https.git] / Source / WebCore / page / scrolling / ScrollingTree.h
1 /*
2  * Copyright (C) 2012-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 #if ENABLE(ASYNC_SCROLLING)
29
30 #include "EventTrackingRegions.h"
31 #include "PageIdentifier.h"
32 #include "PlatformWheelEvent.h"
33 #include "RectEdges.h"
34 #include "Region.h"
35 #include "ScrollTypes.h"
36 #include "ScrollingCoordinatorTypes.h"
37 #include "ScrollingTreeGestureState.h"
38 #include "ScrollingTreeLatchingController.h"
39 #include "WheelEventTestMonitor.h"
40 #include <wtf/HashMap.h>
41 #include <wtf/Lock.h>
42 #include <wtf/MonotonicTime.h>
43 #include <wtf/ThreadSafeRefCounted.h>
44 #include <wtf/TypeCasts.h>
45
46 namespace WebCore {
47
48 class IntPoint;
49 class ScrollingStateTree;
50 class ScrollingStateNode;
51 class ScrollingTreeFrameScrollingNode;
52 class ScrollingTreeNode;
53 class ScrollingTreeOverflowScrollProxyNode;
54 class ScrollingTreePositionedNode;
55 class ScrollingTreeScrollingNode;
56 enum class EventListenerRegionType : uint8_t;
57 using PlatformDisplayID = uint32_t;
58
59 struct WheelEventHandlingResult {
60     OptionSet<WheelEventProcessingSteps> steps;
61     bool wasHandled { false };
62     bool needsMainThreadProcessing() const { return steps.containsAny({ WheelEventProcessingSteps::MainThreadForScrolling, WheelEventProcessingSteps::MainThreadForDOMEventDispatch }); }
63
64     static WheelEventHandlingResult handled()
65     {
66         return { { }, true };
67     }
68     static WheelEventHandlingResult unhandled()
69     {
70         return { { }, false };
71     }
72     static WheelEventHandlingResult result(bool handled)
73     {
74         return { { }, handled };
75     }
76 };
77
78 class ScrollingTree : public ThreadSafeRefCounted<ScrollingTree> {
79 friend class ScrollingTreeLatchingController;
80 public:
81     WEBCORE_EXPORT ScrollingTree();
82     WEBCORE_EXPORT virtual ~ScrollingTree();
83
84     virtual bool isThreadedScrollingTree() const { return false; }
85     virtual bool isRemoteScrollingTree() const { return false; }
86     virtual bool isScrollingTreeIOS() const { return false; }
87
88     // This implies that we'll do hit-testing in the scrolling tree.
89     bool asyncFrameOrOverflowScrollingEnabled() const { return m_asyncFrameOrOverflowScrollingEnabled; }
90     void setAsyncFrameOrOverflowScrollingEnabled(bool);
91
92     WEBCORE_EXPORT OptionSet<WheelEventProcessingSteps> determineWheelEventProcessing(const PlatformWheelEvent&);
93     WEBCORE_EXPORT virtual WheelEventHandlingResult handleWheelEvent(const PlatformWheelEvent&);
94
95     void setMainFrameIsRubberBanding(bool);
96     bool isRubberBandInProgress();
97
98     void setNodeScrollSnapInProgress(ScrollingNodeID, bool);
99     bool isScrollSnapInProgressForNode(ScrollingNodeID);
100
101     virtual void invalidate() { }
102     WEBCORE_EXPORT virtual void commitTreeState(std::unique_ptr<ScrollingStateTree>&&);
103     
104     WEBCORE_EXPORT virtual void applyLayerPositions();
105     WEBCORE_EXPORT void applyLayerPositionsAfterCommit();
106
107     virtual Ref<ScrollingTreeNode> createScrollingTreeNode(ScrollingNodeType, ScrollingNodeID) = 0;
108     
109     WEBCORE_EXPORT ScrollingTreeNode* nodeForID(ScrollingNodeID) const;
110
111     using VisitorFunction = WTF::Function<void (ScrollingNodeID, ScrollingNodeType, Optional<FloatPoint> scrollPosition, Optional<FloatPoint> layoutViewportOrigin, bool scrolledSinceLastCommit)>;
112     void traverseScrollingTree(VisitorFunction&&);
113
114     // Called after a scrolling tree node has handled a scroll and updated its layers.
115     // Updates FrameView/RenderLayer scrolling state and GraphicsLayers.
116     virtual void scrollingTreeNodeDidScroll(ScrollingTreeScrollingNode&, ScrollingLayerPositionAction = ScrollingLayerPositionAction::Sync) = 0;
117
118     // Called for requested scroll position updates.
119     virtual void scrollingTreeNodeRequestsScroll(ScrollingNodeID, const FloatPoint& /*scrollPosition*/, ScrollType, ScrollClamping) { }
120
121     // Delegated scrolling/zooming has caused the viewport to change, so update viewport-constrained layers
122     WEBCORE_EXPORT void mainFrameViewportChangedViaDelegatedScrolling(const FloatPoint& scrollPosition, const WebCore::FloatRect& layoutViewport, double scale);
123
124     void setNeedsApplyLayerPositionsAfterCommit() { m_needsApplyLayerPositionsAfterCommit = true; }
125
126     void notifyRelatedNodesAfterScrollPositionChange(ScrollingTreeScrollingNode& changedNode);
127
128     virtual void reportSynchronousScrollingReasonsChanged(MonotonicTime, OptionSet<SynchronousScrollingReason>) { }
129     virtual void reportExposedUnfilledArea(MonotonicTime, unsigned /* unfilledArea */) { }
130
131 #if PLATFORM(IOS_FAMILY)
132     virtual void scrollingTreeNodeWillStartPanGesture() { }
133     virtual void scrollingTreeNodeWillStartScroll() { }
134     virtual void scrollingTreeNodeDidEndScroll() { }
135 #endif
136
137     WEBCORE_EXPORT TrackingType eventTrackingTypeForPoint(const AtomString& eventName, IntPoint);
138
139 #if PLATFORM(MAC)
140     virtual void handleWheelEventPhase(ScrollingNodeID, PlatformWheelEventPhase) = 0;
141     virtual void setActiveScrollSnapIndices(ScrollingNodeID, unsigned /*horizontalIndex*/, unsigned /*verticalIndex*/) { }
142
143     virtual void setWheelEventTestMonitor(RefPtr<WheelEventTestMonitor>&&) { }
144
145     virtual void deferWheelEventTestCompletionForReason(WheelEventTestMonitor::ScrollableAreaIdentifier, WheelEventTestMonitor::DeferReason) { }
146     virtual void removeWheelEventTestCompletionDeferralForReason(WheelEventTestMonitor::ScrollableAreaIdentifier, WheelEventTestMonitor::DeferReason) { }
147 #else
148     void handleWheelEventPhase(ScrollingNodeID, PlatformWheelEventPhase) { }
149 #endif
150
151 #if PLATFORM(COCOA)
152     WEBCORE_EXPORT virtual void currentSnapPointIndicesDidChange(ScrollingNodeID, unsigned horizontal, unsigned vertical) = 0;
153 #endif
154
155     void setMainFramePinnedState(RectEdges<bool>);
156
157     // Can be called from any thread. Will update what edges allow rubber-banding.
158     WEBCORE_EXPORT void setMainFrameCanRubberBand(RectEdges<bool>);
159     bool mainFrameCanRubberBandInDirection(ScrollDirection);
160
161     bool isHandlingProgrammaticScroll() const { return m_isHandlingProgrammaticScroll; }
162     void setIsHandlingProgrammaticScroll(bool isHandlingProgrammaticScroll) { m_isHandlingProgrammaticScroll = isHandlingProgrammaticScroll; }
163     
164     void setScrollPinningBehavior(ScrollPinningBehavior);
165     WEBCORE_EXPORT ScrollPinningBehavior scrollPinningBehavior();
166
167     WEBCORE_EXPORT bool willWheelEventStartSwipeGesture(const PlatformWheelEvent&);
168
169     WEBCORE_EXPORT void setScrollingPerformanceLoggingEnabled(bool flag);
170     bool scrollingPerformanceLoggingEnabled();
171
172     ScrollingTreeFrameScrollingNode* rootNode() const { return m_rootNode.get(); }
173     Optional<ScrollingNodeID> latchedNodeID() const;
174     void clearLatchedNode();
175
176     bool hasFixedOrSticky() const { return !!m_fixedOrStickyNodeCount; }
177     void fixedOrStickyNodeAdded() { ++m_fixedOrStickyNodeCount; }
178     void fixedOrStickyNodeRemoved()
179     {
180         ASSERT(m_fixedOrStickyNodeCount);
181         --m_fixedOrStickyNodeCount;
182     }
183
184     // A map of overflow scrolling nodes to positioned nodes which need to be updated
185     // when the scroller changes, but are not descendants.
186     using RelatedNodesMap = HashMap<ScrollingNodeID, Vector<ScrollingNodeID>>;
187     RelatedNodesMap& overflowRelatedNodes() { return m_overflowRelatedNodesMap; }
188
189     HashSet<Ref<ScrollingTreeOverflowScrollProxyNode>>& activeOverflowScrollProxyNodes() { return m_activeOverflowScrollProxyNodes; }
190     HashSet<Ref<ScrollingTreePositionedNode>>& activePositionedNodes() { return m_activePositionedNodes; }
191
192     WEBCORE_EXPORT String scrollingTreeAsText(ScrollingStateTreeAsTextBehavior = ScrollingStateTreeAsTextBehaviorNormal);
193
194     bool isMonitoringWheelEvents() const { return m_isMonitoringWheelEvents; }
195     bool inCommitTreeState() const { return m_inCommitTreeState; }
196
197     void scrollBySimulatingWheelEventForTesting(ScrollingNodeID, FloatSize);
198
199     virtual void lockLayersForHitTesting() { }
200     virtual void unlockLayersForHitTesting() { }
201
202     Lock& treeMutex() { return m_treeMutex; }
203
204     void windowScreenDidChange(PlatformDisplayID, Optional<unsigned> nominalFramesPerSecond);
205     PlatformDisplayID displayID();
206
207 protected:
208     FloatPoint mainFrameScrollPosition() const;
209     void setMainFrameScrollPosition(FloatPoint);
210
211     Optional<unsigned> nominalFramesPerSecond();
212
213     void applyLayerPositionsInternal();
214     void removeAllNodes();
215
216     Lock m_treeMutex; // Protects the scrolling tree.
217
218 private:
219     void updateTreeFromStateNodeRecursive(const ScrollingStateNode*, struct CommitTreeState&);
220     virtual void propagateSynchronousScrollingReasons(const HashSet<ScrollingNodeID>&) { }
221
222     void applyLayerPositionsRecursive(ScrollingTreeNode&);
223     void notifyRelatedNodesRecursive(ScrollingTreeNode&);
224     void traverseScrollingTreeRecursive(ScrollingTreeNode&, const VisitorFunction&);
225
226     WEBCORE_EXPORT virtual RefPtr<ScrollingTreeNode> scrollingNodeForPoint(FloatPoint);
227     WEBCORE_EXPORT virtual OptionSet<EventListenerRegionType> eventListenerRegionTypesForPoint(FloatPoint) const;
228     virtual void receivedWheelEvent(const PlatformWheelEvent&) { }
229     
230     RefPtr<ScrollingTreeFrameScrollingNode> m_rootNode;
231
232     using ScrollingTreeNodeMap = HashMap<ScrollingNodeID, RefPtr<ScrollingTreeNode>>;
233     ScrollingTreeNodeMap m_nodeMap;
234
235     ScrollingTreeLatchingController m_latchingController;
236     ScrollingTreeGestureState m_gestureState;
237
238     RelatedNodesMap m_overflowRelatedNodesMap;
239
240     HashSet<Ref<ScrollingTreeOverflowScrollProxyNode>> m_activeOverflowScrollProxyNodes;
241     HashSet<Ref<ScrollingTreePositionedNode>> m_activePositionedNodes;
242
243     struct TreeState {
244         EventTrackingRegions eventTrackingRegions;
245         FloatPoint mainFrameScrollPosition;
246         PlatformDisplayID displayID { 0 };
247         Optional<unsigned> nominalFramesPerSecond;
248         HashSet<ScrollingNodeID> nodesWithActiveScrollSnap;
249         bool mainFrameIsRubberBanding { false };
250     };
251     
252     Lock m_treeStateMutex;
253     TreeState m_treeState;
254
255     struct SwipeState {
256         ScrollPinningBehavior scrollPinningBehavior { DoNotPin };
257         bool rubberBandsAtLeft { true };
258         bool rubberBandsAtRight { true };
259         bool rubberBandsAtTop { true };
260         bool rubberBandsAtBottom { true };
261         
262         RectEdges<bool> canRubberBand  { true, true, true, true };
263         RectEdges<bool> mainFramePinnedState { true, true, true, true };
264     };
265
266     Lock m_swipeStateMutex;
267     SwipeState m_swipeState;
268
269 protected:
270     bool m_allowLatching { true };
271
272 private:
273     unsigned m_fixedOrStickyNodeCount { 0 };
274     bool m_isHandlingProgrammaticScroll { false };
275     bool m_isMonitoringWheelEvents { false };
276     bool m_scrollingPerformanceLoggingEnabled { false };
277     bool m_asyncFrameOrOverflowScrollingEnabled { false };
278     bool m_needsApplyLayerPositionsAfterCommit { false };
279     bool m_inCommitTreeState { false };
280 };
281
282 } // namespace WebCore
283
284 #define SPECIALIZE_TYPE_TRAITS_SCROLLING_TREE(ToValueTypeName, predicate) \
285 SPECIALIZE_TYPE_TRAITS_BEGIN(ToValueTypeName) \
286     static bool isType(const WebCore::ScrollingTree& tree) { return tree.predicate; } \
287 SPECIALIZE_TYPE_TRAITS_END()
288 #endif // ENABLE(ASYNC_SCROLLING)