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