<!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>[209299] 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/209299">209299</a></dd>
<dt>Author</dt> <dd>simon.fraser@apple.com</dd>
<dt>Date</dt> <dd>2016-12-03 10:33:54 -0800 (Sat, 03 Dec 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>Improve the behavior of scroll-into-view when the target is inside position:fixed
https://bugs.webkit.org/show_bug.cgi?id=165354

Reviewed by Zalan Bujtas.
Source/WebCore:

The existing RenderLayer::scrollRectToVisible() code paid no heed to whether the
target was inside position:fixed, resulting in unwanted scrolls.

Fix this by plumbing through from the call sites a &quot;insideFixed&quot; flag which we get
when we call localToAbsolute(), and use this flag to avoid scrolling at all if
unzoomed.

If zoomed and we're focussing something inside position:fixed, and if visual viewports
are enabled, we can compute the visual viewport required to reveal the target rect,
which gives us the ideal scroll position.

Fix a bug on non-iOS platforms when zoomed, which is to scale the viewRect since
frameView.visibleContentRect() gives an unscaled rect on those platforms.

Not all callers of scrollRectToVisible() are fixed, but those that are not will get
the current behavior.

Tests: fast/overflow/scroll-anchor-in-position-fixed.html
       fast/visual-viewport/zoomed-scroll-into-view-fixed.html
       fast/visual-viewport/zoomed-scroll-to-anchor-in-position-fixed.html

* dom/Element.cpp:
(WebCore::Element::scrollIntoView):
(WebCore::Element::scrollIntoViewIfNeeded):
(WebCore::Element::scrollIntoViewIfNotVisible):
(WebCore::Element::updateFocusAppearance):
* editing/FrameSelection.cpp:
(WebCore::FrameSelection::FrameSelection):
(WebCore::FrameSelection::absoluteCaretBounds):
(WebCore::FrameSelection::recomputeCaretRect):
(WebCore::FrameSelection::revealSelection):
* editing/FrameSelection.h:
* editing/VisiblePosition.cpp:
(WebCore::VisiblePosition::absoluteCaretBounds):
* editing/VisiblePosition.h:
* editing/htmlediting.cpp:
(WebCore::absoluteBoundsForLocalCaretRect):
* editing/htmlediting.h:
* page/FrameView.cpp:
(WebCore::FrameView::scrollElementToRect):
(WebCore::FrameView::scrollToAnchor):
* page/PrintContext.cpp:
(WebCore::PrintContext::outputLinkedDestinations):
* rendering/RenderElement.cpp:
(WebCore::RenderElement::getLeadingCorner):
(WebCore::RenderElement::getTrailingCorner):
(WebCore::RenderElement::absoluteAnchorRect):
(WebCore::RenderElement::anchorRect): Renamed to absoluteAnchorRect().
* rendering/RenderElement.h:
* rendering/RenderLayer.cpp:
(WebCore::RenderLayer::scrollRectToVisible):
(WebCore::RenderLayer::getRectToExpose):
(WebCore::RenderLayer::autoscroll):
* rendering/RenderLayer.h:
* rendering/RenderObject.cpp:
(WebCore::RenderObject::scrollRectToVisible):
* rendering/RenderObject.h:

Source/WebKit/mac:

Plumb through 'insideFixed'. We don't get compute it, so behavior from
these call sites won't change.

* WebView/WebFrame.mm:
(-[WebFrame _scrollDOMRangeToVisible:]):
(-[WebFrame _scrollDOMRangeToVisible:withInset:]):

LayoutTests:

* fast/overflow/scroll-anchor-in-position-fixed-expected.txt: Added.
* fast/overflow/scroll-anchor-in-position-fixed.html: Added.
* fast/visual-viewport/zoomed-scroll-to-anchor-in-position-fixed-expected.txt: Added.
* fast/visual-viewport/zoomed-scroll-to-anchor-in-position-fixed.html: Added.
* platform/ios-simulator/TestExpectations:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsfasttransformsselectionboundsintransformedviewhtml">trunk/LayoutTests/fast/transforms/selection-bounds-in-transformed-view.html</a></li>
<li><a href="#trunkLayoutTestsplatformiossimulatorTestExpectations">trunk/LayoutTests/platform/ios-simulator/TestExpectations</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="#trunkSourceWebCoreeditingFrameSelectioncpp">trunk/Source/WebCore/editing/FrameSelection.cpp</a></li>
<li><a href="#trunkSourceWebCoreeditingFrameSelectionh">trunk/Source/WebCore/editing/FrameSelection.h</a></li>
<li><a href="#trunkSourceWebCoreeditingVisiblePositioncpp">trunk/Source/WebCore/editing/VisiblePosition.cpp</a></li>
<li><a href="#trunkSourceWebCoreeditingVisiblePositionh">trunk/Source/WebCore/editing/VisiblePosition.h</a></li>
<li><a href="#trunkSourceWebCoreeditinghtmleditingcpp">trunk/Source/WebCore/editing/htmlediting.cpp</a></li>
<li><a href="#trunkSourceWebCoreeditinghtmleditingh">trunk/Source/WebCore/editing/htmlediting.h</a></li>
<li><a href="#trunkSourceWebCorepageFrameViewcpp">trunk/Source/WebCore/page/FrameView.cpp</a></li>
<li><a href="#trunkSourceWebCorepagePrintContextcpp">trunk/Source/WebCore/page/PrintContext.cpp</a></li>
<li><a href="#trunkSourceWebCorerenderingRenderElementcpp">trunk/Source/WebCore/rendering/RenderElement.cpp</a></li>
<li><a href="#trunkSourceWebCorerenderingRenderElementh">trunk/Source/WebCore/rendering/RenderElement.h</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>
<li><a href="#trunkSourceWebCorerenderingRenderObjectcpp">trunk/Source/WebCore/rendering/RenderObject.cpp</a></li>
<li><a href="#trunkSourceWebCorerenderingRenderObjecth">trunk/Source/WebCore/rendering/RenderObject.h</a></li>
<li><a href="#trunkSourceWebKitmacChangeLog">trunk/Source/WebKit/mac/ChangeLog</a></li>
<li><a href="#trunkSourceWebKitmacWebViewWebFramemm">trunk/Source/WebKit/mac/WebView/WebFrame.mm</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsfastoverflowscrollanchorinpositionfixedexpectedtxt">trunk/LayoutTests/fast/overflow/scroll-anchor-in-position-fixed-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastoverflowscrollanchorinpositionfixedhtml">trunk/LayoutTests/fast/overflow/scroll-anchor-in-position-fixed.html</a></li>
<li><a href="#trunkLayoutTestsfastvisualviewportzoomedscrollintoviewfixedexpectedtxt">trunk/LayoutTests/fast/visual-viewport/zoomed-scroll-into-view-fixed-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastvisualviewportzoomedscrollintoviewfixedhtml">trunk/LayoutTests/fast/visual-viewport/zoomed-scroll-into-view-fixed.html</a></li>
<li><a href="#trunkLayoutTestsfastvisualviewportzoomedscrolltoanchorinpositionfixedexpectedtxt">trunk/LayoutTests/fast/visual-viewport/zoomed-scroll-to-anchor-in-position-fixed-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastvisualviewportzoomedscrolltoanchorinpositionfixedhtml">trunk/LayoutTests/fast/visual-viewport/zoomed-scroll-to-anchor-in-position-fixed.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (209298 => 209299)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2016-12-03 17:37:46 UTC (rev 209298)
+++ trunk/LayoutTests/ChangeLog        2016-12-03 18:33:54 UTC (rev 209299)
</span><span class="lines">@@ -1,3 +1,16 @@
</span><ins>+2016-12-02  Simon Fraser  &lt;simon.fraser@apple.com&gt;
+
+        Improve the behavior of scroll-into-view when the target is inside position:fixed
+        https://bugs.webkit.org/show_bug.cgi?id=165354
+
+        Reviewed by Zalan Bujtas.
+
+        * fast/overflow/scroll-anchor-in-position-fixed-expected.txt: Added.
+        * fast/overflow/scroll-anchor-in-position-fixed.html: Added.
+        * fast/visual-viewport/zoomed-scroll-to-anchor-in-position-fixed-expected.txt: Added.
+        * fast/visual-viewport/zoomed-scroll-to-anchor-in-position-fixed.html: Added.
+        * platform/ios-simulator/TestExpectations:
+
</ins><span class="cx"> 2016-11-30  Simon Fraser  &lt;simon.fraser@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         localToAbsolute() does incorrect conversion for elements inside position:fixed with zooming
</span></span></pre></div>
<a id="trunkLayoutTestsfastoverflowscrollanchorinpositionfixedexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/overflow/scroll-anchor-in-position-fixed-expected.txt (0 => 209299)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/overflow/scroll-anchor-in-position-fixed-expected.txt                                (rev 0)
+++ trunk/LayoutTests/fast/overflow/scroll-anchor-in-position-fixed-expected.txt        2016-12-03 18:33:54 UTC (rev 209299)
</span><span class="lines">@@ -0,0 +1,11 @@
</span><ins>+Tests scrolling to an anchor inside position:fixed doesn't try to scroll the page
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS document.scrollingElement.scrollTop is 800
+PASS document.scrollingElement.scrollLeft is 100
+PASS successfullyParsed is true
+
+TEST COMPLETE
+Anchor is here
</ins></span></pre></div>
<a id="trunkLayoutTestsfastoverflowscrollanchorinpositionfixedhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/overflow/scroll-anchor-in-position-fixed.html (0 => 209299)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/overflow/scroll-anchor-in-position-fixed.html                                (rev 0)
+++ trunk/LayoutTests/fast/overflow/scroll-anchor-in-position-fixed.html        2016-12-03 18:33:54 UTC (rev 209299)
</span><span class="lines">@@ -0,0 +1,53 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+&lt;head&gt;
+    &lt;style&gt;
+        body {
+            height: 2000px;
+            width: 2000px;
+        }
+        
+        .fixed {
+            position: fixed;
+            top: 50px;
+            left: 40px;
+            border: 1px solid black;
+        }
+    &lt;/style&gt;
+    &lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+    &lt;script&gt;
+    description(&quot;Tests scrolling to an anchor inside position:fixed doesn't try to scroll the page&quot;);
+    window.jsTestIsAsync = true;
+
+    function runTest()
+    {
+        window.scrollTo(100, 800);
+        setTimeout(function() {
+            window.location='#anchor';
+            setTimeout(finishTest, 0);
+        }, 0);
+    }
+
+    function finishTest()
+    {
+        if (window.location.toString().indexOf(&quot;#&quot;) == -1) {
+            setTimeout(finishTest, 0);
+            return;
+        }
+        
+        shouldBe('document.scrollingElement.scrollTop', '800');
+        shouldBe('document.scrollingElement.scrollLeft', '100');
+
+        finishJSTest();
+    }
+    &lt;/script&gt;
+&lt;/head&gt;
+&lt;body onload=&quot;runTest()&quot;&gt;
+
+&lt;div class=&quot;fixed&quot;&gt;
+    &lt;a name=&quot;anchor&quot;&gt;Anchor is here&lt;/a&gt;
+&lt;/div&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="trunkLayoutTestsfasttransformsselectionboundsintransformedviewhtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/transforms/selection-bounds-in-transformed-view.html (209298 => 209299)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/transforms/selection-bounds-in-transformed-view.html        2016-12-03 17:37:46 UTC (rev 209298)
+++ trunk/LayoutTests/fast/transforms/selection-bounds-in-transformed-view.html        2016-12-03 18:33:54 UTC (rev 209299)
</span><span class="lines">@@ -10,6 +10,6 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         document.execCommand(&quot;FindString&quot;, false, &quot;target&quot;);
</span><del>-        document.getElementById(&quot;result&quot;).innerText = document.body.scrollTop === 864 ? &quot;PASS&quot; : &quot;FAIL&quot;;
</del><ins>+        document.getElementById(&quot;result&quot;).innerText = document.body.scrollTop === 937 ? &quot;PASS&quot; : &quot;FAIL&quot;;
</ins><span class="cx">     &lt;/script&gt;
</span><span class="cx"> &lt;/body&gt;
</span></span></pre></div>
<a id="trunkLayoutTestsfastvisualviewportzoomedscrollintoviewfixedexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/visual-viewport/zoomed-scroll-into-view-fixed-expected.txt (0 => 209299)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/visual-viewport/zoomed-scroll-into-view-fixed-expected.txt                                (rev 0)
+++ trunk/LayoutTests/fast/visual-viewport/zoomed-scroll-into-view-fixed-expected.txt        2016-12-03 18:33:54 UTC (rev 209299)
</span><span class="lines">@@ -0,0 +1,24 @@
</span><ins>+Tests revealing elements inside position:fixed after zooming.
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+Reveal &quot;left-target&quot;
+PASS document.scrollingElement.scrollTop is 838
+PASS document.scrollingElement.scrollLeft is 40
+
+Reveal &quot;bottom-target&quot;
+PASS document.scrollingElement.scrollTop is 1048
+PASS document.scrollingElement.scrollLeft is 40
+
+Reveal &quot;right-target&quot;
+PASS document.scrollingElement.scrollTop is 1086
+PASS document.scrollingElement.scrollLeft is 333
+
+Reveal &quot;top-target&quot;
+PASS document.scrollingElement.scrollTop is 834
+PASS document.scrollingElement.scrollLeft is 230
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsfastvisualviewportzoomedscrollintoviewfixedhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/visual-viewport/zoomed-scroll-into-view-fixed.html (0 => 209299)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/visual-viewport/zoomed-scroll-into-view-fixed.html                                (rev 0)
+++ trunk/LayoutTests/fast/visual-viewport/zoomed-scroll-into-view-fixed.html        2016-12-03 18:33:54 UTC (rev 209299)
</span><span class="lines">@@ -0,0 +1,120 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+&lt;head&gt;
+    &lt;style&gt;
+        body {
+            height: 2000px;
+            width: 2000px;
+        }
+        
+        .fixed {
+            position: fixed;
+            top: 50px;
+            left: 40px;
+            height: 200px;
+            width: 200px;
+            background-color: rgba(0, 0, 0, 0.3);
+        }
+        
+        .fixed &gt; div {
+            background-color: blue;
+            width: 20px;
+            height: 10px;
+            margin: 30px;
+        }
+        
+        .left, .right {
+            top: 500px;
+            width: 100px;
+        }
+
+        .top, .bottom {
+            left: 200px;
+            height: 100px;
+        }
+        
+        .left {
+            top: 300px;
+            left: 10px;
+        }
+
+        .right {
+            top: 300px;
+            left: auto;
+            right: 10px;
+        }
+
+        .top {
+            top: 11px;
+        }
+
+        .bottom {
+            top: auto;
+            bottom: 12px;
+        }
+    &lt;/style&gt;
+    &lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+    &lt;script&gt;
+
+    if (window.internals)
+        internals.settings.setVisualViewportEnabled(true);
+
+    description(&quot;Tests revealing elements inside position:fixed after zooming.&quot;);
+
+    window.jsTestIsAsync = true;
+
+    function runTest()
+    {
+        if (window.eventSender)
+            eventSender.scalePageBy(2);
+
+        window.scrollTo(300, 800);
+
+        debug('Reveal &quot;left-target&quot;');
+        document.getElementById('left-target').scrollIntoView();
+        shouldBe('document.scrollingElement.scrollTop', '838');
+        shouldBe('document.scrollingElement.scrollLeft', '40');
+
+        debug('');
+        debug('Reveal &quot;bottom-target&quot;');
+        document.getElementById('bottom-target').scrollIntoView();
+        shouldBe('document.scrollingElement.scrollTop', '1048');
+        shouldBe('document.scrollingElement.scrollLeft', '40');
+
+        debug('');
+        debug('Reveal &quot;right-target&quot;');
+        document.getElementById('right-target').scrollIntoView();
+        shouldBe('document.scrollingElement.scrollTop', '1086');
+        shouldBe('document.scrollingElement.scrollLeft', '333');
+
+        debug('');
+        debug('Reveal &quot;top-target&quot;');
+        document.getElementById('top-target').scrollIntoView();
+        shouldBe('document.scrollingElement.scrollTop', '834');
+        shouldBe('document.scrollingElement.scrollLeft', '230');
+        
+        finishJSTest();
+    }
+    &lt;/script&gt;
+&lt;/head&gt;
+&lt;body onload=&quot;runTest()&quot;&gt;
+
+&lt;div class=&quot;left fixed&quot;&gt;
+    &lt;div id=&quot;left-target&quot;&gt;&lt;/div&gt;
+&lt;/div&gt;
+
+&lt;div class=&quot;right fixed&quot;&gt;
+    &lt;div id=&quot;right-target&quot;&gt;&lt;/div&gt;
+&lt;/div&gt;
+
+&lt;div class=&quot;top fixed&quot;&gt;
+    &lt;div id=&quot;top-target&quot;&gt;&lt;/div&gt;
+&lt;/div&gt;
+
+&lt;div class=&quot;bottom fixed&quot;&gt;
+    &lt;div id=&quot;bottom-target&quot;&gt;&lt;/div&gt;
+&lt;/div&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="trunkLayoutTestsfastvisualviewportzoomedscrolltoanchorinpositionfixedexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/visual-viewport/zoomed-scroll-to-anchor-in-position-fixed-expected.txt (0 => 209299)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/visual-viewport/zoomed-scroll-to-anchor-in-position-fixed-expected.txt                                (rev 0)
+++ trunk/LayoutTests/fast/visual-viewport/zoomed-scroll-to-anchor-in-position-fixed-expected.txt        2016-12-03 18:33:54 UTC (rev 209299)
</span><span class="lines">@@ -0,0 +1,11 @@
</span><ins>+Tests scrolling to an anchor inside position:fixed after zooming doesn't try to scroll the page
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS document.scrollingElement.scrollTop is 559
+PASS document.scrollingElement.scrollLeft is 41
+PASS successfullyParsed is true
+
+TEST COMPLETE
+Anchor is here
</ins></span></pre></div>
<a id="trunkLayoutTestsfastvisualviewportzoomedscrolltoanchorinpositionfixedhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/visual-viewport/zoomed-scroll-to-anchor-in-position-fixed.html (0 => 209299)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/visual-viewport/zoomed-scroll-to-anchor-in-position-fixed.html                                (rev 0)
+++ trunk/LayoutTests/fast/visual-viewport/zoomed-scroll-to-anchor-in-position-fixed.html        2016-12-03 18:33:54 UTC (rev 209299)
</span><span class="lines">@@ -0,0 +1,62 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+&lt;head&gt;
+    &lt;style&gt;
+        body {
+            height: 2000px;
+            width: 2000px;
+        }
+        
+        .fixed {
+            position: fixed;
+            top: 50px;
+            left: 40px;
+            border: 1px solid black;
+        }
+    &lt;/style&gt;
+    &lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+    &lt;script&gt;
+
+    if (window.internals)
+        internals.settings.setVisualViewportEnabled(true);
+
+    description(&quot;Tests scrolling to an anchor inside position:fixed after zooming doesn't try to scroll the page&quot;);
+
+    window.jsTestIsAsync = true;
+
+    function runTest()
+    {
+        if (window.eventSender)
+            eventSender.scalePageBy(2);
+
+        window.scrollTo(300, 800);
+
+        setTimeout(function() {
+            window.location='#anchor';
+            setTimeout(finishTest, 0);
+        }, 0);
+    }
+
+    function finishTest()
+    {
+        if (window.location.toString().indexOf(&quot;#&quot;) == -1) {
+            setTimeout(finishTest, 0);
+            return;
+        }
+        
+        shouldBe('document.scrollingElement.scrollTop', '559');
+        shouldBe('document.scrollingElement.scrollLeft', '41');
+
+        finishJSTest();
+    }
+    &lt;/script&gt;
+&lt;/head&gt;
+&lt;body onload=&quot;runTest()&quot;&gt;
+
+&lt;div class=&quot;fixed&quot;&gt;
+    &lt;a name=&quot;anchor&quot;&gt;Anchor is here&lt;/a&gt;
+&lt;/div&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="trunkLayoutTestsplatformiossimulatorTestExpectations"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/platform/ios-simulator/TestExpectations (209298 => 209299)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/platform/ios-simulator/TestExpectations        2016-12-03 17:37:46 UTC (rev 209298)
+++ trunk/LayoutTests/platform/ios-simulator/TestExpectations        2016-12-03 18:33:54 UTC (rev 209299)
</span><span class="lines">@@ -2767,3 +2767,5 @@
</span><span class="cx"> 
</span><span class="cx"> # Test relies on window.scrollTo
</span><span class="cx"> fast/zooming/client-rect-in-fixed-zoomed.html [ Skip ]
</span><ins>+fast/visual-viewport/zoomed-scroll-to-anchor-in-position-fixed.html [ Skip ]
+fast/visual-viewport/zoomed-scroll-into-view-fixed.html [ Skip ]
</ins></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (209298 => 209299)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2016-12-03 17:37:46 UTC (rev 209298)
+++ trunk/Source/WebCore/ChangeLog        2016-12-03 18:33:54 UTC (rev 209299)
</span><span class="lines">@@ -1,3 +1,68 @@
</span><ins>+2016-12-02  Simon Fraser  &lt;simon.fraser@apple.com&gt;
+
+        Improve the behavior of scroll-into-view when the target is inside position:fixed
+        https://bugs.webkit.org/show_bug.cgi?id=165354
+
+        Reviewed by Zalan Bujtas.
+        
+        The existing RenderLayer::scrollRectToVisible() code paid no heed to whether the 
+        target was inside position:fixed, resulting in unwanted scrolls.
+        
+        Fix this by plumbing through from the call sites a &quot;insideFixed&quot; flag which we get
+        when we call localToAbsolute(), and use this flag to avoid scrolling at all if
+        unzoomed.
+        
+        If zoomed and we're focussing something inside position:fixed, and if visual viewports
+        are enabled, we can compute the visual viewport required to reveal the target rect,
+        which gives us the ideal scroll position.
+        
+        Fix a bug on non-iOS platforms when zoomed, which is to scale the viewRect since
+        frameView.visibleContentRect() gives an unscaled rect on those platforms.
+        
+        Not all callers of scrollRectToVisible() are fixed, but those that are not will get
+        the current behavior.
+
+        Tests: fast/overflow/scroll-anchor-in-position-fixed.html
+               fast/visual-viewport/zoomed-scroll-into-view-fixed.html
+               fast/visual-viewport/zoomed-scroll-to-anchor-in-position-fixed.html
+
+        * dom/Element.cpp:
+        (WebCore::Element::scrollIntoView):
+        (WebCore::Element::scrollIntoViewIfNeeded):
+        (WebCore::Element::scrollIntoViewIfNotVisible):
+        (WebCore::Element::updateFocusAppearance):
+        * editing/FrameSelection.cpp:
+        (WebCore::FrameSelection::FrameSelection):
+        (WebCore::FrameSelection::absoluteCaretBounds):
+        (WebCore::FrameSelection::recomputeCaretRect):
+        (WebCore::FrameSelection::revealSelection):
+        * editing/FrameSelection.h:
+        * editing/VisiblePosition.cpp:
+        (WebCore::VisiblePosition::absoluteCaretBounds):
+        * editing/VisiblePosition.h:
+        * editing/htmlediting.cpp:
+        (WebCore::absoluteBoundsForLocalCaretRect):
+        * editing/htmlediting.h:
+        * page/FrameView.cpp:
+        (WebCore::FrameView::scrollElementToRect):
+        (WebCore::FrameView::scrollToAnchor):
+        * page/PrintContext.cpp:
+        (WebCore::PrintContext::outputLinkedDestinations):
+        * rendering/RenderElement.cpp:
+        (WebCore::RenderElement::getLeadingCorner):
+        (WebCore::RenderElement::getTrailingCorner):
+        (WebCore::RenderElement::absoluteAnchorRect):
+        (WebCore::RenderElement::anchorRect): Renamed to absoluteAnchorRect().
+        * rendering/RenderElement.h:
+        * rendering/RenderLayer.cpp:
+        (WebCore::RenderLayer::scrollRectToVisible):
+        (WebCore::RenderLayer::getRectToExpose):
+        (WebCore::RenderLayer::autoscroll):
+        * rendering/RenderLayer.h:
+        * rendering/RenderObject.cpp:
+        (WebCore::RenderObject::scrollRectToVisible):
+        * rendering/RenderObject.h:
+
</ins><span class="cx"> 2016-11-30  Simon Fraser  &lt;simon.fraser@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         localToAbsolute() does incorrect conversion for elements inside position:fixed with zooming
</span></span></pre></div>
<a id="trunkSourceWebCoredomElementcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/Element.cpp (209298 => 209299)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/Element.cpp        2016-12-03 17:37:46 UTC (rev 209298)
+++ trunk/Source/WebCore/dom/Element.cpp        2016-12-03 18:33:54 UTC (rev 209299)
</span><span class="lines">@@ -649,12 +649,13 @@
</span><span class="cx">     if (!renderer())
</span><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    LayoutRect bounds = renderer()-&gt;anchorRect();
</del><ins>+    bool insideFixed;
+    LayoutRect absoluteBounds = renderer()-&gt;absoluteAnchorRect(&amp;insideFixed);
</ins><span class="cx">     // Align to the top / bottom and to the closest edge.
</span><span class="cx">     if (alignToTop)
</span><del>-        renderer()-&gt;scrollRectToVisible(SelectionRevealMode::Reveal, bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
</del><ins>+        renderer()-&gt;scrollRectToVisible(SelectionRevealMode::Reveal, absoluteBounds, insideFixed, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
</ins><span class="cx">     else
</span><del>-        renderer()-&gt;scrollRectToVisible(SelectionRevealMode::Reveal, bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignBottomAlways);
</del><ins>+        renderer()-&gt;scrollRectToVisible(SelectionRevealMode::Reveal, absoluteBounds, insideFixed, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignBottomAlways);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void Element::scrollIntoViewIfNeeded(bool centerIfNeeded)
</span><span class="lines">@@ -664,11 +665,12 @@
</span><span class="cx">     if (!renderer())
</span><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    LayoutRect bounds = renderer()-&gt;anchorRect();
</del><ins>+    bool insideFixed;
+    LayoutRect absoluteBounds = renderer()-&gt;absoluteAnchorRect(&amp;insideFixed);
</ins><span class="cx">     if (centerIfNeeded)
</span><del>-        renderer()-&gt;scrollRectToVisible(SelectionRevealMode::Reveal, bounds, ScrollAlignment::alignCenterIfNeeded, ScrollAlignment::alignCenterIfNeeded);
</del><ins>+        renderer()-&gt;scrollRectToVisible(SelectionRevealMode::Reveal, absoluteBounds, insideFixed, ScrollAlignment::alignCenterIfNeeded, ScrollAlignment::alignCenterIfNeeded);
</ins><span class="cx">     else
</span><del>-        renderer()-&gt;scrollRectToVisible(SelectionRevealMode::Reveal, bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
</del><ins>+        renderer()-&gt;scrollRectToVisible(SelectionRevealMode::Reveal, absoluteBounds, insideFixed, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void Element::scrollIntoViewIfNotVisible(bool centerIfNotVisible)
</span><span class="lines">@@ -678,11 +680,12 @@
</span><span class="cx">     if (!renderer())
</span><span class="cx">         return;
</span><span class="cx">     
</span><del>-    LayoutRect bounds = renderer()-&gt;anchorRect();
</del><ins>+    bool insideFixed;
+    LayoutRect absoluteBounds = renderer()-&gt;absoluteAnchorRect(&amp;insideFixed);
</ins><span class="cx">     if (centerIfNotVisible)
</span><del>-        renderer()-&gt;scrollRectToVisible(SelectionRevealMode::Reveal, bounds, ScrollAlignment::alignCenterIfNotVisible, ScrollAlignment::alignCenterIfNotVisible);
</del><ins>+        renderer()-&gt;scrollRectToVisible(SelectionRevealMode::Reveal, absoluteBounds, insideFixed, ScrollAlignment::alignCenterIfNotVisible, ScrollAlignment::alignCenterIfNotVisible);
</ins><span class="cx">     else
</span><del>-        renderer()-&gt;scrollRectToVisible(SelectionRevealMode::Reveal, bounds, ScrollAlignment::alignToEdgeIfNotVisible, ScrollAlignment::alignToEdgeIfNotVisible);
</del><ins>+        renderer()-&gt;scrollRectToVisible(SelectionRevealMode::Reveal, absoluteBounds, insideFixed, ScrollAlignment::alignToEdgeIfNotVisible, ScrollAlignment::alignToEdgeIfNotVisible);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void Element::scrollBy(const ScrollToOptions&amp; options)
</span><span class="lines">@@ -2426,8 +2429,11 @@
</span><span class="cx">             frame-&gt;selection().setSelection(newSelection, FrameSelection::defaultSetSelectionOptions(), Element::defaultFocusTextStateChangeIntent());
</span><span class="cx">             frame-&gt;selection().revealSelection(revealMode);
</span><span class="cx">         }
</span><del>-    } else if (renderer() &amp;&amp; !renderer()-&gt;isWidget())
-        renderer()-&gt;scrollRectToVisible(revealMode, renderer()-&gt;anchorRect());
</del><ins>+    } else if (renderer() &amp;&amp; !renderer()-&gt;isWidget()) {
+        bool insideFixed;
+        LayoutRect absoluteBounds = renderer()-&gt;absoluteAnchorRect(&amp;insideFixed);
+        renderer()-&gt;scrollRectToVisible(revealMode, absoluteBounds, insideFixed);
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void Element::blur()
</span></span></pre></div>
<a id="trunkSourceWebCoreeditingFrameSelectioncpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/editing/FrameSelection.cpp (209298 => 209299)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/editing/FrameSelection.cpp        2016-12-03 17:37:46 UTC (rev 209298)
+++ trunk/Source/WebCore/editing/FrameSelection.cpp        2016-12-03 18:33:54 UTC (rev 209299)
</span><span class="lines">@@ -112,6 +112,7 @@
</span><span class="cx">     , m_xPosForVerticalArrowNavigation(NoXPosForVerticalArrowNavigation())
</span><span class="cx">     , m_granularity(CharacterGranularity)
</span><span class="cx">     , m_caretBlinkTimer(*this, &amp;FrameSelection::caretBlinkTimerFired)
</span><ins>+    , m_caretInsidePositionFixed(false)
</ins><span class="cx">     , m_absCaretBoundsDirty(true)
</span><span class="cx">     , m_caretPaint(true)
</span><span class="cx">     , m_isCaretBlinkingSuspended(false)
</span><span class="lines">@@ -1577,12 +1578,14 @@
</span><span class="cx">     return selection.isCaret() &amp;&amp; !selection.start().isOrphan() &amp;&amp; !selection.end().isOrphan();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-IntRect FrameSelection::absoluteCaretBounds()
</del><ins>+IntRect FrameSelection::absoluteCaretBounds(bool* insideFixed)
</ins><span class="cx"> {
</span><span class="cx">     if (!m_frame)
</span><span class="cx">         return IntRect();
</span><span class="cx">     updateSelectionByUpdatingLayoutOrStyle(*m_frame);
</span><span class="cx">     recomputeCaretRect();
</span><ins>+    if (insideFixed)
+        *insideFixed = m_caretInsidePositionFixed;
</ins><span class="cx">     return m_absCaretBounds;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -1624,7 +1627,9 @@
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><span class="cx">     IntRect oldAbsCaretBounds = m_absCaretBounds;
</span><del>-    m_absCaretBounds = absoluteBoundsForLocalCaretRect(rendererForCaretPainting(caretNode.get()), newRect);
</del><ins>+    bool isInsideFixed;
+    m_absCaretBounds = absoluteBoundsForLocalCaretRect(rendererForCaretPainting(caretNode.get()), newRect, &amp;isInsideFixed);
+    m_caretInsidePositionFixed = isInsideFixed;
</ins><span class="cx"> 
</span><span class="cx">     if (m_absCaretBoundsDirty &amp;&amp; m_selection.isCaret()) // We should be able to always assert this condition.
</span><span class="cx">         ASSERT(m_absCaretBounds == m_selection.visibleStart().absoluteCaretBounds());
</span><span class="lines">@@ -2300,12 +2305,12 @@
</span><span class="cx">         return;
</span><span class="cx"> 
</span><span class="cx">     LayoutRect rect;
</span><del>-
</del><ins>+    bool insideFixed = false;
</ins><span class="cx">     switch (m_selection.selectionType()) {
</span><span class="cx">     case VisibleSelection::NoSelection:
</span><span class="cx">         return;
</span><span class="cx">     case VisibleSelection::CaretSelection:
</span><del>-        rect = absoluteCaretBounds();
</del><ins>+        rect = absoluteCaretBounds(&amp;insideFixed);
</ins><span class="cx">         break;
</span><span class="cx">     case VisibleSelection::RangeSelection:
</span><span class="cx">         rect = revealExtentOption == RevealExtent ? VisiblePosition(m_selection.extent()).absoluteCaretBounds() : enclosingIntRect(selectionBounds(false));
</span><span class="lines">@@ -2319,7 +2324,7 @@
</span><span class="cx">         if (RenderLayer* layer = start.deprecatedNode()-&gt;renderer()-&gt;enclosingLayer()) {
</span><span class="cx">             if (!m_scrollingSuppressCount) {
</span><span class="cx">                 layer-&gt;setAdjustForIOSCaretWhenScrolling(true);
</span><del>-                layer-&gt;scrollRectToVisible(revealMode, rect, alignment, alignment);
</del><ins>+                layer-&gt;scrollRectToVisible(revealMode, rect, insideFixed, alignment, alignment);
</ins><span class="cx">                 layer-&gt;setAdjustForIOSCaretWhenScrolling(false);
</span><span class="cx">                 updateAppearance();
</span><span class="cx">                 if (m_frame-&gt;page())
</span><span class="lines">@@ -2330,7 +2335,7 @@
</span><span class="cx">         // FIXME: This code only handles scrolling the startContainer's layer, but
</span><span class="cx">         // the selection rect could intersect more than just that.
</span><span class="cx">         // See &lt;rdar://problem/4799899&gt;.
</span><del>-        if (start.deprecatedNode()-&gt;renderer()-&gt;scrollRectToVisible(revealMode, rect, alignment, alignment))
</del><ins>+        if (start.deprecatedNode()-&gt;renderer()-&gt;scrollRectToVisible(revealMode, rect, insideFixed, alignment, alignment))
</ins><span class="cx">             updateAppearance();
</span><span class="cx"> #endif
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceWebCoreeditingFrameSelectionh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/editing/FrameSelection.h (209298 => 209299)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/editing/FrameSelection.h        2016-12-03 17:37:46 UTC (rev 209298)
+++ trunk/Source/WebCore/editing/FrameSelection.h        2016-12-03 18:33:54 UTC (rev 209299)
</span><span class="lines">@@ -173,7 +173,7 @@
</span><span class="cx">     RenderBlock* caretRendererWithoutUpdatingLayout() const;
</span><span class="cx"> 
</span><span class="cx">     // Bounds of (possibly transformed) caret in absolute coords
</span><del>-    WEBCORE_EXPORT IntRect absoluteCaretBounds();
</del><ins>+    WEBCORE_EXPORT IntRect absoluteCaretBounds(bool* insideFixed = nullptr);
</ins><span class="cx">     void setCaretRectNeedsUpdate() { CaretBase::setCaretRectNeedsUpdate(); }
</span><span class="cx"> 
</span><span class="cx">     void willBeModified(EAlteration, SelectionDirection);
</span><span class="lines">@@ -336,6 +336,7 @@
</span><span class="cx">     Timer m_caretBlinkTimer;
</span><span class="cx">     // The painted bounds of the caret in absolute coordinates
</span><span class="cx">     IntRect m_absCaretBounds;
</span><ins>+    bool m_caretInsidePositionFixed : 1;
</ins><span class="cx">     bool m_absCaretBoundsDirty : 1;
</span><span class="cx">     bool m_caretPaint : 1;
</span><span class="cx">     bool m_isCaretBlinkingSuspended : 1;
</span></span></pre></div>
<a id="trunkSourceWebCoreeditingVisiblePositioncpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/editing/VisiblePosition.cpp (209298 => 209299)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/editing/VisiblePosition.cpp        2016-12-03 17:37:46 UTC (rev 209298)
+++ trunk/Source/WebCore/editing/VisiblePosition.cpp        2016-12-03 18:33:54 UTC (rev 209299)
</span><span class="lines">@@ -660,11 +660,11 @@
</span><span class="cx">     return renderer-&gt;localCaretRect(inlineBox, caretOffset);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-IntRect VisiblePosition::absoluteCaretBounds() const
</del><ins>+IntRect VisiblePosition::absoluteCaretBounds(bool* insideFixed) const
</ins><span class="cx"> {
</span><span class="cx">     RenderBlock* renderer = nullptr;
</span><span class="cx">     LayoutRect localRect = localCaretRectInRendererForCaretPainting(*this, renderer);
</span><del>-    return absoluteBoundsForLocalCaretRect(renderer, localRect);
</del><ins>+    return absoluteBoundsForLocalCaretRect(renderer, localRect, insideFixed);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> int VisiblePosition::lineDirectionPointForBlockDirectionNavigation() const
</span></span></pre></div>
<a id="trunkSourceWebCoreeditingVisiblePositionh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/editing/VisiblePosition.h (209298 => 209299)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/editing/VisiblePosition.h        2016-12-03 17:37:46 UTC (rev 209298)
+++ trunk/Source/WebCore/editing/VisiblePosition.h        2016-12-03 18:33:54 UTC (rev 209299)
</span><span class="lines">@@ -95,7 +95,7 @@
</span><span class="cx">     // Rect is local to the returned renderer
</span><span class="cx">     WEBCORE_EXPORT LayoutRect localCaretRect(RenderObject*&amp;) const;
</span><span class="cx">     // Bounds of (possibly transformed) caret in absolute coords
</span><del>-    WEBCORE_EXPORT IntRect absoluteCaretBounds() const;
</del><ins>+    WEBCORE_EXPORT IntRect absoluteCaretBounds(bool* insideFixed = nullptr) const;
</ins><span class="cx">     // Abs x/y position of the caret ignoring transforms.
</span><span class="cx">     // FIXME: navigation with transforms should be smarter.
</span><span class="cx">     WEBCORE_EXPORT int lineDirectionPointForBlockDirectionNavigation() const;
</span></span></pre></div>
<a id="trunkSourceWebCoreeditinghtmleditingcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/editing/htmlediting.cpp (209298 => 209299)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/editing/htmlediting.cpp        2016-12-03 17:37:46 UTC (rev 209298)
+++ trunk/Source/WebCore/editing/htmlediting.cpp        2016-12-03 18:33:54 UTC (rev 209299)
</span><span class="lines">@@ -1290,7 +1290,7 @@
</span><span class="cx">     return localRect;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-IntRect absoluteBoundsForLocalCaretRect(RenderBlock* rendererForCaretPainting, const LayoutRect&amp; rect)
</del><ins>+IntRect absoluteBoundsForLocalCaretRect(RenderBlock* rendererForCaretPainting, const LayoutRect&amp; rect, bool* insideFixed)
</ins><span class="cx"> {
</span><span class="cx">     if (!rendererForCaretPainting || rect.isEmpty())
</span><span class="cx">         return IntRect();
</span><span class="lines">@@ -1297,7 +1297,7 @@
</span><span class="cx"> 
</span><span class="cx">     LayoutRect localRect(rect);
</span><span class="cx">     rendererForCaretPainting-&gt;flipForWritingMode(localRect);
</span><del>-    return rendererForCaretPainting-&gt;localToAbsoluteQuad(FloatRect(localRect)).enclosingBoundingBox();
</del><ins>+    return rendererForCaretPainting-&gt;localToAbsoluteQuad(FloatRect(localRect), UseTransforms, insideFixed).enclosingBoundingBox();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebCore
</span></span></pre></div>
<a id="trunkSourceWebCoreeditinghtmleditingh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/editing/htmlediting.h (209298 => 209299)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/editing/htmlediting.h        2016-12-03 17:37:46 UTC (rev 209298)
+++ trunk/Source/WebCore/editing/htmlediting.h        2016-12-03 18:33:54 UTC (rev 209299)
</span><span class="lines">@@ -200,7 +200,7 @@
</span><span class="cx"> RenderBlock* rendererForCaretPainting(Node*);
</span><span class="cx"> LayoutRect localCaretRectInRendererForCaretPainting(const VisiblePosition&amp;, RenderBlock*&amp;);
</span><span class="cx"> LayoutRect localCaretRectInRendererForRect(LayoutRect&amp;, Node*, RenderObject*, RenderBlock*&amp;);
</span><del>-IntRect absoluteBoundsForLocalCaretRect(RenderBlock* rendererForCaretPainting, const LayoutRect&amp;);
</del><ins>+IntRect absoluteBoundsForLocalCaretRect(RenderBlock* rendererForCaretPainting, const LayoutRect&amp;, bool* insideFixed = nullptr);
</ins><span class="cx"> 
</span><span class="cx"> // -------------------------------------------------------------------------
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCorepageFrameViewcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/FrameView.cpp (209298 => 209299)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/FrameView.cpp        2016-12-03 17:37:46 UTC (rev 209298)
+++ trunk/Source/WebCore/page/FrameView.cpp        2016-12-03 18:33:54 UTC (rev 209299)
</span><span class="lines">@@ -2351,7 +2351,7 @@
</span><span class="cx"> 
</span><span class="cx">     LayoutRect bounds;
</span><span class="cx">     if (RenderElement* renderer = element.renderer())
</span><del>-        bounds = renderer-&gt;anchorRect();
</del><ins>+        bounds = renderer-&gt;absoluteAnchorRect();
</ins><span class="cx">     int centeringOffsetX = (rect.width() - bounds.width()) / 2;
</span><span class="cx">     int centeringOffsetY = (rect.height() - bounds.height()) / 2;
</span><span class="cx">     setScrollPosition(IntPoint(bounds.x() - centeringOffsetX - rect.x(), bounds.y() - centeringOffsetY - rect.y()));
</span><span class="lines">@@ -3271,17 +3271,18 @@
</span><span class="cx">         return;
</span><span class="cx"> 
</span><span class="cx">     LayoutRect rect;
</span><ins>+    bool insideFixed = false;
</ins><span class="cx">     if (anchorNode != frame().document() &amp;&amp; anchorNode-&gt;renderer())
</span><del>-        rect = anchorNode-&gt;renderer()-&gt;anchorRect();
</del><ins>+        rect = anchorNode-&gt;renderer()-&gt;absoluteAnchorRect(&amp;insideFixed);
</ins><span class="cx"> 
</span><span class="cx">     // Scroll nested layers and frames to reveal the anchor.
</span><span class="cx">     // Align to the top and to the closest side (this matches other browsers).
</span><span class="cx">     if (anchorNode-&gt;renderer()-&gt;style().isHorizontalWritingMode())
</span><del>-        anchorNode-&gt;renderer()-&gt;scrollRectToVisible(SelectionRevealMode::Reveal, rect, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
</del><ins>+        anchorNode-&gt;renderer()-&gt;scrollRectToVisible(SelectionRevealMode::Reveal, rect, insideFixed, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
</ins><span class="cx">     else if (anchorNode-&gt;renderer()-&gt;style().isFlippedBlocksWritingMode())
</span><del>-        anchorNode-&gt;renderer()-&gt;scrollRectToVisible(SelectionRevealMode::Reveal, rect, ScrollAlignment::alignRightAlways, ScrollAlignment::alignToEdgeIfNeeded);
</del><ins>+        anchorNode-&gt;renderer()-&gt;scrollRectToVisible(SelectionRevealMode::Reveal, rect, insideFixed, ScrollAlignment::alignRightAlways, ScrollAlignment::alignToEdgeIfNeeded);
</ins><span class="cx">     else
</span><del>-        anchorNode-&gt;renderer()-&gt;scrollRectToVisible(SelectionRevealMode::Reveal, rect, ScrollAlignment::alignLeftAlways, ScrollAlignment::alignToEdgeIfNeeded);
</del><ins>+        anchorNode-&gt;renderer()-&gt;scrollRectToVisible(SelectionRevealMode::Reveal, rect, insideFixed, ScrollAlignment::alignLeftAlways, ScrollAlignment::alignToEdgeIfNeeded);
</ins><span class="cx"> 
</span><span class="cx">     if (AXObjectCache* cache = frame().document()-&gt;existingAXObjectCache())
</span><span class="cx">         cache-&gt;handleScrolledToAnchor(anchorNode.get());
</span></span></pre></div>
<a id="trunkSourceWebCorepagePrintContextcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/PrintContext.cpp (209298 => 209299)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/PrintContext.cpp        2016-12-03 17:37:46 UTC (rev 209298)
+++ trunk/Source/WebCore/page/PrintContext.cpp        2016-12-03 18:33:54 UTC (rev 209299)
</span><span class="lines">@@ -274,7 +274,7 @@
</span><span class="cx">         if (!renderer)
</span><span class="cx">             continue;
</span><span class="cx"> 
</span><del>-        FloatPoint point = renderer-&gt;anchorRect().minXMinYCorner();
</del><ins>+        FloatPoint point = renderer-&gt;absoluteAnchorRect().minXMinYCorner();
</ins><span class="cx">         point.expandedTo(FloatPoint());
</span><span class="cx"> 
</span><span class="cx">         if (!pageRect.contains(roundedIntPoint(point)))
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderElementcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderElement.cpp (209298 => 209299)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderElement.cpp        2016-12-03 17:37:46 UTC (rev 209298)
+++ trunk/Source/WebCore/rendering/RenderElement.cpp        2016-12-03 18:33:54 UTC (rev 209299)
</span><span class="lines">@@ -1625,10 +1625,10 @@
</span><span class="cx">     return theme().inactiveSelectionBackgroundColor();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool RenderElement::getLeadingCorner(FloatPoint&amp; point) const
</del><ins>+bool RenderElement::getLeadingCorner(FloatPoint&amp; point, bool&amp; insideFixed) const
</ins><span class="cx"> {
</span><span class="cx">     if (!isInline() || isReplaced()) {
</span><del>-        point = localToAbsolute(FloatPoint(), UseTransforms);
</del><ins>+        point = localToAbsolute(FloatPoint(), UseTransforms, &amp;insideFixed);
</ins><span class="cx">         return true;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -1654,7 +1654,7 @@
</span><span class="cx">         ASSERT(o);
</span><span class="cx"> 
</span><span class="cx">         if (!o-&gt;isInline() || o-&gt;isReplaced()) {
</span><del>-            point = o-&gt;localToAbsolute(FloatPoint(), UseTransforms);
</del><ins>+            point = o-&gt;localToAbsolute(FloatPoint(), UseTransforms, &amp;insideFixed);
</ins><span class="cx">             return true;
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="lines">@@ -1666,7 +1666,7 @@
</span><span class="cx">                 point.move(downcast&lt;RenderText&gt;(*o).linesBoundingBox().x(), downcast&lt;RenderText&gt;(*o).topOfFirstText());
</span><span class="cx">             else if (is&lt;RenderBox&gt;(*o))
</span><span class="cx">                 point.moveBy(downcast&lt;RenderBox&gt;(*o).location());
</span><del>-            point = o-&gt;container()-&gt;localToAbsolute(point, UseTransforms);
</del><ins>+            point = o-&gt;container()-&gt;localToAbsolute(point, UseTransforms, &amp;insideFixed);
</ins><span class="cx">             return true;
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="lines">@@ -1680,10 +1680,10 @@
</span><span class="cx">     return false;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool RenderElement::getTrailingCorner(FloatPoint&amp; point) const
</del><ins>+bool RenderElement::getTrailingCorner(FloatPoint&amp; point, bool&amp; insideFixed) const
</ins><span class="cx"> {
</span><span class="cx">     if (!isInline() || isReplaced()) {
</span><del>-        point = localToAbsolute(LayoutPoint(downcast&lt;RenderBox&gt;(*this).size()), UseTransforms);
</del><ins>+        point = localToAbsolute(LayoutPoint(downcast&lt;RenderBox&gt;(*this).size()), UseTransforms, &amp;insideFixed);
</ins><span class="cx">         return true;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -1714,7 +1714,7 @@
</span><span class="cx">                 point.moveBy(linesBox.maxXMaxYCorner());
</span><span class="cx">             } else
</span><span class="cx">                 point.moveBy(downcast&lt;RenderBox&gt;(*o).frameRect().maxXMaxYCorner());
</span><del>-            point = o-&gt;container()-&gt;localToAbsolute(point, UseTransforms);
</del><ins>+            point = o-&gt;container()-&gt;localToAbsolute(point, UseTransforms, &amp;insideFixed);
</ins><span class="cx">             return true;
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="lines">@@ -1721,11 +1721,13 @@
</span><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-LayoutRect RenderElement::anchorRect() const
</del><ins>+LayoutRect RenderElement::absoluteAnchorRect(bool* insideFixed) const
</ins><span class="cx"> {
</span><span class="cx">     FloatPoint leading, trailing;
</span><del>-    getLeadingCorner(leading);
-    getTrailingCorner(trailing);
</del><ins>+    bool leadingInFixed = false;
+    bool trailingInFixed = false;
+    getLeadingCorner(leading, leadingInFixed);
+    getTrailingCorner(trailing, trailingInFixed);
</ins><span class="cx"> 
</span><span class="cx">     FloatPoint upperLeft = leading;
</span><span class="cx">     FloatPoint lowerRight = trailing;
</span><span class="lines">@@ -1736,6 +1738,11 @@
</span><span class="cx">         lowerRight = FloatPoint(std::max(leading.x(), trailing.x()), std::max(leading.y(), trailing.y()));
</span><span class="cx">     } // Otherwise, it's not obvious what to do.
</span><span class="cx"> 
</span><ins>+    if (insideFixed) {
+        // For now, just look at the leading corner. Handling one inside fixed and one not would be tricky.
+        *insideFixed = leadingInFixed;
+    }
+
</ins><span class="cx">     return enclosingLayoutRect(FloatRect(upperLeft, lowerRight.expandedTo(upperLeft) - upperLeft));
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderElementh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderElement.h (209298 => 209299)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderElement.h        2016-12-03 17:37:46 UTC (rev 209298)
+++ trunk/Source/WebCore/rendering/RenderElement.h        2016-12-03 18:33:54 UTC (rev 209299)
</span><span class="lines">@@ -164,7 +164,7 @@
</span><span class="cx">     // anchorRect() is conceptually similar to absoluteBoundingBoxRect(), but is intended for scrolling to an anchor.
</span><span class="cx">     // For inline renderers, this gets the logical top left of the first leaf child and the logical bottom right of the
</span><span class="cx">     // last leaf child, converts them to absolute coordinates, and makes a box out of them.
</span><del>-    LayoutRect anchorRect() const;
</del><ins>+    LayoutRect absoluteAnchorRect(bool* insideFixed = nullptr) const;
</ins><span class="cx"> 
</span><span class="cx">     bool hasFilter() const { return style().hasFilter(); }
</span><span class="cx">     bool hasBackdropFilter() const
</span><span class="lines">@@ -307,8 +307,8 @@
</span><span class="cx"> 
</span><span class="cx">     void newImageAnimationFrameAvailable(CachedImage&amp;) final;
</span><span class="cx"> 
</span><del>-    bool getLeadingCorner(FloatPoint&amp; output) const;
-    bool getTrailingCorner(FloatPoint&amp; output) const;
</del><ins>+    bool getLeadingCorner(FloatPoint&amp; output, bool&amp; insideFixed) const;
+    bool getTrailingCorner(FloatPoint&amp; output, bool&amp; insideFixed) const;
</ins><span class="cx"> 
</span><span class="cx">     void clearLayoutRootIfNeeded() const;
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderLayercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderLayer.cpp (209298 => 209299)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderLayer.cpp        2016-12-03 17:37:46 UTC (rev 209298)
+++ trunk/Source/WebCore/rendering/RenderLayer.cpp        2016-12-03 18:33:54 UTC (rev 209299)
</span><span class="lines">@@ -2506,12 +2506,12 @@
</span><span class="cx">     return box-&gt;hasHorizontalOverflow() || box-&gt;hasVerticalOverflow();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void RenderLayer::scrollRectToVisible(SelectionRevealMode revealMode, const LayoutRect&amp; rect, const ScrollAlignment&amp; alignX, const ScrollAlignment&amp; alignY)
</del><ins>+void RenderLayer::scrollRectToVisible(SelectionRevealMode revealMode, const LayoutRect&amp; absoluteRect, bool insideFixed, const ScrollAlignment&amp; alignX, const ScrollAlignment&amp; alignY)
</ins><span class="cx"> {
</span><del>-    LOG_WITH_STREAM(Scrolling, stream &lt;&lt; &quot;Layer &quot; &lt;&lt; this &lt;&lt; &quot; scrollRectToVisible &quot; &lt;&lt; rect);
</del><ins>+    LOG_WITH_STREAM(Scrolling, stream &lt;&lt; &quot;Layer &quot; &lt;&lt; this &lt;&lt; &quot; scrollRectToVisible &quot; &lt;&lt; absoluteRect);
</ins><span class="cx"> 
</span><span class="cx">     RenderLayer* parentLayer = nullptr;
</span><del>-    LayoutRect newRect = rect;
</del><ins>+    LayoutRect newRect = absoluteRect;
</ins><span class="cx"> 
</span><span class="cx">     // We may end up propagating a scroll event. It is important that we suspend events until 
</span><span class="cx">     // the end of the function since they could delete the layer or the layer's renderer().
</span><span class="lines">@@ -2525,11 +2525,11 @@
</span><span class="cx">         // This will prevent us from revealing text hidden by the slider in Safari RSS.
</span><span class="cx">         RenderBox* box = renderBox();
</span><span class="cx">         ASSERT(box);
</span><del>-        LayoutRect localExposeRect(box-&gt;absoluteToLocalQuad(FloatQuad(FloatRect(rect))).boundingBox());
</del><ins>+        LayoutRect localExposeRect(box-&gt;absoluteToLocalQuad(FloatQuad(FloatRect(absoluteRect))).boundingBox());
</ins><span class="cx">         LayoutRect layerBounds(0, 0, box-&gt;clientWidth(), box-&gt;clientHeight());
</span><del>-        LayoutRect r = getRectToExpose(layerBounds, layerBounds, localExposeRect, alignX, alignY);
</del><ins>+        LayoutRect revealRect = getRectToExpose(layerBounds, layerBounds, localExposeRect, insideFixed, alignX, alignY);
</ins><span class="cx"> 
</span><del>-        ScrollOffset clampedScrollOffset = clampScrollOffset(scrollOffset() + toIntSize(roundedIntRect(r).location()));
</del><ins>+        ScrollOffset clampedScrollOffset = clampScrollOffset(scrollOffset() + toIntSize(roundedIntRect(revealRect).location()));
</ins><span class="cx">         if (clampedScrollOffset != scrollOffset()) {
</span><span class="cx">             ScrollOffset oldScrollOffset = scrollOffset();
</span><span class="cx">             scrollToOffset(clampedScrollOffset);
</span><span class="lines">@@ -2551,7 +2551,7 @@
</span><span class="cx">                 NoEventDispatchAssertion assertNoEventDispatch;
</span><span class="cx"> 
</span><span class="cx">                 LayoutRect viewRect = frameView.visibleContentRect(LegacyIOSDocumentVisibleRect);
</span><del>-                LayoutRect exposeRect = getRectToExpose(viewRect, viewRect, rect, alignX, alignY);
</del><ins>+                LayoutRect exposeRect = getRectToExpose(viewRect, viewRect, absoluteRect, insideFixed, alignX, alignY);
</ins><span class="cx"> 
</span><span class="cx">                 IntPoint scrollOffset(roundedIntPoint(exposeRect.location()));
</span><span class="cx">                 // Adjust offsets if they're outside of the allowable range.
</span><span class="lines">@@ -2562,6 +2562,7 @@
</span><span class="cx">                     parentLayer = ownerElement-&gt;renderer()-&gt;enclosingLayer();
</span><span class="cx">                     // Convert the rect into the coordinate space of the parent frame's document.
</span><span class="cx">                     newRect = frameView.contentsToContainingViewContents(enclosingIntRect(newRect));
</span><ins>+                    insideFixed = false; // FIXME: ideally need to determine if this &lt;iframe&gt; is inside position:fixed.
</ins><span class="cx">                 } else
</span><span class="cx">                     parentLayer = nullptr;
</span><span class="cx">             }
</span><span class="lines">@@ -2571,6 +2572,8 @@
</span><span class="cx"> 
</span><span class="cx"> #if !PLATFORM(IOS)
</span><span class="cx">             LayoutRect viewRect = frameView.visibleContentRect();
</span><ins>+            viewRect.scale(1 / frameView.frameScaleFactor());
+
</ins><span class="cx">             LayoutRect visibleRectRelativeToDocument = viewRect;
</span><span class="cx">             visibleRectRelativeToDocument.setLocation(frameView.documentScrollPositionRelativeToScrollableAreaOrigin());
</span><span class="cx"> #else
</span><span class="lines">@@ -2577,10 +2580,9 @@
</span><span class="cx">             LayoutRect viewRect = frameView.unobscuredContentRect();
</span><span class="cx">             LayoutRect visibleRectRelativeToDocument = viewRect;
</span><span class="cx"> #endif
</span><del>-
-            LayoutRect r = getRectToExpose(viewRect, visibleRectRelativeToDocument, rect, alignX, alignY);
</del><ins>+            LayoutRect revealRect = getRectToExpose(viewRect, visibleRectRelativeToDocument, absoluteRect, insideFixed, alignX, alignY);
</ins><span class="cx">                 
</span><del>-            frameView.setScrollPosition(roundedIntPoint(r.location()));
</del><ins>+            frameView.setScrollPosition(roundedIntPoint(revealRect.location()));
</ins><span class="cx"> 
</span><span class="cx">             // This is the outermost view of a web page, so after scrolling this view we
</span><span class="cx">             // scroll its container by calling Page::scrollRectIntoView.
</span><span class="lines">@@ -2588,12 +2590,12 @@
</span><span class="cx">             // that put web views into scrolling containers, such as Mac OS X Mail.
</span><span class="cx">             // The canAutoscroll function in EventHandler also knows about this.
</span><span class="cx">             if (Page* page = frameView.frame().page())
</span><del>-                page-&gt;chrome().scrollRectIntoView(snappedIntRect(rect));
</del><ins>+                page-&gt;chrome().scrollRectIntoView(snappedIntRect(absoluteRect));
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     if (parentLayer)
</span><del>-        parentLayer-&gt;scrollRectToVisible(revealMode, newRect, alignX, alignY);
</del><ins>+        parentLayer-&gt;scrollRectToVisible(revealMode, newRect, insideFixed, alignX, alignY);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void RenderLayer::updateCompositingLayersAfterScroll()
</span><span class="lines">@@ -2610,8 +2612,35 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-LayoutRect RenderLayer::getRectToExpose(const LayoutRect &amp;visibleRect, const LayoutRect &amp;visibleRectRelativeToDocument, const LayoutRect &amp;exposeRect, const ScrollAlignment&amp; alignX, const ScrollAlignment&amp; alignY)
</del><ins>+LayoutRect RenderLayer::getRectToExpose(const LayoutRect &amp;visibleRect, const LayoutRect &amp;visibleRectRelativeToDocument, const LayoutRect &amp;exposeRect, bool insideFixed, const ScrollAlignment&amp; alignX, const ScrollAlignment&amp; alignY)
</ins><span class="cx"> {
</span><ins>+    FrameView&amp; frameView = renderer().view().frameView();
+    if (insideFixed) {
+        // If the element is inside position:fixed and we're not scaled, no amount of scrolling is going to move things around.
+        if (frameView.frameScaleFactor() == 1)
+            return visibleRect;
+
+        if (frameView.frame().settings().visualViewportEnabled()) {
+            // exposeRect is in absolute coords, affected by page scale. Unscale it.
+            LayoutRect unscaledExposeRect = exposeRect;
+            unscaledExposeRect.scale(1 / frameView.frameScaleFactor());
+            // These are both in unscaled coordinates.
+            LayoutRect layoutViewport = frameView.layoutViewportRect();
+            LayoutRect visualViewport = frameView.visualViewportRect();
+
+            // The rect to expose may be partially offscreen, which we can't do anything about with position:fixed.
+            unscaledExposeRect.intersect(layoutViewport);
+            // Make sure it's not larger than the visual viewport; if so, we'll just move to the top left.
+            unscaledExposeRect.setSize(unscaledExposeRect.size().shrunkTo(visualViewport.size()));
+
+            // Compute how much we have to move the visualViewport to reveal the part of the layoutViewport that contains exposeRect.
+            LayoutRect requiredVisualViewport = getRectToExpose(visualViewport, visualViewport, unscaledExposeRect, false, alignX, alignY);
+            // Scale it back up.
+            requiredVisualViewport.scale(frameView.frameScaleFactor());
+            return requiredVisualViewport;
+        }
+    }
+
</ins><span class="cx">     // Determine the appropriate X behavior.
</span><span class="cx">     ScrollAlignment::Behavior scrollX;
</span><span class="cx">     LayoutRect exposeRectX(exposeRect.x(), visibleRect.y(), exposeRect.width(), visibleRect.height());
</span><span class="lines">@@ -2686,7 +2715,7 @@
</span><span class="cx"> void RenderLayer::autoscroll(const IntPoint&amp; position)
</span><span class="cx"> {
</span><span class="cx">     IntPoint currentDocumentPosition = renderer().view().frameView().windowToContents(position);
</span><del>-    scrollRectToVisible(SelectionRevealMode::Reveal, LayoutRect(currentDocumentPosition, LayoutSize(1, 1)), ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
</del><ins>+    scrollRectToVisible(SelectionRevealMode::Reveal, LayoutRect(currentDocumentPosition, LayoutSize(1, 1)), false, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool RenderLayer::canResize() const
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderLayerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderLayer.h (209298 => 209299)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderLayer.h        2016-12-03 17:37:46 UTC (rev 209298)
+++ trunk/Source/WebCore/rendering/RenderLayer.h        2016-12-03 18:33:54 UTC (rev 209299)
</span><span class="lines">@@ -204,9 +204,9 @@
</span><span class="cx"> 
</span><span class="cx">     void availableContentSizeChanged(AvailableSizeChangeReason) override;
</span><span class="cx"> 
</span><del>-    void scrollRectToVisible(SelectionRevealMode, const LayoutRect&amp;, const ScrollAlignment&amp; alignX, const ScrollAlignment&amp; alignY);
</del><ins>+    void scrollRectToVisible(SelectionRevealMode, const LayoutRect&amp; absoluteRect, bool insideFixed, const ScrollAlignment&amp; alignX, const ScrollAlignment&amp; alignY);
</ins><span class="cx"> 
</span><del>-    LayoutRect getRectToExpose(const LayoutRect&amp; visibleRect, const LayoutRect&amp; visibleRectRelativeToDocument, const LayoutRect&amp; exposeRect, const ScrollAlignment&amp; alignX, const ScrollAlignment&amp; alignY);
</del><ins>+    LayoutRect getRectToExpose(const LayoutRect&amp; visibleRect, const LayoutRect&amp; visibleRectRelativeToDocument, const LayoutRect&amp; exposeRect, bool insideFixed, const ScrollAlignment&amp; alignX, const ScrollAlignment&amp; alignY);
</ins><span class="cx"> 
</span><span class="cx">     bool scrollsOverflow() const;
</span><span class="cx">     bool hasScrollbars() const { return m_hBar || m_vBar; }
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderObjectcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderObject.cpp (209298 => 209299)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderObject.cpp        2016-12-03 17:37:46 UTC (rev 209298)
+++ trunk/Source/WebCore/rendering/RenderObject.cpp        2016-12-03 18:33:54 UTC (rev 209299)
</span><span class="lines">@@ -396,7 +396,7 @@
</span><span class="cx">     return nullptr;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool RenderObject::scrollRectToVisible(SelectionRevealMode revealMode, const LayoutRect&amp; rect, const ScrollAlignment&amp; alignX, const ScrollAlignment&amp; alignY)
</del><ins>+bool RenderObject::scrollRectToVisible(SelectionRevealMode revealMode, const LayoutRect&amp; absoluteRect, bool insideFixed, const ScrollAlignment&amp; alignX, const ScrollAlignment&amp; alignY)
</ins><span class="cx"> {
</span><span class="cx">     if (revealMode == SelectionRevealMode::DoNotReveal)
</span><span class="cx">         return false;
</span><span class="lines">@@ -405,7 +405,7 @@
</span><span class="cx">     if (!enclosingLayer)
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    enclosingLayer-&gt;scrollRectToVisible(revealMode, rect, alignX, alignY);
</del><ins>+    enclosingLayer-&gt;scrollRectToVisible(revealMode, absoluteRect, insideFixed, alignX, alignY);
</ins><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderObjecth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderObject.h (209298 => 209299)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderObject.h        2016-12-03 17:37:46 UTC (rev 209298)
+++ trunk/Source/WebCore/rendering/RenderObject.h        2016-12-03 18:33:54 UTC (rev 209299)
</span><span class="lines">@@ -154,7 +154,7 @@
</span><span class="cx">     WEBCORE_EXPORT RenderLayer* enclosingLayer() const;
</span><span class="cx"> 
</span><span class="cx">     // Scrolling is a RenderBox concept, however some code just cares about recursively scrolling our enclosing ScrollableArea(s).
</span><del>-    WEBCORE_EXPORT bool scrollRectToVisible(SelectionRevealMode, const LayoutRect&amp;, const ScrollAlignment&amp; alignX = ScrollAlignment::alignCenterIfNeeded, const ScrollAlignment&amp; alignY = ScrollAlignment::alignCenterIfNeeded);
</del><ins>+    WEBCORE_EXPORT bool scrollRectToVisible(SelectionRevealMode, const LayoutRect&amp; absoluteRect, bool insideFixed, const ScrollAlignment&amp; alignX = ScrollAlignment::alignCenterIfNeeded, const ScrollAlignment&amp; alignY = ScrollAlignment::alignCenterIfNeeded);
</ins><span class="cx"> 
</span><span class="cx">     // Convenience function for getting to the nearest enclosing box of a RenderObject.
</span><span class="cx">     WEBCORE_EXPORT RenderBox&amp; enclosingBox() const;
</span></span></pre></div>
<a id="trunkSourceWebKitmacChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/mac/ChangeLog (209298 => 209299)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/mac/ChangeLog        2016-12-03 17:37:46 UTC (rev 209298)
+++ trunk/Source/WebKit/mac/ChangeLog        2016-12-03 18:33:54 UTC (rev 209299)
</span><span class="lines">@@ -1,3 +1,17 @@
</span><ins>+2016-12-02  Simon Fraser  &lt;simon.fraser@apple.com&gt;
+
+        Improve the behavior of scroll-into-view when the target is inside position:fixed
+        https://bugs.webkit.org/show_bug.cgi?id=165354
+
+        Reviewed by Zalan Bujtas.
+
+        Plumb through 'insideFixed'. We don't get compute it, so behavior from
+        these call sites won't change.
+
+        * WebView/WebFrame.mm:
+        (-[WebFrame _scrollDOMRangeToVisible:]):
+        (-[WebFrame _scrollDOMRangeToVisible:withInset:]):
+
</ins><span class="cx"> 2016-12-02  Andy Estes  &lt;aestes@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [Cocoa] Adopt the PRODUCT_BUNDLE_IDENTIFIER build setting
</span></span></pre></div>
<a id="trunkSourceWebKitmacWebViewWebFramemm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/mac/WebView/WebFrame.mm (209298 => 209299)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/mac/WebView/WebFrame.mm        2016-12-03 17:37:46 UTC (rev 209298)
+++ trunk/Source/WebKit/mac/WebView/WebFrame.mm        2016-12-03 18:33:54 UTC (rev 209299)
</span><span class="lines">@@ -711,17 +711,18 @@
</span><span class="cx"> 
</span><span class="cx"> - (void)_scrollDOMRangeToVisible:(DOMRange *)range
</span><span class="cx"> {
</span><ins>+    bool insideFixed = false; // FIXME: get via firstRectForRange().
</ins><span class="cx">     NSRect rangeRect = [self _firstRectForDOMRange:range];    
</span><span class="cx">     Node *startNode = core([range startContainer]);
</span><span class="cx">         
</span><span class="cx">     if (startNode &amp;&amp; startNode-&gt;renderer()) {
</span><span class="cx"> #if !PLATFORM(IOS)
</span><del>-        startNode-&gt;renderer()-&gt;scrollRectToVisible(SelectionRevealMode::Reveal, enclosingIntRect(rangeRect), ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
</del><ins>+        startNode-&gt;renderer()-&gt;scrollRectToVisible(SelectionRevealMode::Reveal, enclosingIntRect(rangeRect), insideFixed, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
</ins><span class="cx"> #else
</span><span class="cx">         RenderLayer* layer = startNode-&gt;renderer()-&gt;enclosingLayer();
</span><span class="cx">         if (layer) {
</span><span class="cx">             layer-&gt;setAdjustForIOSCaretWhenScrolling(true);
</span><del>-            startNode-&gt;renderer()-&gt;scrollRectToVisible(SelectionRevealMode::Reveal, enclosingIntRect(rangeRect), ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
</del><ins>+            startNode-&gt;renderer()-&gt;scrollRectToVisible(SelectionRevealMode::Reveal, enclosingIntRect(rangeRect), insideFixed, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
</ins><span class="cx">             layer-&gt;setAdjustForIOSCaretWhenScrolling(false);
</span><span class="cx">             _private-&gt;coreFrame-&gt;selection().setCaretRectNeedsUpdate();
</span><span class="cx">             _private-&gt;coreFrame-&gt;selection().updateAppearance();
</span><span class="lines">@@ -733,6 +734,7 @@
</span><span class="cx"> #if PLATFORM(IOS)
</span><span class="cx"> - (void)_scrollDOMRangeToVisible:(DOMRange *)range withInset:(CGFloat)inset
</span><span class="cx"> {
</span><ins>+    bool insideFixed = false; // FIXME: get via firstRectForRange().
</ins><span class="cx">     NSRect rangeRect = NSInsetRect([self _firstRectForDOMRange:range], inset, inset);
</span><span class="cx">     Node *startNode = core([range startContainer]);
</span><span class="cx"> 
</span><span class="lines">@@ -740,7 +742,7 @@
</span><span class="cx">         RenderLayer* layer = startNode-&gt;renderer()-&gt;enclosingLayer();
</span><span class="cx">         if (layer) {
</span><span class="cx">             layer-&gt;setAdjustForIOSCaretWhenScrolling(true);
</span><del>-            startNode-&gt;renderer()-&gt;scrollRectToVisible(SelectionRevealMode::Reveal, enclosingIntRect(rangeRect), ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
</del><ins>+            startNode-&gt;renderer()-&gt;scrollRectToVisible(SelectionRevealMode::Reveal, enclosingIntRect(rangeRect), insideFixed, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
</ins><span class="cx">             layer-&gt;setAdjustForIOSCaretWhenScrolling(false);
</span><span class="cx"> 
</span><span class="cx">             Frame *coreFrame = core(self);
</span></span></pre>
</div>
</div>

</body>
</html>