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