summaryrefslogtreecommitdiff
path: root/Source/WebCore/page/scrolling
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/page/scrolling
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebCore/page/scrolling')
-rw-r--r--Source/WebCore/page/scrolling/AsyncScrollingCoordinator.cpp707
-rw-r--r--Source/WebCore/page/scrolling/AsyncScrollingCoordinator.h170
-rw-r--r--Source/WebCore/page/scrolling/AxisScrollSnapOffsets.cpp346
-rw-r--r--Source/WebCore/page/scrolling/AxisScrollSnapOffsets.h50
-rw-r--r--Source/WebCore/page/scrolling/ScrollLatchingState.cpp70
-rw-r--r--Source/WebCore/page/scrolling/ScrollLatchingState.h70
-rw-r--r--Source/WebCore/page/scrolling/ScrollSnapOffsetsInfo.h51
-rw-r--r--Source/WebCore/page/scrolling/ScrollingConstraints.cpp18
-rw-r--r--Source/WebCore/page/scrolling/ScrollingConstraints.h21
-rw-r--r--Source/WebCore/page/scrolling/ScrollingCoordinator.cpp345
-rw-r--r--Source/WebCore/page/scrolling/ScrollingCoordinator.h146
-rw-r--r--Source/WebCore/page/scrolling/ScrollingMomentumCalculator.cpp235
-rw-r--r--Source/WebCore/page/scrolling/ScrollingMomentumCalculator.h90
-rw-r--r--Source/WebCore/page/scrolling/ScrollingStateFixedNode.cpp35
-rw-r--r--Source/WebCore/page/scrolling/ScrollingStateFixedNode.h19
-rw-r--r--Source/WebCore/page/scrolling/ScrollingStateFrameScrollingNode.cpp329
-rw-r--r--Source/WebCore/page/scrolling/ScrollingStateFrameScrollingNode.h177
-rw-r--r--Source/WebCore/page/scrolling/ScrollingStateNode.cpp72
-rw-r--r--Source/WebCore/page/scrolling/ScrollingStateNode.h107
-rw-r--r--Source/WebCore/page/scrolling/ScrollingStateOverflowScrollingNode.cpp85
-rw-r--r--Source/WebCore/page/scrolling/ScrollingStateOverflowScrollingNode.h63
-rw-r--r--Source/WebCore/page/scrolling/ScrollingStateScrollingNode.cpp220
-rw-r--r--Source/WebCore/page/scrolling/ScrollingStateScrollingNode.h163
-rw-r--r--Source/WebCore/page/scrolling/ScrollingStateStickyNode.cpp152
-rw-r--r--Source/WebCore/page/scrolling/ScrollingStateStickyNode.h69
-rw-r--r--Source/WebCore/page/scrolling/ScrollingStateTree.cpp191
-rw-r--r--Source/WebCore/page/scrolling/ScrollingStateTree.h56
-rw-r--r--Source/WebCore/page/scrolling/ScrollingThread.cpp120
-rw-r--r--Source/WebCore/page/scrolling/ScrollingThread.h93
-rw-r--r--Source/WebCore/page/scrolling/ScrollingTree.cpp410
-rw-r--r--Source/WebCore/page/scrolling/ScrollingTree.h200
-rw-r--r--Source/WebCore/page/scrolling/ScrollingTreeFrameScrollingNode.cpp157
-rw-r--r--Source/WebCore/page/scrolling/ScrollingTreeFrameScrollingNode.h103
-rw-r--r--Source/WebCore/page/scrolling/ScrollingTreeNode.cpp95
-rw-r--r--Source/WebCore/page/scrolling/ScrollingTreeNode.h94
-rw-r--r--Source/WebCore/page/scrolling/ScrollingTreeOverflowScrollingNode.cpp47
-rw-r--r--Source/WebCore/page/scrolling/ScrollingTreeOverflowScrollingNode.h46
-rw-r--r--Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.cpp165
-rw-r--r--Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.h119
-rw-r--r--Source/WebCore/page/scrolling/ThreadedScrollingTree.cpp163
-rw-r--r--Source/WebCore/page/scrolling/ThreadedScrollingTree.h79
-rw-r--r--Source/WebCore/page/scrolling/coordinatedgraphics/ScrollingCoordinatorCoordinatedGraphics.cpp125
-rw-r--r--Source/WebCore/page/scrolling/coordinatedgraphics/ScrollingCoordinatorCoordinatedGraphics.h60
-rw-r--r--Source/WebCore/page/scrolling/coordinatedgraphics/ScrollingStateNodeCoordinatedGraphics.cpp49
44 files changed, 5572 insertions, 610 deletions
diff --git a/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.cpp b/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.cpp
new file mode 100644
index 000000000..fce95a0a3
--- /dev/null
+++ b/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.cpp
@@ -0,0 +1,707 @@
+/*
+ * Copyright (C) 2014-2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(ASYNC_SCROLLING)
+#include "AsyncScrollingCoordinator.h"
+
+#include "Document.h"
+#include "EditorClient.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "GraphicsLayer.h"
+#include "Logging.h"
+#include "MainFrame.h"
+#include "Page.h"
+#include "ScrollAnimator.h"
+#include "ScrollingConstraints.h"
+#include "ScrollingStateFixedNode.h"
+#include "ScrollingStateFrameScrollingNode.h"
+#include "ScrollingStateOverflowScrollingNode.h"
+#include "ScrollingStateStickyNode.h"
+#include "ScrollingStateTree.h"
+#include "Settings.h"
+#include "TextStream.h"
+#include "WheelEventTestTrigger.h"
+
+namespace WebCore {
+
+AsyncScrollingCoordinator::AsyncScrollingCoordinator(Page* page)
+ : ScrollingCoordinator(page)
+ , m_updateNodeScrollPositionTimer(*this, &AsyncScrollingCoordinator::updateScrollPositionAfterAsyncScrollTimerFired)
+ , m_scrollingStateTree(std::make_unique<ScrollingStateTree>(this))
+{
+}
+
+AsyncScrollingCoordinator::~AsyncScrollingCoordinator()
+{
+}
+
+void AsyncScrollingCoordinator::scrollingStateTreePropertiesChanged()
+{
+ scheduleTreeStateCommit();
+}
+
+static inline void setStateScrollingNodeSnapOffsetsAsFloat(ScrollingStateScrollingNode& node, ScrollEventAxis axis, const Vector<LayoutUnit>* snapOffsets, const Vector<ScrollOffsetRange<LayoutUnit>>* snapOffsetRanges, float deviceScaleFactor)
+{
+ // 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?
+ Vector<float> snapOffsetsAsFloat;
+ if (snapOffsets) {
+ snapOffsetsAsFloat.reserveInitialCapacity(snapOffsets->size());
+ for (auto& offset : *snapOffsets)
+ snapOffsetsAsFloat.uncheckedAppend(roundToDevicePixel(offset, deviceScaleFactor, false));
+ }
+
+ Vector<ScrollOffsetRange<float>> snapOffsetRangesAsFloat;
+ if (snapOffsetRanges) {
+ snapOffsetRangesAsFloat.reserveInitialCapacity(snapOffsetRanges->size());
+ for (auto& range : *snapOffsetRanges)
+ snapOffsetRangesAsFloat.uncheckedAppend({ roundToDevicePixel(range.start, deviceScaleFactor, false), roundToDevicePixel(range.end, deviceScaleFactor, false) });
+ }
+ if (axis == ScrollEventAxis::Horizontal) {
+ node.setHorizontalSnapOffsets(snapOffsetsAsFloat);
+ node.setHorizontalSnapOffsetRanges(snapOffsetRangesAsFloat);
+ } else {
+ node.setVerticalSnapOffsets(snapOffsetsAsFloat);
+ node.setVerticalSnapOffsetRanges(snapOffsetRangesAsFloat);
+ }
+}
+
+void AsyncScrollingCoordinator::setEventTrackingRegionsDirty()
+{
+ m_eventTrackingRegionsDirty = true;
+ // We have to schedule a commit, but the computed non-fast region may not have actually changed.
+ scheduleTreeStateCommit();
+}
+
+void AsyncScrollingCoordinator::willCommitTree()
+{
+ updateEventTrackingRegions();
+}
+
+void AsyncScrollingCoordinator::updateEventTrackingRegions()
+{
+ if (!m_eventTrackingRegionsDirty)
+ return;
+
+ if (!m_scrollingStateTree->rootStateNode())
+ return;
+
+ m_scrollingStateTree->rootStateNode()->setEventTrackingRegions(absoluteEventTrackingRegions());
+ m_eventTrackingRegionsDirty = false;
+}
+
+void AsyncScrollingCoordinator::frameViewLayoutUpdated(FrameView& frameView)
+{
+ ASSERT(isMainThread());
+ ASSERT(m_page);
+
+ // If there isn't a root node yet, don't do anything. We'll be called again after creating one.
+ if (!m_scrollingStateTree->rootStateNode())
+ return;
+
+ // Compute the region of the page that we can't do fast scrolling for. This currently includes
+ // all scrollable areas, such as subframes, overflow divs and list boxes. We need to do this even if the
+ // frame view whose layout was updated is not the main frame.
+ // In the future, we may want to have the ability to set non-fast scrolling regions for more than
+ // just the root node. But right now, this concept only applies to the root.
+ m_scrollingStateTree->rootStateNode()->setEventTrackingRegions(absoluteEventTrackingRegions());
+ m_eventTrackingRegionsDirty = false;
+
+ if (!coordinatesScrollingForFrameView(frameView))
+ return;
+
+ ScrollingStateFrameScrollingNode* node = downcast<ScrollingStateFrameScrollingNode>(m_scrollingStateTree->stateNodeForID(frameView.scrollLayerID()));
+ if (!node)
+ return;
+
+ Scrollbar* verticalScrollbar = frameView.verticalScrollbar();
+ Scrollbar* horizontalScrollbar = frameView.horizontalScrollbar();
+ node->setScrollerImpsFromScrollbars(verticalScrollbar, horizontalScrollbar);
+
+ node->setFrameScaleFactor(frameView.frame().frameScaleFactor());
+ node->setHeaderHeight(frameView.headerHeight());
+ node->setFooterHeight(frameView.footerHeight());
+ node->setTopContentInset(frameView.topContentInset());
+
+ node->setVisualViewportEnabled(visualViewportEnabled());
+ node->setLayoutViewport(frameView.layoutViewportRect());
+ node->setMinLayoutViewportOrigin(frameView.minStableLayoutViewportOrigin());
+ node->setMaxLayoutViewportOrigin(frameView.maxStableLayoutViewportOrigin());
+
+ node->setScrollOrigin(frameView.scrollOrigin());
+ node->setScrollableAreaSize(frameView.visibleContentRect().size());
+ node->setTotalContentsSize(frameView.totalContentsSize());
+ node->setReachableContentsSize(frameView.totalContentsSize());
+ node->setFixedElementsLayoutRelativeToFrame(frameView.fixedElementsLayoutRelativeToFrame());
+ node->setScrollBehaviorForFixedElements(frameView.scrollBehaviorForFixedElements());
+
+#if ENABLE(CSS_SCROLL_SNAP)
+ frameView.updateSnapOffsets();
+ updateScrollSnapPropertiesWithFrameView(frameView);
+#endif
+
+#if PLATFORM(COCOA)
+ Page* page = frameView.frame().page();
+ if (page && page->expectsWheelEventTriggers()) {
+ LOG(WheelEventTestTriggers, " AsyncScrollingCoordinator::frameViewLayoutUpdated: Expects wheel event test trigger=%d", page->expectsWheelEventTriggers());
+ node->setExpectsWheelEventTestTrigger(page->expectsWheelEventTriggers());
+ }
+#endif
+
+ ScrollableAreaParameters scrollParameters;
+ scrollParameters.horizontalScrollElasticity = frameView.horizontalScrollElasticity();
+ scrollParameters.verticalScrollElasticity = frameView.verticalScrollElasticity();
+ scrollParameters.hasEnabledHorizontalScrollbar = horizontalScrollbar && horizontalScrollbar->enabled();
+ scrollParameters.hasEnabledVerticalScrollbar = verticalScrollbar && verticalScrollbar->enabled();
+ scrollParameters.horizontalScrollbarMode = frameView.horizontalScrollbarMode();
+ scrollParameters.verticalScrollbarMode = frameView.verticalScrollbarMode();
+
+ node->setScrollableAreaParameters(scrollParameters);
+}
+
+void AsyncScrollingCoordinator::updateExpectsWheelEventTestTriggerWithFrameView(const FrameView& frameView)
+{
+ auto* page = frameView.frame().page();
+ if (!page)
+ return;
+
+ auto* node = downcast<ScrollingStateFrameScrollingNode>(m_scrollingStateTree->stateNodeForID(frameView.scrollLayerID()));
+ if (!node)
+ return;
+
+ node->setExpectsWheelEventTestTrigger(page->expectsWheelEventTriggers());
+}
+
+void AsyncScrollingCoordinator::frameViewEventTrackingRegionsChanged(FrameView&)
+{
+ if (!m_scrollingStateTree->rootStateNode())
+ return;
+
+ setEventTrackingRegionsDirty();
+}
+
+void AsyncScrollingCoordinator::frameViewRootLayerDidChange(FrameView& frameView)
+{
+ ASSERT(isMainThread());
+ ASSERT(m_page);
+
+ if (!coordinatesScrollingForFrameView(frameView))
+ return;
+
+ // FIXME: In some navigation scenarios, the FrameView has no RenderView or that RenderView has not been composited.
+ // This needs cleaning up: https://bugs.webkit.org/show_bug.cgi?id=132724
+ if (!frameView.scrollLayerID())
+ return;
+
+ // If the root layer does not have a ScrollingStateNode, then we should create one.
+ ensureRootStateNodeForFrameView(frameView);
+ ASSERT(m_scrollingStateTree->rootStateNode());
+
+ ScrollingCoordinator::frameViewRootLayerDidChange(frameView);
+
+ ScrollingStateFrameScrollingNode* node = downcast<ScrollingStateFrameScrollingNode>(m_scrollingStateTree->stateNodeForID(frameView.scrollLayerID()));
+ node->setLayer(scrollLayerForFrameView(frameView));
+ node->setScrolledContentsLayer(rootContentLayerForFrameView(frameView));
+ node->setCounterScrollingLayer(counterScrollingLayerForFrameView(frameView));
+ node->setInsetClipLayer(insetClipLayerForFrameView(frameView));
+ node->setContentShadowLayer(contentShadowLayerForFrameView(frameView));
+ node->setHeaderLayer(headerLayerForFrameView(frameView));
+ node->setFooterLayer(footerLayerForFrameView(frameView));
+ node->setScrollBehaviorForFixedElements(frameView.scrollBehaviorForFixedElements());
+}
+
+bool AsyncScrollingCoordinator::requestScrollPositionUpdate(FrameView& frameView, const IntPoint& scrollPosition)
+{
+ ASSERT(isMainThread());
+ ASSERT(m_page);
+
+ if (!coordinatesScrollingForFrameView(frameView))
+ return false;
+
+ bool isProgrammaticScroll = frameView.inProgrammaticScroll();
+ if (isProgrammaticScroll || frameView.frame().document()->pageCacheState() != Document::NotInPageCache)
+ updateScrollPositionAfterAsyncScroll(frameView.scrollLayerID(), scrollPosition, std::nullopt, isProgrammaticScroll, ScrollingLayerPositionAction::Set);
+
+ // If this frame view's document is being put into the page cache, we don't want to update our
+ // main frame scroll position. Just let the FrameView think that we did.
+ if (frameView.frame().document()->pageCacheState() != Document::NotInPageCache)
+ return true;
+
+ ScrollingStateScrollingNode* stateNode = downcast<ScrollingStateScrollingNode>(m_scrollingStateTree->stateNodeForID(frameView.scrollLayerID()));
+ if (!stateNode)
+ return false;
+
+ stateNode->setRequestedScrollPosition(scrollPosition, isProgrammaticScroll);
+ return true;
+}
+
+void AsyncScrollingCoordinator::scheduleUpdateScrollPositionAfterAsyncScroll(ScrollingNodeID nodeID, const FloatPoint& scrollPosition, const std::optional<FloatPoint>& layoutViewportOrigin, bool programmaticScroll, ScrollingLayerPositionAction scrollingLayerPositionAction)
+{
+ ScheduledScrollUpdate scrollUpdate(nodeID, scrollPosition, layoutViewportOrigin, programmaticScroll, scrollingLayerPositionAction);
+
+ // For programmatic scrolls, requestScrollPositionUpdate() has already called updateScrollPositionAfterAsyncScroll().
+ if (programmaticScroll)
+ return;
+
+ if (m_updateNodeScrollPositionTimer.isActive()) {
+ if (m_scheduledScrollUpdate.matchesUpdateType(scrollUpdate)) {
+ m_scheduledScrollUpdate.scrollPosition = scrollPosition;
+ m_scheduledScrollUpdate.layoutViewportOrigin = layoutViewportOrigin;
+ return;
+ }
+
+ // If the parameters don't match what was previously scheduled, dispatch immediately.
+ m_updateNodeScrollPositionTimer.stop();
+ updateScrollPositionAfterAsyncScroll(m_scheduledScrollUpdate.nodeID, m_scheduledScrollUpdate.scrollPosition, m_scheduledScrollUpdate.layoutViewportOrigin, m_scheduledScrollUpdate.isProgrammaticScroll, m_scheduledScrollUpdate.updateLayerPositionAction);
+ updateScrollPositionAfterAsyncScroll(nodeID, scrollPosition, layoutViewportOrigin, programmaticScroll, scrollingLayerPositionAction);
+ return;
+ }
+
+ m_scheduledScrollUpdate = scrollUpdate;
+ m_updateNodeScrollPositionTimer.startOneShot(0);
+}
+
+void AsyncScrollingCoordinator::updateScrollPositionAfterAsyncScrollTimerFired()
+{
+ updateScrollPositionAfterAsyncScroll(m_scheduledScrollUpdate.nodeID, m_scheduledScrollUpdate.scrollPosition, m_scheduledScrollUpdate.layoutViewportOrigin, m_scheduledScrollUpdate.isProgrammaticScroll, m_scheduledScrollUpdate.updateLayerPositionAction);
+}
+
+FrameView* AsyncScrollingCoordinator::frameViewForScrollingNode(ScrollingNodeID scrollingNodeID) const
+{
+ if (!m_scrollingStateTree->rootStateNode())
+ return nullptr;
+
+ if (scrollingNodeID == m_scrollingStateTree->rootStateNode()->scrollingNodeID())
+ return m_page->mainFrame().view();
+
+ ScrollingStateNode* stateNode = m_scrollingStateTree->stateNodeForID(scrollingNodeID);
+ if (!stateNode)
+ return nullptr;
+
+ // Find the enclosing frame scrolling node.
+ ScrollingStateNode* parentNode = stateNode;
+ while (parentNode && parentNode->nodeType() != FrameScrollingNode)
+ parentNode = parentNode->parent();
+
+ if (!parentNode)
+ return nullptr;
+
+ // Walk the frame tree to find the matching FrameView. This is not ideal, but avoids back pointers to FrameViews
+ // from ScrollingTreeStateNodes.
+ for (Frame* frame = &m_page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
+ if (FrameView* view = frame->view()) {
+ if (view->scrollLayerID() == parentNode->scrollingNodeID())
+ return view;
+ }
+ }
+
+ return nullptr;
+}
+
+void AsyncScrollingCoordinator::updateScrollPositionAfterAsyncScroll(ScrollingNodeID scrollingNodeID, const FloatPoint& scrollPosition, std::optional<FloatPoint> layoutViewportOrigin, bool programmaticScroll, ScrollingLayerPositionAction scrollingLayerPositionAction)
+{
+ ASSERT(isMainThread());
+
+ if (!m_page)
+ return;
+
+ FrameView* frameViewPtr = frameViewForScrollingNode(scrollingNodeID);
+ if (!frameViewPtr)
+ return;
+
+ LOG_WITH_STREAM(Scrolling, stream << "AsyncScrollingCoordinator::updateScrollPositionAfterAsyncScroll node " << scrollingNodeID << " scrollPosition " << scrollPosition << " action " << scrollingLayerPositionAction);
+
+ FrameView& frameView = *frameViewPtr;
+
+ if (scrollingNodeID == frameView.scrollLayerID()) {
+ reconcileScrollingState(frameView, scrollPosition, layoutViewportOrigin, programmaticScroll, true, scrollingLayerPositionAction);
+
+#if PLATFORM(COCOA)
+ if (m_page->expectsWheelEventTriggers()) {
+ frameView.scrollAnimator().setWheelEventTestTrigger(m_page->testTrigger());
+ if (const auto& trigger = m_page->testTrigger())
+ trigger->removeTestDeferralForReason(reinterpret_cast<WheelEventTestTrigger::ScrollableAreaIdentifier>(scrollingNodeID), WheelEventTestTrigger::ScrollingThreadSyncNeeded);
+ }
+#endif
+
+ return;
+ }
+
+ // Overflow-scroll area.
+ if (ScrollableArea* scrollableArea = frameView.scrollableAreaForScrollLayerID(scrollingNodeID)) {
+ scrollableArea->setIsUserScroll(scrollingLayerPositionAction == ScrollingLayerPositionAction::Sync);
+ scrollableArea->scrollToOffsetWithoutAnimation(scrollPosition);
+ scrollableArea->setIsUserScroll(false);
+ if (scrollingLayerPositionAction == ScrollingLayerPositionAction::Set)
+ m_page->editorClient().overflowScrollPositionChanged();
+
+#if PLATFORM(COCOA)
+ if (m_page->expectsWheelEventTriggers()) {
+ frameView.scrollAnimator().setWheelEventTestTrigger(m_page->testTrigger());
+ if (const auto& trigger = m_page->testTrigger())
+ trigger->removeTestDeferralForReason(reinterpret_cast<WheelEventTestTrigger::ScrollableAreaIdentifier>(scrollingNodeID), WheelEventTestTrigger::ScrollingThreadSyncNeeded);
+ }
+#endif
+ }
+}
+
+void AsyncScrollingCoordinator::reconcileScrollingState(FrameView& frameView, const FloatPoint& scrollPosition, const LayoutViewportOriginOrOverrideRect& layoutViewportOriginOrOverrideRect, bool programmaticScroll, bool inStableState, ScrollingLayerPositionAction scrollingLayerPositionAction)
+{
+ bool oldProgrammaticScroll = frameView.inProgrammaticScroll();
+ frameView.setInProgrammaticScroll(programmaticScroll);
+
+ std::optional<FloatRect> layoutViewportRect;
+
+ WTF::switchOn(layoutViewportOriginOrOverrideRect,
+ [&frameView](std::optional<FloatPoint> origin) {
+ if (origin)
+ frameView.setBaseLayoutViewportOrigin(LayoutPoint(origin.value()), FrameView::TriggerLayoutOrNot::No);
+ }, [&frameView, &layoutViewportRect, inStableState, visualViewportEnabled = visualViewportEnabled()](std::optional<FloatRect> overrideRect) {
+ layoutViewportRect = overrideRect;
+ if (overrideRect && inStableState) {
+ if (visualViewportEnabled)
+ frameView.setLayoutViewportOverrideRect(LayoutRect(overrideRect.value()));
+#if PLATFORM(IOS)
+ else
+ frameView.setCustomFixedPositionLayoutRect(enclosingIntRect(overrideRect.value()));
+#endif
+ }
+ }
+ );
+
+ frameView.setConstrainsScrollingToContentEdge(false);
+ frameView.notifyScrollPositionChanged(roundedIntPoint(scrollPosition));
+ frameView.setConstrainsScrollingToContentEdge(true);
+ frameView.setInProgrammaticScroll(oldProgrammaticScroll);
+
+ if (!programmaticScroll && scrollingLayerPositionAction != ScrollingLayerPositionAction::Set) {
+ if (inStableState)
+ reconcileViewportConstrainedLayerPositions(frameView.rectForFixedPositionLayout(), scrollingLayerPositionAction);
+ else if (layoutViewportRect)
+ reconcileViewportConstrainedLayerPositions(LayoutRect(layoutViewportRect.value()), scrollingLayerPositionAction);
+ }
+
+ GraphicsLayer* scrollLayer = scrollLayerForFrameView(frameView);
+ if (!scrollLayer)
+ return;
+
+ GraphicsLayer* counterScrollingLayer = counterScrollingLayerForFrameView(frameView);
+ GraphicsLayer* insetClipLayer = insetClipLayerForFrameView(frameView);
+ GraphicsLayer* contentShadowLayer = contentShadowLayerForFrameView(frameView);
+ GraphicsLayer* scrolledContentsLayer = rootContentLayerForFrameView(frameView);
+ GraphicsLayer* headerLayer = headerLayerForFrameView(frameView);
+ GraphicsLayer* footerLayer = footerLayerForFrameView(frameView);
+
+ ASSERT(frameView.scrollPosition() == roundedIntPoint(scrollPosition));
+ LayoutPoint scrollPositionForFixed = frameView.scrollPositionForFixedPosition();
+ float topContentInset = frameView.topContentInset();
+
+ FloatPoint positionForInsetClipLayer;
+ if (insetClipLayer)
+ positionForInsetClipLayer = FloatPoint(insetClipLayer->position().x(), FrameView::yPositionForInsetClipLayer(scrollPosition, topContentInset));
+ FloatPoint positionForContentsLayer = frameView.positionForRootContentLayer();
+
+ FloatPoint positionForHeaderLayer = FloatPoint(scrollPositionForFixed.x(), FrameView::yPositionForHeaderLayer(scrollPosition, topContentInset));
+ FloatPoint positionForFooterLayer = FloatPoint(scrollPositionForFixed.x(),
+ FrameView::yPositionForFooterLayer(scrollPosition, topContentInset, frameView.totalContentsSize().height(), frameView.footerHeight()));
+
+ if (programmaticScroll || scrollingLayerPositionAction == ScrollingLayerPositionAction::Set) {
+ scrollLayer->setPosition(-frameView.scrollPosition());
+ if (counterScrollingLayer)
+ counterScrollingLayer->setPosition(scrollPositionForFixed);
+ if (insetClipLayer)
+ insetClipLayer->setPosition(positionForInsetClipLayer);
+ if (contentShadowLayer)
+ contentShadowLayer->setPosition(positionForContentsLayer);
+ if (scrolledContentsLayer)
+ scrolledContentsLayer->setPosition(positionForContentsLayer);
+ if (headerLayer)
+ headerLayer->setPosition(positionForHeaderLayer);
+ if (footerLayer)
+ footerLayer->setPosition(positionForFooterLayer);
+ } else {
+ scrollLayer->syncPosition(-frameView.scrollPosition());
+ if (counterScrollingLayer)
+ counterScrollingLayer->syncPosition(scrollPositionForFixed);
+ if (insetClipLayer)
+ insetClipLayer->syncPosition(positionForInsetClipLayer);
+ if (contentShadowLayer)
+ contentShadowLayer->syncPosition(positionForContentsLayer);
+ if (scrolledContentsLayer)
+ scrolledContentsLayer->syncPosition(positionForContentsLayer);
+ if (headerLayer)
+ headerLayer->syncPosition(positionForHeaderLayer);
+ if (footerLayer)
+ footerLayer->syncPosition(positionForFooterLayer);
+ }
+}
+
+void AsyncScrollingCoordinator::scrollableAreaScrollbarLayerDidChange(ScrollableArea& scrollableArea, ScrollbarOrientation orientation)
+{
+ ASSERT(isMainThread());
+ ASSERT(m_page);
+
+ if (&scrollableArea != static_cast<ScrollableArea*>(m_page->mainFrame().view()))
+ return;
+
+ if (orientation == VerticalScrollbar)
+ scrollableArea.verticalScrollbarLayerDidChange();
+ else
+ scrollableArea.horizontalScrollbarLayerDidChange();
+}
+
+ScrollingNodeID AsyncScrollingCoordinator::attachToStateTree(ScrollingNodeType nodeType, ScrollingNodeID newNodeID, ScrollingNodeID parentID)
+{
+ return m_scrollingStateTree->attachNode(nodeType, newNodeID, parentID);
+}
+
+void AsyncScrollingCoordinator::detachFromStateTree(ScrollingNodeID nodeID)
+{
+ m_scrollingStateTree->detachNode(nodeID);
+}
+
+void AsyncScrollingCoordinator::clearStateTree()
+{
+ m_scrollingStateTree->clear();
+}
+
+void AsyncScrollingCoordinator::reconcileViewportConstrainedLayerPositions(const LayoutRect& viewportRect, ScrollingLayerPositionAction action)
+{
+ if (!m_scrollingStateTree->rootStateNode())
+ return;
+
+ auto children = m_scrollingStateTree->rootStateNode()->children();
+ if (!children)
+ return;
+
+ LOG_WITH_STREAM(Scrolling, stream << "AsyncScrollingCoordinator::reconcileViewportConstrainedLayerPositions for viewport rect " << viewportRect);
+
+ // FIXME: We'll have to traverse deeper into the tree at some point.
+ for (auto& child : *children)
+ child->reconcileLayerPositionForViewportRect(viewportRect, action);
+}
+
+void AsyncScrollingCoordinator::ensureRootStateNodeForFrameView(FrameView& frameView)
+{
+ ASSERT(frameView.scrollLayerID());
+ attachToStateTree(FrameScrollingNode, frameView.scrollLayerID(), 0);
+}
+
+void AsyncScrollingCoordinator::updateFrameScrollingNode(ScrollingNodeID nodeID, GraphicsLayer* layer, GraphicsLayer* scrolledContentsLayer, GraphicsLayer* counterScrollingLayer, GraphicsLayer* insetClipLayer, const ScrollingGeometry* scrollingGeometry)
+{
+ ScrollingStateFrameScrollingNode* node = downcast<ScrollingStateFrameScrollingNode>(m_scrollingStateTree->stateNodeForID(nodeID));
+ ASSERT(node);
+ if (!node)
+ return;
+
+ node->setLayer(layer);
+ node->setInsetClipLayer(insetClipLayer);
+ node->setScrolledContentsLayer(scrolledContentsLayer);
+ node->setCounterScrollingLayer(counterScrollingLayer);
+
+ if (scrollingGeometry) {
+ node->setScrollOrigin(scrollingGeometry->scrollOrigin);
+ node->setScrollPosition(scrollingGeometry->scrollPosition);
+ node->setTotalContentsSize(scrollingGeometry->contentSize);
+ node->setReachableContentsSize(scrollingGeometry->reachableContentSize);
+ node->setScrollableAreaSize(scrollingGeometry->scrollableAreaSize);
+ }
+}
+
+void AsyncScrollingCoordinator::updateOverflowScrollingNode(ScrollingNodeID nodeID, GraphicsLayer* layer, GraphicsLayer* scrolledContentsLayer, const ScrollingGeometry* scrollingGeometry)
+{
+ ScrollingStateOverflowScrollingNode* node = downcast<ScrollingStateOverflowScrollingNode>(m_scrollingStateTree->stateNodeForID(nodeID));
+ ASSERT(node);
+ if (!node)
+ return;
+
+ node->setLayer(layer);
+ node->setScrolledContentsLayer(scrolledContentsLayer);
+
+ if (scrollingGeometry) {
+ node->setScrollOrigin(scrollingGeometry->scrollOrigin);
+ node->setScrollPosition(scrollingGeometry->scrollPosition);
+ node->setTotalContentsSize(scrollingGeometry->contentSize);
+ node->setReachableContentsSize(scrollingGeometry->reachableContentSize);
+ node->setScrollableAreaSize(scrollingGeometry->scrollableAreaSize);
+#if ENABLE(CSS_SCROLL_SNAP)
+ setStateScrollingNodeSnapOffsetsAsFloat(*node, ScrollEventAxis::Horizontal, &scrollingGeometry->horizontalSnapOffsets, &scrollingGeometry->horizontalSnapOffsetRanges, m_page->deviceScaleFactor());
+ setStateScrollingNodeSnapOffsetsAsFloat(*node, ScrollEventAxis::Vertical, &scrollingGeometry->verticalSnapOffsets, &scrollingGeometry->verticalSnapOffsetRanges, m_page->deviceScaleFactor());
+ node->setCurrentHorizontalSnapPointIndex(scrollingGeometry->currentHorizontalSnapPointIndex);
+ node->setCurrentVerticalSnapPointIndex(scrollingGeometry->currentVerticalSnapPointIndex);
+#endif
+ }
+}
+
+void AsyncScrollingCoordinator::updateViewportConstrainedNode(ScrollingNodeID nodeID, const ViewportConstraints& constraints, GraphicsLayer* graphicsLayer)
+{
+ ASSERT(supportsFixedPositionLayers());
+
+ ScrollingStateNode* node = m_scrollingStateTree->stateNodeForID(nodeID);
+ if (!node)
+ return;
+
+ switch (constraints.constraintType()) {
+ case ViewportConstraints::FixedPositionConstraint: {
+ ScrollingStateFixedNode& fixedNode = downcast<ScrollingStateFixedNode>(*node);
+ fixedNode.setLayer(graphicsLayer);
+ fixedNode.updateConstraints((const FixedPositionViewportConstraints&)constraints);
+ break;
+ }
+ case ViewportConstraints::StickyPositionConstraint: {
+ ScrollingStateStickyNode& stickyNode = downcast<ScrollingStateStickyNode>(*node);
+ stickyNode.setLayer(graphicsLayer);
+ stickyNode.updateConstraints((const StickyPositionViewportConstraints&)constraints);
+ break;
+ }
+ }
+}
+
+void AsyncScrollingCoordinator::setSynchronousScrollingReasons(SynchronousScrollingReasons reasons)
+{
+ if (!m_scrollingStateTree->rootStateNode())
+ return;
+
+ // The FrameView's GraphicsLayer is likely to be out-of-synch with the PlatformLayer
+ // at this point. So we'll update it before we switch back to main thread scrolling
+ // in order to avoid layer positioning bugs.
+ if (reasons)
+ updateMainFrameScrollLayerPosition();
+ m_scrollingStateTree->rootStateNode()->setSynchronousScrollingReasons(reasons);
+}
+
+void AsyncScrollingCoordinator::updateMainFrameScrollLayerPosition()
+{
+ ASSERT(isMainThread());
+
+ if (!m_page)
+ return;
+
+ FrameView* frameView = m_page->mainFrame().view();
+ if (!frameView)
+ return;
+
+ if (GraphicsLayer* scrollLayer = scrollLayerForFrameView(*frameView))
+ scrollLayer->setPosition(-frameView->scrollPosition());
+}
+
+bool AsyncScrollingCoordinator::isRubberBandInProgress() const
+{
+ return scrollingTree()->isRubberBandInProgress();
+}
+
+void AsyncScrollingCoordinator::setScrollPinningBehavior(ScrollPinningBehavior pinning)
+{
+ scrollingTree()->setScrollPinningBehavior(pinning);
+}
+
+bool AsyncScrollingCoordinator::visualViewportEnabled() const
+{
+ return m_page->mainFrame().settings().visualViewportEnabled();
+}
+
+String AsyncScrollingCoordinator::scrollingStateTreeAsText() const
+{
+ if (m_scrollingStateTree->rootStateNode()) {
+ if (m_eventTrackingRegionsDirty)
+ m_scrollingStateTree->rootStateNode()->setEventTrackingRegions(absoluteEventTrackingRegions());
+ return m_scrollingStateTree->rootStateNode()->scrollingStateTreeAsText();
+ }
+
+ return String();
+}
+
+#if PLATFORM(COCOA)
+void AsyncScrollingCoordinator::setActiveScrollSnapIndices(ScrollingNodeID scrollingNodeID, unsigned horizontalIndex, unsigned verticalIndex)
+{
+ ASSERT(isMainThread());
+
+ if (!m_page)
+ return;
+
+ FrameView* frameView = frameViewForScrollingNode(scrollingNodeID);
+ if (!frameView)
+ return;
+
+ if (scrollingNodeID == frameView->scrollLayerID()) {
+ frameView->setCurrentHorizontalSnapPointIndex(horizontalIndex);
+ frameView->setCurrentVerticalSnapPointIndex(verticalIndex);
+ return;
+ }
+
+ // Overflow-scroll area.
+ if (ScrollableArea* scrollableArea = frameView->scrollableAreaForScrollLayerID(scrollingNodeID)) {
+ scrollableArea->setCurrentHorizontalSnapPointIndex(horizontalIndex);
+ scrollableArea->setCurrentVerticalSnapPointIndex(verticalIndex);
+ }
+}
+
+void AsyncScrollingCoordinator::deferTestsForReason(WheelEventTestTrigger::ScrollableAreaIdentifier identifier, WheelEventTestTrigger::DeferTestTriggerReason reason) const
+{
+ ASSERT(isMainThread());
+ if (!m_page || !m_page->expectsWheelEventTriggers())
+ return;
+
+ if (const auto& trigger = m_page->testTrigger()) {
+ LOG(WheelEventTestTriggers, " (!) AsyncScrollingCoordinator::deferTestsForReason: Deferring %p for reason %d.", identifier, reason);
+ trigger->deferTestsForReason(identifier, reason);
+ }
+}
+
+void AsyncScrollingCoordinator::removeTestDeferralForReason(WheelEventTestTrigger::ScrollableAreaIdentifier identifier, WheelEventTestTrigger::DeferTestTriggerReason reason) const
+{
+ ASSERT(isMainThread());
+ if (!m_page || !m_page->expectsWheelEventTriggers())
+ return;
+
+ if (const auto& trigger = m_page->testTrigger()) {
+ LOG(WheelEventTestTriggers, " (!) AsyncScrollingCoordinator::removeTestDeferralForReason: Deferring %p for reason %d.", identifier, reason);
+ trigger->removeTestDeferralForReason(identifier, reason);
+ }
+}
+#endif
+
+#if ENABLE(CSS_SCROLL_SNAP)
+bool AsyncScrollingCoordinator::isScrollSnapInProgress() const
+{
+ return scrollingTree()->isScrollSnapInProgress();
+}
+
+void AsyncScrollingCoordinator::updateScrollSnapPropertiesWithFrameView(const FrameView& frameView)
+{
+ if (auto node = downcast<ScrollingStateFrameScrollingNode>(m_scrollingStateTree->stateNodeForID(frameView.scrollLayerID()))) {
+ setStateScrollingNodeSnapOffsetsAsFloat(*node, ScrollEventAxis::Horizontal, frameView.horizontalSnapOffsets(), frameView.horizontalSnapOffsetRanges(), m_page->deviceScaleFactor());
+ setStateScrollingNodeSnapOffsetsAsFloat(*node, ScrollEventAxis::Vertical, frameView.verticalSnapOffsets(), frameView.verticalSnapOffsetRanges(), m_page->deviceScaleFactor());
+ node->setCurrentHorizontalSnapPointIndex(frameView.currentHorizontalSnapPointIndex());
+ node->setCurrentVerticalSnapPointIndex(frameView.currentVerticalSnapPointIndex());
+ }
+}
+#endif
+
+} // namespace WebCore
+
+#endif // ENABLE(ASYNC_SCROLLING)
diff --git a/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.h b/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.h
new file mode 100644
index 000000000..011ae0f23
--- /dev/null
+++ b/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2014-2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(ASYNC_SCROLLING)
+
+#include "ScrollingCoordinator.h"
+#include "ScrollingTree.h"
+#include "Timer.h"
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class Page;
+class Scrollbar;
+class ScrollingStateNode;
+class ScrollingStateScrollingNode;
+class ScrollingStateTree;
+
+// ScrollingCoordinator subclass that maintains a ScrollingStateTree and a ScrollingTree,
+// allowing asynchronous scrolling (in another thread or process).
+class AsyncScrollingCoordinator : public ScrollingCoordinator {
+public:
+ static Ref<AsyncScrollingCoordinator> create(Page*);
+ WEBCORE_EXPORT virtual ~AsyncScrollingCoordinator();
+
+ ScrollingTree* scrollingTree() const { return m_scrollingTree.get(); }
+
+ void scrollingStateTreePropertiesChanged();
+
+ WEBCORE_EXPORT void scheduleUpdateScrollPositionAfterAsyncScroll(ScrollingNodeID, const FloatPoint&, const std::optional<FloatPoint>& layoutViewportOrigin, bool programmaticScroll, ScrollingLayerPositionAction);
+
+#if PLATFORM(COCOA)
+ WEBCORE_EXPORT void setActiveScrollSnapIndices(ScrollingNodeID, unsigned horizontalIndex, unsigned verticalIndex);
+ void deferTestsForReason(WheelEventTestTrigger::ScrollableAreaIdentifier, WheelEventTestTrigger::DeferTestTriggerReason) const;
+ void removeTestDeferralForReason(WheelEventTestTrigger::ScrollableAreaIdentifier, WheelEventTestTrigger::DeferTestTriggerReason) const;
+#endif
+
+#if ENABLE(CSS_SCROLL_SNAP)
+ WEBCORE_EXPORT void updateScrollSnapPropertiesWithFrameView(const FrameView&) override;
+#endif
+
+ WEBCORE_EXPORT void updateExpectsWheelEventTestTriggerWithFrameView(const FrameView&) override;
+
+protected:
+ WEBCORE_EXPORT AsyncScrollingCoordinator(Page*);
+
+ void setScrollingTree(Ref<ScrollingTree>&& scrollingTree) { m_scrollingTree = WTFMove(scrollingTree); }
+
+ ScrollingStateTree* scrollingStateTree() { return m_scrollingStateTree.get(); }
+
+ RefPtr<ScrollingTree> releaseScrollingTree() { return WTFMove(m_scrollingTree); }
+
+ void updateScrollPositionAfterAsyncScroll(ScrollingNodeID, const FloatPoint&, std::optional<FloatPoint> layoutViewportOrigin, bool programmaticScroll, ScrollingLayerPositionAction);
+
+ WEBCORE_EXPORT String scrollingStateTreeAsText() const override;
+ WEBCORE_EXPORT void willCommitTree() override;
+
+ bool eventTrackingRegionsDirty() const { return m_eventTrackingRegionsDirty; }
+
+private:
+ bool isAsyncScrollingCoordinator() const override { return true; }
+
+ bool supportsFixedPositionLayers() const override { return true; }
+ bool hasVisibleSlowRepaintViewportConstrainedObjects(const FrameView&) const override { return false; }
+
+ bool visualViewportEnabled() const;
+
+ WEBCORE_EXPORT void frameViewLayoutUpdated(FrameView&) override;
+ WEBCORE_EXPORT void frameViewRootLayerDidChange(FrameView&) override;
+ WEBCORE_EXPORT void frameViewEventTrackingRegionsChanged(FrameView&) override;
+
+ WEBCORE_EXPORT bool requestScrollPositionUpdate(FrameView&, const IntPoint&) override;
+
+ WEBCORE_EXPORT ScrollingNodeID attachToStateTree(ScrollingNodeType, ScrollingNodeID newNodeID, ScrollingNodeID parentID) override;
+ WEBCORE_EXPORT void detachFromStateTree(ScrollingNodeID) override;
+ WEBCORE_EXPORT void clearStateTree() override;
+
+ WEBCORE_EXPORT void updateViewportConstrainedNode(ScrollingNodeID, const ViewportConstraints&, GraphicsLayer*) override;
+
+ WEBCORE_EXPORT void updateFrameScrollingNode(ScrollingNodeID, GraphicsLayer* scrollLayer, GraphicsLayer* scrolledContentsLayer, GraphicsLayer* counterScrollingLayer, GraphicsLayer* insetClipLayer, const ScrollingGeometry* = nullptr) override;
+ WEBCORE_EXPORT void updateOverflowScrollingNode(ScrollingNodeID, GraphicsLayer* scrollLayer, GraphicsLayer* scrolledContentsLayer, const ScrollingGeometry* = nullptr) override;
+
+ WEBCORE_EXPORT void reconcileScrollingState(FrameView&, const FloatPoint&, const LayoutViewportOriginOrOverrideRect&, bool programmaticScroll, bool inStableState, ScrollingLayerPositionAction) override;
+
+ bool isRubberBandInProgress() const override;
+ void setScrollPinningBehavior(ScrollPinningBehavior) override;
+
+#if ENABLE(CSS_SCROLL_SNAP)
+ bool isScrollSnapInProgress() const override;
+#endif
+
+ WEBCORE_EXPORT void reconcileViewportConstrainedLayerPositions(const LayoutRect& viewportRect, ScrollingLayerPositionAction) override;
+ WEBCORE_EXPORT void scrollableAreaScrollbarLayerDidChange(ScrollableArea&, ScrollbarOrientation) override;
+
+ WEBCORE_EXPORT void setSynchronousScrollingReasons(SynchronousScrollingReasons) override;
+
+ virtual void scheduleTreeStateCommit() = 0;
+
+ void ensureRootStateNodeForFrameView(FrameView&);
+ void updateMainFrameScrollLayerPosition();
+
+ void updateScrollPositionAfterAsyncScrollTimerFired();
+ void setEventTrackingRegionsDirty();
+ void updateEventTrackingRegions();
+
+ FrameView* frameViewForScrollingNode(ScrollingNodeID) const;
+
+ Timer m_updateNodeScrollPositionTimer;
+
+ struct ScheduledScrollUpdate {
+ ScheduledScrollUpdate() = default;
+ ScheduledScrollUpdate(ScrollingNodeID scrollingNodeID, FloatPoint point, std::optional<FloatPoint> viewportOrigin, bool isProgrammatic, ScrollingLayerPositionAction udpateAction)
+ : nodeID(scrollingNodeID)
+ , scrollPosition(point)
+ , layoutViewportOrigin(viewportOrigin)
+ , isProgrammaticScroll(isProgrammatic)
+ , updateLayerPositionAction(udpateAction)
+ { }
+
+ ScrollingNodeID nodeID { 0 };
+ FloatPoint scrollPosition;
+ std::optional<FloatPoint> layoutViewportOrigin;
+ bool isProgrammaticScroll { false };
+ ScrollingLayerPositionAction updateLayerPositionAction { ScrollingLayerPositionAction::Sync };
+
+ bool matchesUpdateType(const ScheduledScrollUpdate& other) const
+ {
+ return nodeID == other.nodeID
+ && isProgrammaticScroll == other.isProgrammaticScroll
+ && updateLayerPositionAction == other.updateLayerPositionAction;
+ }
+ };
+
+ ScheduledScrollUpdate m_scheduledScrollUpdate;
+
+ std::unique_ptr<ScrollingStateTree> m_scrollingStateTree;
+ RefPtr<ScrollingTree> m_scrollingTree;
+
+ bool m_eventTrackingRegionsDirty { false };
+};
+
+} // namespace WebCore
+
+SPECIALIZE_TYPE_TRAITS_SCROLLING_COORDINATOR(WebCore::AsyncScrollingCoordinator, isAsyncScrollingCoordinator());
+
+#endif // ENABLE(ASYNC_SCROLLING)
diff --git a/Source/WebCore/page/scrolling/AxisScrollSnapOffsets.cpp b/Source/WebCore/page/scrolling/AxisScrollSnapOffsets.cpp
new file mode 100644
index 000000000..020753847
--- /dev/null
+++ b/Source/WebCore/page/scrolling/AxisScrollSnapOffsets.cpp
@@ -0,0 +1,346 @@
+/*
+ * Copyright (C) 2014-2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "AxisScrollSnapOffsets.h"
+
+#include "ElementChildIterator.h"
+#include "HTMLCollection.h"
+#include "HTMLElement.h"
+#include "Length.h"
+#include "Logging.h"
+#include "RenderBox.h"
+#include "RenderView.h"
+#include "ScrollableArea.h"
+#include "StyleScrollSnapPoints.h"
+
+#if ENABLE(CSS_SCROLL_SNAP)
+
+namespace WebCore {
+
+enum class InsetOrOutset {
+ Inset,
+ Outset
+};
+
+static LayoutRect computeScrollSnapPortOrAreaRect(const LayoutRect& rect, const LengthBox& insetOrOutsetBox, InsetOrOutset insetOrOutset)
+{
+ LayoutBoxExtent extents(valueForLength(insetOrOutsetBox.top(), rect.height()), valueForLength(insetOrOutsetBox.right(), rect.width()), valueForLength(insetOrOutsetBox.bottom(), rect.height()), valueForLength(insetOrOutsetBox.left(), rect.width()));
+ auto snapPortOrArea(rect);
+ if (insetOrOutset == InsetOrOutset::Inset)
+ snapPortOrArea.contract(extents);
+ else
+ snapPortOrArea.expand(extents);
+ return snapPortOrArea;
+}
+
+static LayoutUnit computeScrollSnapAlignOffset(const LayoutUnit& leftOrTop, const LayoutUnit& widthOrHeight, ScrollSnapAxisAlignType alignment)
+{
+ switch (alignment) {
+ case ScrollSnapAxisAlignType::Start:
+ return leftOrTop;
+ case ScrollSnapAxisAlignType::Center:
+ return leftOrTop + widthOrHeight / 2;
+ case ScrollSnapAxisAlignType::End:
+ return leftOrTop + widthOrHeight;
+ default:
+ ASSERT_NOT_REACHED();
+ return 0;
+ }
+}
+
+#if !LOG_DISABLED
+
+static String snapOffsetsToString(const Vector<LayoutUnit>& snapOffsets)
+{
+ StringBuilder s;
+ s.append("[ ");
+ for (auto offset : snapOffsets)
+ s.append(String::format("%.1f ", offset.toFloat()));
+
+ s.append("]");
+ return s.toString();
+}
+
+static String snapOffsetRangesToString(const Vector<ScrollOffsetRange<LayoutUnit>>& ranges)
+{
+ StringBuilder s;
+ s.append("[ ");
+ for (auto range : ranges)
+ s.append(String::format("(%.1f, %.1f) ", range.start.toFloat(), range.end.toFloat()));
+ s.append("]");
+ return s.toString();
+}
+
+static String snapPortOrAreaToString(const LayoutRect& rect)
+{
+ return String::format("{{%.1f, %.1f} {%.1f, %.1f}}", rect.x().toFloat(), rect.y().toFloat(), rect.width().toFloat(), rect.height().toFloat());
+}
+
+#endif
+
+template <typename LayoutType>
+static void indicesOfNearestSnapOffsetRanges(LayoutType offset, const Vector<ScrollOffsetRange<LayoutType>>& snapOffsetRanges, unsigned& lowerIndex, unsigned& upperIndex)
+{
+ if (snapOffsetRanges.isEmpty()) {
+ lowerIndex = invalidSnapOffsetIndex;
+ upperIndex = invalidSnapOffsetIndex;
+ return;
+ }
+
+ int lowerIndexAsInt = -1;
+ int upperIndexAsInt = snapOffsetRanges.size();
+ do {
+ int middleIndex = (lowerIndexAsInt + upperIndexAsInt) / 2;
+ auto& range = snapOffsetRanges[middleIndex];
+ if (range.start < offset && offset < range.end) {
+ lowerIndexAsInt = middleIndex;
+ upperIndexAsInt = middleIndex;
+ break;
+ }
+
+ if (offset > range.end)
+ lowerIndexAsInt = middleIndex;
+ else
+ upperIndexAsInt = middleIndex;
+ } while (lowerIndexAsInt < upperIndexAsInt - 1);
+
+ if (offset <= snapOffsetRanges.first().start)
+ lowerIndex = invalidSnapOffsetIndex;
+ else
+ lowerIndex = lowerIndexAsInt;
+
+ if (offset >= snapOffsetRanges.last().end)
+ upperIndex = invalidSnapOffsetIndex;
+ else
+ upperIndex = upperIndexAsInt;
+}
+
+template <typename LayoutType>
+static void indicesOfNearestSnapOffsets(LayoutType offset, const Vector<LayoutType>& snapOffsets, unsigned& lowerIndex, unsigned& upperIndex)
+{
+ lowerIndex = 0;
+ upperIndex = snapOffsets.size() - 1;
+ while (lowerIndex < upperIndex - 1) {
+ int middleIndex = (lowerIndex + upperIndex) / 2;
+ auto middleOffset = snapOffsets[middleIndex];
+ if (offset == middleOffset) {
+ upperIndex = middleIndex;
+ lowerIndex = middleIndex;
+ break;
+ }
+
+ if (offset > middleOffset)
+ lowerIndex = middleIndex;
+ else
+ upperIndex = middleIndex;
+ }
+}
+
+static void adjustAxisSnapOffsetsForScrollExtent(Vector<LayoutUnit>& snapOffsets, float maxScrollExtent)
+{
+ if (snapOffsets.isEmpty())
+ return;
+
+ std::sort(snapOffsets.begin(), snapOffsets.end());
+ if (snapOffsets.last() != maxScrollExtent)
+ snapOffsets.append(maxScrollExtent);
+ if (snapOffsets.first())
+ snapOffsets.insert(0, 0);
+}
+
+static void computeAxisProximitySnapOffsetRanges(const Vector<LayoutUnit>& snapOffsets, Vector<ScrollOffsetRange<LayoutUnit>>& offsetRanges, LayoutUnit scrollPortAxisLength)
+{
+ // This is an arbitrary choice for what it means to be "in proximity" of a snap offset. We should play around with
+ // this and see what feels best.
+ static const float ratioOfScrollPortAxisLengthToBeConsideredForProximity = 0.3;
+ if (snapOffsets.size() < 2)
+ return;
+
+ // The extra rule accounting for scroll offset ranges in between the scroll destination and a potential snap offset
+ // handles the corner case where the user scrolls with momentum very lightly away from a snap offset, such that the
+ // predicted scroll destination is still within proximity of the snap offset. In this case, the regular (mandatory
+ // scroll snapping) behavior would be to snap to the next offset in the direction of momentum scrolling, but
+ // instead, it is more intuitive to either return to the original snap position (which we arbitrarily choose here)
+ // or scroll just outside of the snap offset range. This is another minor behavior tweak that we should play around
+ // with to see what feels best.
+ LayoutUnit proximityDistance = ratioOfScrollPortAxisLengthToBeConsideredForProximity * scrollPortAxisLength;
+ for (size_t index = 1; index < snapOffsets.size(); ++index) {
+ auto startOffset = snapOffsets[index - 1] + proximityDistance;
+ auto endOffset = snapOffsets[index] - proximityDistance;
+ if (startOffset < endOffset)
+ offsetRanges.append({ startOffset, endOffset });
+ }
+}
+
+void updateSnapOffsetsForScrollableArea(ScrollableArea& scrollableArea, HTMLElement& scrollingElement, const RenderBox& scrollingElementBox, const RenderStyle& scrollingElementStyle)
+{
+ auto* scrollContainer = scrollingElement.renderer();
+ auto scrollSnapType = scrollingElementStyle.scrollSnapType();
+ if (!scrollContainer || scrollSnapType.strictness == ScrollSnapStrictness::None || scrollContainer->view().boxesWithScrollSnapPositions().isEmpty()) {
+ scrollableArea.clearHorizontalSnapOffsets();
+ scrollableArea.clearVerticalSnapOffsets();
+ return;
+ }
+
+ Vector<LayoutUnit> verticalSnapOffsets;
+ Vector<LayoutUnit> horizontalSnapOffsets;
+ Vector<ScrollOffsetRange<LayoutUnit>> verticalSnapOffsetRanges;
+ Vector<ScrollOffsetRange<LayoutUnit>> horizontalSnapOffsetRanges;
+ HashSet<float> seenVerticalSnapOffsets;
+ HashSet<float> seenHorizontalSnapOffsets;
+ bool hasHorizontalSnapOffsets = scrollSnapType.axis == ScrollSnapAxis::Both || scrollSnapType.axis == ScrollSnapAxis::XAxis || scrollSnapType.axis == ScrollSnapAxis::Inline;
+ bool hasVerticalSnapOffsets = scrollSnapType.axis == ScrollSnapAxis::Both || scrollSnapType.axis == ScrollSnapAxis::YAxis || scrollSnapType.axis == ScrollSnapAxis::Block;
+ auto maxScrollLeft = scrollingElementBox.scrollWidth() - scrollingElementBox.contentWidth();
+ auto maxScrollTop = scrollingElementBox.scrollHeight() - scrollingElementBox.contentHeight();
+ LayoutPoint containerScrollOffset(scrollingElementBox.scrollLeft(), scrollingElementBox.scrollTop());
+
+ // The bounds of the scrolling container's snap port, where the top left of the scrolling container's border box is the origin.
+ auto scrollSnapPort = computeScrollSnapPortOrAreaRect(scrollingElementBox.paddingBoxRect(), scrollingElementStyle.scrollPadding(), InsetOrOutset::Inset);
+#if !LOG_DISABLED
+ LOG(Scrolling, "Computing scroll snap offsets in snap port: %s", snapPortOrAreaToString(scrollSnapPort).utf8().data());
+#endif
+ for (auto* child : scrollContainer->view().boxesWithScrollSnapPositions()) {
+ if (child->findEnclosingScrollableContainer() != scrollContainer)
+ continue;
+
+ // The bounds of the child element's snap area, where the top left of the scrolling container's border box is the origin.
+ // The snap area is the bounding box of the child element's border box, after applying transformations.
+ auto scrollSnapArea = LayoutRect(child->localToContainerQuad(FloatQuad(child->borderBoundingBox()), scrollingElement.renderBox()).boundingBox());
+ scrollSnapArea.moveBy(containerScrollOffset);
+ scrollSnapArea = computeScrollSnapPortOrAreaRect(scrollSnapArea, child->style().scrollSnapMargin(), InsetOrOutset::Outset);
+#if !LOG_DISABLED
+ LOG(Scrolling, " Considering scroll snap area: %s", snapPortOrAreaToString(scrollSnapArea).utf8().data());
+#endif
+ auto alignment = child->style().scrollSnapAlign();
+ if (hasHorizontalSnapOffsets && alignment.x != ScrollSnapAxisAlignType::None) {
+ auto absoluteScrollOffset = clampTo<LayoutUnit>(computeScrollSnapAlignOffset(scrollSnapArea.x(), scrollSnapArea.width(), alignment.x) - computeScrollSnapAlignOffset(scrollSnapPort.x(), scrollSnapPort.width(), alignment.x), 0, maxScrollLeft);
+ if (!seenHorizontalSnapOffsets.contains(absoluteScrollOffset)) {
+ seenHorizontalSnapOffsets.add(absoluteScrollOffset);
+ horizontalSnapOffsets.append(absoluteScrollOffset);
+ }
+ }
+ if (hasVerticalSnapOffsets && alignment.y != ScrollSnapAxisAlignType::None) {
+ auto absoluteScrollOffset = clampTo<LayoutUnit>(computeScrollSnapAlignOffset(scrollSnapArea.y(), scrollSnapArea.height(), alignment.y) - computeScrollSnapAlignOffset(scrollSnapPort.y(), scrollSnapPort.height(), alignment.y), 0, maxScrollTop);
+ if (!seenVerticalSnapOffsets.contains(absoluteScrollOffset)) {
+ seenVerticalSnapOffsets.add(absoluteScrollOffset);
+ verticalSnapOffsets.append(absoluteScrollOffset);
+ }
+ }
+ }
+
+ if (!horizontalSnapOffsets.isEmpty()) {
+ adjustAxisSnapOffsetsForScrollExtent(horizontalSnapOffsets, maxScrollLeft);
+#if !LOG_DISABLED
+ LOG(Scrolling, " => Computed horizontal scroll snap offsets: %s", snapOffsetsToString(horizontalSnapOffsets).utf8().data());
+ LOG(Scrolling, " => Computed horizontal scroll snap offset ranges: %s", snapOffsetRangesToString(horizontalSnapOffsetRanges).utf8().data());
+#endif
+ if (scrollSnapType.strictness == ScrollSnapStrictness::Proximity)
+ computeAxisProximitySnapOffsetRanges(horizontalSnapOffsets, horizontalSnapOffsetRanges, scrollSnapPort.width());
+
+ scrollableArea.setHorizontalSnapOffsets(horizontalSnapOffsets);
+ scrollableArea.setHorizontalSnapOffsetRanges(horizontalSnapOffsetRanges);
+ } else
+ scrollableArea.clearHorizontalSnapOffsets();
+
+ if (!verticalSnapOffsets.isEmpty()) {
+ adjustAxisSnapOffsetsForScrollExtent(verticalSnapOffsets, maxScrollTop);
+#if !LOG_DISABLED
+ LOG(Scrolling, " => Computed vertical scroll snap offsets: %s", snapOffsetsToString(verticalSnapOffsets).utf8().data());
+ LOG(Scrolling, " => Computed vertical scroll snap offset ranges: %s", snapOffsetRangesToString(verticalSnapOffsetRanges).utf8().data());
+#endif
+ if (scrollSnapType.strictness == ScrollSnapStrictness::Proximity)
+ computeAxisProximitySnapOffsetRanges(verticalSnapOffsets, verticalSnapOffsetRanges, scrollSnapPort.height());
+
+ scrollableArea.setVerticalSnapOffsets(verticalSnapOffsets);
+ scrollableArea.setVerticalSnapOffsetRanges(verticalSnapOffsetRanges);
+ } else
+ scrollableArea.clearVerticalSnapOffsets();
+}
+
+template <typename LayoutType>
+LayoutType closestSnapOffset(const Vector<LayoutType>& snapOffsets, const Vector<ScrollOffsetRange<LayoutType>>& snapOffsetRanges, LayoutType scrollDestination, float velocity, unsigned& activeSnapIndex)
+{
+ ASSERT(snapOffsets.size());
+ activeSnapIndex = 0;
+
+ unsigned lowerSnapOffsetRangeIndex;
+ unsigned upperSnapOffsetRangeIndex;
+ indicesOfNearestSnapOffsetRanges<LayoutType>(scrollDestination, snapOffsetRanges, lowerSnapOffsetRangeIndex, upperSnapOffsetRangeIndex);
+ if (lowerSnapOffsetRangeIndex == upperSnapOffsetRangeIndex && upperSnapOffsetRangeIndex != invalidSnapOffsetIndex) {
+ activeSnapIndex = invalidSnapOffsetIndex;
+ return scrollDestination;
+ }
+
+ if (scrollDestination <= snapOffsets.first())
+ return snapOffsets.first();
+
+ activeSnapIndex = snapOffsets.size() - 1;
+ if (scrollDestination >= snapOffsets.last())
+ return snapOffsets.last();
+
+ unsigned lowerIndex;
+ unsigned upperIndex;
+ indicesOfNearestSnapOffsets<LayoutType>(scrollDestination, snapOffsets, lowerIndex, upperIndex);
+ LayoutType lowerSnapPosition = snapOffsets[lowerIndex];
+ LayoutType upperSnapPosition = snapOffsets[upperIndex];
+ if (!std::abs(velocity)) {
+ bool isCloserToLowerSnapPosition = scrollDestination - lowerSnapPosition <= upperSnapPosition - scrollDestination;
+ activeSnapIndex = isCloserToLowerSnapPosition ? lowerIndex : upperIndex;
+ return isCloserToLowerSnapPosition ? lowerSnapPosition : upperSnapPosition;
+ }
+
+ // Non-zero velocity indicates a flick gesture. Even if another snap point is closer, we should choose the one in the direction of the flick gesture
+ // as long as a scroll snap offset range does not lie between the scroll destination and the targeted snap offset.
+ if (velocity < 0) {
+ if (lowerSnapOffsetRangeIndex != invalidSnapOffsetIndex && lowerSnapPosition < snapOffsetRanges[lowerSnapOffsetRangeIndex].end) {
+ activeSnapIndex = upperIndex;
+ return upperSnapPosition;
+ }
+ activeSnapIndex = lowerIndex;
+ return lowerSnapPosition;
+ }
+
+ if (upperSnapOffsetRangeIndex != invalidSnapOffsetIndex && snapOffsetRanges[upperSnapOffsetRangeIndex].start < upperSnapPosition) {
+ activeSnapIndex = lowerIndex;
+ return lowerSnapPosition;
+ }
+ activeSnapIndex = upperIndex;
+ return upperSnapPosition;
+}
+
+LayoutUnit closestSnapOffset(const Vector<LayoutUnit>& snapOffsets, const Vector<ScrollOffsetRange<LayoutUnit>>& snapOffsetRanges, LayoutUnit scrollDestination, float velocity, unsigned& activeSnapIndex)
+{
+ return closestSnapOffset<LayoutUnit>(snapOffsets, snapOffsetRanges, scrollDestination, velocity, activeSnapIndex);
+}
+
+float closestSnapOffset(const Vector<float>& snapOffsets, const Vector<ScrollOffsetRange<float>>& snapOffsetRanges, float scrollDestination, float velocity, unsigned& activeSnapIndex)
+{
+ return closestSnapOffset<float>(snapOffsets, snapOffsetRanges, scrollDestination, velocity, activeSnapIndex);
+}
+
+} // namespace WebCore
+
+#endif // CSS_SCROLL_SNAP
diff --git a/Source/WebCore/page/scrolling/AxisScrollSnapOffsets.h b/Source/WebCore/page/scrolling/AxisScrollSnapOffsets.h
new file mode 100644
index 000000000..6b6b2bc85
--- /dev/null
+++ b/Source/WebCore/page/scrolling/AxisScrollSnapOffsets.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2014-2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(CSS_SCROLL_SNAP)
+
+#include "LayoutUnit.h"
+#include "ScrollSnapOffsetsInfo.h"
+#include "ScrollTypes.h"
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class HTMLElement;
+class RenderBox;
+class RenderStyle;
+class ScrollableArea;
+
+void updateSnapOffsetsForScrollableArea(ScrollableArea&, HTMLElement& scrollingElement, const RenderBox& scrollingElementBox, const RenderStyle& scrollingElementStyle);
+
+const unsigned invalidSnapOffsetIndex = UINT_MAX;
+WEBCORE_EXPORT LayoutUnit closestSnapOffset(const Vector<LayoutUnit>& snapOffsets, const Vector<ScrollOffsetRange<LayoutUnit>>& snapOffsetRanges, LayoutUnit scrollDestination, float velocity, unsigned& activeSnapIndex);
+WEBCORE_EXPORT float closestSnapOffset(const Vector<float>& snapOffsets, const Vector<ScrollOffsetRange<float>>& snapOffsetRanges, float scrollDestination, float velocity, unsigned& activeSnapIndex);
+
+} // namespace WebCore
+
+#endif // ENABLE(CSS_SCROLL_SNAP)
diff --git a/Source/WebCore/page/scrolling/ScrollLatchingState.cpp b/Source/WebCore/page/scrolling/ScrollLatchingState.cpp
new file mode 100644
index 000000000..01e6529b0
--- /dev/null
+++ b/Source/WebCore/page/scrolling/ScrollLatchingState.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ScrollLatchingState.h"
+
+#include "Element.h"
+
+namespace WebCore {
+
+ScrollLatchingState::ScrollLatchingState()
+{
+}
+
+ScrollLatchingState::~ScrollLatchingState()
+{
+}
+
+void ScrollLatchingState::clear()
+{
+ m_wheelEventElement = nullptr;
+ m_frame = nullptr;
+ m_scrollableContainer = nullptr;
+ m_widgetIsLatched = false;
+ m_previousWheelScrolledElement = nullptr;
+}
+
+void ScrollLatchingState::setWheelEventElement(Element* element)
+{
+ m_wheelEventElement = element;
+}
+
+void ScrollLatchingState::setWidgetIsLatched(bool isOverWidget)
+{
+ m_widgetIsLatched = isOverWidget;
+}
+
+void ScrollLatchingState::setPreviousWheelScrolledElement(Element* element)
+{
+ m_previousWheelScrolledElement = element;
+}
+
+void ScrollLatchingState::setScrollableContainer(ContainerNode* container)
+{
+ m_scrollableContainer = container;
+}
+
+}
diff --git a/Source/WebCore/page/scrolling/ScrollLatchingState.h b/Source/WebCore/page/scrolling/ScrollLatchingState.h
new file mode 100644
index 000000000..11dcbd0db
--- /dev/null
+++ b/Source/WebCore/page/scrolling/ScrollLatchingState.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class ContainerNode;
+class Element;
+class Frame;
+
+class ScrollLatchingState final {
+public:
+ ScrollLatchingState();
+ ~ScrollLatchingState();
+
+ void clear();
+
+ Element* wheelEventElement() { return m_wheelEventElement.get(); }
+ void setWheelEventElement(Element*);
+ Frame* frame() { return m_frame; }
+ void setFrame(Frame* frame) { m_frame = frame; }
+
+ bool widgetIsLatched() const { return m_widgetIsLatched; }
+ void setWidgetIsLatched(bool isOverWidget);
+
+ Element* previousWheelScrolledElement() { return m_previousWheelScrolledElement.get(); }
+ void setPreviousWheelScrolledElement(Element*);
+
+ ContainerNode* scrollableContainer() { return m_scrollableContainer.get(); }
+ void setScrollableContainer(ContainerNode*);
+ bool startedGestureAtScrollLimit() const { return m_startedGestureAtScrollLimit; }
+ void setStartedGestureAtScrollLimit(bool startedAtLimit) { m_startedGestureAtScrollLimit = startedAtLimit; }
+
+private:
+ RefPtr<Element> m_wheelEventElement;
+ RefPtr<Element> m_previousWheelScrolledElement;
+ RefPtr<ContainerNode> m_scrollableContainer;
+
+ Frame* m_frame { nullptr };
+
+ bool m_widgetIsLatched { false };
+ bool m_startedGestureAtScrollLimit { false };
+};
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/scrolling/ScrollSnapOffsetsInfo.h b/Source/WebCore/page/scrolling/ScrollSnapOffsetsInfo.h
new file mode 100644
index 000000000..63bd9638b
--- /dev/null
+++ b/Source/WebCore/page/scrolling/ScrollSnapOffsetsInfo.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+template <typename T>
+struct ScrollOffsetRange {
+ T start;
+ T end;
+};
+
+template <typename T>
+struct ScrollSnapOffsetsInfo {
+ Vector<T> horizontalSnapOffsets;
+ Vector<T> verticalSnapOffsets;
+
+ // Snap offset ranges represent non-empty ranges of scroll offsets in which scrolling may rest after scroll snapping.
+ // These are used in two cases: (1) for proximity scroll snapping, where portions of areas between adjacent snap offsets
+ // may emit snap offset ranges, and (2) in the case where the snap area is larger than the snap port, in which case areas
+ // where the snap port fits within the snap area are considered to be valid snap positions.
+ Vector<ScrollOffsetRange<T>> horizontalSnapOffsetRanges;
+ Vector<ScrollOffsetRange<T>> verticalSnapOffsetRanges;
+};
+
+}; // namespace WebCore
diff --git a/Source/WebCore/page/scrolling/ScrollingConstraints.cpp b/Source/WebCore/page/scrolling/ScrollingConstraints.cpp
index 4b3f4d68c..00f101a34 100644
--- a/Source/WebCore/page/scrolling/ScrollingConstraints.cpp
+++ b/Source/WebCore/page/scrolling/ScrollingConstraints.cpp
@@ -26,6 +26,8 @@
#include "config.h"
#include "ScrollingConstraints.h"
+#include "TextStream.h"
+
namespace WebCore {
FloatPoint FixedPositionViewportConstraints::layerPositionForViewportRect(const FloatRect& viewportRect) const
@@ -98,4 +100,20 @@ FloatPoint StickyPositionViewportConstraints::layerPositionForConstrainingRect(c
return m_layerPositionAtLastLayout + offset - m_stickyOffsetAtLastLayout;
}
+TextStream& operator<<(TextStream& ts, const FixedPositionViewportConstraints& constraints)
+{
+ ts.dumpProperty("viewport-rect-at-last-layout", constraints.viewportRectAtLastLayout());
+ ts.dumpProperty("layer-position-at-last-layout", constraints.layerPositionAtLastLayout());
+
+ return ts;
+}
+
+TextStream& operator<<(TextStream& ts, const StickyPositionViewportConstraints& constraints)
+{
+ ts.dumpProperty("sticky-position-at-last-layout", constraints.stickyOffsetAtLastLayout());
+ ts.dumpProperty("layer-position-at-last-layout", constraints.layerPositionAtLastLayout());
+
+ return ts;
+}
+
} // namespace WebCore
diff --git a/Source/WebCore/page/scrolling/ScrollingConstraints.h b/Source/WebCore/page/scrolling/ScrollingConstraints.h
index d4c1dd461..9d3860062 100644
--- a/Source/WebCore/page/scrolling/ScrollingConstraints.h
+++ b/Source/WebCore/page/scrolling/ScrollingConstraints.h
@@ -23,8 +23,7 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ScrollingConstraints_h
-#define ScrollingConstraints_h
+#pragma once
#include "FloatRect.h"
@@ -33,6 +32,7 @@ namespace WebCore {
// ViewportConstraints classes encapsulate data and logic required to reposition elements whose layout
// depends on the viewport rect (positions fixed and sticky), when scrolling and zooming.
class ViewportConstraints {
+ WTF_MAKE_FAST_ALLOCATED;
public:
enum ConstraintType {
FixedPositionConstraint,
@@ -85,7 +85,7 @@ public:
, m_layerPositionAtLastLayout(other.m_layerPositionAtLastLayout)
{ }
- FloatPoint layerPositionForViewportRect(const FloatRect& viewportRect) const;
+ WEBCORE_EXPORT FloatPoint layerPositionForViewportRect(const FloatRect& viewportRect) const;
const FloatRect& viewportRectAtLastLayout() const { return m_viewportRectAtLastLayout; }
void setViewportRectAtLastLayout(const FloatRect& rect) { m_viewportRectAtLastLayout = rect; }
@@ -104,7 +104,7 @@ public:
bool operator!=(const FixedPositionViewportConstraints& other) const { return !(*this == other); }
private:
- virtual ConstraintType constraintType() const override { return FixedPositionConstraint; };
+ ConstraintType constraintType() const override { return FixedPositionConstraint; };
FloatRect m_viewportRectAtLastLayout;
FloatPoint m_layerPositionAtLastLayout;
@@ -137,7 +137,7 @@ public:
const FloatSize stickyOffsetAtLastLayout() const { return m_stickyOffsetAtLastLayout; }
void setStickyOffsetAtLastLayout(const FloatSize& offset) { m_stickyOffsetAtLastLayout = offset; }
- FloatPoint layerPositionForConstrainingRect(const FloatRect& constrainingRect) const;
+ WEBCORE_EXPORT FloatPoint layerPositionForConstrainingRect(const FloatRect& constrainingRect) const;
const FloatPoint& layerPositionAtLastLayout() const { return m_layerPositionAtLastLayout; }
void setLayerPositionAtLastLayout(const FloatPoint& point) { m_layerPositionAtLastLayout = point; }
@@ -167,7 +167,9 @@ public:
bool operator==(const StickyPositionViewportConstraints& other) const
{
- return m_leftOffset == other.m_leftOffset
+ return m_alignmentOffset == other.m_alignmentOffset
+ && m_anchorEdges == other.m_anchorEdges
+ && m_leftOffset == other.m_leftOffset
&& m_rightOffset == other.m_rightOffset
&& m_topOffset == other.m_topOffset
&& m_bottomOffset == other.m_bottomOffset
@@ -180,7 +182,7 @@ public:
bool operator!=(const StickyPositionViewportConstraints& other) const { return !(*this == other); }
private:
- virtual ConstraintType constraintType() const override { return StickyPositionConstraint; };
+ ConstraintType constraintType() const override { return StickyPositionConstraint; };
float m_leftOffset;
float m_rightOffset;
@@ -193,6 +195,7 @@ private:
FloatPoint m_layerPositionAtLastLayout;
};
-} // namespace WebCore
+WEBCORE_EXPORT TextStream& operator<<(TextStream&, const FixedPositionViewportConstraints&);
+WEBCORE_EXPORT TextStream& operator<<(TextStream&, const StickyPositionViewportConstraints&);
-#endif // ScrollingConstraints_h
+} // namespace WebCore
diff --git a/Source/WebCore/page/scrolling/ScrollingCoordinator.cpp b/Source/WebCore/page/scrolling/ScrollingCoordinator.cpp
index 93dfb0cec..ff34266a7 100644
--- a/Source/WebCore/page/scrolling/ScrollingCoordinator.cpp
+++ b/Source/WebCore/page/scrolling/ScrollingCoordinator.cpp
@@ -28,6 +28,7 @@
#include "ScrollingCoordinator.h"
#include "Document.h"
+#include "EventNames.h"
#include "FrameView.h"
#include "GraphicsLayer.h"
#include "IntRect.h"
@@ -36,35 +37,38 @@
#include "PlatformWheelEvent.h"
#include "PluginViewBase.h"
#include "Region.h"
+#include "RenderLayerCompositor.h"
#include "RenderView.h"
#include "ScrollAnimator.h"
+#include "Settings.h"
+#include "TextStream.h"
#include <wtf/MainThread.h>
#include <wtf/text/StringBuilder.h>
-#if USE(ACCELERATED_COMPOSITING)
-#include "RenderLayerCompositor.h"
-#endif
-
#if USE(COORDINATED_GRAPHICS)
#include "ScrollingCoordinatorCoordinatedGraphics.h"
#endif
+#if ENABLE(WEB_REPLAY)
+#include "ReplayController.h"
+#include <replay/InputCursor.h>
+#endif
+
namespace WebCore {
-#if !PLATFORM(MAC)
-PassRefPtr<ScrollingCoordinator> ScrollingCoordinator::create(Page* page)
+#if !PLATFORM(COCOA)
+Ref<ScrollingCoordinator> ScrollingCoordinator::create(Page* page)
{
#if USE(COORDINATED_GRAPHICS)
- return adoptRef(new ScrollingCoordinatorCoordinatedGraphics(page));
+ return adoptRef(*new ScrollingCoordinatorCoordinatedGraphics(page));
#endif
- return adoptRef(new ScrollingCoordinator(page));
+ return adoptRef(*new ScrollingCoordinator(page));
}
#endif
ScrollingCoordinator::ScrollingCoordinator(Page* page)
: m_page(page)
- , m_forceSynchronousScrollLayerPositionUpdates(false)
{
}
@@ -76,88 +80,112 @@ ScrollingCoordinator::~ScrollingCoordinator()
void ScrollingCoordinator::pageDestroyed()
{
ASSERT(m_page);
- m_page = 0;
+ m_page = nullptr;
}
-bool ScrollingCoordinator::coordinatesScrollingForFrameView(FrameView* frameView) const
+bool ScrollingCoordinator::coordinatesScrollingForFrameView(const FrameView& frameView) const
{
ASSERT(isMainThread());
ASSERT(m_page);
- // We currently only handle the main frame.
- if (!frameView->frame().isMainFrame())
+ if (!frameView.frame().isMainFrame() && !m_page->settings().scrollingTreeIncludesFrames())
return false;
- // We currently only support composited mode.
-#if USE(ACCELERATED_COMPOSITING)
RenderView* renderView = m_page->mainFrame().contentRenderer();
if (!renderView)
return false;
return renderView->usesCompositing();
-#else
- return false;
-#endif
}
-Region ScrollingCoordinator::computeNonFastScrollableRegion(const Frame* frame, const IntPoint& frameLocation) const
+EventTrackingRegions ScrollingCoordinator::absoluteEventTrackingRegionsForFrame(const Frame& frame) const
{
- Region nonFastScrollableRegion;
- FrameView* frameView = frame->view();
+ auto* renderView = frame.contentRenderer();
+ if (!renderView || renderView->renderTreeBeingDestroyed())
+ return EventTrackingRegions();
+
+#if ENABLE(IOS_TOUCH_EVENTS)
+ // On iOS, we use nonFastScrollableRegion to represent the region covered by elements with touch event handlers.
+ ASSERT(frame.isMainFrame());
+ auto* document = frame.document();
+ if (!document)
+ return EventTrackingRegions();
+ return document->eventTrackingRegions();
+#else
+ auto* frameView = frame.view();
if (!frameView)
- return nonFastScrollableRegion;
+ return EventTrackingRegions();
- IntPoint offset = frameLocation;
- offset.moveBy(frameView->frameRect().location());
+ Region nonFastScrollableRegion;
- if (const FrameView::ScrollableAreaSet* scrollableAreas = frameView->scrollableAreas()) {
- for (FrameView::ScrollableAreaSet::const_iterator it = scrollableAreas->begin(), end = scrollableAreas->end(); it != end; ++it) {
- ScrollableArea* scrollableArea = *it;
-#if USE(ACCELERATED_COMPOSITING)
+ // FIXME: should ASSERT(!frameView->needsLayout()) here, but need to fix DebugPageOverlays
+ // to not ask for regions at bad times.
+
+ if (auto* scrollableAreas = frameView->scrollableAreas()) {
+ for (auto& scrollableArea : *scrollableAreas) {
// Composited scrollable areas can be scrolled off the main thread.
- if (scrollableArea->usesCompositedScrolling())
+ if (scrollableArea->usesAsyncScrolling())
continue;
-#endif
- IntRect box = scrollableArea->scrollableAreaBoundingBox();
- box.moveBy(offset);
+
+ bool isInsideFixed;
+ IntRect box = scrollableArea->scrollableAreaBoundingBox(&isInsideFixed);
+ if (isInsideFixed)
+ box = IntRect(frameView->fixedScrollableAreaBoundsInflatedForScrolling(LayoutRect(box)));
+
nonFastScrollableRegion.unite(box);
}
}
- for (auto it = frameView->children().begin(), end = frameView->children().end(); it != end; ++it) {
- if (!(*it)->isPluginViewBase())
+ for (auto& widget : frameView->widgetsInRenderTree()) {
+ if (!is<PluginViewBase>(*widget))
+ continue;
+ if (!downcast<PluginViewBase>(*widget).wantsWheelEvents())
+ continue;
+ auto* renderWidget = RenderWidget::find(*widget);
+ if (!renderWidget)
continue;
- PluginViewBase* pluginViewBase = toPluginViewBase((*it).get());
- if (pluginViewBase->wantsWheelEvents())
- nonFastScrollableRegion.unite(pluginViewBase->frameRect());
+ nonFastScrollableRegion.unite(renderWidget->absoluteBoundingBoxRect());
}
+
+ EventTrackingRegions eventTrackingRegions;
- for (Frame* subframe = frame->tree().firstChild(); subframe; subframe = subframe->tree().nextSibling())
- nonFastScrollableRegion.unite(computeNonFastScrollableRegion(subframe, offset));
+ // FIXME: if we've already accounted for this subframe as a scrollable area, we can avoid recursing into it here.
+ for (Frame* subframe = frame.tree().firstChild(); subframe; subframe = subframe->tree().nextSibling()) {
+ auto* subframeView = subframe->view();
+ if (!subframeView)
+ continue;
- return nonFastScrollableRegion;
-}
+ EventTrackingRegions subframeRegion = absoluteEventTrackingRegionsForFrame(*subframe);
+ // Map from the frame document to our document.
+ IntPoint offset = subframeView->contentsToContainingViewContents(IntPoint());
-unsigned ScrollingCoordinator::computeCurrentWheelEventHandlerCount()
-{
- unsigned wheelEventHandlerCount = 0;
+ // FIXME: this translation ignores non-trival transforms on the frame.
+ subframeRegion.translate(toIntSize(offset));
+ eventTrackingRegions.unite(subframeRegion);
+ }
- for (Frame* frame = &m_page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
- if (frame->document())
- wheelEventHandlerCount += frame->document()->wheelEventHandlerCount();
+ auto wheelHandlerRegion = frame.document()->absoluteRegionForEventTargets(frame.document()->wheelEventTargets());
+ bool wheelHandlerInFixedContent = wheelHandlerRegion.second;
+ if (wheelHandlerInFixedContent) {
+ // FIXME: need to handle position:sticky here too.
+ LayoutRect inflatedWheelHandlerBounds = frameView->fixedScrollableAreaBoundsInflatedForScrolling(LayoutRect(wheelHandlerRegion.first.bounds()));
+ wheelHandlerRegion.first.unite(enclosingIntRect(inflatedWheelHandlerBounds));
}
+
+ nonFastScrollableRegion.unite(wheelHandlerRegion.first);
+
+ // FIXME: If this is not the main frame, we could clip the region to the frame's bounds.
+ eventTrackingRegions.uniteSynchronousRegion(eventNames().wheelEvent, nonFastScrollableRegion);
- return wheelEventHandlerCount;
+ return eventTrackingRegions;
+#endif
}
-void ScrollingCoordinator::frameViewWheelEventHandlerCountChanged(FrameView* frameView)
+EventTrackingRegions ScrollingCoordinator::absoluteEventTrackingRegions() const
{
- ASSERT(isMainThread());
- ASSERT(m_page);
-
- recomputeWheelEventHandlerCountForFrameView(frameView);
+ return absoluteEventTrackingRegionsForFrame(m_page->mainFrame());
}
-void ScrollingCoordinator::frameViewHasSlowRepaintObjectsDidChange(FrameView* frameView)
+void ScrollingCoordinator::frameViewHasSlowRepaintObjectsDidChange(FrameView& frameView)
{
ASSERT(isMainThread());
ASSERT(m_page);
@@ -165,10 +193,10 @@ void ScrollingCoordinator::frameViewHasSlowRepaintObjectsDidChange(FrameView* fr
if (!coordinatesScrollingForFrameView(frameView))
return;
- updateSynchronousScrollingReasons();
+ updateSynchronousScrollingReasons(frameView);
}
-void ScrollingCoordinator::frameViewFixedObjectsDidChange(FrameView* frameView)
+void ScrollingCoordinator::frameViewFixedObjectsDidChange(FrameView& frameView)
{
ASSERT(isMainThread());
ASSERT(m_page);
@@ -176,75 +204,80 @@ void ScrollingCoordinator::frameViewFixedObjectsDidChange(FrameView* frameView)
if (!coordinatesScrollingForFrameView(frameView))
return;
- updateSynchronousScrollingReasons();
+ updateSynchronousScrollingReasons(frameView);
}
-#if USE(ACCELERATED_COMPOSITING)
-GraphicsLayer* ScrollingCoordinator::scrollLayerForScrollableArea(ScrollableArea* scrollableArea)
+GraphicsLayer* ScrollingCoordinator::scrollLayerForScrollableArea(ScrollableArea& scrollableArea)
{
- return scrollableArea->layerForScrolling();
+ return scrollableArea.layerForScrolling();
}
-GraphicsLayer* ScrollingCoordinator::horizontalScrollbarLayerForScrollableArea(ScrollableArea* scrollableArea)
+GraphicsLayer* ScrollingCoordinator::scrollLayerForFrameView(FrameView& frameView)
{
- return scrollableArea->layerForHorizontalScrollbar();
-}
-
-GraphicsLayer* ScrollingCoordinator::verticalScrollbarLayerForScrollableArea(ScrollableArea* scrollableArea)
-{
- return scrollableArea->layerForVerticalScrollbar();
-}
-#endif
-
-GraphicsLayer* ScrollingCoordinator::scrollLayerForFrameView(FrameView* frameView)
-{
-#if USE(ACCELERATED_COMPOSITING)
- if (RenderView* renderView = frameView->frame().contentRenderer())
+ if (RenderView* renderView = frameView.frame().contentRenderer())
return renderView->compositor().scrollLayer();
- return 0;
-#else
- UNUSED_PARAM(frameView);
- return 0;
-#endif
+ return nullptr;
}
-GraphicsLayer* ScrollingCoordinator::headerLayerForFrameView(FrameView* frameView)
+GraphicsLayer* ScrollingCoordinator::headerLayerForFrameView(FrameView& frameView)
{
-#if USE(ACCELERATED_COMPOSITING) && ENABLE(RUBBER_BANDING)
- if (RenderView* renderView = frameView->frame().contentRenderer())
- renderView->compositor().headerLayer();
- return 0;
+#if ENABLE(RUBBER_BANDING)
+ if (RenderView* renderView = frameView.frame().contentRenderer())
+ return renderView->compositor().headerLayer();
+ return nullptr;
#else
UNUSED_PARAM(frameView);
- return 0;
+ return nullptr;
#endif
}
-GraphicsLayer* ScrollingCoordinator::footerLayerForFrameView(FrameView* frameView)
+GraphicsLayer* ScrollingCoordinator::footerLayerForFrameView(FrameView& frameView)
{
-#if USE(ACCELERATED_COMPOSITING) && ENABLE(RUBBER_BANDING)
- if (RenderView* renderView = frameView->frame().contentRenderer())
+#if ENABLE(RUBBER_BANDING)
+ if (RenderView* renderView = frameView.frame().contentRenderer())
return renderView->compositor().footerLayer();
- return 0;
+ return nullptr;
#else
UNUSED_PARAM(frameView);
- return 0;
+ return nullptr;
#endif
}
-GraphicsLayer* ScrollingCoordinator::counterScrollingLayerForFrameView(FrameView* frameView)
+GraphicsLayer* ScrollingCoordinator::counterScrollingLayerForFrameView(FrameView& frameView)
{
-#if USE(ACCELERATED_COMPOSITING)
- if (RenderView* renderView = frameView->frame().contentRenderer())
+ if (RenderView* renderView = frameView.frame().contentRenderer())
return renderView->compositor().fixedRootBackgroundLayer();
- return 0;
+ return nullptr;
+}
+
+GraphicsLayer* ScrollingCoordinator::insetClipLayerForFrameView(FrameView& frameView)
+{
+ if (RenderView* renderView = frameView.frame().contentRenderer())
+ return renderView->compositor().clipLayer();
+ return nullptr;
+}
+
+GraphicsLayer* ScrollingCoordinator::contentShadowLayerForFrameView(FrameView& frameView)
+{
+#if ENABLE(RUBBER_BANDING)
+ if (RenderView* renderView = frameView.frame().contentRenderer())
+ return renderView->compositor().layerForContentShadow();
+
+ return nullptr;
#else
UNUSED_PARAM(frameView);
- return 0;
+ return nullptr;
#endif
}
-void ScrollingCoordinator::frameViewRootLayerDidChange(FrameView* frameView)
+GraphicsLayer* ScrollingCoordinator::rootContentLayerForFrameView(FrameView& frameView)
+{
+ if (RenderView* renderView = frameView.frame().contentRenderer())
+ return renderView->compositor().rootContentLayer();
+ return nullptr;
+}
+
+void ScrollingCoordinator::frameViewRootLayerDidChange(FrameView& frameView)
{
ASSERT(isMainThread());
ASSERT(m_page);
@@ -253,11 +286,10 @@ void ScrollingCoordinator::frameViewRootLayerDidChange(FrameView* frameView)
return;
frameViewLayoutUpdated(frameView);
- recomputeWheelEventHandlerCountForFrameView(frameView);
- updateSynchronousScrollingReasons();
+ updateSynchronousScrollingReasons(frameView);
}
-#if PLATFORM(MAC)
+#if PLATFORM(COCOA)
void ScrollingCoordinator::handleWheelEventPhase(PlatformWheelEventPhase phase)
{
ASSERT(isMainThread());
@@ -269,57 +301,58 @@ void ScrollingCoordinator::handleWheelEventPhase(PlatformWheelEventPhase phase)
if (!frameView)
return;
- frameView->scrollAnimator()->handleWheelEventPhase(phase);
+ frameView->scrollAnimator().handleWheelEventPhase(phase);
}
#endif
-bool ScrollingCoordinator::hasVisibleSlowRepaintViewportConstrainedObjects(FrameView* frameView) const
+bool ScrollingCoordinator::hasVisibleSlowRepaintViewportConstrainedObjects(const FrameView& frameView) const
{
- const FrameView::ViewportConstrainedObjectSet* viewportConstrainedObjects = frameView->viewportConstrainedObjects();
+ const FrameView::ViewportConstrainedObjectSet* viewportConstrainedObjects = frameView.viewportConstrainedObjects();
if (!viewportConstrainedObjects)
return false;
-#if USE(ACCELERATED_COMPOSITING)
- for (FrameView::ViewportConstrainedObjectSet::const_iterator it = viewportConstrainedObjects->begin(), end = viewportConstrainedObjects->end(); it != end; ++it) {
- RenderObject* viewportConstrainedObject = *it;
- if (!viewportConstrainedObject->isBoxModelObject() || !viewportConstrainedObject->hasLayer())
+ for (auto& viewportConstrainedObject : *viewportConstrainedObjects) {
+ if (!is<RenderBoxModelObject>(*viewportConstrainedObject) || !viewportConstrainedObject->hasLayer())
return true;
- RenderLayer* layer = toRenderBoxModelObject(viewportConstrainedObject)->layer();
+ RenderLayer& layer = *downcast<RenderBoxModelObject>(*viewportConstrainedObject).layer();
// Any explicit reason that a fixed position element is not composited shouldn't cause slow scrolling.
- if (!layer->isComposited() && layer->viewportConstrainedNotCompositedReason() == RenderLayer::NoNotCompositedReason)
+ if (!layer.isComposited() && layer.viewportConstrainedNotCompositedReason() == RenderLayer::NoNotCompositedReason)
return true;
}
return false;
-#else
- return viewportConstrainedObjects->size();
-#endif
}
-SynchronousScrollingReasons ScrollingCoordinator::synchronousScrollingReasons() const
+SynchronousScrollingReasons ScrollingCoordinator::synchronousScrollingReasons(const FrameView& frameView) const
{
- FrameView* frameView = m_page->mainFrame().view();
- if (!frameView)
- return static_cast<SynchronousScrollingReasons>(0);
-
SynchronousScrollingReasons synchronousScrollingReasons = (SynchronousScrollingReasons)0;
if (m_forceSynchronousScrollLayerPositionUpdates)
synchronousScrollingReasons |= ForcedOnMainThread;
- if (frameView->hasSlowRepaintObjects())
+#if ENABLE(WEB_REPLAY)
+ InputCursor& cursor = m_page->replayController().activeInputCursor();
+ if (cursor.isCapturing() || cursor.isReplaying())
+ synchronousScrollingReasons |= ForcedOnMainThread;
+#endif
+ if (frameView.hasSlowRepaintObjects())
synchronousScrollingReasons |= HasSlowRepaintObjects;
- if (!supportsFixedPositionLayers() && frameView->hasViewportConstrainedObjects())
+ if (!supportsFixedPositionLayers() && frameView.hasViewportConstrainedObjects())
synchronousScrollingReasons |= HasViewportConstrainedObjectsWithoutSupportingFixedLayers;
if (supportsFixedPositionLayers() && hasVisibleSlowRepaintViewportConstrainedObjects(frameView))
synchronousScrollingReasons |= HasNonLayerViewportConstrainedObjects;
- if (m_page->mainFrame().document() && m_page->mainFrame().document()->isImageDocument())
+ if (frameView.frame().mainFrame().document() && frameView.frame().document()->isImageDocument())
synchronousScrollingReasons |= IsImageDocument;
return synchronousScrollingReasons;
}
-void ScrollingCoordinator::updateSynchronousScrollingReasons()
+void ScrollingCoordinator::updateSynchronousScrollingReasons(const FrameView& frameView)
{
- setSynchronousScrollingReasons(synchronousScrollingReasons());
+ // FIXME: Once we support async scrolling of iframes, we'll have to track the synchronous scrolling
+ // reasons per frame (maybe on scrolling tree nodes).
+ if (!frameView.frame().isMainFrame())
+ return;
+
+ setSynchronousScrollingReasons(synchronousScrollingReasons(frameView));
}
void ScrollingCoordinator::setForceSynchronousScrollLayerPositionUpdates(bool forceSynchronousScrollLayerPositionUpdates)
@@ -328,9 +361,27 @@ void ScrollingCoordinator::setForceSynchronousScrollLayerPositionUpdates(bool fo
return;
m_forceSynchronousScrollLayerPositionUpdates = forceSynchronousScrollLayerPositionUpdates;
- updateSynchronousScrollingReasons();
+ if (FrameView* frameView = m_page->mainFrame().view())
+ updateSynchronousScrollingReasons(*frameView);
}
+bool ScrollingCoordinator::shouldUpdateScrollLayerPositionSynchronously(const FrameView& frameView) const
+{
+ if (&frameView == m_page->mainFrame().view())
+ return synchronousScrollingReasons(frameView);
+
+ return true;
+}
+
+#if ENABLE(WEB_REPLAY)
+void ScrollingCoordinator::replaySessionStateDidChange()
+{
+ // FIXME: Once we support async scrolling of iframes, this should go through all subframes.
+ if (FrameView* frameView = m_page->mainFrame().view())
+ updateSynchronousScrollingReasons(*frameView);
+}
+#endif
+
ScrollingNodeID ScrollingCoordinator::uniqueScrollLayerID()
{
static ScrollingNodeID uniqueScrollLayerID = 1;
@@ -347,15 +398,15 @@ String ScrollingCoordinator::synchronousScrollingReasonsAsText(SynchronousScroll
StringBuilder stringBuilder;
if (reasons & ScrollingCoordinator::ForcedOnMainThread)
- stringBuilder.append("Forced on main thread, ");
+ stringBuilder.appendLiteral("Forced on main thread, ");
if (reasons & ScrollingCoordinator::HasSlowRepaintObjects)
- stringBuilder.append("Has slow repaint objects, ");
+ stringBuilder.appendLiteral("Has slow repaint objects, ");
if (reasons & ScrollingCoordinator::HasViewportConstrainedObjectsWithoutSupportingFixedLayers)
- stringBuilder.append("Has viewport constrained objects without supporting fixed layers, ");
+ stringBuilder.appendLiteral("Has viewport constrained objects without supporting fixed layers, ");
if (reasons & ScrollingCoordinator::HasNonLayerViewportConstrainedObjects)
- stringBuilder.append("Has non-layer viewport-constrained objects, ");
+ stringBuilder.appendLiteral("Has non-layer viewport-constrained objects, ");
if (reasons & ScrollingCoordinator::IsImageDocument)
- stringBuilder.append("Is image document, ");
+ stringBuilder.appendLiteral("Is image document, ");
if (stringBuilder.length())
stringBuilder.resize(stringBuilder.length() - 2);
@@ -364,7 +415,45 @@ String ScrollingCoordinator::synchronousScrollingReasonsAsText(SynchronousScroll
String ScrollingCoordinator::synchronousScrollingReasonsAsText() const
{
- return synchronousScrollingReasonsAsText(synchronousScrollingReasons());
+ if (FrameView* frameView = m_page->mainFrame().view())
+ return synchronousScrollingReasonsAsText(synchronousScrollingReasons(*frameView));
+
+ return String();
+}
+
+TextStream& operator<<(TextStream& ts, ScrollingNodeType nodeType)
+{
+ switch (nodeType) {
+ case FrameScrollingNode:
+ ts << "frame-scrolling";
+ break;
+ case OverflowScrollingNode:
+ ts << "overflow-scrolling";
+ break;
+ case FixedNode:
+ ts << "fixed";
+ break;
+ case StickyNode:
+ ts << "sticky";
+ break;
+ }
+ return ts;
+}
+
+TextStream& operator<<(TextStream& ts, ScrollingLayerPositionAction action)
+{
+ switch (action) {
+ case ScrollingLayerPositionAction::Set:
+ ts << "set";
+ break;
+ case ScrollingLayerPositionAction::SetApproximate:
+ ts << "set approximate";
+ break;
+ case ScrollingLayerPositionAction::Sync:
+ ts << "sync";
+ break;
+ }
+ return ts;
}
} // namespace WebCore
diff --git a/Source/WebCore/page/scrolling/ScrollingCoordinator.h b/Source/WebCore/page/scrolling/ScrollingCoordinator.h
index 0e05d69fd..eb6dabf97 100644
--- a/Source/WebCore/page/scrolling/ScrollingCoordinator.h
+++ b/Source/WebCore/page/scrolling/ScrollingCoordinator.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -23,15 +23,18 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ScrollingCoordinator_h
-#define ScrollingCoordinator_h
+#pragma once
+#include "EventTrackingRegions.h"
#include "IntRect.h"
#include "LayoutRect.h"
#include "PlatformWheelEvent.h"
-#include "RenderObject.h"
+#include "ScrollSnapOffsetsInfo.h"
#include "ScrollTypes.h"
#include <wtf/Forward.h>
+#include <wtf/ThreadSafeRefCounted.h>
+#include <wtf/TypeCasts.h>
+#include <wtf/Variant.h>
#if ENABLE(ASYNC_SCROLLING)
#include <wtf/HashMap.h>
@@ -39,8 +42,8 @@
#include <wtf/Threading.h>
#endif
-#if PLATFORM(MAC)
-#include <wtf/RetainPtr.h>
+#if ENABLE(CSS_SCROLL_SNAP)
+#include "AxisScrollSnapOffsets.h"
#endif
namespace WebCore {
@@ -48,7 +51,7 @@ namespace WebCore {
typedef unsigned SynchronousScrollingReasons;
typedef uint64_t ScrollingNodeID;
-enum ScrollingNodeType { ScrollingNode, FixedNode, StickyNode };
+enum ScrollingNodeType { FrameScrollingNode, OverflowScrollingNode, FixedNode, StickyNode };
class Document;
class Frame;
@@ -57,15 +60,17 @@ class GraphicsLayer;
class Page;
class Region;
class ScrollableArea;
+class TextStream;
class ViewportConstraints;
#if ENABLE(ASYNC_SCROLLING)
class ScrollingTree;
#endif
-enum SetOrSyncScrollingLayerPosition {
- SetScrollingLayerPosition,
- SyncScrollingLayerPosition
+enum class ScrollingLayerPositionAction {
+ Set,
+ SetApproximate,
+ Sync
};
struct ScrollableAreaParameters {
@@ -101,114 +106,145 @@ struct ScrollableAreaParameters {
class ScrollingCoordinator : public ThreadSafeRefCounted<ScrollingCoordinator> {
public:
- static PassRefPtr<ScrollingCoordinator> create(Page*);
+ static Ref<ScrollingCoordinator> create(Page*);
virtual ~ScrollingCoordinator();
- virtual void pageDestroyed();
+ WEBCORE_EXPORT virtual void pageDestroyed();
virtual bool isAsyncScrollingCoordinator() const { return false; }
virtual bool isRemoteScrollingCoordinator() const { return false; }
// Return whether this scrolling coordinator handles scrolling for the given frame view.
- bool coordinatesScrollingForFrameView(FrameView*) const;
+ virtual bool coordinatesScrollingForFrameView(const FrameView&) const;
// Should be called whenever the given frame view has been laid out.
- virtual void frameViewLayoutUpdated(FrameView*) { }
+ virtual void frameViewLayoutUpdated(FrameView&) { }
- // Should be called whenever a wheel event handler is added or removed in the
- // frame view's underlying document.
- void frameViewWheelEventHandlerCountChanged(FrameView*);
+ using LayoutViewportOriginOrOverrideRect = WTF::Variant<std::optional<FloatPoint>, std::optional<FloatRect>>;
+ virtual void reconcileScrollingState(FrameView&, const FloatPoint&, const LayoutViewportOriginOrOverrideRect&, bool /* programmaticScroll */, bool /* inStableState*/, ScrollingLayerPositionAction) { }
// Should be called whenever the slow repaint objects counter changes between zero and one.
- void frameViewHasSlowRepaintObjectsDidChange(FrameView*);
+ void frameViewHasSlowRepaintObjectsDidChange(FrameView&);
// Should be called whenever the set of fixed objects changes.
- void frameViewFixedObjectsDidChange(FrameView*);
+ void frameViewFixedObjectsDidChange(FrameView&);
+
+ // Called whenever the non-fast scrollable region changes for reasons other than layout.
+ virtual void frameViewEventTrackingRegionsChanged(FrameView&) { }
// Should be called whenever the root layer for the given frame view changes.
- virtual void frameViewRootLayerDidChange(FrameView*);
+ virtual void frameViewRootLayerDidChange(FrameView&);
// Return whether this scrolling coordinator can keep fixed position layers fixed to their
// containers while scrolling.
virtual bool supportsFixedPositionLayers() const { return false; }
-#if PLATFORM(MAC)
+#if PLATFORM(COCOA)
// Dispatched by the scrolling tree during handleWheelEvent. This is required as long as scrollbars are painted on the main thread.
void handleWheelEventPhase(PlatformWheelEventPhase);
#endif
+#if ENABLE(WEB_REPLAY)
+ // Called when the page transitions between executing normally and deterministically.
+ void replaySessionStateDidChange();
+#endif
+
// Force all scroll layer position updates to happen on the main thread.
- void setForceSynchronousScrollLayerPositionUpdates(bool);
+ WEBCORE_EXPORT void setForceSynchronousScrollLayerPositionUpdates(bool);
// These virtual functions are currently unique to the threaded scrolling architecture.
// Their meaningful implementations are in ScrollingCoordinatorMac.
virtual void commitTreeStateIfNeeded() { }
- virtual bool requestScrollPositionUpdate(FrameView*, const IntPoint&) { return false; }
- virtual bool handleWheelEvent(FrameView*, const PlatformWheelEvent&) { return true; }
+ virtual bool requestScrollPositionUpdate(FrameView&, const IntPoint&) { return false; }
+ virtual bool handleWheelEvent(FrameView&, const PlatformWheelEvent&) { return true; }
virtual ScrollingNodeID attachToStateTree(ScrollingNodeType, ScrollingNodeID newNodeID, ScrollingNodeID /*parentID*/) { return newNodeID; }
virtual void detachFromStateTree(ScrollingNodeID) { }
virtual void clearStateTree() { }
virtual void updateViewportConstrainedNode(ScrollingNodeID, const ViewportConstraints&, GraphicsLayer*) { }
- virtual void updateScrollingNode(ScrollingNodeID, GraphicsLayer* /*scrollLayer*/, GraphicsLayer* /*counterScrollingLayer*/) { }
- virtual void syncChildPositions(const LayoutRect&) { }
+
+ struct ScrollingGeometry {
+ FloatSize scrollableAreaSize;
+ FloatSize contentSize;
+ FloatSize reachableContentSize; // Smaller than contentSize when overflow is hidden on one axis.
+ FloatPoint scrollPosition;
+ IntPoint scrollOrigin;
+#if ENABLE(CSS_SCROLL_SNAP)
+ Vector<LayoutUnit> horizontalSnapOffsets;
+ Vector<LayoutUnit> verticalSnapOffsets;
+ Vector<ScrollOffsetRange<LayoutUnit>> horizontalSnapOffsetRanges;
+ Vector<ScrollOffsetRange<LayoutUnit>> verticalSnapOffsetRanges;
+ unsigned currentHorizontalSnapPointIndex;
+ unsigned currentVerticalSnapPointIndex;
+#endif
+ };
+
+ virtual void updateFrameScrollingNode(ScrollingNodeID, GraphicsLayer* /*scrollLayer*/, GraphicsLayer* /*scrolledContentsLayer*/, GraphicsLayer* /*counterScrollingLayer*/, GraphicsLayer* /*insetClipLayer*/, const ScrollingGeometry* = nullptr) { }
+ virtual void updateOverflowScrollingNode(ScrollingNodeID, GraphicsLayer* /*scrollLayer*/, GraphicsLayer* /*scrolledContentsLayer*/, const ScrollingGeometry* = nullptr) { }
+ virtual void reconcileViewportConstrainedLayerPositions(const LayoutRect&, ScrollingLayerPositionAction) { }
virtual String scrollingStateTreeAsText() const;
virtual bool isRubberBandInProgress() const { return false; }
+ virtual bool isScrollSnapInProgress() const { return false; }
+ virtual void updateScrollSnapPropertiesWithFrameView(const FrameView&) { }
virtual void setScrollPinningBehavior(ScrollPinningBehavior) { }
// Generated a unique id for scroll layers.
ScrollingNodeID uniqueScrollLayerID();
enum MainThreadScrollingReasonFlags {
- ForcedOnMainThread = 1 << 0,
- HasSlowRepaintObjects = 1 << 1,
- HasViewportConstrainedObjectsWithoutSupportingFixedLayers = 1 << 2,
- HasNonLayerViewportConstrainedObjects = 1 << 3,
- IsImageDocument = 1 << 4
+ ForcedOnMainThread = 1 << 0,
+ HasSlowRepaintObjects = 1 << 1,
+ HasViewportConstrainedObjectsWithoutSupportingFixedLayers = 1 << 2,
+ HasNonLayerViewportConstrainedObjects = 1 << 3,
+ IsImageDocument = 1 << 4
};
- SynchronousScrollingReasons synchronousScrollingReasons() const;
- bool shouldUpdateScrollLayerPositionSynchronously() const { return synchronousScrollingReasons(); }
+ SynchronousScrollingReasons synchronousScrollingReasons(const FrameView&) const;
+ bool shouldUpdateScrollLayerPositionSynchronously(const FrameView&) const;
- virtual void willDestroyScrollableArea(ScrollableArea*) { }
- virtual void scrollableAreaScrollLayerDidChange(ScrollableArea*) { }
- virtual void scrollableAreaScrollbarLayerDidChange(ScrollableArea*, ScrollbarOrientation) { }
- virtual void setLayerIsContainerForFixedPositionLayers(GraphicsLayer*, bool) { }
+ virtual void willDestroyScrollableArea(ScrollableArea&) { }
+ virtual void scrollableAreaScrollLayerDidChange(ScrollableArea&) { }
+ virtual void scrollableAreaScrollbarLayerDidChange(ScrollableArea&, ScrollbarOrientation) { }
static String synchronousScrollingReasonsAsText(SynchronousScrollingReasons);
String synchronousScrollingReasonsAsText() const;
- Region computeNonFastScrollableRegion(const Frame*, const IntPoint& frameLocation) const;
+ EventTrackingRegions absoluteEventTrackingRegions() const;
+ virtual void updateExpectsWheelEventTestTriggerWithFrameView(const FrameView&) { }
protected:
explicit ScrollingCoordinator(Page*);
-#if USE(ACCELERATED_COMPOSITING)
- static GraphicsLayer* scrollLayerForScrollableArea(ScrollableArea*);
- static GraphicsLayer* horizontalScrollbarLayerForScrollableArea(ScrollableArea*);
- static GraphicsLayer* verticalScrollbarLayerForScrollableArea(ScrollableArea*);
-#endif
+ static GraphicsLayer* scrollLayerForScrollableArea(ScrollableArea&);
- unsigned computeCurrentWheelEventHandlerCount();
- GraphicsLayer* scrollLayerForFrameView(FrameView*);
- GraphicsLayer* counterScrollingLayerForFrameView(FrameView*);
- GraphicsLayer* headerLayerForFrameView(FrameView*);
- GraphicsLayer* footerLayerForFrameView(FrameView*);
+ GraphicsLayer* scrollLayerForFrameView(FrameView&);
+ GraphicsLayer* counterScrollingLayerForFrameView(FrameView&);
+ GraphicsLayer* insetClipLayerForFrameView(FrameView&);
+ GraphicsLayer* rootContentLayerForFrameView(FrameView&);
+ GraphicsLayer* contentShadowLayerForFrameView(FrameView&);
+ GraphicsLayer* headerLayerForFrameView(FrameView&);
+ GraphicsLayer* footerLayerForFrameView(FrameView&);
+
+ virtual void willCommitTree() { }
Page* m_page; // FIXME: ideally this would be a reference but it gets nulled on async teardown.
private:
- virtual void recomputeWheelEventHandlerCountForFrameView(FrameView*) { }
virtual void setSynchronousScrollingReasons(SynchronousScrollingReasons) { }
- virtual bool hasVisibleSlowRepaintViewportConstrainedObjects(FrameView*) const;
- void updateSynchronousScrollingReasons();
+ virtual bool hasVisibleSlowRepaintViewportConstrainedObjects(const FrameView&) const;
+ void updateSynchronousScrollingReasons(const FrameView&);
+
+ EventTrackingRegions absoluteEventTrackingRegionsForFrame(const Frame&) const;
- bool m_forceSynchronousScrollLayerPositionUpdates;
+ bool m_forceSynchronousScrollLayerPositionUpdates { false };
};
-#define SCROLLING_COORDINATOR_TYPE_CASTS(ToValueTypeName, predicate) \
- TYPE_CASTS_BASE(ToValueTypeName, WebCore::ScrollingCoordinator, value, value->predicate, value.predicate)
+WEBCORE_EXPORT TextStream& operator<<(TextStream&, ScrollingNodeType);
+WEBCORE_EXPORT TextStream& operator<<(TextStream&, ScrollingLayerPositionAction);
} // namespace WebCore
-#endif // ScrollingCoordinator_h
+#define SPECIALIZE_TYPE_TRAITS_SCROLLING_COORDINATOR(ToValueTypeName, predicate) \
+SPECIALIZE_TYPE_TRAITS_BEGIN(ToValueTypeName) \
+ static bool isType(const WebCore::ScrollingCoordinator& value) { return value.predicate; } \
+SPECIALIZE_TYPE_TRAITS_END()
diff --git a/Source/WebCore/page/scrolling/ScrollingMomentumCalculator.cpp b/Source/WebCore/page/scrolling/ScrollingMomentumCalculator.cpp
new file mode 100644
index 000000000..1fa5674a2
--- /dev/null
+++ b/Source/WebCore/page/scrolling/ScrollingMomentumCalculator.cpp
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ScrollingMomentumCalculator.h"
+
+#include "FloatPoint.h"
+#include "FloatSize.h"
+
+namespace WebCore {
+
+static const Seconds scrollSnapAnimationDuration = 1_s;
+static inline float projectedInertialScrollDistance(float initialWheelDelta)
+{
+ // On macOS 10.10 and earlier, we don't have a platform scrolling momentum calculator, so we instead approximate the scroll destination
+ // by multiplying the initial wheel delta by a constant factor. By running a few experiments (i.e. logging scroll destination and initial
+ // wheel delta for many scroll gestures) we determined that this is a reasonable way to approximate where scrolling will take us without
+ // using _NSScrollingMomentumCalculator.
+ const static double inertialScrollPredictionFactor = 16.7;
+ return inertialScrollPredictionFactor * initialWheelDelta;
+}
+
+ScrollingMomentumCalculator::ScrollingMomentumCalculator(const FloatSize& viewportSize, const FloatSize& contentSize, const FloatPoint& initialOffset, const FloatSize& initialDelta, const FloatSize& initialVelocity)
+ : m_initialDelta(initialDelta)
+ , m_initialVelocity(initialVelocity)
+ , m_initialScrollOffset(initialOffset.x(), initialOffset.y())
+ , m_viewportSize(viewportSize)
+ , m_contentSize(contentSize)
+{
+}
+
+void ScrollingMomentumCalculator::setRetargetedScrollOffset(const FloatSize& target)
+{
+ if (m_retargetedScrollOffset && m_retargetedScrollOffset == target)
+ return;
+
+ m_retargetedScrollOffset = target;
+ retargetedScrollOffsetDidChange();
+}
+
+FloatSize ScrollingMomentumCalculator::predictedDestinationOffset()
+{
+ float initialOffsetX = clampTo<float>(m_initialScrollOffset.width() + projectedInertialScrollDistance(m_initialDelta.width()), 0, m_contentSize.width() - m_viewportSize.width());
+ float initialOffsetY = clampTo<float>(m_initialScrollOffset.height() + projectedInertialScrollDistance(m_initialDelta.height()), 0, m_contentSize.height() - m_viewportSize.height());
+ return { initialOffsetX, initialOffsetY };
+}
+
+#if !HAVE(NSSCROLLING_FILTERS)
+
+std::unique_ptr<ScrollingMomentumCalculator> ScrollingMomentumCalculator::create(const FloatSize& viewportSize, const FloatSize& contentSize, const FloatPoint& initialOffset, const FloatSize& initialDelta, const FloatSize& initialVelocity)
+{
+ return std::make_unique<BasicScrollingMomentumCalculator>(viewportSize, contentSize, initialOffset, initialDelta, initialVelocity);
+}
+
+void ScrollingMomentumCalculator::setPlatformMomentumScrollingPredictionEnabled(bool)
+{
+}
+
+#endif
+
+BasicScrollingMomentumCalculator::BasicScrollingMomentumCalculator(const FloatSize& viewportSize, const FloatSize& contentSize, const FloatPoint& initialOffset, const FloatSize& initialDelta, const FloatSize& initialVelocity)
+ : ScrollingMomentumCalculator(viewportSize, contentSize, initialOffset, initialDelta, initialVelocity)
+{
+}
+
+FloatSize BasicScrollingMomentumCalculator::linearlyInterpolatedOffsetAtProgress(float progress)
+{
+ return m_initialScrollOffset + progress * (retargetedScrollOffset() - m_initialScrollOffset);
+}
+
+FloatSize BasicScrollingMomentumCalculator::cubicallyInterpolatedOffsetAtProgress(float progress) const
+{
+ ASSERT(!m_forceLinearAnimationCurve);
+ FloatSize interpolatedPoint;
+ for (int i = 0; i < 4; ++i)
+ interpolatedPoint += std::pow(progress, i) * m_snapAnimationCurveCoefficients[i];
+
+ return interpolatedPoint;
+}
+
+FloatPoint BasicScrollingMomentumCalculator::scrollOffsetAfterElapsedTime(Seconds elapsedTime)
+{
+ if (m_momentumCalculatorRequiresInitialization) {
+ initializeSnapProgressCurve();
+ initializeInterpolationCoefficientsIfNecessary();
+ m_momentumCalculatorRequiresInitialization = false;
+ }
+
+ float progress = animationProgressAfterElapsedTime(elapsedTime);
+ auto offsetAsSize = m_forceLinearAnimationCurve ? linearlyInterpolatedOffsetAtProgress(progress) : cubicallyInterpolatedOffsetAtProgress(progress);
+ return FloatPoint(offsetAsSize.width(), offsetAsSize.height());
+}
+
+Seconds BasicScrollingMomentumCalculator::animationDuration()
+{
+ return scrollSnapAnimationDuration;
+}
+
+/**
+ * Computes and sets coefficients required for interpolated snapping when scrolling in 2 dimensions, given
+ * initial conditions (the initial and target vectors, along with the initial wheel delta as a vector). The
+ * path is a cubic Bezier curve of the form p(s) = INITIAL + (C_1 * s) + (C_2 * s^2) + (C_3 * s^3) where each
+ * C_i is a 2D vector and INITIAL is the vector representing the initial scroll offset. s is a real in the
+ * interval [0, 1] indicating the "progress" of the curve (i.e. how much of the curve has been traveled).
+ *
+ * The curve has 4 control points, the first and last of which are the initial and target points, respectively.
+ * The distances between adjacent control points are constrained to be the same, making the convex hull an
+ * isosceles trapezoid with 3 sides of equal length. Additionally, the vector from the first control point to
+ * the second points in the same direction as the initial scroll delta. These constraints ensure two properties:
+ * 1. The direction of the snap animation at s=0 will be equal to the direction of the initial scroll delta.
+ * 2. Points at regular intervals of s will be evenly spread out.
+ *
+ * If the initial scroll direction is orthogonal to or points in the opposite direction as the vector from the
+ * initial point to the target point, initialization returns early and sets the curve to animate directly to the
+ * snap point without cubic interpolation.
+ *
+ * FIXME: This should be refactored to use UnitBezier.
+ */
+void BasicScrollingMomentumCalculator::initializeInterpolationCoefficientsIfNecessary()
+{
+ m_forceLinearAnimationCurve = true;
+ float initialDeltaMagnitude = m_initialDelta.diagonalLength();
+ if (initialDeltaMagnitude < 1) {
+ // The initial wheel delta is so insignificant that we're better off considering this to have the same effect as finishing a scroll gesture with no momentum.
+ // Thus, cubic interpolation isn't needed here.
+ return;
+ }
+
+ FloatSize startToEndVector = retargetedScrollOffset() - m_initialScrollOffset;
+ float startToEndDistance = startToEndVector.diagonalLength();
+ if (!startToEndDistance) {
+ // The start and end positions are the same, so we shouldn't try to interpolate a path.
+ return;
+ }
+
+ float cosTheta = (m_initialDelta.width() * startToEndVector.width() + m_initialDelta.height() * startToEndVector.height()) / (initialDeltaMagnitude * startToEndDistance);
+ if (cosTheta <= 0) {
+ // It's possible that the user is not scrolling towards the target snap offset (for instance, scrolling against a corner when 2D scroll snapping).
+ // In this case, just let the scroll offset animate to the target without computing a cubic curve.
+ return;
+ }
+
+ float sideLength = startToEndDistance / (2.0f * cosTheta + 1.0f);
+ FloatSize controlVector1 = m_initialScrollOffset + sideLength * m_initialDelta / initialDeltaMagnitude;
+ FloatSize controlVector2 = controlVector1 + (sideLength * startToEndVector / startToEndDistance);
+ m_snapAnimationCurveCoefficients[0] = m_initialScrollOffset;
+ m_snapAnimationCurveCoefficients[1] = 3 * (controlVector1 - m_initialScrollOffset);
+ m_snapAnimationCurveCoefficients[2] = 3 * (m_initialScrollOffset - 2 * controlVector1 + controlVector2);
+ m_snapAnimationCurveCoefficients[3] = 3 * (controlVector1 - controlVector2) - m_initialScrollOffset + retargetedScrollOffset();
+ m_forceLinearAnimationCurve = false;
+}
+
+static const float framesPerSecond = 60.0f;
+
+/**
+ * Computes and sets parameters required for tracking the progress of a snap animation curve, interpolated
+ * or linear. The progress curve s(t) maps time t to progress s; both variables are in the interval [0, 1].
+ * The time input t is 0 when the current time is the start of the animation, t = 0, and 1 when the current
+ * time is at or after the end of the animation, t = m_scrollSnapAnimationDuration.
+ *
+ * In this exponential progress model, s(t) = A - A * b^(-kt), where k = 60T is the number of frames in the
+ * animation (assuming 60 FPS and an animation duration of T) and A, b are reals greater than or equal to 1.
+ * Also note that we are given the initial progress, a value indicating the portion of the curve which our
+ * initial scroll delta takes us. This is important when matching the initial speed of the animation to the
+ * user's initial momentum scrolling speed. Let this initial progress amount equal v_0. I clamp this initial
+ * progress amount to a minimum or maximum value.
+ *
+ * A is referred to as the curve magnitude, while b is referred to as the decay factor. We solve for A and b,
+ * keeping the following constraints in mind:
+ * 1. s(0) = 0
+ * 2. s(1) = 1
+ * 3. s(1/k) = v_0
+ *
+ * First, observe that s(0) = 0 holds for appropriate values of A, b. Solving for the remaining constraints
+ * yields a nonlinear system of two equations. In lieu of a purely analytical solution, an alternating
+ * optimization scheme is used to approximate A and b. This technique converges quickly (within 5 iterations
+ * or so) for appropriate values of v_0. The optimization terminates early when the decay factor changes by
+ * less than a threshold between one iteration and the next.
+ */
+void BasicScrollingMomentumCalculator::initializeSnapProgressCurve()
+{
+ static const int maxNumScrollSnapParameterEstimationIterations = 10;
+ static const float scrollSnapDecayFactorConvergenceThreshold = 0.001;
+ static const float initialScrollSnapCurveMagnitude = 1.1;
+ static const float minScrollSnapInitialProgress = 0.1;
+ static const float maxScrollSnapInitialProgress = 0.5;
+
+ FloatSize alignmentVector = m_initialDelta * (retargetedScrollOffset() - m_initialScrollOffset);
+ float initialProgress;
+ if (alignmentVector.width() + alignmentVector.height() > 0)
+ initialProgress = clampTo(m_initialDelta.diagonalLength() / (retargetedScrollOffset() - m_initialScrollOffset).diagonalLength(), minScrollSnapInitialProgress, maxScrollSnapInitialProgress);
+ else
+ initialProgress = minScrollSnapInitialProgress;
+
+ float previousDecayFactor = 1.0f;
+ m_snapAnimationCurveMagnitude = initialScrollSnapCurveMagnitude;
+ for (int i = 0; i < maxNumScrollSnapParameterEstimationIterations; ++i) {
+ m_snapAnimationDecayFactor = m_snapAnimationCurveMagnitude / (m_snapAnimationCurveMagnitude - initialProgress);
+ m_snapAnimationCurveMagnitude = 1.0f / (1.0f - std::pow(m_snapAnimationDecayFactor, -framesPerSecond * scrollSnapAnimationDuration.value()));
+ if (std::abs(m_snapAnimationDecayFactor - previousDecayFactor) < scrollSnapDecayFactorConvergenceThreshold)
+ break;
+
+ previousDecayFactor = m_snapAnimationDecayFactor;
+ }
+}
+
+float BasicScrollingMomentumCalculator::animationProgressAfterElapsedTime(Seconds elapsedTime) const
+{
+ float timeProgress = clampTo<float>(elapsedTime / scrollSnapAnimationDuration, 0, 1);
+ return std::min(1.0, m_snapAnimationCurveMagnitude * (1.0 - std::pow(m_snapAnimationDecayFactor, -framesPerSecond * scrollSnapAnimationDuration.value() * timeProgress)));
+}
+
+}; // namespace WebCore
diff --git a/Source/WebCore/page/scrolling/ScrollingMomentumCalculator.h b/Source/WebCore/page/scrolling/ScrollingMomentumCalculator.h
new file mode 100644
index 000000000..a82afaa66
--- /dev/null
+++ b/Source/WebCore/page/scrolling/ScrollingMomentumCalculator.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(CSS_SCROLL_SNAP)
+
+#include "AxisScrollSnapOffsets.h"
+#include "PlatformWheelEvent.h"
+#include "ScrollTypes.h"
+#include <wtf/Optional.h>
+#include <wtf/Seconds.h>
+
+namespace WebCore {
+
+class FloatPoint;
+class FloatSize;
+
+class ScrollingMomentumCalculator {
+public:
+ ScrollingMomentumCalculator(const FloatSize& viewportSize, const FloatSize& contentSize, const FloatPoint& initialOffset, const FloatSize& initialDelta, const FloatSize& initialVelocity);
+ static std::unique_ptr<ScrollingMomentumCalculator> create(const FloatSize& viewportSize, const FloatSize& contentSize, const FloatPoint& initialOffset, const FloatSize& initialDelta, const FloatSize& initialVelocity);
+ WEBCORE_EXPORT static void setPlatformMomentumScrollingPredictionEnabled(bool);
+ virtual ~ScrollingMomentumCalculator() { }
+
+ virtual FloatPoint scrollOffsetAfterElapsedTime(Seconds) = 0;
+ virtual Seconds animationDuration() = 0;
+ virtual FloatSize predictedDestinationOffset();
+ void setRetargetedScrollOffset(const FloatSize&);
+
+protected:
+ const FloatSize& retargetedScrollOffset() const { return m_retargetedScrollOffset.value(); }
+ virtual void retargetedScrollOffsetDidChange() { }
+
+ FloatSize m_initialDelta;
+ FloatSize m_initialVelocity;
+ FloatSize m_initialScrollOffset;
+ FloatSize m_viewportSize;
+ FloatSize m_contentSize;
+
+private:
+ std::optional<FloatSize> m_retargetedScrollOffset;
+};
+
+class BasicScrollingMomentumCalculator final : public ScrollingMomentumCalculator {
+public:
+ BasicScrollingMomentumCalculator(const FloatSize& viewportSize, const FloatSize& contentSize, const FloatPoint& initialOffset, const FloatSize& initialDelta, const FloatSize& initialVelocity);
+
+private:
+ FloatPoint scrollOffsetAfterElapsedTime(Seconds) final;
+ Seconds animationDuration() final;
+ void initializeInterpolationCoefficientsIfNecessary();
+ void initializeSnapProgressCurve();
+ float animationProgressAfterElapsedTime(Seconds) const;
+ FloatSize linearlyInterpolatedOffsetAtProgress(float progress);
+ FloatSize cubicallyInterpolatedOffsetAtProgress(float progress) const;
+
+ float m_snapAnimationCurveMagnitude { 0 };
+ float m_snapAnimationDecayFactor { 0 };
+ FloatSize m_snapAnimationCurveCoefficients[4] { };
+ bool m_forceLinearAnimationCurve { false };
+ bool m_momentumCalculatorRequiresInitialization { true };
+ std::optional<FloatSize> m_predictedDestinationOffset;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(CSS_SCROLL_SNAP)
diff --git a/Source/WebCore/page/scrolling/ScrollingStateFixedNode.cpp b/Source/WebCore/page/scrolling/ScrollingStateFixedNode.cpp
index cce42eb7e..17d016597 100644
--- a/Source/WebCore/page/scrolling/ScrollingStateFixedNode.cpp
+++ b/Source/WebCore/page/scrolling/ScrollingStateFixedNode.cpp
@@ -27,17 +27,17 @@
#include "ScrollingStateFixedNode.h"
#include "GraphicsLayer.h"
+#include "Logging.h"
#include "ScrollingStateTree.h"
#include "TextStream.h"
-#include <wtf/OwnPtr.h>
#if ENABLE(ASYNC_SCROLLING) || USE(COORDINATED_GRAPHICS)
namespace WebCore {
-PassOwnPtr<ScrollingStateFixedNode> ScrollingStateFixedNode::create(ScrollingStateTree& stateTree, ScrollingNodeID nodeID)
+Ref<ScrollingStateFixedNode> ScrollingStateFixedNode::create(ScrollingStateTree& stateTree, ScrollingNodeID nodeID)
{
- return adoptPtr(new ScrollingStateFixedNode(stateTree, nodeID));
+ return adoptRef(*new ScrollingStateFixedNode(stateTree, nodeID));
}
ScrollingStateFixedNode::ScrollingStateFixedNode(ScrollingStateTree& tree, ScrollingNodeID nodeID)
@@ -55,9 +55,9 @@ ScrollingStateFixedNode::~ScrollingStateFixedNode()
{
}
-PassOwnPtr<ScrollingStateNode> ScrollingStateFixedNode::clone(ScrollingStateTree& adoptiveTree)
+Ref<ScrollingStateNode> ScrollingStateFixedNode::clone(ScrollingStateTree& adoptiveTree)
{
- return adoptPtr(new ScrollingStateFixedNode(*this, adoptiveTree));
+ return adoptRef(*new ScrollingStateFixedNode(*this, adoptiveTree));
}
void ScrollingStateFixedNode::updateConstraints(const FixedPositionViewportConstraints& constraints)
@@ -69,14 +69,31 @@ void ScrollingStateFixedNode::updateConstraints(const FixedPositionViewportConst
setPropertyChanged(ViewportConstraints);
}
-void ScrollingStateFixedNode::syncLayerPositionForViewportRect(const LayoutRect& viewportRect)
+void ScrollingStateFixedNode::reconcileLayerPositionForViewportRect(const LayoutRect& viewportRect, ScrollingLayerPositionAction action)
{
FloatPoint position = m_constraints.layerPositionForViewportRect(viewportRect);
- if (layer().representsGraphicsLayer())
- static_cast<GraphicsLayer*>(layer())->syncPosition(position);
+ if (layer().representsGraphicsLayer()) {
+ GraphicsLayer* graphicsLayer = static_cast<GraphicsLayer*>(layer());
+
+ LOG_WITH_STREAM(Compositing, stream << "ScrollingStateFixedNode::reconcileLayerPositionForViewportRect setting position of layer " << graphicsLayer->primaryLayerID() << " to " << position);
+
+ switch (action) {
+ case ScrollingLayerPositionAction::Set:
+ graphicsLayer->setPosition(position);
+ break;
+
+ case ScrollingLayerPositionAction::SetApproximate:
+ graphicsLayer->setApproximatePosition(position);
+ break;
+
+ case ScrollingLayerPositionAction::Sync:
+ graphicsLayer->syncPosition(position);
+ break;
+ }
+ }
}
-void ScrollingStateFixedNode::dumpProperties(TextStream& ts, int indent) const
+void ScrollingStateFixedNode::dumpProperties(TextStream& ts, int indent, ScrollingStateTreeAsTextBehavior) const
{
ts << "(" << "Fixed node" << "\n";
diff --git a/Source/WebCore/page/scrolling/ScrollingStateFixedNode.h b/Source/WebCore/page/scrolling/ScrollingStateFixedNode.h
index a52d7b6d0..e761b6a73 100644
--- a/Source/WebCore/page/scrolling/ScrollingStateFixedNode.h
+++ b/Source/WebCore/page/scrolling/ScrollingStateFixedNode.h
@@ -23,8 +23,7 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ScrollingStateFixedNode_h
-#define ScrollingStateFixedNode_h
+#pragma once
#if ENABLE(ASYNC_SCROLLING) || USE(COORDINATED_GRAPHICS)
@@ -39,9 +38,9 @@ class FixedPositionViewportConstraints;
class ScrollingStateFixedNode final : public ScrollingStateNode {
public:
- static PassOwnPtr<ScrollingStateFixedNode> create(ScrollingStateTree&, ScrollingNodeID);
+ static Ref<ScrollingStateFixedNode> create(ScrollingStateTree&, ScrollingNodeID);
- virtual PassOwnPtr<ScrollingStateNode> clone(ScrollingStateTree&);
+ Ref<ScrollingStateNode> clone(ScrollingStateTree&) override;
virtual ~ScrollingStateFixedNode();
@@ -49,24 +48,22 @@ public:
ViewportConstraints = NumStateNodeBits
};
- void updateConstraints(const FixedPositionViewportConstraints&);
+ WEBCORE_EXPORT void updateConstraints(const FixedPositionViewportConstraints&);
const FixedPositionViewportConstraints& viewportConstraints() const { return m_constraints; }
private:
ScrollingStateFixedNode(ScrollingStateTree&, ScrollingNodeID);
ScrollingStateFixedNode(const ScrollingStateFixedNode&, ScrollingStateTree&);
- virtual void syncLayerPositionForViewportRect(const LayoutRect& viewportRect) override;
+ void reconcileLayerPositionForViewportRect(const LayoutRect& viewportRect, ScrollingLayerPositionAction) override;
- virtual void dumpProperties(TextStream&, int indent) const override;
+ void dumpProperties(TextStream&, int indent, ScrollingStateTreeAsTextBehavior) const override;
FixedPositionViewportConstraints m_constraints;
};
-SCROLLING_STATE_NODE_TYPE_CASTS(ScrollingStateFixedNode, nodeType() == FixedNode);
-
} // namespace WebCore
-#endif // ENABLE(ASYNC_SCROLLING) || USE(COORDINATED_GRAPHICS)
+SPECIALIZE_TYPE_TRAITS_SCROLLING_STATE_NODE(ScrollingStateFixedNode, isFixedNode())
-#endif // ScrollingStateFixedNode_h
+#endif // ENABLE(ASYNC_SCROLLING) || USE(COORDINATED_GRAPHICS)
diff --git a/Source/WebCore/page/scrolling/ScrollingStateFrameScrollingNode.cpp b/Source/WebCore/page/scrolling/ScrollingStateFrameScrollingNode.cpp
new file mode 100644
index 000000000..6313c1385
--- /dev/null
+++ b/Source/WebCore/page/scrolling/ScrollingStateFrameScrollingNode.cpp
@@ -0,0 +1,329 @@
+/*
+ * Copyright (C) 2014, 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ScrollingStateFrameScrollingNode.h"
+
+#if ENABLE(ASYNC_SCROLLING) || USE(COORDINATED_GRAPHICS)
+
+#include "ScrollingStateTree.h"
+#include "TextStream.h"
+
+namespace WebCore {
+
+Ref<ScrollingStateFrameScrollingNode> ScrollingStateFrameScrollingNode::create(ScrollingStateTree& stateTree, ScrollingNodeID nodeID)
+{
+ return adoptRef(*new ScrollingStateFrameScrollingNode(stateTree, nodeID));
+}
+
+ScrollingStateFrameScrollingNode::ScrollingStateFrameScrollingNode(ScrollingStateTree& stateTree, ScrollingNodeID nodeID)
+ : ScrollingStateScrollingNode(stateTree, FrameScrollingNode, nodeID)
+{
+}
+
+ScrollingStateFrameScrollingNode::ScrollingStateFrameScrollingNode(const ScrollingStateFrameScrollingNode& stateNode, ScrollingStateTree& adoptiveTree)
+ : ScrollingStateScrollingNode(stateNode, adoptiveTree)
+#if PLATFORM(MAC)
+ , m_verticalScrollerImp(stateNode.verticalScrollerImp())
+ , m_horizontalScrollerImp(stateNode.horizontalScrollerImp())
+#endif
+ , m_eventTrackingRegions(stateNode.eventTrackingRegions())
+ , m_requestedScrollPosition(stateNode.requestedScrollPosition())
+ , m_layoutViewport(stateNode.layoutViewport())
+ , m_minLayoutViewportOrigin(stateNode.minLayoutViewportOrigin())
+ , m_maxLayoutViewportOrigin(stateNode.maxLayoutViewportOrigin())
+ , m_frameScaleFactor(stateNode.frameScaleFactor())
+ , m_topContentInset(stateNode.topContentInset())
+ , m_headerHeight(stateNode.headerHeight())
+ , m_footerHeight(stateNode.footerHeight())
+ , m_synchronousScrollingReasons(stateNode.synchronousScrollingReasons())
+ , m_behaviorForFixed(stateNode.scrollBehaviorForFixedElements())
+ , m_requestedScrollPositionRepresentsProgrammaticScroll(stateNode.requestedScrollPositionRepresentsProgrammaticScroll())
+ , m_fixedElementsLayoutRelativeToFrame(stateNode.fixedElementsLayoutRelativeToFrame())
+ , m_visualViewportEnabled(stateNode.visualViewportEnabled())
+{
+ if (hasChangedProperty(ScrolledContentsLayer))
+ setScrolledContentsLayer(stateNode.scrolledContentsLayer().toRepresentation(adoptiveTree.preferredLayerRepresentation()));
+
+ if (hasChangedProperty(CounterScrollingLayer))
+ setCounterScrollingLayer(stateNode.counterScrollingLayer().toRepresentation(adoptiveTree.preferredLayerRepresentation()));
+
+ if (hasChangedProperty(InsetClipLayer))
+ setInsetClipLayer(stateNode.insetClipLayer().toRepresentation(adoptiveTree.preferredLayerRepresentation()));
+
+ if (hasChangedProperty(ContentShadowLayer))
+ setContentShadowLayer(stateNode.contentShadowLayer().toRepresentation(adoptiveTree.preferredLayerRepresentation()));
+
+ if (hasChangedProperty(HeaderLayer))
+ setHeaderLayer(stateNode.headerLayer().toRepresentation(adoptiveTree.preferredLayerRepresentation()));
+
+ if (hasChangedProperty(FooterLayer))
+ setFooterLayer(stateNode.footerLayer().toRepresentation(adoptiveTree.preferredLayerRepresentation()));
+}
+
+ScrollingStateFrameScrollingNode::~ScrollingStateFrameScrollingNode()
+{
+}
+
+Ref<ScrollingStateNode> ScrollingStateFrameScrollingNode::clone(ScrollingStateTree& adoptiveTree)
+{
+ return adoptRef(*new ScrollingStateFrameScrollingNode(*this, adoptiveTree));
+}
+
+void ScrollingStateFrameScrollingNode::setFrameScaleFactor(float scaleFactor)
+{
+ if (m_frameScaleFactor == scaleFactor)
+ return;
+
+ m_frameScaleFactor = scaleFactor;
+
+ setPropertyChanged(FrameScaleFactor);
+}
+
+void ScrollingStateFrameScrollingNode::setEventTrackingRegions(const EventTrackingRegions& eventTrackingRegions)
+{
+ if (m_eventTrackingRegions == eventTrackingRegions)
+ return;
+
+ m_eventTrackingRegions = eventTrackingRegions;
+ setPropertyChanged(EventTrackingRegion);
+}
+
+void ScrollingStateFrameScrollingNode::setSynchronousScrollingReasons(SynchronousScrollingReasons reasons)
+{
+ if (m_synchronousScrollingReasons == reasons)
+ return;
+
+ m_synchronousScrollingReasons = reasons;
+ setPropertyChanged(ReasonsForSynchronousScrolling);
+}
+
+void ScrollingStateFrameScrollingNode::setScrollBehaviorForFixedElements(ScrollBehaviorForFixedElements behaviorForFixed)
+{
+ if (m_behaviorForFixed == behaviorForFixed)
+ return;
+
+ m_behaviorForFixed = behaviorForFixed;
+ setPropertyChanged(BehaviorForFixedElements);
+}
+
+void ScrollingStateFrameScrollingNode::setLayoutViewport(const FloatRect& r)
+{
+ if (m_layoutViewport == r)
+ return;
+
+ m_layoutViewport = r;
+ setPropertyChanged(LayoutViewport);
+}
+
+void ScrollingStateFrameScrollingNode::setMinLayoutViewportOrigin(const FloatPoint& p)
+{
+ if (m_minLayoutViewportOrigin == p)
+ return;
+
+ m_minLayoutViewportOrigin = p;
+ setPropertyChanged(MinLayoutViewportOrigin);
+}
+
+void ScrollingStateFrameScrollingNode::setMaxLayoutViewportOrigin(const FloatPoint& p)
+{
+ if (m_maxLayoutViewportOrigin == p)
+ return;
+
+ m_maxLayoutViewportOrigin = p;
+ setPropertyChanged(MaxLayoutViewportOrigin);
+}
+
+void ScrollingStateFrameScrollingNode::setHeaderHeight(int headerHeight)
+{
+ if (m_headerHeight == headerHeight)
+ return;
+
+ m_headerHeight = headerHeight;
+ setPropertyChanged(HeaderHeight);
+}
+
+void ScrollingStateFrameScrollingNode::setFooterHeight(int footerHeight)
+{
+ if (m_footerHeight == footerHeight)
+ return;
+
+ m_footerHeight = footerHeight;
+ setPropertyChanged(FooterHeight);
+}
+
+void ScrollingStateFrameScrollingNode::setTopContentInset(float topContentInset)
+{
+ if (m_topContentInset == topContentInset)
+ return;
+
+ m_topContentInset = topContentInset;
+ setPropertyChanged(TopContentInset);
+}
+
+void ScrollingStateFrameScrollingNode::setScrolledContentsLayer(const LayerRepresentation& layerRepresentation)
+{
+ if (layerRepresentation == m_scrolledContentsLayer)
+ return;
+
+ m_scrolledContentsLayer = layerRepresentation;
+ setPropertyChanged(ScrolledContentsLayer);
+}
+
+void ScrollingStateFrameScrollingNode::setCounterScrollingLayer(const LayerRepresentation& layerRepresentation)
+{
+ if (layerRepresentation == m_counterScrollingLayer)
+ return;
+
+ m_counterScrollingLayer = layerRepresentation;
+ setPropertyChanged(CounterScrollingLayer);
+}
+
+void ScrollingStateFrameScrollingNode::setInsetClipLayer(const LayerRepresentation& layerRepresentation)
+{
+ if (layerRepresentation == m_insetClipLayer)
+ return;
+
+ m_insetClipLayer = layerRepresentation;
+ setPropertyChanged(InsetClipLayer);
+}
+
+void ScrollingStateFrameScrollingNode::setContentShadowLayer(const LayerRepresentation& layerRepresentation)
+{
+ if (layerRepresentation == m_contentShadowLayer)
+ return;
+
+ m_contentShadowLayer = layerRepresentation;
+ setPropertyChanged(ContentShadowLayer);
+}
+
+void ScrollingStateFrameScrollingNode::setHeaderLayer(const LayerRepresentation& layerRepresentation)
+{
+ if (layerRepresentation == m_headerLayer)
+ return;
+
+ m_headerLayer = layerRepresentation;
+ setPropertyChanged(HeaderLayer);
+}
+
+void ScrollingStateFrameScrollingNode::setFooterLayer(const LayerRepresentation& layerRepresentation)
+{
+ if (layerRepresentation == m_footerLayer)
+ return;
+
+ m_footerLayer = layerRepresentation;
+ setPropertyChanged(FooterLayer);
+}
+
+void ScrollingStateFrameScrollingNode::setFixedElementsLayoutRelativeToFrame(bool fixedElementsLayoutRelativeToFrame)
+{
+ if (fixedElementsLayoutRelativeToFrame == m_fixedElementsLayoutRelativeToFrame)
+ return;
+
+ m_fixedElementsLayoutRelativeToFrame = fixedElementsLayoutRelativeToFrame;
+ setPropertyChanged(FixedElementsLayoutRelativeToFrame);
+}
+
+// Only needed while visual viewports are runtime-switchable.
+void ScrollingStateFrameScrollingNode::setVisualViewportEnabled(bool visualViewportEnabled)
+{
+ if (visualViewportEnabled == m_visualViewportEnabled)
+ return;
+
+ m_visualViewportEnabled = visualViewportEnabled;
+ setPropertyChanged(VisualViewportEnabled);
+}
+
+#if !PLATFORM(MAC)
+void ScrollingStateFrameScrollingNode::setScrollerImpsFromScrollbars(Scrollbar*, Scrollbar*)
+{
+}
+#endif
+
+void ScrollingStateFrameScrollingNode::dumpProperties(TextStream& ts, int indent, ScrollingStateTreeAsTextBehavior behavior) const
+{
+ ts << "(Frame scrolling node" << "\n";
+
+ ScrollingStateScrollingNode::dumpProperties(ts, indent, behavior);
+
+ if (m_frameScaleFactor != 1) {
+ writeIndent(ts, indent + 1);
+ ts << "(frame scale factor " << m_frameScaleFactor << ")\n";
+ }
+
+ if (m_visualViewportEnabled) {
+ writeIndent(ts, indent + 1);
+ ts << "(layout viewport " << m_layoutViewport << ")\n";
+ writeIndent(ts, indent + 1);
+ ts << "(min layout viewport origin " << m_minLayoutViewportOrigin << ")\n";
+ writeIndent(ts, indent + 1);
+ ts << "(max layout viewport origin " << m_maxLayoutViewportOrigin << ")\n";
+ }
+
+ if (m_behaviorForFixed == StickToViewportBounds) {
+ writeIndent(ts, indent + 1);
+ ts << "(fixed behavior: stick to viewport)\n";
+ }
+
+ if (!m_eventTrackingRegions.asynchronousDispatchRegion.isEmpty()) {
+ ++indent;
+ writeIndent(ts, indent);
+ ts << "(asynchronous event dispatch region";
+ ++indent;
+ for (auto rect : m_eventTrackingRegions.asynchronousDispatchRegion.rects()) {
+ ts << "\n";
+ writeIndent(ts, indent);
+ ts << rect;
+ }
+ ts << ")\n";
+ indent -= 2;
+ }
+ if (!m_eventTrackingRegions.eventSpecificSynchronousDispatchRegions.isEmpty()) {
+ for (const auto& synchronousEventRegion : m_eventTrackingRegions.eventSpecificSynchronousDispatchRegions) {
+ ++indent;
+ writeIndent(ts, indent);
+ ts << "(synchronous event dispatch region for event " << synchronousEventRegion.key;
+ ++indent;
+ for (auto rect : synchronousEventRegion.value.rects()) {
+ ts << "\n";
+ writeIndent(ts, indent);
+ ts << rect;
+ }
+ ts << ")\n";
+ indent -= 2;
+ }
+ }
+
+ if (m_synchronousScrollingReasons) {
+ writeIndent(ts, indent + 1);
+ ts << "(Scrolling on main thread because: " << ScrollingCoordinator::synchronousScrollingReasonsAsText(m_synchronousScrollingReasons) << ")\n";
+ }
+
+ // FIXME: dump more properties.
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(ASYNC_SCROLLING) || USE(COORDINATED_GRAPHICS)
diff --git a/Source/WebCore/page/scrolling/ScrollingStateFrameScrollingNode.h b/Source/WebCore/page/scrolling/ScrollingStateFrameScrollingNode.h
new file mode 100644
index 000000000..eeaa71fe3
--- /dev/null
+++ b/Source/WebCore/page/scrolling/ScrollingStateFrameScrollingNode.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2014, 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(ASYNC_SCROLLING) || USE(COORDINATED_GRAPHICS)
+
+#include "EventTrackingRegions.h"
+#include "ScrollTypes.h"
+#include "ScrollbarThemeComposite.h"
+#include "ScrollingCoordinator.h"
+#include "ScrollingStateScrollingNode.h"
+
+namespace WebCore {
+
+class Scrollbar;
+
+class ScrollingStateFrameScrollingNode final : public ScrollingStateScrollingNode {
+public:
+ static Ref<ScrollingStateFrameScrollingNode> create(ScrollingStateTree&, ScrollingNodeID);
+
+ Ref<ScrollingStateNode> clone(ScrollingStateTree&) override;
+
+ virtual ~ScrollingStateFrameScrollingNode();
+
+ enum ChangedProperty {
+ FrameScaleFactor = NumScrollingStateNodeBits,
+ EventTrackingRegion,
+ ReasonsForSynchronousScrolling,
+ ScrolledContentsLayer,
+ CounterScrollingLayer,
+ InsetClipLayer,
+ ContentShadowLayer,
+ HeaderHeight,
+ FooterHeight,
+ HeaderLayer,
+ FooterLayer,
+ PainterForScrollbar,
+ BehaviorForFixedElements,
+ TopContentInset,
+ FixedElementsLayoutRelativeToFrame,
+ VisualViewportEnabled,
+ LayoutViewport,
+ MinLayoutViewportOrigin,
+ MaxLayoutViewportOrigin,
+ };
+
+ float frameScaleFactor() const { return m_frameScaleFactor; }
+ WEBCORE_EXPORT void setFrameScaleFactor(float);
+
+ const EventTrackingRegions& eventTrackingRegions() const { return m_eventTrackingRegions; }
+ WEBCORE_EXPORT void setEventTrackingRegions(const EventTrackingRegions&);
+
+ SynchronousScrollingReasons synchronousScrollingReasons() const { return m_synchronousScrollingReasons; }
+ WEBCORE_EXPORT void setSynchronousScrollingReasons(SynchronousScrollingReasons);
+
+ ScrollBehaviorForFixedElements scrollBehaviorForFixedElements() const { return m_behaviorForFixed; }
+ WEBCORE_EXPORT void setScrollBehaviorForFixedElements(ScrollBehaviorForFixedElements);
+
+ FloatRect layoutViewport() const { return m_layoutViewport; };
+ WEBCORE_EXPORT void setLayoutViewport(const FloatRect&);
+
+ FloatPoint minLayoutViewportOrigin() const { return m_minLayoutViewportOrigin; }
+ WEBCORE_EXPORT void setMinLayoutViewportOrigin(const FloatPoint&);
+
+ FloatPoint maxLayoutViewportOrigin() const { return m_maxLayoutViewportOrigin; }
+ WEBCORE_EXPORT void setMaxLayoutViewportOrigin(const FloatPoint&);
+
+ int headerHeight() const { return m_headerHeight; }
+ WEBCORE_EXPORT void setHeaderHeight(int);
+
+ int footerHeight() const { return m_footerHeight; }
+ WEBCORE_EXPORT void setFooterHeight(int);
+
+ float topContentInset() const { return m_topContentInset; }
+ WEBCORE_EXPORT void setTopContentInset(float);
+
+ const LayerRepresentation& scrolledContentsLayer() const { return m_scrolledContentsLayer; }
+ WEBCORE_EXPORT void setScrolledContentsLayer(const LayerRepresentation&);
+
+ // This is a layer moved in the opposite direction to scrolling, for example for background-attachment:fixed
+ const LayerRepresentation& counterScrollingLayer() const { return m_counterScrollingLayer; }
+ WEBCORE_EXPORT void setCounterScrollingLayer(const LayerRepresentation&);
+
+ // This is a clipping layer that will scroll with the page for all y-delta scroll values between 0
+ // and topContentInset(). Once the y-deltas get beyond the content inset point, this layer no longer
+ // needs to move. If the topContentInset() is 0, this layer does not need to move at all. This is
+ // only used on the Mac.
+ const LayerRepresentation& insetClipLayer() const { return m_insetClipLayer; }
+ WEBCORE_EXPORT void setInsetClipLayer(const LayerRepresentation&);
+
+ const LayerRepresentation& contentShadowLayer() const { return m_contentShadowLayer; }
+ WEBCORE_EXPORT void setContentShadowLayer(const LayerRepresentation&);
+
+ // The header and footer layers scroll vertically with the page, they should remain fixed when scrolling horizontally.
+ const LayerRepresentation& headerLayer() const { return m_headerLayer; }
+ WEBCORE_EXPORT void setHeaderLayer(const LayerRepresentation&);
+
+ // The header and footer layers scroll vertically with the page, they should remain fixed when scrolling horizontally.
+ const LayerRepresentation& footerLayer() const { return m_footerLayer; }
+ WEBCORE_EXPORT void setFooterLayer(const LayerRepresentation&);
+
+ bool fixedElementsLayoutRelativeToFrame() const { return m_fixedElementsLayoutRelativeToFrame; }
+ WEBCORE_EXPORT void setFixedElementsLayoutRelativeToFrame(bool);
+
+ bool visualViewportEnabled() const { return m_visualViewportEnabled; };
+ WEBCORE_EXPORT void setVisualViewportEnabled(bool);
+
+#if PLATFORM(MAC)
+ NSScrollerImp *verticalScrollerImp() const { return m_verticalScrollerImp.get(); }
+ NSScrollerImp *horizontalScrollerImp() const { return m_horizontalScrollerImp.get(); }
+#endif
+ void setScrollerImpsFromScrollbars(Scrollbar* verticalScrollbar, Scrollbar* horizontalScrollbar);
+
+ void dumpProperties(TextStream&, int indent, ScrollingStateTreeAsTextBehavior) const override;
+
+private:
+ ScrollingStateFrameScrollingNode(ScrollingStateTree&, ScrollingNodeID);
+ ScrollingStateFrameScrollingNode(const ScrollingStateFrameScrollingNode&, ScrollingStateTree&);
+
+ LayerRepresentation m_counterScrollingLayer;
+ LayerRepresentation m_insetClipLayer;
+ LayerRepresentation m_scrolledContentsLayer;
+ LayerRepresentation m_contentShadowLayer;
+ LayerRepresentation m_headerLayer;
+ LayerRepresentation m_footerLayer;
+
+#if PLATFORM(MAC)
+ RetainPtr<NSScrollerImp> m_verticalScrollerImp;
+ RetainPtr<NSScrollerImp> m_horizontalScrollerImp;
+#endif
+
+ EventTrackingRegions m_eventTrackingRegions;
+ FloatPoint m_requestedScrollPosition;
+
+ FloatRect m_layoutViewport;
+ FloatPoint m_minLayoutViewportOrigin;
+ FloatPoint m_maxLayoutViewportOrigin;
+
+ float m_frameScaleFactor { 1 };
+ float m_topContentInset { 0 };
+ int m_headerHeight { 0 };
+ int m_footerHeight { 0 };
+ SynchronousScrollingReasons m_synchronousScrollingReasons { 0 };
+ ScrollBehaviorForFixedElements m_behaviorForFixed { StickToDocumentBounds };
+ bool m_requestedScrollPositionRepresentsProgrammaticScroll { false };
+ bool m_fixedElementsLayoutRelativeToFrame { false };
+ bool m_visualViewportEnabled { false };
+};
+
+} // namespace WebCore
+
+SPECIALIZE_TYPE_TRAITS_SCROLLING_STATE_NODE(ScrollingStateFrameScrollingNode, isFrameScrollingNode())
+
+#endif // ENABLE(ASYNC_SCROLLING) || USE(COORDINATED_GRAPHICS)
diff --git a/Source/WebCore/page/scrolling/ScrollingStateNode.cpp b/Source/WebCore/page/scrolling/ScrollingStateNode.cpp
index 0b60c5acb..61da58a9d 100644
--- a/Source/WebCore/page/scrolling/ScrollingStateNode.cpp
+++ b/Source/WebCore/page/scrolling/ScrollingStateNode.cpp
@@ -41,7 +41,7 @@ ScrollingStateNode::ScrollingStateNode(ScrollingNodeType nodeType, ScrollingStat
, m_nodeID(nodeID)
, m_changedProperties(0)
, m_scrollingStateTree(scrollingStateTree)
- , m_parent(0)
+ , m_parent(nullptr)
{
}
@@ -52,7 +52,7 @@ ScrollingStateNode::ScrollingStateNode(const ScrollingStateNode& stateNode, Scro
, m_nodeID(stateNode.scrollingNodeID())
, m_changedProperties(stateNode.changedProperties())
, m_scrollingStateTree(adoptiveTree)
- , m_parent(0)
+ , m_parent(nullptr)
{
if (hasChangedProperty(ScrollLayer))
setLayer(stateNode.layer().toRepresentation(adoptiveTree.preferredLayerRepresentation()));
@@ -72,15 +72,16 @@ void ScrollingStateNode::setPropertyChanged(unsigned propertyBit)
m_scrollingStateTree.setHasChangedProperties();
}
-PassOwnPtr<ScrollingStateNode> ScrollingStateNode::cloneAndReset(ScrollingStateTree& adoptiveTree)
+Ref<ScrollingStateNode> ScrollingStateNode::cloneAndReset(ScrollingStateTree& adoptiveTree)
{
- OwnPtr<ScrollingStateNode> clone = this->clone(adoptiveTree);
+ auto clone = this->clone(adoptiveTree);
// Now that this node is cloned, reset our change properties.
resetChangedProperties();
- cloneAndResetChildren(*clone, adoptiveTree);
- return clone.release();
+ cloneAndResetChildren(clone.get(), adoptiveTree);
+
+ return clone;
}
void ScrollingStateNode::cloneAndResetChildren(ScrollingStateNode& clone, ScrollingStateTree& adoptiveTree)
@@ -88,51 +89,17 @@ void ScrollingStateNode::cloneAndResetChildren(ScrollingStateNode& clone, Scroll
if (!m_children)
return;
- size_t size = m_children->size();
- for (size_t i = 0; i < size; ++i)
- clone.appendChild(m_children->at(i)->cloneAndReset(adoptiveTree));
+ for (auto& child : *m_children)
+ clone.appendChild(child->cloneAndReset(adoptiveTree));
}
-void ScrollingStateNode::appendChild(PassOwnPtr<ScrollingStateNode> childNode)
+void ScrollingStateNode::appendChild(Ref<ScrollingStateNode>&& childNode)
{
childNode->setParent(this);
if (!m_children)
- m_children = adoptPtr(new Vector<OwnPtr<ScrollingStateNode>>);
-
- m_children->append(childNode);
-}
-
-void ScrollingStateNode::removeChild(ScrollingStateNode* node)
-{
- if (!m_children)
- return;
-
- size_t index = m_children->find(node);
-
- // The index will be notFound if the node to remove is a deeper-than-1-level descendant or
- // if node is the root state node.
- if (index != notFound) {
- node->willBeRemovedFromStateTree();
- m_children->remove(index);
- return;
- }
-
- size_t size = m_children->size();
- for (size_t i = 0; i < size; ++i)
- m_children->at(i)->removeChild(node);
-}
-
-void ScrollingStateNode::willBeRemovedFromStateTree()
-{
- scrollingStateTree().didRemoveNode(scrollingNodeID());
-
- if (!m_children)
- return;
-
- size_t size = m_children->size();
- for (size_t i = 0; i < size; ++i)
- m_children->at(i)->willBeRemovedFromStateTree();
+ m_children = std::make_unique<Vector<RefPtr<ScrollingStateNode>>>();
+ m_children->append(WTFMove(childNode));
}
void ScrollingStateNode::setLayer(const LayerRepresentation& layerRepresentation)
@@ -145,18 +112,17 @@ void ScrollingStateNode::setLayer(const LayerRepresentation& layerRepresentation
setPropertyChanged(ScrollLayer);
}
-void ScrollingStateNode::dump(TextStream& ts, int indent) const
+void ScrollingStateNode::dump(TextStream& ts, int indent, ScrollingStateTreeAsTextBehavior behavior) const
{
writeIndent(ts, indent);
- dumpProperties(ts, indent);
+ dumpProperties(ts, indent, behavior);
if (m_children) {
writeIndent(ts, indent + 1);
- size_t size = children()->size();
- ts << "(children " << size << "\n";
+ ts << "(children " << children()->size() << "\n";
- for (size_t i = 0; i < size; i++)
- m_children->at(i)->dump(ts, indent + 2);
+ for (auto& child : *m_children)
+ child->dump(ts, indent + 2, behavior);
writeIndent(ts, indent + 1);
ts << ")\n";
}
@@ -167,9 +133,9 @@ void ScrollingStateNode::dump(TextStream& ts, int indent) const
String ScrollingStateNode::scrollingStateTreeAsText() const
{
- TextStream ts;
+ TextStream ts(TextStream::LineMode::MultipleLine, TextStream::Formatting::SVGStyleRect);
- dump(ts, 0);
+ dump(ts, 0, ScrollingStateTreeAsTextBehaviorNormal);
return ts.release();
}
diff --git a/Source/WebCore/page/scrolling/ScrollingStateNode.h b/Source/WebCore/page/scrolling/ScrollingStateNode.h
index ca705f3e2..087d61829 100644
--- a/Source/WebCore/page/scrolling/ScrollingStateNode.h
+++ b/Source/WebCore/page/scrolling/ScrollingStateNode.h
@@ -23,27 +23,31 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ScrollingStateNode_h
-#define ScrollingStateNode_h
+#pragma once
#if ENABLE(ASYNC_SCROLLING) || USE(COORDINATED_GRAPHICS)
#include "GraphicsLayer.h"
#include "ScrollingCoordinator.h"
-#include <wtf/OwnPtr.h>
-#include <wtf/PassOwnPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/TypeCasts.h>
#include <wtf/Vector.h>
-#if PLATFORM(MAC)
-#include <wtf/RetainPtr.h>
-#endif
-
namespace WebCore {
class GraphicsLayer;
class ScrollingStateTree;
class TextStream;
+enum ScrollingStateTreeAsTextBehaviorFlags {
+ ScrollingStateTreeAsTextBehaviorNormal = 0,
+ ScrollingStateTreeAsTextBehaviorIncludeLayerIDs = 1 << 0,
+ ScrollingStateTreeAsTextBehaviorIncludeNodeIDs = 1 << 1,
+ ScrollingStateTreeAsTextBehaviorIncludeLayerPositions = 1 << 2,
+ ScrollingStateTreeAsTextBehaviorDebug = ScrollingStateTreeAsTextBehaviorIncludeLayerIDs | ScrollingStateTreeAsTextBehaviorIncludeNodeIDs | ScrollingStateTreeAsTextBehaviorIncludeLayerPositions
+};
+typedef unsigned ScrollingStateTreeAsTextBehavior;
+
// Used to allow ScrollingStateNodes to refer to layers in various contexts:
// a) Async scrolling, main thread: ScrollingStateNode holds onto a GraphicsLayer, and uses m_layerID
// to detect whether that GraphicsLayer's underlying PlatformLayer changed.
@@ -75,14 +79,32 @@ public:
: m_platformLayer(platformLayer)
, m_layerID(0)
, m_representation(PlatformLayerRepresentation)
- { }
+ {
+ retainPlatformLayer(platformLayer);
+ }
LayerRepresentation(GraphicsLayer::PlatformLayerID layerID)
: m_graphicsLayer(nullptr)
, m_layerID(layerID)
, m_representation(PlatformLayerIDRepresentation)
- { }
-
+ {
+ }
+
+ LayerRepresentation(const LayerRepresentation& other)
+ : m_platformLayer(other.m_platformLayer)
+ , m_layerID(other.m_layerID)
+ , m_representation(other.m_representation)
+ {
+ if (m_representation == PlatformLayerRepresentation)
+ retainPlatformLayer(m_platformLayer);
+ }
+
+ ~LayerRepresentation()
+ {
+ if (m_representation == PlatformLayerRepresentation)
+ releasePlatformLayer(m_platformLayer);
+ }
+
operator GraphicsLayer*() const
{
ASSERT(m_representation == GraphicsLayerRepresentation);
@@ -94,14 +116,31 @@ public:
ASSERT(m_representation == PlatformLayerRepresentation);
return m_platformLayer;
}
+
+ GraphicsLayer::PlatformLayerID layerID() const
+ {
+ return m_layerID;
+ }
operator GraphicsLayer::PlatformLayerID() const
{
ASSERT(m_representation != PlatformLayerRepresentation);
return m_layerID;
}
-
- bool operator ==(const LayerRepresentation& other) const
+
+ LayerRepresentation& operator=(const LayerRepresentation& other)
+ {
+ m_platformLayer = other.m_platformLayer;
+ m_layerID = other.m_layerID;
+ m_representation = other.m_representation;
+
+ if (m_representation == PlatformLayerRepresentation)
+ retainPlatformLayer(m_platformLayer);
+
+ return *this;
+ }
+
+ bool operator==(const LayerRepresentation& other) const
{
if (m_representation != other.m_representation)
return false;
@@ -140,6 +179,9 @@ public:
bool representsPlatformLayerID() const { return m_representation == PlatformLayerIDRepresentation; }
private:
+ WEBCORE_EXPORT void retainPlatformLayer(PlatformLayer*);
+ WEBCORE_EXPORT void releasePlatformLayer(PlatformLayer*);
+
union {
GraphicsLayer* m_graphicsLayer;
PlatformLayer *m_platformLayer;
@@ -149,15 +191,22 @@ private:
Type m_representation;
};
-class ScrollingStateNode {
+class ScrollingStateNode : public RefCounted<ScrollingStateNode> {
+ WTF_MAKE_FAST_ALLOCATED;
public:
ScrollingStateNode(ScrollingNodeType, ScrollingStateTree&, ScrollingNodeID);
virtual ~ScrollingStateNode();
ScrollingNodeType nodeType() const { return m_nodeType; }
- virtual PassOwnPtr<ScrollingStateNode> clone(ScrollingStateTree& adoptiveTree) = 0;
- PassOwnPtr<ScrollingStateNode> cloneAndReset(ScrollingStateTree& adoptiveTree);
+ bool isFixedNode() const { return m_nodeType == FixedNode; }
+ bool isStickyNode() const { return m_nodeType == StickyNode; }
+ bool isScrollingNode() const { return m_nodeType == FrameScrollingNode || m_nodeType == OverflowScrollingNode; }
+ bool isFrameScrollingNode() const { return m_nodeType == FrameScrollingNode; }
+ bool isOverflowScrollingNode() const { return m_nodeType == OverflowScrollingNode; }
+
+ virtual Ref<ScrollingStateNode> clone(ScrollingStateTree& adoptiveTree) = 0;
+ Ref<ScrollingStateNode> cloneAndReset(ScrollingStateTree& adoptiveTree);
void cloneAndResetChildren(ScrollingStateNode&, ScrollingStateTree& adoptiveTree);
enum {
@@ -174,10 +223,10 @@ public:
ChangedProperties changedProperties() const { return m_changedProperties; }
void setChangedProperties(ChangedProperties changedProperties) { m_changedProperties = changedProperties; }
- virtual void syncLayerPositionForViewportRect(const LayoutRect& /*viewportRect*/) { }
+ virtual void reconcileLayerPositionForViewportRect(const LayoutRect& /*viewportRect*/, ScrollingLayerPositionAction) { }
const LayerRepresentation& layer() const { return m_layer; }
- void setLayer(const LayerRepresentation&);
+ WEBCORE_EXPORT void setLayer(const LayerRepresentation&);
ScrollingStateTree& scrollingStateTree() const { return m_scrollingStateTree; }
@@ -187,10 +236,9 @@ public:
void setParent(ScrollingStateNode* parent) { m_parent = parent; }
ScrollingNodeID parentNodeID() const { return m_parent ? m_parent->scrollingNodeID() : 0; }
- Vector<OwnPtr<ScrollingStateNode>>* children() const { return m_children.get(); }
+ Vector<RefPtr<ScrollingStateNode>>* children() const { return m_children.get(); }
- void appendChild(PassOwnPtr<ScrollingStateNode>);
- void removeChild(ScrollingStateNode*);
+ void appendChild(Ref<ScrollingStateNode>&&);
String scrollingStateTreeAsText() const;
@@ -198,10 +246,9 @@ protected:
ScrollingStateNode(const ScrollingStateNode&, ScrollingStateTree&);
private:
- void dump(TextStream&, int indent) const;
+ void dump(TextStream&, int indent, ScrollingStateTreeAsTextBehavior) const;
- virtual void dumpProperties(TextStream&, int indent) const = 0;
- void willBeRemovedFromStateTree();
+ virtual void dumpProperties(TextStream&, int indent, ScrollingStateTreeAsTextBehavior) const = 0;
const ScrollingNodeType m_nodeType;
ScrollingNodeID m_nodeID;
@@ -210,16 +257,16 @@ private:
ScrollingStateTree& m_scrollingStateTree;
ScrollingStateNode* m_parent;
- OwnPtr<Vector<OwnPtr<ScrollingStateNode>>> m_children;
+ std::unique_ptr<Vector<RefPtr<ScrollingStateNode>>> m_children;
LayerRepresentation m_layer;
};
-#define SCROLLING_STATE_NODE_TYPE_CASTS(ToValueTypeName, predicate) \
- TYPE_CASTS_BASE(ToValueTypeName, ScrollingStateNode, value, value->predicate, value.predicate)
-
} // namespace WebCore
-#endif // ENABLE(ASYNC_SCROLLING) || USE(COORDINATED_GRAPHICS)
+#define SPECIALIZE_TYPE_TRAITS_SCROLLING_STATE_NODE(ToValueTypeName, predicate) \
+SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::ToValueTypeName) \
+ static bool isType(const WebCore::ScrollingStateNode& node) { return node.predicate; } \
+SPECIALIZE_TYPE_TRAITS_END()
-#endif // ScrollingStateNode_h
+#endif // ENABLE(ASYNC_SCROLLING) || USE(COORDINATED_GRAPHICS)
diff --git a/Source/WebCore/page/scrolling/ScrollingStateOverflowScrollingNode.cpp b/Source/WebCore/page/scrolling/ScrollingStateOverflowScrollingNode.cpp
new file mode 100644
index 000000000..346459a71
--- /dev/null
+++ b/Source/WebCore/page/scrolling/ScrollingStateOverflowScrollingNode.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ScrollingStateOverflowScrollingNode.h"
+
+#if ENABLE(ASYNC_SCROLLING) || USE(COORDINATED_GRAPHICS)
+
+#include "ScrollingStateTree.h"
+#include "TextStream.h"
+
+namespace WebCore {
+
+Ref<ScrollingStateOverflowScrollingNode> ScrollingStateOverflowScrollingNode::create(ScrollingStateTree& stateTree, ScrollingNodeID nodeID)
+{
+ return adoptRef(*new ScrollingStateOverflowScrollingNode(stateTree, nodeID));
+}
+
+ScrollingStateOverflowScrollingNode::ScrollingStateOverflowScrollingNode(ScrollingStateTree& stateTree, ScrollingNodeID nodeID)
+ : ScrollingStateScrollingNode(stateTree, OverflowScrollingNode, nodeID)
+{
+}
+
+ScrollingStateOverflowScrollingNode::ScrollingStateOverflowScrollingNode(const ScrollingStateOverflowScrollingNode& stateNode, ScrollingStateTree& adoptiveTree)
+ : ScrollingStateScrollingNode(stateNode, adoptiveTree)
+{
+ if (hasChangedProperty(ScrolledContentsLayer))
+ setScrolledContentsLayer(stateNode.scrolledContentsLayer().toRepresentation(adoptiveTree.preferredLayerRepresentation()));
+}
+
+ScrollingStateOverflowScrollingNode::~ScrollingStateOverflowScrollingNode()
+{
+}
+
+Ref<ScrollingStateNode> ScrollingStateOverflowScrollingNode::clone(ScrollingStateTree& adoptiveTree)
+{
+ return adoptRef(*new ScrollingStateOverflowScrollingNode(*this, adoptiveTree));
+}
+
+void ScrollingStateOverflowScrollingNode::setScrolledContentsLayer(const LayerRepresentation& layerRepresentation)
+{
+ if (layerRepresentation == m_scrolledContentsLayer)
+ return;
+
+ m_scrolledContentsLayer = layerRepresentation;
+ setPropertyChanged(ScrolledContentsLayer);
+}
+
+void ScrollingStateOverflowScrollingNode::dumpProperties(TextStream& ts, int indent, ScrollingStateTreeAsTextBehavior behavior) const
+{
+ ts << "(" << "Overflow scrolling node" << "\n";
+
+ ScrollingStateScrollingNode::dumpProperties(ts, indent, behavior);
+
+ if ((behavior & ScrollingStateTreeAsTextBehaviorIncludeLayerIDs) && m_scrolledContentsLayer.layerID()) {
+ writeIndent(ts, indent + 1);
+ ts << "(scrolled contents layer " << m_scrolledContentsLayer.layerID() << ")\n";
+ }
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(ASYNC_SCROLLING) || USE(COORDINATED_GRAPHICS)
diff --git a/Source/WebCore/page/scrolling/ScrollingStateOverflowScrollingNode.h b/Source/WebCore/page/scrolling/ScrollingStateOverflowScrollingNode.h
new file mode 100644
index 000000000..042bcf87d
--- /dev/null
+++ b/Source/WebCore/page/scrolling/ScrollingStateOverflowScrollingNode.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(ASYNC_SCROLLING) || USE(COORDINATED_GRAPHICS)
+
+#include "ScrollingStateScrollingNode.h"
+
+namespace WebCore {
+
+class ScrollingStateOverflowScrollingNode : public ScrollingStateScrollingNode {
+public:
+ static Ref<ScrollingStateOverflowScrollingNode> create(ScrollingStateTree&, ScrollingNodeID);
+
+ Ref<ScrollingStateNode> clone(ScrollingStateTree&) override;
+
+ virtual ~ScrollingStateOverflowScrollingNode();
+
+ enum ChangedProperty {
+ ScrolledContentsLayer = NumScrollingStateNodeBits
+ };
+
+ // This is a layer with the contents that move.
+ const LayerRepresentation& scrolledContentsLayer() const { return m_scrolledContentsLayer; }
+ WEBCORE_EXPORT void setScrolledContentsLayer(const LayerRepresentation&);
+
+ void dumpProperties(TextStream&, int indent, ScrollingStateTreeAsTextBehavior) const override;
+
+private:
+ ScrollingStateOverflowScrollingNode(ScrollingStateTree&, ScrollingNodeID);
+ ScrollingStateOverflowScrollingNode(const ScrollingStateOverflowScrollingNode&, ScrollingStateTree&);
+
+ LayerRepresentation m_scrolledContentsLayer;
+};
+
+} // namespace WebCore
+
+SPECIALIZE_TYPE_TRAITS_SCROLLING_STATE_NODE(ScrollingStateOverflowScrollingNode, isOverflowScrollingNode())
+
+#endif // ENABLE(ASYNC_SCROLLING) || USE(COORDINATED_GRAPHICS)
diff --git a/Source/WebCore/page/scrolling/ScrollingStateScrollingNode.cpp b/Source/WebCore/page/scrolling/ScrollingStateScrollingNode.cpp
index 8ef8ff6a5..b3de26324 100644
--- a/Source/WebCore/page/scrolling/ScrollingStateScrollingNode.cpp
+++ b/Source/WebCore/page/scrolling/ScrollingStateScrollingNode.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -30,80 +30,45 @@
#include "ScrollingStateTree.h"
#include "TextStream.h"
-#include <wtf/OwnPtr.h>
namespace WebCore {
-PassOwnPtr<ScrollingStateScrollingNode> ScrollingStateScrollingNode::create(ScrollingStateTree& stateTree, ScrollingNodeID nodeID)
-{
- return adoptPtr(new ScrollingStateScrollingNode(stateTree, nodeID));
-}
-
-ScrollingStateScrollingNode::ScrollingStateScrollingNode(ScrollingStateTree& stateTree, ScrollingNodeID nodeID)
- : ScrollingStateNode(ScrollingNode, stateTree, nodeID)
-#if PLATFORM(MAC) && !PLATFORM(IOS)
- , m_verticalScrollbarPainter(0)
- , m_horizontalScrollbarPainter(0)
-#endif
- , m_frameScaleFactor(1)
- , m_wheelEventHandlerCount(0)
- , m_synchronousScrollingReasons(0)
- , m_behaviorForFixed(StickToDocumentBounds)
- , m_headerHeight(0)
- , m_footerHeight(0)
- , m_requestedScrollPositionRepresentsProgrammaticScroll(false)
+ScrollingStateScrollingNode::ScrollingStateScrollingNode(ScrollingStateTree& stateTree, ScrollingNodeType nodeType, ScrollingNodeID nodeID)
+ : ScrollingStateNode(nodeType, stateTree, nodeID)
{
}
ScrollingStateScrollingNode::ScrollingStateScrollingNode(const ScrollingStateScrollingNode& stateNode, ScrollingStateTree& adoptiveTree)
: ScrollingStateNode(stateNode, adoptiveTree)
-#if PLATFORM(MAC) && !PLATFORM(IOS)
- , m_verticalScrollbarPainter(stateNode.verticalScrollbarPainter())
- , m_horizontalScrollbarPainter(stateNode.horizontalScrollbarPainter())
-#endif
- , m_viewportRect(stateNode.viewportRect())
+ , m_scrollableAreaSize(stateNode.scrollableAreaSize())
, m_totalContentsSize(stateNode.totalContentsSize())
+ , m_reachableContentsSize(stateNode.reachableContentsSize())
+ , m_scrollPosition(stateNode.scrollPosition())
+ , m_requestedScrollPosition(stateNode.requestedScrollPosition())
, m_scrollOrigin(stateNode.scrollOrigin())
+#if ENABLE(CSS_SCROLL_SNAP)
+ , m_snapOffsetsInfo(stateNode.m_snapOffsetsInfo)
+#endif
, m_scrollableAreaParameters(stateNode.scrollableAreaParameters())
- , m_nonFastScrollableRegion(stateNode.nonFastScrollableRegion())
- , m_frameScaleFactor(stateNode.frameScaleFactor())
- , m_wheelEventHandlerCount(stateNode.wheelEventHandlerCount())
- , m_synchronousScrollingReasons(stateNode.synchronousScrollingReasons())
- , m_behaviorForFixed(stateNode.scrollBehaviorForFixedElements())
- , m_headerHeight(stateNode.headerHeight())
- , m_footerHeight(stateNode.footerHeight())
- , m_requestedScrollPosition(stateNode.requestedScrollPosition())
, m_requestedScrollPositionRepresentsProgrammaticScroll(stateNode.requestedScrollPositionRepresentsProgrammaticScroll())
+ , m_expectsWheelEventTestTrigger(stateNode.expectsWheelEventTestTrigger())
{
- if (hasChangedProperty(CounterScrollingLayer))
- setCounterScrollingLayer(stateNode.counterScrollingLayer().toRepresentation(adoptiveTree.preferredLayerRepresentation()));
-
- if (hasChangedProperty(HeaderLayer))
- setHeaderLayer(stateNode.headerLayer().toRepresentation(adoptiveTree.preferredLayerRepresentation()));
-
- if (hasChangedProperty(FooterLayer))
- setFooterLayer(stateNode.footerLayer().toRepresentation(adoptiveTree.preferredLayerRepresentation()));
}
ScrollingStateScrollingNode::~ScrollingStateScrollingNode()
{
}
-PassOwnPtr<ScrollingStateNode> ScrollingStateScrollingNode::clone(ScrollingStateTree& adoptiveTree)
+void ScrollingStateScrollingNode::setScrollableAreaSize(const FloatSize& size)
{
- return adoptPtr(new ScrollingStateScrollingNode(*this, adoptiveTree));
-}
-
-void ScrollingStateScrollingNode::setViewportRect(const IntRect& viewportRect)
-{
- if (m_viewportRect == viewportRect)
+ if (m_scrollableAreaSize == size)
return;
- m_viewportRect = viewportRect;
- setPropertyChanged(ViewportRect);
+ m_scrollableAreaSize = size;
+ setPropertyChanged(ScrollableAreaSize);
}
-void ScrollingStateScrollingNode::setTotalContentsSize(const IntSize& totalContentsSize)
+void ScrollingStateScrollingNode::setTotalContentsSize(const FloatSize& totalContentsSize)
{
if (m_totalContentsSize == totalContentsSize)
return;
@@ -112,159 +77,142 @@ void ScrollingStateScrollingNode::setTotalContentsSize(const IntSize& totalConte
setPropertyChanged(TotalContentsSize);
}
-void ScrollingStateScrollingNode::setScrollOrigin(const IntPoint& scrollOrigin)
+void ScrollingStateScrollingNode::setReachableContentsSize(const FloatSize& reachableContentsSize)
{
- if (m_scrollOrigin == scrollOrigin)
+ if (m_reachableContentsSize == reachableContentsSize)
return;
- m_scrollOrigin = scrollOrigin;
- setPropertyChanged(ScrollOrigin);
+ m_reachableContentsSize = reachableContentsSize;
+ setPropertyChanged(ReachableContentsSize);
}
-void ScrollingStateScrollingNode::setScrollableAreaParameters(const ScrollableAreaParameters& parameters)
+void ScrollingStateScrollingNode::setScrollPosition(const FloatPoint& scrollPosition)
{
- if (m_scrollableAreaParameters == parameters)
+ if (m_scrollPosition == scrollPosition)
return;
- m_scrollableAreaParameters = parameters;
- setPropertyChanged(ScrollableAreaParams);
+ m_scrollPosition = scrollPosition;
+ setPropertyChanged(ScrollPosition);
}
-void ScrollingStateScrollingNode::setFrameScaleFactor(float scaleFactor)
+void ScrollingStateScrollingNode::setScrollOrigin(const IntPoint& scrollOrigin)
{
- if (m_frameScaleFactor == scaleFactor)
+ if (m_scrollOrigin == scrollOrigin)
return;
- m_frameScaleFactor = scaleFactor;
-
- setPropertyChanged(FrameScaleFactor);
+ m_scrollOrigin = scrollOrigin;
+ setPropertyChanged(ScrollOrigin);
}
-void ScrollingStateScrollingNode::setNonFastScrollableRegion(const Region& nonFastScrollableRegion)
+#if ENABLE(CSS_SCROLL_SNAP)
+void ScrollingStateScrollingNode::setHorizontalSnapOffsets(const Vector<float>& snapOffsets)
{
- if (m_nonFastScrollableRegion == nonFastScrollableRegion)
+ if (m_snapOffsetsInfo.horizontalSnapOffsets == snapOffsets)
return;
- m_nonFastScrollableRegion = nonFastScrollableRegion;
- setPropertyChanged(NonFastScrollableRegion);
+ m_snapOffsetsInfo.horizontalSnapOffsets = snapOffsets;
+ setPropertyChanged(HorizontalSnapOffsets);
}
-void ScrollingStateScrollingNode::setWheelEventHandlerCount(unsigned wheelEventHandlerCount)
+void ScrollingStateScrollingNode::setVerticalSnapOffsets(const Vector<float>& snapOffsets)
{
- if (m_wheelEventHandlerCount == wheelEventHandlerCount)
+ if (m_snapOffsetsInfo.verticalSnapOffsets == snapOffsets)
return;
- m_wheelEventHandlerCount = wheelEventHandlerCount;
- setPropertyChanged(WheelEventHandlerCount);
+ m_snapOffsetsInfo.verticalSnapOffsets = snapOffsets;
+ setPropertyChanged(VerticalSnapOffsets);
}
-void ScrollingStateScrollingNode::setSynchronousScrollingReasons(SynchronousScrollingReasons reasons)
+void ScrollingStateScrollingNode::setHorizontalSnapOffsetRanges(const Vector<ScrollOffsetRange<float>>& scrollOffsetRanges)
{
- if (m_synchronousScrollingReasons == reasons)
+ if (m_snapOffsetsInfo.horizontalSnapOffsetRanges == scrollOffsetRanges)
return;
- m_synchronousScrollingReasons = reasons;
- setPropertyChanged(ReasonsForSynchronousScrolling);
+ m_snapOffsetsInfo.horizontalSnapOffsetRanges = scrollOffsetRanges;
+ setPropertyChanged(HorizontalSnapOffsetRanges);
}
-void ScrollingStateScrollingNode::setScrollBehaviorForFixedElements(ScrollBehaviorForFixedElements behaviorForFixed)
+void ScrollingStateScrollingNode::setVerticalSnapOffsetRanges(const Vector<ScrollOffsetRange<float>>& scrollOffsetRanges)
{
- if (m_behaviorForFixed == behaviorForFixed)
+ if (m_snapOffsetsInfo.verticalSnapOffsetRanges == scrollOffsetRanges)
return;
- m_behaviorForFixed = behaviorForFixed;
- setPropertyChanged(BehaviorForFixedElements);
-}
-
-void ScrollingStateScrollingNode::setRequestedScrollPosition(const IntPoint& requestedScrollPosition, bool representsProgrammaticScroll)
-{
- m_requestedScrollPosition = requestedScrollPosition;
- m_requestedScrollPositionRepresentsProgrammaticScroll = representsProgrammaticScroll;
- setPropertyChanged(RequestedScrollPosition);
+ m_snapOffsetsInfo.verticalSnapOffsetRanges = scrollOffsetRanges;
+ setPropertyChanged(VerticalSnapOffsetRanges);
}
-void ScrollingStateScrollingNode::setHeaderHeight(int headerHeight)
+void ScrollingStateScrollingNode::setCurrentHorizontalSnapPointIndex(unsigned index)
{
- if (m_headerHeight == headerHeight)
+ if (m_currentHorizontalSnapPointIndex == index)
return;
-
- m_headerHeight = headerHeight;
- setPropertyChanged(HeaderHeight);
+
+ m_currentHorizontalSnapPointIndex = index;
+ setPropertyChanged(CurrentHorizontalSnapOffsetIndex);
}
-void ScrollingStateScrollingNode::setFooterHeight(int footerHeight)
+void ScrollingStateScrollingNode::setCurrentVerticalSnapPointIndex(unsigned index)
{
- if (m_footerHeight == footerHeight)
+ if (m_currentVerticalSnapPointIndex == index)
return;
-
- m_footerHeight = footerHeight;
- setPropertyChanged(FooterHeight);
+
+ m_currentVerticalSnapPointIndex = index;
+ setPropertyChanged(CurrentVerticalSnapOffsetIndex);
}
+#endif
-void ScrollingStateScrollingNode::setCounterScrollingLayer(const LayerRepresentation& layerRepresentation)
+void ScrollingStateScrollingNode::setScrollableAreaParameters(const ScrollableAreaParameters& parameters)
{
- if (layerRepresentation == m_counterScrollingLayer)
+ if (m_scrollableAreaParameters == parameters)
return;
-
- m_counterScrollingLayer = layerRepresentation;
- setPropertyChanged(CounterScrollingLayer);
+ m_scrollableAreaParameters = parameters;
+ setPropertyChanged(ScrollableAreaParams);
}
-void ScrollingStateScrollingNode::setHeaderLayer(const LayerRepresentation& layerRepresentation)
+void ScrollingStateScrollingNode::setRequestedScrollPosition(const FloatPoint& requestedScrollPosition, bool representsProgrammaticScroll)
{
- if (layerRepresentation == m_headerLayer)
- return;
-
- m_headerLayer = layerRepresentation;
-
- setPropertyChanged(HeaderLayer);
+ m_requestedScrollPosition = requestedScrollPosition;
+ m_requestedScrollPositionRepresentsProgrammaticScroll = representsProgrammaticScroll;
+ setPropertyChanged(RequestedScrollPosition);
}
-
-void ScrollingStateScrollingNode::setFooterLayer(const LayerRepresentation& layerRepresentation)
+void ScrollingStateScrollingNode::setExpectsWheelEventTestTrigger(bool expectsTestTrigger)
{
- if (layerRepresentation == m_footerLayer)
+ if (expectsTestTrigger == m_expectsWheelEventTestTrigger)
return;
-
- m_footerLayer = layerRepresentation;
- setPropertyChanged(FooterLayer);
+ m_expectsWheelEventTestTrigger = expectsTestTrigger;
+ setPropertyChanged(ExpectsWheelEventTestTrigger);
}
-#if !(PLATFORM(MAC) && !PLATFORM(IOS))
-void ScrollingStateScrollingNode::setScrollbarPaintersFromScrollbars(Scrollbar*, Scrollbar*)
+void ScrollingStateScrollingNode::dumpProperties(TextStream& ts, int indent, ScrollingStateTreeAsTextBehavior) const
{
-}
-#endif
-
-void ScrollingStateScrollingNode::dumpProperties(TextStream& ts, int indent) const
-{
- ts << "(" << "Scrolling node" << "\n";
-
- if (!m_viewportRect.isEmpty()) {
+ if (m_scrollPosition != FloatPoint()) {
writeIndent(ts, indent + 1);
- ts << "(viewport rect " << m_viewportRect.x() << " " << m_viewportRect.y() << " " << m_viewportRect.width() << " " << m_viewportRect.height() << ")\n";
+ ts << "(scroll position "
+ << TextStream::FormatNumberRespectingIntegers(m_scrollPosition.x()) << " "
+ << TextStream::FormatNumberRespectingIntegers(m_scrollPosition.y()) << ")\n";
}
- if (!m_totalContentsSize.isEmpty()) {
+ if (!m_scrollableAreaSize.isEmpty()) {
writeIndent(ts, indent + 1);
- ts << "(contents size " << m_totalContentsSize.width() << " " << m_totalContentsSize.height() << ")\n";
+ ts << "(scrollable area size "
+ << TextStream::FormatNumberRespectingIntegers(m_scrollableAreaSize.width()) << " "
+ << TextStream::FormatNumberRespectingIntegers(m_scrollableAreaSize.height()) << ")\n";
}
- if (m_frameScaleFactor != 1) {
- writeIndent(ts, indent + 1);
- ts << "(frame scale factor " << m_frameScaleFactor << ")\n";
- }
-
- if (m_synchronousScrollingReasons) {
+ if (!m_totalContentsSize.isEmpty()) {
writeIndent(ts, indent + 1);
- ts << "(Scrolling on main thread because: " << ScrollingCoordinator::synchronousScrollingReasonsAsText(m_synchronousScrollingReasons) << ")\n";
+ ts << "(contents size "
+ << TextStream::FormatNumberRespectingIntegers(m_totalContentsSize.width()) << " "
+ << TextStream::FormatNumberRespectingIntegers(m_totalContentsSize.height()) << ")\n";
}
if (m_requestedScrollPosition != IntPoint()) {
writeIndent(ts, indent + 1);
- ts << "(requested scroll position " << m_requestedScrollPosition.x() << " " << m_requestedScrollPosition.y() << ")\n";
+ ts << "(requested scroll position "
+ << TextStream::FormatNumberRespectingIntegers(m_requestedScrollPosition.x()) << " "
+ << TextStream::FormatNumberRespectingIntegers(m_requestedScrollPosition.y()) << ")\n";
}
if (m_scrollOrigin != IntPoint()) {
diff --git a/Source/WebCore/page/scrolling/ScrollingStateScrollingNode.h b/Source/WebCore/page/scrolling/ScrollingStateScrollingNode.h
index 14be04b97..628c34f7f 100644
--- a/Source/WebCore/page/scrolling/ScrollingStateScrollingNode.h
+++ b/Source/WebCore/page/scrolling/ScrollingStateScrollingNode.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2014-2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -23,142 +23,111 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ScrollingStateScrollingNode_h
-#define ScrollingStateScrollingNode_h
+#pragma once
#if ENABLE(ASYNC_SCROLLING) || USE(COORDINATED_GRAPHICS)
-#include "GraphicsLayer.h"
-#include "IntRect.h"
-#include "Region.h"
+#include "ScrollSnapOffsetsInfo.h"
#include "ScrollTypes.h"
-#include "ScrollbarThemeComposite.h"
#include "ScrollingCoordinator.h"
#include "ScrollingStateNode.h"
-#include <wtf/PassOwnPtr.h>
namespace WebCore {
-class Scrollbar;
-
-class ScrollingStateScrollingNode final : public ScrollingStateNode {
+class ScrollingStateScrollingNode : public ScrollingStateNode {
public:
- static PassOwnPtr<ScrollingStateScrollingNode> create(ScrollingStateTree&, ScrollingNodeID);
-
- virtual PassOwnPtr<ScrollingStateNode> clone(ScrollingStateTree&);
-
virtual ~ScrollingStateScrollingNode();
enum ChangedProperty {
- ViewportRect = NumStateNodeBits,
+ ScrollableAreaSize = NumStateNodeBits,
TotalContentsSize,
+ ReachableContentsSize,
+ ScrollPosition,
ScrollOrigin,
ScrollableAreaParams,
- FrameScaleFactor,
- NonFastScrollableRegion,
- WheelEventHandlerCount,
- ReasonsForSynchronousScrolling,
RequestedScrollPosition,
- CounterScrollingLayer,
- HeaderHeight,
- FooterHeight,
- HeaderLayer,
- FooterLayer,
- PainterForScrollbar,
- BehaviorForFixedElements
+ NumScrollingStateNodeBits,
+#if ENABLE(CSS_SCROLL_SNAP)
+ HorizontalSnapOffsets,
+ VerticalSnapOffsets,
+ HorizontalSnapOffsetRanges,
+ VerticalSnapOffsetRanges,
+ CurrentHorizontalSnapOffsetIndex,
+ CurrentVerticalSnapOffsetIndex,
+#endif
+ ExpectsWheelEventTestTrigger,
};
- const IntRect& viewportRect() const { return m_viewportRect; }
- void setViewportRect(const IntRect&);
-
- const IntSize& totalContentsSize() const { return m_totalContentsSize; }
- void setTotalContentsSize(const IntSize&);
-
- const IntPoint& scrollOrigin() const { return m_scrollOrigin; }
- void setScrollOrigin(const IntPoint&);
+ const FloatSize& scrollableAreaSize() const { return m_scrollableAreaSize; }
+ WEBCORE_EXPORT void setScrollableAreaSize(const FloatSize&);
- float frameScaleFactor() const { return m_frameScaleFactor; }
- void setFrameScaleFactor(float);
+ const FloatSize& totalContentsSize() const { return m_totalContentsSize; }
+ WEBCORE_EXPORT void setTotalContentsSize(const FloatSize&);
- const Region& nonFastScrollableRegion() const { return m_nonFastScrollableRegion; }
- void setNonFastScrollableRegion(const Region&);
+ const FloatSize& reachableContentsSize() const { return m_reachableContentsSize; }
+ WEBCORE_EXPORT void setReachableContentsSize(const FloatSize&);
- unsigned wheelEventHandlerCount() const { return m_wheelEventHandlerCount; }
- void setWheelEventHandlerCount(unsigned);
+ const FloatPoint& scrollPosition() const { return m_scrollPosition; }
+ WEBCORE_EXPORT void setScrollPosition(const FloatPoint&);
- SynchronousScrollingReasons synchronousScrollingReasons() const { return m_synchronousScrollingReasons; }
- void setSynchronousScrollingReasons(SynchronousScrollingReasons);
-
- const ScrollableAreaParameters& scrollableAreaParameters() const { return m_scrollableAreaParameters; }
- void setScrollableAreaParameters(const ScrollableAreaParameters& params);
-
- ScrollBehaviorForFixedElements scrollBehaviorForFixedElements() const { return m_behaviorForFixed; }
- void setScrollBehaviorForFixedElements(ScrollBehaviorForFixedElements);
-
- const IntPoint& requestedScrollPosition() const { return m_requestedScrollPosition; }
- void setRequestedScrollPosition(const IntPoint&, bool representsProgrammaticScroll);
+ const IntPoint& scrollOrigin() const { return m_scrollOrigin; }
+ WEBCORE_EXPORT void setScrollOrigin(const IntPoint&);
- int headerHeight() const { return m_headerHeight; }
- void setHeaderHeight(int);
+#if ENABLE(CSS_SCROLL_SNAP)
+ const Vector<float>& horizontalSnapOffsets() const { return m_snapOffsetsInfo.horizontalSnapOffsets; }
+ WEBCORE_EXPORT void setHorizontalSnapOffsets(const Vector<float>&);
- int footerHeight() const { return m_footerHeight; }
- void setFooterHeight(int);
+ const Vector<float>& verticalSnapOffsets() const { return m_snapOffsetsInfo.verticalSnapOffsets; }
+ WEBCORE_EXPORT void setVerticalSnapOffsets(const Vector<float>&);
- // This is a layer moved in the opposite direction to scrolling, for example for background-attachment:fixed
- const LayerRepresentation& counterScrollingLayer() const { return m_counterScrollingLayer; }
- void setCounterScrollingLayer(const LayerRepresentation&);
+ const Vector<ScrollOffsetRange<float>>& horizontalSnapOffsetRanges() const { return m_snapOffsetsInfo.horizontalSnapOffsetRanges; }
+ WEBCORE_EXPORT void setHorizontalSnapOffsetRanges(const Vector<ScrollOffsetRange<float>>&);
- // The header and footer layers scroll vertically with the page, they should remain fixed when scrolling horizontally.
- const LayerRepresentation& headerLayer() const { return m_headerLayer; }
- void setHeaderLayer(const LayerRepresentation&);
+ const Vector<ScrollOffsetRange<float>>& verticalSnapOffsetRanges() const { return m_snapOffsetsInfo.verticalSnapOffsetRanges; }
+ WEBCORE_EXPORT void setVerticalSnapOffsetRanges(const Vector<ScrollOffsetRange<float>>&);
- // The header and footer layers scroll vertically with the page, they should remain fixed when scrolling horizontally.
- const LayerRepresentation& footerLayer() const { return m_footerLayer; }
- void setFooterLayer(const LayerRepresentation&);
+ unsigned currentHorizontalSnapPointIndex() const { return m_currentHorizontalSnapPointIndex; }
+ WEBCORE_EXPORT void setCurrentHorizontalSnapPointIndex(unsigned);
-#if PLATFORM(MAC) && !PLATFORM(IOS)
- ScrollbarPainter verticalScrollbarPainter() const { return m_verticalScrollbarPainter.get(); }
- ScrollbarPainter horizontalScrollbarPainter() const { return m_horizontalScrollbarPainter.get(); }
+ unsigned currentVerticalSnapPointIndex() const { return m_currentVerticalSnapPointIndex; }
+ WEBCORE_EXPORT void setCurrentVerticalSnapPointIndex(unsigned);
#endif
- void setScrollbarPaintersFromScrollbars(Scrollbar* verticalScrollbar, Scrollbar* horizontalScrollbar);
+ const ScrollableAreaParameters& scrollableAreaParameters() const { return m_scrollableAreaParameters; }
+ WEBCORE_EXPORT void setScrollableAreaParameters(const ScrollableAreaParameters& params);
+
+ const FloatPoint& requestedScrollPosition() const { return m_requestedScrollPosition; }
bool requestedScrollPositionRepresentsProgrammaticScroll() const { return m_requestedScrollPositionRepresentsProgrammaticScroll; }
+ WEBCORE_EXPORT void setRequestedScrollPosition(const FloatPoint&, bool representsProgrammaticScroll);
- virtual void dumpProperties(TextStream&, int indent) const override;
+ bool expectsWheelEventTestTrigger() const { return m_expectsWheelEventTestTrigger; }
+ WEBCORE_EXPORT void setExpectsWheelEventTestTrigger(bool);
-private:
- ScrollingStateScrollingNode(ScrollingStateTree&, ScrollingNodeID);
+protected:
+ ScrollingStateScrollingNode(ScrollingStateTree&, ScrollingNodeType, ScrollingNodeID);
ScrollingStateScrollingNode(const ScrollingStateScrollingNode&, ScrollingStateTree&);
- LayerRepresentation m_counterScrollingLayer;
- LayerRepresentation m_headerLayer;
- LayerRepresentation m_footerLayer;
-
-#if PLATFORM(MAC) && !PLATFORM(IOS)
- RetainPtr<ScrollbarPainter> m_verticalScrollbarPainter;
- RetainPtr<ScrollbarPainter> m_horizontalScrollbarPainter;
-#endif
-
- IntRect m_viewportRect;
- IntSize m_totalContentsSize;
- IntPoint m_scrollOrigin;
+ void dumpProperties(TextStream&, int indent, ScrollingStateTreeAsTextBehavior) const override;
+private:
+ FloatSize m_scrollableAreaSize;
+ FloatSize m_totalContentsSize;
+ FloatSize m_reachableContentsSize;
+ FloatPoint m_scrollPosition;
+ FloatPoint m_requestedScrollPosition;
+ IntPoint m_scrollOrigin;
+#if ENABLE(CSS_SCROLL_SNAP)
+ ScrollSnapOffsetsInfo<float> m_snapOffsetsInfo;
+ unsigned m_currentHorizontalSnapPointIndex { 0 };
+ unsigned m_currentVerticalSnapPointIndex { 0 };
+#endif
ScrollableAreaParameters m_scrollableAreaParameters;
- Region m_nonFastScrollableRegion;
- float m_frameScaleFactor;
- unsigned m_wheelEventHandlerCount;
- SynchronousScrollingReasons m_synchronousScrollingReasons;
- ScrollBehaviorForFixedElements m_behaviorForFixed;
- int m_headerHeight;
- int m_footerHeight;
- IntPoint m_requestedScrollPosition;
- bool m_requestedScrollPositionRepresentsProgrammaticScroll;
+ bool m_requestedScrollPositionRepresentsProgrammaticScroll { false };
+ bool m_expectsWheelEventTestTrigger { false };
};
-SCROLLING_STATE_NODE_TYPE_CASTS(ScrollingStateScrollingNode, nodeType() == ScrollingNode);
-
} // namespace WebCore
-#endif // ENABLE(ASYNC_SCROLLING) || USE(COORDINATED_GRAPHICS)
+SPECIALIZE_TYPE_TRAITS_SCROLLING_STATE_NODE(ScrollingStateScrollingNode, isScrollingNode())
-#endif // ScrollingStateScrollingNode_h
+#endif // ENABLE(ASYNC_SCROLLING) || USE(COORDINATED_GRAPHICS)
diff --git a/Source/WebCore/page/scrolling/ScrollingStateStickyNode.cpp b/Source/WebCore/page/scrolling/ScrollingStateStickyNode.cpp
new file mode 100644
index 000000000..912f5b9d7
--- /dev/null
+++ b/Source/WebCore/page/scrolling/ScrollingStateStickyNode.cpp
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ScrollingStateStickyNode.h"
+
+#if ENABLE(ASYNC_SCROLLING) || USE(COORDINATED_GRAPHICS)
+
+#include "GraphicsLayer.h"
+#include "Logging.h"
+#include "ScrollingStateTree.h"
+#include "TextStream.h"
+
+namespace WebCore {
+
+Ref<ScrollingStateStickyNode> ScrollingStateStickyNode::create(ScrollingStateTree& stateTree, ScrollingNodeID nodeID)
+{
+ return adoptRef(*new ScrollingStateStickyNode(stateTree, nodeID));
+}
+
+ScrollingStateStickyNode::ScrollingStateStickyNode(ScrollingStateTree& tree, ScrollingNodeID nodeID)
+ : ScrollingStateNode(StickyNode, tree, nodeID)
+{
+}
+
+ScrollingStateStickyNode::ScrollingStateStickyNode(const ScrollingStateStickyNode& node, ScrollingStateTree& adoptiveTree)
+ : ScrollingStateNode(node, adoptiveTree)
+ , m_constraints(StickyPositionViewportConstraints(node.viewportConstraints()))
+{
+}
+
+ScrollingStateStickyNode::~ScrollingStateStickyNode()
+{
+}
+
+Ref<ScrollingStateNode> ScrollingStateStickyNode::clone(ScrollingStateTree& adoptiveTree)
+{
+ return adoptRef(*new ScrollingStateStickyNode(*this, adoptiveTree));
+}
+
+void ScrollingStateStickyNode::updateConstraints(const StickyPositionViewportConstraints& constraints)
+{
+ if (m_constraints == constraints)
+ return;
+
+ m_constraints = constraints;
+ setPropertyChanged(ViewportConstraints);
+}
+
+void ScrollingStateStickyNode::reconcileLayerPositionForViewportRect(const LayoutRect& viewportRect, ScrollingLayerPositionAction action)
+{
+ FloatPoint position = m_constraints.layerPositionForConstrainingRect(viewportRect);
+ if (layer().representsGraphicsLayer()) {
+ GraphicsLayer* graphicsLayer = static_cast<GraphicsLayer*>(layer());
+
+ LOG_WITH_STREAM(Compositing, stream << "ScrollingStateStickyNode::reconcileLayerPositionForViewportRect setting position of layer " << graphicsLayer->primaryLayerID() << " to " << position);
+
+ switch (action) {
+ case ScrollingLayerPositionAction::Set:
+ graphicsLayer->setPosition(position);
+ break;
+
+ case ScrollingLayerPositionAction::SetApproximate:
+ graphicsLayer->setApproximatePosition(position);
+ break;
+
+ case ScrollingLayerPositionAction::Sync:
+ graphicsLayer->syncPosition(position);
+ break;
+ }
+ }
+}
+
+void ScrollingStateStickyNode::dumpProperties(TextStream& ts, int indent, ScrollingStateTreeAsTextBehavior) const
+{
+ ts << "(" << "Sticky node" << "\n";
+
+ if (m_constraints.anchorEdges()) {
+ writeIndent(ts, indent + 1);
+ ts << "(anchor edges: ";
+ if (m_constraints.hasAnchorEdge(ViewportConstraints::AnchorEdgeLeft))
+ ts << "AnchorEdgeLeft ";
+ if (m_constraints.hasAnchorEdge(ViewportConstraints::AnchorEdgeRight))
+ ts << "AnchorEdgeRight ";
+ if (m_constraints.hasAnchorEdge(ViewportConstraints::AnchorEdgeTop))
+ ts << "AnchorEdgeTop ";
+ if (m_constraints.hasAnchorEdge(ViewportConstraints::AnchorEdgeBottom))
+ ts << "AnchorEdgeBottom";
+ ts << ")\n";
+ }
+
+ if (m_constraints.hasAnchorEdge(ViewportConstraints::AnchorEdgeLeft)) {
+ writeIndent(ts, indent + 1);
+ ts << "(left offset " << m_constraints.leftOffset() << ")\n";
+ }
+ if (m_constraints.hasAnchorEdge(ViewportConstraints::AnchorEdgeRight)) {
+ writeIndent(ts, indent + 1);
+ ts << "(right offset " << m_constraints.rightOffset() << ")\n";
+ }
+ if (m_constraints.hasAnchorEdge(ViewportConstraints::AnchorEdgeTop)) {
+ writeIndent(ts, indent + 1);
+ ts << "(top offset " << m_constraints.topOffset() << ")\n";
+ }
+ if (m_constraints.hasAnchorEdge(ViewportConstraints::AnchorEdgeBottom)) {
+ writeIndent(ts, indent + 1);
+ ts << "(bottom offset " << m_constraints.bottomOffset() << ")\n";
+ }
+
+ writeIndent(ts, indent + 1);
+ FloatRect r = m_constraints.containingBlockRect();
+ ts << "(containing block rect " << r.x() << ", " << r.y() << " " << r.width() << " x " << r.height() << ")\n";
+
+ writeIndent(ts, indent + 1);
+ r = m_constraints.stickyBoxRect();
+ ts << "(sticky box rect " << r.x() << " " << r.y() << " " << r.width() << " " << r.height() << ")\n";
+
+ writeIndent(ts, indent + 1);
+ r = m_constraints.constrainingRectAtLastLayout();
+ ts << "(constraining rect " << r.x() << " " << r.y() << " " << r.width() << " " << r.height() << ")\n";
+
+ writeIndent(ts, indent + 1);
+ ts << "(sticky offset at last layout " << m_constraints.stickyOffsetAtLastLayout().width() << " " << m_constraints.stickyOffsetAtLastLayout().height() << ")\n";
+
+ writeIndent(ts, indent + 1);
+ ts << "(layer position at last layout " << m_constraints.layerPositionAtLastLayout().x() << " " << m_constraints.layerPositionAtLastLayout().y() << ")\n";
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(ASYNC_SCROLLING) || USE(COORDINATED_GRAPHICS)
diff --git a/Source/WebCore/page/scrolling/ScrollingStateStickyNode.h b/Source/WebCore/page/scrolling/ScrollingStateStickyNode.h
new file mode 100644
index 000000000..63f908e76
--- /dev/null
+++ b/Source/WebCore/page/scrolling/ScrollingStateStickyNode.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(ASYNC_SCROLLING) || USE(COORDINATED_GRAPHICS)
+
+#include "ScrollingConstraints.h"
+#include "ScrollingStateNode.h"
+
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+class StickyPositionViewportConstraints;
+
+class ScrollingStateStickyNode final : public ScrollingStateNode {
+public:
+ static Ref<ScrollingStateStickyNode> create(ScrollingStateTree&, ScrollingNodeID);
+
+ Ref<ScrollingStateNode> clone(ScrollingStateTree&) override;
+
+ virtual ~ScrollingStateStickyNode();
+
+ enum {
+ ViewportConstraints = NumStateNodeBits
+ };
+
+ WEBCORE_EXPORT void updateConstraints(const StickyPositionViewportConstraints&);
+ const StickyPositionViewportConstraints& viewportConstraints() const { return m_constraints; }
+
+private:
+ ScrollingStateStickyNode(ScrollingStateTree&, ScrollingNodeID);
+ ScrollingStateStickyNode(const ScrollingStateStickyNode&, ScrollingStateTree&);
+
+ void reconcileLayerPositionForViewportRect(const LayoutRect& viewportRect, ScrollingLayerPositionAction) override;
+
+ void dumpProperties(TextStream&, int indent, ScrollingStateTreeAsTextBehavior) const override;
+
+ StickyPositionViewportConstraints m_constraints;
+};
+
+} // namespace WebCore
+
+SPECIALIZE_TYPE_TRAITS_SCROLLING_STATE_NODE(ScrollingStateStickyNode, isStickyNode())
+
+#endif // ENABLE(ASYNC_SCROLLING) || USE(COORDINATED_GRAPHICS)
diff --git a/Source/WebCore/page/scrolling/ScrollingStateTree.cpp b/Source/WebCore/page/scrolling/ScrollingStateTree.cpp
index e06f22168..0bbc1b733 100644
--- a/Source/WebCore/page/scrolling/ScrollingStateTree.cpp
+++ b/Source/WebCore/page/scrolling/ScrollingStateTree.cpp
@@ -30,15 +30,16 @@
#include "AsyncScrollingCoordinator.h"
#include "ScrollingStateFixedNode.h"
-#include "ScrollingStateScrollingNode.h"
+#include "ScrollingStateFrameScrollingNode.h"
+#include "ScrollingStateOverflowScrollingNode.h"
#include "ScrollingStateStickyNode.h"
+#include <wtf/text/CString.h>
-namespace WebCore {
+#ifndef NDEBUG
+#include <stdio.h>
+#endif
-PassOwnPtr<ScrollingStateTree> ScrollingStateTree::create(AsyncScrollingCoordinator* scrollingCoordinator)
-{
- return adoptPtr(new ScrollingStateTree(scrollingCoordinator));
-}
+namespace WebCore {
ScrollingStateTree::ScrollingStateTree(AsyncScrollingCoordinator* scrollingCoordinator)
: m_scrollingCoordinator(scrollingCoordinator)
@@ -66,27 +67,58 @@ void ScrollingStateTree::setHasChangedProperties(bool changedProperties)
#endif
}
+Ref<ScrollingStateNode> ScrollingStateTree::createNode(ScrollingNodeType nodeType, ScrollingNodeID nodeID)
+{
+ switch (nodeType) {
+ case FixedNode:
+ return ScrollingStateFixedNode::create(*this, nodeID);
+ case StickyNode:
+ return ScrollingStateStickyNode::create(*this, nodeID);
+ case FrameScrollingNode:
+ return ScrollingStateFrameScrollingNode::create(*this, nodeID);
+ case OverflowScrollingNode:
+ return ScrollingStateOverflowScrollingNode::create(*this, nodeID);
+ }
+ ASSERT_NOT_REACHED();
+ return ScrollingStateFixedNode::create(*this, nodeID);
+}
+
+bool ScrollingStateTree::nodeTypeAndParentMatch(ScrollingStateNode& node, ScrollingNodeType nodeType, ScrollingNodeID parentID) const
+{
+ if (node.nodeType() != nodeType)
+ return false;
+
+ ScrollingStateNode* parent = stateNodeForID(parentID);
+ if (!parent)
+ return true;
+
+ return node.parent() == parent;
+}
+
ScrollingNodeID ScrollingStateTree::attachNode(ScrollingNodeType nodeType, ScrollingNodeID newNodeID, ScrollingNodeID parentID)
{
ASSERT(newNodeID);
if (ScrollingStateNode* node = stateNodeForID(newNodeID)) {
- ScrollingStateNode* parent = stateNodeForID(parentID);
- if (!parent)
- return newNodeID;
- if (node->parent() == parent)
+ if (nodeTypeAndParentMatch(*node, nodeType, parentID))
return newNodeID;
- // The node is being re-parented. To do that, we'll remove it, and then re-create a new node.
- removeNode(node);
+#if ENABLE(ASYNC_SCROLLING)
+ // If the type has changed, we need to destroy and recreate the node with a new ID.
+ if (nodeType != node->nodeType())
+ newNodeID = m_scrollingCoordinator->uniqueScrollLayerID();
+#endif
+
+ // The node is being re-parented. To do that, we'll remove it, and then create a new node.
+ removeNodeAndAllDescendants(node, SubframeNodeRemoval::Orphan);
}
- ScrollingStateNode* newNode = 0;
+ ScrollingStateNode* newNode = nullptr;
if (!parentID) {
// If we're resetting the root node, we should clear the HashMap and destroy the current children.
clear();
- setRootStateNode(ScrollingStateScrollingNode::create(*this, newNodeID));
+ setRootStateNode(ScrollingStateFrameScrollingNode::create(*this, newNodeID));
newNode = rootStateNode();
m_hasNewRootStateNode = true;
} else {
@@ -94,31 +126,22 @@ ScrollingNodeID ScrollingStateTree::attachNode(ScrollingNodeType nodeType, Scrol
if (!parent)
return 0;
- switch (nodeType) {
- case FixedNode: {
- OwnPtr<ScrollingStateFixedNode> fixedNode = ScrollingStateFixedNode::create(*this, newNodeID);
- newNode = fixedNode.get();
- parent->appendChild(fixedNode.release());
- break;
- }
- case StickyNode: {
- OwnPtr<ScrollingStateStickyNode> stickyNode = ScrollingStateStickyNode::create(*this, newNodeID);
- newNode = stickyNode.get();
- parent->appendChild(stickyNode.release());
- break;
- }
- case ScrollingNode: {
- // FIXME: We currently only support child nodes that are fixed.
- ASSERT_NOT_REACHED();
- OwnPtr<ScrollingStateScrollingNode> scrollingNode = ScrollingStateScrollingNode::create(*this, newNodeID);
- newNode = scrollingNode.get();
- parent->appendChild(scrollingNode.release());
- break;
+ if (nodeType == FrameScrollingNode && parentID) {
+ if (auto orphanedNode = m_orphanedSubframeNodes.take(newNodeID)) {
+ newNode = orphanedNode.get();
+ parent->appendChild(orphanedNode.releaseNonNull());
+ }
}
+
+ if (!newNode) {
+ auto stateNode = createNode(nodeType, newNodeID);
+ newNode = stateNode.ptr();
+ parent->appendChild(WTFMove(stateNode));
}
}
m_stateNodeMap.set(newNodeID, newNode);
+ m_nodesRemovedSinceLastCommit.remove(newNodeID);
return newNodeID;
}
@@ -132,35 +155,46 @@ void ScrollingStateTree::detachNode(ScrollingNodeID nodeID)
if (!node)
return;
- removeNode(node);
+ removeNodeAndAllDescendants(node, SubframeNodeRemoval::Orphan);
}
void ScrollingStateTree::clear()
{
- removeNode(rootStateNode());
+ if (rootStateNode())
+ removeNodeAndAllDescendants(rootStateNode());
+
m_stateNodeMap.clear();
+ m_orphanedSubframeNodes.clear();
}
-PassOwnPtr<ScrollingStateTree> ScrollingStateTree::commit(LayerRepresentation::Type preferredLayerRepresentation)
+std::unique_ptr<ScrollingStateTree> ScrollingStateTree::commit(LayerRepresentation::Type preferredLayerRepresentation)
{
+ if (!m_orphanedSubframeNodes.isEmpty()) {
+ // If we still have orphaned subtrees, remove them from m_stateNodeMap since they will be deleted
+ // when clearing m_orphanedSubframeNodes.
+ for (auto& orphanNode : m_orphanedSubframeNodes.values())
+ recursiveNodeWillBeRemoved(orphanNode.get(), SubframeNodeRemoval::Delete);
+ m_orphanedSubframeNodes.clear();
+ }
+
// This function clones and resets the current state tree, but leaves the tree structure intact.
- OwnPtr<ScrollingStateTree> treeStateClone = ScrollingStateTree::create();
+ std::unique_ptr<ScrollingStateTree> treeStateClone = std::make_unique<ScrollingStateTree>();
treeStateClone->setPreferredLayerRepresentation(preferredLayerRepresentation);
if (m_rootStateNode)
- treeStateClone->setRootStateNode(static_pointer_cast<ScrollingStateScrollingNode>(m_rootStateNode->cloneAndReset(*treeStateClone)));
+ treeStateClone->setRootStateNode(static_reference_cast<ScrollingStateFrameScrollingNode>(m_rootStateNode->cloneAndReset(*treeStateClone)));
// Copy the IDs of the nodes that have been removed since the last commit into the clone.
treeStateClone->m_nodesRemovedSinceLastCommit.swap(m_nodesRemovedSinceLastCommit);
// Now the clone tree has changed properties, and the original tree does not.
- treeStateClone->m_hasChangedProperties = true;
+ treeStateClone->m_hasChangedProperties = m_hasChangedProperties;
m_hasChangedProperties = false;
treeStateClone->m_hasNewRootStateNode = m_hasNewRootStateNode;
m_hasNewRootStateNode = false;
- return treeStateClone.release();
+ return treeStateClone;
}
void ScrollingStateTree::addNode(ScrollingStateNode* node)
@@ -168,39 +202,54 @@ void ScrollingStateTree::addNode(ScrollingStateNode* node)
m_stateNodeMap.add(node->scrollingNodeID(), node);
}
-void ScrollingStateTree::removeNode(ScrollingStateNode* node)
+void ScrollingStateTree::removeNodeAndAllDescendants(ScrollingStateNode* node, SubframeNodeRemoval subframeNodeRemoval)
{
- if (!node)
- return;
+ ScrollingStateNode* parent = node->parent();
- if (node == m_rootStateNode) {
- didRemoveNode(node->scrollingNodeID());
+ recursiveNodeWillBeRemoved(node, subframeNodeRemoval);
+
+ if (node == m_rootStateNode)
m_rootStateNode = nullptr;
+ else if (parent) {
+ ASSERT(parent->children());
+ ASSERT(parent->children()->find(node) != notFound);
+ if (auto children = parent->children()) {
+ size_t index = children->find(node);
+ if (index != notFound)
+ children->remove(index);
+ }
+ }
+}
+
+void ScrollingStateTree::recursiveNodeWillBeRemoved(ScrollingStateNode* currNode, SubframeNodeRemoval subframeNodeRemoval)
+{
+ currNode->setParent(nullptr);
+ if (subframeNodeRemoval == SubframeNodeRemoval::Orphan && currNode != m_rootStateNode && currNode->isFrameScrollingNode()) {
+ m_orphanedSubframeNodes.add(currNode->scrollingNodeID(), currNode);
return;
}
- ASSERT(m_rootStateNode);
- m_rootStateNode->removeChild(node);
+ willRemoveNode(currNode);
- // ScrollingStateTree::removeNode() will destroy children, so we have to make sure we remove those children
- // from the HashMap.
- size_t size = m_nodesRemovedSinceLastCommit.size();
- for (size_t i = 0; i < size; ++i)
- m_stateNodeMap.remove(m_nodesRemovedSinceLastCommit[i]);
+ if (auto children = currNode->children()) {
+ for (auto& child : *children)
+ recursiveNodeWillBeRemoved(child.get(), subframeNodeRemoval);
+ }
}
-void ScrollingStateTree::didRemoveNode(ScrollingNodeID nodeID)
+void ScrollingStateTree::willRemoveNode(ScrollingStateNode* node)
{
- m_nodesRemovedSinceLastCommit.append(nodeID);
+ m_nodesRemovedSinceLastCommit.add(node->scrollingNodeID());
+ m_stateNodeMap.remove(node->scrollingNodeID());
setHasChangedProperties();
}
-void ScrollingStateTree::setRemovedNodes(Vector<ScrollingNodeID> nodes)
+void ScrollingStateTree::setRemovedNodes(HashSet<ScrollingNodeID> nodes)
{
- m_nodesRemovedSinceLastCommit = std::move(nodes);
+ m_nodesRemovedSinceLastCommit = WTFMove(nodes);
}
-ScrollingStateNode* ScrollingStateTree::stateNodeForID(ScrollingNodeID scrollLayerID)
+ScrollingStateNode* ScrollingStateTree::stateNodeForID(ScrollingNodeID scrollLayerID) const
{
if (!scrollLayerID)
return 0;
@@ -215,4 +264,30 @@ ScrollingStateNode* ScrollingStateTree::stateNodeForID(ScrollingNodeID scrollLay
} // namespace WebCore
+#ifndef NDEBUG
+void showScrollingStateTree(const WebCore::ScrollingStateTree* tree)
+{
+ if (!tree)
+ return;
+
+ auto rootNode = tree->rootStateNode();
+ if (!rootNode) {
+ fprintf(stderr, "Scrolling state tree %p with no root node\n", tree);
+ return;
+ }
+
+ String output = rootNode->scrollingStateTreeAsText();
+ fprintf(stderr, "%s\n", output.utf8().data());
+}
+
+void showScrollingStateTree(const WebCore::ScrollingStateNode* node)
+{
+ if (!node)
+ return;
+
+ showScrollingStateTree(&node->scrollingStateTree());
+}
+
+#endif
+
#endif // ENABLE(ASYNC_SCROLLING) || USE(COORDINATED_GRAPHICS)
diff --git a/Source/WebCore/page/scrolling/ScrollingStateTree.h b/Source/WebCore/page/scrolling/ScrollingStateTree.h
index 59659e534..3b256151a 100644
--- a/Source/WebCore/page/scrolling/ScrollingStateTree.h
+++ b/Source/WebCore/page/scrolling/ScrollingStateTree.h
@@ -23,14 +23,11 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ScrollingStateTree_h
-#define ScrollingStateTree_h
+#pragma once
#if ENABLE(ASYNC_SCROLLING) || USE(COORDINATED_GRAPHICS)
-#include "ScrollingStateScrollingNode.h"
-#include <wtf/OwnPtr.h>
-#include <wtf/PassOwnPtr.h>
+#include "ScrollingStateFrameScrollingNode.h"
#include <wtf/RefPtr.h>
namespace WebCore {
@@ -43,29 +40,30 @@ class AsyncScrollingCoordinator;
// the scrolling thread, avoiding locking.
class ScrollingStateTree {
+ WTF_MAKE_FAST_ALLOCATED;
friend class ScrollingStateNode;
public:
-
- static PassOwnPtr<ScrollingStateTree> create(AsyncScrollingCoordinator* = 0);
- ~ScrollingStateTree();
+ WEBCORE_EXPORT ScrollingStateTree(AsyncScrollingCoordinator* = nullptr);
+ WEBCORE_EXPORT ~ScrollingStateTree();
- ScrollingStateScrollingNode* rootStateNode() const { return m_rootStateNode.get(); }
- ScrollingStateNode* stateNodeForID(ScrollingNodeID);
+ ScrollingStateFrameScrollingNode* rootStateNode() const { return m_rootStateNode.get(); }
+ WEBCORE_EXPORT ScrollingStateNode* stateNodeForID(ScrollingNodeID) const;
- ScrollingNodeID attachNode(ScrollingNodeType, ScrollingNodeID, ScrollingNodeID parentID);
+ WEBCORE_EXPORT ScrollingNodeID attachNode(ScrollingNodeType, ScrollingNodeID, ScrollingNodeID parentID);
void detachNode(ScrollingNodeID);
void clear();
- const Vector<ScrollingNodeID>& removedNodes() const { return m_nodesRemovedSinceLastCommit; }
- void setRemovedNodes(Vector<ScrollingNodeID>);
+ const HashSet<ScrollingNodeID>& removedNodes() const { return m_nodesRemovedSinceLastCommit; }
+ WEBCORE_EXPORT void setRemovedNodes(HashSet<ScrollingNodeID>);
// Copies the current tree state and clears the changed properties mask in the original.
- PassOwnPtr<ScrollingStateTree> commit(LayerRepresentation::Type preferredLayerRepresentation);
+ WEBCORE_EXPORT std::unique_ptr<ScrollingStateTree> commit(LayerRepresentation::Type preferredLayerRepresentation);
- void setHasChangedProperties(bool = true);
+ WEBCORE_EXPORT void setHasChangedProperties(bool = true);
bool hasChangedProperties() const { return m_hasChangedProperties; }
bool hasNewRootStateNode() const { return m_hasNewRootStateNode; }
+ void setHasNewRootStateNode(bool hasNewRoot) { m_hasNewRootStateNode = hasNewRoot; }
int nodeCount() const { return m_stateNodeMap.size(); }
@@ -76,17 +74,24 @@ public:
void setPreferredLayerRepresentation(LayerRepresentation::Type representation) { m_preferredLayerRepresentation = representation; }
private:
- ScrollingStateTree(AsyncScrollingCoordinator*);
-
- void setRootStateNode(PassOwnPtr<ScrollingStateScrollingNode> rootStateNode) { m_rootStateNode = rootStateNode; }
+ void setRootStateNode(Ref<ScrollingStateFrameScrollingNode>&& rootStateNode) { m_rootStateNode = WTFMove(rootStateNode); }
void addNode(ScrollingStateNode*);
- void removeNode(ScrollingStateNode*);
- void didRemoveNode(ScrollingNodeID);
+
+ Ref<ScrollingStateNode> createNode(ScrollingNodeType, ScrollingNodeID);
+
+ bool nodeTypeAndParentMatch(ScrollingStateNode&, ScrollingNodeType, ScrollingNodeID parentID) const;
+
+ enum class SubframeNodeRemoval { Delete, Orphan };
+ void removeNodeAndAllDescendants(ScrollingStateNode*, SubframeNodeRemoval = SubframeNodeRemoval::Delete);
+
+ void recursiveNodeWillBeRemoved(ScrollingStateNode* currNode, SubframeNodeRemoval);
+ void willRemoveNode(ScrollingStateNode*);
AsyncScrollingCoordinator* m_scrollingCoordinator;
StateNodeMap m_stateNodeMap;
- OwnPtr<ScrollingStateScrollingNode> m_rootStateNode;
- Vector<ScrollingNodeID> m_nodesRemovedSinceLastCommit;
+ RefPtr<ScrollingStateFrameScrollingNode> m_rootStateNode;
+ HashSet<ScrollingNodeID> m_nodesRemovedSinceLastCommit;
+ HashMap<ScrollingNodeID, RefPtr<ScrollingStateNode>> m_orphanedSubframeNodes;
bool m_hasChangedProperties;
bool m_hasNewRootStateNode;
LayerRepresentation::Type m_preferredLayerRepresentation;
@@ -94,6 +99,9 @@ private:
} // namespace WebCore
-#endif // ENABLE(ASYNC_SCROLLING) || USE(COORDINATED_GRAPHICS)
+#ifndef NDEBUG
+void showScrollingStateTree(const WebCore::ScrollingStateTree*);
+void showScrollingStateTree(const WebCore::ScrollingStateNode*);
+#endif
-#endif // ScrollingStateTree_h
+#endif // ENABLE(ASYNC_SCROLLING) || USE(COORDINATED_GRAPHICS)
diff --git a/Source/WebCore/page/scrolling/ScrollingThread.cpp b/Source/WebCore/page/scrolling/ScrollingThread.cpp
new file mode 100644
index 000000000..730c0a6bd
--- /dev/null
+++ b/Source/WebCore/page/scrolling/ScrollingThread.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2012, 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ScrollingThread.h"
+
+#if ENABLE(ASYNC_SCROLLING)
+
+#include <mutex>
+#include <wtf/MainThread.h>
+#include <wtf/NeverDestroyed.h>
+
+namespace WebCore {
+
+ScrollingThread::ScrollingThread()
+ : m_threadIdentifier(0)
+{
+}
+
+bool ScrollingThread::isCurrentThread()
+{
+ auto threadIdentifier = ScrollingThread::singleton().m_threadIdentifier;
+ return threadIdentifier && currentThread() == threadIdentifier;
+}
+
+void ScrollingThread::dispatch(Function<void ()>&& function)
+{
+ auto& scrollingThread = ScrollingThread::singleton();
+ scrollingThread.createThreadIfNeeded();
+
+ {
+ std::lock_guard<Lock> lock(scrollingThread.m_functionsMutex);
+ scrollingThread.m_functions.append(WTFMove(function));
+ }
+
+ scrollingThread.wakeUpRunLoop();
+}
+
+void ScrollingThread::dispatchBarrier(Function<void ()>&& function)
+{
+ dispatch([function = WTFMove(function)]() mutable {
+ callOnMainThread(WTFMove(function));
+ });
+}
+
+ScrollingThread& ScrollingThread::singleton()
+{
+ static NeverDestroyed<ScrollingThread> scrollingThread;
+
+ return scrollingThread;
+}
+
+void ScrollingThread::createThreadIfNeeded()
+{
+ if (m_threadIdentifier)
+ return;
+
+ // Wait for the thread to initialize the run loop.
+ {
+ std::unique_lock<Lock> lock(m_initializeRunLoopMutex);
+
+ m_threadIdentifier = createThread(threadCallback, this, "WebCore: Scrolling");
+
+#if PLATFORM(COCOA)
+ m_initializeRunLoopConditionVariable.wait(lock, [this]{ return m_threadRunLoop; });
+#endif
+ }
+}
+
+void ScrollingThread::threadCallback(void* scrollingThread)
+{
+ WTF::setCurrentThreadIsUserInteractive();
+ static_cast<ScrollingThread*>(scrollingThread)->threadBody();
+}
+
+void ScrollingThread::threadBody()
+{
+ initializeRunLoop();
+}
+
+void ScrollingThread::dispatchFunctionsFromScrollingThread()
+{
+ ASSERT(isCurrentThread());
+
+ Vector<Function<void ()>> functions;
+
+ {
+ std::lock_guard<Lock> lock(m_functionsMutex);
+ functions = WTFMove(m_functions);
+ }
+
+ for (auto& function : functions)
+ function();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(ASYNC_SCROLLING)
diff --git a/Source/WebCore/page/scrolling/ScrollingThread.h b/Source/WebCore/page/scrolling/ScrollingThread.h
new file mode 100644
index 000000000..de062d77a
--- /dev/null
+++ b/Source/WebCore/page/scrolling/ScrollingThread.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2012, 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(ASYNC_SCROLLING)
+
+#include <functional>
+#include <wtf/Condition.h>
+#include <wtf/Forward.h>
+#include <wtf/Function.h>
+#include <wtf/Lock.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/Threading.h>
+#include <wtf/Vector.h>
+
+#if PLATFORM(COCOA)
+#include <wtf/RetainPtr.h>
+#endif
+
+namespace WebCore {
+
+class ScrollingThread {
+ WTF_MAKE_NONCOPYABLE(ScrollingThread);
+
+public:
+ static bool isCurrentThread();
+ WEBCORE_EXPORT static void dispatch(Function<void ()>&&);
+
+ // Will dispatch the given function on the main thread once all pending functions
+ // on the scrolling thread have finished executing. Used for synchronization purposes.
+ WEBCORE_EXPORT static void dispatchBarrier(Function<void ()>&&);
+
+private:
+ friend NeverDestroyed<ScrollingThread>;
+
+ ScrollingThread();
+
+ static ScrollingThread& singleton();
+
+ void createThreadIfNeeded();
+ static void threadCallback(void* scrollingThread);
+ void threadBody();
+ void dispatchFunctionsFromScrollingThread();
+
+ void initializeRunLoop();
+ void wakeUpRunLoop();
+
+#if PLATFORM(COCOA)
+ static void threadRunLoopSourceCallback(void* scrollingThread);
+ void threadRunLoopSourceCallback();
+#endif
+
+ ThreadIdentifier m_threadIdentifier;
+
+ Condition m_initializeRunLoopConditionVariable;
+ Lock m_initializeRunLoopMutex;
+
+ Lock m_functionsMutex;
+ Vector<Function<void ()>> m_functions;
+
+#if PLATFORM(COCOA)
+ // FIXME: We should use WebCore::RunLoop here.
+ RetainPtr<CFRunLoopRef> m_threadRunLoop;
+ RetainPtr<CFRunLoopSourceRef> m_threadRunLoopSource;
+#endif
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(ASYNC_SCROLLING)
diff --git a/Source/WebCore/page/scrolling/ScrollingTree.cpp b/Source/WebCore/page/scrolling/ScrollingTree.cpp
new file mode 100644
index 000000000..40bcc63ff
--- /dev/null
+++ b/Source/WebCore/page/scrolling/ScrollingTree.cpp
@@ -0,0 +1,410 @@
+/*
+ * Copyright (C) 2012-2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ScrollingTree.h"
+
+#if ENABLE(ASYNC_SCROLLING)
+
+#include "EventNames.h"
+#include "Logging.h"
+#include "PlatformWheelEvent.h"
+#include "ScrollingStateTree.h"
+#include "ScrollingTreeFrameScrollingNode.h"
+#include "ScrollingTreeNode.h"
+#include "ScrollingTreeOverflowScrollingNode.h"
+#include "ScrollingTreeScrollingNode.h"
+#include "TextStream.h"
+#include <wtf/SetForScope.h>
+
+namespace WebCore {
+
+ScrollingTree::ScrollingTree()
+{
+}
+
+ScrollingTree::~ScrollingTree()
+{
+}
+
+bool ScrollingTree::shouldHandleWheelEventSynchronously(const PlatformWheelEvent& wheelEvent)
+{
+ // This method is invoked by the event handling thread
+ LockHolder lock(m_mutex);
+
+ bool shouldSetLatch = wheelEvent.shouldConsiderLatching();
+
+ if (hasLatchedNode() && !shouldSetLatch)
+ return false;
+
+ if (shouldSetLatch)
+ m_latchedNode = 0;
+
+ if (!m_eventTrackingRegions.isEmpty() && m_rootNode) {
+ ScrollingTreeFrameScrollingNode& frameScrollingNode = downcast<ScrollingTreeFrameScrollingNode>(*m_rootNode);
+ FloatPoint position = wheelEvent.position();
+ position.move(frameScrollingNode.viewToContentsOffset(m_mainFrameScrollPosition));
+
+ const EventNames& names = eventNames();
+ IntPoint roundedPosition = roundedIntPoint(position);
+ bool isSynchronousDispatchRegion = m_eventTrackingRegions.trackingTypeForPoint(names.wheelEvent, roundedPosition) == TrackingType::Synchronous
+ || m_eventTrackingRegions.trackingTypeForPoint(names.mousewheelEvent, roundedPosition) == TrackingType::Synchronous;
+ LOG_WITH_STREAM(Scrolling, stream << "ScrollingTree::shouldHandleWheelEventSynchronously: wheelEvent at " << wheelEvent.position() << " mapped to content point " << position << ", in non-fast region " << isSynchronousDispatchRegion);
+
+ if (isSynchronousDispatchRegion)
+ return true;
+ }
+ return false;
+}
+
+void ScrollingTree::setOrClearLatchedNode(const PlatformWheelEvent& wheelEvent, ScrollingNodeID nodeID)
+{
+ if (wheelEvent.shouldConsiderLatching())
+ setLatchedNode(nodeID);
+ else if (wheelEvent.shouldResetLatching())
+ clearLatchedNode();
+}
+
+void ScrollingTree::handleWheelEvent(const PlatformWheelEvent& wheelEvent)
+{
+ if (m_rootNode)
+ downcast<ScrollingTreeScrollingNode>(*m_rootNode).handleWheelEvent(wheelEvent);
+}
+
+void ScrollingTree::viewportChangedViaDelegatedScrolling(ScrollingNodeID nodeID, const FloatRect& fixedPositionRect, double scale)
+{
+ ScrollingTreeNode* node = nodeForID(nodeID);
+ if (!is<ScrollingTreeScrollingNode>(node))
+ return;
+
+ downcast<ScrollingTreeScrollingNode>(*node).updateLayersAfterViewportChange(fixedPositionRect, scale);
+}
+
+void ScrollingTree::scrollPositionChangedViaDelegatedScrolling(ScrollingNodeID nodeID, const WebCore::FloatPoint& scrollPosition, bool inUserInteration)
+{
+ ScrollingTreeNode* node = nodeForID(nodeID);
+ if (!is<ScrollingTreeOverflowScrollingNode>(node))
+ return;
+
+ // Update descendant nodes
+ downcast<ScrollingTreeOverflowScrollingNode>(*node).updateLayersAfterDelegatedScroll(scrollPosition);
+
+ // Update GraphicsLayers and scroll state.
+ scrollingTreeNodeDidScroll(nodeID, scrollPosition, std::nullopt, inUserInteration ? ScrollingLayerPositionAction::Sync : ScrollingLayerPositionAction::Set);
+}
+
+void ScrollingTree::commitTreeState(std::unique_ptr<ScrollingStateTree> scrollingStateTree)
+{
+ bool rootStateNodeChanged = scrollingStateTree->hasNewRootStateNode();
+
+ ScrollingStateScrollingNode* rootNode = scrollingStateTree->rootStateNode();
+ if (rootNode
+ && (rootStateNodeChanged
+ || rootNode->hasChangedProperty(ScrollingStateFrameScrollingNode::EventTrackingRegion)
+ || rootNode->hasChangedProperty(ScrollingStateNode::ScrollLayer)
+ || rootNode->hasChangedProperty(ScrollingStateFrameScrollingNode::VisualViewportEnabled))) {
+ LockHolder lock(m_mutex);
+
+ if (rootStateNodeChanged || rootNode->hasChangedProperty(ScrollingStateNode::ScrollLayer))
+ m_mainFrameScrollPosition = FloatPoint();
+
+ if (rootStateNodeChanged || rootNode->hasChangedProperty(ScrollingStateFrameScrollingNode::EventTrackingRegion))
+ m_eventTrackingRegions = scrollingStateTree->rootStateNode()->eventTrackingRegions();
+
+ if (rootStateNodeChanged || rootNode->hasChangedProperty(ScrollingStateFrameScrollingNode::VisualViewportEnabled))
+ m_visualViewportEnabled = scrollingStateTree->rootStateNode()->visualViewportEnabled();
+ }
+
+ bool scrollRequestIsProgammatic = rootNode ? rootNode->requestedScrollPositionRepresentsProgrammaticScroll() : false;
+ SetForScope<bool> changeHandlingProgrammaticScroll(m_isHandlingProgrammaticScroll, scrollRequestIsProgammatic);
+
+ removeDestroyedNodes(*scrollingStateTree);
+
+ OrphanScrollingNodeMap orphanNodes;
+ updateTreeFromStateNode(rootNode, orphanNodes);
+}
+
+void ScrollingTree::updateTreeFromStateNode(const ScrollingStateNode* stateNode, OrphanScrollingNodeMap& orphanNodes)
+{
+ if (!stateNode) {
+ m_nodeMap.clear();
+ m_rootNode = nullptr;
+ return;
+ }
+
+ ScrollingNodeID nodeID = stateNode->scrollingNodeID();
+ ScrollingNodeID parentNodeID = stateNode->parentNodeID();
+
+ auto it = m_nodeMap.find(nodeID);
+
+ RefPtr<ScrollingTreeNode> node;
+ if (it != m_nodeMap.end())
+ node = it->value;
+ else {
+ node = createScrollingTreeNode(stateNode->nodeType(), nodeID);
+ if (!parentNodeID) {
+ // This is the root node. Clear the node map.
+ ASSERT(stateNode->nodeType() == FrameScrollingNode);
+ m_rootNode = node;
+ m_nodeMap.clear();
+ }
+ m_nodeMap.set(nodeID, node.get());
+ }
+
+ if (parentNodeID) {
+ auto parentIt = m_nodeMap.find(parentNodeID);
+ ASSERT_WITH_SECURITY_IMPLICATION(parentIt != m_nodeMap.end());
+ if (parentIt != m_nodeMap.end()) {
+ ScrollingTreeNode* parent = parentIt->value;
+ node->setParent(parent);
+ parent->appendChild(*node);
+ }
+ }
+
+ node->commitStateBeforeChildren(*stateNode);
+
+ // Move all children into the orphanNodes map. Live ones will get added back as we recurse over children.
+ if (auto nodeChildren = node->children()) {
+ for (auto& childScrollingNode : *nodeChildren) {
+ childScrollingNode->setParent(nullptr);
+ orphanNodes.add(childScrollingNode->scrollingNodeID(), childScrollingNode.get());
+ }
+ nodeChildren->clear();
+ }
+
+ // Now update the children if we have any.
+ if (auto children = stateNode->children()) {
+ for (auto& child : *children)
+ updateTreeFromStateNode(child.get(), orphanNodes);
+ }
+
+ node->commitStateAfterChildren(*stateNode);
+}
+
+void ScrollingTree::removeDestroyedNodes(const ScrollingStateTree& stateTree)
+{
+ for (const auto& removedNodeID : stateTree.removedNodes()) {
+ m_nodeMap.remove(removedNodeID);
+ if (removedNodeID == m_latchedNode)
+ clearLatchedNode();
+ }
+}
+
+ScrollingTreeNode* ScrollingTree::nodeForID(ScrollingNodeID nodeID) const
+{
+ if (!nodeID)
+ return nullptr;
+
+ return m_nodeMap.get(nodeID);
+}
+
+void ScrollingTree::setMainFramePinState(bool pinnedToTheLeft, bool pinnedToTheRight, bool pinnedToTheTop, bool pinnedToTheBottom)
+{
+ LockHolder locker(m_swipeStateMutex);
+
+ m_mainFramePinnedToTheLeft = pinnedToTheLeft;
+ m_mainFramePinnedToTheRight = pinnedToTheRight;
+ m_mainFramePinnedToTheTop = pinnedToTheTop;
+ m_mainFramePinnedToTheBottom = pinnedToTheBottom;
+}
+
+FloatPoint ScrollingTree::mainFrameScrollPosition()
+{
+ LockHolder lock(m_mutex);
+ return m_mainFrameScrollPosition;
+}
+
+void ScrollingTree::setMainFrameScrollPosition(FloatPoint position)
+{
+ LockHolder lock(m_mutex);
+ m_mainFrameScrollPosition = position;
+}
+
+TrackingType ScrollingTree::eventTrackingTypeForPoint(const AtomicString& eventName, IntPoint p)
+{
+ LockHolder lock(m_mutex);
+
+ return m_eventTrackingRegions.trackingTypeForPoint(eventName, p);
+}
+
+bool ScrollingTree::isRubberBandInProgress()
+{
+ LockHolder lock(m_mutex);
+
+ return m_mainFrameIsRubberBanding;
+}
+
+void ScrollingTree::setMainFrameIsRubberBanding(bool isRubberBanding)
+{
+ LockHolder locker(m_mutex);
+
+ m_mainFrameIsRubberBanding = isRubberBanding;
+}
+
+bool ScrollingTree::isScrollSnapInProgress()
+{
+ LockHolder lock(m_mutex);
+
+ return m_mainFrameIsScrollSnapping;
+}
+
+void ScrollingTree::setMainFrameIsScrollSnapping(bool isScrollSnapping)
+{
+ LockHolder locker(m_mutex);
+
+ m_mainFrameIsScrollSnapping = isScrollSnapping;
+}
+
+void ScrollingTree::setCanRubberBandState(bool canRubberBandAtLeft, bool canRubberBandAtRight, bool canRubberBandAtTop, bool canRubberBandAtBottom)
+{
+ LockHolder locker(m_swipeStateMutex);
+
+ m_rubberBandsAtLeft = canRubberBandAtLeft;
+ m_rubberBandsAtRight = canRubberBandAtRight;
+ m_rubberBandsAtTop = canRubberBandAtTop;
+ m_rubberBandsAtBottom = canRubberBandAtBottom;
+}
+
+bool ScrollingTree::rubberBandsAtLeft()
+{
+ LockHolder lock(m_swipeStateMutex);
+
+ return m_rubberBandsAtLeft;
+}
+
+bool ScrollingTree::rubberBandsAtRight()
+{
+ LockHolder lock(m_swipeStateMutex);
+
+ return m_rubberBandsAtRight;
+}
+
+bool ScrollingTree::rubberBandsAtBottom()
+{
+ LockHolder lock(m_swipeStateMutex);
+
+ return m_rubberBandsAtBottom;
+}
+
+bool ScrollingTree::rubberBandsAtTop()
+{
+ LockHolder lock(m_swipeStateMutex);
+
+ return m_rubberBandsAtTop;
+}
+
+bool ScrollingTree::isHandlingProgrammaticScroll()
+{
+ return m_isHandlingProgrammaticScroll;
+}
+
+void ScrollingTree::setScrollPinningBehavior(ScrollPinningBehavior pinning)
+{
+ LockHolder locker(m_swipeStateMutex);
+
+ m_scrollPinningBehavior = pinning;
+}
+
+ScrollPinningBehavior ScrollingTree::scrollPinningBehavior()
+{
+ LockHolder lock(m_swipeStateMutex);
+
+ return m_scrollPinningBehavior;
+}
+
+bool ScrollingTree::willWheelEventStartSwipeGesture(const PlatformWheelEvent& wheelEvent)
+{
+ if (wheelEvent.phase() != PlatformWheelEventPhaseBegan)
+ return false;
+
+ LockHolder lock(m_swipeStateMutex);
+
+ if (wheelEvent.deltaX() > 0 && m_mainFramePinnedToTheLeft && !m_rubberBandsAtLeft)
+ return true;
+ if (wheelEvent.deltaX() < 0 && m_mainFramePinnedToTheRight && !m_rubberBandsAtRight)
+ return true;
+ if (wheelEvent.deltaY() > 0 && m_mainFramePinnedToTheTop && !m_rubberBandsAtTop)
+ return true;
+ if (wheelEvent.deltaY() < 0 && m_mainFramePinnedToTheBottom && !m_rubberBandsAtBottom)
+ return true;
+
+ return false;
+}
+
+void ScrollingTree::setScrollingPerformanceLoggingEnabled(bool flag)
+{
+ m_scrollingPerformanceLoggingEnabled = flag;
+}
+
+bool ScrollingTree::scrollingPerformanceLoggingEnabled()
+{
+ return m_scrollingPerformanceLoggingEnabled;
+}
+
+ScrollingNodeID ScrollingTree::latchedNode()
+{
+ LockHolder locker(m_mutex);
+ return m_latchedNode;
+}
+
+void ScrollingTree::setLatchedNode(ScrollingNodeID node)
+{
+ LockHolder locker(m_mutex);
+ m_latchedNode = node;
+}
+
+void ScrollingTree::clearLatchedNode()
+{
+ LockHolder locker(m_mutex);
+ m_latchedNode = 0;
+}
+
+String ScrollingTree::scrollingTreeAsText()
+{
+ TextStream ts(TextStream::LineMode::MultipleLine);
+
+ TextStream::GroupScope scope(ts);
+ ts << "scrolling tree";
+
+ if (m_latchedNode)
+ ts.dumpProperty("latched node", m_latchedNode);
+
+ if (m_mainFrameScrollPosition != IntPoint())
+ ts.dumpProperty("main frame scroll position", m_mainFrameScrollPosition);
+
+ {
+ LockHolder lock(m_mutex);
+ if (m_rootNode) {
+ TextStream::GroupScope scope(ts);
+ m_rootNode->dump(ts, ScrollingStateTreeAsTextBehaviorIncludeLayerPositions);
+ }
+ }
+
+ return ts.release();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(ASYNC_SCROLLING)
diff --git a/Source/WebCore/page/scrolling/ScrollingTree.h b/Source/WebCore/page/scrolling/ScrollingTree.h
new file mode 100644
index 000000000..aaf2d478b
--- /dev/null
+++ b/Source/WebCore/page/scrolling/ScrollingTree.h
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2012-2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(ASYNC_SCROLLING)
+
+#include "PlatformWheelEvent.h"
+#include "Region.h"
+#include "ScrollingCoordinator.h"
+#include "WheelEventTestTrigger.h"
+#include <wtf/HashMap.h>
+#include <wtf/Lock.h>
+#include <wtf/ThreadSafeRefCounted.h>
+#include <wtf/TypeCasts.h>
+
+namespace WebCore {
+
+class IntPoint;
+class ScrollingStateTree;
+class ScrollingStateNode;
+class ScrollingTreeNode;
+class ScrollingTreeScrollingNode;
+
+class ScrollingTree : public ThreadSafeRefCounted<ScrollingTree> {
+public:
+ WEBCORE_EXPORT ScrollingTree();
+ WEBCORE_EXPORT virtual ~ScrollingTree();
+
+ enum EventResult {
+ DidNotHandleEvent,
+ DidHandleEvent,
+ SendToMainThread
+ };
+
+ virtual bool isThreadedScrollingTree() const { return false; }
+ virtual bool isRemoteScrollingTree() const { return false; }
+ virtual bool isScrollingTreeIOS() const { return false; }
+
+ bool visualViewportEnabled() const { return m_visualViewportEnabled; }
+
+ virtual EventResult tryToHandleWheelEvent(const PlatformWheelEvent&) = 0;
+ WEBCORE_EXPORT bool shouldHandleWheelEventSynchronously(const PlatformWheelEvent&);
+
+ void setMainFrameIsRubberBanding(bool);
+ bool isRubberBandInProgress();
+ void setMainFrameIsScrollSnapping(bool);
+ bool isScrollSnapInProgress();
+
+ virtual void invalidate() { }
+ WEBCORE_EXPORT virtual void commitTreeState(std::unique_ptr<ScrollingStateTree>);
+
+ void setMainFramePinState(bool pinnedToTheLeft, bool pinnedToTheRight, bool pinnedToTheTop, bool pinnedToTheBottom);
+
+ virtual Ref<ScrollingTreeNode> createScrollingTreeNode(ScrollingNodeType, ScrollingNodeID) = 0;
+
+ // Called after a scrolling tree node has handled a scroll and updated its layers.
+ // Updates FrameView/RenderLayer scrolling state and GraphicsLayers.
+ virtual void scrollingTreeNodeDidScroll(ScrollingNodeID, const FloatPoint& scrollPosition, const std::optional<FloatPoint>& layoutViewportOrigin, ScrollingLayerPositionAction = ScrollingLayerPositionAction::Sync) = 0;
+
+ // Called for requested scroll position updates.
+ virtual void scrollingTreeNodeRequestsScroll(ScrollingNodeID, const FloatPoint& /*scrollPosition*/, bool /*representsProgrammaticScroll*/) { }
+
+ // Delegated scrolling/zooming has caused the viewport to change, so update viewport-constrained layers
+ // (but don't cause scroll events to be fired).
+ WEBCORE_EXPORT virtual void viewportChangedViaDelegatedScrolling(ScrollingNodeID, const WebCore::FloatRect& fixedPositionRect, double scale);
+
+ // Delegated scrolling has scrolled a node. Update layer positions on descendant tree nodes,
+ // and call scrollingTreeNodeDidScroll().
+ WEBCORE_EXPORT virtual void scrollPositionChangedViaDelegatedScrolling(ScrollingNodeID, const WebCore::FloatPoint& scrollPosition, bool inUserInteration);
+
+ WEBCORE_EXPORT virtual void currentSnapPointIndicesDidChange(ScrollingNodeID, unsigned horizontal, unsigned vertical) = 0;
+
+ FloatPoint mainFrameScrollPosition();
+
+#if PLATFORM(IOS)
+ virtual FloatRect fixedPositionRect() = 0;
+ virtual void scrollingTreeNodeWillStartPanGesture() { }
+ virtual void scrollingTreeNodeWillStartScroll() { }
+ virtual void scrollingTreeNodeDidEndScroll() { }
+#endif
+
+ WEBCORE_EXPORT TrackingType eventTrackingTypeForPoint(const AtomicString& eventName, IntPoint);
+
+#if PLATFORM(MAC)
+ virtual void handleWheelEventPhase(PlatformWheelEventPhase) = 0;
+ virtual void setActiveScrollSnapIndices(ScrollingNodeID, unsigned /*horizontalIndex*/, unsigned /*verticalIndex*/) { }
+ virtual void deferTestsForReason(WheelEventTestTrigger::ScrollableAreaIdentifier, WheelEventTestTrigger::DeferTestTriggerReason) { }
+ virtual void removeTestDeferralForReason(WheelEventTestTrigger::ScrollableAreaIdentifier, WheelEventTestTrigger::DeferTestTriggerReason) { }
+#endif
+
+ // Can be called from any thread. Will update what edges allow rubber-banding.
+ WEBCORE_EXPORT void setCanRubberBandState(bool canRubberBandAtLeft, bool canRubberBandAtRight, bool canRubberBandAtTop, bool canRubberBandAtBottom);
+
+ bool rubberBandsAtLeft();
+ bool rubberBandsAtRight();
+ bool rubberBandsAtTop();
+ bool rubberBandsAtBottom();
+ bool isHandlingProgrammaticScroll();
+
+ void setScrollPinningBehavior(ScrollPinningBehavior);
+ ScrollPinningBehavior scrollPinningBehavior();
+
+ WEBCORE_EXPORT bool willWheelEventStartSwipeGesture(const PlatformWheelEvent&);
+
+ WEBCORE_EXPORT void setScrollingPerformanceLoggingEnabled(bool flag);
+ bool scrollingPerformanceLoggingEnabled();
+
+ ScrollingTreeNode* rootNode() const { return m_rootNode.get(); }
+
+ ScrollingNodeID latchedNode();
+ void setLatchedNode(ScrollingNodeID);
+ void clearLatchedNode();
+
+ bool hasLatchedNode() const { return m_latchedNode; }
+ void setOrClearLatchedNode(const PlatformWheelEvent&, ScrollingNodeID);
+
+ bool hasFixedOrSticky() const { return !!m_fixedOrStickyNodeCount; }
+ void fixedOrStickyNodeAdded() { ++m_fixedOrStickyNodeCount; }
+ void fixedOrStickyNodeRemoved()
+ {
+ ASSERT(m_fixedOrStickyNodeCount);
+ --m_fixedOrStickyNodeCount;
+ }
+
+ WEBCORE_EXPORT String scrollingTreeAsText();
+
+protected:
+ void setMainFrameScrollPosition(FloatPoint);
+ void setVisualViewportEnabled(bool b) { m_visualViewportEnabled = b; }
+
+ WEBCORE_EXPORT virtual void handleWheelEvent(const PlatformWheelEvent&);
+
+private:
+ void removeDestroyedNodes(const ScrollingStateTree&);
+
+ typedef HashMap<ScrollingNodeID, RefPtr<ScrollingTreeNode>> OrphanScrollingNodeMap;
+ void updateTreeFromStateNode(const ScrollingStateNode*, OrphanScrollingNodeMap&);
+
+ ScrollingTreeNode* nodeForID(ScrollingNodeID) const;
+
+ RefPtr<ScrollingTreeNode> m_rootNode;
+
+ typedef HashMap<ScrollingNodeID, ScrollingTreeNode*> ScrollingTreeNodeMap;
+ ScrollingTreeNodeMap m_nodeMap;
+
+ Lock m_mutex;
+ EventTrackingRegions m_eventTrackingRegions;
+ FloatPoint m_mainFrameScrollPosition;
+
+ Lock m_swipeStateMutex;
+ ScrollPinningBehavior m_scrollPinningBehavior { DoNotPin };
+ ScrollingNodeID m_latchedNode { 0 };
+
+ unsigned m_fixedOrStickyNodeCount { 0 };
+
+ bool m_rubberBandsAtLeft { true };
+ bool m_rubberBandsAtRight { true };
+ bool m_rubberBandsAtTop { true };
+ bool m_rubberBandsAtBottom { true };
+ bool m_mainFramePinnedToTheLeft { true };
+ bool m_mainFramePinnedToTheRight { true };
+ bool m_mainFramePinnedToTheTop { true };
+ bool m_mainFramePinnedToTheBottom { true };
+ bool m_mainFrameIsRubberBanding { false };
+ bool m_mainFrameIsScrollSnapping { false };
+ bool m_scrollingPerformanceLoggingEnabled { false };
+ bool m_isHandlingProgrammaticScroll { false };
+ bool m_visualViewportEnabled { false };
+};
+
+} // namespace WebCore
+
+#define SPECIALIZE_TYPE_TRAITS_SCROLLING_TREE(ToValueTypeName, predicate) \
+SPECIALIZE_TYPE_TRAITS_BEGIN(ToValueTypeName) \
+ static bool isType(const WebCore::ScrollingTree& tree) { return tree.predicate; } \
+SPECIALIZE_TYPE_TRAITS_END()
+#endif // ENABLE(ASYNC_SCROLLING)
diff --git a/Source/WebCore/page/scrolling/ScrollingTreeFrameScrollingNode.cpp b/Source/WebCore/page/scrolling/ScrollingTreeFrameScrollingNode.cpp
new file mode 100644
index 000000000..17ac7a431
--- /dev/null
+++ b/Source/WebCore/page/scrolling/ScrollingTreeFrameScrollingNode.cpp
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ScrollingTreeFrameScrollingNode.h"
+
+#if ENABLE(ASYNC_SCROLLING)
+
+#include "FrameView.h"
+#include "Logging.h"
+#include "ScrollingStateTree.h"
+#include "ScrollingTree.h"
+#include "TextStream.h"
+
+namespace WebCore {
+
+ScrollingTreeFrameScrollingNode::ScrollingTreeFrameScrollingNode(ScrollingTree& scrollingTree, ScrollingNodeID nodeID)
+ : ScrollingTreeScrollingNode(scrollingTree, FrameScrollingNode, nodeID)
+{
+}
+
+ScrollingTreeFrameScrollingNode::~ScrollingTreeFrameScrollingNode()
+{
+}
+
+void ScrollingTreeFrameScrollingNode::commitStateBeforeChildren(const ScrollingStateNode& stateNode)
+{
+ ScrollingTreeScrollingNode::commitStateBeforeChildren(stateNode);
+
+ const ScrollingStateFrameScrollingNode& state = downcast<ScrollingStateFrameScrollingNode>(stateNode);
+
+ if (state.hasChangedProperty(ScrollingStateFrameScrollingNode::FrameScaleFactor))
+ m_frameScaleFactor = state.frameScaleFactor();
+
+ if (state.hasChangedProperty(ScrollingStateFrameScrollingNode::ReasonsForSynchronousScrolling))
+ m_synchronousScrollingReasons = state.synchronousScrollingReasons();
+
+ if (state.hasChangedProperty(ScrollingStateFrameScrollingNode::HeaderHeight))
+ m_headerHeight = state.headerHeight();
+
+ if (state.hasChangedProperty(ScrollingStateFrameScrollingNode::FooterHeight))
+ m_footerHeight = state.footerHeight();
+
+ if (state.hasChangedProperty(ScrollingStateFrameScrollingNode::BehaviorForFixedElements))
+ m_behaviorForFixed = state.scrollBehaviorForFixedElements();
+
+ if (state.hasChangedProperty(ScrollingStateFrameScrollingNode::TopContentInset))
+ m_topContentInset = state.topContentInset();
+
+ if (state.hasChangedProperty(ScrollingStateFrameScrollingNode::FixedElementsLayoutRelativeToFrame))
+ m_fixedElementsLayoutRelativeToFrame = state.fixedElementsLayoutRelativeToFrame();
+
+ if (state.hasChangedProperty(ScrollingStateFrameScrollingNode::LayoutViewport))
+ m_layoutViewport = state.layoutViewport();
+
+ if (state.hasChangedProperty(ScrollingStateFrameScrollingNode::MinLayoutViewportOrigin))
+ m_minLayoutViewportOrigin = state.minLayoutViewportOrigin();
+
+ if (state.hasChangedProperty(ScrollingStateFrameScrollingNode::MaxLayoutViewportOrigin))
+ m_maxLayoutViewportOrigin = state.maxLayoutViewportOrigin();
+}
+
+void ScrollingTreeFrameScrollingNode::scrollBy(const FloatSize& delta)
+{
+ setScrollPosition(scrollPosition() + delta);
+}
+
+void ScrollingTreeFrameScrollingNode::scrollByWithoutContentEdgeConstraints(const FloatSize& offset)
+{
+ setScrollPositionWithoutContentEdgeConstraints(scrollPosition() + offset);
+}
+
+void ScrollingTreeFrameScrollingNode::setScrollPosition(const FloatPoint& scrollPosition)
+{
+ FloatPoint newScrollPosition = scrollPosition.constrainedBetween(minimumScrollPosition(), maximumScrollPosition());
+ setScrollPositionWithoutContentEdgeConstraints(newScrollPosition);
+}
+
+FloatRect ScrollingTreeFrameScrollingNode::layoutViewportForScrollPosition(const FloatPoint& visibleContentOrigin, float scale) const
+{
+ ASSERT(scrollingTree().visualViewportEnabled());
+
+ FloatRect visibleContentRect(visibleContentOrigin, scrollableAreaSize());
+ LayoutRect visualViewport(FrameView::visibleDocumentRect(visibleContentRect, headerHeight(), footerHeight(), totalContentsSize(), scale));
+ LayoutRect layoutViewport(m_layoutViewport);
+
+ LOG_WITH_STREAM(Scrolling, stream << "\nScrolling thread: " << "(visibleContentOrigin " << visibleContentOrigin << ") fixed behavior " << m_behaviorForFixed);
+ LOG_WITH_STREAM(Scrolling, stream << " layoutViewport: " << layoutViewport);
+ LOG_WITH_STREAM(Scrolling, stream << " visualViewport: " << visualViewport);
+ LOG_WITH_STREAM(Scrolling, stream << " scroll positions: min: " << minLayoutViewportOrigin() << " max: "<< maxLayoutViewportOrigin());
+
+ LayoutPoint newLocation = FrameView::computeLayoutViewportOrigin(LayoutRect(visualViewport), LayoutPoint(minLayoutViewportOrigin()), LayoutPoint(maxLayoutViewportOrigin()), layoutViewport, m_behaviorForFixed);
+
+ if (layoutViewport.location() != newLocation) {
+ layoutViewport.setLocation(newLocation);
+ LOG_WITH_STREAM(Scrolling, stream << " new layoutViewport " << layoutViewport);
+ }
+
+ return layoutViewport;
+}
+
+FloatSize ScrollingTreeFrameScrollingNode::viewToContentsOffset(const FloatPoint& scrollPosition) const
+{
+ return toFloatSize(scrollPosition) - FloatSize(0, headerHeight() + topContentInset());
+}
+
+void ScrollingTreeFrameScrollingNode::dumpProperties(TextStream& ts, ScrollingStateTreeAsTextBehavior) const
+{
+ ts << "frame scrolling node";
+
+ ts.dumpProperty("layout viewport", m_layoutViewport);
+ ts.dumpProperty("min layoutViewport origin", m_minLayoutViewportOrigin);
+ ts.dumpProperty("max layoutViewport origin", m_maxLayoutViewportOrigin);
+
+ if (m_frameScaleFactor != 1)
+ ts.dumpProperty("frame scale factor", m_frameScaleFactor);
+ if (m_topContentInset)
+ ts.dumpProperty("top content inset", m_topContentInset);
+
+ if (m_headerHeight)
+ ts.dumpProperty("header height", m_headerHeight);
+ if (m_footerHeight)
+ ts.dumpProperty("footer height", m_footerHeight);
+ if (m_synchronousScrollingReasons)
+ ts.dumpProperty("synchronous scrolling reasons", ScrollingCoordinator::synchronousScrollingReasonsAsText(m_synchronousScrollingReasons));
+
+ ts.dumpProperty("behavior for fixed", m_behaviorForFixed);
+ if (m_fixedElementsLayoutRelativeToFrame)
+ ts.dumpProperty("fixed elements lay out relative to frame", m_fixedElementsLayoutRelativeToFrame);
+}
+
+
+} // namespace WebCore
+
+#endif // ENABLE(ASYNC_SCROLLING)
diff --git a/Source/WebCore/page/scrolling/ScrollingTreeFrameScrollingNode.h b/Source/WebCore/page/scrolling/ScrollingTreeFrameScrollingNode.h
new file mode 100644
index 000000000..43488c4fa
--- /dev/null
+++ b/Source/WebCore/page/scrolling/ScrollingTreeFrameScrollingNode.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(ASYNC_SCROLLING)
+
+#include "ScrollingTreeScrollingNode.h"
+
+namespace WebCore {
+
+class PlatformWheelEvent;
+class ScrollingTree;
+class ScrollingStateScrollingNode;
+
+class ScrollingTreeFrameScrollingNode : public ScrollingTreeScrollingNode {
+public:
+ virtual ~ScrollingTreeFrameScrollingNode();
+
+ void commitStateBeforeChildren(const ScrollingStateNode&) override;
+
+ // FIXME: We should implement this when we support ScrollingTreeScrollingNodes as children.
+ void updateLayersAfterAncestorChange(const ScrollingTreeNode& /*changedNode*/, const FloatRect& /*fixedPositionRect*/, const FloatSize& /*cumulativeDelta*/) override { }
+
+ void handleWheelEvent(const PlatformWheelEvent&) override = 0;
+ void setScrollPosition(const FloatPoint&) override;
+ void setScrollPositionWithoutContentEdgeConstraints(const FloatPoint&) override = 0;
+
+ void updateLayersAfterViewportChange(const FloatRect& fixedPositionRect, double scale) override = 0;
+ void updateLayersAfterDelegatedScroll(const FloatPoint&) override { }
+
+ SynchronousScrollingReasons synchronousScrollingReasons() const { return m_synchronousScrollingReasons; }
+ bool shouldUpdateScrollLayerPositionSynchronously() const { return m_synchronousScrollingReasons; }
+ bool fixedElementsLayoutRelativeToFrame() const { return m_fixedElementsLayoutRelativeToFrame; }
+
+ FloatSize viewToContentsOffset(const FloatPoint& scrollPosition) const;
+ FloatRect layoutViewportForScrollPosition(const FloatPoint& visibleContentOrigin, float scale) const;
+
+protected:
+ ScrollingTreeFrameScrollingNode(ScrollingTree&, ScrollingNodeID);
+
+ void scrollBy(const FloatSize&);
+ void scrollByWithoutContentEdgeConstraints(const FloatSize&);
+
+ float frameScaleFactor() const { return m_frameScaleFactor; }
+ int headerHeight() const { return m_headerHeight; }
+ int footerHeight() const { return m_footerHeight; }
+ float topContentInset() const { return m_topContentInset; }
+
+ FloatRect layoutViewport() const { return m_layoutViewport; };
+ void setLayoutViewport(const FloatRect& r) { m_layoutViewport = r; };
+
+ FloatPoint minLayoutViewportOrigin() const { return m_minLayoutViewportOrigin; }
+ FloatPoint maxLayoutViewportOrigin() const { return m_maxLayoutViewportOrigin; }
+
+ ScrollBehaviorForFixedElements scrollBehaviorForFixedElements() const { return m_behaviorForFixed; }
+
+private:
+ void dumpProperties(TextStream&, ScrollingStateTreeAsTextBehavior) const override;
+
+ FloatRect m_layoutViewport;
+ FloatPoint m_minLayoutViewportOrigin;
+ FloatPoint m_maxLayoutViewportOrigin;
+
+ float m_frameScaleFactor { 1 };
+ float m_topContentInset { 0 };
+
+ int m_headerHeight { 0 };
+ int m_footerHeight { 0 };
+
+ SynchronousScrollingReasons m_synchronousScrollingReasons { 0 };
+ ScrollBehaviorForFixedElements m_behaviorForFixed { StickToDocumentBounds };
+
+ bool m_fixedElementsLayoutRelativeToFrame { false };
+};
+
+} // namespace WebCore
+
+SPECIALIZE_TYPE_TRAITS_SCROLLING_NODE(ScrollingTreeFrameScrollingNode, isFrameScrollingNode())
+
+#endif // ENABLE(ASYNC_SCROLLING)
diff --git a/Source/WebCore/page/scrolling/ScrollingTreeNode.cpp b/Source/WebCore/page/scrolling/ScrollingTreeNode.cpp
new file mode 100644
index 000000000..0f6616d0f
--- /dev/null
+++ b/Source/WebCore/page/scrolling/ScrollingTreeNode.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ScrollingTreeNode.h"
+
+#if ENABLE(ASYNC_SCROLLING)
+
+#include "ScrollingStateTree.h"
+#include "TextStream.h"
+
+namespace WebCore {
+
+ScrollingTreeNode::ScrollingTreeNode(ScrollingTree& scrollingTree, ScrollingNodeType nodeType, ScrollingNodeID nodeID)
+ : m_scrollingTree(scrollingTree)
+ , m_nodeType(nodeType)
+ , m_nodeID(nodeID)
+ , m_parent(nullptr)
+{
+}
+
+ScrollingTreeNode::~ScrollingTreeNode()
+{
+}
+
+void ScrollingTreeNode::appendChild(Ref<ScrollingTreeNode>&& childNode)
+{
+ childNode->setParent(this);
+
+ if (!m_children)
+ m_children = std::make_unique<Vector<RefPtr<ScrollingTreeNode>>>();
+ m_children->append(WTFMove(childNode));
+}
+
+void ScrollingTreeNode::removeChild(ScrollingTreeNode& node)
+{
+ if (!m_children)
+ return;
+
+ size_t index = m_children->find(&node);
+
+ // The index will be notFound if the node to remove is a deeper-than-1-level descendant or
+ // if node is the root state node.
+ if (index != notFound) {
+ m_children->remove(index);
+ return;
+ }
+
+ for (auto& child : *m_children)
+ child->removeChild(node);
+}
+
+void ScrollingTreeNode::dumpProperties(TextStream& ts, ScrollingStateTreeAsTextBehavior behavior) const
+{
+ if (behavior & ScrollingStateTreeAsTextBehaviorIncludeNodeIDs)
+ ts.dumpProperty("nodeID", scrollingNodeID());
+}
+
+void ScrollingTreeNode::dump(TextStream& ts, ScrollingStateTreeAsTextBehavior behavior) const
+{
+ dumpProperties(ts, behavior);
+
+ if (m_children) {
+ for (auto& child : *m_children) {
+ TextStream::GroupScope scope(ts);
+ child->dump(ts, behavior);
+ }
+ }
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(ASYNC_SCROLLING)
diff --git a/Source/WebCore/page/scrolling/ScrollingTreeNode.h b/Source/WebCore/page/scrolling/ScrollingTreeNode.h
new file mode 100644
index 000000000..2e163246b
--- /dev/null
+++ b/Source/WebCore/page/scrolling/ScrollingTreeNode.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(ASYNC_SCROLLING)
+
+#include "IntRect.h"
+#include "ScrollTypes.h"
+#include "ScrollingCoordinator.h"
+#include "ScrollingStateNode.h"
+#include <wtf/RefCounted.h>
+#include <wtf/TypeCasts.h>
+
+namespace WebCore {
+
+class ScrollingStateFixedNode;
+class ScrollingStateScrollingNode;
+
+class ScrollingTreeNode : public RefCounted<ScrollingTreeNode> {
+public:
+ virtual ~ScrollingTreeNode();
+
+ ScrollingNodeType nodeType() const { return m_nodeType; }
+ ScrollingNodeID scrollingNodeID() const { return m_nodeID; }
+
+ bool isFixedNode() const { return nodeType() == FixedNode; }
+ bool isStickyNode() const { return nodeType() == StickyNode; }
+ bool isScrollingNode() const { return nodeType() == FrameScrollingNode || nodeType() == OverflowScrollingNode; }
+ bool isFrameScrollingNode() const { return nodeType() == FrameScrollingNode; }
+ bool isOverflowScrollingNode() const { return nodeType() == OverflowScrollingNode; }
+
+ virtual void commitStateBeforeChildren(const ScrollingStateNode&) = 0;
+ virtual void commitStateAfterChildren(const ScrollingStateNode&) { }
+
+ virtual void updateLayersAfterAncestorChange(const ScrollingTreeNode& changedNode, const FloatRect& fixedPositionRect, const FloatSize& cumulativeDelta) = 0;
+
+ ScrollingTreeNode* parent() const { return m_parent; }
+ void setParent(ScrollingTreeNode* parent) { m_parent = parent; }
+
+ Vector<RefPtr<ScrollingTreeNode>>* children() { return m_children.get(); }
+
+ void appendChild(Ref<ScrollingTreeNode>&&);
+ void removeChild(ScrollingTreeNode&);
+
+ WEBCORE_EXPORT void dump(TextStream&, ScrollingStateTreeAsTextBehavior) const;
+
+protected:
+ ScrollingTreeNode(ScrollingTree&, ScrollingNodeType, ScrollingNodeID);
+ ScrollingTree& scrollingTree() const { return m_scrollingTree; }
+
+ std::unique_ptr<Vector<RefPtr<ScrollingTreeNode>>> m_children;
+
+ WEBCORE_EXPORT virtual void dumpProperties(TextStream&, ScrollingStateTreeAsTextBehavior) const;
+
+private:
+ ScrollingTree& m_scrollingTree;
+
+ const ScrollingNodeType m_nodeType;
+ const ScrollingNodeID m_nodeID;
+
+ ScrollingTreeNode* m_parent;
+};
+
+} // namespace WebCore
+
+#define SPECIALIZE_TYPE_TRAITS_SCROLLING_NODE(ToValueTypeName, predicate) \
+SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::ToValueTypeName) \
+ static bool isType(const WebCore::ScrollingTreeNode& node) { return node.predicate; } \
+SPECIALIZE_TYPE_TRAITS_END()
+
+#endif // ENABLE(ASYNC_SCROLLING)
diff --git a/Source/WebCore/page/scrolling/ScrollingTreeOverflowScrollingNode.cpp b/Source/WebCore/page/scrolling/ScrollingTreeOverflowScrollingNode.cpp
new file mode 100644
index 000000000..013e350e6
--- /dev/null
+++ b/Source/WebCore/page/scrolling/ScrollingTreeOverflowScrollingNode.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ScrollingTreeOverflowScrollingNode.h"
+
+#if ENABLE(ASYNC_SCROLLING)
+
+#include "ScrollingStateTree.h"
+#include "ScrollingTree.h"
+
+namespace WebCore {
+
+ScrollingTreeOverflowScrollingNode::ScrollingTreeOverflowScrollingNode(ScrollingTree& scrollingTree, ScrollingNodeID nodeID)
+ : ScrollingTreeScrollingNode(scrollingTree, OverflowScrollingNode, nodeID)
+{
+}
+
+ScrollingTreeOverflowScrollingNode::~ScrollingTreeOverflowScrollingNode()
+{
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(ASYNC_SCROLLING)
diff --git a/Source/WebCore/page/scrolling/ScrollingTreeOverflowScrollingNode.h b/Source/WebCore/page/scrolling/ScrollingTreeOverflowScrollingNode.h
new file mode 100644
index 000000000..97fb95cc4
--- /dev/null
+++ b/Source/WebCore/page/scrolling/ScrollingTreeOverflowScrollingNode.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(ASYNC_SCROLLING)
+
+#include "ScrollingTreeScrollingNode.h"
+
+namespace WebCore {
+
+class ScrollingTreeOverflowScrollingNode : public ScrollingTreeScrollingNode {
+public:
+ WEBCORE_EXPORT virtual ~ScrollingTreeOverflowScrollingNode();
+
+protected:
+ WEBCORE_EXPORT ScrollingTreeOverflowScrollingNode(ScrollingTree&, ScrollingNodeID);
+};
+
+} // namespace WebCore
+
+SPECIALIZE_TYPE_TRAITS_SCROLLING_NODE(ScrollingTreeOverflowScrollingNode, isOverflowScrollingNode())
+
+#endif // ENABLE(ASYNC_SCROLLING)
diff --git a/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.cpp b/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.cpp
new file mode 100644
index 000000000..19754f5c2
--- /dev/null
+++ b/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ScrollingTreeScrollingNode.h"
+
+#if ENABLE(ASYNC_SCROLLING)
+
+#include "ScrollingStateTree.h"
+#include "ScrollingTree.h"
+#include "TextStream.h"
+
+namespace WebCore {
+
+ScrollingTreeScrollingNode::ScrollingTreeScrollingNode(ScrollingTree& scrollingTree, ScrollingNodeType nodeType, ScrollingNodeID nodeID)
+ : ScrollingTreeNode(scrollingTree, nodeType, nodeID)
+{
+}
+
+ScrollingTreeScrollingNode::~ScrollingTreeScrollingNode()
+{
+}
+
+void ScrollingTreeScrollingNode::commitStateBeforeChildren(const ScrollingStateNode& stateNode)
+{
+ const ScrollingStateScrollingNode& state = downcast<ScrollingStateScrollingNode>(stateNode);
+
+ if (state.hasChangedProperty(ScrollingStateScrollingNode::ScrollableAreaSize))
+ m_scrollableAreaSize = state.scrollableAreaSize();
+
+ if (state.hasChangedProperty(ScrollingStateScrollingNode::TotalContentsSize)) {
+ if (scrollingTree().isRubberBandInProgress())
+ m_totalContentsSizeForRubberBand = m_totalContentsSize;
+ else
+ m_totalContentsSizeForRubberBand = state.totalContentsSize();
+
+ m_totalContentsSize = state.totalContentsSize();
+ }
+
+ if (state.hasChangedProperty(ScrollingStateScrollingNode::ReachableContentsSize))
+ m_reachableContentsSize = state.reachableContentsSize();
+
+ if (state.hasChangedProperty(ScrollingStateScrollingNode::ScrollPosition))
+ m_lastCommittedScrollPosition = state.scrollPosition();
+
+ if (state.hasChangedProperty(ScrollingStateScrollingNode::ScrollOrigin))
+ m_scrollOrigin = state.scrollOrigin();
+
+#if ENABLE(CSS_SCROLL_SNAP)
+ if (state.hasChangedProperty(ScrollingStateScrollingNode::HorizontalSnapOffsets))
+ m_snapOffsetsInfo.horizontalSnapOffsets = state.horizontalSnapOffsets();
+
+ if (state.hasChangedProperty(ScrollingStateScrollingNode::VerticalSnapOffsets))
+ m_snapOffsetsInfo.verticalSnapOffsets = state.verticalSnapOffsets();
+
+ if (state.hasChangedProperty(ScrollingStateScrollingNode::HorizontalSnapOffsetRanges))
+ m_snapOffsetsInfo.horizontalSnapOffsetRanges = state.horizontalSnapOffsetRanges();
+
+ if (state.hasChangedProperty(ScrollingStateScrollingNode::VerticalSnapOffsetRanges))
+ m_snapOffsetsInfo.verticalSnapOffsetRanges = state.verticalSnapOffsetRanges();
+
+ if (state.hasChangedProperty(ScrollingStateScrollingNode::CurrentHorizontalSnapOffsetIndex))
+ m_currentHorizontalSnapPointIndex = state.currentHorizontalSnapPointIndex();
+
+ if (state.hasChangedProperty(ScrollingStateScrollingNode::CurrentVerticalSnapOffsetIndex))
+ m_currentVerticalSnapPointIndex = state.currentVerticalSnapPointIndex();
+#endif
+
+ if (state.hasChangedProperty(ScrollingStateScrollingNode::ScrollableAreaParams))
+ m_scrollableAreaParameters = state.scrollableAreaParameters();
+}
+
+void ScrollingTreeScrollingNode::commitStateAfterChildren(const ScrollingStateNode& stateNode)
+{
+ const ScrollingStateScrollingNode& scrollingStateNode = downcast<ScrollingStateScrollingNode>(stateNode);
+ if (scrollingStateNode.hasChangedProperty(ScrollingStateScrollingNode::RequestedScrollPosition))
+ scrollingTree().scrollingTreeNodeRequestsScroll(scrollingNodeID(), scrollingStateNode.requestedScrollPosition(), scrollingStateNode.requestedScrollPositionRepresentsProgrammaticScroll());
+}
+
+void ScrollingTreeScrollingNode::updateLayersAfterAncestorChange(const ScrollingTreeNode& changedNode, const FloatRect& fixedPositionRect, const FloatSize& cumulativeDelta)
+{
+ if (!m_children)
+ return;
+
+ for (auto& child : *m_children)
+ child->updateLayersAfterAncestorChange(changedNode, fixedPositionRect, cumulativeDelta);
+}
+
+void ScrollingTreeScrollingNode::setScrollPosition(const FloatPoint& scrollPosition)
+{
+ FloatPoint newScrollPosition = scrollPosition.constrainedBetween(minimumScrollPosition(), maximumScrollPosition());
+ setScrollPositionWithoutContentEdgeConstraints(newScrollPosition);
+}
+
+void ScrollingTreeScrollingNode::setScrollPositionWithoutContentEdgeConstraints(const FloatPoint& scrollPosition)
+{
+ setScrollLayerPosition(scrollPosition, { });
+ scrollingTree().scrollingTreeNodeDidScroll(scrollingNodeID(), scrollPosition, std::nullopt);
+}
+
+FloatPoint ScrollingTreeScrollingNode::minimumScrollPosition() const
+{
+ return FloatPoint();
+}
+
+FloatPoint ScrollingTreeScrollingNode::maximumScrollPosition() const
+{
+ FloatPoint contentSizePoint(totalContentsSize());
+ return FloatPoint(contentSizePoint - scrollableAreaSize()).expandedTo(FloatPoint());
+}
+
+void ScrollingTreeScrollingNode::dumpProperties(TextStream& ts, ScrollingStateTreeAsTextBehavior behavior) const
+{
+ ScrollingTreeNode::dumpProperties(ts, behavior);
+ ts.dumpProperty("scrollable area size", m_scrollableAreaSize);
+ ts.dumpProperty("total content size", m_totalContentsSize);
+ if (m_totalContentsSizeForRubberBand != m_totalContentsSize)
+ ts.dumpProperty("total content size for rubber band", m_totalContentsSizeForRubberBand);
+ if (m_reachableContentsSize != m_totalContentsSize)
+ ts.dumpProperty("reachable content size", m_reachableContentsSize);
+ ts.dumpProperty("scrollable area size", m_lastCommittedScrollPosition);
+ if (m_scrollOrigin != IntPoint())
+ ts.dumpProperty("scrollable area size", m_scrollOrigin);
+
+#if ENABLE(CSS_SCROLL_SNAP)
+ if (m_snapOffsetsInfo.horizontalSnapOffsets.size())
+ ts.dumpProperty("horizontal snap offsets", m_snapOffsetsInfo.horizontalSnapOffsets);
+
+ if (m_snapOffsetsInfo.verticalSnapOffsets.size())
+ ts.dumpProperty("horizontal snap offsets", m_snapOffsetsInfo.verticalSnapOffsets);
+
+ if (m_currentHorizontalSnapPointIndex)
+ ts.dumpProperty("current horizontal snap point index", m_currentHorizontalSnapPointIndex);
+
+ if (m_currentVerticalSnapPointIndex)
+ ts.dumpProperty("current vertical snap point index", m_currentVerticalSnapPointIndex);
+
+#endif
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(ASYNC_SCROLLING)
diff --git a/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.h b/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.h
new file mode 100644
index 000000000..3594b1086
--- /dev/null
+++ b/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(ASYNC_SCROLLING)
+
+#include "IntRect.h"
+#include "ScrollSnapOffsetsInfo.h"
+#include "ScrollTypes.h"
+#include "ScrollingCoordinator.h"
+#include "ScrollingTreeNode.h"
+
+namespace WebCore {
+
+class ScrollingTree;
+class ScrollingStateScrollingNode;
+
+class ScrollingTreeScrollingNode : public ScrollingTreeNode {
+public:
+ virtual ~ScrollingTreeScrollingNode();
+
+ WEBCORE_EXPORT void commitStateBeforeChildren(const ScrollingStateNode&) override;
+ WEBCORE_EXPORT void commitStateAfterChildren(const ScrollingStateNode&) override;
+
+ WEBCORE_EXPORT void updateLayersAfterAncestorChange(const ScrollingTreeNode& changedNode, const FloatRect& fixedPositionRect, const FloatSize& cumulativeDelta) override;
+
+ virtual void handleWheelEvent(const PlatformWheelEvent&) = 0;
+ WEBCORE_EXPORT virtual void setScrollPosition(const FloatPoint&);
+ WEBCORE_EXPORT virtual void setScrollPositionWithoutContentEdgeConstraints(const FloatPoint&);
+
+ virtual void updateLayersAfterViewportChange(const FloatRect& fixedPositionRect, double scale) = 0;
+ virtual void updateLayersAfterDelegatedScroll(const FloatPoint&) { }
+
+ virtual FloatPoint scrollPosition() const = 0;
+
+#if ENABLE(CSS_SCROLL_SNAP)
+ const Vector<float>& horizontalSnapOffsets() const { return m_snapOffsetsInfo.horizontalSnapOffsets; }
+ const Vector<float>& verticalSnapOffsets() const { return m_snapOffsetsInfo.verticalSnapOffsets; }
+ const Vector<ScrollOffsetRange<float>>& horizontalSnapOffsetRanges() const { return m_snapOffsetsInfo.horizontalSnapOffsetRanges; }
+ const Vector<ScrollOffsetRange<float>>& verticalSnapOffsetRanges() const { return m_snapOffsetsInfo.verticalSnapOffsetRanges; }
+ unsigned currentHorizontalSnapPointIndex() const { return m_currentHorizontalSnapPointIndex; }
+ unsigned currentVerticalSnapPointIndex() const { return m_currentVerticalSnapPointIndex; }
+ void setCurrentHorizontalSnapPointIndex(unsigned index) { m_currentHorizontalSnapPointIndex = index; }
+ void setCurrentVerticalSnapPointIndex(unsigned index) { m_currentVerticalSnapPointIndex = index; }
+#endif
+
+protected:
+ ScrollingTreeScrollingNode(ScrollingTree&, ScrollingNodeType, ScrollingNodeID);
+
+ WEBCORE_EXPORT virtual FloatPoint minimumScrollPosition() const;
+ WEBCORE_EXPORT virtual FloatPoint maximumScrollPosition() const;
+
+ virtual void setScrollLayerPosition(const FloatPoint&, const FloatRect& layoutViewport) = 0;
+
+ FloatPoint lastCommittedScrollPosition() const { return m_lastCommittedScrollPosition; }
+ const FloatSize& scrollableAreaSize() const { return m_scrollableAreaSize; }
+ const FloatSize& totalContentsSize() const { return m_totalContentsSize; }
+ const FloatSize& reachableContentsSize() const { return m_reachableContentsSize; }
+ const IntPoint& scrollOrigin() const { return m_scrollOrigin; }
+
+ // If the totalContentsSize changes in the middle of a rubber-band, we still want to use the old totalContentsSize for the sake of
+ // computing the stretchAmount(). Using the old value will keep the animation smooth. When there is no rubber-band in progress at
+ // all, m_totalContentsSizeForRubberBand should be equivalent to m_totalContentsSize.
+ const FloatSize& totalContentsSizeForRubberBand() const { return m_totalContentsSizeForRubberBand; }
+ void setTotalContentsSizeForRubberBand(const FloatSize& totalContentsSizeForRubberBand) { m_totalContentsSizeForRubberBand = totalContentsSizeForRubberBand; }
+
+ ScrollElasticity horizontalScrollElasticity() const { return m_scrollableAreaParameters.horizontalScrollElasticity; }
+ ScrollElasticity verticalScrollElasticity() const { return m_scrollableAreaParameters.verticalScrollElasticity; }
+
+ bool hasEnabledHorizontalScrollbar() const { return m_scrollableAreaParameters.hasEnabledHorizontalScrollbar; }
+ bool hasEnabledVerticalScrollbar() const { return m_scrollableAreaParameters.hasEnabledVerticalScrollbar; }
+
+ bool canHaveScrollbars() const { return m_scrollableAreaParameters.horizontalScrollbarMode != ScrollbarAlwaysOff || m_scrollableAreaParameters.verticalScrollbarMode != ScrollbarAlwaysOff; }
+
+ WEBCORE_EXPORT void dumpProperties(TextStream&, ScrollingStateTreeAsTextBehavior) const override;
+
+private:
+ FloatSize m_scrollableAreaSize;
+ FloatSize m_totalContentsSize;
+ FloatSize m_totalContentsSizeForRubberBand;
+ FloatSize m_reachableContentsSize;
+ FloatPoint m_lastCommittedScrollPosition;
+ IntPoint m_scrollOrigin;
+#if ENABLE(CSS_SCROLL_SNAP)
+ ScrollSnapOffsetsInfo<float> m_snapOffsetsInfo;
+ unsigned m_currentHorizontalSnapPointIndex { 0 };
+ unsigned m_currentVerticalSnapPointIndex { 0 };
+#endif
+ ScrollableAreaParameters m_scrollableAreaParameters;
+};
+
+} // namespace WebCore
+
+SPECIALIZE_TYPE_TRAITS_SCROLLING_NODE(ScrollingTreeScrollingNode, isScrollingNode())
+
+#endif // ENABLE(ASYNC_SCROLLING)
diff --git a/Source/WebCore/page/scrolling/ThreadedScrollingTree.cpp b/Source/WebCore/page/scrolling/ThreadedScrollingTree.cpp
new file mode 100644
index 000000000..f664ed3ac
--- /dev/null
+++ b/Source/WebCore/page/scrolling/ThreadedScrollingTree.cpp
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2014-2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ThreadedScrollingTree.h"
+
+#if ENABLE(ASYNC_SCROLLING)
+
+#include "AsyncScrollingCoordinator.h"
+#include "PlatformWheelEvent.h"
+#include "ScrollingThread.h"
+#include "ScrollingTreeFixedNode.h"
+#include "ScrollingTreeNode.h"
+#include "ScrollingTreeScrollingNode.h"
+#include "ScrollingTreeStickyNode.h"
+#include <wtf/RunLoop.h>
+
+namespace WebCore {
+
+ThreadedScrollingTree::ThreadedScrollingTree(AsyncScrollingCoordinator& scrollingCoordinator)
+ : m_scrollingCoordinator(&scrollingCoordinator)
+{
+}
+
+ThreadedScrollingTree::~ThreadedScrollingTree()
+{
+ // invalidate() should have cleared m_scrollingCoordinator.
+ ASSERT(!m_scrollingCoordinator);
+}
+
+ScrollingTree::EventResult ThreadedScrollingTree::tryToHandleWheelEvent(const PlatformWheelEvent& wheelEvent)
+{
+ if (shouldHandleWheelEventSynchronously(wheelEvent))
+ return SendToMainThread;
+
+ if (willWheelEventStartSwipeGesture(wheelEvent))
+ return DidNotHandleEvent;
+
+ RefPtr<ThreadedScrollingTree> protectedThis(this);
+ ScrollingThread::dispatch([protectedThis, wheelEvent] {
+ protectedThis->handleWheelEvent(wheelEvent);
+ });
+
+ return DidHandleEvent;
+}
+
+void ThreadedScrollingTree::handleWheelEvent(const PlatformWheelEvent& wheelEvent)
+{
+ ASSERT(ScrollingThread::isCurrentThread());
+ ScrollingTree::handleWheelEvent(wheelEvent);
+}
+
+void ThreadedScrollingTree::invalidate()
+{
+ // Invalidate is dispatched by the ScrollingCoordinator class on the ScrollingThread
+ // to break the reference cycle between ScrollingTree and ScrollingCoordinator when the
+ // ScrollingCoordinator's page is destroyed.
+ ASSERT(ScrollingThread::isCurrentThread());
+
+ // Since this can potentially be the last reference to the scrolling coordinator,
+ // we need to release it on the main thread since it has member variables (such as timers)
+ // that expect to be destroyed from the main thread.
+ RunLoop::main().dispatch([scrollingCoordinator = WTFMove(m_scrollingCoordinator)] {
+ });
+}
+
+void ThreadedScrollingTree::commitTreeState(std::unique_ptr<ScrollingStateTree> scrollingStateTree)
+{
+ ASSERT(ScrollingThread::isCurrentThread());
+ ScrollingTree::commitTreeState(WTFMove(scrollingStateTree));
+}
+
+void ThreadedScrollingTree::scrollingTreeNodeDidScroll(ScrollingNodeID nodeID, const FloatPoint& scrollPosition, const std::optional<FloatPoint>& layoutViewportOrigin, ScrollingLayerPositionAction scrollingLayerPositionAction)
+{
+ if (!m_scrollingCoordinator)
+ return;
+
+ if (nodeID == rootNode()->scrollingNodeID())
+ setMainFrameScrollPosition(scrollPosition);
+
+ RunLoop::main().dispatch([scrollingCoordinator = m_scrollingCoordinator, nodeID, scrollPosition, layoutViewportOrigin, localIsHandlingProgrammaticScroll = isHandlingProgrammaticScroll(), scrollingLayerPositionAction] {
+ scrollingCoordinator->scheduleUpdateScrollPositionAfterAsyncScroll(nodeID, scrollPosition, layoutViewportOrigin, localIsHandlingProgrammaticScroll, scrollingLayerPositionAction);
+ });
+}
+
+void ThreadedScrollingTree::currentSnapPointIndicesDidChange(ScrollingNodeID nodeID, unsigned horizontal, unsigned vertical)
+{
+ if (!m_scrollingCoordinator)
+ return;
+
+ RunLoop::main().dispatch([scrollingCoordinator = m_scrollingCoordinator, nodeID, horizontal, vertical] {
+ scrollingCoordinator->setActiveScrollSnapIndices(nodeID, horizontal, vertical);
+ });
+}
+
+#if PLATFORM(MAC)
+void ThreadedScrollingTree::handleWheelEventPhase(PlatformWheelEventPhase phase)
+{
+ if (!m_scrollingCoordinator)
+ return;
+
+ RunLoop::main().dispatch([scrollingCoordinator = m_scrollingCoordinator, phase] {
+ scrollingCoordinator->handleWheelEventPhase(phase);
+ });
+}
+
+void ThreadedScrollingTree::setActiveScrollSnapIndices(ScrollingNodeID nodeID, unsigned horizontalIndex, unsigned verticalIndex)
+{
+ if (!m_scrollingCoordinator)
+ return;
+
+ RunLoop::main().dispatch([scrollingCoordinator = m_scrollingCoordinator, nodeID, horizontalIndex, verticalIndex] {
+ scrollingCoordinator->setActiveScrollSnapIndices(nodeID, horizontalIndex, verticalIndex);
+ });
+}
+
+void ThreadedScrollingTree::deferTestsForReason(WheelEventTestTrigger::ScrollableAreaIdentifier identifier, WheelEventTestTrigger::DeferTestTriggerReason reason)
+{
+ if (!m_scrollingCoordinator)
+ return;
+
+ RunLoop::main().dispatch([scrollingCoordinator = m_scrollingCoordinator, identifier, reason] {
+ scrollingCoordinator->deferTestsForReason(identifier, reason);
+ });
+}
+
+void ThreadedScrollingTree::removeTestDeferralForReason(WheelEventTestTrigger::ScrollableAreaIdentifier identifier, WheelEventTestTrigger::DeferTestTriggerReason reason)
+{
+ if (!m_scrollingCoordinator)
+ return;
+
+ RunLoop::main().dispatch([scrollingCoordinator = m_scrollingCoordinator, identifier, reason] {
+ scrollingCoordinator->removeTestDeferralForReason(identifier, reason);
+ });
+}
+
+#endif
+
+} // namespace WebCore
+
+#endif // ENABLE(ASYNC_SCROLLING)
diff --git a/Source/WebCore/page/scrolling/ThreadedScrollingTree.h b/Source/WebCore/page/scrolling/ThreadedScrollingTree.h
new file mode 100644
index 000000000..6d1d49d67
--- /dev/null
+++ b/Source/WebCore/page/scrolling/ThreadedScrollingTree.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2014-2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(ASYNC_SCROLLING)
+
+#include "ScrollingStateTree.h"
+#include "ScrollingTree.h"
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class AsyncScrollingCoordinator;
+
+// The ThreadedScrollingTree class lives almost exclusively on the scrolling thread and manages the
+// hierarchy of scrollable regions on the page. It's also responsible for dispatching events
+// to the correct scrolling tree nodes or dispatching events back to the ScrollingCoordinator
+// object on the main thread if they can't be handled on the scrolling thread for various reasons.
+class ThreadedScrollingTree : public ScrollingTree {
+public:
+ virtual ~ThreadedScrollingTree();
+
+ void commitTreeState(std::unique_ptr<ScrollingStateTree>) override;
+
+ void handleWheelEvent(const PlatformWheelEvent&) override;
+
+ // Can be called from any thread. Will try to handle the wheel event on the scrolling thread.
+ // Returns true if the wheel event can be handled on the scrolling thread and false if the
+ // event must be sent again to the WebCore event handler.
+ EventResult tryToHandleWheelEvent(const PlatformWheelEvent&) override;
+
+ void invalidate() override;
+
+protected:
+ explicit ThreadedScrollingTree(AsyncScrollingCoordinator&);
+
+ void scrollingTreeNodeDidScroll(ScrollingNodeID, const FloatPoint& scrollPosition, const std::optional<FloatPoint>& layoutViewportOrigin, ScrollingLayerPositionAction = ScrollingLayerPositionAction::Sync) override;
+ void currentSnapPointIndicesDidChange(ScrollingNodeID, unsigned horizontal, unsigned vertical) override;
+#if PLATFORM(MAC)
+ void handleWheelEventPhase(PlatformWheelEventPhase) override;
+ void setActiveScrollSnapIndices(ScrollingNodeID, unsigned horizontalIndex, unsigned verticalIndex) override;
+ void deferTestsForReason(WheelEventTestTrigger::ScrollableAreaIdentifier, WheelEventTestTrigger::DeferTestTriggerReason) override;
+ void removeTestDeferralForReason(WheelEventTestTrigger::ScrollableAreaIdentifier, WheelEventTestTrigger::DeferTestTriggerReason) override;
+#endif
+
+private:
+ bool isThreadedScrollingTree() const override { return true; }
+
+ RefPtr<AsyncScrollingCoordinator> m_scrollingCoordinator;
+};
+
+} // namespace WebCore
+
+SPECIALIZE_TYPE_TRAITS_SCROLLING_TREE(WebCore::ThreadedScrollingTree, isThreadedScrollingTree())
+
+#endif // ENABLE(ASYNC_SCROLLING)
diff --git a/Source/WebCore/page/scrolling/coordinatedgraphics/ScrollingCoordinatorCoordinatedGraphics.cpp b/Source/WebCore/page/scrolling/coordinatedgraphics/ScrollingCoordinatorCoordinatedGraphics.cpp
new file mode 100644
index 000000000..fa662500e
--- /dev/null
+++ b/Source/WebCore/page/scrolling/coordinatedgraphics/ScrollingCoordinatorCoordinatedGraphics.cpp
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if USE(COORDINATED_GRAPHICS)
+
+#include "ScrollingCoordinatorCoordinatedGraphics.h"
+
+#include "CoordinatedGraphicsLayer.h"
+#include "FrameView.h"
+#include "HostWindow.h"
+#include "Page.h"
+#include "RenderLayer.h"
+#include "RenderLayerBacking.h"
+#include "ScrollingConstraints.h"
+#include "ScrollingStateFixedNode.h"
+#include "ScrollingStateScrollingNode.h"
+#include "ScrollingStateStickyNode.h"
+#include "ScrollingStateTree.h"
+
+namespace WebCore {
+
+ScrollingCoordinatorCoordinatedGraphics::ScrollingCoordinatorCoordinatedGraphics(Page* page)
+ : ScrollingCoordinator(page)
+ , m_scrollingStateTree(std::make_unique<ScrollingStateTree>())
+{
+}
+
+ScrollingCoordinatorCoordinatedGraphics::~ScrollingCoordinatorCoordinatedGraphics()
+{
+}
+
+ScrollingNodeID ScrollingCoordinatorCoordinatedGraphics::attachToStateTree(ScrollingNodeType nodeType, ScrollingNodeID newNodeID, ScrollingNodeID parentID)
+{
+ return m_scrollingStateTree->attachNode(nodeType, newNodeID, parentID);
+}
+
+void ScrollingCoordinatorCoordinatedGraphics::detachFromStateTree(ScrollingNodeID nodeID)
+{
+ ScrollingStateNode* node = m_scrollingStateTree->stateNodeForID(nodeID);
+ if (node && node->nodeType() == FixedNode)
+ downcast<CoordinatedGraphicsLayer>(*static_cast<GraphicsLayer*>(node->layer())).setFixedToViewport(false);
+
+ m_scrollingStateTree->detachNode(nodeID);
+}
+
+void ScrollingCoordinatorCoordinatedGraphics::clearStateTree()
+{
+ m_scrollingStateTree->clear();
+}
+
+void ScrollingCoordinatorCoordinatedGraphics::updateViewportConstrainedNode(ScrollingNodeID nodeID, const ViewportConstraints& constraints, GraphicsLayer* graphicsLayer)
+{
+ ASSERT(supportsFixedPositionLayers());
+
+ ScrollingStateNode* node = m_scrollingStateTree->stateNodeForID(nodeID);
+ if (!node)
+ return;
+
+ switch (constraints.constraintType()) {
+ case ViewportConstraints::FixedPositionConstraint: {
+ downcast<CoordinatedGraphicsLayer>(*graphicsLayer).setFixedToViewport(true);
+ downcast<ScrollingStateFixedNode>(*node).setLayer(graphicsLayer);
+ break;
+ }
+ case ViewportConstraints::StickyPositionConstraint:
+ break; // FIXME : Support sticky elements.
+ default:
+ ASSERT_NOT_REACHED();
+ }
+}
+
+void ScrollingCoordinatorCoordinatedGraphics::scrollableAreaScrollLayerDidChange(ScrollableArea& scrollableArea)
+{
+ CoordinatedGraphicsLayer* layer = downcast<CoordinatedGraphicsLayer>(scrollLayerForScrollableArea(scrollableArea));
+ if (!layer)
+ return;
+
+ layer->setScrollableArea(&scrollableArea);
+}
+
+void ScrollingCoordinatorCoordinatedGraphics::willDestroyScrollableArea(ScrollableArea& scrollableArea)
+{
+ CoordinatedGraphicsLayer* layer = downcast<CoordinatedGraphicsLayer>(scrollLayerForScrollableArea(scrollableArea));
+ if (!layer)
+ return;
+
+ layer->setScrollableArea(nullptr);
+}
+
+bool ScrollingCoordinatorCoordinatedGraphics::requestScrollPositionUpdate(FrameView& frameView, const IntPoint& scrollPosition)
+{
+ if (!frameView.delegatesScrolling())
+ return false;
+
+ frameView.hostWindow()->delegatedScrollRequested(scrollPosition);
+ return true;
+}
+
+} // namespace WebCore
+
+#endif // USE(COORDINATED_GRAPHICS)
diff --git a/Source/WebCore/page/scrolling/coordinatedgraphics/ScrollingCoordinatorCoordinatedGraphics.h b/Source/WebCore/page/scrolling/coordinatedgraphics/ScrollingCoordinatorCoordinatedGraphics.h
new file mode 100644
index 000000000..075bcfcc8
--- /dev/null
+++ b/Source/WebCore/page/scrolling/coordinatedgraphics/ScrollingCoordinatorCoordinatedGraphics.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if USE(COORDINATED_GRAPHICS)
+
+#include "ScrollingCoordinator.h"
+
+namespace WebCore {
+
+class ScrollingStateTree;
+
+class ScrollingCoordinatorCoordinatedGraphics : public ScrollingCoordinator {
+public:
+ explicit ScrollingCoordinatorCoordinatedGraphics(Page*);
+ virtual ~ScrollingCoordinatorCoordinatedGraphics();
+
+ bool supportsFixedPositionLayers() const override { return true; }
+
+ ScrollingNodeID attachToStateTree(ScrollingNodeType, ScrollingNodeID newNodeID, ScrollingNodeID parentID) override;
+ void detachFromStateTree(ScrollingNodeID) override;
+ void clearStateTree() override;
+
+ void updateViewportConstrainedNode(ScrollingNodeID, const ViewportConstraints&, GraphicsLayer*) override;
+
+ void scrollableAreaScrollLayerDidChange(ScrollableArea&) override;
+ void willDestroyScrollableArea(ScrollableArea&) override;
+
+ bool requestScrollPositionUpdate(FrameView&, const IntPoint&) override;
+
+private:
+ std::unique_ptr<ScrollingStateTree> m_scrollingStateTree;
+};
+
+} // namespace WebCore
+
+#endif // USE(COORDINATED_GRAPHICS)
diff --git a/Source/WebCore/page/scrolling/coordinatedgraphics/ScrollingStateNodeCoordinatedGraphics.cpp b/Source/WebCore/page/scrolling/coordinatedgraphics/ScrollingStateNodeCoordinatedGraphics.cpp
new file mode 100644
index 000000000..aeb6223c1
--- /dev/null
+++ b/Source/WebCore/page/scrolling/coordinatedgraphics/ScrollingStateNodeCoordinatedGraphics.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2013 Intel Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ScrollingStateNode.h"
+
+#include "GraphicsLayer.h"
+#include "NotImplemented.h"
+#include "ScrollingStateTree.h"
+
+#if USE(COORDINATED_GRAPHICS)
+
+namespace WebCore {
+
+void LayerRepresentation::retainPlatformLayer(PlatformLayer*)
+{
+ notImplemented();
+}
+
+void LayerRepresentation::releasePlatformLayer(PlatformLayer*)
+{
+ notImplemented();
+}
+
+} // namespace WebCore
+
+#endif // USE(COORDINATED_GRAPHICS)