f8e9e7606da0ec1fa0090e56d2728a57be056a05
[WebKit-https.git] / Source / WebCore / page / scrolling / ScrollingTree.cpp
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 #include "config.h"
27 #include "ScrollingTree.h"
28
29 #if ENABLE(ASYNC_SCROLLING)
30
31 #include "EventNames.h"
32 #include "Logging.h"
33 #include "PlatformWheelEvent.h"
34 #include "ScrollingStateTree.h"
35 #include "ScrollingTreeFrameScrollingNode.h"
36 #include "ScrollingTreeNode.h"
37 #include "ScrollingTreeOverflowScrollingNode.h"
38 #include "ScrollingTreeScrollingNode.h"
39 #include "TextStream.h"
40 #include <wtf/TemporaryChange.h>
41
42 namespace WebCore {
43
44 ScrollingTree::ScrollingTree()
45 {
46 }
47
48 ScrollingTree::~ScrollingTree()
49 {
50 }
51
52 bool ScrollingTree::shouldHandleWheelEventSynchronously(const PlatformWheelEvent& wheelEvent)
53 {
54     // This method is invoked by the event handling thread
55     LockHolder lock(m_mutex);
56
57     bool shouldSetLatch = wheelEvent.shouldConsiderLatching();
58     
59     if (hasLatchedNode() && !shouldSetLatch)
60         return false;
61
62     if (shouldSetLatch)
63         m_latchedNode = 0;
64     
65     if (!m_eventTrackingRegions.isEmpty() && m_rootNode) {
66         ScrollingTreeFrameScrollingNode& frameScrollingNode = downcast<ScrollingTreeFrameScrollingNode>(*m_rootNode);
67         FloatPoint position = wheelEvent.position();
68         position.move(frameScrollingNode.viewToContentsOffset(m_mainFrameScrollPosition));
69
70         const EventNames& names = eventNames();
71         IntPoint roundedPosition = roundedIntPoint(position);
72         bool isSynchronousDispatchRegion = m_eventTrackingRegions.trackingTypeForPoint(names.wheelEvent, roundedPosition) == TrackingType::Synchronous
73             || m_eventTrackingRegions.trackingTypeForPoint(names.mousewheelEvent, roundedPosition) == TrackingType::Synchronous;
74         LOG_WITH_STREAM(Scrolling, stream << "ScrollingTree::shouldHandleWheelEventSynchronously: wheelEvent at " << wheelEvent.position() << " mapped to content point " << position << ", in non-fast region " << isSynchronousDispatchRegion);
75
76         if (isSynchronousDispatchRegion)
77             return true;
78     }
79     return false;
80 }
81
82 void ScrollingTree::setOrClearLatchedNode(const PlatformWheelEvent& wheelEvent, ScrollingNodeID nodeID)
83 {
84     if (wheelEvent.shouldConsiderLatching())
85         setLatchedNode(nodeID);
86     else if (wheelEvent.shouldResetLatching())
87         clearLatchedNode();
88 }
89
90 void ScrollingTree::handleWheelEvent(const PlatformWheelEvent& wheelEvent)
91 {
92     if (m_rootNode)
93         downcast<ScrollingTreeScrollingNode>(*m_rootNode).handleWheelEvent(wheelEvent);
94 }
95
96 void ScrollingTree::viewportChangedViaDelegatedScrolling(ScrollingNodeID nodeID, const WebCore::FloatRect& fixedPositionRect, double scale)
97 {
98     ScrollingTreeNode* node = nodeForID(nodeID);
99     if (!is<ScrollingTreeScrollingNode>(node))
100         return;
101
102     downcast<ScrollingTreeScrollingNode>(*node).updateLayersAfterViewportChange(fixedPositionRect, scale);
103 }
104
105 void ScrollingTree::scrollPositionChangedViaDelegatedScrolling(ScrollingNodeID nodeID, const WebCore::FloatPoint& scrollPosition, bool inUserInteration)
106 {
107     ScrollingTreeNode* node = nodeForID(nodeID);
108     if (!is<ScrollingTreeOverflowScrollingNode>(node))
109         return;
110
111     // Update descendant nodes
112     downcast<ScrollingTreeOverflowScrollingNode>(*node).updateLayersAfterDelegatedScroll(scrollPosition);
113
114     // Update GraphicsLayers and scroll state.
115     scrollingTreeNodeDidScroll(nodeID, scrollPosition, inUserInteration ? SyncScrollingLayerPosition : SetScrollingLayerPosition);
116 }
117
118 void ScrollingTree::commitTreeState(std::unique_ptr<ScrollingStateTree> scrollingStateTree)
119 {
120     bool rootStateNodeChanged = scrollingStateTree->hasNewRootStateNode();
121     
122     ScrollingStateScrollingNode* rootNode = scrollingStateTree->rootStateNode();
123     if (rootNode
124         && (rootStateNodeChanged
125             || rootNode->hasChangedProperty(ScrollingStateFrameScrollingNode::EventTrackingRegion)
126             || rootNode->hasChangedProperty(ScrollingStateNode::ScrollLayer))) {
127         LockHolder lock(m_mutex);
128
129         if (rootStateNodeChanged || rootNode->hasChangedProperty(ScrollingStateNode::ScrollLayer))
130             m_mainFrameScrollPosition = FloatPoint();
131         if (rootStateNodeChanged || rootNode->hasChangedProperty(ScrollingStateFrameScrollingNode::EventTrackingRegion))
132             m_eventTrackingRegions = scrollingStateTree->rootStateNode()->eventTrackingRegions();
133     }
134     
135     bool scrollRequestIsProgammatic = rootNode ? rootNode->requestedScrollPositionRepresentsProgrammaticScroll() : false;
136     TemporaryChange<bool> changeHandlingProgrammaticScroll(m_isHandlingProgrammaticScroll, scrollRequestIsProgammatic);
137
138     removeDestroyedNodes(*scrollingStateTree);
139
140     OrphanScrollingNodeMap orphanNodes;
141     updateTreeFromStateNode(rootNode, orphanNodes);
142 }
143
144 void ScrollingTree::updateTreeFromStateNode(const ScrollingStateNode* stateNode, OrphanScrollingNodeMap& orphanNodes)
145 {
146     if (!stateNode) {
147         m_nodeMap.clear();
148         m_rootNode = nullptr;
149         return;
150     }
151     
152     ScrollingNodeID nodeID = stateNode->scrollingNodeID();
153     ScrollingNodeID parentNodeID = stateNode->parentNodeID();
154
155     auto it = m_nodeMap.find(nodeID);
156
157     RefPtr<ScrollingTreeNode> node;
158     if (it != m_nodeMap.end())
159         node = it->value;
160     else {
161         node = createScrollingTreeNode(stateNode->nodeType(), nodeID);
162         if (!parentNodeID) {
163             // This is the root node. Clear the node map.
164             ASSERT(stateNode->nodeType() == FrameScrollingNode);
165             m_rootNode = node;
166             m_nodeMap.clear();
167         } 
168         m_nodeMap.set(nodeID, node.get());
169     }
170
171     if (parentNodeID) {
172         auto parentIt = m_nodeMap.find(parentNodeID);
173         ASSERT_WITH_SECURITY_IMPLICATION(parentIt != m_nodeMap.end());
174         if (parentIt != m_nodeMap.end()) {
175             ScrollingTreeNode* parent = parentIt->value;
176             node->setParent(parent);
177             parent->appendChild(node);
178         }
179     }
180
181     node->commitStateBeforeChildren(*stateNode);
182     
183     // Move all children into the orphanNodes map. Live ones will get added back as we recurse over children.
184     if (auto nodeChildren = node->children()) {
185         for (auto& childScrollingNode : *nodeChildren) {
186             childScrollingNode->setParent(nullptr);
187             orphanNodes.add(childScrollingNode->scrollingNodeID(), childScrollingNode);
188         }
189         nodeChildren->clear();
190     }
191
192     // Now update the children if we have any.
193     if (auto children = stateNode->children()) {
194         for (auto& child : *children)
195             updateTreeFromStateNode(child.get(), orphanNodes);
196     }
197
198     node->commitStateAfterChildren(*stateNode);
199 }
200
201 void ScrollingTree::removeDestroyedNodes(const ScrollingStateTree& stateTree)
202 {
203     for (const auto& removedNodeID : stateTree.removedNodes()) {
204         m_nodeMap.remove(removedNodeID);
205         if (removedNodeID == m_latchedNode)
206             clearLatchedNode();
207     }
208 }
209
210 ScrollingTreeNode* ScrollingTree::nodeForID(ScrollingNodeID nodeID) const
211 {
212     if (!nodeID)
213         return nullptr;
214
215     return m_nodeMap.get(nodeID);
216 }
217
218 void ScrollingTree::setMainFramePinState(bool pinnedToTheLeft, bool pinnedToTheRight, bool pinnedToTheTop, bool pinnedToTheBottom)
219 {
220     LockHolder locker(m_swipeStateMutex);
221
222     m_mainFramePinnedToTheLeft = pinnedToTheLeft;
223     m_mainFramePinnedToTheRight = pinnedToTheRight;
224     m_mainFramePinnedToTheTop = pinnedToTheTop;
225     m_mainFramePinnedToTheBottom = pinnedToTheBottom;
226 }
227
228 FloatPoint ScrollingTree::mainFrameScrollPosition()
229 {
230     LockHolder lock(m_mutex);
231     return m_mainFrameScrollPosition;
232 }
233
234 void ScrollingTree::setMainFrameScrollPosition(FloatPoint position)
235 {
236     LockHolder lock(m_mutex);
237     m_mainFrameScrollPosition = position;
238 }
239
240 TrackingType ScrollingTree::eventTrackingTypeForPoint(const AtomicString& eventName, IntPoint p)
241 {
242     LockHolder lock(m_mutex);
243     
244     return m_eventTrackingRegions.trackingTypeForPoint(eventName, p);
245 }
246
247 bool ScrollingTree::isRubberBandInProgress()
248 {
249     LockHolder lock(m_mutex);    
250
251     return m_mainFrameIsRubberBanding;
252 }
253
254 void ScrollingTree::setMainFrameIsRubberBanding(bool isRubberBanding)
255 {
256     LockHolder locker(m_mutex);
257
258     m_mainFrameIsRubberBanding = isRubberBanding;
259 }
260
261 bool ScrollingTree::isScrollSnapInProgress()
262 {
263     LockHolder lock(m_mutex);
264     
265     return m_mainFrameIsScrollSnapping;
266 }
267     
268 void ScrollingTree::setMainFrameIsScrollSnapping(bool isScrollSnapping)
269 {
270     LockHolder locker(m_mutex);
271     
272     m_mainFrameIsScrollSnapping = isScrollSnapping;
273 }
274
275 void ScrollingTree::setCanRubberBandState(bool canRubberBandAtLeft, bool canRubberBandAtRight, bool canRubberBandAtTop, bool canRubberBandAtBottom)
276 {
277     LockHolder locker(m_swipeStateMutex);
278
279     m_rubberBandsAtLeft = canRubberBandAtLeft;
280     m_rubberBandsAtRight = canRubberBandAtRight;
281     m_rubberBandsAtTop = canRubberBandAtTop;
282     m_rubberBandsAtBottom = canRubberBandAtBottom;
283 }
284
285 bool ScrollingTree::rubberBandsAtLeft()
286 {
287     LockHolder lock(m_swipeStateMutex);
288
289     return m_rubberBandsAtLeft;
290 }
291
292 bool ScrollingTree::rubberBandsAtRight()
293 {
294     LockHolder lock(m_swipeStateMutex);
295
296     return m_rubberBandsAtRight;
297 }
298
299 bool ScrollingTree::rubberBandsAtBottom()
300 {
301     LockHolder lock(m_swipeStateMutex);
302
303     return m_rubberBandsAtBottom;
304 }
305
306 bool ScrollingTree::rubberBandsAtTop()
307 {
308     LockHolder lock(m_swipeStateMutex);
309
310     return m_rubberBandsAtTop;
311 }
312
313 bool ScrollingTree::isHandlingProgrammaticScroll()
314 {
315     return m_isHandlingProgrammaticScroll;
316 }
317
318 void ScrollingTree::setScrollPinningBehavior(ScrollPinningBehavior pinning)
319 {
320     LockHolder locker(m_swipeStateMutex);
321     
322     m_scrollPinningBehavior = pinning;
323 }
324
325 ScrollPinningBehavior ScrollingTree::scrollPinningBehavior()
326 {
327     LockHolder lock(m_swipeStateMutex);
328     
329     return m_scrollPinningBehavior;
330 }
331
332 bool ScrollingTree::willWheelEventStartSwipeGesture(const PlatformWheelEvent& wheelEvent)
333 {
334     if (wheelEvent.phase() != PlatformWheelEventPhaseBegan)
335         return false;
336
337     LockHolder lock(m_swipeStateMutex);
338
339     if (wheelEvent.deltaX() > 0 && m_mainFramePinnedToTheLeft && !m_rubberBandsAtLeft)
340         return true;
341     if (wheelEvent.deltaX() < 0 && m_mainFramePinnedToTheRight && !m_rubberBandsAtRight)
342         return true;
343     if (wheelEvent.deltaY() > 0 && m_mainFramePinnedToTheTop && !m_rubberBandsAtTop)
344         return true;
345     if (wheelEvent.deltaY() < 0 && m_mainFramePinnedToTheBottom && !m_rubberBandsAtBottom)
346         return true;
347
348     return false;
349 }
350
351 void ScrollingTree::setScrollingPerformanceLoggingEnabled(bool flag)
352 {
353     m_scrollingPerformanceLoggingEnabled = flag;
354 }
355
356 bool ScrollingTree::scrollingPerformanceLoggingEnabled()
357 {
358     return m_scrollingPerformanceLoggingEnabled;
359 }
360
361 ScrollingNodeID ScrollingTree::latchedNode()
362 {
363     LockHolder locker(m_mutex);
364     return m_latchedNode;
365 }
366
367 void ScrollingTree::setLatchedNode(ScrollingNodeID node)
368 {
369     LockHolder locker(m_mutex);
370     m_latchedNode = node;
371 }
372
373 void ScrollingTree::clearLatchedNode()
374 {
375     LockHolder locker(m_mutex);
376     m_latchedNode = 0;
377 }
378
379 } // namespace WebCore
380
381 #endif // ENABLE(ASYNC_SCROLLING)