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