[iOS WK2] REGRESSION (r242687): Programmatic scroll of overflow scroll results in...
[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 "ScrollingStateFrameHostingNode.h"
44 #include "ScrollingStateFrameScrollingNode.h"
45 #include "ScrollingStateOverflowScrollingNode.h"
46 #include "ScrollingStatePositionedNode.h"
47 #include "ScrollingStateStickyNode.h"
48 #include "ScrollingStateTree.h"
49 #include "Settings.h"
50 #include "WheelEventTestTrigger.h"
51 #include <wtf/ProcessID.h>
52 #include <wtf/text/TextStream.h>
53
54 namespace WebCore {
55
56 AsyncScrollingCoordinator::AsyncScrollingCoordinator(Page* page)
57     : ScrollingCoordinator(page)
58     , m_updateNodeScrollPositionTimer(*this, &AsyncScrollingCoordinator::updateScrollPositionAfterAsyncScrollTimerFired)
59     , m_scrollingStateTree(std::make_unique<ScrollingStateTree>(this))
60 {
61 }
62
63 AsyncScrollingCoordinator::~AsyncScrollingCoordinator() = default;
64
65 void AsyncScrollingCoordinator::scrollingStateTreePropertiesChanged()
66 {
67     scheduleTreeStateCommit();
68 }
69
70 #if ENABLE(CSS_SCROLL_SNAP)
71 static inline void setStateScrollingNodeSnapOffsetsAsFloat(ScrollingStateScrollingNode& node, ScrollEventAxis axis, const Vector<LayoutUnit>* snapOffsets, const Vector<ScrollOffsetRange<LayoutUnit>>* snapOffsetRanges, float deviceScaleFactor)
72 {
73     // 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?
74     Vector<float> snapOffsetsAsFloat;
75     if (snapOffsets) {
76         snapOffsetsAsFloat.reserveInitialCapacity(snapOffsets->size());
77         for (auto& offset : *snapOffsets)
78             snapOffsetsAsFloat.uncheckedAppend(roundToDevicePixel(offset, deviceScaleFactor, false));
79     }
80
81     Vector<ScrollOffsetRange<float>> snapOffsetRangesAsFloat;
82     if (snapOffsetRanges) {
83         snapOffsetRangesAsFloat.reserveInitialCapacity(snapOffsetRanges->size());
84         for (auto& range : *snapOffsetRanges)
85             snapOffsetRangesAsFloat.uncheckedAppend({ roundToDevicePixel(range.start, deviceScaleFactor, false), roundToDevicePixel(range.end, deviceScaleFactor, false) });
86     }
87     if (axis == ScrollEventAxis::Horizontal) {
88         node.setHorizontalSnapOffsets(snapOffsetsAsFloat);
89         node.setHorizontalSnapOffsetRanges(snapOffsetRangesAsFloat);
90     } else {
91         node.setVerticalSnapOffsets(snapOffsetsAsFloat);
92         node.setVerticalSnapOffsetRanges(snapOffsetRangesAsFloat);
93     }
94 }
95 #endif
96
97 void AsyncScrollingCoordinator::setEventTrackingRegionsDirty()
98 {
99     m_eventTrackingRegionsDirty = true;
100     // We have to schedule a commit, but the computed non-fast region may not have actually changed.
101     scheduleTreeStateCommit();
102 }
103
104 void AsyncScrollingCoordinator::willCommitTree()
105 {
106     updateEventTrackingRegions();
107 }
108
109 void AsyncScrollingCoordinator::updateEventTrackingRegions()
110 {
111     if (!m_eventTrackingRegionsDirty)
112         return;
113
114     if (!m_scrollingStateTree->rootStateNode())
115         return;
116
117     m_scrollingStateTree->rootStateNode()->setEventTrackingRegions(absoluteEventTrackingRegions());
118     m_eventTrackingRegionsDirty = false;
119 }
120
121 void AsyncScrollingCoordinator::frameViewLayoutUpdated(FrameView& frameView)
122 {
123     ASSERT(isMainThread());
124     ASSERT(m_page);
125
126     // If there isn't a root node yet, don't do anything. We'll be called again after creating one.
127     if (!m_scrollingStateTree->rootStateNode())
128         return;
129
130     setEventTrackingRegionsDirty();
131
132 #if PLATFORM(COCOA)
133     if (!coordinatesScrollingForFrameView(frameView))
134         return;
135
136     auto* page = frameView.frame().page();
137     if (page && page->expectsWheelEventTriggers()) {
138         LOG(WheelEventTestTriggers, "    AsyncScrollingCoordinator::frameViewLayoutUpdated: Expects wheel event test trigger=%d", page->expectsWheelEventTriggers());
139
140         auto* node = m_scrollingStateTree->stateNodeForID(frameView.scrollingNodeID());
141         if (!is<ScrollingStateFrameScrollingNode>(node))
142             return;
143
144         auto& frameScrollingNode = downcast<ScrollingStateFrameScrollingNode>(*node);
145         frameScrollingNode.setExpectsWheelEventTestTrigger(page->expectsWheelEventTriggers());
146     }
147 #else
148     UNUSED_PARAM(frameView);
149 #endif
150 }
151
152 void AsyncScrollingCoordinator::updateExpectsWheelEventTestTriggerWithFrameView(const FrameView& frameView)
153 {
154     auto* page = frameView.frame().page();
155     if (!page)
156         return;
157
158     auto* node = downcast<ScrollingStateFrameScrollingNode>(m_scrollingStateTree->stateNodeForID(frameView.scrollingNodeID()));
159     if (!node)
160         return;
161
162     node->setExpectsWheelEventTestTrigger(page->expectsWheelEventTriggers());
163 }
164
165 void AsyncScrollingCoordinator::frameViewEventTrackingRegionsChanged(FrameView& frameView)
166 {
167     if (!m_scrollingStateTree->rootStateNode())
168         return;
169
170     setEventTrackingRegionsDirty();
171     DebugPageOverlays::didChangeEventHandlers(frameView.frame());
172 }
173
174 void AsyncScrollingCoordinator::frameViewRootLayerDidChange(FrameView& frameView)
175 {
176     ASSERT(isMainThread());
177     ASSERT(m_page);
178
179     if (!coordinatesScrollingForFrameView(frameView))
180         return;
181     
182     // FIXME: In some navigation scenarios, the FrameView has no RenderView or that RenderView has not been composited.
183     // This needs cleaning up: https://bugs.webkit.org/show_bug.cgi?id=132724
184     if (!frameView.scrollingNodeID())
185         return;
186     
187     // If the root layer does not have a ScrollingStateNode, then we should create one.
188     ensureRootStateNodeForFrameView(frameView);
189     ASSERT(m_scrollingStateTree->stateNodeForID(frameView.scrollingNodeID()));
190
191     ScrollingCoordinator::frameViewRootLayerDidChange(frameView);
192
193     auto* node = downcast<ScrollingStateFrameScrollingNode>(m_scrollingStateTree->stateNodeForID(frameView.scrollingNodeID()));
194     node->setScrollContainerLayer(scrollContainerLayerForFrameView(frameView));
195     node->setScrolledContentsLayer(scrolledContentsLayerForFrameView(frameView));
196     node->setRootContentsLayer(rootContentsLayerForFrameView(frameView));
197     node->setCounterScrollingLayer(counterScrollingLayerForFrameView(frameView));
198     node->setInsetClipLayer(insetClipLayerForFrameView(frameView));
199     node->setContentShadowLayer(contentShadowLayerForFrameView(frameView));
200     node->setHeaderLayer(headerLayerForFrameView(frameView));
201     node->setFooterLayer(footerLayerForFrameView(frameView));
202     node->setScrollBehaviorForFixedElements(frameView.scrollBehaviorForFixedElements());
203     node->setVerticalScrollbarLayer(frameView.layerForVerticalScrollbar());
204     node->setHorizontalScrollbarLayer(frameView.layerForHorizontalScrollbar());
205 }
206
207 bool AsyncScrollingCoordinator::requestScrollPositionUpdate(ScrollableArea& scrollableArea, const IntPoint& scrollPosition)
208 {
209     ASSERT(isMainThread());
210     ASSERT(m_page);
211
212     auto scrollingNodeID = scrollableArea.scrollingNodeID();
213     if (!scrollingNodeID)
214         return false;
215
216     auto* frameView = frameViewForScrollingNode(scrollingNodeID);
217     if (!frameView)
218         return false;
219
220     if (!coordinatesScrollingForFrameView(*frameView))
221         return false;
222
223     bool inPageCache = frameView->frame().document()->pageCacheState() != Document::NotInPageCache;
224     bool inProgrammaticScroll = scrollableArea.currentScrollType() == ScrollType::Programmatic;
225     if (inProgrammaticScroll || inPageCache)
226         updateScrollPositionAfterAsyncScroll(scrollingNodeID, scrollPosition, { }, ScrollType::Programmatic, ScrollingLayerPositionAction::Set);
227
228     // If this frame view's document is being put into the page cache, we don't want to update our
229     // main frame scroll position. Just let the FrameView think that we did.
230     if (inPageCache)
231         return true;
232
233     auto* stateNode = downcast<ScrollingStateScrollingNode>(m_scrollingStateTree->stateNodeForID(scrollingNodeID));
234     if (!stateNode)
235         return false;
236
237     stateNode->setRequestedScrollPosition(scrollPosition, inProgrammaticScroll);
238     return true;
239 }
240
241 void AsyncScrollingCoordinator::applyScrollingTreeLayerPositions()
242 {
243     m_scrollingTree->applyLayerPositions();
244 }
245
246 void AsyncScrollingCoordinator::scheduleUpdateScrollPositionAfterAsyncScroll(ScrollingNodeID nodeID, const FloatPoint& scrollPosition, const Optional<FloatPoint>& layoutViewportOrigin, ScrollingLayerPositionAction scrollingLayerPositionAction)
247 {
248     ScheduledScrollUpdate scrollUpdate(nodeID, scrollPosition, layoutViewportOrigin, scrollingLayerPositionAction);
249     
250     if (m_updateNodeScrollPositionTimer.isActive()) {
251         if (m_scheduledScrollUpdate.matchesUpdateType(scrollUpdate)) {
252             m_scheduledScrollUpdate.scrollPosition = scrollPosition;
253             m_scheduledScrollUpdate.layoutViewportOrigin = layoutViewportOrigin;
254             return;
255         }
256     
257         // If the parameters don't match what was previously scheduled, dispatch immediately.
258         m_updateNodeScrollPositionTimer.stop();
259         updateScrollPositionAfterAsyncScroll(m_scheduledScrollUpdate.nodeID, m_scheduledScrollUpdate.scrollPosition, m_scheduledScrollUpdate.layoutViewportOrigin, ScrollType::User, m_scheduledScrollUpdate.updateLayerPositionAction);
260         updateScrollPositionAfterAsyncScroll(nodeID, scrollPosition, layoutViewportOrigin, ScrollType::User, scrollingLayerPositionAction);
261         return;
262     }
263
264     m_scheduledScrollUpdate = scrollUpdate;
265     m_updateNodeScrollPositionTimer.startOneShot(0_s);
266 }
267
268 void AsyncScrollingCoordinator::updateScrollPositionAfterAsyncScrollTimerFired()
269 {
270     updateScrollPositionAfterAsyncScroll(m_scheduledScrollUpdate.nodeID, m_scheduledScrollUpdate.scrollPosition, m_scheduledScrollUpdate.layoutViewportOrigin, ScrollType::User, m_scheduledScrollUpdate.updateLayerPositionAction);
271 }
272
273 FrameView* AsyncScrollingCoordinator::frameViewForScrollingNode(ScrollingNodeID scrollingNodeID) const
274 {
275     if (!m_scrollingStateTree->rootStateNode())
276         return nullptr;
277     
278     if (scrollingNodeID == m_scrollingStateTree->rootStateNode()->scrollingNodeID())
279         return m_page->mainFrame().view();
280
281     auto* stateNode = m_scrollingStateTree->stateNodeForID(scrollingNodeID);
282     if (!stateNode)
283         return nullptr;
284
285     // Find the enclosing frame scrolling node.
286     auto* parentNode = stateNode;
287     while (parentNode && !parentNode->isFrameScrollingNode())
288         parentNode = parentNode->parent();
289     
290     if (!parentNode)
291         return nullptr;
292     
293     // Walk the frame tree to find the matching FrameView. This is not ideal, but avoids back pointers to FrameViews
294     // from ScrollingTreeStateNodes.
295     for (Frame* frame = &m_page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
296         if (auto* view = frame->view()) {
297             if (view->scrollingNodeID() == parentNode->scrollingNodeID())
298                 return view;
299         }
300     }
301
302     return nullptr;
303 }
304
305 void AsyncScrollingCoordinator::updateScrollPositionAfterAsyncScroll(ScrollingNodeID scrollingNodeID, const FloatPoint& scrollPosition, Optional<FloatPoint> layoutViewportOrigin, ScrollType scrollType, ScrollingLayerPositionAction scrollingLayerPositionAction)
306 {
307     ASSERT(isMainThread());
308
309     if (!m_page)
310         return;
311
312     auto* frameViewPtr = frameViewForScrollingNode(scrollingNodeID);
313     if (!frameViewPtr)
314         return;
315
316     LOG_WITH_STREAM(Scrolling, stream << "AsyncScrollingCoordinator::updateScrollPositionAfterAsyncScroll node " << scrollingNodeID << " scrollPosition " << scrollPosition << " action " << scrollingLayerPositionAction);
317
318     auto& frameView = *frameViewPtr;
319
320     if (scrollingNodeID == frameView.scrollingNodeID()) {
321         reconcileScrollingState(frameView, scrollPosition, layoutViewportOrigin, scrollType, ViewportRectStability::Stable, scrollingLayerPositionAction);
322
323 #if PLATFORM(COCOA)
324         if (m_page->expectsWheelEventTriggers()) {
325             frameView.scrollAnimator().setWheelEventTestTrigger(m_page->testTrigger());
326             if (const auto& trigger = m_page->testTrigger())
327                 trigger->removeTestDeferralForReason(reinterpret_cast<WheelEventTestTrigger::ScrollableAreaIdentifier>(scrollingNodeID), WheelEventTestTrigger::ScrollingThreadSyncNeeded);
328         }
329 #endif
330         
331         return;
332     }
333
334     // Overflow-scroll area.
335     if (auto* scrollableArea = frameView.scrollableAreaForScrollLayerID(scrollingNodeID)) {
336         auto previousScrollType = scrollableArea->currentScrollType();
337         scrollableArea->setCurrentScrollType(scrollType);
338         scrollableArea->scrollToOffsetWithoutAnimation(scrollPosition);
339         scrollableArea->setCurrentScrollType(previousScrollType);
340
341         if (scrollingLayerPositionAction == ScrollingLayerPositionAction::Set)
342             m_page->editorClient().overflowScrollPositionChanged();
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 }
353
354 void AsyncScrollingCoordinator::reconcileScrollingState(FrameView& frameView, const FloatPoint& scrollPosition, const LayoutViewportOriginOrOverrideRect& layoutViewportOriginOrOverrideRect, ScrollType scrollType, ViewportRectStability viewportRectStability, ScrollingLayerPositionAction scrollingLayerPositionAction)
355 {
356     auto previousScrollType = frameView.currentScrollType();
357     frameView.setCurrentScrollType(scrollType);
358
359     LOG_WITH_STREAM(Scrolling, stream << getCurrentProcessID() << " AsyncScrollingCoordinator " << this << " reconcileScrollingState scrollPosition " << scrollPosition << " type " << scrollType << " stability " << viewportRectStability << " " << scrollingLayerPositionAction);
360
361     Optional<FloatRect> layoutViewportRect;
362
363     WTF::switchOn(layoutViewportOriginOrOverrideRect,
364         [&frameView](Optional<FloatPoint> origin) {
365             if (origin)
366                 frameView.setBaseLayoutViewportOrigin(LayoutPoint(origin.value()), FrameView::TriggerLayoutOrNot::No);
367         }, [&frameView, &layoutViewportRect, viewportRectStability](Optional<FloatRect> overrideRect) {
368             if (!overrideRect)
369                 return;
370
371             layoutViewportRect = overrideRect;
372             if (viewportRectStability != ViewportRectStability::ChangingObscuredInsetsInteractively)
373                 frameView.setLayoutViewportOverrideRect(LayoutRect(overrideRect.value()), viewportRectStability == ViewportRectStability::Stable ? FrameView::TriggerLayoutOrNot::Yes : FrameView::TriggerLayoutOrNot::No);
374         }
375     );
376
377     frameView.setConstrainsScrollingToContentEdge(false);
378     frameView.notifyScrollPositionChanged(roundedIntPoint(scrollPosition));
379     frameView.setConstrainsScrollingToContentEdge(true);
380
381     frameView.setCurrentScrollType(previousScrollType);
382
383     if (scrollType == ScrollType::User && scrollingLayerPositionAction != ScrollingLayerPositionAction::Set) {
384         auto scrollingNodeID = frameView.scrollingNodeID();
385         if (viewportRectStability == ViewportRectStability::Stable)
386             reconcileViewportConstrainedLayerPositions(scrollingNodeID, frameView.rectForFixedPositionLayout(), scrollingLayerPositionAction);
387         else if (layoutViewportRect)
388             reconcileViewportConstrainedLayerPositions(scrollingNodeID, LayoutRect(layoutViewportRect.value()), scrollingLayerPositionAction);
389     }
390
391     if (!scrolledContentsLayerForFrameView(frameView))
392         return;
393
394     auto* counterScrollingLayer = counterScrollingLayerForFrameView(frameView);
395     auto* insetClipLayer = insetClipLayerForFrameView(frameView);
396     auto* contentShadowLayer = contentShadowLayerForFrameView(frameView);
397     auto* rootContentsLayer = rootContentsLayerForFrameView(frameView);
398     auto* headerLayer = headerLayerForFrameView(frameView);
399     auto* footerLayer = footerLayerForFrameView(frameView);
400
401     ASSERT(frameView.scrollPosition() == roundedIntPoint(scrollPosition));
402     LayoutPoint scrollPositionForFixed = frameView.scrollPositionForFixedPosition();
403     float topContentInset = frameView.topContentInset();
404
405     FloatPoint positionForInsetClipLayer;
406     if (insetClipLayer)
407         positionForInsetClipLayer = FloatPoint(insetClipLayer->position().x(), FrameView::yPositionForInsetClipLayer(scrollPosition, topContentInset));
408     FloatPoint positionForContentsLayer = frameView.positionForRootContentLayer();
409     
410     FloatPoint positionForHeaderLayer = FloatPoint(scrollPositionForFixed.x(), FrameView::yPositionForHeaderLayer(scrollPosition, topContentInset));
411     FloatPoint positionForFooterLayer = FloatPoint(scrollPositionForFixed.x(),
412         FrameView::yPositionForFooterLayer(scrollPosition, topContentInset, frameView.totalContentsSize().height(), frameView.footerHeight()));
413
414     if (scrollType == ScrollType::Programmatic || scrollingLayerPositionAction == ScrollingLayerPositionAction::Set) {
415         reconcileScrollPosition(frameView, ScrollingLayerPositionAction::Set);
416
417         if (counterScrollingLayer)
418             counterScrollingLayer->setPosition(scrollPositionForFixed);
419         if (insetClipLayer)
420             insetClipLayer->setPosition(positionForInsetClipLayer);
421         if (contentShadowLayer)
422             contentShadowLayer->setPosition(positionForContentsLayer);
423         if (rootContentsLayer)
424             rootContentsLayer->setPosition(positionForContentsLayer);
425         if (headerLayer)
426             headerLayer->setPosition(positionForHeaderLayer);
427         if (footerLayer)
428             footerLayer->setPosition(positionForFooterLayer);
429     } else {
430         reconcileScrollPosition(frameView, ScrollingLayerPositionAction::Sync);
431
432         if (counterScrollingLayer)
433             counterScrollingLayer->syncPosition(scrollPositionForFixed);
434         if (insetClipLayer)
435             insetClipLayer->syncPosition(positionForInsetClipLayer);
436         if (contentShadowLayer)
437             contentShadowLayer->syncPosition(positionForContentsLayer);
438         if (rootContentsLayer)
439             rootContentsLayer->syncPosition(positionForContentsLayer);
440         if (headerLayer)
441             headerLayer->syncPosition(positionForHeaderLayer);
442         if (footerLayer)
443             footerLayer->syncPosition(positionForFooterLayer);
444     }
445 }
446
447 void AsyncScrollingCoordinator::reconcileScrollPosition(FrameView& frameView, ScrollingLayerPositionAction scrollingLayerPositionAction)
448 {
449 #if PLATFORM(IOS_FAMILY)
450     // Doing all scrolling like this (UIScrollView style) would simplify code.
451     auto* scrollContainerLayer = scrollContainerLayerForFrameView(frameView);
452     if (!scrollContainerLayer)
453         return;
454     if (scrollingLayerPositionAction == ScrollingLayerPositionAction::Set)
455         scrollContainerLayer->setBoundsOrigin(frameView.scrollPosition());
456     else
457         scrollContainerLayer->syncBoundsOrigin(frameView.scrollPosition());
458 #else
459     auto* scrolledContentsLayer = scrolledContentsLayerForFrameView(frameView);
460     if (!scrolledContentsLayer)
461         return;
462     if (scrollingLayerPositionAction == ScrollingLayerPositionAction::Set)
463         scrolledContentsLayer->setPosition(-frameView.scrollPosition());
464     else
465         scrolledContentsLayer->syncPosition(-frameView.scrollPosition());
466 #endif
467 }
468
469 void AsyncScrollingCoordinator::scrollableAreaScrollbarLayerDidChange(ScrollableArea& scrollableArea, ScrollbarOrientation orientation)
470 {
471     ASSERT(isMainThread());
472     ASSERT(m_page);
473
474     auto* node = m_scrollingStateTree->stateNodeForID(scrollableArea.scrollingNodeID());
475     if (is<ScrollingStateScrollingNode>(node)) {
476         auto& scrollingNode = downcast<ScrollingStateScrollingNode>(*node);
477         if (orientation == VerticalScrollbar)
478             scrollingNode.setVerticalScrollbarLayer(scrollableArea.layerForVerticalScrollbar());
479         else
480             scrollingNode.setHorizontalScrollbarLayer(scrollableArea.layerForHorizontalScrollbar());
481     }
482
483     if (orientation == VerticalScrollbar)
484         scrollableArea.verticalScrollbarLayerDidChange();
485     else
486         scrollableArea.horizontalScrollbarLayerDidChange();
487 }
488
489 ScrollingNodeID AsyncScrollingCoordinator::createNode(ScrollingNodeType nodeType, ScrollingNodeID newNodeID)
490 {
491     LOG_WITH_STREAM(Scrolling, stream << "AsyncScrollingCoordinator::createNode " << nodeType << " node " << newNodeID);
492     return m_scrollingStateTree->createUnparentedNode(nodeType, newNodeID);
493 }
494
495 ScrollingNodeID AsyncScrollingCoordinator::insertNode(ScrollingNodeType nodeType, ScrollingNodeID newNodeID, ScrollingNodeID parentID, size_t childIndex)
496 {
497     LOG_WITH_STREAM(Scrolling, stream << "AsyncScrollingCoordinator::insertNode " << nodeType << " node " << newNodeID << " parent " << parentID << " index " << childIndex);
498     return m_scrollingStateTree->insertNode(nodeType, newNodeID, parentID, childIndex);
499 }
500
501 void AsyncScrollingCoordinator::unparentNode(ScrollingNodeID nodeID)
502 {
503     m_scrollingStateTree->unparentNode(nodeID);
504 }
505
506 void AsyncScrollingCoordinator::unparentChildrenAndDestroyNode(ScrollingNodeID nodeID)
507 {
508     m_scrollingStateTree->unparentChildrenAndDestroyNode(nodeID);
509 }
510
511 void AsyncScrollingCoordinator::detachAndDestroySubtree(ScrollingNodeID nodeID)
512 {
513     m_scrollingStateTree->detachAndDestroySubtree(nodeID);
514 }
515
516 void AsyncScrollingCoordinator::clearAllNodes()
517 {
518     m_scrollingStateTree->clear();
519 }
520
521 ScrollingNodeID AsyncScrollingCoordinator::parentOfNode(ScrollingNodeID nodeID) const
522 {
523     auto* scrollingNode = m_scrollingStateTree->stateNodeForID(nodeID);
524     if (!scrollingNode)
525         return 0;
526
527     return scrollingNode->parentNodeID();
528 }
529
530 Vector<ScrollingNodeID> AsyncScrollingCoordinator::childrenOfNode(ScrollingNodeID nodeID) const
531 {
532     auto* scrollingNode = m_scrollingStateTree->stateNodeForID(nodeID);
533     if (!scrollingNode)
534         return { };
535
536     auto* children = scrollingNode->children();
537     if (!children || children->isEmpty())
538         return { };
539     
540     Vector<ScrollingNodeID> childNodeIDs;
541     childNodeIDs.reserveInitialCapacity(children->size());
542     for (const auto& childNode : *children)
543         childNodeIDs.uncheckedAppend(childNode->scrollingNodeID());
544
545     return childNodeIDs;
546 }
547
548 void AsyncScrollingCoordinator::reconcileViewportConstrainedLayerPositions(ScrollingNodeID scrollingNodeID, const LayoutRect& viewportRect, ScrollingLayerPositionAction action)
549 {
550     LOG_WITH_STREAM(Scrolling, stream << getCurrentProcessID() << " AsyncScrollingCoordinator::reconcileViewportConstrainedLayerPositions for viewport rect " << viewportRect << " and node " << scrollingNodeID);
551
552     m_scrollingStateTree->reconcileViewportConstrainedLayerPositions(scrollingNodeID, viewportRect, action);
553 }
554
555 void AsyncScrollingCoordinator::ensureRootStateNodeForFrameView(FrameView& frameView)
556 {
557     ASSERT(frameView.scrollingNodeID());
558     if (m_scrollingStateTree->stateNodeForID(frameView.scrollingNodeID()))
559         return;
560
561     // For non-main frames, it is only possible to arrive in this function from
562     // RenderLayerCompositor::updateBacking where the node has already been created.
563     ASSERT(frameView.frame().isMainFrame());
564     insertNode(ScrollingNodeType::MainFrame, frameView.scrollingNodeID(), 0, 0);
565 }
566
567 void AsyncScrollingCoordinator::setNodeLayers(ScrollingNodeID nodeID, const NodeLayers& nodeLayers)
568 {
569     auto* node = m_scrollingStateTree->stateNodeForID(nodeID);
570     ASSERT(node);
571     if (!node)
572         return;
573
574     node->setLayer(nodeLayers.layer);
575
576     if (is<ScrollingStateScrollingNode>(node)) {
577         auto& scrollingNode = downcast<ScrollingStateScrollingNode>(*node);
578         scrollingNode.setScrollContainerLayer(nodeLayers.scrollContainerLayer);
579         scrollingNode.setScrolledContentsLayer(nodeLayers.scrolledContentsLayer);
580         scrollingNode.setHorizontalScrollbarLayer(nodeLayers.horizontalScrollbarLayer);
581         scrollingNode.setVerticalScrollbarLayer(nodeLayers.verticalScrollbarLayer);
582
583         if (is<ScrollingStateFrameScrollingNode>(node)) {
584             auto& frameScrollingNode = downcast<ScrollingStateFrameScrollingNode>(*node);
585             frameScrollingNode.setInsetClipLayer(nodeLayers.insetClipLayer);
586             frameScrollingNode.setCounterScrollingLayer(nodeLayers.counterScrollingLayer);
587             frameScrollingNode.setRootContentsLayer(nodeLayers.rootContentsLayer);
588         }
589     }
590 }
591
592 void AsyncScrollingCoordinator::setRectRelativeToParentNode(ScrollingNodeID nodeID, const LayoutRect& parentRelativeScrollableRect)
593 {
594     auto* stateNode = m_scrollingStateTree->stateNodeForID(nodeID);
595     ASSERT(stateNode);
596     if (!stateNode)
597         return;
598
599     if (is<ScrollingStateFrameHostingNode>(*stateNode)) {
600         auto& frameHostingStateNode = downcast<ScrollingStateFrameHostingNode>(*stateNode);
601         frameHostingStateNode.setParentRelativeScrollableRect(parentRelativeScrollableRect);
602         return;
603     }
604
605     if (is<ScrollingStateScrollingNode>(stateNode)) {
606         auto& scrollingStateNode = downcast<ScrollingStateScrollingNode>(*stateNode);
607         scrollingStateNode.setParentRelativeScrollableRect(parentRelativeScrollableRect);
608     }
609 }
610
611 void AsyncScrollingCoordinator::setFrameScrollingNodeState(ScrollingNodeID nodeID, const FrameView& frameView)
612 {
613     auto* stateNode = m_scrollingStateTree->stateNodeForID(nodeID);
614     ASSERT(stateNode);
615     if (!is<ScrollingStateFrameScrollingNode>(stateNode))
616         return;
617
618     auto& frameScrollingNode = downcast<ScrollingStateFrameScrollingNode>(*stateNode);
619
620     frameScrollingNode.setFrameScaleFactor(frameView.frame().frameScaleFactor());
621     frameScrollingNode.setHeaderHeight(frameView.headerHeight());
622     frameScrollingNode.setFooterHeight(frameView.footerHeight());
623     frameScrollingNode.setTopContentInset(frameView.topContentInset());
624     frameScrollingNode.setLayoutViewport(frameView.layoutViewportRect());
625     frameScrollingNode.setAsyncFrameOrOverflowScrollingEnabled(asyncFrameOrOverflowScrollingEnabled());
626
627     frameScrollingNode.setMinLayoutViewportOrigin(frameView.minStableLayoutViewportOrigin());
628     frameScrollingNode.setMaxLayoutViewportOrigin(frameView.maxStableLayoutViewportOrigin());
629
630     frameScrollingNode.setFixedElementsLayoutRelativeToFrame(frameView.fixedElementsLayoutRelativeToFrame());
631     frameScrollingNode.setScrollBehaviorForFixedElements(frameView.scrollBehaviorForFixedElements());
632 }
633
634 void AsyncScrollingCoordinator::setScrollingNodeScrollableAreaGeometry(ScrollingNodeID nodeID, ScrollableArea& scrollableArea)
635 {
636     auto* stateNode = m_scrollingStateTree->stateNodeForID(nodeID);
637     ASSERT(stateNode);
638     if (!stateNode)
639         return;
640
641     auto& scrollingNode = downcast<ScrollingStateScrollingNode>(*stateNode);
642
643     auto* verticalScrollbar = scrollableArea.verticalScrollbar();
644     auto* horizontalScrollbar = scrollableArea.horizontalScrollbar();
645     scrollingNode.setScrollerImpsFromScrollbars(verticalScrollbar, horizontalScrollbar);
646
647     scrollingNode.setScrollOrigin(scrollableArea.scrollOrigin());
648     scrollingNode.setScrollPosition(scrollableArea.scrollPosition());
649     scrollingNode.setTotalContentsSize(scrollableArea.totalContentsSize());
650     scrollingNode.setReachableContentsSize(scrollableArea.reachableTotalContentsSize());
651     scrollingNode.setScrollableAreaSize(scrollableArea.visibleSize());
652
653     ScrollableAreaParameters scrollParameters;
654     scrollParameters.horizontalScrollElasticity = scrollableArea.horizontalScrollElasticity();
655     scrollParameters.verticalScrollElasticity = scrollableArea.verticalScrollElasticity();
656     scrollParameters.hasEnabledHorizontalScrollbar = horizontalScrollbar && horizontalScrollbar->enabled();
657     scrollParameters.hasEnabledVerticalScrollbar = verticalScrollbar && verticalScrollbar->enabled();
658     scrollParameters.horizontalScrollbarMode = scrollableArea.horizontalScrollbarMode();
659     scrollParameters.verticalScrollbarMode = scrollableArea.verticalScrollbarMode();
660     scrollParameters.horizontalScrollbarHiddenByStyle = scrollableArea.horizontalScrollbarHiddenByStyle();
661     scrollParameters.verticalScrollbarHiddenByStyle = scrollableArea.verticalScrollbarHiddenByStyle();
662     scrollParameters.useDarkAppearanceForScrollbars = scrollableArea.useDarkAppearanceForScrollbars();
663
664     scrollingNode.setScrollableAreaParameters(scrollParameters);
665
666 #if ENABLE(CSS_SCROLL_SNAP)
667     scrollableArea.updateSnapOffsets();
668     setStateScrollingNodeSnapOffsetsAsFloat(scrollingNode, ScrollEventAxis::Horizontal, scrollableArea.horizontalSnapOffsets(), scrollableArea.horizontalSnapOffsetRanges(), m_page->deviceScaleFactor());
669     setStateScrollingNodeSnapOffsetsAsFloat(scrollingNode, ScrollEventAxis::Vertical, scrollableArea.verticalSnapOffsets(), scrollableArea.verticalSnapOffsetRanges(), m_page->deviceScaleFactor());
670     scrollingNode.setCurrentHorizontalSnapPointIndex(scrollableArea.currentHorizontalSnapPointIndex());
671     scrollingNode.setCurrentVerticalSnapPointIndex(scrollableArea.currentVerticalSnapPointIndex());
672 #endif
673 }
674
675 void AsyncScrollingCoordinator::setViewportConstraintedNodeConstraints(ScrollingNodeID nodeID, const ViewportConstraints& constraints)
676 {
677     auto* node = m_scrollingStateTree->stateNodeForID(nodeID);
678     if (!node)
679         return;
680
681     switch (constraints.constraintType()) {
682     case ViewportConstraints::FixedPositionConstraint: {
683         auto& fixedNode = downcast<ScrollingStateFixedNode>(*node);
684         fixedNode.updateConstraints((const FixedPositionViewportConstraints&)constraints);
685         break;
686     }
687     case ViewportConstraints::StickyPositionConstraint: {
688         auto& stickyNode = downcast<ScrollingStateStickyNode>(*node);
689         stickyNode.updateConstraints((const StickyPositionViewportConstraints&)constraints);
690         break;
691     }
692     }
693 }
694
695 void AsyncScrollingCoordinator::setPositionedNodeGeometry(ScrollingNodeID nodeID, const LayoutConstraints& constraints)
696 {
697     auto* node = m_scrollingStateTree->stateNodeForID(nodeID);
698     if (!node)
699         return;
700
701     ASSERT(is<ScrollingStatePositionedNode>(*node));
702     if (auto* positionedNode = downcast<ScrollingStatePositionedNode>(node))
703         positionedNode->updateConstraints(constraints);
704 }
705
706 void AsyncScrollingCoordinator::setRelatedOverflowScrollingNodes(ScrollingNodeID nodeID, Vector<ScrollingNodeID>&& relatedNodes)
707 {
708     auto* node = m_scrollingStateTree->stateNodeForID(nodeID);
709     if (!node)
710         return;
711
712     ASSERT(is<ScrollingStatePositionedNode>(*node));
713     if (auto* positionedNode = downcast<ScrollingStatePositionedNode>(node))
714         positionedNode->setRelatedOverflowScrollingNodes(WTFMove(relatedNodes));
715 }
716
717 void AsyncScrollingCoordinator::setSynchronousScrollingReasons(FrameView& frameView, SynchronousScrollingReasons reasons)
718 {
719     auto* scrollingStateNode = static_cast<ScrollingStateFrameScrollingNode*>(m_scrollingStateTree->stateNodeForID(frameView.scrollingNodeID()));
720     if (!scrollingStateNode)
721         return;
722
723     // The FrameView's GraphicsLayer is likely to be out-of-synch with the PlatformLayer
724     // at this point. So we'll update it before we switch back to main thread scrolling
725     // in order to avoid layer positioning bugs.
726     if (reasons)
727         reconcileScrollPosition(frameView, ScrollingLayerPositionAction::Set);
728     scrollingStateNode->setSynchronousScrollingReasons(reasons);
729 }
730
731 bool AsyncScrollingCoordinator::isRubberBandInProgress() const
732 {
733     return scrollingTree()->isRubberBandInProgress();
734 }
735
736 void AsyncScrollingCoordinator::setScrollPinningBehavior(ScrollPinningBehavior pinning)
737 {
738     scrollingTree()->setScrollPinningBehavior(pinning);
739 }
740
741 bool AsyncScrollingCoordinator::asyncFrameOrOverflowScrollingEnabled() const
742 {
743     auto& settings = m_page->mainFrame().settings();
744     return settings.asyncFrameScrollingEnabled() || settings.asyncOverflowScrollingEnabled();
745 }
746
747 String AsyncScrollingCoordinator::scrollingStateTreeAsText(ScrollingStateTreeAsTextBehavior behavior) const
748 {
749     if (m_scrollingStateTree->rootStateNode()) {
750         if (m_eventTrackingRegionsDirty)
751             m_scrollingStateTree->rootStateNode()->setEventTrackingRegions(absoluteEventTrackingRegions());
752         return m_scrollingStateTree->rootStateNode()->scrollingStateTreeAsText(behavior);
753     }
754
755     return String();
756 }
757
758 #if PLATFORM(COCOA)
759 void AsyncScrollingCoordinator::setActiveScrollSnapIndices(ScrollingNodeID scrollingNodeID, unsigned horizontalIndex, unsigned verticalIndex)
760 {
761     ASSERT(isMainThread());
762     
763     if (!m_page)
764         return;
765     
766     auto* frameView = frameViewForScrollingNode(scrollingNodeID);
767     if (!frameView)
768         return;
769     
770     if (scrollingNodeID == frameView->scrollingNodeID()) {
771         frameView->setCurrentHorizontalSnapPointIndex(horizontalIndex);
772         frameView->setCurrentVerticalSnapPointIndex(verticalIndex);
773         return;
774     }
775     
776     // Overflow-scroll area.
777     if (auto* scrollableArea = frameView->scrollableAreaForScrollLayerID(scrollingNodeID)) {
778         scrollableArea->setCurrentHorizontalSnapPointIndex(horizontalIndex);
779         scrollableArea->setCurrentVerticalSnapPointIndex(verticalIndex);
780     }
781 }
782
783 void AsyncScrollingCoordinator::deferTestsForReason(WheelEventTestTrigger::ScrollableAreaIdentifier identifier, WheelEventTestTrigger::DeferTestTriggerReason reason) const
784 {
785     ASSERT(isMainThread());
786     if (!m_page || !m_page->expectsWheelEventTriggers())
787         return;
788
789     if (const auto& trigger = m_page->testTrigger()) {
790         LOG(WheelEventTestTriggers, "    (!) AsyncScrollingCoordinator::deferTestsForReason: Deferring %p for reason %d.", identifier, reason);
791         trigger->deferTestsForReason(identifier, reason);
792     }
793 }
794
795 void AsyncScrollingCoordinator::removeTestDeferralForReason(WheelEventTestTrigger::ScrollableAreaIdentifier identifier, WheelEventTestTrigger::DeferTestTriggerReason reason) const
796 {
797     ASSERT(isMainThread());
798     if (!m_page || !m_page->expectsWheelEventTriggers())
799         return;
800
801     if (const auto& trigger = m_page->testTrigger()) {
802         LOG(WheelEventTestTriggers, "    (!) AsyncScrollingCoordinator::removeTestDeferralForReason: Deferring %p for reason %d.", identifier, reason);
803         trigger->removeTestDeferralForReason(identifier, reason);
804     }
805 }
806 #endif
807
808 #if ENABLE(CSS_SCROLL_SNAP)
809 bool AsyncScrollingCoordinator::isScrollSnapInProgress() const
810 {
811     return scrollingTree()->isScrollSnapInProgress();
812 }
813
814 void AsyncScrollingCoordinator::updateScrollSnapPropertiesWithFrameView(const FrameView& frameView)
815 {
816     if (auto node = downcast<ScrollingStateFrameScrollingNode>(m_scrollingStateTree->stateNodeForID(frameView.scrollingNodeID()))) {
817         setStateScrollingNodeSnapOffsetsAsFloat(*node, ScrollEventAxis::Horizontal, frameView.horizontalSnapOffsets(), frameView.horizontalSnapOffsetRanges(), m_page->deviceScaleFactor());
818         setStateScrollingNodeSnapOffsetsAsFloat(*node, ScrollEventAxis::Vertical, frameView.verticalSnapOffsets(), frameView.verticalSnapOffsetRanges(), m_page->deviceScaleFactor());
819         node->setCurrentHorizontalSnapPointIndex(frameView.currentHorizontalSnapPointIndex());
820         node->setCurrentVerticalSnapPointIndex(frameView.currentVerticalSnapPointIndex());
821     }
822 }
823 #endif
824
825 void AsyncScrollingCoordinator::reportExposedUnfilledArea(MonotonicTime timestamp, unsigned unfilledArea)
826 {
827     if (m_page && m_page->performanceLoggingClient())
828         m_page->performanceLoggingClient()->logScrollingEvent(PerformanceLoggingClient::ScrollingEvent::ExposedTilelessArea, timestamp, unfilledArea);
829 }
830
831 void AsyncScrollingCoordinator::reportSynchronousScrollingReasonsChanged(MonotonicTime timestamp, SynchronousScrollingReasons reasons)
832 {
833     if (m_page && m_page->performanceLoggingClient())
834         m_page->performanceLoggingClient()->logScrollingEvent(PerformanceLoggingClient::ScrollingEvent::SwitchedScrollingMode, timestamp, reasons);
835 }
836
837 } // namespace WebCore
838
839 #endif // ENABLE(ASYNC_SCROLLING)