<!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>[187593] 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/187593">187593</a></dd>
<dt>Author</dt> <dd>simon.fraser@apple.com</dd>
<dt>Date</dt> <dd>2015-07-30 11:32:45 -0700 (Thu, 30 Jul 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Selecting in an iframe can cause main page scrolling
https://bugs.webkit.org/show_bug.cgi?id=147431
rdar://problem/19244589

Reviewed by Zalan Bujtas.

Source/WebCore:

The RenderLayer auatoscroll code walks up the RenderLayer hierarchy, crossing
frame boundaries. However, as it crosses into an ancestor frame it failed to
map the target rect into the coordinate space of the new frame, which caused
us to scroll to an incorrect location in that parent frame.

Test: fast/events/autoscroll-in-iframe.html

* rendering/RenderLayer.cpp:
(WebCore::parentLayerCrossFrame): Make the layer a reference, and pass in
an optional rect. When crossing frame boundaries, map the rect from the
contents of the child frame to the contents of the parent frame.
(WebCore::RenderLayer::enclosingScrollableLayer): Pass optional rect.
(WebCore::RenderLayer::scrollRectToVisible):
(WebCore::RenderLayer::hasScrollableOrRubberbandableAncestor):
* rendering/RenderLayer.h:

LayoutTests:

Test that uses eventSender to select in an iframe after scrolling the
main page.

* fast/events/autoscroll-in-iframe-expected.txt: Added.
* fast/events/autoscroll-in-iframe.html: 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="#trunkSourceWebCorerenderingRenderLayercpp">trunk/Source/WebCore/rendering/RenderLayer.cpp</a></li>
<li><a href="#trunkSourceWebCorerenderingRenderLayerh">trunk/Source/WebCore/rendering/RenderLayer.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsfasteventsautoscrolliniframeexpectedtxt">trunk/LayoutTests/fast/events/autoscroll-in-iframe-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfasteventsautoscrolliniframehtml">trunk/LayoutTests/fast/events/autoscroll-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 (187592 => 187593)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2015-07-30 18:31:01 UTC (rev 187592)
+++ trunk/LayoutTests/ChangeLog        2015-07-30 18:32:45 UTC (rev 187593)
</span><span class="lines">@@ -1,3 +1,17 @@
</span><ins>+2015-07-30  Simon Fraser  &lt;simon.fraser@apple.com&gt;
+
+        Selecting in an iframe can cause main page scrolling
+        https://bugs.webkit.org/show_bug.cgi?id=147431
+        rdar://problem/19244589
+
+        Reviewed by Zalan Bujtas.
+        
+        Test that uses eventSender to select in an iframe after scrolling the
+        main page.
+
+        * fast/events/autoscroll-in-iframe-expected.txt: Added.
+        * fast/events/autoscroll-in-iframe.html: Added.
+
</ins><span class="cx"> 2015-07-29  Matt Rajca  &lt;mrajca@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Media Session: test Next/Previous Track media control events delivered to Content media sessions
</span></span></pre></div>
<a id="trunkLayoutTestsfasteventsautoscrolliniframeexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/events/autoscroll-in-iframe-expected.txt (0 => 187593)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/events/autoscroll-in-iframe-expected.txt                                (rev 0)
+++ trunk/LayoutTests/fast/events/autoscroll-in-iframe-expected.txt        2015-07-30 18:32:45 UTC (rev 187593)
</span><span class="lines">@@ -0,0 +1,3 @@
</span><ins>+
+PASSED: selecting in the iframe did not scroll the page.
+
</ins></span></pre></div>
<a id="trunkLayoutTestsfasteventsautoscrolliniframehtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/events/autoscroll-in-iframe.html (0 => 187593)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/events/autoscroll-in-iframe.html                                (rev 0)
+++ trunk/LayoutTests/fast/events/autoscroll-in-iframe.html        2015-07-30 18:32:45 UTC (rev 187593)
</span><span class="lines">@@ -0,0 +1,89 @@
</span><ins>+&lt;html&gt;
+    &lt;head&gt;
+        &lt;style&gt;
+            body {
+                height: 2000px;
+            }
+            iframe {
+                position: absolute;
+                top: 800px;
+            }
+        &lt;/style&gt;
+        &lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+        &lt;script&gt;
+
+        if (window.testRunner) {
+            testRunner.waitUntilDone();
+            testRunner.dumpAsText();
+        }
+
+        function log(msg)
+        {
+            document.getElementById('console').appendChild(document.createTextNode(msg + '\n'));
+        }
+        
+        var verticalScrollOffset;
+        var iframe;
+        
+        function doTest()
+        {
+            document.scrollingElement.scrollTop = 800;
+            if (document.scrollingElement.scrollTop != 800)
+                log(&quot;FAILED: failed to scroll by 800px&quot;);
+
+            iframe = document.getElementById('targetFrame');
+
+            var textInIframe = iframe.contentDocument.getElementById('starthere');
+            var x = iframe.clientLeft + textInIframe.offsetLeft + 7;
+            var y = iframe.clientTop + textInIframe.offsetTop + 7;
+            if (window.eventSender) {
+                eventSender.dragMode = false;
+                eventSender.mouseMoveTo(x, y);
+                eventSender.mouseDown();
+                eventSender.mouseUp();
+            }
+            setTimeout(autoscrollTestPart1, 0);
+        }
+
+        function autoscrollTestPart1()
+        {
+            var mainDocumentTop = document.scrollingElement.scrollTop;
+            if (mainDocumentTop != 800)
+                log(&quot;FAILED: Clicking in the iframe scrolled the page (window.scrollTops is &quot; + mainDocumentTop + &quot;)&quot;);
+
+            if (window.eventSender) {
+                var textInIframe = iframe.contentDocument.getElementById('starthere');
+                var x = iframe.clientLeft + textInIframe.offsetLeft + 7;
+                var y = iframe.clientTop + textInIframe.offsetTop + 7;
+                eventSender.dragMode = false;
+                eventSender.mouseMoveTo(x, y);
+                eventSender.mouseDown();
+                eventSender.mouseMoveTo(x + 10, y);
+            }
+            setTimeout(autoscrollTestPart2, 100);
+        }
+
+        function autoscrollTestPart2()
+        {
+            if (window.eventSender)
+                eventSender.mouseUp();
+
+            var mainDocumentTop = document.scrollingElement.scrollTop;
+            if (mainDocumentTop == 800)
+                log(&quot;PASSED: selecting in the iframe did not scroll the page.&quot;);
+            else
+                log(&quot;FAILED: the page autoscrolled (window.scrollTop is &quot; + mainDocumentTop + &quot;).&quot;);
+
+            if (window.testRunner)
+                testRunner.notifyDone();
+        }
+        
+        window.addEventListener('load', doTest, false);
+        &lt;/script&gt;
+    &lt;/head&gt;
+&lt;body&gt;
+    &lt;iframe id=&quot;targetFrame&quot; srcdoc=&quot;&lt;!DOCTYPE html&gt;&lt;html&gt;&lt;body&gt;&lt;div id='starthere' style='height:60px; overflow:auto;'&gt;asdf&lt;br&gt;asdf&lt;br&gt;asdf&lt;br&gt;asdf&lt;br&gt;asdf&quot;&gt;&lt;/iframe&gt;
+    &lt;div id=&quot;console&quot;&gt;&lt;/div&gt;
+&lt;/body&gt;
+&lt;/html&gt;
+
</ins></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (187592 => 187593)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2015-07-30 18:31:01 UTC (rev 187592)
+++ trunk/Source/WebCore/ChangeLog        2015-07-30 18:32:45 UTC (rev 187593)
</span><span class="lines">@@ -1,5 +1,29 @@
</span><span class="cx"> 2015-07-30  Simon Fraser  &lt;simon.fraser@apple.com&gt;
</span><span class="cx"> 
</span><ins>+        Selecting in an iframe can cause main page scrolling
+        https://bugs.webkit.org/show_bug.cgi?id=147431
+        rdar://problem/19244589
+
+        Reviewed by Zalan Bujtas.
+        
+        The RenderLayer auatoscroll code walks up the RenderLayer hierarchy, crossing
+        frame boundaries. However, as it crosses into an ancestor frame it failed to
+        map the target rect into the coordinate space of the new frame, which caused
+        us to scroll to an incorrect location in that parent frame.
+
+        Test: fast/events/autoscroll-in-iframe.html
+
+        * rendering/RenderLayer.cpp:
+        (WebCore::parentLayerCrossFrame): Make the layer a reference, and pass in
+        an optional rect. When crossing frame boundaries, map the rect from the
+        contents of the child frame to the contents of the parent frame.
+        (WebCore::RenderLayer::enclosingScrollableLayer): Pass optional rect.
+        (WebCore::RenderLayer::scrollRectToVisible):
+        (WebCore::RenderLayer::hasScrollableOrRubberbandableAncestor):
+        * rendering/RenderLayer.h:
+
+2015-07-30  Simon Fraser  &lt;simon.fraser@apple.com&gt;
+
</ins><span class="cx">         Improve the history logging output
</span><span class="cx">         https://bugs.webkit.org/show_bug.cgi?id=147429
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderLayercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderLayer.cpp (187592 => 187593)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderLayer.cpp        2015-07-30 18:31:01 UTC (rev 187592)
+++ trunk/Source/WebCore/rendering/RenderLayer.cpp        2015-07-30 18:32:45 UTC (rev 187593)
</span><span class="lines">@@ -1449,13 +1449,12 @@
</span><span class="cx">     return curr;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static RenderLayer* parentLayerCrossFrame(const RenderLayer* layer)
</del><ins>+static RenderLayer* parentLayerCrossFrame(const RenderLayer&amp; layer, LayoutRect* rect = nullptr)
</ins><span class="cx"> {
</span><del>-    ASSERT(layer);
-    if (layer-&gt;parent())
-        return layer-&gt;parent();
</del><ins>+    if (layer.parent())
+        return layer.parent();
</ins><span class="cx"> 
</span><del>-    HTMLFrameOwnerElement* ownerElement = layer-&gt;renderer().document().ownerElement();
</del><ins>+    HTMLFrameOwnerElement* ownerElement = layer.renderer().document().ownerElement();
</ins><span class="cx">     if (!ownerElement)
</span><span class="cx">         return nullptr;
</span><span class="cx"> 
</span><span class="lines">@@ -1463,12 +1462,18 @@
</span><span class="cx">     if (!ownerRenderer)
</span><span class="cx">         return nullptr;
</span><span class="cx"> 
</span><ins>+    // Convert the rect into the coordinate space of the parent frame's document.
+    if (rect) {
+        IntRect viewRect = layer.renderer().frame().view()-&gt;convertToContainingView(enclosingIntRect(*rect));
+        *rect = ownerRenderer-&gt;frame().view()-&gt;viewToContents(viewRect);
+    }
+
</ins><span class="cx">     return ownerRenderer-&gt;enclosingLayer();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-RenderLayer* RenderLayer::enclosingScrollableLayer() const
</del><ins>+RenderLayer* RenderLayer::enclosingScrollableLayer(LayoutRect* rect) const
</ins><span class="cx"> {
</span><del>-    for (RenderLayer* nextLayer = parentLayerCrossFrame(this); nextLayer; nextLayer = parentLayerCrossFrame(nextLayer)) {
</del><ins>+    for (RenderLayer* nextLayer = parentLayerCrossFrame(*this, rect); nextLayer; nextLayer = parentLayerCrossFrame(*nextLayer, rect)) {
</ins><span class="cx">         if (is&lt;RenderBox&gt;(nextLayer-&gt;renderer()) &amp;&amp; downcast&lt;RenderBox&gt;(nextLayer-&gt;renderer()).canBeScrolledAndHasScrollableArea())
</span><span class="cx">             return nextLayer;
</span><span class="cx">     }
</span><span class="lines">@@ -2531,7 +2536,7 @@
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     if (renderer().frame().eventHandler().autoscrollInProgress())
</span><del>-        parentLayer = enclosingScrollableLayer();
</del><ins>+        parentLayer = enclosingScrollableLayer(&amp;newRect);
</ins><span class="cx"> 
</span><span class="cx">     if (parentLayer)
</span><span class="cx">         parentLayer-&gt;scrollRectToVisible(newRect, alignX, alignY);
</span><span class="lines">@@ -3182,7 +3187,7 @@
</span><span class="cx"> 
</span><span class="cx"> bool RenderLayer::hasScrollableOrRubberbandableAncestor()
</span><span class="cx"> {
</span><del>-    for (RenderLayer* nextLayer = parentLayerCrossFrame(this); nextLayer; nextLayer = parentLayerCrossFrame(nextLayer)) {
</del><ins>+    for (RenderLayer* nextLayer = parentLayerCrossFrame(*this); nextLayer; nextLayer = parentLayerCrossFrame(*nextLayer)) {
</ins><span class="cx">         if (nextLayer-&gt;isScrollableOrRubberbandable())
</span><span class="cx">             return true;
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderLayerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderLayer.h (187592 => 187593)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderLayer.h        2015-07-30 18:31:01 UTC (rev 187592)
+++ trunk/Source/WebCore/rendering/RenderLayer.h        2015-07-30 18:32:45 UTC (rev 187593)
</span><span class="lines">@@ -404,7 +404,7 @@
</span><span class="cx">     RenderLayer* enclosingAncestorForPosition(EPosition) const;
</span><span class="cx"> 
</span><span class="cx">     // Returns the nearest enclosing layer that is scrollable.
</span><del>-    RenderLayer* enclosingScrollableLayer() const;
</del><ins>+    RenderLayer* enclosingScrollableLayer(LayoutRect* = nullptr) const;
</ins><span class="cx"> 
</span><span class="cx">     // The layer relative to which clipping rects for this layer are computed.
</span><span class="cx">     RenderLayer* clippingRootForPainting() const;
</span></span></pre>
</div>
</div>

</body>
</html>