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