[iOS WK2] A top fixed bar can flicker when scrolling with the keyboard up
authorsimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 25 Jul 2019 21:12:01 +0000 (21:12 +0000)
committersimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 25 Jul 2019 21:12:01 +0000 (21:12 +0000)
https://bugs.webkit.org/show_bug.cgi?id=200105
rdar://problem/52871975

Reviewed by Wenson Hsieh.

Source/WebCore:

ScrollingTreeFrameScrollingNode::layoutViewportForScrollPosition() computes a visual viewport
from the current scroll position and scrollableAreaSize(). This doesn't know anything about
the impact of keyboards on the visual viewport, so it computes a too-large visual viewport
when the keyboard is up, triggering incorrect manipulations of the layout viewport. This
leads to the top bar flashing to position 0 when it should be hidden off the top.

Fix by feeding into the scrolling tree the height of the visual viewport which takes
FrameView::visualViewportOverrideRect() into account. This is stored on ScrollingStateFrameScrollingNode/
ScrollingTreeFrameScrollingNode.

Test: scrollingcoordinator/ios/fixed-scrolling-with-keyboard.html

* page/FrameView.h:
* page/scrolling/AsyncScrollingCoordinator.cpp:
(WebCore::AsyncScrollingCoordinator::setFrameScrollingNodeState):
* page/scrolling/ScrollingStateFrameScrollingNode.cpp:
(WebCore::ScrollingStateFrameScrollingNode::ScrollingStateFrameScrollingNode):
(WebCore::ScrollingStateFrameScrollingNode::setPropertyChangedBitsAfterReattach):
(WebCore::ScrollingStateFrameScrollingNode::setOverrideVisualViewportSize):
(WebCore::ScrollingStateFrameScrollingNode::dumpProperties const):
* page/scrolling/ScrollingStateFrameScrollingNode.h:
* page/scrolling/ScrollingTree.cpp:
(WebCore::ScrollingTree::commitTreeState): LOG_WITH_STREAM() doesn't evaluate scrollingTreeAsText()
every time.
* page/scrolling/ScrollingTreeFrameScrollingNode.cpp:
(WebCore::ScrollingTreeFrameScrollingNode::commitStateBeforeChildren):
(WebCore::ScrollingTreeFrameScrollingNode::layoutViewportForScrollPosition const):
(WebCore::ScrollingTreeFrameScrollingNode::dumpProperties const):
* page/scrolling/ScrollingTreeFrameScrollingNode.h:

Source/WebKit:

ScrollingTreeFrameScrollingNode::layoutViewportForScrollPosition() computes a visual viewport
from the current scroll position and scrollableAreaSize(). This doesn't know anything about
the impact of keyboards on the visual viewport, so it computes a too-large visual viewport
when the keyboard is up, triggering incorrect manipulations of the layout viewport. This
leads to the top bar flashing to position 0 when it should be hidden off the top.

Fix by feeding into the scrolling tree the height of the visual viewport which takes
FrameView::visualViewportOverrideRect() into account. This is stored on ScrollingStateFrameScrollingNode/
ScrollingTreeFrameScrollingNode.

* Shared/RemoteLayerTree/RemoteScrollingCoordinatorTransaction.cpp:
(ArgumentCoder<ScrollingStateFrameScrollingNode>::encode):
(ArgumentCoder<ScrollingStateFrameScrollingNode>::decode):

LayoutTests:

* resources/ui-helper.js:
(window.UIHelper.ensureStablePresentationUpdate.return.new.Promise):
(window.UIHelper.ensureStablePresentationUpdate):
* scrollingcoordinator/ios/fixed-scrolling-with-keyboard-expected.txt: Added.
* scrollingcoordinator/ios/fixed-scrolling-with-keyboard.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@247839 268f45cc-cd09-0410-ab3c-d52691b4dbfc

14 files changed:
LayoutTests/ChangeLog
LayoutTests/resources/ui-helper.js
LayoutTests/scrollingcoordinator/ios/fixed-scrolling-with-keyboard-expected.txt [new file with mode: 0644]
LayoutTests/scrollingcoordinator/ios/fixed-scrolling-with-keyboard.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/page/FrameView.h
Source/WebCore/page/scrolling/AsyncScrollingCoordinator.cpp
Source/WebCore/page/scrolling/ScrollingStateFrameScrollingNode.cpp
Source/WebCore/page/scrolling/ScrollingStateFrameScrollingNode.h
Source/WebCore/page/scrolling/ScrollingTree.cpp
Source/WebCore/page/scrolling/ScrollingTreeFrameScrollingNode.cpp
Source/WebCore/page/scrolling/ScrollingTreeFrameScrollingNode.h
Source/WebKit/ChangeLog
Source/WebKit/Shared/RemoteLayerTree/RemoteScrollingCoordinatorTransaction.cpp

index ee5b5eb..225a3d9 100644 (file)
         * fast/canvas/setTransfrom-aliases-transform-expected.html: Added.
         * fast/canvas/setTransfrom-aliases-transform.html: Added.
 
+2019-07-24  Simon Fraser  <simon.fraser@apple.com>
+
+        [iOS WK2] A top fixed bar can flicker when scrolling with the keyboard up
+        https://bugs.webkit.org/show_bug.cgi?id=200105
+        rdar://problem/52871975
+
+        Reviewed by Wenson Hsieh.
+
+        * resources/ui-helper.js:
+        (window.UIHelper.ensureStablePresentationUpdate.return.new.Promise):
+        (window.UIHelper.ensureStablePresentationUpdate):
+        * scrollingcoordinator/ios/fixed-scrolling-with-keyboard-expected.txt: Added.
+        * scrollingcoordinator/ios/fixed-scrolling-with-keyboard.html: Added.
+
 2019-07-23  Tim Horton  <timothy_horton@apple.com>
 
         Long press hint of AirPods buy buttons are tall and narrow during animation
index 98174c3..b6fb242 100644 (file)
@@ -254,6 +254,21 @@ window.UIHelper = class UIHelper {
         });
     }
 
+    static ensureStablePresentationUpdate()
+    {
+        if (!this.isWebKit2()) {
+            testRunner.display();
+            return Promise.resolve();
+        }
+
+        return new Promise(resolve => {
+            testRunner.runUIScript(`
+                uiController.doAfterNextStablePresentationUpdate(function() {
+                    uiController.uiScriptComplete();
+                });`, resolve);
+        });
+    }
+
     static ensurePositionInformationUpdateForElement(element)
     {
         const boundingRect = element.getBoundingClientRect();
@@ -969,4 +984,16 @@ window.UIHelper = class UIHelper {
             })()`, resolve);
         });
     }
+
+    static getScrollingTree()
+    {
+        if (!this.isWebKit2() || !this.isIOSFamily())
+            return Promise.resolve();
+
+        return new Promise(resolve => {
+            testRunner.runUIScript(`(() => {
+                return uiController.scrollingTreeAsText;
+            })()`, resolve);
+        });
+    }
 }
diff --git a/LayoutTests/scrollingcoordinator/ios/fixed-scrolling-with-keyboard-expected.txt b/LayoutTests/scrollingcoordinator/ios/fixed-scrolling-with-keyboard-expected.txt
new file mode 100644 (file)
index 0000000..69e7db7
--- /dev/null
@@ -0,0 +1,23 @@
+
+
+(scrolling tree
+  (frame scrolling node
+    (scrollable area size width=220 height=377)
+    (total content size width=320 height=4021)
+    (last committed scroll position (0,0))
+    (scrollable area parameters 
+      (horizontal scroll elasticity 1)
+      (vertical scroll elasticity 1)
+      (horizontal scrollbar mode 0)
+      (vertical scrollbar mode 0))
+    (layout viewport (0,0) width=320 height=548)
+    (min layoutViewport origin (0,0))
+    (max layoutViewport origin (100,3644))
+    (override visual viewport size width=220.20 height=346.83)
+    (behavior for fixed 0)
+    (visual viewport is smaller than layout viewport 1)
+    (fixed node
+      (fixed constraints 
+        (viewport-rect-at-last-layout (0,0) width=320 height=548)
+        (layer-position-at-last-layout (0,0)))
+      (layer top left (0,0)))))
diff --git a/LayoutTests/scrollingcoordinator/ios/fixed-scrolling-with-keyboard.html b/LayoutTests/scrollingcoordinator/ios/fixed-scrolling-with-keyboard.html
new file mode 100644 (file)
index 0000000..a45a9ce
--- /dev/null
@@ -0,0 +1,45 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true ] -->
+<html>
+<head>
+    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+
+    <style>
+        body {
+            height: 4000px;
+        }
+        .header {
+            position: fixed;
+            top: 0;
+            left: 0;
+            height: 30px;
+            width: 100%;
+            background-color: rgba(0, 0, 0, 0.5);
+        }
+    </style>
+
+    <script src="../../resources/ui-helper.js"></script>
+    <script>
+        if (window.testRunner) {
+            testRunner.waitUntilDone();
+            testRunner.dumpAsText();
+        }
+
+        window.addEventListener('load', async () => {
+
+            await UIHelper.activateAndWaitForInputSessionAt(5, 5);
+            document.getElementById('input').value = 'hi'; // Trigger a layout and flush.
+            await UIHelper.ensureStablePresentationUpdate();
+
+            let scrollingTree = await UIHelper.getScrollingTree();
+            document.getElementById('scrolling-tree').textContent = scrollingTree;
+            testRunner.notifyDone();
+        }, false);
+    </script>
+</head>
+<body>
+    <div class="header">
+        <input id="input">
+    </div>
+<pre id="scrolling-tree"></pre>
+</body>
+</html>
index 038e7e2..a54803d 100644 (file)
         * html/canvas/CanvasRenderingContext2DBase.cpp:
         (WebCore::CanvasRenderingContext2DBase::setTransform):
 
+2019-07-24  Simon Fraser  <simon.fraser@apple.com>
+
+        [iOS WK2] A top fixed bar can flicker when scrolling with the keyboard up
+        https://bugs.webkit.org/show_bug.cgi?id=200105
+        rdar://problem/52871975
+
+        Reviewed by Wenson Hsieh.
+
+        ScrollingTreeFrameScrollingNode::layoutViewportForScrollPosition() computes a visual viewport
+        from the current scroll position and scrollableAreaSize(). This doesn't know anything about
+        the impact of keyboards on the visual viewport, so it computes a too-large visual viewport
+        when the keyboard is up, triggering incorrect manipulations of the layout viewport. This
+        leads to the top bar flashing to position 0 when it should be hidden off the top.
+
+        Fix by feeding into the scrolling tree the height of the visual viewport which takes
+        FrameView::visualViewportOverrideRect() into account. This is stored on ScrollingStateFrameScrollingNode/
+        ScrollingTreeFrameScrollingNode.
+
+        Test: scrollingcoordinator/ios/fixed-scrolling-with-keyboard.html
+
+        * page/FrameView.h:
+        * page/scrolling/AsyncScrollingCoordinator.cpp:
+        (WebCore::AsyncScrollingCoordinator::setFrameScrollingNodeState):
+        * page/scrolling/ScrollingStateFrameScrollingNode.cpp:
+        (WebCore::ScrollingStateFrameScrollingNode::ScrollingStateFrameScrollingNode):
+        (WebCore::ScrollingStateFrameScrollingNode::setPropertyChangedBitsAfterReattach):
+        (WebCore::ScrollingStateFrameScrollingNode::setOverrideVisualViewportSize):
+        (WebCore::ScrollingStateFrameScrollingNode::dumpProperties const):
+        * page/scrolling/ScrollingStateFrameScrollingNode.h:
+        * page/scrolling/ScrollingTree.cpp:
+        (WebCore::ScrollingTree::commitTreeState): LOG_WITH_STREAM() doesn't evaluate scrollingTreeAsText()
+        every time.
+        * page/scrolling/ScrollingTreeFrameScrollingNode.cpp:
+        (WebCore::ScrollingTreeFrameScrollingNode::commitStateBeforeChildren):
+        (WebCore::ScrollingTreeFrameScrollingNode::layoutViewportForScrollPosition const):
+        (WebCore::ScrollingTreeFrameScrollingNode::dumpProperties const):
+        * page/scrolling/ScrollingTreeFrameScrollingNode.h:
+
 2019-07-23  Tim Horton  <timothy_horton@apple.com>
 
         Long press hint of AirPods buy buttons are tall and narrow during animation
index cbd188c..7cd95df 100644 (file)
@@ -258,6 +258,7 @@ public:
     Optional<LayoutRect> layoutViewportOverrideRect() const { return m_layoutViewportOverrideRect; }
 
     WEBCORE_EXPORT void setVisualViewportOverrideRect(Optional<LayoutRect>);
+    Optional<LayoutRect> visualViewportOverrideRect() const { return m_visualViewportOverrideRect; }
 
     // These are in document coordinates, unaffected by page scale (but affected by zooming).
     WEBCORE_EXPORT LayoutRect layoutViewportRect() const;
index 6e8a1eb..ae8a9fb 100644 (file)
@@ -652,6 +652,11 @@ void AsyncScrollingCoordinator::setFrameScrollingNodeState(ScrollingNodeID nodeI
     frameScrollingNode.setMinLayoutViewportOrigin(frameView.minStableLayoutViewportOrigin());
     frameScrollingNode.setMaxLayoutViewportOrigin(frameView.maxStableLayoutViewportOrigin());
 
+    if (auto visualOverrideRect = frameView.visualViewportOverrideRect())
+        frameScrollingNode.setOverrideVisualViewportSize(FloatSize(visualOverrideRect.value().size()));
+    else
+        frameScrollingNode.setOverrideVisualViewportSize(WTF::nullopt);
+
     frameScrollingNode.setFixedElementsLayoutRelativeToFrame(frameView.fixedElementsLayoutRelativeToFrame());
 
     auto visualViewportIsSmallerThanLayoutViewport = [](const FrameView& frameView) {
index 6169e21..c895b34 100644 (file)
@@ -50,6 +50,7 @@ ScrollingStateFrameScrollingNode::ScrollingStateFrameScrollingNode(const Scrolli
     , m_layoutViewport(stateNode.layoutViewport())
     , m_minLayoutViewportOrigin(stateNode.minLayoutViewportOrigin())
     , m_maxLayoutViewportOrigin(stateNode.maxLayoutViewportOrigin())
+    , m_overrideVisualViewportSize(stateNode.overrideVisualViewportSize())
     , m_frameScaleFactor(stateNode.frameScaleFactor())
     , m_topContentInset(stateNode.topContentInset())
     , m_headerHeight(stateNode.headerHeight())
@@ -108,6 +109,7 @@ void ScrollingStateFrameScrollingNode::setPropertyChangedBitsAfterReattach()
     setPropertyChangedBit(LayoutViewport);
     setPropertyChangedBit(MinLayoutViewportOrigin);
     setPropertyChangedBit(MaxLayoutViewportOrigin);
+    setPropertyChangedBit(OverrideVisualViewportSize);
 
     ScrollingStateScrollingNode::setPropertyChangedBitsAfterReattach();
 }
@@ -176,6 +178,15 @@ void ScrollingStateFrameScrollingNode::setMaxLayoutViewportOrigin(const FloatPoi
     setPropertyChanged(MaxLayoutViewportOrigin);
 }
 
+void ScrollingStateFrameScrollingNode::setOverrideVisualViewportSize(Optional<FloatSize> viewportSize)
+{
+    if (viewportSize == m_overrideVisualViewportSize)
+        return;
+
+    m_overrideVisualViewportSize = viewportSize;
+    setPropertyChanged(OverrideVisualViewportSize);
+}
+
 void ScrollingStateFrameScrollingNode::setHeaderHeight(int headerHeight)
 {
     if (m_headerHeight == headerHeight)
@@ -312,6 +323,9 @@ void ScrollingStateFrameScrollingNode::dumpProperties(TextStream& ts, ScrollingS
     ts.dumpProperty("min layout viewport origin", m_minLayoutViewportOrigin);
     ts.dumpProperty("max layout viewport origin", m_maxLayoutViewportOrigin);
     
+    if (m_overrideVisualViewportSize)
+        ts.dumpProperty("override visual viewport size", m_overrideVisualViewportSize.value());
+
     if (m_behaviorForFixed == StickToViewportBounds)
         ts.dumpProperty("behavior for fixed", m_behaviorForFixed);
 
index 473c442..5e8e3b1 100644 (file)
@@ -66,6 +66,7 @@ public:
         LayoutViewport,
         MinLayoutViewportOrigin,
         MaxLayoutViewportOrigin,
+        OverrideVisualViewportSize,
     };
 
     float frameScaleFactor() const { return m_frameScaleFactor; }
@@ -89,6 +90,9 @@ public:
     FloatPoint maxLayoutViewportOrigin() const { return m_maxLayoutViewportOrigin; }
     WEBCORE_EXPORT void setMaxLayoutViewportOrigin(const FloatPoint&);
 
+    Optional<FloatSize> overrideVisualViewportSize() const { return m_overrideVisualViewportSize; };
+    WEBCORE_EXPORT void setOverrideVisualViewportSize(Optional<FloatSize>);
+
     int headerHeight() const { return m_headerHeight; }
     WEBCORE_EXPORT void setHeaderHeight(int);
 
@@ -154,6 +158,7 @@ private:
     FloatRect m_layoutViewport;
     FloatPoint m_minLayoutViewportOrigin;
     FloatPoint m_maxLayoutViewportOrigin;
+    Optional<FloatSize> m_overrideVisualViewportSize;
 
     float m_frameScaleFactor { 1 };
     float m_topContentInset { 0 };
index 5096e1e..37cc72a 100644 (file)
@@ -186,7 +186,7 @@ void ScrollingTree::commitTreeState(std::unique_ptr<ScrollingStateTree> scrollin
         m_nodeMap.remove(nodeID);
     }
 
-    LOG(Scrolling, "committed ScrollingTree\n%s", scrollingTreeAsText(ScrollingStateTreeAsTextBehaviorDebug).utf8().data());
+    LOG_WITH_STREAM(Scrolling, stream << "committed ScrollingTree" << scrollingTreeAsText(ScrollingStateTreeAsTextBehaviorDebug));
 }
 
 void ScrollingTree::updateTreeFromStateNode(const ScrollingStateNode* stateNode, OrphanScrollingNodeMap& orphanNodes, HashSet<ScrollingNodeID>& unvisitedNodes)
index 4c695f9..11c7269 100644 (file)
@@ -85,6 +85,9 @@ void ScrollingTreeFrameScrollingNode::commitStateBeforeChildren(const ScrollingS
 
     if (state.hasChangedProperty(ScrollingStateFrameScrollingNode::MaxLayoutViewportOrigin))
         m_maxLayoutViewportOrigin = state.maxLayoutViewportOrigin();
+
+    if (state.hasChangedProperty(ScrollingStateFrameScrollingNode::OverrideVisualViewportSize))
+        m_overrideVisualViewportSize = state.overrideVisualViewportSize();
 }
 
 bool ScrollingTreeFrameScrollingNode::scrollPositionAndLayoutViewportMatch(const FloatPoint& position, Optional<FloatRect> overrideLayoutViewport)
@@ -94,11 +97,12 @@ bool ScrollingTreeFrameScrollingNode::scrollPositionAndLayoutViewportMatch(const
 
 FloatRect ScrollingTreeFrameScrollingNode::layoutViewportForScrollPosition(const FloatPoint& visibleContentOrigin, float scale) const
 {
-    FloatRect visibleContentRect(visibleContentOrigin, scrollableAreaSize());
+    FloatSize visualViewportSize = m_overrideVisualViewportSize.valueOr(scrollableAreaSize());
+    FloatRect visibleContentRect(visibleContentOrigin, visualViewportSize);
     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 << "\nScrolling thread: " << "(visibleContentOrigin " << visibleContentOrigin << ", visualViewportSize " << visualViewportSize << ") 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());
@@ -146,6 +150,9 @@ void ScrollingTreeFrameScrollingNode::dumpProperties(TextStream& ts, ScrollingSt
     ts.dumpProperty("min layoutViewport origin", m_minLayoutViewportOrigin);
     ts.dumpProperty("max layoutViewport origin", m_maxLayoutViewportOrigin);
 
+    if (m_overrideVisualViewportSize)
+        ts.dumpProperty("override visual viewport size", m_overrideVisualViewportSize.value());
+
     if (m_frameScaleFactor != 1)
         ts.dumpProperty("frame scale factor", m_frameScaleFactor);
     if (m_topContentInset)
index 1aaded5..3c639c0 100644 (file)
@@ -78,6 +78,7 @@ private:
     FloatRect m_layoutViewport;
     FloatPoint m_minLayoutViewportOrigin;
     FloatPoint m_maxLayoutViewportOrigin;
+    Optional<FloatSize> m_overrideVisualViewportSize;
     
     float m_frameScaleFactor { 1 };
     float m_topContentInset { 0 };
index 6401589..bbfb5f8 100644 (file)
         (WebKit::WebProcessPool::sendWebProcessDataStoreParameters):
         * UIProcess/WebProcessPool.h:
 
+2019-07-24  Simon Fraser  <simon.fraser@apple.com>
+
+        [iOS WK2] A top fixed bar can flicker when scrolling with the keyboard up
+        https://bugs.webkit.org/show_bug.cgi?id=200105
+        rdar://problem/52871975
+
+        Reviewed by Wenson Hsieh.
+
+        ScrollingTreeFrameScrollingNode::layoutViewportForScrollPosition() computes a visual viewport
+        from the current scroll position and scrollableAreaSize(). This doesn't know anything about
+        the impact of keyboards on the visual viewport, so it computes a too-large visual viewport
+        when the keyboard is up, triggering incorrect manipulations of the layout viewport. This
+        leads to the top bar flashing to position 0 when it should be hidden off the top.
+
+        Fix by feeding into the scrolling tree the height of the visual viewport which takes
+        FrameView::visualViewportOverrideRect() into account. This is stored on ScrollingStateFrameScrollingNode/
+        ScrollingTreeFrameScrollingNode.
+
+        * Shared/RemoteLayerTree/RemoteScrollingCoordinatorTransaction.cpp:
+        (ArgumentCoder<ScrollingStateFrameScrollingNode>::encode):
+        (ArgumentCoder<ScrollingStateFrameScrollingNode>::decode):
+
 2019-07-23  Alex Christensen  <achristensen@webkit.org>
 
         Add SPI for setting media cache and key location on _WKWebsiteDataStoreConfiguration
index 5f9b68f..978c4bb 100644 (file)
@@ -183,6 +183,7 @@ void ArgumentCoder<ScrollingStateFrameScrollingNode>::encode(Encoder& encoder, c
     SCROLLING_NODE_ENCODE(ScrollingStateFrameScrollingNode::LayoutViewport, layoutViewport)
     SCROLLING_NODE_ENCODE(ScrollingStateFrameScrollingNode::MinLayoutViewportOrigin, minLayoutViewportOrigin)
     SCROLLING_NODE_ENCODE(ScrollingStateFrameScrollingNode::MaxLayoutViewportOrigin, maxLayoutViewportOrigin)
+    SCROLLING_NODE_ENCODE(ScrollingStateFrameScrollingNode::OverrideVisualViewportSize, overrideVisualViewportSize)
 
     if (node.hasChangedProperty(ScrollingStateFrameScrollingNode::CounterScrollingLayer))
         encoder << static_cast<GraphicsLayer::PlatformLayerID>(node.counterScrollingLayer());
@@ -311,6 +312,7 @@ bool ArgumentCoder<ScrollingStateFrameScrollingNode>::decode(Decoder& decoder, S
     SCROLLING_NODE_DECODE(ScrollingStateFrameScrollingNode::LayoutViewport, FloatRect, setLayoutViewport)
     SCROLLING_NODE_DECODE(ScrollingStateFrameScrollingNode::MinLayoutViewportOrigin, FloatPoint, setMinLayoutViewportOrigin)
     SCROLLING_NODE_DECODE(ScrollingStateFrameScrollingNode::MaxLayoutViewportOrigin, FloatPoint, setMaxLayoutViewportOrigin)
+    SCROLLING_NODE_DECODE(ScrollingStateFrameScrollingNode::OverrideVisualViewportSize, Optional<FloatSize>, setOverrideVisualViewportSize)
 
     if (node.hasChangedProperty(ScrollingStateFrameScrollingNode::CounterScrollingLayer)) {
         GraphicsLayer::PlatformLayerID layerID;