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