UI process side scrollbars for UI side compositing on Mac
[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     scrollParameters.useDarkAppearanceForScrollbars = frameView.useDarkAppearanceForScrollbars();
178
179     node->setScrollableAreaParameters(scrollParameters);
180 }
181
182 void AsyncScrollingCoordinator::updateExpectsWheelEventTestTriggerWithFrameView(const FrameView& frameView)
183 {
184     auto* page = frameView.frame().page();
185     if (!page)
186         return;
187
188     auto* node = downcast<ScrollingStateFrameScrollingNode>(m_scrollingStateTree->stateNodeForID(frameView.scrollLayerID()));
189     if (!node)
190         return;
191
192     node->setExpectsWheelEventTestTrigger(page->expectsWheelEventTriggers());
193 }
194
195 void AsyncScrollingCoordinator::frameViewEventTrackingRegionsChanged(FrameView& frameView)
196 {
197     if (!m_scrollingStateTree->rootStateNode())
198         return;
199
200     setEventTrackingRegionsDirty();
201     DebugPageOverlays::didChangeEventHandlers(frameView.frame());
202 }
203
204 void AsyncScrollingCoordinator::frameViewRootLayerDidChange(FrameView& frameView)
205 {
206     ASSERT(isMainThread());
207     ASSERT(m_page);
208
209     if (!coordinatesScrollingForFrameView(frameView))
210         return;
211     
212     // FIXME: In some navigation scenarios, the FrameView has no RenderView or that RenderView has not been composited.
213     // This needs cleaning up: https://bugs.webkit.org/show_bug.cgi?id=132724
214     if (!frameView.scrollLayerID())
215         return;
216     
217     // If the root layer does not have a ScrollingStateNode, then we should create one.
218     ensureRootStateNodeForFrameView(frameView);
219     ASSERT(m_scrollingStateTree->stateNodeForID(frameView.scrollLayerID()));
220
221     ScrollingCoordinator::frameViewRootLayerDidChange(frameView);
222
223     auto* node = downcast<ScrollingStateFrameScrollingNode>(m_scrollingStateTree->stateNodeForID(frameView.scrollLayerID()));
224     node->setLayer(scrollLayerForFrameView(frameView));
225     node->setScrolledContentsLayer(rootContentLayerForFrameView(frameView));
226     node->setCounterScrollingLayer(counterScrollingLayerForFrameView(frameView));
227     node->setInsetClipLayer(insetClipLayerForFrameView(frameView));
228     node->setContentShadowLayer(contentShadowLayerForFrameView(frameView));
229     node->setHeaderLayer(headerLayerForFrameView(frameView));
230     node->setFooterLayer(footerLayerForFrameView(frameView));
231     node->setScrollBehaviorForFixedElements(frameView.scrollBehaviorForFixedElements());
232     node->setVerticalScrollbarLayer(frameView.layerForVerticalScrollbar());
233     node->setHorizontalScrollbarLayer(frameView.layerForHorizontalScrollbar());
234 }
235
236 bool AsyncScrollingCoordinator::requestScrollPositionUpdate(FrameView& frameView, const IntPoint& scrollPosition)
237 {
238     ASSERT(isMainThread());
239     ASSERT(m_page);
240
241     if (!coordinatesScrollingForFrameView(frameView))
242         return false;
243
244     bool isProgrammaticScroll = frameView.inProgrammaticScroll();
245     if (isProgrammaticScroll || frameView.frame().document()->pageCacheState() != Document::NotInPageCache)
246         updateScrollPositionAfterAsyncScroll(frameView.scrollLayerID(), scrollPosition, WTF::nullopt, isProgrammaticScroll, ScrollingLayerPositionAction::Set);
247
248     // If this frame view's document is being put into the page cache, we don't want to update our
249     // main frame scroll position. Just let the FrameView think that we did.
250     if (frameView.frame().document()->pageCacheState() != Document::NotInPageCache)
251         return true;
252
253     auto* stateNode = downcast<ScrollingStateScrollingNode>(m_scrollingStateTree->stateNodeForID(frameView.scrollLayerID()));
254     if (!stateNode)
255         return false;
256
257     stateNode->setRequestedScrollPosition(scrollPosition, isProgrammaticScroll);
258     return true;
259 }
260
261 void AsyncScrollingCoordinator::scheduleUpdateScrollPositionAfterAsyncScroll(ScrollingNodeID nodeID, const FloatPoint& scrollPosition, const Optional<FloatPoint>& layoutViewportOrigin, bool programmaticScroll, ScrollingLayerPositionAction scrollingLayerPositionAction)
262 {
263     ScheduledScrollUpdate scrollUpdate(nodeID, scrollPosition, layoutViewportOrigin, programmaticScroll, scrollingLayerPositionAction);
264     
265     // For programmatic scrolls, requestScrollPositionUpdate() has already called updateScrollPositionAfterAsyncScroll().
266     if (programmaticScroll)
267         return;
268
269     if (m_updateNodeScrollPositionTimer.isActive()) {
270         if (m_scheduledScrollUpdate.matchesUpdateType(scrollUpdate)) {
271             m_scheduledScrollUpdate.scrollPosition = scrollPosition;
272             m_scheduledScrollUpdate.layoutViewportOrigin = layoutViewportOrigin;
273             return;
274         }
275     
276         // If the parameters don't match what was previously scheduled, dispatch immediately.
277         m_updateNodeScrollPositionTimer.stop();
278         updateScrollPositionAfterAsyncScroll(m_scheduledScrollUpdate.nodeID, m_scheduledScrollUpdate.scrollPosition, m_scheduledScrollUpdate.layoutViewportOrigin, m_scheduledScrollUpdate.isProgrammaticScroll, m_scheduledScrollUpdate.updateLayerPositionAction);
279         updateScrollPositionAfterAsyncScroll(nodeID, scrollPosition, layoutViewportOrigin, programmaticScroll, scrollingLayerPositionAction);
280         return;
281     }
282
283     m_scheduledScrollUpdate = scrollUpdate;
284     m_updateNodeScrollPositionTimer.startOneShot(0_s);
285 }
286
287 void AsyncScrollingCoordinator::updateScrollPositionAfterAsyncScrollTimerFired()
288 {
289     updateScrollPositionAfterAsyncScroll(m_scheduledScrollUpdate.nodeID, m_scheduledScrollUpdate.scrollPosition, m_scheduledScrollUpdate.layoutViewportOrigin, m_scheduledScrollUpdate.isProgrammaticScroll, m_scheduledScrollUpdate.updateLayerPositionAction);
290 }
291
292 FrameView* AsyncScrollingCoordinator::frameViewForScrollingNode(ScrollingNodeID scrollingNodeID) const
293 {
294     if (!m_scrollingStateTree->rootStateNode())
295         return nullptr;
296     
297     if (scrollingNodeID == m_scrollingStateTree->rootStateNode()->scrollingNodeID())
298         return m_page->mainFrame().view();
299
300     auto* stateNode = m_scrollingStateTree->stateNodeForID(scrollingNodeID);
301     if (!stateNode)
302         return nullptr;
303
304     // Find the enclosing frame scrolling node.
305     auto* parentNode = stateNode;
306     while (parentNode && !parentNode->isFrameScrollingNode())
307         parentNode = parentNode->parent();
308     
309     if (!parentNode)
310         return nullptr;
311     
312     // Walk the frame tree to find the matching FrameView. This is not ideal, but avoids back pointers to FrameViews
313     // from ScrollingTreeStateNodes.
314     for (Frame* frame = &m_page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
315         if (auto* view = frame->view()) {
316             if (view->scrollLayerID() == parentNode->scrollingNodeID())
317                 return view;
318         }
319     }
320
321     return nullptr;
322 }
323
324 void AsyncScrollingCoordinator::updateScrollPositionAfterAsyncScroll(ScrollingNodeID scrollingNodeID, const FloatPoint& scrollPosition, Optional<FloatPoint> layoutViewportOrigin, bool programmaticScroll, ScrollingLayerPositionAction scrollingLayerPositionAction)
325 {
326     ASSERT(isMainThread());
327
328     if (!m_page)
329         return;
330
331     auto* frameViewPtr = frameViewForScrollingNode(scrollingNodeID);
332     if (!frameViewPtr)
333         return;
334
335     LOG_WITH_STREAM(Scrolling, stream << "AsyncScrollingCoordinator::updateScrollPositionAfterAsyncScroll node " << scrollingNodeID << " scrollPosition " << scrollPosition << " action " << scrollingLayerPositionAction);
336
337     auto& frameView = *frameViewPtr;
338
339     if (scrollingNodeID == frameView.scrollLayerID()) {
340         reconcileScrollingState(frameView, scrollPosition, layoutViewportOrigin, programmaticScroll, ViewportRectStability::Stable, scrollingLayerPositionAction);
341
342 #if PLATFORM(COCOA)
343         if (m_page->expectsWheelEventTriggers()) {
344             frameView.scrollAnimator().setWheelEventTestTrigger(m_page->testTrigger());
345             if (const auto& trigger = m_page->testTrigger())
346                 trigger->removeTestDeferralForReason(reinterpret_cast<WheelEventTestTrigger::ScrollableAreaIdentifier>(scrollingNodeID), WheelEventTestTrigger::ScrollingThreadSyncNeeded);
347         }
348 #endif
349         
350         return;
351     }
352
353     // Overflow-scroll area.
354     if (auto* scrollableArea = frameView.scrollableAreaForScrollLayerID(scrollingNodeID)) {
355         scrollableArea->setIsUserScroll(scrollingLayerPositionAction == ScrollingLayerPositionAction::Sync);
356         scrollableArea->scrollToOffsetWithoutAnimation(scrollPosition);
357         scrollableArea->setIsUserScroll(false);
358         if (scrollingLayerPositionAction == ScrollingLayerPositionAction::Set)
359             m_page->editorClient().overflowScrollPositionChanged();
360
361 #if PLATFORM(COCOA)
362         if (m_page->expectsWheelEventTriggers()) {
363             frameView.scrollAnimator().setWheelEventTestTrigger(m_page->testTrigger());
364             if (const auto& trigger = m_page->testTrigger())
365                 trigger->removeTestDeferralForReason(reinterpret_cast<WheelEventTestTrigger::ScrollableAreaIdentifier>(scrollingNodeID), WheelEventTestTrigger::ScrollingThreadSyncNeeded);
366         }
367 #endif
368     }
369 }
370
371 void AsyncScrollingCoordinator::reconcileScrollingState(FrameView& frameView, const FloatPoint& scrollPosition, const LayoutViewportOriginOrOverrideRect& layoutViewportOriginOrOverrideRect, bool programmaticScroll, ViewportRectStability viewportRectStability, ScrollingLayerPositionAction scrollingLayerPositionAction)
372 {
373     bool oldProgrammaticScroll = frameView.inProgrammaticScroll();
374     frameView.setInProgrammaticScroll(programmaticScroll);
375
376     LOG_WITH_STREAM(Scrolling, stream << getCurrentProcessID() << " AsyncScrollingCoordinator " << this << " reconcileScrollingState scrollPosition " << scrollPosition << " programmaticScroll " << programmaticScroll << " stability " << viewportRectStability << " " << scrollingLayerPositionAction);
377
378     Optional<FloatRect> layoutViewportRect;
379
380     WTF::switchOn(layoutViewportOriginOrOverrideRect,
381         [&frameView](Optional<FloatPoint> origin) {
382             if (origin)
383                 frameView.setBaseLayoutViewportOrigin(LayoutPoint(origin.value()), FrameView::TriggerLayoutOrNot::No);
384         }, [&frameView, &layoutViewportRect, viewportRectStability, visualViewportEnabled = visualViewportEnabled()](Optional<FloatRect> overrideRect) {
385             if (!overrideRect)
386                 return;
387
388             layoutViewportRect = overrideRect;
389             if (visualViewportEnabled && viewportRectStability != ViewportRectStability::ChangingObscuredInsetsInteractively)
390                 frameView.setLayoutViewportOverrideRect(LayoutRect(overrideRect.value()), viewportRectStability == ViewportRectStability::Stable ? FrameView::TriggerLayoutOrNot::Yes : FrameView::TriggerLayoutOrNot::No);
391 #if PLATFORM(IOS_FAMILY)
392             else if (viewportRectStability == ViewportRectStability::Stable)
393                 frameView.setCustomFixedPositionLayoutRect(enclosingIntRect(overrideRect.value()));
394 #endif
395         }
396     );
397
398     frameView.setConstrainsScrollingToContentEdge(false);
399     frameView.notifyScrollPositionChanged(roundedIntPoint(scrollPosition));
400     frameView.setConstrainsScrollingToContentEdge(true);
401     frameView.setInProgrammaticScroll(oldProgrammaticScroll);
402
403     if (!programmaticScroll && scrollingLayerPositionAction != ScrollingLayerPositionAction::Set) {
404         auto scrollingNodeID = frameView.scrollLayerID();
405         if (viewportRectStability == ViewportRectStability::Stable)
406             reconcileViewportConstrainedLayerPositions(scrollingNodeID, frameView.rectForFixedPositionLayout(), scrollingLayerPositionAction);
407         else if (layoutViewportRect)
408             reconcileViewportConstrainedLayerPositions(scrollingNodeID, LayoutRect(layoutViewportRect.value()), scrollingLayerPositionAction);
409     }
410
411     auto* scrollLayer = scrollLayerForFrameView(frameView);
412     if (!scrollLayer)
413         return;
414
415     auto* counterScrollingLayer = counterScrollingLayerForFrameView(frameView);
416     auto* insetClipLayer = insetClipLayerForFrameView(frameView);
417     auto* contentShadowLayer = contentShadowLayerForFrameView(frameView);
418     auto* scrolledContentsLayer = rootContentLayerForFrameView(frameView);
419     auto* headerLayer = headerLayerForFrameView(frameView);
420     auto* footerLayer = footerLayerForFrameView(frameView);
421
422     ASSERT(frameView.scrollPosition() == roundedIntPoint(scrollPosition));
423     LayoutPoint scrollPositionForFixed = frameView.scrollPositionForFixedPosition();
424     float topContentInset = frameView.topContentInset();
425
426     FloatPoint positionForInsetClipLayer;
427     if (insetClipLayer)
428         positionForInsetClipLayer = FloatPoint(insetClipLayer->position().x(), FrameView::yPositionForInsetClipLayer(scrollPosition, topContentInset));
429     FloatPoint positionForContentsLayer = frameView.positionForRootContentLayer();
430     
431     FloatPoint positionForHeaderLayer = FloatPoint(scrollPositionForFixed.x(), FrameView::yPositionForHeaderLayer(scrollPosition, topContentInset));
432     FloatPoint positionForFooterLayer = FloatPoint(scrollPositionForFixed.x(),
433         FrameView::yPositionForFooterLayer(scrollPosition, topContentInset, frameView.totalContentsSize().height(), frameView.footerHeight()));
434
435     if (programmaticScroll || scrollingLayerPositionAction == ScrollingLayerPositionAction::Set) {
436         scrollLayer->setPosition(-frameView.scrollPosition());
437         if (counterScrollingLayer)
438             counterScrollingLayer->setPosition(scrollPositionForFixed);
439         if (insetClipLayer)
440             insetClipLayer->setPosition(positionForInsetClipLayer);
441         if (contentShadowLayer)
442             contentShadowLayer->setPosition(positionForContentsLayer);
443         if (scrolledContentsLayer)
444             scrolledContentsLayer->setPosition(positionForContentsLayer);
445         if (headerLayer)
446             headerLayer->setPosition(positionForHeaderLayer);
447         if (footerLayer)
448             footerLayer->setPosition(positionForFooterLayer);
449     } else {
450         scrollLayer->syncPosition(-frameView.scrollPosition());
451         if (counterScrollingLayer)
452             counterScrollingLayer->syncPosition(scrollPositionForFixed);
453         if (insetClipLayer)
454             insetClipLayer->syncPosition(positionForInsetClipLayer);
455         if (contentShadowLayer)
456             contentShadowLayer->syncPosition(positionForContentsLayer);
457         if (scrolledContentsLayer)
458             scrolledContentsLayer->syncPosition(positionForContentsLayer);
459         if (headerLayer)
460             headerLayer->syncPosition(positionForHeaderLayer);
461         if (footerLayer)
462             footerLayer->syncPosition(positionForFooterLayer);
463     }
464 }
465
466 void AsyncScrollingCoordinator::scrollableAreaScrollbarLayerDidChange(ScrollableArea& scrollableArea, ScrollbarOrientation orientation)
467 {
468     ASSERT(isMainThread());
469     ASSERT(m_page);
470
471     auto* node = m_scrollingStateTree->stateNodeForID(scrollableArea.scrollLayerID());
472     if (is<ScrollingStateFrameScrollingNode>(node)) {
473         auto& scrollingNode = downcast<ScrollingStateFrameScrollingNode>(*node);
474         if (orientation == VerticalScrollbar)
475             scrollingNode.setVerticalScrollbarLayer(scrollableArea.layerForVerticalScrollbar());
476         else
477             scrollingNode.setHorizontalScrollbarLayer(scrollableArea.layerForHorizontalScrollbar());
478
479     }
480
481     if (&scrollableArea == m_page->mainFrame().view()) {
482         if (orientation == VerticalScrollbar)
483             scrollableArea.verticalScrollbarLayerDidChange();
484         else
485             scrollableArea.horizontalScrollbarLayerDidChange();
486     }
487 }
488
489 ScrollingNodeID AsyncScrollingCoordinator::attachToStateTree(ScrollingNodeType nodeType, ScrollingNodeID newNodeID, ScrollingNodeID parentID, size_t childIndex)
490 {
491     LOG_WITH_STREAM(Scrolling, stream << "AsyncScrollingCoordinator::attachToStateTree " << nodeType << " node " << newNodeID << " parent " << parentID << " index " << childIndex);
492     return m_scrollingStateTree->attachNode(nodeType, newNodeID, parentID, childIndex);
493 }
494
495 void AsyncScrollingCoordinator::detachFromStateTree(ScrollingNodeID nodeID)
496 {
497     m_scrollingStateTree->detachNode(nodeID);
498 }
499
500 void AsyncScrollingCoordinator::clearStateTree()
501 {
502     m_scrollingStateTree->clear();
503 }
504
505 void AsyncScrollingCoordinator::reconcileViewportConstrainedLayerPositions(ScrollingNodeID scrollingNodeID, const LayoutRect& viewportRect, ScrollingLayerPositionAction action)
506 {
507     auto* scrollingNode = m_scrollingStateTree->stateNodeForID(scrollingNodeID);
508     if (!scrollingNode)
509         return;
510
511     LOG_WITH_STREAM(Scrolling, stream << getCurrentProcessID() << " AsyncScrollingCoordinator::reconcileViewportConstrainedLayerPositions for viewport rect " << viewportRect << " and node " << scrollingNodeID);
512
513     scrollingNode->reconcileLayerPositionForViewportRect(viewportRect, action);
514 }
515
516 void AsyncScrollingCoordinator::ensureRootStateNodeForFrameView(FrameView& frameView)
517 {
518     ASSERT(frameView.scrollLayerID());
519     if (m_scrollingStateTree->stateNodeForID(frameView.scrollLayerID()))
520         return;
521
522     // For non-main frames, it is only possible to arrive in this function from
523     // RenderLayerCompositor::updateBacking where the node has already been created.
524     ASSERT(frameView.frame().isMainFrame());
525     attachToStateTree(ScrollingNodeType::MainFrame, frameView.scrollLayerID(), 0, 0);
526 }
527
528 void AsyncScrollingCoordinator::updateFrameScrollingNode(ScrollingNodeID nodeID, GraphicsLayer* layer, GraphicsLayer* scrolledContentsLayer, GraphicsLayer* counterScrollingLayer, GraphicsLayer* insetClipLayer, const ScrollingGeometry& scrollingGeometry)
529 {
530     auto* node = downcast<ScrollingStateFrameScrollingNode>(m_scrollingStateTree->stateNodeForID(nodeID));
531     ASSERT(node);
532     if (!node)
533         return;
534
535     node->setLayer(layer);
536     node->setInsetClipLayer(insetClipLayer);
537     node->setScrolledContentsLayer(scrolledContentsLayer);
538     node->setCounterScrollingLayer(counterScrollingLayer);
539     node->setParentRelativeScrollableRect(scrollingGeometry.parentRelativeScrollableRect);
540     node->setScrollOrigin(scrollingGeometry.scrollOrigin);
541     node->setScrollPosition(scrollingGeometry.scrollPosition);
542     node->setTotalContentsSize(scrollingGeometry.contentSize);
543     node->setReachableContentsSize(scrollingGeometry.reachableContentSize);
544     node->setScrollableAreaSize(scrollingGeometry.scrollableAreaSize);
545 }
546     
547 void AsyncScrollingCoordinator::updateOverflowScrollingNode(ScrollingNodeID nodeID, GraphicsLayer* layer, GraphicsLayer* scrolledContentsLayer, const ScrollingGeometry& scrollingGeometry)
548 {
549     auto* node = downcast<ScrollingStateOverflowScrollingNode>(m_scrollingStateTree->stateNodeForID(nodeID));
550     ASSERT(node);
551     if (!node)
552         return;
553
554     node->setLayer(layer);
555     node->setScrolledContentsLayer(scrolledContentsLayer);
556     node->setParentRelativeScrollableRect(scrollingGeometry.parentRelativeScrollableRect);
557     node->setScrollOrigin(scrollingGeometry.scrollOrigin);
558     node->setScrollPosition(scrollingGeometry.scrollPosition);
559     node->setTotalContentsSize(scrollingGeometry.contentSize);
560     node->setReachableContentsSize(scrollingGeometry.reachableContentSize);
561     node->setScrollableAreaSize(scrollingGeometry.scrollableAreaSize);
562 #if ENABLE(CSS_SCROLL_SNAP)
563     setStateScrollingNodeSnapOffsetsAsFloat(*node, ScrollEventAxis::Horizontal, &scrollingGeometry.horizontalSnapOffsets, &scrollingGeometry.horizontalSnapOffsetRanges, m_page->deviceScaleFactor());
564     setStateScrollingNodeSnapOffsetsAsFloat(*node, ScrollEventAxis::Vertical, &scrollingGeometry.verticalSnapOffsets, &scrollingGeometry.verticalSnapOffsetRanges, m_page->deviceScaleFactor());
565     node->setCurrentHorizontalSnapPointIndex(scrollingGeometry.currentHorizontalSnapPointIndex);
566     node->setCurrentVerticalSnapPointIndex(scrollingGeometry.currentVerticalSnapPointIndex);
567 #endif
568 }
569
570 void AsyncScrollingCoordinator::updateNodeLayer(ScrollingNodeID nodeID, GraphicsLayer* graphicsLayer)
571 {
572     auto* node = m_scrollingStateTree->stateNodeForID(nodeID);
573     if (!node)
574         return;
575
576     node->setLayer(graphicsLayer);
577 }
578
579 void AsyncScrollingCoordinator::updateNodeViewportConstraints(ScrollingNodeID nodeID, const ViewportConstraints& constraints)
580 {
581     auto* node = m_scrollingStateTree->stateNodeForID(nodeID);
582     if (!node)
583         return;
584
585     switch (constraints.constraintType()) {
586     case ViewportConstraints::FixedPositionConstraint: {
587         auto& fixedNode = downcast<ScrollingStateFixedNode>(*node);
588         fixedNode.updateConstraints((const FixedPositionViewportConstraints&)constraints);
589         break;
590     }
591     case ViewportConstraints::StickyPositionConstraint: {
592         auto& stickyNode = downcast<ScrollingStateStickyNode>(*node);
593         stickyNode.updateConstraints((const StickyPositionViewportConstraints&)constraints);
594         break;
595     }
596     }
597 }
598
599 void AsyncScrollingCoordinator::setSynchronousScrollingReasons(FrameView& frameView, SynchronousScrollingReasons reasons)
600 {
601     auto* scrollingStateNode = static_cast<ScrollingStateFrameScrollingNode*>(m_scrollingStateTree->stateNodeForID(frameView.scrollLayerID()));
602     if (!scrollingStateNode)
603         return;
604
605     // The FrameView's GraphicsLayer is likely to be out-of-synch with the PlatformLayer
606     // at this point. So we'll update it before we switch back to main thread scrolling
607     // in order to avoid layer positioning bugs.
608     if (reasons)
609         updateScrollLayerPosition(frameView);
610     scrollingStateNode->setSynchronousScrollingReasons(reasons);
611 }
612
613 void AsyncScrollingCoordinator::updateScrollLayerPosition(FrameView& frameView)
614 {
615     ASSERT(isMainThread());
616     if (auto* scrollLayer = scrollLayerForFrameView(frameView))
617         scrollLayer->setPosition(-frameView.scrollPosition());
618 }
619
620 bool AsyncScrollingCoordinator::isRubberBandInProgress() const
621 {
622     return scrollingTree()->isRubberBandInProgress();
623 }
624
625 void AsyncScrollingCoordinator::setScrollPinningBehavior(ScrollPinningBehavior pinning)
626 {
627     scrollingTree()->setScrollPinningBehavior(pinning);
628 }
629
630 bool AsyncScrollingCoordinator::visualViewportEnabled() const
631 {
632     return m_page->mainFrame().settings().visualViewportEnabled();
633 }
634
635 String AsyncScrollingCoordinator::scrollingStateTreeAsText(ScrollingStateTreeAsTextBehavior behavior) const
636 {
637     if (m_scrollingStateTree->rootStateNode()) {
638         if (m_eventTrackingRegionsDirty)
639             m_scrollingStateTree->rootStateNode()->setEventTrackingRegions(absoluteEventTrackingRegions());
640         return m_scrollingStateTree->rootStateNode()->scrollingStateTreeAsText(behavior);
641     }
642
643     return String();
644 }
645
646 #if PLATFORM(COCOA)
647 void AsyncScrollingCoordinator::setActiveScrollSnapIndices(ScrollingNodeID scrollingNodeID, unsigned horizontalIndex, unsigned verticalIndex)
648 {
649     ASSERT(isMainThread());
650     
651     if (!m_page)
652         return;
653     
654     auto* frameView = frameViewForScrollingNode(scrollingNodeID);
655     if (!frameView)
656         return;
657     
658     if (scrollingNodeID == frameView->scrollLayerID()) {
659         frameView->setCurrentHorizontalSnapPointIndex(horizontalIndex);
660         frameView->setCurrentVerticalSnapPointIndex(verticalIndex);
661         return;
662     }
663     
664     // Overflow-scroll area.
665     if (auto* scrollableArea = frameView->scrollableAreaForScrollLayerID(scrollingNodeID)) {
666         scrollableArea->setCurrentHorizontalSnapPointIndex(horizontalIndex);
667         scrollableArea->setCurrentVerticalSnapPointIndex(verticalIndex);
668     }
669 }
670
671 void AsyncScrollingCoordinator::deferTestsForReason(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::deferTestsForReason: Deferring %p for reason %d.", identifier, reason);
679         trigger->deferTestsForReason(identifier, reason);
680     }
681 }
682
683 void AsyncScrollingCoordinator::removeTestDeferralForReason(WheelEventTestTrigger::ScrollableAreaIdentifier identifier, WheelEventTestTrigger::DeferTestTriggerReason reason) const
684 {
685     ASSERT(isMainThread());
686     if (!m_page || !m_page->expectsWheelEventTriggers())
687         return;
688
689     if (const auto& trigger = m_page->testTrigger()) {
690         LOG(WheelEventTestTriggers, "    (!) AsyncScrollingCoordinator::removeTestDeferralForReason: Deferring %p for reason %d.", identifier, reason);
691         trigger->removeTestDeferralForReason(identifier, reason);
692     }
693 }
694 #endif
695
696 #if ENABLE(CSS_SCROLL_SNAP)
697 bool AsyncScrollingCoordinator::isScrollSnapInProgress() const
698 {
699     return scrollingTree()->isScrollSnapInProgress();
700 }
701
702 void AsyncScrollingCoordinator::updateScrollSnapPropertiesWithFrameView(const FrameView& frameView)
703 {
704     if (auto node = downcast<ScrollingStateFrameScrollingNode>(m_scrollingStateTree->stateNodeForID(frameView.scrollLayerID()))) {
705         setStateScrollingNodeSnapOffsetsAsFloat(*node, ScrollEventAxis::Horizontal, frameView.horizontalSnapOffsets(), frameView.horizontalSnapOffsetRanges(), m_page->deviceScaleFactor());
706         setStateScrollingNodeSnapOffsetsAsFloat(*node, ScrollEventAxis::Vertical, frameView.verticalSnapOffsets(), frameView.verticalSnapOffsetRanges(), m_page->deviceScaleFactor());
707         node->setCurrentHorizontalSnapPointIndex(frameView.currentHorizontalSnapPointIndex());
708         node->setCurrentVerticalSnapPointIndex(frameView.currentVerticalSnapPointIndex());
709     }
710 }
711 #endif
712
713 void AsyncScrollingCoordinator::reportExposedUnfilledArea(MonotonicTime timestamp, unsigned unfilledArea)
714 {
715     if (m_page && m_page->performanceLoggingClient())
716         m_page->performanceLoggingClient()->logScrollingEvent(PerformanceLoggingClient::ScrollingEvent::ExposedTilelessArea, timestamp, unfilledArea);
717 }
718
719 void AsyncScrollingCoordinator::reportSynchronousScrollingReasonsChanged(MonotonicTime timestamp, SynchronousScrollingReasons reasons)
720 {
721     if (m_page && m_page->performanceLoggingClient())
722         m_page->performanceLoggingClient()->logScrollingEvent(PerformanceLoggingClient::ScrollingEvent::SwitchedScrollingMode, timestamp, reasons);
723 }
724
725 } // namespace WebCore
726
727 #endif // ENABLE(ASYNC_SCROLLING)