Title: [209299] trunk
Revision
209299
Author
simon.fra...@apple.com
Date
2016-12-03 10:33:54 -0800 (Sat, 03 Dec 2016)

Log Message

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 "insideFixed" 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:

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (209298 => 209299)


--- trunk/LayoutTests/ChangeLog	2016-12-03 17:37:46 UTC (rev 209298)
+++ trunk/LayoutTests/ChangeLog	2016-12-03 18:33:54 UTC (rev 209299)
@@ -1,3 +1,16 @@
+2016-12-02  Simon Fraser  <simon.fra...@apple.com>
+
+        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:
+
 2016-11-30  Simon Fraser  <simon.fra...@apple.com>
 
         localToAbsolute() does incorrect conversion for elements inside position:fixed with zooming

Added: trunk/LayoutTests/fast/overflow/scroll-anchor-in-position-fixed-expected.txt (0 => 209299)


--- 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)
@@ -0,0 +1,11 @@
+Tests scrolling to an anchor inside position:fixed doesn't try to scroll the page
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS document.scrollingElement.scrollTop is 800
+PASS document.scrollingElement.scrollLeft is 100
+PASS successfullyParsed is true
+
+TEST COMPLETE
+Anchor is here

Added: trunk/LayoutTests/fast/overflow/scroll-anchor-in-position-fixed.html (0 => 209299)


--- 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)
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <style>
+        body {
+            height: 2000px;
+            width: 2000px;
+        }
+        
+        .fixed {
+            position: fixed;
+            top: 50px;
+            left: 40px;
+            border: 1px solid black;
+        }
+    </style>
+    <script src=""
+    <script>
+    description("Tests scrolling to an anchor inside position:fixed doesn't try to scroll the page");
+    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("#") == -1) {
+            setTimeout(finishTest, 0);
+            return;
+        }
+        
+        shouldBe('document.scrollingElement.scrollTop', '800');
+        shouldBe('document.scrollingElement.scrollLeft', '100');
+
+        finishJSTest();
+    }
+    </script>
+</head>
+<body _onload_="runTest()">
+
+<div class="fixed">
+    <a name="anchor">Anchor is here</a>
+</div>
+
+<script src=""
+
+</body></html>

Modified: trunk/LayoutTests/fast/transforms/selection-bounds-in-transformed-view.html (209298 => 209299)


--- 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)
@@ -10,6 +10,6 @@
         }
 
         document.execCommand("FindString", false, "target");
-        document.getElementById("result").innerText = document.body.scrollTop === 864 ? "PASS" : "FAIL";
+        document.getElementById("result").innerText = document.body.scrollTop === 937 ? "PASS" : "FAIL";
     </script>
 </body>

Added: trunk/LayoutTests/fast/visual-viewport/zoomed-scroll-into-view-fixed-expected.txt (0 => 209299)


--- 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)
@@ -0,0 +1,24 @@
+Tests revealing elements inside position:fixed after zooming.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Reveal "left-target"
+PASS document.scrollingElement.scrollTop is 838
+PASS document.scrollingElement.scrollLeft is 40
+
+Reveal "bottom-target"
+PASS document.scrollingElement.scrollTop is 1048
+PASS document.scrollingElement.scrollLeft is 40
+
+Reveal "right-target"
+PASS document.scrollingElement.scrollTop is 1086
+PASS document.scrollingElement.scrollLeft is 333
+
+Reveal "top-target"
+PASS document.scrollingElement.scrollTop is 834
+PASS document.scrollingElement.scrollLeft is 230
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/fast/visual-viewport/zoomed-scroll-into-view-fixed.html (0 => 209299)


--- 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)
@@ -0,0 +1,120 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <style>
+        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 > 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;
+        }
+    </style>
+    <script src=""
+    <script>
+
+    if (window.internals)
+        internals.settings.setVisualViewportEnabled(true);
+
+    description("Tests revealing elements inside position:fixed after zooming.");
+
+    window.jsTestIsAsync = true;
+
+    function runTest()
+    {
+        if (window.eventSender)
+            eventSender.scalePageBy(2);
+
+        window.scrollTo(300, 800);
+
+        debug('Reveal "left-target"');
+        document.getElementById('left-target').scrollIntoView();
+        shouldBe('document.scrollingElement.scrollTop', '838');
+        shouldBe('document.scrollingElement.scrollLeft', '40');
+
+        debug('');
+        debug('Reveal "bottom-target"');
+        document.getElementById('bottom-target').scrollIntoView();
+        shouldBe('document.scrollingElement.scrollTop', '1048');
+        shouldBe('document.scrollingElement.scrollLeft', '40');
+
+        debug('');
+        debug('Reveal "right-target"');
+        document.getElementById('right-target').scrollIntoView();
+        shouldBe('document.scrollingElement.scrollTop', '1086');
+        shouldBe('document.scrollingElement.scrollLeft', '333');
+
+        debug('');
+        debug('Reveal "top-target"');
+        document.getElementById('top-target').scrollIntoView();
+        shouldBe('document.scrollingElement.scrollTop', '834');
+        shouldBe('document.scrollingElement.scrollLeft', '230');
+        
+        finishJSTest();
+    }
+    </script>
+</head>
+<body _onload_="runTest()">
+
+<div class="left fixed">
+    <div id="left-target"></div>
+</div>
+
+<div class="right fixed">
+    <div id="right-target"></div>
+</div>
+
+<div class="top fixed">
+    <div id="top-target"></div>
+</div>
+
+<div class="bottom fixed">
+    <div id="bottom-target"></div>
+</div>
+
+<script src=""
+
+</body></html>

Added: trunk/LayoutTests/fast/visual-viewport/zoomed-scroll-to-anchor-in-position-fixed-expected.txt (0 => 209299)


--- 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)
@@ -0,0 +1,11 @@
+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 "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS document.scrollingElement.scrollTop is 559
+PASS document.scrollingElement.scrollLeft is 41
+PASS successfullyParsed is true
+
+TEST COMPLETE
+Anchor is here

Added: trunk/LayoutTests/fast/visual-viewport/zoomed-scroll-to-anchor-in-position-fixed.html (0 => 209299)


--- 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)
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <style>
+        body {
+            height: 2000px;
+            width: 2000px;
+        }
+        
+        .fixed {
+            position: fixed;
+            top: 50px;
+            left: 40px;
+            border: 1px solid black;
+        }
+    </style>
+    <script src=""
+    <script>
+
+    if (window.internals)
+        internals.settings.setVisualViewportEnabled(true);
+
+    description("Tests scrolling to an anchor inside position:fixed after zooming doesn't try to scroll the page");
+
+    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("#") == -1) {
+            setTimeout(finishTest, 0);
+            return;
+        }
+        
+        shouldBe('document.scrollingElement.scrollTop', '559');
+        shouldBe('document.scrollingElement.scrollLeft', '41');
+
+        finishJSTest();
+    }
+    </script>
+</head>
+<body _onload_="runTest()">
+
+<div class="fixed">
+    <a name="anchor">Anchor is here</a>
+</div>
+
+<script src=""
+
+</body></html>

Modified: trunk/LayoutTests/platform/ios-simulator/TestExpectations (209298 => 209299)


--- 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)
@@ -2767,3 +2767,5 @@
 
 # Test relies on window.scrollTo
 fast/zooming/client-rect-in-fixed-zoomed.html [ Skip ]
+fast/visual-viewport/zoomed-scroll-to-anchor-in-position-fixed.html [ Skip ]
+fast/visual-viewport/zoomed-scroll-into-view-fixed.html [ Skip ]

Modified: trunk/Source/WebCore/ChangeLog (209298 => 209299)


--- 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)
@@ -1,3 +1,68 @@
+2016-12-02  Simon Fraser  <simon.fra...@apple.com>
+
+        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 "insideFixed" 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:
+
 2016-11-30  Simon Fraser  <simon.fra...@apple.com>
 
         localToAbsolute() does incorrect conversion for elements inside position:fixed with zooming

Modified: trunk/Source/WebCore/dom/Element.cpp (209298 => 209299)


--- 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)
@@ -649,12 +649,13 @@
     if (!renderer())
         return;
 
-    LayoutRect bounds = renderer()->anchorRect();
+    bool insideFixed;
+    LayoutRect absoluteBounds = renderer()->absoluteAnchorRect(&insideFixed);
     // Align to the top / bottom and to the closest edge.
     if (alignToTop)
-        renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
+        renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, absoluteBounds, insideFixed, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
     else
-        renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignBottomAlways);
+        renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, absoluteBounds, insideFixed, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignBottomAlways);
 }
 
 void Element::scrollIntoViewIfNeeded(bool centerIfNeeded)
@@ -664,11 +665,12 @@
     if (!renderer())
         return;
 
-    LayoutRect bounds = renderer()->anchorRect();
+    bool insideFixed;
+    LayoutRect absoluteBounds = renderer()->absoluteAnchorRect(&insideFixed);
     if (centerIfNeeded)
-        renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, bounds, ScrollAlignment::alignCenterIfNeeded, ScrollAlignment::alignCenterIfNeeded);
+        renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, absoluteBounds, insideFixed, ScrollAlignment::alignCenterIfNeeded, ScrollAlignment::alignCenterIfNeeded);
     else
-        renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
+        renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, absoluteBounds, insideFixed, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
 }
 
 void Element::scrollIntoViewIfNotVisible(bool centerIfNotVisible)
@@ -678,11 +680,12 @@
     if (!renderer())
         return;
     
-    LayoutRect bounds = renderer()->anchorRect();
+    bool insideFixed;
+    LayoutRect absoluteBounds = renderer()->absoluteAnchorRect(&insideFixed);
     if (centerIfNotVisible)
-        renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, bounds, ScrollAlignment::alignCenterIfNotVisible, ScrollAlignment::alignCenterIfNotVisible);
+        renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, absoluteBounds, insideFixed, ScrollAlignment::alignCenterIfNotVisible, ScrollAlignment::alignCenterIfNotVisible);
     else
-        renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, bounds, ScrollAlignment::alignToEdgeIfNotVisible, ScrollAlignment::alignToEdgeIfNotVisible);
+        renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, absoluteBounds, insideFixed, ScrollAlignment::alignToEdgeIfNotVisible, ScrollAlignment::alignToEdgeIfNotVisible);
 }
 
 void Element::scrollBy(const ScrollToOptions& options)
@@ -2426,8 +2429,11 @@
             frame->selection().setSelection(newSelection, FrameSelection::defaultSetSelectionOptions(), Element::defaultFocusTextStateChangeIntent());
             frame->selection().revealSelection(revealMode);
         }
-    } else if (renderer() && !renderer()->isWidget())
-        renderer()->scrollRectToVisible(revealMode, renderer()->anchorRect());
+    } else if (renderer() && !renderer()->isWidget()) {
+        bool insideFixed;
+        LayoutRect absoluteBounds = renderer()->absoluteAnchorRect(&insideFixed);
+        renderer()->scrollRectToVisible(revealMode, absoluteBounds, insideFixed);
+    }
 }
 
 void Element::blur()

Modified: trunk/Source/WebCore/editing/FrameSelection.cpp (209298 => 209299)


--- 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)
@@ -112,6 +112,7 @@
     , m_xPosForVerticalArrowNavigation(NoXPosForVerticalArrowNavigation())
     , m_granularity(CharacterGranularity)
     , m_caretBlinkTimer(*this, &FrameSelection::caretBlinkTimerFired)
+    , m_caretInsidePositionFixed(false)
     , m_absCaretBoundsDirty(true)
     , m_caretPaint(true)
     , m_isCaretBlinkingSuspended(false)
@@ -1577,12 +1578,14 @@
     return selection.isCaret() && !selection.start().isOrphan() && !selection.end().isOrphan();
 }
 
-IntRect FrameSelection::absoluteCaretBounds()
+IntRect FrameSelection::absoluteCaretBounds(bool* insideFixed)
 {
     if (!m_frame)
         return IntRect();
     updateSelectionByUpdatingLayoutOrStyle(*m_frame);
     recomputeCaretRect();
+    if (insideFixed)
+        *insideFixed = m_caretInsidePositionFixed;
     return m_absCaretBounds;
 }
 
@@ -1624,7 +1627,9 @@
         return false;
 
     IntRect oldAbsCaretBounds = m_absCaretBounds;
-    m_absCaretBounds = absoluteBoundsForLocalCaretRect(rendererForCaretPainting(caretNode.get()), newRect);
+    bool isInsideFixed;
+    m_absCaretBounds = absoluteBoundsForLocalCaretRect(rendererForCaretPainting(caretNode.get()), newRect, &isInsideFixed);
+    m_caretInsidePositionFixed = isInsideFixed;
 
     if (m_absCaretBoundsDirty && m_selection.isCaret()) // We should be able to always assert this condition.
         ASSERT(m_absCaretBounds == m_selection.visibleStart().absoluteCaretBounds());
@@ -2300,12 +2305,12 @@
         return;
 
     LayoutRect rect;
-
+    bool insideFixed = false;
     switch (m_selection.selectionType()) {
     case VisibleSelection::NoSelection:
         return;
     case VisibleSelection::CaretSelection:
-        rect = absoluteCaretBounds();
+        rect = absoluteCaretBounds(&insideFixed);
         break;
     case VisibleSelection::RangeSelection:
         rect = revealExtentOption == RevealExtent ? VisiblePosition(m_selection.extent()).absoluteCaretBounds() : enclosingIntRect(selectionBounds(false));
@@ -2319,7 +2324,7 @@
         if (RenderLayer* layer = start.deprecatedNode()->renderer()->enclosingLayer()) {
             if (!m_scrollingSuppressCount) {
                 layer->setAdjustForIOSCaretWhenScrolling(true);
-                layer->scrollRectToVisible(revealMode, rect, alignment, alignment);
+                layer->scrollRectToVisible(revealMode, rect, insideFixed, alignment, alignment);
                 layer->setAdjustForIOSCaretWhenScrolling(false);
                 updateAppearance();
                 if (m_frame->page())
@@ -2330,7 +2335,7 @@
         // FIXME: This code only handles scrolling the startContainer's layer, but
         // the selection rect could intersect more than just that.
         // See <rdar://problem/4799899>.
-        if (start.deprecatedNode()->renderer()->scrollRectToVisible(revealMode, rect, alignment, alignment))
+        if (start.deprecatedNode()->renderer()->scrollRectToVisible(revealMode, rect, insideFixed, alignment, alignment))
             updateAppearance();
 #endif
     }

Modified: trunk/Source/WebCore/editing/FrameSelection.h (209298 => 209299)


--- 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)
@@ -173,7 +173,7 @@
     RenderBlock* caretRendererWithoutUpdatingLayout() const;
 
     // Bounds of (possibly transformed) caret in absolute coords
-    WEBCORE_EXPORT IntRect absoluteCaretBounds();
+    WEBCORE_EXPORT IntRect absoluteCaretBounds(bool* insideFixed = nullptr);
     void setCaretRectNeedsUpdate() { CaretBase::setCaretRectNeedsUpdate(); }
 
     void willBeModified(EAlteration, SelectionDirection);
@@ -336,6 +336,7 @@
     Timer m_caretBlinkTimer;
     // The painted bounds of the caret in absolute coordinates
     IntRect m_absCaretBounds;
+    bool m_caretInsidePositionFixed : 1;
     bool m_absCaretBoundsDirty : 1;
     bool m_caretPaint : 1;
     bool m_isCaretBlinkingSuspended : 1;

Modified: trunk/Source/WebCore/editing/VisiblePosition.cpp (209298 => 209299)


--- 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)
@@ -660,11 +660,11 @@
     return renderer->localCaretRect(inlineBox, caretOffset);
 }
 
-IntRect VisiblePosition::absoluteCaretBounds() const
+IntRect VisiblePosition::absoluteCaretBounds(bool* insideFixed) const
 {
     RenderBlock* renderer = nullptr;
     LayoutRect localRect = localCaretRectInRendererForCaretPainting(*this, renderer);
-    return absoluteBoundsForLocalCaretRect(renderer, localRect);
+    return absoluteBoundsForLocalCaretRect(renderer, localRect, insideFixed);
 }
 
 int VisiblePosition::lineDirectionPointForBlockDirectionNavigation() const

Modified: trunk/Source/WebCore/editing/VisiblePosition.h (209298 => 209299)


--- 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)
@@ -95,7 +95,7 @@
     // Rect is local to the returned renderer
     WEBCORE_EXPORT LayoutRect localCaretRect(RenderObject*&) const;
     // Bounds of (possibly transformed) caret in absolute coords
-    WEBCORE_EXPORT IntRect absoluteCaretBounds() const;
+    WEBCORE_EXPORT IntRect absoluteCaretBounds(bool* insideFixed = nullptr) const;
     // Abs x/y position of the caret ignoring transforms.
     // FIXME: navigation with transforms should be smarter.
     WEBCORE_EXPORT int lineDirectionPointForBlockDirectionNavigation() const;

Modified: trunk/Source/WebCore/editing/htmlediting.cpp (209298 => 209299)


--- 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)
@@ -1290,7 +1290,7 @@
     return localRect;
 }
 
-IntRect absoluteBoundsForLocalCaretRect(RenderBlock* rendererForCaretPainting, const LayoutRect& rect)
+IntRect absoluteBoundsForLocalCaretRect(RenderBlock* rendererForCaretPainting, const LayoutRect& rect, bool* insideFixed)
 {
     if (!rendererForCaretPainting || rect.isEmpty())
         return IntRect();
@@ -1297,7 +1297,7 @@
 
     LayoutRect localRect(rect);
     rendererForCaretPainting->flipForWritingMode(localRect);
-    return rendererForCaretPainting->localToAbsoluteQuad(FloatRect(localRect)).enclosingBoundingBox();
+    return rendererForCaretPainting->localToAbsoluteQuad(FloatRect(localRect), UseTransforms, insideFixed).enclosingBoundingBox();
 }
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/editing/htmlediting.h (209298 => 209299)


--- 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)
@@ -200,7 +200,7 @@
 RenderBlock* rendererForCaretPainting(Node*);
 LayoutRect localCaretRectInRendererForCaretPainting(const VisiblePosition&, RenderBlock*&);
 LayoutRect localCaretRectInRendererForRect(LayoutRect&, Node*, RenderObject*, RenderBlock*&);
-IntRect absoluteBoundsForLocalCaretRect(RenderBlock* rendererForCaretPainting, const LayoutRect&);
+IntRect absoluteBoundsForLocalCaretRect(RenderBlock* rendererForCaretPainting, const LayoutRect&, bool* insideFixed = nullptr);
 
 // -------------------------------------------------------------------------
 

Modified: trunk/Source/WebCore/page/FrameView.cpp (209298 => 209299)


--- 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)
@@ -2351,7 +2351,7 @@
 
     LayoutRect bounds;
     if (RenderElement* renderer = element.renderer())
-        bounds = renderer->anchorRect();
+        bounds = renderer->absoluteAnchorRect();
     int centeringOffsetX = (rect.width() - bounds.width()) / 2;
     int centeringOffsetY = (rect.height() - bounds.height()) / 2;
     setScrollPosition(IntPoint(bounds.x() - centeringOffsetX - rect.x(), bounds.y() - centeringOffsetY - rect.y()));
@@ -3271,17 +3271,18 @@
         return;
 
     LayoutRect rect;
+    bool insideFixed = false;
     if (anchorNode != frame().document() && anchorNode->renderer())
-        rect = anchorNode->renderer()->anchorRect();
+        rect = anchorNode->renderer()->absoluteAnchorRect(&insideFixed);
 
     // Scroll nested layers and frames to reveal the anchor.
     // Align to the top and to the closest side (this matches other browsers).
     if (anchorNode->renderer()->style().isHorizontalWritingMode())
-        anchorNode->renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, rect, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
+        anchorNode->renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, rect, insideFixed, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
     else if (anchorNode->renderer()->style().isFlippedBlocksWritingMode())
-        anchorNode->renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, rect, ScrollAlignment::alignRightAlways, ScrollAlignment::alignToEdgeIfNeeded);
+        anchorNode->renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, rect, insideFixed, ScrollAlignment::alignRightAlways, ScrollAlignment::alignToEdgeIfNeeded);
     else
-        anchorNode->renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, rect, ScrollAlignment::alignLeftAlways, ScrollAlignment::alignToEdgeIfNeeded);
+        anchorNode->renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, rect, insideFixed, ScrollAlignment::alignLeftAlways, ScrollAlignment::alignToEdgeIfNeeded);
 
     if (AXObjectCache* cache = frame().document()->existingAXObjectCache())
         cache->handleScrolledToAnchor(anchorNode.get());

Modified: trunk/Source/WebCore/page/PrintContext.cpp (209298 => 209299)


--- 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)
@@ -274,7 +274,7 @@
         if (!renderer)
             continue;
 
-        FloatPoint point = renderer->anchorRect().minXMinYCorner();
+        FloatPoint point = renderer->absoluteAnchorRect().minXMinYCorner();
         point.expandedTo(FloatPoint());
 
         if (!pageRect.contains(roundedIntPoint(point)))

Modified: trunk/Source/WebCore/rendering/RenderElement.cpp (209298 => 209299)


--- 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)
@@ -1625,10 +1625,10 @@
     return theme().inactiveSelectionBackgroundColor();
 }
 
-bool RenderElement::getLeadingCorner(FloatPoint& point) const
+bool RenderElement::getLeadingCorner(FloatPoint& point, bool& insideFixed) const
 {
     if (!isInline() || isReplaced()) {
-        point = localToAbsolute(FloatPoint(), UseTransforms);
+        point = localToAbsolute(FloatPoint(), UseTransforms, &insideFixed);
         return true;
     }
 
@@ -1654,7 +1654,7 @@
         ASSERT(o);
 
         if (!o->isInline() || o->isReplaced()) {
-            point = o->localToAbsolute(FloatPoint(), UseTransforms);
+            point = o->localToAbsolute(FloatPoint(), UseTransforms, &insideFixed);
             return true;
         }
 
@@ -1666,7 +1666,7 @@
                 point.move(downcast<RenderText>(*o).linesBoundingBox().x(), downcast<RenderText>(*o).topOfFirstText());
             else if (is<RenderBox>(*o))
                 point.moveBy(downcast<RenderBox>(*o).location());
-            point = o->container()->localToAbsolute(point, UseTransforms);
+            point = o->container()->localToAbsolute(point, UseTransforms, &insideFixed);
             return true;
         }
     }
@@ -1680,10 +1680,10 @@
     return false;
 }
 
-bool RenderElement::getTrailingCorner(FloatPoint& point) const
+bool RenderElement::getTrailingCorner(FloatPoint& point, bool& insideFixed) const
 {
     if (!isInline() || isReplaced()) {
-        point = localToAbsolute(LayoutPoint(downcast<RenderBox>(*this).size()), UseTransforms);
+        point = localToAbsolute(LayoutPoint(downcast<RenderBox>(*this).size()), UseTransforms, &insideFixed);
         return true;
     }
 
@@ -1714,7 +1714,7 @@
                 point.moveBy(linesBox.maxXMaxYCorner());
             } else
                 point.moveBy(downcast<RenderBox>(*o).frameRect().maxXMaxYCorner());
-            point = o->container()->localToAbsolute(point, UseTransforms);
+            point = o->container()->localToAbsolute(point, UseTransforms, &insideFixed);
             return true;
         }
     }
@@ -1721,11 +1721,13 @@
     return true;
 }
 
-LayoutRect RenderElement::anchorRect() const
+LayoutRect RenderElement::absoluteAnchorRect(bool* insideFixed) const
 {
     FloatPoint leading, trailing;
-    getLeadingCorner(leading);
-    getTrailingCorner(trailing);
+    bool leadingInFixed = false;
+    bool trailingInFixed = false;
+    getLeadingCorner(leading, leadingInFixed);
+    getTrailingCorner(trailing, trailingInFixed);
 
     FloatPoint upperLeft = leading;
     FloatPoint lowerRight = trailing;
@@ -1736,6 +1738,11 @@
         lowerRight = FloatPoint(std::max(leading.x(), trailing.x()), std::max(leading.y(), trailing.y()));
     } // Otherwise, it's not obvious what to do.
 
+    if (insideFixed) {
+        // For now, just look at the leading corner. Handling one inside fixed and one not would be tricky.
+        *insideFixed = leadingInFixed;
+    }
+
     return enclosingLayoutRect(FloatRect(upperLeft, lowerRight.expandedTo(upperLeft) - upperLeft));
 }
 

Modified: trunk/Source/WebCore/rendering/RenderElement.h (209298 => 209299)


--- 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)
@@ -164,7 +164,7 @@
     // anchorRect() is conceptually similar to absoluteBoundingBoxRect(), but is intended for scrolling to an anchor.
     // For inline renderers, this gets the logical top left of the first leaf child and the logical bottom right of the
     // last leaf child, converts them to absolute coordinates, and makes a box out of them.
-    LayoutRect anchorRect() const;
+    LayoutRect absoluteAnchorRect(bool* insideFixed = nullptr) const;
 
     bool hasFilter() const { return style().hasFilter(); }
     bool hasBackdropFilter() const
@@ -307,8 +307,8 @@
 
     void newImageAnimationFrameAvailable(CachedImage&) final;
 
-    bool getLeadingCorner(FloatPoint& output) const;
-    bool getTrailingCorner(FloatPoint& output) const;
+    bool getLeadingCorner(FloatPoint& output, bool& insideFixed) const;
+    bool getTrailingCorner(FloatPoint& output, bool& insideFixed) const;
 
     void clearLayoutRootIfNeeded() const;
     

Modified: trunk/Source/WebCore/rendering/RenderLayer.cpp (209298 => 209299)


--- 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)
@@ -2506,12 +2506,12 @@
     return box->hasHorizontalOverflow() || box->hasVerticalOverflow();
 }
 
-void RenderLayer::scrollRectToVisible(SelectionRevealMode revealMode, const LayoutRect& rect, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
+void RenderLayer::scrollRectToVisible(SelectionRevealMode revealMode, const LayoutRect& absoluteRect, bool insideFixed, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
 {
-    LOG_WITH_STREAM(Scrolling, stream << "Layer " << this << " scrollRectToVisible " << rect);
+    LOG_WITH_STREAM(Scrolling, stream << "Layer " << this << " scrollRectToVisible " << absoluteRect);
 
     RenderLayer* parentLayer = nullptr;
-    LayoutRect newRect = rect;
+    LayoutRect newRect = absoluteRect;
 
     // We may end up propagating a scroll event. It is important that we suspend events until 
     // the end of the function since they could delete the layer or the layer's renderer().
@@ -2525,11 +2525,11 @@
         // This will prevent us from revealing text hidden by the slider in Safari RSS.
         RenderBox* box = renderBox();
         ASSERT(box);
-        LayoutRect localExposeRect(box->absoluteToLocalQuad(FloatQuad(FloatRect(rect))).boundingBox());
+        LayoutRect localExposeRect(box->absoluteToLocalQuad(FloatQuad(FloatRect(absoluteRect))).boundingBox());
         LayoutRect layerBounds(0, 0, box->clientWidth(), box->clientHeight());
-        LayoutRect r = getRectToExpose(layerBounds, layerBounds, localExposeRect, alignX, alignY);
+        LayoutRect revealRect = getRectToExpose(layerBounds, layerBounds, localExposeRect, insideFixed, alignX, alignY);
 
-        ScrollOffset clampedScrollOffset = clampScrollOffset(scrollOffset() + toIntSize(roundedIntRect(r).location()));
+        ScrollOffset clampedScrollOffset = clampScrollOffset(scrollOffset() + toIntSize(roundedIntRect(revealRect).location()));
         if (clampedScrollOffset != scrollOffset()) {
             ScrollOffset oldScrollOffset = scrollOffset();
             scrollToOffset(clampedScrollOffset);
@@ -2551,7 +2551,7 @@
                 NoEventDispatchAssertion assertNoEventDispatch;
 
                 LayoutRect viewRect = frameView.visibleContentRect(LegacyIOSDocumentVisibleRect);
-                LayoutRect exposeRect = getRectToExpose(viewRect, viewRect, rect, alignX, alignY);
+                LayoutRect exposeRect = getRectToExpose(viewRect, viewRect, absoluteRect, insideFixed, alignX, alignY);
 
                 IntPoint scrollOffset(roundedIntPoint(exposeRect.location()));
                 // Adjust offsets if they're outside of the allowable range.
@@ -2562,6 +2562,7 @@
                     parentLayer = ownerElement->renderer()->enclosingLayer();
                     // Convert the rect into the coordinate space of the parent frame's document.
                     newRect = frameView.contentsToContainingViewContents(enclosingIntRect(newRect));
+                    insideFixed = false; // FIXME: ideally need to determine if this <iframe> is inside position:fixed.
                 } else
                     parentLayer = nullptr;
             }
@@ -2571,6 +2572,8 @@
 
 #if !PLATFORM(IOS)
             LayoutRect viewRect = frameView.visibleContentRect();
+            viewRect.scale(1 / frameView.frameScaleFactor());
+
             LayoutRect visibleRectRelativeToDocument = viewRect;
             visibleRectRelativeToDocument.setLocation(frameView.documentScrollPositionRelativeToScrollableAreaOrigin());
 #else
@@ -2577,10 +2580,9 @@
             LayoutRect viewRect = frameView.unobscuredContentRect();
             LayoutRect visibleRectRelativeToDocument = viewRect;
 #endif
-
-            LayoutRect r = getRectToExpose(viewRect, visibleRectRelativeToDocument, rect, alignX, alignY);
+            LayoutRect revealRect = getRectToExpose(viewRect, visibleRectRelativeToDocument, absoluteRect, insideFixed, alignX, alignY);
                 
-            frameView.setScrollPosition(roundedIntPoint(r.location()));
+            frameView.setScrollPosition(roundedIntPoint(revealRect.location()));
 
             // This is the outermost view of a web page, so after scrolling this view we
             // scroll its container by calling Page::scrollRectIntoView.
@@ -2588,12 +2590,12 @@
             // that put web views into scrolling containers, such as Mac OS X Mail.
             // The canAutoscroll function in EventHandler also knows about this.
             if (Page* page = frameView.frame().page())
-                page->chrome().scrollRectIntoView(snappedIntRect(rect));
+                page->chrome().scrollRectIntoView(snappedIntRect(absoluteRect));
         }
     }
     
     if (parentLayer)
-        parentLayer->scrollRectToVisible(revealMode, newRect, alignX, alignY);
+        parentLayer->scrollRectToVisible(revealMode, newRect, insideFixed, alignX, alignY);
 }
 
 void RenderLayer::updateCompositingLayersAfterScroll()
@@ -2610,8 +2612,35 @@
     }
 }
 
-LayoutRect RenderLayer::getRectToExpose(const LayoutRect &visibleRect, const LayoutRect &visibleRectRelativeToDocument, const LayoutRect &exposeRect, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
+LayoutRect RenderLayer::getRectToExpose(const LayoutRect &visibleRect, const LayoutRect &visibleRectRelativeToDocument, const LayoutRect &exposeRect, bool insideFixed, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
 {
+    FrameView& 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;
+        }
+    }
+
     // Determine the appropriate X behavior.
     ScrollAlignment::Behavior scrollX;
     LayoutRect exposeRectX(exposeRect.x(), visibleRect.y(), exposeRect.width(), visibleRect.height());
@@ -2686,7 +2715,7 @@
 void RenderLayer::autoscroll(const IntPoint& position)
 {
     IntPoint currentDocumentPosition = renderer().view().frameView().windowToContents(position);
-    scrollRectToVisible(SelectionRevealMode::Reveal, LayoutRect(currentDocumentPosition, LayoutSize(1, 1)), ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
+    scrollRectToVisible(SelectionRevealMode::Reveal, LayoutRect(currentDocumentPosition, LayoutSize(1, 1)), false, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
 }
 
 bool RenderLayer::canResize() const

Modified: trunk/Source/WebCore/rendering/RenderLayer.h (209298 => 209299)


--- 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)
@@ -204,9 +204,9 @@
 
     void availableContentSizeChanged(AvailableSizeChangeReason) override;
 
-    void scrollRectToVisible(SelectionRevealMode, const LayoutRect&, const ScrollAlignment& alignX, const ScrollAlignment& alignY);
+    void scrollRectToVisible(SelectionRevealMode, const LayoutRect& absoluteRect, bool insideFixed, const ScrollAlignment& alignX, const ScrollAlignment& alignY);
 
-    LayoutRect getRectToExpose(const LayoutRect& visibleRect, const LayoutRect& visibleRectRelativeToDocument, const LayoutRect& exposeRect, const ScrollAlignment& alignX, const ScrollAlignment& alignY);
+    LayoutRect getRectToExpose(const LayoutRect& visibleRect, const LayoutRect& visibleRectRelativeToDocument, const LayoutRect& exposeRect, bool insideFixed, const ScrollAlignment& alignX, const ScrollAlignment& alignY);
 
     bool scrollsOverflow() const;
     bool hasScrollbars() const { return m_hBar || m_vBar; }

Modified: trunk/Source/WebCore/rendering/RenderObject.cpp (209298 => 209299)


--- 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)
@@ -396,7 +396,7 @@
     return nullptr;
 }
 
-bool RenderObject::scrollRectToVisible(SelectionRevealMode revealMode, const LayoutRect& rect, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
+bool RenderObject::scrollRectToVisible(SelectionRevealMode revealMode, const LayoutRect& absoluteRect, bool insideFixed, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
 {
     if (revealMode == SelectionRevealMode::DoNotReveal)
         return false;
@@ -405,7 +405,7 @@
     if (!enclosingLayer)
         return false;
 
-    enclosingLayer->scrollRectToVisible(revealMode, rect, alignX, alignY);
+    enclosingLayer->scrollRectToVisible(revealMode, absoluteRect, insideFixed, alignX, alignY);
     return true;
 }
 

Modified: trunk/Source/WebCore/rendering/RenderObject.h (209298 => 209299)


--- 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)
@@ -154,7 +154,7 @@
     WEBCORE_EXPORT RenderLayer* enclosingLayer() const;
 
     // Scrolling is a RenderBox concept, however some code just cares about recursively scrolling our enclosing ScrollableArea(s).
-    WEBCORE_EXPORT bool scrollRectToVisible(SelectionRevealMode, const LayoutRect&, const ScrollAlignment& alignX = ScrollAlignment::alignCenterIfNeeded, const ScrollAlignment& alignY = ScrollAlignment::alignCenterIfNeeded);
+    WEBCORE_EXPORT bool scrollRectToVisible(SelectionRevealMode, const LayoutRect& absoluteRect, bool insideFixed, const ScrollAlignment& alignX = ScrollAlignment::alignCenterIfNeeded, const ScrollAlignment& alignY = ScrollAlignment::alignCenterIfNeeded);
 
     // Convenience function for getting to the nearest enclosing box of a RenderObject.
     WEBCORE_EXPORT RenderBox& enclosingBox() const;

Modified: trunk/Source/WebKit/mac/ChangeLog (209298 => 209299)


--- 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)
@@ -1,3 +1,17 @@
+2016-12-02  Simon Fraser  <simon.fra...@apple.com>
+
+        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:]):
+
 2016-12-02  Andy Estes  <aes...@apple.com>
 
         [Cocoa] Adopt the PRODUCT_BUNDLE_IDENTIFIER build setting

Modified: trunk/Source/WebKit/mac/WebView/WebFrame.mm (209298 => 209299)


--- 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)
@@ -711,17 +711,18 @@
 
 - (void)_scrollDOMRangeToVisible:(DOMRange *)range
 {
+    bool insideFixed = false; // FIXME: get via firstRectForRange().
     NSRect rangeRect = [self _firstRectForDOMRange:range];    
     Node *startNode = core([range startContainer]);
         
     if (startNode && startNode->renderer()) {
 #if !PLATFORM(IOS)
-        startNode->renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, enclosingIntRect(rangeRect), ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
+        startNode->renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, enclosingIntRect(rangeRect), insideFixed, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
 #else
         RenderLayer* layer = startNode->renderer()->enclosingLayer();
         if (layer) {
             layer->setAdjustForIOSCaretWhenScrolling(true);
-            startNode->renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, enclosingIntRect(rangeRect), ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
+            startNode->renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, enclosingIntRect(rangeRect), insideFixed, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
             layer->setAdjustForIOSCaretWhenScrolling(false);
             _private->coreFrame->selection().setCaretRectNeedsUpdate();
             _private->coreFrame->selection().updateAppearance();
@@ -733,6 +734,7 @@
 #if PLATFORM(IOS)
 - (void)_scrollDOMRangeToVisible:(DOMRange *)range withInset:(CGFloat)inset
 {
+    bool insideFixed = false; // FIXME: get via firstRectForRange().
     NSRect rangeRect = NSInsetRect([self _firstRectForDOMRange:range], inset, inset);
     Node *startNode = core([range startContainer]);
 
@@ -740,7 +742,7 @@
         RenderLayer* layer = startNode->renderer()->enclosingLayer();
         if (layer) {
             layer->setAdjustForIOSCaretWhenScrolling(true);
-            startNode->renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, enclosingIntRect(rangeRect), ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
+            startNode->renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, enclosingIntRect(rangeRect), insideFixed, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
             layer->setAdjustForIOSCaretWhenScrolling(false);
 
             Frame *coreFrame = core(self);
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to