<!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>[202147] 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/202147">202147</a></dd>
<dt>Author</dt> <dd>simon.fraser@apple.com</dd>
<dt>Date</dt> <dd>2016-06-16 16:34:17 -0700 (Thu, 16 Jun 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>Source/WebCore:
[iOS] Focus event dispatched in iframe causes parent document to scroll incorrectly
https://bugs.webkit.org/show_bug.cgi?id=158629
rdar://problem/26521616

Reviewed by Enrica Casucci.

When focussing elements in iframes, the page could scroll to an incorrect location.
This happened because code in Element::focus() tried to disable scrolling on focus,
but did so only for the current frame, so ancestor frames got programmatically scrolled.
On iOS we handle the scrolling in the UI process, so never want the web process to
do programmatic scrolling.

Fix by changing the focus and cache restore code to use SelectionRevealMode::DoNotReveal,
rather than manually prohibiting frame scrolling.

Tests: fast/forms/ios/focus-input-in-iframe.html
       fast/forms/ios/programmatic-focus-input-in-iframe.html

* dom/Element.cpp:
(WebCore::Element::focus):
* history/CachedPage.cpp:
(WebCore::CachedPage::restore):

LayoutTests:
Focus event dispatched in iframe causes parent document to scroll incorrectly
https://bugs.webkit.org/show_bug.cgi?id=158629
rdar://problem/26521616

Reviewed by Enrica Casucci.

Tests for user-initiated and programmatic focus in frames.

* fast/forms/ios/focus-input-in-iframe-expected.txt: Added.
* fast/forms/ios/focus-input-in-iframe.html: Added.
* fast/forms/ios/programmatic-focus-input-in-iframe.html: Added.
* fast/forms/ios/programmatic-focus-input-in-iframe-expected.txt: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoredomElementcpp">trunk/Source/WebCore/dom/Element.cpp</a></li>
<li><a href="#trunkSourceWebCorehistoryCachedPagecpp">trunk/Source/WebCore/history/CachedPage.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsfastformsiosfocusinputiniframeexpectedtxt">trunk/LayoutTests/fast/forms/ios/focus-input-in-iframe-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastformsiosfocusinputiniframehtml">trunk/LayoutTests/fast/forms/ios/focus-input-in-iframe.html</a></li>
<li><a href="#trunkLayoutTestsfastformsiosprogrammaticfocusinputiniframeexpectedtxt">trunk/LayoutTests/fast/forms/ios/programmatic-focus-input-in-iframe-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastformsiosprogrammaticfocusinputiniframehtml">trunk/LayoutTests/fast/forms/ios/programmatic-focus-input-in-iframe.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (202146 => 202147)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2016-06-16 23:27:46 UTC (rev 202146)
+++ trunk/LayoutTests/ChangeLog        2016-06-16 23:34:17 UTC (rev 202147)
</span><span class="lines">@@ -1,3 +1,18 @@
</span><ins>+2016-06-16  Simon Fraser  &lt;simon.fraser@apple.com&gt;
+
+        Focus event dispatched in iframe causes parent document to scroll incorrectly
+        https://bugs.webkit.org/show_bug.cgi?id=158629
+        rdar://problem/26521616
+
+        Reviewed by Enrica Casucci.
+        
+        Tests for user-initiated and programmatic focus in frames.
+
+        * fast/forms/ios/focus-input-in-iframe-expected.txt: Added.
+        * fast/forms/ios/focus-input-in-iframe.html: Added.
+        * fast/forms/ios/programmatic-focus-input-in-iframe.html: Added.
+        * fast/forms/ios/programmatic-focus-input-in-iframe-expected.txt: Added.
+
</ins><span class="cx"> 2016-06-16  Zalan Bujtas  &lt;zalan@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [New Block-Inside-Inline Model] Do not attempt to re-run margin collapsing on the block sequence.
</span></span></pre></div>
<a id="trunkLayoutTestsfastformsiosfocusinputiniframeexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/forms/ios/focus-input-in-iframe-expected.txt (0 => 202147)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/forms/ios/focus-input-in-iframe-expected.txt                                (rev 0)
+++ trunk/LayoutTests/fast/forms/ios/focus-input-in-iframe-expected.txt        2016-06-16 23:34:17 UTC (rev 202147)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+Tests zooming into a text input on tap.
+
+Click to focus input
+
+tap location        { x: 20.000, y: 62.000 }
+scale        1.455
+visibleRect        { left: 0.000, top: 1201.976, width: 219.979, height: 329.968 }
</ins></span></pre></div>
<a id="trunkLayoutTestsfastformsiosfocusinputiniframehtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/forms/ios/focus-input-in-iframe.html (0 => 202147)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/forms/ios/focus-input-in-iframe.html                                (rev 0)
+++ trunk/LayoutTests/fast/forms/ios/focus-input-in-iframe.html        2016-06-16 23:34:17 UTC (rev 202147)
</span><span class="lines">@@ -0,0 +1,48 @@
</span><ins>+&lt;!DOCTYPE html&gt; &lt;!-- webkit-test-runner [ useFlexibleViewport=true ] --&gt;
+
+&lt;html&gt;
+&lt;head&gt;
+    &lt;meta name=&quot;viewport&quot; content=&quot;initial-scale=0.5&quot;&gt;
+    &lt;style&gt;
+        button {
+            display: block;
+        }
+        iframe {
+            margin-top: 800px;
+        }
+    &lt;/style&gt;
+    
+    &lt;script src=&quot;resources/zooming-test-utils.js&quot;&gt;&lt;/script&gt;
+    &lt;script&gt;
+    if (window.testRunner) {
+        testRunner.dumpAsText();
+        testRunner.waitUntilDone();
+    }
+
+    if (window.internals)
+        internals.settings.setFrameFlatteningEnabled(true);
+    
+    function buttonClicked()
+    {
+        document.getElementById('frame').contentDocument.getElementById('input').focus();
+    }
+
+    function doTest()
+    {
+        testZoomAfterTap(document.getElementById('target'), 10, 10);
+    }
+
+    window.addEventListener('load', doTest, false);
+    &lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+
+&lt;p&gt;Tests zooming into a text input on tap.&lt;/p&gt;
+&lt;button id=&quot;target&quot; onclick=&quot;buttonClicked()&quot;&gt;Click to focus input&lt;/button&gt;
+
+&lt;iframe id=&quot;frame&quot; srcdoc=&quot;&lt;style&gt;input { margin: 400px 20px; }&lt;/style&gt;
+&lt;input id='input' type='text'&gt;
+&quot;&gt;&lt;/iframe&gt;
+
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsfastformsiosprogrammaticfocusinputiniframeexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/forms/ios/programmatic-focus-input-in-iframe-expected.txt (0 => 202147)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/forms/ios/programmatic-focus-input-in-iframe-expected.txt                                (rev 0)
+++ trunk/LayoutTests/fast/forms/ios/programmatic-focus-input-in-iframe-expected.txt        2016-06-16 23:34:17 UTC (rev 202147)
</span><span class="lines">@@ -0,0 +1,4 @@
</span><ins>+Tests that a programmatic focus should not scroll into view
+
+PASS: page did not scroll.
+
</ins></span></pre></div>
<a id="trunkLayoutTestsfastformsiosprogrammaticfocusinputiniframehtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/forms/ios/programmatic-focus-input-in-iframe.html (0 => 202147)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/forms/ios/programmatic-focus-input-in-iframe.html                                (rev 0)
+++ trunk/LayoutTests/fast/forms/ios/programmatic-focus-input-in-iframe.html        2016-06-16 23:34:17 UTC (rev 202147)
</span><span class="lines">@@ -0,0 +1,57 @@
</span><ins>+&lt;!DOCTYPE html&gt; &lt;!-- webkit-test-runner [ useFlexibleViewport=true ] --&gt;
+
+&lt;html&gt;
+&lt;head&gt;
+    &lt;meta name=&quot;viewport&quot; content=&quot;initial-scale=0.5&quot;&gt;
+    &lt;style&gt;
+        button {
+            display: block;
+        }
+        iframe {
+            margin-top: 800px;
+        }
+    &lt;/style&gt;
+    
+    &lt;script&gt;
+    if (window.testRunner) {
+        testRunner.dumpAsText();
+        testRunner.waitUntilDone();
+    }
+    
+    if (window.internals)
+        internals.settings.setFrameFlatteningEnabled(true);
+    
+    function pageDidScroll()
+    {
+        document.getElementById('result').textContent = 'FAIL: page scrolled to ' + document.scrollingElement.scrollTop;
+    }
+
+    function doTest()
+    {
+        window.setTimeout(function() {
+            document.getElementById('frame').contentDocument.getElementById('input').focus();
+        }, 0);
+
+        // Wait for any scroll to happen.
+        window.setTimeout(function() {
+            if (window.testRunner)
+                testRunner.notifyDone();
+        }, 100);
+    }
+
+    window.addEventListener('load', doTest, false);
+    &lt;/script&gt;
+&lt;/head&gt;
+&lt;body onscroll=&quot;pageDidScroll()&quot;&gt;
+
+&lt;p&gt;Tests that a programmatic focus should not scroll into view&lt;/p&gt;
+&lt;div id=&quot;result&quot;&gt;
+    PASS: page did not scroll.
+&lt;/div&gt;
+
+&lt;iframe id=&quot;frame&quot; srcdoc=&quot;&lt;style&gt;input { margin: 400px 20px; }&lt;/style&gt;
+&lt;input id='input' type='text'&gt;
+&quot;&gt;&lt;/iframe&gt;
+
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (202146 => 202147)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2016-06-16 23:27:46 UTC (rev 202146)
+++ trunk/Source/WebCore/ChangeLog        2016-06-16 23:34:17 UTC (rev 202147)
</span><span class="lines">@@ -1,3 +1,28 @@
</span><ins>+2016-06-16  Simon Fraser  &lt;simon.fraser@apple.com&gt;
+
+        [iOS] Focus event dispatched in iframe causes parent document to scroll incorrectly
+        https://bugs.webkit.org/show_bug.cgi?id=158629
+        rdar://problem/26521616
+
+        Reviewed by Enrica Casucci.
+
+        When focussing elements in iframes, the page could scroll to an incorrect location.
+        This happened because code in Element::focus() tried to disable scrolling on focus,
+        but did so only for the current frame, so ancestor frames got programmatically scrolled.
+        On iOS we handle the scrolling in the UI process, so never want the web process to
+        do programmatic scrolling.
+
+        Fix by changing the focus and cache restore code to use SelectionRevealMode::DoNotReveal,
+        rather than manually prohibiting frame scrolling.
+
+        Tests: fast/forms/ios/focus-input-in-iframe.html
+               fast/forms/ios/programmatic-focus-input-in-iframe.html
+
+        * dom/Element.cpp:
+        (WebCore::Element::focus):
+        * history/CachedPage.cpp:
+        (WebCore::CachedPage::restore):
+
</ins><span class="cx"> 2016-06-16  Zalan Bujtas  &lt;zalan@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [New Block-Inside-Inline Model] Do not attempt to re-run margin collapsing on the block sequence.
</span></span></pre></div>
<a id="trunkSourceWebCoredomElementcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/Element.cpp (202146 => 202147)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/Element.cpp        2016-06-16 23:27:46 UTC (rev 202146)
+++ trunk/Source/WebCore/dom/Element.cpp        2016-06-16 23:34:17 UTC (rev 202147)
</span><span class="lines">@@ -2245,6 +2245,8 @@
</span><span class="cx">     }
</span><span class="cx">         
</span><span class="cx">     cancelFocusAppearanceUpdate();
</span><ins>+
+    SelectionRevealMode revealMode = SelectionRevealMode::Reveal;
</ins><span class="cx"> #if PLATFORM(IOS)
</span><span class="cx">     // Focusing a form element triggers animation in UIKit to scroll to the right position.
</span><span class="cx">     // Calling updateFocusAppearance() would generate an unnecessary call to ScrollView::setScrollPosition(),
</span><span class="lines">@@ -2252,13 +2254,9 @@
</span><span class="cx">     FrameView* view = document().view();
</span><span class="cx">     bool isFormControl = view &amp;&amp; is&lt;HTMLFormControlElement&gt;(*this);
</span><span class="cx">     if (isFormControl)
</span><del>-        view-&gt;setProhibitsScrolling(true);
</del><ins>+        revealMode = SelectionRevealMode::DoNotReveal;
</ins><span class="cx"> #endif
</span><del>-    updateFocusAppearance(restorePreviousSelection ? SelectionRestorationMode::Restore : SelectionRestorationMode::SetDefault);
-#if PLATFORM(IOS)
-    if (isFormControl)
-        view-&gt;setProhibitsScrolling(false);
-#endif
</del><ins>+    updateFocusAppearance(restorePreviousSelection ? SelectionRestorationMode::Restore : SelectionRestorationMode::SetDefault, revealMode);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void Element::updateFocusAppearanceAfterAttachIfNeeded()
</span></span></pre></div>
<a id="trunkSourceWebCorehistoryCachedPagecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/history/CachedPage.cpp (202146 => 202147)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/history/CachedPage.cpp        2016-06-16 23:27:46 UTC (rev 202146)
+++ trunk/Source/WebCore/history/CachedPage.cpp        2016-06-16 23:34:17 UTC (rev 202147)
</span><span class="lines">@@ -77,25 +77,18 @@
</span><span class="cx">     m_cachedMainFrame-&gt;open();
</span><span class="cx">     
</span><span class="cx">     // Restore the focus appearance for the focused element.
</span><del>-    // FIXME: Right now we don't support pages w/ frames in the b/f cache.  This may need to be tweaked when we add support for that.
</del><ins>+    // FIXME: Right now we don't support pages with frames in the b/f cache. This may need to be tweaked when we add support for that.
</ins><span class="cx">     Document* focusedDocument = page.focusController().focusedOrMainFrame().document();
</span><span class="cx">     if (Element* element = focusedDocument-&gt;focusedElement()) {
</span><ins>+        SelectionRevealMode revealMode = SelectionRevealMode::Reveal;
</ins><span class="cx"> #if PLATFORM(IOS)
</span><span class="cx">         // We don't want focused nodes changing scroll position when restoring from the cache
</span><span class="cx">         // as it can cause ugly jumps before we manage to restore the cached position.
</span><span class="cx">         page.mainFrame().selection().suppressScrolling();
</span><del>-
-        bool hadProhibitsScrolling = false;
-        FrameView* frameView = page.mainFrame().view();
-        if (frameView) {
-            hadProhibitsScrolling = frameView-&gt;prohibitsScrolling();
-            frameView-&gt;setProhibitsScrolling(true);
-        }
</del><ins>+        revealMode = SelectionRevealMode::DoNotReveal;
</ins><span class="cx"> #endif
</span><del>-        element-&gt;updateFocusAppearance(SelectionRestorationMode::Restore);
</del><ins>+        element-&gt;updateFocusAppearance(SelectionRestorationMode::Restore, revealMode);
</ins><span class="cx"> #if PLATFORM(IOS)
</span><del>-        if (frameView)
-            frameView-&gt;setProhibitsScrolling(hadProhibitsScrolling);
</del><span class="cx">         page.mainFrame().selection().restoreScrolling();
</span><span class="cx"> #endif
</span><span class="cx">     }
</span></span></pre>
</div>
</div>

</body>
</html>