a861fec56daf7bc786ec0d294326a671aa5bc5ec
[WebKit-https.git] / Source / WebKit2 / UIProcess / ios / RemoteScrollingCoordinatorProxyIOS.mm
1 /*
2  * Copyright (C) 2014 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 #import "config.h"
27 #import "RemoteScrollingCoordinatorProxy.h"
28
29 #if PLATFORM(IOS)
30 #if ENABLE(ASYNC_SCROLLING)
31
32 #import "LayerRepresentation.h"
33 #import "RemoteLayerTreeHost.h"
34 #import "WebPageProxy.h"
35 #import <UIKit/UIView.h>
36 #import <WebCore/ScrollingStateFrameScrollingNode.h>
37 #import <WebCore/ScrollingStateOverflowScrollingNode.h>
38 #import <WebCore/ScrollingStateTree.h>
39
40 #if ENABLE(CSS_SCROLL_SNAP)
41 #import <WebCore/AxisScrollSnapOffsets.h>
42 #import <WebCore/ScrollTypes.h>
43 #import <WebCore/ScrollingTreeFrameScrollingNode.h>
44 #endif
45
46 using namespace WebCore;
47
48 namespace WebKit {
49
50 static LayerRepresentation layerRepresentationFromLayerOrView(LayerOrView *layerOrView)
51 {
52     return LayerRepresentation(layerOrView.layer);
53 }
54
55 void RemoteScrollingCoordinatorProxy::connectStateNodeLayers(ScrollingStateTree& stateTree, const RemoteLayerTreeHost& layerTreeHost)
56 {
57     for (auto& currNode : stateTree.nodeMap().values()) {
58         switch (currNode->nodeType()) {
59         case OverflowScrollingNode: {
60             ScrollingStateOverflowScrollingNode& scrollingStateNode = downcast<ScrollingStateOverflowScrollingNode>(*currNode);
61             
62             if (scrollingStateNode.hasChangedProperty(ScrollingStateNode::ScrollLayer))
63                 scrollingStateNode.setLayer(layerRepresentationFromLayerOrView(layerTreeHost.getLayer(scrollingStateNode.layer())));
64             
65             if (scrollingStateNode.hasChangedProperty(ScrollingStateOverflowScrollingNode::ScrolledContentsLayer))
66                 scrollingStateNode.setScrolledContentsLayer(layerRepresentationFromLayerOrView(layerTreeHost.getLayer(scrollingStateNode.scrolledContentsLayer())));
67             break;
68         };
69         case FrameScrollingNode: {
70             ScrollingStateFrameScrollingNode& scrollingStateNode = downcast<ScrollingStateFrameScrollingNode>(*currNode);
71             
72             if (scrollingStateNode.hasChangedProperty(ScrollingStateNode::ScrollLayer))
73                 scrollingStateNode.setLayer(layerRepresentationFromLayerOrView(layerTreeHost.getLayer(scrollingStateNode.layer())));
74
75             if (scrollingStateNode.hasChangedProperty(ScrollingStateFrameScrollingNode::CounterScrollingLayer))
76                 scrollingStateNode.setCounterScrollingLayer(layerRepresentationFromLayerOrView(layerTreeHost.getLayer(scrollingStateNode.counterScrollingLayer())));
77
78             // FIXME: we should never have header and footer layers coming from the WebProcess.
79             if (scrollingStateNode.hasChangedProperty(ScrollingStateFrameScrollingNode::HeaderLayer))
80                 scrollingStateNode.setHeaderLayer(layerRepresentationFromLayerOrView(layerTreeHost.getLayer(scrollingStateNode.headerLayer())));
81
82             if (scrollingStateNode.hasChangedProperty(ScrollingStateFrameScrollingNode::FooterLayer))
83                 scrollingStateNode.setFooterLayer(layerRepresentationFromLayerOrView(layerTreeHost.getLayer(scrollingStateNode.footerLayer())));
84             break;
85         }
86         case FixedNode:
87         case StickyNode:
88             if (currNode->hasChangedProperty(ScrollingStateNode::ScrollLayer))
89                 currNode->setLayer(layerRepresentationFromLayerOrView(layerTreeHost.getLayer(currNode->layer())));
90             break;
91         }
92     }
93 }
94
95 FloatRect RemoteScrollingCoordinatorProxy::customFixedPositionRect() const
96 {
97     return m_webPageProxy.computeCustomFixedPositionRect(m_webPageProxy.unobscuredContentRect(), m_webPageProxy.displayedContentScale());
98 }
99
100 void RemoteScrollingCoordinatorProxy::scrollingTreeNodeWillStartPanGesture()
101 {
102     m_webPageProxy.overflowScrollViewWillStartPanGesture();
103 }
104
105 void RemoteScrollingCoordinatorProxy::scrollingTreeNodeWillStartScroll()
106 {
107     m_webPageProxy.overflowScrollWillStartScroll();
108 }
109     
110 void RemoteScrollingCoordinatorProxy::scrollingTreeNodeDidEndScroll()
111 {
112     m_webPageProxy.overflowScrollDidEndScroll();
113 }
114
115 #if ENABLE(CSS_SCROLL_SNAP)
116 void RemoteScrollingCoordinatorProxy::adjustTargetContentOffsetForSnapping(CGSize maxScrollOffsets, CGPoint velocity, CGPoint* targetContentOffset) const
117 {
118     // The bounds checking with maxScrollOffsets is to ensure that we won't interfere with rubber-banding when scrolling to the edge of the page.
119     if (shouldSnapForMainFrameScrolling(WebCore::ScrollEventAxis::Horizontal) && targetContentOffset->x > 0 && targetContentOffset->x < maxScrollOffsets.width) {
120         float potentialSnapPosition = closestSnapOffsetForMainFrameScrolling(WebCore::ScrollEventAxis::Horizontal, targetContentOffset->x, velocity.x);
121         targetContentOffset->x = std::min<float>(maxScrollOffsets.width, potentialSnapPosition);
122     }
123     // FIXME: We need to account for how the top navigation bar changes in size.
124     if (shouldSnapForMainFrameScrolling(WebCore::ScrollEventAxis::Vertical) && targetContentOffset->y > 0 && targetContentOffset->y < maxScrollOffsets.height) {
125         float potentialSnapPosition = closestSnapOffsetForMainFrameScrolling(WebCore::ScrollEventAxis::Vertical, targetContentOffset->y, velocity.y);
126         targetContentOffset->y = std::min<float>(maxScrollOffsets.height, potentialSnapPosition);
127     }
128 }
129
130 bool RemoteScrollingCoordinatorProxy::shouldSetScrollViewDecelerationRateFast() const
131 {
132     return shouldSnapForMainFrameScrolling(ScrollEventAxis::Horizontal) || shouldSnapForMainFrameScrolling(ScrollEventAxis::Vertical);
133 }
134
135 bool RemoteScrollingCoordinatorProxy::shouldSnapForMainFrameScrolling(ScrollEventAxis axis) const
136 {
137     ScrollingTreeNode* root = m_scrollingTree->rootNode();
138     if (root && root->isFrameScrollingNode()) {
139         ScrollingTreeFrameScrollingNode* rootFrame = static_cast<ScrollingTreeFrameScrollingNode*>(root);
140         const Vector<float>& snapOffsets = axis == ScrollEventAxis::Horizontal ? rootFrame->horizontalSnapOffsets() : rootFrame->verticalSnapOffsets();
141         return snapOffsets.size() > 0;
142     }
143     return false;
144 }
145
146 float RemoteScrollingCoordinatorProxy::closestSnapOffsetForMainFrameScrolling(ScrollEventAxis axis, float scrollDestination, float velocity) const
147 {
148     ScrollingTreeNode* root = m_scrollingTree->rootNode();
149     ASSERT(root && root->isFrameScrollingNode());
150     ScrollingTreeFrameScrollingNode* rootFrame = static_cast<ScrollingTreeFrameScrollingNode*>(root);
151     const Vector<float>& snapOffsets = axis == ScrollEventAxis::Horizontal ? rootFrame->horizontalSnapOffsets() : rootFrame->verticalSnapOffsets();
152
153     unsigned ignore = 0;
154     float scaledScrollDestination = scrollDestination / m_webPageProxy.displayedContentScale();
155     float rawClosestSnapOffset = closestSnapOffset<float, float>(snapOffsets, scaledScrollDestination, velocity, ignore);
156     return rawClosestSnapOffset * m_webPageProxy.displayedContentScale();
157 }
158 #endif
159
160 } // namespace WebKit
161
162
163 #endif // ENABLE(ASYNC_SCROLLING)
164 #endif // PLATFORM(IOS)