Fixed elements bounce when rubber-banding at the bottom of the page
[WebKit-https.git] / Source / WebCore / page / scrolling / AsyncScrollingCoordinator.cpp
1 /*
2  * Copyright (C) 2014-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
28 #if ENABLE(ASYNC_SCROLLING)
29 #include "AsyncScrollingCoordinator.h"
30
31 #include "Document.h"
32 #include "EditorClient.h"
33 #include "Frame.h"
34 #include "FrameView.h"
35 #include "GraphicsLayer.h"
36 #include "Logging.h"
37 #include "MainFrame.h"
38 #include "Page.h"
39 #include "ScrollAnimator.h"
40 #include "ScrollingConstraints.h"
41 #include "ScrollingStateFixedNode.h"
42 #include "ScrollingStateFrameScrollingNode.h"
43 #include "ScrollingStateOverflowScrollingNode.h"
44 #include "ScrollingStateStickyNode.h"
45 #include "ScrollingStateTree.h"
46 #include "Settings.h"
47 #include "TextStream.h"
48 #include "WheelEventTestTrigger.h"
49
50 namespace WebCore {
51
52 AsyncScrollingCoordinator::AsyncScrollingCoordinator(Page* page)
53     : ScrollingCoordinator(page)
54     , m_updateNodeScrollPositionTimer(*this, &AsyncScrollingCoordinator::updateScrollPositionAfterAsyncScrollTimerFired)
55     , m_scrollingStateTree(std::make_unique<ScrollingStateTree>(this))
56 {
57 }
58
59 AsyncScrollingCoordinator::~AsyncScrollingCoordinator()
60 {
61 }
62
63 void AsyncScrollingCoordinator::scrollingStateTreePropertiesChanged()
64 {
65     scheduleTreeStateCommit();
66 }
67
68 static inline void setStateScrollingNodeSnapOffsetsAsFloat(ScrollingStateScrollingNode& node, ScrollEventAxis axis, const Vector<LayoutUnit>* snapOffsets, const Vector<ScrollOffsetRange<LayoutUnit>>* snapOffsetRanges, float deviceScaleFactor)
69 {
70     // FIXME: Incorporate current page scale factor in snapping to device pixel. Perhaps we should just convert to float here and let UI process do the pixel snapping?
71     Vector<float> snapOffsetsAsFloat;
72     if (snapOffsets) {
73         snapOffsetsAsFloat.reserveInitialCapacity(snapOffsets->size());
74         for (auto& offset : *snapOffsets)
75             snapOffsetsAsFloat.uncheckedAppend(roundToDevicePixel(offset, deviceScaleFactor, false));
76     }
77
78     Vector<ScrollOffsetRange<float>> snapOffsetRangesAsFloat;
79     if (snapOffsetRanges) {
80         snapOffsetRangesAsFloat.reserveInitialCapacity(snapOffsetRanges->size());
81         for (auto& range : *snapOffsetRanges)
82             snapOffsetRangesAsFloat.uncheckedAppend({ roundToDevicePixel(range.start, deviceScaleFactor, false), roundToDevicePixel(range.end, deviceScaleFactor, false) });
83     }
84     if (axis == ScrollEventAxis::Horizontal) {
85         node.setHorizontalSnapOffsets(snapOffsetsAsFloat);
86         node.setHorizontalSnapOffsetRanges(snapOffsetRangesAsFloat);
87     } else {
88         node.setVerticalSnapOffsets(snapOffsetsAsFloat);
89         node.setVerticalSnapOffsetRanges(snapOffsetRangesAsFloat);
90     }
91 }
92
93 void AsyncScrollingCoordinator::setEventTrackingRegionsDirty()
94 {
95     m_eventTrackingRegionsDirty = true;
96     // We have to schedule a commit, but the computed non-fast region may not have actually changed.
97     scheduleTreeStateCommit();
98 }
99
100 void AsyncScrollingCoordinator::willCommitTree()
101 {
102     updateEventTrackingRegions();
103 }
104
105 void AsyncScrollingCoordinator::updateEventTrackingRegions()
106 {
107     if (!m_eventTrackingRegionsDirty)
108         return;
109
110     if (!m_scrollingStateTree->rootStateNode())
111         return;
112
113     m_scrollingStateTree->rootStateNode()->setEventTrackingRegions(absoluteEventTrackingRegions());
114     m_eventTrackingRegionsDirty = false;
115 }
116
117 void AsyncScrollingCoordinator::frameViewLayoutUpdated(FrameView& frameView)
118 {
119     ASSERT(isMainThread());
120     ASSERT(m_page);
121
122     // If there isn't a root node yet, don't do anything. We'll be called again after creating one.
123     if (!m_scrollingStateTree->rootStateNode())
124         return;
125
126     // Compute the region of the page that we can't do fast scrolling for. This currently includes
127     // all scrollable areas, such as subframes, overflow divs and list boxes. We need to do this even if the
128     // frame view whose layout was updated is not the main frame.
129     // In the future, we may want to have the ability to set non-fast scrolling regions for more than
130     // just the root node. But right now, this concept only applies to the root.
131     m_scrollingStateTree->rootStateNode()->setEventTrackingRegions(absoluteEventTrackingRegions());
132     m_eventTrackingRegionsDirty = false;
133
134     if (!coordinatesScrollingForFrameView(frameView))
135         return;
136
137     ScrollingStateFrameScrollingNode* node = downcast<ScrollingStateFrameScrollingNode>(m_scrollingStateTree->stateNodeForID(frameView.scrollLayerID()));
138     if (!node)
139         return;
140
141     Scrollbar* verticalScrollbar = frameView.verticalScrollbar();
142     Scrollbar* horizontalScrollbar = frameView.horizontalScrollbar();
143     node->setScrollerImpsFromScrollbars(verticalScrollbar, horizontalScrollbar);
144     
145     node->setFrameScaleFactor(frameView.frame().frameScaleFactor());
146     node->setHeaderHeight(frameView.headerHeight());
147     node->setFooterHeight(frameView.footerHeight());
148     node->setTopContentInset(frameView.topContentInset());
149
150     node->setVisualViewportEnabled(visualViewportEnabled());
151     node->setLayoutViewport(frameView.layoutViewportRect());
152     node->setMinLayoutViewportOrigin(frameView.minStableLayoutViewportOrigin());
153     node->setMaxLayoutViewportOrigin(frameView.maxStableLayoutViewportOrigin());
154
155     node->setScrollOrigin(frameView.scrollOrigin());
156     node->setScrollableAreaSize(frameView.visibleContentRect().size());
157     node->setTotalContentsSize(frameView.totalContentsSize());
158     node->setReachableContentsSize(frameView.totalContentsSize());
159     node->setFixedElementsLayoutRelativeToFrame(frameView.fixedElementsLayoutRelativeToFrame());
160     node->setScrollBehaviorForFixedElements(frameView.scrollBehaviorForFixedElements());
161
162 #if ENABLE(CSS_SCROLL_SNAP)
163     frameView.updateSnapOffsets();
164     updateScrollSnapPropertiesWithFrameView(frameView);
165 #endif
166
167 #if PLATFORM(COCOA)
168     Page* page = frameView.frame().page();
169     if (page && page->expectsWheelEventTriggers()) {
170         LOG(WheelEventTestTriggers, "    AsyncScrollingCoordinator::frameViewLayoutUpdated: Expects wheel event test trigger=%d", page->expectsWheelEventTriggers());
171         node->setExpectsWheelEventTestTrigger(page->expectsWheelEventTriggers());
172     }
173 #endif
174
175     ScrollableAreaParameters scrollParameters;
176     scrollParameters.horizontalScrollElasticity = frameView.horizontalScrollElasticity();
177     scrollParameters.verticalScrollElasticity = frameView.verticalScrollElasticity();
178     scrollParameters.hasEnabledHorizontalScrollbar = horizontalScrollbar && horizontalScrollbar->enabled();
179     scrollParameters.hasEnabledVerticalScrollbar = verticalScrollbar && verticalScrollbar->enabled();
180     scrollParameters.horizontalScrollbarMode = frameView.horizontalScrollbarMode();
181     scrollParameters.verticalScrollbarMode = frameView.verticalScrollbarMode();
182
183     node->setScrollableAreaParameters(scrollParameters);
184 }
185
186 void AsyncScrollingCoordinator::updateExpectsWheelEventTestTriggerWithFrameView(const FrameView& frameView)
187 {
188     auto* page = frameView.frame().page();
189     if (!page)
190         return;
191
192     auto* node = downcast<ScrollingStateFrameScrollingNode>(m_scrollingStateTree->stateNodeForID(frameView.scrollLayerID()));
193     if (!node)
194         return;
195
196     node->setExpectsWheelEventTestTrigger(page->expectsWheelEventTriggers());
197 }
198
199 void AsyncScrollingCoordinator::frameViewEventTrackingRegionsChanged(FrameView&)
200 {
201     if (!m_scrollingStateTree->rootStateNode())
202         return;
203
204     setEventTrackingRegionsDirty();
205 }
206
207 void AsyncScrollingCoordinator::frameViewRootLayerDidChange(FrameView& frameView)
208 {
209     ASSERT(isMainThread());
210     ASSERT(m_page);
211
212     if (!coordinatesScrollingForFrameView(frameView))
213         return;
214     
215     // FIXME: In some navigation scenarios, the FrameView has no RenderView or that RenderView has not been composited.
216     // This needs cleaning up: https://bugs.webkit.org/show_bug.cgi?id=132724
217     if (!frameView.scrollLayerID())
218         return;
219     
220     // If the root layer does not have a ScrollingStateNode, then we should create one.
221     ensureRootStateNodeForFrameView(frameView);
222     ASSERT(m_scrollingStateTree->rootStateNode());
223
224     ScrollingCoordinator::frameViewRootLayerDidChange(frameView);
225
226     ScrollingStateFrameScrollingNode* node = downcast<ScrollingStateFrameScrollingNode>(m_scrollingStateTree->stateNodeForID(frameView.scrollLayerID()));
227     node->setLayer(scrollLayerForFrameView(frameView));
228     node->setScrolledContentsLayer(rootContentLayerForFrameView(frameView));
229     node->setCounterScrollingLayer(counterScrollingLayerForFrameView(frameView));
230     node->setInsetClipLayer(insetClipLayerForFrameView(frameView));
231     node->setContentShadowLayer(contentShadowLayerForFrameView(frameView));
232     node->setHeaderLayer(headerLayerForFrameView(frameView));
233     node->setFooterLayer(footerLayerForFrameView(frameView));
234     node->setScrollBehaviorForFixedElements(frameView.scrollBehaviorForFixedElements());
235 }
236
237 bool AsyncScrollingCoordinator::requestScrollPositionUpdate(FrameView& frameView, const IntPoint& scrollPosition)
238 {
239     ASSERT(isMainThread());
240     ASSERT(m_page);
241
242     if (!coordinatesScrollingForFrameView(frameView))
243         return false;
244
245     bool isProgrammaticScroll = frameView.inProgrammaticScroll();
246     if (isProgrammaticScroll || frameView.frame().document()->pageCacheState() != Document::NotInPageCache)
247         updateScrollPositionAfterAsyncScroll(frameView.scrollLayerID(), scrollPosition, std::nullopt, isProgrammaticScroll, ScrollingLayerPositionAction::Set);
248
249     // If this frame view's document is being put into the page cache, we don't want to update our
250     // main frame scroll position. Just let the FrameView think that we did.
251     if (frameView.frame().document()->pageCacheState() != Document::NotInPageCache)
252         return true;
253
254     ScrollingStateScrollingNode* stateNode = downcast<ScrollingStateScrollingNode>(m_scrollingStateTree->stateNodeForID(frameView.scrollLayerID()));
255     if (!stateNode)
256         return false;
257
258     stateNode->setRequestedScrollPosition(scrollPosition, isProgrammaticScroll);
259     return true;
260 }
261
262 void AsyncScrollingCoordinator::scheduleUpdateScrollPositionAfterAsyncScroll(ScrollingNodeID nodeID, const FloatPoint& scrollPosition, const std::optional<FloatPoint>& layoutViewportOrigin, bool programmaticScroll, ScrollingLayerPositionAction scrollingLayerPositionAction)
263 {
264     ScheduledScrollUpdate scrollUpdate(nodeID, scrollPosition, layoutViewportOrigin, programmaticScroll, scrollingLayerPositionAction);
265     
266     // For programmatic scrolls, requestScrollPositionUpdate() has already called updateScrollPositionAfterAsyncScroll().
267     if (programmaticScroll)
268         return;
269
270     if (m_updateNodeScrollPositionTimer.isActive()) {
271         if (m_scheduledScrollUpdate.matchesUpdateType(scrollUpdate)) {
272             m_scheduledScrollUpdate.scrollPosition = scrollPosition;
273             m_scheduledScrollUpdate.layoutViewportOrigin = layoutViewportOrigin;
274             return;
275         }
276     
277         // If the parameters don't match what was previously scheduled, dispatch immediately.
278         m_updateNodeScrollPositionTimer.stop();
279         updateScrollPositionAfterAsyncScroll(m_scheduledScrollUpdate.nodeID, m_scheduledScrollUpdate.scrollPosition, m_scheduledScrollUpdate.layoutViewportOrigin, m_scheduledScrollUpdate.isProgrammaticScroll, m_scheduledScrollUpdate.updateLayerPositionAction);
280         updateScrollPositionAfterAsyncScroll(nodeID, scrollPosition, layoutViewportOrigin, programmaticScroll, scrollingLayerPositionAction);
281         return;
282     }
283
284     m_scheduledScrollUpdate = scrollUpdate;
285     m_updateNodeScrollPositionTimer.startOneShot(0);
286 }
287
288 void AsyncScrollingCoordinator::updateScrollPositionAfterAsyncScrollTimerFired()
289 {
290     updateScrollPositionAfterAsyncScroll(m_scheduledScrollUpdate.nodeID, m_scheduledScrollUpdate.scrollPosition, m_scheduledScrollUpdate.layoutViewportOrigin, m_scheduledScrollUpdate.isProgrammaticScroll, m_scheduledScrollUpdate.updateLayerPositionAction);
291 }
292
293 FrameView* AsyncScrollingCoordinator::frameViewForScrollingNode(ScrollingNodeID scrollingNodeID) const
294 {
295     if (!m_scrollingStateTree->rootStateNode())
296         return nullptr;
297     
298     if (scrollingNodeID == m_scrollingStateTree->rootStateNode()->scrollingNodeID())
299         return m_page->mainFrame().view();
300
301     ScrollingStateNode* stateNode = m_scrollingStateTree->stateNodeForID(scrollingNodeID);
302     if (!stateNode)
303         return nullptr;
304
305     // Find the enclosing frame scrolling node.
306     ScrollingStateNode* parentNode = stateNode;
307     while (parentNode && parentNode->nodeType() != FrameScrollingNode)
308         parentNode = parentNode->parent();
309     
310     if (!parentNode)
311         return nullptr;
312     
313     // Walk the frame tree to find the matching FrameView. This is not ideal, but avoids back pointers to FrameViews
314     // from ScrollingTreeStateNodes.
315     for (Frame* frame = &m_page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
316         if (FrameView* view = frame->view()) {
317             if (view->scrollLayerID() == parentNode->scrollingNodeID())
318                 return view;
319         }
320     }
321
322     return nullptr;
323 }
324
325 void AsyncScrollingCoordinator::updateScrollPositionAfterAsyncScroll(ScrollingNodeID scrollingNodeID, const FloatPoint& scrollPosition, std::optional<FloatPoint> layoutViewportOrigin, bool programmaticScroll, ScrollingLayerPositionAction scrollingLayerPositionAction)
326 {
327     ASSERT(isMainThread());
328
329     if (!m_page)
330         return;
331
332     FrameView* frameViewPtr = frameViewForScrollingNode(scrollingNodeID);
333     if (!frameViewPtr)
334         return;
335
336     LOG_WITH_STREAM(Scrolling, stream << "AsyncScrollingCoordinator::updateScrollPositionAfterAsyncScroll node " << scrollingNodeID << " scrollPosition " << scrollPosition << " action " << scrollingLayerPositionAction);
337
338     FrameView& frameView = *frameViewPtr;
339
340     if (scrollingNodeID == frameView.scrollLayerID()) {
341         reconcileScrollingState(frameView, scrollPosition, layoutViewportOrigin, programmaticScroll, true, scrollingLayerPositionAction);
342
343 #if PLATFORM(COCOA)
344         if (m_page->expectsWheelEventTriggers()) {
345             frameView.scrollAnimator().setWheelEventTestTrigger(m_page->testTrigger());
346             if (const auto& trigger = m_page->testTrigger())
347                 trigger->removeTestDeferralForReason(reinterpret_cast<WheelEventTestTrigger::ScrollableAreaIdentifier>(scrollingNodeID), WheelEventTestTrigger::ScrollingThreadSyncNeeded);
348         }
349 #endif
350         
351         return;
352     }
353
354     // Overflow-scroll area.
355     if (ScrollableArea* scrollableArea = frameView.scrollableAreaForScrollLayerID(scrollingNodeID)) {
356         scrollableArea->setIsUserScroll(scrollingLayerPositionAction == ScrollingLayerPositionAction::Sync);
357         scrollableArea->scrollToOffsetWithoutAnimation(scrollPosition);
358         scrollableArea->setIsUserScroll(false);
359         if (scrollingLayerPositionAction == ScrollingLayerPositionAction::Set)
360             m_page->editorClient().overflowScrollPositionChanged();
361
362 #if PLATFORM(COCOA)
363         if (m_page->expectsWheelEventTriggers()) {
364             frameView.scrollAnimator().setWheelEventTestTrigger(m_page->testTrigger());
365             if (const auto& trigger = m_page->testTrigger())
366                 trigger->removeTestDeferralForReason(reinterpret_cast<WheelEventTestTrigger::ScrollableAreaIdentifier>(scrollingNodeID), WheelEventTestTrigger::ScrollingThreadSyncNeeded);
367         }
368 #endif
369     }
370 }
371
372 void AsyncScrollingCoordinator::reconcileScrollingState(FrameView& frameView, const FloatPoint& scrollPosition, const LayoutViewportOriginOrOverrideRect& layoutViewportOriginOrOverrideRect, bool programmaticScroll, bool inStableState, ScrollingLayerPositionAction scrollingLayerPositionAction)
373 {
374     bool oldProgrammaticScroll = frameView.inProgrammaticScroll();
375     frameView.setInProgrammaticScroll(programmaticScroll);
376
377     std::optional<FloatRect> layoutViewportRect;
378
379     WTF::switchOn(layoutViewportOriginOrOverrideRect,
380         [&frameView](std::optional<FloatPoint> origin) {
381             if (origin)
382                 frameView.setBaseLayoutViewportOrigin(LayoutPoint(origin.value()), FrameView::TriggerLayoutOrNot::No);
383         }, [&frameView, &layoutViewportRect, inStableState, visualViewportEnabled = visualViewportEnabled()](std::optional<FloatRect> overrideRect) {
384             layoutViewportRect = overrideRect;
385             if (overrideRect && inStableState) {
386                 if (visualViewportEnabled)
387                     frameView.setLayoutViewportOverrideRect(LayoutRect(overrideRect.value()));
388 #if PLATFORM(IOS)
389                 else
390                     frameView.setCustomFixedPositionLayoutRect(enclosingIntRect(overrideRect.value()));
391 #endif
392             }
393         }
394     );
395
396     frameView.setConstrainsScrollingToContentEdge(false);
397     frameView.notifyScrollPositionChanged(roundedIntPoint(scrollPosition));
398     frameView.setConstrainsScrollingToContentEdge(true);
399     frameView.setInProgrammaticScroll(oldProgrammaticScroll);
400
401     if (!programmaticScroll && scrollingLayerPositionAction != ScrollingLayerPositionAction::Set) {
402         if (inStableState)
403             reconcileViewportConstrainedLayerPositions(frameView.rectForFixedPositionLayout(), scrollingLayerPositionAction);
404         else if (layoutViewportRect)
405             reconcileViewportConstrainedLayerPositions(LayoutRect(layoutViewportRect.value()), scrollingLayerPositionAction);
406     }
407
408     GraphicsLayer* scrollLayer = scrollLayerForFrameView(frameView);
409     if (!scrollLayer)
410         return;
411
412     GraphicsLayer* counterScrollingLayer = counterScrollingLayerForFrameView(frameView);
413     GraphicsLayer* insetClipLayer = insetClipLayerForFrameView(frameView);
414     GraphicsLayer* contentShadowLayer = contentShadowLayerForFrameView(frameView);
415     GraphicsLayer* scrolledContentsLayer = rootContentLayerForFrameView(frameView);
416     GraphicsLayer* headerLayer = headerLayerForFrameView(frameView);
417     GraphicsLayer* footerLayer = footerLayerForFrameView(frameView);
418
419     ASSERT(frameView.scrollPosition() == roundedIntPoint(scrollPosition));
420     LayoutPoint scrollPositionForFixed = frameView.scrollPositionForFixedPosition();
421     float topContentInset = frameView.topContentInset();
422
423     FloatPoint positionForInsetClipLayer;
424     if (insetClipLayer)
425         positionForInsetClipLayer = FloatPoint(insetClipLayer->position().x(), FrameView::yPositionForInsetClipLayer(scrollPosition, topContentInset));
426     FloatPoint positionForContentsLayer = frameView.positionForRootContentLayer();
427     
428     FloatPoint positionForHeaderLayer = FloatPoint(scrollPositionForFixed.x(), FrameView::yPositionForHeaderLayer(scrollPosition, topContentInset));
429     FloatPoint positionForFooterLayer = FloatPoint(scrollPositionForFixed.x(),
430         FrameView::yPositionForFooterLayer(scrollPosition, topContentInset, frameView.totalContentsSize().height(), frameView.footerHeight()));
431
432     if (programmaticScroll || scrollingLayerPositionAction == ScrollingLayerPositionAction::Set) {
433         scrollLayer->setPosition(-frameView.scrollPosition());
434         if (counterScrollingLayer)
435             counterScrollingLayer->setPosition(scrollPositionForFixed);
436         if (insetClipLayer)
437             insetClipLayer->setPosition(positionForInsetClipLayer);
438         if (contentShadowLayer)
439             contentShadowLayer->setPosition(positionForContentsLayer);
440         if (scrolledContentsLayer)
441             scrolledContentsLayer->setPosition(positionForContentsLayer);
442         if (headerLayer)
443             headerLayer->setPosition(positionForHeaderLayer);
444         if (footerLayer)
445             footerLayer->setPosition(positionForFooterLayer);
446     } else {
447         scrollLayer->syncPosition(-frameView.scrollPosition());
448         if (counterScrollingLayer)
449             counterScrollingLayer->syncPosition(scrollPositionForFixed);
450         if (insetClipLayer)
451             insetClipLayer->syncPosition(positionForInsetClipLayer);
452         if (contentShadowLayer)
453             contentShadowLayer->syncPosition(positionForContentsLayer);
454         if (scrolledContentsLayer)
455             scrolledContentsLayer->syncPosition(positionForContentsLayer);
456         if (headerLayer)
457             headerLayer->syncPosition(positionForHeaderLayer);
458         if (footerLayer)
459             footerLayer->syncPosition(positionForFooterLayer);
460     }
461 }
462
463 void AsyncScrollingCoordinator::scrollableAreaScrollbarLayerDidChange(ScrollableArea& scrollableArea, ScrollbarOrientation orientation)
464 {
465     ASSERT(isMainThread());
466     ASSERT(m_page);
467
468     if (&scrollableArea != static_cast<ScrollableArea*>(m_page->mainFrame().view()))
469         return;
470
471     if (orientation == VerticalScrollbar)
472         scrollableArea.verticalScrollbarLayerDidChange();
473     else
474         scrollableArea.horizontalScrollbarLayerDidChange();
475 }
476
477 ScrollingNodeID AsyncScrollingCoordinator::attachToStateTree(ScrollingNodeType nodeType, ScrollingNodeID newNodeID, ScrollingNodeID parentID)
478 {
479     return m_scrollingStateTree->attachNode(nodeType, newNodeID, parentID);
480 }
481
482 void AsyncScrollingCoordinator::detachFromStateTree(ScrollingNodeID nodeID)
483 {
484     m_scrollingStateTree->detachNode(nodeID);
485 }
486
487 void AsyncScrollingCoordinator::clearStateTree()
488 {
489     m_scrollingStateTree->clear();
490 }
491
492 void AsyncScrollingCoordinator::reconcileViewportConstrainedLayerPositions(const LayoutRect& viewportRect, ScrollingLayerPositionAction action)
493 {
494     if (!m_scrollingStateTree->rootStateNode())
495         return;
496
497     auto children = m_scrollingStateTree->rootStateNode()->children();
498     if (!children)
499         return;
500
501     LOG_WITH_STREAM(Scrolling, stream << "AsyncScrollingCoordinator::reconcileViewportConstrainedLayerPositions for viewport rect " << viewportRect);
502
503     // FIXME: We'll have to traverse deeper into the tree at some point.
504     for (auto& child : *children)
505         child->reconcileLayerPositionForViewportRect(viewportRect, action);
506 }
507
508 void AsyncScrollingCoordinator::ensureRootStateNodeForFrameView(FrameView& frameView)
509 {
510     ASSERT(frameView.scrollLayerID());
511     attachToStateTree(FrameScrollingNode, frameView.scrollLayerID(), 0);
512 }
513
514 void AsyncScrollingCoordinator::updateFrameScrollingNode(ScrollingNodeID nodeID, GraphicsLayer* layer, GraphicsLayer* scrolledContentsLayer, GraphicsLayer* counterScrollingLayer, GraphicsLayer* insetClipLayer, const ScrollingGeometry* scrollingGeometry)
515 {
516     ScrollingStateFrameScrollingNode* node = downcast<ScrollingStateFrameScrollingNode>(m_scrollingStateTree->stateNodeForID(nodeID));
517     ASSERT(node);
518     if (!node)
519         return;
520
521     node->setLayer(layer);
522     node->setInsetClipLayer(insetClipLayer);
523     node->setScrolledContentsLayer(scrolledContentsLayer);
524     node->setCounterScrollingLayer(counterScrollingLayer);
525
526     if (scrollingGeometry) {
527         node->setScrollOrigin(scrollingGeometry->scrollOrigin);
528         node->setScrollPosition(scrollingGeometry->scrollPosition);
529         node->setTotalContentsSize(scrollingGeometry->contentSize);
530         node->setReachableContentsSize(scrollingGeometry->reachableContentSize);
531         node->setScrollableAreaSize(scrollingGeometry->scrollableAreaSize);
532     }
533 }
534     
535 void AsyncScrollingCoordinator::updateOverflowScrollingNode(ScrollingNodeID nodeID, GraphicsLayer* layer, GraphicsLayer* scrolledContentsLayer, const ScrollingGeometry* scrollingGeometry)
536 {
537     ScrollingStateOverflowScrollingNode* node = downcast<ScrollingStateOverflowScrollingNode>(m_scrollingStateTree->stateNodeForID(nodeID));
538     ASSERT(node);
539     if (!node)
540         return;
541
542     node->setLayer(layer);
543     node->setScrolledContentsLayer(scrolledContentsLayer);
544     
545     if (scrollingGeometry) {
546         node->setScrollOrigin(scrollingGeometry->scrollOrigin);
547         node->setScrollPosition(scrollingGeometry->scrollPosition);
548         node->setTotalContentsSize(scrollingGeometry->contentSize);
549         node->setReachableContentsSize(scrollingGeometry->reachableContentSize);
550         node->setScrollableAreaSize(scrollingGeometry->scrollableAreaSize);
551 #if ENABLE(CSS_SCROLL_SNAP)
552         setStateScrollingNodeSnapOffsetsAsFloat(*node, ScrollEventAxis::Horizontal, &scrollingGeometry->horizontalSnapOffsets, &scrollingGeometry->horizontalSnapOffsetRanges, m_page->deviceScaleFactor());
553         setStateScrollingNodeSnapOffsetsAsFloat(*node, ScrollEventAxis::Vertical, &scrollingGeometry->verticalSnapOffsets, &scrollingGeometry->verticalSnapOffsetRanges, m_page->deviceScaleFactor());
554         node->setCurrentHorizontalSnapPointIndex(scrollingGeometry->currentHorizontalSnapPointIndex);
555         node->setCurrentVerticalSnapPointIndex(scrollingGeometry->currentVerticalSnapPointIndex);
556 #endif
557     }
558 }
559
560 void AsyncScrollingCoordinator::updateViewportConstrainedNode(ScrollingNodeID nodeID, const ViewportConstraints& constraints, GraphicsLayer* graphicsLayer)
561 {
562     ASSERT(supportsFixedPositionLayers());
563
564     ScrollingStateNode* node = m_scrollingStateTree->stateNodeForID(nodeID);
565     if (!node)
566         return;
567
568     switch (constraints.constraintType()) {
569     case ViewportConstraints::FixedPositionConstraint: {
570         ScrollingStateFixedNode& fixedNode = downcast<ScrollingStateFixedNode>(*node);
571         fixedNode.setLayer(graphicsLayer);
572         fixedNode.updateConstraints((const FixedPositionViewportConstraints&)constraints);
573         break;
574     }
575     case ViewportConstraints::StickyPositionConstraint: {
576         ScrollingStateStickyNode& stickyNode = downcast<ScrollingStateStickyNode>(*node);
577         stickyNode.setLayer(graphicsLayer);
578         stickyNode.updateConstraints((const StickyPositionViewportConstraints&)constraints);
579         break;
580     }
581     }
582 }
583
584 void AsyncScrollingCoordinator::setSynchronousScrollingReasons(SynchronousScrollingReasons reasons)
585 {
586     if (!m_scrollingStateTree->rootStateNode())
587         return;
588
589     // The FrameView's GraphicsLayer is likely to be out-of-synch with the PlatformLayer
590     // at this point. So we'll update it before we switch back to main thread scrolling
591     // in order to avoid layer positioning bugs.
592     if (reasons)
593         updateMainFrameScrollLayerPosition();
594     m_scrollingStateTree->rootStateNode()->setSynchronousScrollingReasons(reasons);
595 }
596
597 void AsyncScrollingCoordinator::updateMainFrameScrollLayerPosition()
598 {
599     ASSERT(isMainThread());
600
601     if (!m_page)
602         return;
603
604     FrameView* frameView = m_page->mainFrame().view();
605     if (!frameView)
606         return;
607
608     if (GraphicsLayer* scrollLayer = scrollLayerForFrameView(*frameView))
609         scrollLayer->setPosition(-frameView->scrollPosition());
610 }
611
612 bool AsyncScrollingCoordinator::isRubberBandInProgress() const
613 {
614     return scrollingTree()->isRubberBandInProgress();
615 }
616
617 void AsyncScrollingCoordinator::setScrollPinningBehavior(ScrollPinningBehavior pinning)
618 {
619     scrollingTree()->setScrollPinningBehavior(pinning);
620 }
621
622 bool AsyncScrollingCoordinator::visualViewportEnabled() const
623 {
624     return m_page->mainFrame().settings().visualViewportEnabled();
625 }
626
627 String AsyncScrollingCoordinator::scrollingStateTreeAsText() const
628 {
629     if (m_scrollingStateTree->rootStateNode()) {
630         if (m_eventTrackingRegionsDirty)
631             m_scrollingStateTree->rootStateNode()->setEventTrackingRegions(absoluteEventTrackingRegions());
632         return m_scrollingStateTree->rootStateNode()->scrollingStateTreeAsText();
633     }
634
635     return String();
636 }
637
638 #if PLATFORM(COCOA)
639 void AsyncScrollingCoordinator::setActiveScrollSnapIndices(ScrollingNodeID scrollingNodeID, unsigned horizontalIndex, unsigned verticalIndex)
640 {
641     ASSERT(isMainThread());
642     
643     if (!m_page)
644         return;
645     
646     FrameView* frameView = frameViewForScrollingNode(scrollingNodeID);
647     if (!frameView)
648         return;
649     
650     if (scrollingNodeID == frameView->scrollLayerID()) {
651         frameView->setCurrentHorizontalSnapPointIndex(horizontalIndex);
652         frameView->setCurrentVerticalSnapPointIndex(verticalIndex);
653         return;
654     }
655     
656     // Overflow-scroll area.
657     if (ScrollableArea* scrollableArea = frameView->scrollableAreaForScrollLayerID(scrollingNodeID)) {
658         scrollableArea->setCurrentHorizontalSnapPointIndex(horizontalIndex);
659         scrollableArea->setCurrentVerticalSnapPointIndex(verticalIndex);
660     }
661 }
662
663 void AsyncScrollingCoordinator::deferTestsForReason(WheelEventTestTrigger::ScrollableAreaIdentifier identifier, WheelEventTestTrigger::DeferTestTriggerReason reason) const
664 {
665     ASSERT(isMainThread());
666     if (!m_page || !m_page->expectsWheelEventTriggers())
667         return;
668
669     if (const auto& trigger = m_page->testTrigger()) {
670         LOG(WheelEventTestTriggers, "    (!) AsyncScrollingCoordinator::deferTestsForReason: Deferring %p for reason %d.", identifier, reason);
671         trigger->deferTestsForReason(identifier, reason);
672     }
673 }
674
675 void AsyncScrollingCoordinator::removeTestDeferralForReason(WheelEventTestTrigger::ScrollableAreaIdentifier identifier, WheelEventTestTrigger::DeferTestTriggerReason reason) const
676 {
677     ASSERT(isMainThread());
678     if (!m_page || !m_page->expectsWheelEventTriggers())
679         return;
680
681     if (const auto& trigger = m_page->testTrigger()) {
682         LOG(WheelEventTestTriggers, "    (!) AsyncScrollingCoordinator::removeTestDeferralForReason: Deferring %p for reason %d.", identifier, reason);
683         trigger->removeTestDeferralForReason(identifier, reason);
684     }
685 }
686 #endif
687
688 #if ENABLE(CSS_SCROLL_SNAP)
689 bool AsyncScrollingCoordinator::isScrollSnapInProgress() const
690 {
691     return scrollingTree()->isScrollSnapInProgress();
692 }
693
694 void AsyncScrollingCoordinator::updateScrollSnapPropertiesWithFrameView(const FrameView& frameView)
695 {
696     if (auto node = downcast<ScrollingStateFrameScrollingNode>(m_scrollingStateTree->stateNodeForID(frameView.scrollLayerID()))) {
697         setStateScrollingNodeSnapOffsetsAsFloat(*node, ScrollEventAxis::Horizontal, frameView.horizontalSnapOffsets(), frameView.horizontalSnapOffsetRanges(), m_page->deviceScaleFactor());
698         setStateScrollingNodeSnapOffsetsAsFloat(*node, ScrollEventAxis::Vertical, frameView.verticalSnapOffsets(), frameView.verticalSnapOffsetRanges(), m_page->deviceScaleFactor());
699         node->setCurrentHorizontalSnapPointIndex(frameView.currentHorizontalSnapPointIndex());
700         node->setCurrentVerticalSnapPointIndex(frameView.currentVerticalSnapPointIndex());
701     }
702 }
703 #endif
704     
705 } // namespace WebCore
706
707 #endif // ENABLE(ASYNC_SCROLLING)