[iOS WK2] REGRESSION (r242687): Programmatic scroll of overflow scroll results in...
[WebKit-https.git] / Source / WebKit / UIProcess / RemoteLayerTree / ios / ScrollingTreeFrameScrollingNodeRemoteIOS.mm
1 /*
2  * Copyright (C) 2019 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 "ScrollingTreeFrameScrollingNodeRemoteIOS.h"
28
29 #if PLATFORM(IOS_FAMILY) && ENABLE(ASYNC_SCROLLING)
30
31 #import "ScrollingTreeScrollingNodeDelegateIOS.h"
32 #import <WebCore/ScrollingStateFrameScrollingNode.h>
33 #import <WebCore/ScrollingStateScrollingNode.h>
34 #import <WebCore/ScrollingTree.h>
35
36 namespace WebKit {
37 using namespace WebCore;
38
39 Ref<ScrollingTreeFrameScrollingNodeRemoteIOS> ScrollingTreeFrameScrollingNodeRemoteIOS::create(ScrollingTree& scrollingTree, ScrollingNodeType nodeType, ScrollingNodeID nodeID)
40 {
41     return adoptRef(*new ScrollingTreeFrameScrollingNodeRemoteIOS(scrollingTree, nodeType, nodeID));
42 }
43
44 ScrollingTreeFrameScrollingNodeRemoteIOS::ScrollingTreeFrameScrollingNodeRemoteIOS(ScrollingTree& scrollingTree, ScrollingNodeType nodeType, ScrollingNodeID nodeID)
45     : ScrollingTreeFrameScrollingNode(scrollingTree, nodeType, nodeID)
46 {
47 }
48
49 ScrollingTreeFrameScrollingNodeRemoteIOS::~ScrollingTreeFrameScrollingNodeRemoteIOS()
50 {
51 }
52
53 void ScrollingTreeFrameScrollingNodeRemoteIOS::commitStateBeforeChildren(const ScrollingStateNode& stateNode)
54 {
55     ScrollingTreeFrameScrollingNode::commitStateBeforeChildren(stateNode);
56     
57     const auto& scrollingStateNode = downcast<ScrollingStateFrameScrollingNode>(stateNode);
58
59     if (scrollingStateNode.hasChangedProperty(ScrollingStateFrameScrollingNode::CounterScrollingLayer))
60         m_counterScrollingLayer = scrollingStateNode.counterScrollingLayer();
61
62     if (scrollingStateNode.hasChangedProperty(ScrollingStateFrameScrollingNode::HeaderLayer))
63         m_headerLayer = scrollingStateNode.headerLayer();
64
65     if (scrollingStateNode.hasChangedProperty(ScrollingStateFrameScrollingNode::FooterLayer))
66         m_footerLayer = scrollingStateNode.footerLayer();
67
68     if (stateNode.hasChangedProperty(ScrollingStateScrollingNode::ScrollContainerLayer)) {
69         if (scrollContainerLayer())
70             m_scrollingNodeDelegate = std::make_unique<ScrollingTreeScrollingNodeDelegateIOS>(*this);
71         else
72             m_scrollingNodeDelegate = nullptr;
73     }
74
75     if (m_scrollingNodeDelegate)
76         m_scrollingNodeDelegate->commitStateBeforeChildren(downcast<ScrollingStateScrollingNode>(stateNode));
77 }
78
79 void ScrollingTreeFrameScrollingNodeRemoteIOS::commitStateAfterChildren(const ScrollingStateNode& stateNode)
80 {
81     ScrollingTreeFrameScrollingNode::commitStateAfterChildren(stateNode);
82
83     const auto& scrollingStateNode = downcast<ScrollingStateFrameScrollingNode>(stateNode);
84
85     if (m_scrollingNodeDelegate) {
86         m_scrollingNodeDelegate->commitStateAfterChildren(scrollingStateNode);
87         return;
88     }
89
90     // Update the scroll position after child nodes have been updated, because they need to have updated their constraints before any scrolling happens.
91     if (scrollingStateNode.hasChangedProperty(ScrollingStateScrollingNode::RequestedScrollPosition)) {
92         auto scrollType = scrollingStateNode.requestedScrollPositionRepresentsProgrammaticScroll() ? ScrollType::Programmatic : ScrollType::User;
93         scrollTo(scrollingStateNode.requestedScrollPosition(), scrollType);
94     }
95 }
96
97 FloatPoint ScrollingTreeFrameScrollingNodeRemoteIOS::minimumScrollPosition() const
98 {
99     FloatPoint position = ScrollableArea::scrollPositionFromOffset(FloatPoint(), toFloatSize(scrollOrigin()));
100     
101     if (isRootNode() && scrollingTree().scrollPinningBehavior() == PinToBottom)
102         position.setY(maximumScrollPosition().y());
103
104     return position;
105 }
106
107 FloatPoint ScrollingTreeFrameScrollingNodeRemoteIOS::maximumScrollPosition() const
108 {
109     FloatPoint position = ScrollableArea::scrollPositionFromOffset(FloatPoint(totalContentsSizeForRubberBand() - scrollableAreaSize()), toFloatSize(scrollOrigin()));
110     position = position.expandedTo(FloatPoint());
111
112     if (isRootNode() && scrollingTree().scrollPinningBehavior() == PinToTop)
113         position.setY(minimumScrollPosition().y());
114
115     return position;
116 }
117
118 void ScrollingTreeFrameScrollingNodeRemoteIOS::repositionScrollingLayers()
119 {
120     if (m_scrollingNodeDelegate) {
121         m_scrollingNodeDelegate->repositionScrollingLayers();
122         return;
123     }
124
125     auto scrollPosition = currentScrollPosition();
126     // FIXME: This is always wrong on iOS. Maybe assert that we always have a delegate.
127     [scrolledContentsLayer() setPosition:-scrollPosition];
128 }
129
130 void ScrollingTreeFrameScrollingNodeRemoteIOS::repositionRelatedLayers()
131 {
132     auto layoutViewport = this->layoutViewport();
133
134     [m_counterScrollingLayer setPosition:layoutViewport.location()];
135
136     // FIXME: I don' think we never have headers and footers on iOS.
137     if (m_headerLayer || m_footerLayer) {
138         // Generally the banners should have the same horizontal-position computation as a fixed element. However,
139         // the banners are not affected by the frameScaleFactor(), so if there is currently a non-1 frameScaleFactor()
140         // then we should recompute scrollPositionForFixedChildren for the banner with a scale factor of 1.
141         if (m_headerLayer)
142             [m_headerLayer setPosition:FloatPoint(layoutViewport.x(), 0)];
143
144         if (m_footerLayer)
145             [m_footerLayer setPosition:FloatPoint(layoutViewport.x(), totalContentsSize().height() - footerHeight())];
146     }
147 }
148
149 }
150 #endif