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