<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[211379] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/211379">211379</a></dd>
<dt>Author</dt> <dd>simon.fraser@apple.com</dd>
<dt>Date</dt> <dd>2017-01-30 11:46:40 -0800 (Mon, 30 Jan 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>Fixed elements should not rubber-band in WK2, nor remain at negative offsets
https://bugs.webkit.org/show_bug.cgi?id=167484
rdar://problem/29453068

Reviewed by Dean Jackson.
Source/WebCore:

There were various problems with the layout rect computation:
1. It ignored the scrollBehaviorForFixedElements() which we use to avoid rubber-banding fixed
   elements in WK2, but allow in WK1, so make use of that.
2. Sometimes layouts/paints of fixed elements would be triggered when coalesced calls to
   AsyncScrollingCoordinator::scheduleUpdateScrollPositionAfterAsyncScroll() failed to
   copy the layoutViewportOrigin to the scheduled update.
3. The layout viewport could be left with a negative top/left after rubber-banding.

Also add a way to do unconstrained scrollTo(), so that a test can call window.scrollTo(-10, -10) to
simulate rubberbanding.

Tests: fast/visual-viewport/rubberbanding-viewport-rects-header-footer.html
       fast/visual-viewport/rubberbanding-viewport-rects.html

* page/FrameView.cpp:
(WebCore::FrameView::computeLayoutViewportOrigin): Handle ScrollBehaviorForFixedElements, incorporating it
into logic that clamps layoutViewportOrigin between min/max when rubberbanding is not allowed, or not in progress.
(WebCore::FrameView::updateLayoutViewport): Pass in scrollBehaviorForFixedElements().
(WebCore::FrameView::visibleDocumentRect): The clamping here was preventing the visible rect from
escaping the document bounds, which caused fixed elements to bounce with rubber-banding, so remove the clamping,
and fix the logic to allow rubber-banding while taking headers and footers into account.
* page/FrameView.h:
* page/scrolling/AsyncScrollingCoordinator.cpp:
(WebCore::AsyncScrollingCoordinator::scheduleUpdateScrollPositionAfterAsyncScroll): layoutViewportOrigin has to
be pushed onto the scheduled update, just like scroll position.
* page/scrolling/ScrollingTreeFrameScrollingNode.cpp:
(WebCore::ScrollingTreeFrameScrollingNode::layoutViewportForScrollPosition): Pass in m_behaviorForFixed.
* platform/ScrollView.cpp:
(WebCore::ScrollView::ScrollView):
(WebCore::ScrollView::adjustScrollPositionWithinRange):
(WebCore::ScrollView::setScrollOffset):
* platform/ScrollView.h:
(WebCore::ScrollView::setAllowsUnclampedScrollPositionForTesting):
(WebCore::ScrollView::allowsUnclampedScrollPosition):
* testing/InternalSettings.cpp:
(WebCore::InternalSettings::setAllowUnclampedScrollPosition):
* testing/InternalSettings.h:
* testing/InternalSettings.idl:

Source/WebKit2:

Pass in StickToViewportBounds as we did before visual viewports.

* UIProcess/ios/WebPageProxyIOS.mm:
(WebKit::WebPageProxy::computeCustomFixedPositionRect):

LayoutTests:

Add two tests that use internals.settings.setAllowUnclampedScrollPosition(true) and then
over-scroll to simulator rubber-banding, dumping viewport rects.

setAllowUnclampedScrollPosition() only works in WebKit2, so skip the tests elsewhere.

* TestExpectations:
* fast/visual-viewport/rubberbanding-viewport-rects-expected.txt: Added.
* fast/visual-viewport/rubberbanding-viewport-rects-header-footer-expected.txt: Added.
* fast/visual-viewport/rubberbanding-viewport-rects-header-footer.html: Added.
* fast/visual-viewport/rubberbanding-viewport-rects.html: Added.
* platform/ios-simulator-wk2/TestExpectations:
* platform/ios-simulator-wk2/fast/visual-viewport/rubberbanding-viewport-rects-expected.txt: Added.
* platform/ios-simulator-wk2/fast/visual-viewport/rubberbanding-viewport-rects-header-footer-expected.txt: Added.
* platform/mac-wk2/TestExpectations:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsTestExpectations">trunk/LayoutTests/TestExpectations</a></li>
<li><a href="#trunkLayoutTestsplatformiossimulatorwk2TestExpectations">trunk/LayoutTests/platform/ios-simulator-wk2/TestExpectations</a></li>
<li><a href="#trunkLayoutTestsplatformmacwk2TestExpectations">trunk/LayoutTests/platform/mac-wk2/TestExpectations</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorepageFrameViewcpp">trunk/Source/WebCore/page/FrameView.cpp</a></li>
<li><a href="#trunkSourceWebCorepageFrameViewh">trunk/Source/WebCore/page/FrameView.h</a></li>
<li><a href="#trunkSourceWebCorepagescrollingAsyncScrollingCoordinatorcpp">trunk/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.cpp</a></li>
<li><a href="#trunkSourceWebCorepagescrollingScrollingTreeFrameScrollingNodecpp">trunk/Source/WebCore/page/scrolling/ScrollingTreeFrameScrollingNode.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformScrollViewcpp">trunk/Source/WebCore/platform/ScrollView.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformScrollViewh">trunk/Source/WebCore/platform/ScrollView.h</a></li>
<li><a href="#trunkSourceWebCoretestingInternalSettingscpp">trunk/Source/WebCore/testing/InternalSettings.cpp</a></li>
<li><a href="#trunkSourceWebCoretestingInternalSettingsh">trunk/Source/WebCore/testing/InternalSettings.h</a></li>
<li><a href="#trunkSourceWebCoretestingInternalSettingsidl">trunk/Source/WebCore/testing/InternalSettings.idl</a></li>
<li><a href="#trunkSourceWebKit2ChangeLog">trunk/Source/WebKit2/ChangeLog</a></li>
<li><a href="#trunkSourceWebKit2UIProcessiosWebPageProxyIOSmm">trunk/Source/WebKit2/UIProcess/ios/WebPageProxyIOS.mm</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsfastvisualviewportrubberbandingviewportrectsexpectedtxt">trunk/LayoutTests/fast/visual-viewport/rubberbanding-viewport-rects-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastvisualviewportrubberbandingviewportrectsheaderfooterexpectedtxt">trunk/LayoutTests/fast/visual-viewport/rubberbanding-viewport-rects-header-footer-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastvisualviewportrubberbandingviewportrectsheaderfooterhtml">trunk/LayoutTests/fast/visual-viewport/rubberbanding-viewport-rects-header-footer.html</a></li>
<li><a href="#trunkLayoutTestsfastvisualviewportrubberbandingviewportrectshtml">trunk/LayoutTests/fast/visual-viewport/rubberbanding-viewport-rects.html</a></li>
<li><a href="#trunkLayoutTestsplatformiossimulatorwk2fastvisualviewportrubberbandingviewportrectsexpectedtxt">trunk/LayoutTests/platform/ios-simulator-wk2/fast/visual-viewport/rubberbanding-viewport-rects-expected.txt</a></li>
<li><a href="#trunkLayoutTestsplatformiossimulatorwk2fastvisualviewportrubberbandingviewportrectsheaderfooterexpectedtxt">trunk/LayoutTests/platform/ios-simulator-wk2/fast/visual-viewport/rubberbanding-viewport-rects-header-footer-expected.txt</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (211378 => 211379)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2017-01-30 19:40:48 UTC (rev 211378)
+++ trunk/LayoutTests/ChangeLog        2017-01-30 19:46:40 UTC (rev 211379)
</span><span class="lines">@@ -1,3 +1,26 @@
</span><ins>+2017-01-30  Simon Fraser  &lt;simon.fraser@apple.com&gt;
+
+        Fixed elements should not rubber-band in WK2, nor remain at negative offsets
+        https://bugs.webkit.org/show_bug.cgi?id=167484
+        rdar://problem/29453068
+
+        Reviewed by Dean Jackson.
+        
+        Add two tests that use internals.settings.setAllowUnclampedScrollPosition(true) and then
+        over-scroll to simulator rubber-banding, dumping viewport rects.
+        
+        setAllowUnclampedScrollPosition() only works in WebKit2, so skip the tests elsewhere.
+
+        * TestExpectations:
+        * fast/visual-viewport/rubberbanding-viewport-rects-expected.txt: Added.
+        * fast/visual-viewport/rubberbanding-viewport-rects-header-footer-expected.txt: Added.
+        * fast/visual-viewport/rubberbanding-viewport-rects-header-footer.html: Added.
+        * fast/visual-viewport/rubberbanding-viewport-rects.html: Added.
+        * platform/ios-simulator-wk2/TestExpectations:
+        * platform/ios-simulator-wk2/fast/visual-viewport/rubberbanding-viewport-rects-expected.txt: Added.
+        * platform/ios-simulator-wk2/fast/visual-viewport/rubberbanding-viewport-rects-header-footer-expected.txt: Added.
+        * platform/mac-wk2/TestExpectations:
+
</ins><span class="cx"> 2017-01-30  Ryan Haddad  &lt;ryanhaddad@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Unreviewed, rollout r211235 Pointer lock events should be delivered directly to the target element.
</span></span></pre></div>
<a id="trunkLayoutTestsTestExpectations"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/TestExpectations (211378 => 211379)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/TestExpectations        2017-01-30 19:40:48 UTC (rev 211378)
+++ trunk/LayoutTests/TestExpectations        2017-01-30 19:46:40 UTC (rev 211379)
</span><span class="lines">@@ -89,6 +89,10 @@
</span><span class="cx"> # ApplePay is only available on iOS (greater than iOS 10) and macOS (greater than macOS 10.12) and only for WebKit2.
</span><span class="cx"> http/tests/ssl/applepay/ [ Skip ]
</span><span class="cx"> 
</span><ins>+# Only WK2 allows unconstrained scrolling
+fast/visual-viewport/rubberbanding-viewport-rects.html [ Skip ]
+fast/visual-viewport/rubberbanding-viewport-rects-header-footer.html  [ Skip ]
+
</ins><span class="cx"> #//////////////////////////////////////////////////////////////////////////////////////////
</span><span class="cx"> # End platform-specific tests.
</span><span class="cx"> #//////////////////////////////////////////////////////////////////////////////////////////
</span></span></pre></div>
<a id="trunkLayoutTestsfastvisualviewportrubberbandingviewportrectsexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/visual-viewport/rubberbanding-viewport-rects-expected.txt (0 => 211379)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/visual-viewport/rubberbanding-viewport-rects-expected.txt                                (rev 0)
+++ trunk/LayoutTests/fast/visual-viewport/rubberbanding-viewport-rects-expected.txt        2017-01-30 19:46:40 UTC (rev 211379)
</span><span class="lines">@@ -0,0 +1,20 @@
</span><ins>+This test scrolls the page and checks that the layout and visual viewports respond as expected.
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+Scrolled to -123, -234
+JSON.stringify(layoutViewport) is {&quot;top&quot;:0,&quot;right&quot;:785,&quot;bottom&quot;:585,&quot;left&quot;:0,&quot;width&quot;:785,&quot;height&quot;:585}
+JSON.stringify(visualViewport) is {&quot;top&quot;:-234,&quot;right&quot;:662,&quot;bottom&quot;:351,&quot;left&quot;:-123,&quot;width&quot;:785,&quot;height&quot;:585}
+
+Scrolled to 475, 525
+JSON.stringify(layoutViewport) is {&quot;top&quot;:525,&quot;right&quot;:1260,&quot;bottom&quot;:1110,&quot;left&quot;:475,&quot;width&quot;:785,&quot;height&quot;:585}
+JSON.stringify(visualViewport) is {&quot;top&quot;:525,&quot;right&quot;:1260,&quot;bottom&quot;:1110,&quot;left&quot;:475,&quot;width&quot;:785,&quot;height&quot;:585}
+
+Scrolled to 1800, 1700
+JSON.stringify(layoutViewport) is {&quot;top&quot;:1690,&quot;right&quot;:2008,&quot;bottom&quot;:2275,&quot;left&quot;:1223,&quot;width&quot;:785,&quot;height&quot;:585}
+JSON.stringify(visualViewport) is {&quot;top&quot;:1700,&quot;right&quot;:2585,&quot;bottom&quot;:2275,&quot;left&quot;:1800,&quot;width&quot;:785,&quot;height&quot;:575}
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsfastvisualviewportrubberbandingviewportrectsheaderfooterexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/visual-viewport/rubberbanding-viewport-rects-header-footer-expected.txt (0 => 211379)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/visual-viewport/rubberbanding-viewport-rects-header-footer-expected.txt                                (rev 0)
+++ trunk/LayoutTests/fast/visual-viewport/rubberbanding-viewport-rects-header-footer-expected.txt        2017-01-30 19:46:40 UTC (rev 211379)
</span><span class="lines">@@ -0,0 +1,20 @@
</span><ins>+This test scrolls the page and checks that the layout and visual viewports respond as expected.
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+Scrolled to -123, -234
+JSON.stringify(layoutViewport) is {&quot;top&quot;:0,&quot;right&quot;:785,&quot;bottom&quot;:585,&quot;left&quot;:0,&quot;width&quot;:785,&quot;height&quot;:585}
+JSON.stringify(visualViewport) is {&quot;top&quot;:-234,&quot;right&quot;:662,&quot;bottom&quot;:299,&quot;left&quot;:-123,&quot;width&quot;:785,&quot;height&quot;:533}
+
+Scrolled to 475, 525
+JSON.stringify(layoutViewport) is {&quot;top&quot;:473,&quot;right&quot;:1260,&quot;bottom&quot;:1058,&quot;left&quot;:475,&quot;width&quot;:785,&quot;height&quot;:585}
+JSON.stringify(visualViewport) is {&quot;top&quot;:473,&quot;right&quot;:1260,&quot;bottom&quot;:1058,&quot;left&quot;:475,&quot;width&quot;:785,&quot;height&quot;:585}
+
+Scrolled to 1800, 1700
+JSON.stringify(layoutViewport) is {&quot;top&quot;:1648,&quot;right&quot;:2008,&quot;bottom&quot;:2233,&quot;left&quot;:1223,&quot;width&quot;:785,&quot;height&quot;:585}
+JSON.stringify(visualViewport) is {&quot;top&quot;:1648,&quot;right&quot;:2585,&quot;bottom&quot;:2233,&quot;left&quot;:1800,&quot;width&quot;:785,&quot;height&quot;:585}
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsfastvisualviewportrubberbandingviewportrectsheaderfooterhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/visual-viewport/rubberbanding-viewport-rects-header-footer.html (0 => 211379)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/visual-viewport/rubberbanding-viewport-rects-header-footer.html                                (rev 0)
+++ trunk/LayoutTests/fast/visual-viewport/rubberbanding-viewport-rects-header-footer.html        2017-01-30 19:46:40 UTC (rev 211379)
</span><span class="lines">@@ -0,0 +1,66 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+
+&lt;html&gt;
+&lt;head&gt;
+    &lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+    &lt;style&gt;
+        body {
+            height: 2000px;
+            width: 2000px;
+        }
+    &lt;/style&gt;
+    &lt;script&gt;
+        description(&quot;This test scrolls the page and checks that the layout and visual viewports respond as expected.&quot;);
+
+        if (window.internals) {
+            internals.settings.setVisualViewportEnabled(true);
+            internals.settings.setAllowUnclampedScrollPosition(true);
+            internals.setHeaderHeight(52);
+            internals.setFooterHeight(43);
+        }
+
+        window.jsTestIsAsync = true;
+
+        var visualViewport;
+        function doTest()
+        {
+            // Zooming may scroll the view away from the origin.
+            window.scrollTo(-123, -234);
+            visualViewport = internals.visualViewportRect();
+            layoutViewport = internals.layoutViewportRect();
+            debug('Scrolled to ' + window.scrollX + ', ' + window.scrollY);
+
+            // Don't use shouldBeEqualToString() to avoid showing failures when correct output differs between platforms. 
+            evalAndLogResult(&quot;JSON.stringify(layoutViewport)&quot;);
+            evalAndLogResult(&quot;JSON.stringify(visualViewport)&quot;);
+
+            debug('');
+            window.scrollTo(475, 525);
+            visualViewport = internals.visualViewportRect();
+            layoutViewport = internals.layoutViewportRect();
+            debug('Scrolled to ' + window.scrollX + ', ' + window.scrollY);
+
+            evalAndLogResult(&quot;JSON.stringify(layoutViewport)&quot;);
+            evalAndLogResult(&quot;JSON.stringify(visualViewport)&quot;);
+
+            debug('');
+            window.scrollTo(1800, 1700);
+            visualViewport = internals.visualViewportRect();
+            layoutViewport = internals.layoutViewportRect();
+            debug('Scrolled to ' + window.scrollX + ', ' + window.scrollY);
+
+            evalAndLogResult(&quot;JSON.stringify(layoutViewport)&quot;);
+            evalAndLogResult(&quot;JSON.stringify(visualViewport)&quot;);
+
+            window.scrollTo(0, 0);
+
+            finishJSTest();
+        }
+        
+        window.addEventListener('load', doTest, false);
+    &lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+    &lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsfastvisualviewportrubberbandingviewportrectshtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/visual-viewport/rubberbanding-viewport-rects.html (0 => 211379)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/visual-viewport/rubberbanding-viewport-rects.html                                (rev 0)
+++ trunk/LayoutTests/fast/visual-viewport/rubberbanding-viewport-rects.html        2017-01-30 19:46:40 UTC (rev 211379)
</span><span class="lines">@@ -0,0 +1,64 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+
+&lt;html&gt;
+&lt;head&gt;
+    &lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+    &lt;style&gt;
+        body {
+            height: 2000px;
+            width: 2000px;
+        }
+    &lt;/style&gt;
+    &lt;script&gt;
+        description(&quot;This test scrolls the page and checks that the layout and visual viewports respond as expected.&quot;);
+
+        if (window.internals) {
+            internals.settings.setVisualViewportEnabled(true);
+            internals.settings.setAllowUnclampedScrollPosition(true);
+        }
+
+        window.jsTestIsAsync = true;
+
+        var visualViewport;
+        function doTest()
+        {
+            // Zooming may scroll the view away from the origin.
+            window.scrollTo(-123, -234);
+            visualViewport = internals.visualViewportRect();
+            layoutViewport = internals.layoutViewportRect();
+            debug('Scrolled to ' + window.scrollX + ', ' + window.scrollY);
+
+            // Don't use shouldBeEqualToString() to avoid showing failures when correct output differs between platforms. 
+            evalAndLogResult(&quot;JSON.stringify(layoutViewport)&quot;);
+            evalAndLogResult(&quot;JSON.stringify(visualViewport)&quot;);
+
+            debug('');
+            window.scrollTo(475, 525);
+            visualViewport = internals.visualViewportRect();
+            layoutViewport = internals.layoutViewportRect();
+            debug('Scrolled to ' + window.scrollX + ', ' + window.scrollY);
+
+            evalAndLogResult(&quot;JSON.stringify(layoutViewport)&quot;);
+            evalAndLogResult(&quot;JSON.stringify(visualViewport)&quot;);
+
+            debug('');
+            window.scrollTo(1800, 1700);
+            visualViewport = internals.visualViewportRect();
+            layoutViewport = internals.layoutViewportRect();
+            debug('Scrolled to ' + window.scrollX + ', ' + window.scrollY);
+
+            evalAndLogResult(&quot;JSON.stringify(layoutViewport)&quot;);
+            evalAndLogResult(&quot;JSON.stringify(visualViewport)&quot;);
+
+            window.scrollTo(0, 0);
+
+            finishJSTest();
+        }
+        
+        window.addEventListener('load', doTest, false);
+    &lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+    &lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsplatformiossimulatorwk2TestExpectations"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/platform/ios-simulator-wk2/TestExpectations (211378 => 211379)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/platform/ios-simulator-wk2/TestExpectations        2017-01-30 19:40:48 UTC (rev 211378)
+++ trunk/LayoutTests/platform/ios-simulator-wk2/TestExpectations        2017-01-30 19:46:40 UTC (rev 211379)
</span><span class="lines">@@ -17,6 +17,9 @@
</span><span class="cx"> fast/media/mq-monochrome-live-update.html [ Pass ]
</span><span class="cx"> fast/media/mq-prefers-reduced-motion-live-update.html [ Pass ]
</span><span class="cx"> 
</span><ins>+fast/visual-viewport/rubberbanding-viewport-rects.html [ Pass ]
+fast/visual-viewport/rubberbanding-viewport-rects-header-footer.html  [ Pass ]
+
</ins><span class="cx"> #//////////////////////////////////////////////////////////////////////////////////////////
</span><span class="cx"> # End platform-specific directories.
</span><span class="cx"> #//////////////////////////////////////////////////////////////////////////////////////////
</span></span></pre></div>
<a id="trunkLayoutTestsplatformiossimulatorwk2fastvisualviewportrubberbandingviewportrectsexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/platform/ios-simulator-wk2/fast/visual-viewport/rubberbanding-viewport-rects-expected.txt (0 => 211379)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/platform/ios-simulator-wk2/fast/visual-viewport/rubberbanding-viewport-rects-expected.txt                                (rev 0)
+++ trunk/LayoutTests/platform/ios-simulator-wk2/fast/visual-viewport/rubberbanding-viewport-rects-expected.txt        2017-01-30 19:46:40 UTC (rev 211379)
</span><span class="lines">@@ -0,0 +1,20 @@
</span><ins>+This test scrolls the page and checks that the layout and visual viewports respond as expected.
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+Scrolled to -123, -234
+JSON.stringify(layoutViewport) is {&quot;top&quot;:0,&quot;right&quot;:800,&quot;bottom&quot;:600,&quot;left&quot;:0,&quot;width&quot;:800,&quot;height&quot;:600}
+JSON.stringify(visualViewport) is {&quot;top&quot;:-234,&quot;right&quot;:677,&quot;bottom&quot;:366,&quot;left&quot;:-123,&quot;width&quot;:800,&quot;height&quot;:600}
+
+Scrolled to 475, 525
+JSON.stringify(layoutViewport) is {&quot;top&quot;:525,&quot;right&quot;:1275,&quot;bottom&quot;:1125,&quot;left&quot;:475,&quot;width&quot;:800,&quot;height&quot;:600}
+JSON.stringify(visualViewport) is {&quot;top&quot;:525,&quot;right&quot;:1275,&quot;bottom&quot;:1125,&quot;left&quot;:475,&quot;width&quot;:800,&quot;height&quot;:600}
+
+Scrolled to 1800, 1700
+JSON.stringify(layoutViewport) is {&quot;top&quot;:1616,&quot;right&quot;:2008,&quot;bottom&quot;:2216,&quot;left&quot;:1208,&quot;width&quot;:800,&quot;height&quot;:600}
+JSON.stringify(visualViewport) is {&quot;top&quot;:1700,&quot;right&quot;:2600,&quot;bottom&quot;:2216,&quot;left&quot;:1800,&quot;width&quot;:800,&quot;height&quot;:516}
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsplatformiossimulatorwk2fastvisualviewportrubberbandingviewportrectsheaderfooterexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/platform/ios-simulator-wk2/fast/visual-viewport/rubberbanding-viewport-rects-header-footer-expected.txt (0 => 211379)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/platform/ios-simulator-wk2/fast/visual-viewport/rubberbanding-viewport-rects-header-footer-expected.txt                                (rev 0)
+++ trunk/LayoutTests/platform/ios-simulator-wk2/fast/visual-viewport/rubberbanding-viewport-rects-header-footer-expected.txt        2017-01-30 19:46:40 UTC (rev 211379)
</span><span class="lines">@@ -0,0 +1,20 @@
</span><ins>+This test scrolls the page and checks that the layout and visual viewports respond as expected.
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+Scrolled to -123, -234
+JSON.stringify(layoutViewport) is {&quot;top&quot;:0,&quot;right&quot;:800,&quot;bottom&quot;:600,&quot;left&quot;:0,&quot;width&quot;:800,&quot;height&quot;:600}
+JSON.stringify(visualViewport) is {&quot;top&quot;:-234,&quot;right&quot;:677,&quot;bottom&quot;:314,&quot;left&quot;:-123,&quot;width&quot;:800,&quot;height&quot;:548}
+
+Scrolled to 475, 525
+JSON.stringify(layoutViewport) is {&quot;top&quot;:473,&quot;right&quot;:1275,&quot;bottom&quot;:1073,&quot;left&quot;:475,&quot;width&quot;:800,&quot;height&quot;:600}
+JSON.stringify(visualViewport) is {&quot;top&quot;:473,&quot;right&quot;:1275,&quot;bottom&quot;:1073,&quot;left&quot;:475,&quot;width&quot;:800,&quot;height&quot;:600}
+
+Scrolled to 1800, 1700
+JSON.stringify(layoutViewport) is {&quot;top&quot;:1648,&quot;right&quot;:2008,&quot;bottom&quot;:2248,&quot;left&quot;:1208,&quot;width&quot;:800,&quot;height&quot;:600}
+JSON.stringify(visualViewport) is {&quot;top&quot;:1648,&quot;right&quot;:2600,&quot;bottom&quot;:2248,&quot;left&quot;:1800,&quot;width&quot;:800,&quot;height&quot;:600}
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsplatformmacwk2TestExpectations"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/platform/mac-wk2/TestExpectations (211378 => 211379)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/platform/mac-wk2/TestExpectations        2017-01-30 19:40:48 UTC (rev 211378)
+++ trunk/LayoutTests/platform/mac-wk2/TestExpectations        2017-01-30 19:46:40 UTC (rev 211379)
</span><span class="lines">@@ -23,6 +23,9 @@
</span><span class="cx"> 
</span><span class="cx"> [ Sierra+ ] http/tests/ssl/applepay/ [ Pass ]
</span><span class="cx"> 
</span><ins>+fast/visual-viewport/rubberbanding-viewport-rects.html [ Pass ]
+fast/visual-viewport/rubberbanding-viewport-rects-header-footer.html  [ Pass ]
+
</ins><span class="cx"> #//////////////////////////////////////////////////////////////////////////////////////////
</span><span class="cx"> # End platform-specific directories.
</span><span class="cx"> #//////////////////////////////////////////////////////////////////////////////////////////
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (211378 => 211379)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2017-01-30 19:40:48 UTC (rev 211378)
+++ trunk/Source/WebCore/ChangeLog        2017-01-30 19:46:40 UTC (rev 211379)
</span><span class="lines">@@ -1,3 +1,50 @@
</span><ins>+2017-01-30  Simon Fraser  &lt;simon.fraser@apple.com&gt;
+
+        Fixed elements should not rubber-band in WK2, nor remain at negative offsets
+        https://bugs.webkit.org/show_bug.cgi?id=167484
+        rdar://problem/29453068
+
+        Reviewed by Dean Jackson.
+
+        There were various problems with the layout rect computation:
+        1. It ignored the scrollBehaviorForFixedElements() which we use to avoid rubber-banding fixed
+           elements in WK2, but allow in WK1, so make use of that.
+        2. Sometimes layouts/paints of fixed elements would be triggered when coalesced calls to
+           AsyncScrollingCoordinator::scheduleUpdateScrollPositionAfterAsyncScroll() failed to
+           copy the layoutViewportOrigin to the scheduled update.
+        3. The layout viewport could be left with a negative top/left after rubber-banding.
+        
+        Also add a way to do unconstrained scrollTo(), so that a test can call window.scrollTo(-10, -10) to
+        simulate rubberbanding.
+
+        Tests: fast/visual-viewport/rubberbanding-viewport-rects-header-footer.html
+               fast/visual-viewport/rubberbanding-viewport-rects.html
+
+        * page/FrameView.cpp:
+        (WebCore::FrameView::computeLayoutViewportOrigin): Handle ScrollBehaviorForFixedElements, incorporating it
+        into logic that clamps layoutViewportOrigin between min/max when rubberbanding is not allowed, or not in progress.
+        (WebCore::FrameView::updateLayoutViewport): Pass in scrollBehaviorForFixedElements().
+        (WebCore::FrameView::visibleDocumentRect): The clamping here was preventing the visible rect from
+        escaping the document bounds, which caused fixed elements to bounce with rubber-banding, so remove the clamping,
+        and fix the logic to allow rubber-banding while taking headers and footers into account.
+        * page/FrameView.h:
+        * page/scrolling/AsyncScrollingCoordinator.cpp:
+        (WebCore::AsyncScrollingCoordinator::scheduleUpdateScrollPositionAfterAsyncScroll): layoutViewportOrigin has to
+        be pushed onto the scheduled update, just like scroll position.
+        * page/scrolling/ScrollingTreeFrameScrollingNode.cpp:
+        (WebCore::ScrollingTreeFrameScrollingNode::layoutViewportForScrollPosition): Pass in m_behaviorForFixed.
+        * platform/ScrollView.cpp:
+        (WebCore::ScrollView::ScrollView):
+        (WebCore::ScrollView::adjustScrollPositionWithinRange):
+        (WebCore::ScrollView::setScrollOffset):
+        * platform/ScrollView.h:
+        (WebCore::ScrollView::setAllowsUnclampedScrollPositionForTesting):
+        (WebCore::ScrollView::allowsUnclampedScrollPosition):
+        * testing/InternalSettings.cpp:
+        (WebCore::InternalSettings::setAllowUnclampedScrollPosition):
+        * testing/InternalSettings.h:
+        * testing/InternalSettings.idl:
+
</ins><span class="cx"> 2017-01-30  Wenson Hsieh  &lt;wenson_hsieh@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Web content process crashes when initiating a drag on a very large image
</span></span></pre></div>
<a id="trunkSourceWebCorepageFrameViewcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/FrameView.cpp (211378 => 211379)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/FrameView.cpp        2017-01-30 19:40:48 UTC (rev 211378)
+++ trunk/Source/WebCore/page/FrameView.cpp        2017-01-30 19:46:40 UTC (rev 211379)
</span><span class="lines">@@ -1806,28 +1806,47 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> // visualViewport and layoutViewport are both in content coordinates (unzoomed).
</span><del>-LayoutPoint FrameView::computeLayoutViewportOrigin(const LayoutRect&amp; visualViewport, const LayoutPoint&amp; stableLayoutViewportOriginMin, const LayoutPoint&amp; stableLayoutViewportOriginMax, const LayoutRect&amp; layoutViewport)
</del><ins>+LayoutPoint FrameView::computeLayoutViewportOrigin(const LayoutRect&amp; visualViewport, const LayoutPoint&amp; stableLayoutViewportOriginMin, const LayoutPoint&amp; stableLayoutViewportOriginMax, const LayoutRect&amp; layoutViewport, ScrollBehaviorForFixedElements fixedBehavior)
</ins><span class="cx"> {
</span><span class="cx">     LayoutPoint layoutViewportOrigin = layoutViewport.location();
</span><ins>+    bool allowRubberBanding = fixedBehavior == StickToViewportBounds;
</ins><span class="cx"> 
</span><span class="cx">     if (visualViewport.width() &gt; layoutViewport.width())
</span><span class="cx">         layoutViewportOrigin.setX(visualViewport.x());
</span><span class="cx">     else {
</span><del>-        if (visualViewport.x() &lt; layoutViewport.x() || visualViewport.x() &lt; stableLayoutViewportOriginMin.x())
</del><ins>+        bool rubberbandingAtLeft = allowRubberBanding &amp;&amp; visualViewport.x() &lt; stableLayoutViewportOriginMin.x();
+        bool rubberbandingAtRight = allowRubberBanding &amp;&amp; (visualViewport.maxX() - layoutViewport.width()) &gt; stableLayoutViewportOriginMax.x();
+
+        if (visualViewport.x() &lt; layoutViewport.x() || rubberbandingAtLeft)
</ins><span class="cx">             layoutViewportOrigin.setX(visualViewport.x());
</span><span class="cx"> 
</span><del>-        if (visualViewport.maxX() &gt; layoutViewport.maxX() || (visualViewport.maxX() - layoutViewport.width()) &gt; stableLayoutViewportOriginMax.x())
</del><ins>+        if (visualViewport.maxX() &gt; layoutViewport.maxX() || rubberbandingAtRight)
</ins><span class="cx">             layoutViewportOrigin.setX(visualViewport.maxX() - layoutViewport.width());
</span><ins>+        
+        if (!rubberbandingAtLeft &amp;&amp; layoutViewportOrigin.x() &lt; stableLayoutViewportOriginMin.x())
+            layoutViewportOrigin.setX(stableLayoutViewportOriginMin.x());
+        
+        if (!rubberbandingAtRight &amp;&amp; layoutViewportOrigin.x() &gt; stableLayoutViewportOriginMax.x())
+            layoutViewportOrigin.setX(stableLayoutViewportOriginMax.x());
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (visualViewport.height() &gt; layoutViewport.height())
</span><span class="cx">         layoutViewportOrigin.setY(visualViewport.y());
</span><span class="cx">     else {
</span><del>-        if (visualViewport.y() &lt; layoutViewport.y() || visualViewport.y() &lt; stableLayoutViewportOriginMin.y())
</del><ins>+        bool rubberbandingAtTop = allowRubberBanding &amp;&amp; visualViewport.y() &lt; stableLayoutViewportOriginMin.y();
+        bool rubberbandingAtBottom = allowRubberBanding &amp;&amp; (visualViewport.maxY() - layoutViewport.height()) &gt; stableLayoutViewportOriginMax.y();
+
+        if (visualViewport.y() &lt; layoutViewport.y() || rubberbandingAtTop)
</ins><span class="cx">             layoutViewportOrigin.setY(visualViewport.y());
</span><span class="cx"> 
</span><del>-        if (visualViewport.maxY() &gt; layoutViewport.maxY() || (visualViewport.maxY() - layoutViewport.height()) &gt; stableLayoutViewportOriginMax.y())
</del><ins>+        if (visualViewport.maxY() &gt; layoutViewport.maxY() || rubberbandingAtBottom)
</ins><span class="cx">             layoutViewportOrigin.setY(visualViewport.maxY() - layoutViewport.height());
</span><ins>+        
+        if (!rubberbandingAtTop &amp;&amp; layoutViewportOrigin.y() &lt; stableLayoutViewportOriginMin.y())
+            layoutViewportOrigin.setY(stableLayoutViewportOriginMin.y());
+        
+        if (!rubberbandingAtBottom &amp;&amp; layoutViewportOrigin.y() &gt; stableLayoutViewportOriginMax.y())
+            layoutViewportOrigin.setY(stableLayoutViewportOriginMax.y());
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     return layoutViewportOrigin;
</span><span class="lines">@@ -1892,7 +1911,7 @@
</span><span class="cx">     LOG_WITH_STREAM(Scrolling, stream &lt;&lt; &quot;visualViewport: &quot; &lt;&lt; visualViewportRect());
</span><span class="cx">     LOG_WITH_STREAM(Scrolling, stream &lt;&lt; &quot;scroll positions: min: &quot; &lt;&lt; unscaledMinimumScrollPosition() &lt;&lt; &quot; max: &quot;&lt;&lt; unscaledMaximumScrollPosition());
</span><span class="cx"> 
</span><del>-    LayoutPoint newLayoutViewportOrigin = computeLayoutViewportOrigin(visualViewportRect(), minStableLayoutViewportOrigin(), maxStableLayoutViewportOrigin(), layoutViewport);
</del><ins>+    LayoutPoint newLayoutViewportOrigin = computeLayoutViewportOrigin(visualViewportRect(), minStableLayoutViewportOrigin(), maxStableLayoutViewportOrigin(), layoutViewport, scrollBehaviorForFixedElements());
</ins><span class="cx">     if (newLayoutViewportOrigin != m_layoutViewportOrigin) {
</span><span class="cx">         setBaseLayoutViewportOrigin(newLayoutViewportOrigin);
</span><span class="cx">         LOG_WITH_STREAM(Scrolling, stream &lt;&lt; &quot;layoutViewport changed to &quot; &lt;&lt; layoutViewportRect());
</span><span class="lines">@@ -1934,16 +1953,19 @@
</span><span class="cx"> // On iOS, pageScaleFactor is always 1 here, and we never have headers and footers.
</span><span class="cx"> LayoutRect FrameView::visibleDocumentRect(const FloatRect&amp; visibleContentRect, float headerHeight, float footerHeight, const FloatSize&amp; totalContentsSize, float pageScaleFactor)
</span><span class="cx"> {
</span><del>-    FloatRect visibleDocumentRect = visibleContentRect;
-
</del><span class="cx">     float contentsHeight = totalContentsSize.height() - headerHeight - footerHeight;
</span><span class="cx"> 
</span><del>-    float visibleScaledDocumentTop = std::max&lt;float&gt;(visibleContentRect.y() - headerHeight, 0);
-    float visibleScaledDocumentBottom = std::min&lt;float&gt;(visibleContentRect.maxY() - headerHeight, contentsHeight);
</del><ins>+    float rubberBandTop = std::min&lt;float&gt;(visibleContentRect.y(), 0);
+    float visibleScaledDocumentTop = std::max&lt;float&gt;(visibleContentRect.y() - headerHeight, 0) + rubberBandTop;
+    
+    float rubberBandBottom = std::min&lt;float&gt;((totalContentsSize.height() - visibleContentRect.y()) - visibleContentRect.height(), 0);
+    float visibleScaledDocumentBottom = std::min&lt;float&gt;(visibleContentRect.maxY() - headerHeight, contentsHeight) + rubberBandBottom;
</ins><span class="cx"> 
</span><ins>+    FloatRect visibleDocumentRect = visibleContentRect;
</ins><span class="cx">     visibleDocumentRect.setY(visibleScaledDocumentTop);
</span><span class="cx">     visibleDocumentRect.setHeight(std::max&lt;float&gt;(visibleScaledDocumentBottom - visibleScaledDocumentTop, 0));
</span><span class="cx">     visibleDocumentRect.scale(1 / pageScaleFactor);
</span><ins>+    
</ins><span class="cx">     return LayoutRect(visibleDocumentRect);
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCorepageFrameViewh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/FrameView.h (211378 => 211379)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/FrameView.h        2017-01-30 19:40:48 UTC (rev 211378)
+++ trunk/Source/WebCore/page/FrameView.h        2017-01-30 19:46:40 UTC (rev 211379)
</span><span class="lines">@@ -304,7 +304,7 @@
</span><span class="cx">     // Static function can be called from another thread.
</span><span class="cx">     static LayoutPoint scrollPositionForFixedPosition(const LayoutRect&amp; visibleContentRect, const LayoutSize&amp; totalContentsSize, const LayoutPoint&amp; scrollPosition, const LayoutPoint&amp; scrollOrigin, float frameScaleFactor, bool fixedElementsLayoutRelativeToFrame, ScrollBehaviorForFixedElements, int headerHeight, int footerHeight);
</span><span class="cx"> 
</span><del>-    WEBCORE_EXPORT static LayoutPoint computeLayoutViewportOrigin(const LayoutRect&amp; visualViewport, const LayoutPoint&amp; stableLayoutViewportOriginMin, const LayoutPoint&amp; stableLayoutViewportOriginMax, const LayoutRect&amp; layoutViewport);
</del><ins>+    WEBCORE_EXPORT static LayoutPoint computeLayoutViewportOrigin(const LayoutRect&amp; visualViewport, const LayoutPoint&amp; stableLayoutViewportOriginMin, const LayoutPoint&amp; stableLayoutViewportOriginMax, const LayoutRect&amp; layoutViewport, ScrollBehaviorForFixedElements fixedBehavior);
</ins><span class="cx"> 
</span><span class="cx">     // These layers are positioned differently when there is a topContentInset, a header, or a footer. These value need to be computed
</span><span class="cx">     // on both the main thread and the scrolling thread.
</span></span></pre></div>
<a id="trunkSourceWebCorepagescrollingAsyncScrollingCoordinatorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.cpp (211378 => 211379)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.cpp        2017-01-30 19:40:48 UTC (rev 211378)
+++ trunk/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.cpp        2017-01-30 19:46:40 UTC (rev 211379)
</span><span class="lines">@@ -269,6 +269,7 @@
</span><span class="cx">     if (m_updateNodeScrollPositionTimer.isActive()) {
</span><span class="cx">         if (m_scheduledScrollUpdate.matchesUpdateType(scrollUpdate)) {
</span><span class="cx">             m_scheduledScrollUpdate.scrollPosition = scrollPosition;
</span><ins>+            m_scheduledScrollUpdate.layoutViewportOrigin = layoutViewportOrigin;
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceWebCorepagescrollingScrollingTreeFrameScrollingNodecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/scrolling/ScrollingTreeFrameScrollingNode.cpp (211378 => 211379)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/scrolling/ScrollingTreeFrameScrollingNode.cpp        2017-01-30 19:40:48 UTC (rev 211378)
+++ trunk/Source/WebCore/page/scrolling/ScrollingTreeFrameScrollingNode.cpp        2017-01-30 19:46:40 UTC (rev 211379)
</span><span class="lines">@@ -111,7 +111,7 @@
</span><span class="cx">     LOG_WITH_STREAM(Scrolling, stream &lt;&lt; &quot;  visualViewport: &quot; &lt;&lt; visualViewport);
</span><span class="cx">     LOG_WITH_STREAM(Scrolling, stream &lt;&lt; &quot;  scroll positions: min: &quot; &lt;&lt; minLayoutViewportOrigin() &lt;&lt; &quot; max: &quot;&lt;&lt; maxLayoutViewportOrigin());
</span><span class="cx"> 
</span><del>-    LayoutPoint newLocation = FrameView::computeLayoutViewportOrigin(LayoutRect(visualViewport), LayoutPoint(minLayoutViewportOrigin()), LayoutPoint(maxLayoutViewportOrigin()), layoutViewport);
</del><ins>+    LayoutPoint newLocation = FrameView::computeLayoutViewportOrigin(LayoutRect(visualViewport), LayoutPoint(minLayoutViewportOrigin()), LayoutPoint(maxLayoutViewportOrigin()), layoutViewport, m_behaviorForFixed);
</ins><span class="cx"> 
</span><span class="cx">     if (layoutViewport.location() != newLocation) {
</span><span class="cx">         layoutViewport.setLocation(newLocation);
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformScrollViewcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/ScrollView.cpp (211378 => 211379)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/ScrollView.cpp        2017-01-30 19:40:48 UTC (rev 211378)
+++ trunk/Source/WebCore/platform/ScrollView.cpp        2017-01-30 19:46:40 UTC (rev 211379)
</span><span class="lines">@@ -41,20 +41,6 @@
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="cx"> ScrollView::ScrollView()
</span><del>-    : m_horizontalScrollbarMode(ScrollbarAuto)
-    , m_verticalScrollbarMode(ScrollbarAuto)
-    , m_horizontalScrollbarLock(false)
-    , m_verticalScrollbarLock(false)
-    , m_prohibitsScrolling(false)
-    , m_canBlitOnScroll(true)
-    , m_scrollbarsSuppressed(false)
-    , m_inUpdateScrollbars(false)
-    , m_updateScrollbarsPass(0)
-    , m_drawPanScrollIcon(false)
-    , m_useFixedLayout(false)
-    , m_paintsEntireContents(false)
-    , m_clipsRepaints(true)
-    , m_delegatesScrolling(false)
</del><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -381,7 +367,7 @@
</span><span class="cx"> 
</span><span class="cx"> ScrollPosition ScrollView::adjustScrollPositionWithinRange(const ScrollPosition&amp; scrollPoint) const
</span><span class="cx"> {
</span><del>-    if (!constrainsScrollingToContentEdge())
</del><ins>+    if (!constrainsScrollingToContentEdge() || m_allowsUnclampedScrollPosition)
</ins><span class="cx">         return scrollPoint;
</span><span class="cx"> 
</span><span class="cx">     return scrollPoint.constrainedBetween(minimumScrollPosition(), maximumScrollPosition());
</span><span class="lines">@@ -418,7 +404,7 @@
</span><span class="cx"> 
</span><span class="cx"> void ScrollView::setScrollOffset(const ScrollOffset&amp; offset)
</span><span class="cx"> {
</span><del>-    LOG_WITH_STREAM(Scrolling, stream &lt;&lt; &quot;\nScrollView::setScrollOffset &quot; &lt;&lt; offset);
</del><ins>+    LOG_WITH_STREAM(Scrolling, stream &lt;&lt; &quot;\nScrollView::setScrollOffset &quot; &lt;&lt; offset &lt;&lt; &quot; constrains &quot; &lt;&lt; constrainsScrollingToContentEdge());
</ins><span class="cx"> 
</span><span class="cx">     IntPoint constrainedOffset = offset;
</span><span class="cx">     if (constrainsScrollingToContentEdge())
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformScrollViewh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/ScrollView.h (211378 => 211379)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/ScrollView.h        2017-01-30 19:40:48 UTC (rev 211378)
+++ trunk/Source/WebCore/platform/ScrollView.h        2017-01-30 19:46:40 UTC (rev 211379)
</span><span class="lines">@@ -373,6 +373,9 @@
</span><span class="cx"> 
</span><span class="cx">     WEBCORE_EXPORT void scrollOffsetChangedViaPlatformWidget(const ScrollOffset&amp; oldOffset, const ScrollOffset&amp; newOffset);
</span><span class="cx"> 
</span><ins>+    void setAllowsUnclampedScrollPositionForTesting(bool allowsUnclampedScrollPosition) { m_allowsUnclampedScrollPosition = allowsUnclampedScrollPosition; }
+    bool allowsUnclampedScrollPosition() const { return m_allowsUnclampedScrollPosition; }
+
</ins><span class="cx"> protected:
</span><span class="cx">     ScrollView();
</span><span class="cx"> 
</span><span class="lines">@@ -433,22 +436,13 @@
</span><span class="cx"> 
</span><span class="cx">     bool isScrollView() const final { return true; }
</span><span class="cx"> 
</span><ins>+    HashSet&lt;Ref&lt;Widget&gt;&gt; m_children;
+
</ins><span class="cx">     RefPtr&lt;Scrollbar&gt; m_horizontalScrollbar;
</span><span class="cx">     RefPtr&lt;Scrollbar&gt; m_verticalScrollbar;
</span><del>-    ScrollbarMode m_horizontalScrollbarMode;
-    ScrollbarMode m_verticalScrollbarMode;
</del><ins>+    ScrollbarMode m_horizontalScrollbarMode { ScrollbarAuto };
+    ScrollbarMode m_verticalScrollbarMode { ScrollbarAuto };
</ins><span class="cx"> 
</span><del>-    bool m_horizontalScrollbarLock;
-    bool m_verticalScrollbarLock;
-
-    bool m_prohibitsScrolling;
-
-    HashSet&lt;Ref&lt;Widget&gt;&gt; m_children;
-
-    // This bool is unused on Mac OS because we directly ask the platform widget
-    // whether it is safe to blit on scroll.
-    bool m_canBlitOnScroll;
-
</del><span class="cx"> #if PLATFORM(IOS)
</span><span class="cx">     // FIXME: exposedContentRect is a very similar concept to fixedVisibleContentRect except it does not differentiate
</span><span class="cx">     // between exposed and unobscured areas. The two attributes should eventually be merged.
</span><span class="lines">@@ -466,19 +460,31 @@
</span><span class="cx">     std::optional&lt;IntSize&gt; m_deferredScrollDelta; // Needed for WebKit scrolling
</span><span class="cx">     std::optional&lt;std::pair&lt;ScrollOffset, ScrollOffset&gt;&gt; m_deferredScrollOffsets; // Needed for platform widget scrolling
</span><span class="cx"> 
</span><del>-    bool m_scrollbarsSuppressed;
</del><ins>+    IntPoint m_panScrollIconPoint;
</ins><span class="cx"> 
</span><del>-    bool m_inUpdateScrollbars;
-    unsigned m_updateScrollbarsPass;
</del><ins>+    bool m_horizontalScrollbarLock { false };
+    bool m_verticalScrollbarLock { false };
</ins><span class="cx"> 
</span><del>-    IntPoint m_panScrollIconPoint;
-    bool m_drawPanScrollIcon;
-    bool m_useFixedLayout;
</del><ins>+    bool m_prohibitsScrolling { false };
+    bool m_allowsUnclampedScrollPosition { false };
</ins><span class="cx"> 
</span><del>-    bool m_paintsEntireContents;
-    bool m_clipsRepaints;
-    bool m_delegatesScrolling;
</del><ins>+    // This bool is unused on Mac OS because we directly ask the platform widget
+    // whether it is safe to blit on scroll.
+    bool m_canBlitOnScroll { true };
</ins><span class="cx"> 
</span><ins>+    bool m_scrollbarsSuppressed { false };
+
+    bool m_inUpdateScrollbars { false };
+    unsigned m_updateScrollbarsPass { 0 };
+
+    bool m_drawPanScrollIcon { false };
+    bool m_useFixedLayout { false };
+
+    bool m_paintsEntireContents { false };
+    bool m_clipsRepaints { true };
+    bool m_delegatesScrolling { false };
+
+
</ins><span class="cx">     void init();
</span><span class="cx">     void destroy();
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoretestingInternalSettingscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/testing/InternalSettings.cpp (211378 => 211379)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/testing/InternalSettings.cpp        2017-01-30 19:40:48 UTC (rev 211378)
+++ trunk/Source/WebCore/testing/InternalSettings.cpp        2017-01-30 19:46:40 UTC (rev 211379)
</span><span class="lines">@@ -640,6 +640,15 @@
</span><span class="cx">     return { };
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+ExceptionOr&lt;void&gt; InternalSettings::setAllowUnclampedScrollPosition(bool allowUnclamped)
+{
+    if (!m_page || !m_page-&gt;mainFrame().view())
+        return Exception { INVALID_ACCESS_ERR };
+
+    m_page-&gt;mainFrame().view()-&gt;setAllowsUnclampedScrollPositionForTesting(allowUnclamped);
+    return { };
+}
+
</ins><span class="cx"> ExceptionOr&lt;void&gt; InternalSettings::setAllowsInlineMediaPlayback(bool allows)
</span><span class="cx"> {
</span><span class="cx">     if (!m_page)
</span></span></pre></div>
<a id="trunkSourceWebCoretestingInternalSettingsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/testing/InternalSettings.h (211378 => 211379)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/testing/InternalSettings.h        2017-01-30 19:40:48 UTC (rev 211378)
+++ trunk/Source/WebCore/testing/InternalSettings.h        2017-01-30 19:46:40 UTC (rev 211379)
</span><span class="lines">@@ -87,6 +87,7 @@
</span><span class="cx">     ExceptionOr&lt;void&gt; setBackgroundShouldExtendBeyondPage(bool);
</span><span class="cx">     ExceptionOr&lt;void&gt; setShouldConvertPositionStyleOnCopy(bool);
</span><span class="cx">     ExceptionOr&lt;void&gt; setScrollingTreeIncludesFrames(bool);
</span><ins>+    ExceptionOr&lt;void&gt; setAllowUnclampedScrollPosition(bool);
</ins><span class="cx">     ExceptionOr&lt;void&gt; setAllowsInlineMediaPlayback(bool);
</span><span class="cx">     ExceptionOr&lt;void&gt; setAllowsInlineMediaPlaybackAfterFullscreen(bool);
</span><span class="cx">     ExceptionOr&lt;void&gt; setInlineMediaPlaybackRequiresPlaysInlineAttribute(bool);
</span></span></pre></div>
<a id="trunkSourceWebCoretestingInternalSettingsidl"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/testing/InternalSettings.idl (211378 => 211379)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/testing/InternalSettings.idl        2017-01-30 19:40:48 UTC (rev 211378)
+++ trunk/Source/WebCore/testing/InternalSettings.idl        2017-01-30 19:46:40 UTC (rev 211379)
</span><span class="lines">@@ -75,6 +75,7 @@
</span><span class="cx">     [MayThrowException] void setAutoscrollForDragAndDropEnabled(boolean enabled);
</span><span class="cx">     [MayThrowException] void setBackgroundShouldExtendBeyondPage(boolean hasExtendedBackground);
</span><span class="cx">     [MayThrowException] void setScrollingTreeIncludesFrames(boolean enabled);
</span><ins>+    [MayThrowException] void setAllowUnclampedScrollPosition(boolean allowUnclamped);
</ins><span class="cx"> 
</span><span class="cx">     [MayThrowException] void setMinimumTimerInterval(unrestricted double intervalInSeconds);
</span><span class="cx">     [MayThrowException] void setAllowsInlineMediaPlayback(boolean allows);
</span></span></pre></div>
<a id="trunkSourceWebKit2ChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/ChangeLog (211378 => 211379)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/ChangeLog        2017-01-30 19:40:48 UTC (rev 211378)
+++ trunk/Source/WebKit2/ChangeLog        2017-01-30 19:46:40 UTC (rev 211379)
</span><span class="lines">@@ -1,3 +1,16 @@
</span><ins>+2017-01-30  Simon Fraser  &lt;simon.fraser@apple.com&gt;
+
+        Fixed elements should not rubber-band in WK2, nor remain at negative offsets
+        https://bugs.webkit.org/show_bug.cgi?id=167484
+        rdar://problem/29453068
+
+        Reviewed by Dean Jackson.
+
+        Pass in StickToViewportBounds as we did before visual viewports.
+
+        * UIProcess/ios/WebPageProxyIOS.mm:
+        (WebKit::WebPageProxy::computeCustomFixedPositionRect):
+
</ins><span class="cx"> 2017-01-30  Chris Dumez  &lt;cdumez@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Update DiagnosticLoggingClient::logDiagnosticMessageWithValue() to take in the value as a double
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessiosWebPageProxyIOSmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/ios/WebPageProxyIOS.mm (211378 => 211379)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/ios/WebPageProxyIOS.mm        2017-01-30 19:40:48 UTC (rev 211378)
+++ trunk/Source/WebKit2/UIProcess/ios/WebPageProxyIOS.mm        2017-01-30 19:46:40 UTC (rev 211379)
</span><span class="lines">@@ -268,9 +268,9 @@
</span><span class="cx"> 
</span><span class="cx">     LayoutPoint layoutViewportOrigin;
</span><span class="cx">     if (isBelowMinimumScale)
</span><del>-        layoutViewportOrigin = FrameView::computeLayoutViewportOrigin(enclosingLayoutRect(constrainedUnobscuredRect), m_minStableLayoutViewportOrigin, m_maxStableLayoutViewportOrigin, enclosingLayoutRect(layoutViewportRect));
</del><ins>+        layoutViewportOrigin = FrameView::computeLayoutViewportOrigin(enclosingLayoutRect(constrainedUnobscuredRect), m_minStableLayoutViewportOrigin, m_maxStableLayoutViewportOrigin, enclosingLayoutRect(layoutViewportRect), StickToViewportBounds);
</ins><span class="cx">     else
</span><del>-        layoutViewportOrigin = FrameView::computeLayoutViewportOrigin(enclosingLayoutRect(unobscuredContentRectRespectingInputViewBounds), m_minStableLayoutViewportOrigin, m_maxStableLayoutViewportOrigin, enclosingLayoutRect(layoutViewportRect));
</del><ins>+        layoutViewportOrigin = FrameView::computeLayoutViewportOrigin(enclosingLayoutRect(unobscuredContentRectRespectingInputViewBounds), m_minStableLayoutViewportOrigin, m_maxStableLayoutViewportOrigin, enclosingLayoutRect(layoutViewportRect), StickToViewportBounds);
</ins><span class="cx"> 
</span><span class="cx">     if (constraint == UnobscuredRectConstraint::ConstrainedToDocumentRect) {
</span><span class="cx">         // The max stable layout viewport origin really depends on the size of the layout viewport itself, so we need to adjust the location of the layout viewport one final time to make sure it does not end up out of bounds of the document.
</span></span></pre>
</div>
</div>

</body>
</html>