Changeset 209411 in webkit


Ignore:
Timestamp:
Dec 6, 2016 12:00:28 PM (7 years ago)
Author:
Simon Fraser
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): Deleted.

  • 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/transforms/selection-bounds-in-transformed-view.html:
  • fast/visual-viewport/zoomed-scroll-into-view-fixed-expected.txt: Added.
  • fast/visual-viewport/zoomed-scroll-into-view-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:
Location:
trunk
Files:
6 added
21 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r209410 r209411  
     12016-12-05  Simon Fraser  <simon.fraser@apple.com>
     2
     3        Improve the behavior of scroll-into-view when the target is inside position:fixed
     4        https://bugs.webkit.org/show_bug.cgi?id=165354
     5
     6        Reviewed by Zalan Bujtas.
     7
     8        * fast/overflow/scroll-anchor-in-position-fixed-expected.txt: Added.
     9        * fast/overflow/scroll-anchor-in-position-fixed.html: Added.
     10        * fast/transforms/selection-bounds-in-transformed-view.html:
     11        * fast/visual-viewport/zoomed-scroll-into-view-fixed-expected.txt: Added.
     12        * fast/visual-viewport/zoomed-scroll-into-view-fixed.html: Added.
     13        * fast/visual-viewport/zoomed-scroll-to-anchor-in-position-fixed-expected.txt: Added.
     14        * fast/visual-viewport/zoomed-scroll-to-anchor-in-position-fixed.html: Added.
     15        * platform/ios-simulator/TestExpectations:
     16
    1172016-12-06  Myles C. Maxfield  <mmaxfield@apple.com>
    218
  • trunk/LayoutTests/fast/transforms/selection-bounds-in-transformed-view.html

    r209348 r209411  
    1111
    1212        document.execCommand("FindString", false, "target");
    13         document.getElementById("result").innerText = document.body.scrollTop === 864 ? "PASS" : "FAIL";
     13        document.getElementById("result").innerText = document.body.scrollTop === 937 ? "PASS" : "FAIL";
    1414    </script>
    1515</body>
  • trunk/LayoutTests/platform/ios-simulator/TestExpectations

    r209410 r209411  
    27372737# Test relies on window.scrollTo
    27382738fast/zooming/client-rect-in-fixed-zoomed.html [ Skip ]
     2739fast/visual-viewport/zoomed-scroll-to-anchor-in-position-fixed.html [ Skip ]
     2740fast/visual-viewport/zoomed-scroll-into-view-fixed.html [ Skip ]
    27392741
    27402742# This test relies on Arial being used to draw Arabic. However, on iOS,
  • trunk/Source/WebCore/ChangeLog

    r209410 r209411  
     12016-12-05  Simon Fraser  <simon.fraser@apple.com>
     2
     3        Improve the behavior of scroll-into-view when the target is inside position:fixed
     4        https://bugs.webkit.org/show_bug.cgi?id=165354
     5
     6        Reviewed by Zalan Bujtas.
     7       
     8        The existing RenderLayer::scrollRectToVisible() code paid no heed to whether the
     9        target was inside position:fixed, resulting in unwanted scrolls.
     10       
     11        Fix this by plumbing through from the call sites a "insideFixed" flag which we get
     12        when we call localToAbsolute(), and use this flag to avoid scrolling at all if
     13        unzoomed.
     14       
     15        If zoomed and we're focussing something inside position:fixed, and if visual viewports
     16        are enabled, we can compute the visual viewport required to reveal the target rect,
     17        which gives us the ideal scroll position.
     18       
     19        Fix a bug on non-iOS platforms when zoomed, which is to scale the viewRect since
     20        frameView.visibleContentRect() gives an unscaled rect on those platforms.
     21       
     22        Not all callers of scrollRectToVisible() are fixed, but those that are not will get
     23        the current behavior.
     24
     25        Tests: fast/overflow/scroll-anchor-in-position-fixed.html
     26               fast/visual-viewport/zoomed-scroll-into-view-fixed.html
     27               fast/visual-viewport/zoomed-scroll-to-anchor-in-position-fixed.html
     28
     29        * dom/Element.cpp:
     30        (WebCore::Element::scrollIntoView):
     31        (WebCore::Element::scrollIntoViewIfNeeded):
     32        (WebCore::Element::scrollIntoViewIfNotVisible):
     33        (WebCore::Element::updateFocusAppearance):
     34        * editing/FrameSelection.cpp:
     35        (WebCore::FrameSelection::FrameSelection):
     36        (WebCore::FrameSelection::absoluteCaretBounds):
     37        (WebCore::FrameSelection::recomputeCaretRect):
     38        (WebCore::FrameSelection::revealSelection):
     39        * editing/FrameSelection.h:
     40        * editing/VisiblePosition.cpp:
     41        (WebCore::VisiblePosition::absoluteCaretBounds):
     42        * editing/VisiblePosition.h:
     43        * editing/htmlediting.cpp:
     44        (WebCore::absoluteBoundsForLocalCaretRect):
     45        * editing/htmlediting.h:
     46        * page/FrameView.cpp:
     47        (WebCore::FrameView::scrollElementToRect):
     48        (WebCore::FrameView::scrollToAnchor):
     49        * page/PrintContext.cpp:
     50        (WebCore::PrintContext::outputLinkedDestinations):
     51        * rendering/RenderElement.cpp:
     52        (WebCore::RenderElement::getLeadingCorner):
     53        (WebCore::RenderElement::getTrailingCorner):
     54        (WebCore::RenderElement::absoluteAnchorRect):
     55        (WebCore::RenderElement::anchorRect): Deleted.
     56        * rendering/RenderElement.h:
     57        * rendering/RenderLayer.cpp:
     58        (WebCore::RenderLayer::scrollRectToVisible):
     59        (WebCore::RenderLayer::getRectToExpose):
     60        (WebCore::RenderLayer::autoscroll):
     61        * rendering/RenderLayer.h:
     62        * rendering/RenderObject.cpp:
     63        (WebCore::RenderObject::scrollRectToVisible):
     64        * rendering/RenderObject.h:
     65
    1662016-12-06  Myles C. Maxfield  <mmaxfield@apple.com>
    267
  • trunk/Source/WebCore/dom/Element.cpp

    r209394 r209411  
    650650        return;
    651651
    652     LayoutRect bounds = renderer()->anchorRect();
     652    bool insideFixed;
     653    LayoutRect absoluteBounds = renderer()->absoluteAnchorRect(&insideFixed);
    653654    // Align to the top / bottom and to the closest edge.
    654655    if (alignToTop)
    655         renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
     656        renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, absoluteBounds, insideFixed, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
    656657    else
    657         renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignBottomAlways);
     658        renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, absoluteBounds, insideFixed, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignBottomAlways);
    658659}
    659660
     
    665666        return;
    666667
    667     LayoutRect bounds = renderer()->anchorRect();
     668    bool insideFixed;
     669    LayoutRect absoluteBounds = renderer()->absoluteAnchorRect(&insideFixed);
    668670    if (centerIfNeeded)
    669         renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, bounds, ScrollAlignment::alignCenterIfNeeded, ScrollAlignment::alignCenterIfNeeded);
     671        renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, absoluteBounds, insideFixed, ScrollAlignment::alignCenterIfNeeded, ScrollAlignment::alignCenterIfNeeded);
    670672    else
    671         renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
     673        renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, absoluteBounds, insideFixed, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
    672674}
    673675
     
    679681        return;
    680682   
    681     LayoutRect bounds = renderer()->anchorRect();
     683    bool insideFixed;
     684    LayoutRect absoluteBounds = renderer()->absoluteAnchorRect(&insideFixed);
    682685    if (centerIfNotVisible)
    683         renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, bounds, ScrollAlignment::alignCenterIfNotVisible, ScrollAlignment::alignCenterIfNotVisible);
     686        renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, absoluteBounds, insideFixed, ScrollAlignment::alignCenterIfNotVisible, ScrollAlignment::alignCenterIfNotVisible);
    684687    else
    685         renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, bounds, ScrollAlignment::alignToEdgeIfNotVisible, ScrollAlignment::alignToEdgeIfNotVisible);
     688        renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, absoluteBounds, insideFixed, ScrollAlignment::alignToEdgeIfNotVisible, ScrollAlignment::alignToEdgeIfNotVisible);
    686689}
    687690
     
    24272430            frame->selection().revealSelection(revealMode);
    24282431        }
    2429     } else if (renderer() && !renderer()->isWidget())
    2430         renderer()->scrollRectToVisible(revealMode, renderer()->anchorRect());
     2432    } else if (renderer() && !renderer()->isWidget()) {
     2433        bool insideFixed;
     2434        LayoutRect absoluteBounds = renderer()->absoluteAnchorRect(&insideFixed);
     2435        renderer()->scrollRectToVisible(revealMode, absoluteBounds, insideFixed);
     2436    }
    24312437}
    24322438
  • trunk/Source/WebCore/editing/FrameSelection.cpp

    r209348 r209411  
    113113    , m_granularity(CharacterGranularity)
    114114    , m_caretBlinkTimer(*this, &FrameSelection::caretBlinkTimerFired)
     115    , m_caretInsidePositionFixed(false)
    115116    , m_absCaretBoundsDirty(true)
    116117    , m_caretPaint(true)
     
    15781579}
    15791580
    1580 IntRect FrameSelection::absoluteCaretBounds()
     1581IntRect FrameSelection::absoluteCaretBounds(bool* insideFixed)
    15811582{
    15821583    if (!m_frame)
     
    15841585    updateSelectionByUpdatingLayoutOrStyle(*m_frame);
    15851586    recomputeCaretRect();
     1587    if (insideFixed)
     1588        *insideFixed = m_caretInsidePositionFixed;
    15861589    return m_absCaretBounds;
    15871590}
     
    16251628
    16261629    IntRect oldAbsCaretBounds = m_absCaretBounds;
    1627     m_absCaretBounds = absoluteBoundsForLocalCaretRect(rendererForCaretPainting(caretNode.get()), newRect);
     1630    bool isInsideFixed;
     1631    m_absCaretBounds = absoluteBoundsForLocalCaretRect(rendererForCaretPainting(caretNode.get()), newRect, &isInsideFixed);
     1632    m_caretInsidePositionFixed = isInsideFixed;
    16281633
    16291634    if (m_absCaretBoundsDirty && m_selection.isCaret()) // We should be able to always assert this condition.
     
    23012306
    23022307    LayoutRect rect;
    2303 
     2308    bool insideFixed = false;
    23042309    switch (m_selection.selectionType()) {
    23052310    case VisibleSelection::NoSelection:
    23062311        return;
    23072312    case VisibleSelection::CaretSelection:
    2308         rect = absoluteCaretBounds();
     2313        rect = absoluteCaretBounds(&insideFixed);
    23092314        break;
    23102315    case VisibleSelection::RangeSelection:
     
    23202325            if (!m_scrollingSuppressCount) {
    23212326                layer->setAdjustForIOSCaretWhenScrolling(true);
    2322                 layer->scrollRectToVisible(revealMode, rect, alignment, alignment);
     2327                layer->scrollRectToVisible(revealMode, rect, insideFixed, alignment, alignment);
    23232328                layer->setAdjustForIOSCaretWhenScrolling(false);
    23242329                updateAppearance();
     
    23312336        // the selection rect could intersect more than just that.
    23322337        // See <rdar://problem/4799899>.
    2333         if (start.deprecatedNode()->renderer()->scrollRectToVisible(revealMode, rect, alignment, alignment))
     2338        if (start.deprecatedNode()->renderer()->scrollRectToVisible(revealMode, rect, insideFixed, alignment, alignment))
    23342339            updateAppearance();
    23352340#endif
  • trunk/Source/WebCore/editing/FrameSelection.h

    r209348 r209411  
    174174
    175175    // Bounds of (possibly transformed) caret in absolute coords
    176     WEBCORE_EXPORT IntRect absoluteCaretBounds();
     176    WEBCORE_EXPORT IntRect absoluteCaretBounds(bool* insideFixed = nullptr);
    177177    void setCaretRectNeedsUpdate() { CaretBase::setCaretRectNeedsUpdate(); }
    178178
     
    337337    // The painted bounds of the caret in absolute coordinates
    338338    IntRect m_absCaretBounds;
     339    bool m_caretInsidePositionFixed : 1;
    339340    bool m_absCaretBoundsDirty : 1;
    340341    bool m_caretPaint : 1;
  • trunk/Source/WebCore/editing/VisiblePosition.cpp

    r209348 r209411  
    661661}
    662662
    663 IntRect VisiblePosition::absoluteCaretBounds() const
     663IntRect VisiblePosition::absoluteCaretBounds(bool* insideFixed) const
    664664{
    665665    RenderBlock* renderer = nullptr;
    666666    LayoutRect localRect = localCaretRectInRendererForCaretPainting(*this, renderer);
    667     return absoluteBoundsForLocalCaretRect(renderer, localRect);
     667    return absoluteBoundsForLocalCaretRect(renderer, localRect, insideFixed);
    668668}
    669669
  • trunk/Source/WebCore/editing/VisiblePosition.h

    r209348 r209411  
    9696    WEBCORE_EXPORT LayoutRect localCaretRect(RenderObject*&) const;
    9797    // Bounds of (possibly transformed) caret in absolute coords
    98     WEBCORE_EXPORT IntRect absoluteCaretBounds() const;
     98    WEBCORE_EXPORT IntRect absoluteCaretBounds(bool* insideFixed = nullptr) const;
    9999    // Abs x/y position of the caret ignoring transforms.
    100100    // FIXME: navigation with transforms should be smarter.
  • trunk/Source/WebCore/editing/htmlediting.cpp

    r209348 r209411  
    12911291}
    12921292
    1293 IntRect absoluteBoundsForLocalCaretRect(RenderBlock* rendererForCaretPainting, const LayoutRect& rect)
     1293IntRect absoluteBoundsForLocalCaretRect(RenderBlock* rendererForCaretPainting, const LayoutRect& rect, bool* insideFixed)
    12941294{
    12951295    if (!rendererForCaretPainting || rect.isEmpty())
     
    12981298    LayoutRect localRect(rect);
    12991299    rendererForCaretPainting->flipForWritingMode(localRect);
    1300     return rendererForCaretPainting->localToAbsoluteQuad(FloatRect(localRect)).enclosingBoundingBox();
     1300    return rendererForCaretPainting->localToAbsoluteQuad(FloatRect(localRect), UseTransforms, insideFixed).enclosingBoundingBox();
    13011301}
    13021302
  • trunk/Source/WebCore/editing/htmlediting.h

    r209348 r209411  
    201201LayoutRect localCaretRectInRendererForCaretPainting(const VisiblePosition&, RenderBlock*&);
    202202LayoutRect localCaretRectInRendererForRect(LayoutRect&, Node*, RenderObject*, RenderBlock*&);
    203 IntRect absoluteBoundsForLocalCaretRect(RenderBlock* rendererForCaretPainting, const LayoutRect&);
     203IntRect absoluteBoundsForLocalCaretRect(RenderBlock* rendererForCaretPainting, const LayoutRect&, bool* insideFixed = nullptr);
    204204
    205205// -------------------------------------------------------------------------
  • trunk/Source/WebCore/page/FrameView.cpp

    r209409 r209411  
    23572357    LayoutRect bounds;
    23582358    if (RenderElement* renderer = element.renderer())
    2359         bounds = renderer->anchorRect();
     2359        bounds = renderer->absoluteAnchorRect();
    23602360    int centeringOffsetX = (rect.width() - bounds.width()) / 2;
    23612361    int centeringOffsetY = (rect.height() - bounds.height()) / 2;
     
    32773277
    32783278    LayoutRect rect;
     3279    bool insideFixed = false;
    32793280    if (anchorNode != frame().document() && anchorNode->renderer())
    3280         rect = anchorNode->renderer()->anchorRect();
     3281        rect = anchorNode->renderer()->absoluteAnchorRect(&insideFixed);
    32813282
    32823283    // Scroll nested layers and frames to reveal the anchor.
    32833284    // Align to the top and to the closest side (this matches other browsers).
    32843285    if (anchorNode->renderer()->style().isHorizontalWritingMode())
    3285         anchorNode->renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, rect, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
     3286        anchorNode->renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, rect, insideFixed, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
    32863287    else if (anchorNode->renderer()->style().isFlippedBlocksWritingMode())
    3287         anchorNode->renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, rect, ScrollAlignment::alignRightAlways, ScrollAlignment::alignToEdgeIfNeeded);
     3288        anchorNode->renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, rect, insideFixed, ScrollAlignment::alignRightAlways, ScrollAlignment::alignToEdgeIfNeeded);
    32883289    else
    3289         anchorNode->renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, rect, ScrollAlignment::alignLeftAlways, ScrollAlignment::alignToEdgeIfNeeded);
     3290        anchorNode->renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, rect, insideFixed, ScrollAlignment::alignLeftAlways, ScrollAlignment::alignToEdgeIfNeeded);
    32903291
    32913292    if (AXObjectCache* cache = frame().document()->existingAXObjectCache())
  • trunk/Source/WebCore/page/PrintContext.cpp

    r209348 r209411  
    275275            continue;
    276276
    277         FloatPoint point = renderer->anchorRect().minXMinYCorner();
     277        FloatPoint point = renderer->absoluteAnchorRect().minXMinYCorner();
    278278        point.expandedTo(FloatPoint());
    279279
  • trunk/Source/WebCore/rendering/RenderElement.cpp

    r209348 r209411  
    16261626}
    16271627
    1628 bool RenderElement::getLeadingCorner(FloatPoint& point) const
     1628bool RenderElement::getLeadingCorner(FloatPoint& point, bool& insideFixed) const
    16291629{
    16301630    if (!isInline() || isReplaced()) {
    1631         point = localToAbsolute(FloatPoint(), UseTransforms);
     1631        point = localToAbsolute(FloatPoint(), UseTransforms, &insideFixed);
    16321632        return true;
    16331633    }
     
    16551655
    16561656        if (!o->isInline() || o->isReplaced()) {
    1657             point = o->localToAbsolute(FloatPoint(), UseTransforms);
     1657            point = o->localToAbsolute(FloatPoint(), UseTransforms, &insideFixed);
    16581658            return true;
    16591659        }
     
    16671667            else if (is<RenderBox>(*o))
    16681668                point.moveBy(downcast<RenderBox>(*o).location());
    1669             point = o->container()->localToAbsolute(point, UseTransforms);
     1669            point = o->container()->localToAbsolute(point, UseTransforms, &insideFixed);
    16701670            return true;
    16711671        }
     
    16811681}
    16821682
    1683 bool RenderElement::getTrailingCorner(FloatPoint& point) const
     1683bool RenderElement::getTrailingCorner(FloatPoint& point, bool& insideFixed) const
    16841684{
    16851685    if (!isInline() || isReplaced()) {
    1686         point = localToAbsolute(LayoutPoint(downcast<RenderBox>(*this).size()), UseTransforms);
     1686        point = localToAbsolute(LayoutPoint(downcast<RenderBox>(*this).size()), UseTransforms, &insideFixed);
    16871687        return true;
    16881688    }
     
    17151715            } else
    17161716                point.moveBy(downcast<RenderBox>(*o).frameRect().maxXMaxYCorner());
    1717             point = o->container()->localToAbsolute(point, UseTransforms);
     1717            point = o->container()->localToAbsolute(point, UseTransforms, &insideFixed);
    17181718            return true;
    17191719        }
     
    17221722}
    17231723
    1724 LayoutRect RenderElement::anchorRect() const
     1724LayoutRect RenderElement::absoluteAnchorRect(bool* insideFixed) const
    17251725{
    17261726    FloatPoint leading, trailing;
    1727     getLeadingCorner(leading);
    1728     getTrailingCorner(trailing);
     1727    bool leadingInFixed = false;
     1728    bool trailingInFixed = false;
     1729    getLeadingCorner(leading, leadingInFixed);
     1730    getTrailingCorner(trailing, trailingInFixed);
    17291731
    17301732    FloatPoint upperLeft = leading;
     
    17361738        lowerRight = FloatPoint(std::max(leading.x(), trailing.x()), std::max(leading.y(), trailing.y()));
    17371739    } // Otherwise, it's not obvious what to do.
     1740
     1741    if (insideFixed) {
     1742        // For now, just look at the leading corner. Handling one inside fixed and one not would be tricky.
     1743        *insideFixed = leadingInFixed;
     1744    }
    17381745
    17391746    return enclosingLayoutRect(FloatRect(upperLeft, lowerRight.expandedTo(upperLeft) - upperLeft));
  • trunk/Source/WebCore/rendering/RenderElement.h

    r209348 r209411  
    165165    // For inline renderers, this gets the logical top left of the first leaf child and the logical bottom right of the
    166166    // last leaf child, converts them to absolute coordinates, and makes a box out of them.
    167     LayoutRect anchorRect() const;
     167    LayoutRect absoluteAnchorRect(bool* insideFixed = nullptr) const;
    168168
    169169    bool hasFilter() const { return style().hasFilter(); }
     
    308308    void newImageAnimationFrameAvailable(CachedImage&) final;
    309309
    310     bool getLeadingCorner(FloatPoint& output) const;
    311     bool getTrailingCorner(FloatPoint& output) const;
     310    bool getLeadingCorner(FloatPoint& output, bool& insideFixed) const;
     311    bool getTrailingCorner(FloatPoint& output, bool& insideFixed) const;
    312312
    313313    void clearLayoutRootIfNeeded() const;
  • trunk/Source/WebCore/rendering/RenderLayer.cpp

    r209348 r209411  
    25072507}
    25082508
    2509 void RenderLayer::scrollRectToVisible(SelectionRevealMode revealMode, const LayoutRect& rect, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
    2510 {
    2511     LOG_WITH_STREAM(Scrolling, stream << "Layer " << this << " scrollRectToVisible " << rect);
     2509void RenderLayer::scrollRectToVisible(SelectionRevealMode revealMode, const LayoutRect& absoluteRect, bool insideFixed, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
     2510{
     2511    LOG_WITH_STREAM(Scrolling, stream << "Layer " << this << " scrollRectToVisible " << absoluteRect);
    25122512
    25132513    RenderLayer* parentLayer = nullptr;
    2514     LayoutRect newRect = rect;
     2514    LayoutRect newRect = absoluteRect;
    25152515
    25162516    // We may end up propagating a scroll event. It is important that we suspend events until
     
    25262526        RenderBox* box = renderBox();
    25272527        ASSERT(box);
    2528         LayoutRect localExposeRect(box->absoluteToLocalQuad(FloatQuad(FloatRect(rect))).boundingBox());
     2528        LayoutRect localExposeRect(box->absoluteToLocalQuad(FloatQuad(FloatRect(absoluteRect))).boundingBox());
    25292529        LayoutRect layerBounds(0, 0, box->clientWidth(), box->clientHeight());
    2530         LayoutRect r = getRectToExpose(layerBounds, layerBounds, localExposeRect, alignX, alignY);
    2531 
    2532         ScrollOffset clampedScrollOffset = clampScrollOffset(scrollOffset() + toIntSize(roundedIntRect(r).location()));
     2530        LayoutRect revealRect = getRectToExpose(layerBounds, layerBounds, localExposeRect, insideFixed, alignX, alignY);
     2531
     2532        ScrollOffset clampedScrollOffset = clampScrollOffset(scrollOffset() + toIntSize(roundedIntRect(revealRect).location()));
    25332533        if (clampedScrollOffset != scrollOffset()) {
    25342534            ScrollOffset oldScrollOffset = scrollOffset();
     
    25522552
    25532553                LayoutRect viewRect = frameView.visibleContentRect(LegacyIOSDocumentVisibleRect);
    2554                 LayoutRect exposeRect = getRectToExpose(viewRect, viewRect, rect, alignX, alignY);
     2554                LayoutRect exposeRect = getRectToExpose(viewRect, viewRect, absoluteRect, insideFixed, alignX, alignY);
    25552555
    25562556                IntPoint scrollOffset(roundedIntPoint(exposeRect.location()));
     
    25632563                    // Convert the rect into the coordinate space of the parent frame's document.
    25642564                    newRect = frameView.contentsToContainingViewContents(enclosingIntRect(newRect));
     2565                    insideFixed = false; // FIXME: ideally need to determine if this <iframe> is inside position:fixed.
    25652566                } else
    25662567                    parentLayer = nullptr;
     
    25722573#if !PLATFORM(IOS)
    25732574            LayoutRect viewRect = frameView.visibleContentRect();
     2575            viewRect.scale(1 / frameView.frameScaleFactor());
     2576
    25742577            LayoutRect visibleRectRelativeToDocument = viewRect;
    25752578            visibleRectRelativeToDocument.setLocation(frameView.documentScrollPositionRelativeToScrollableAreaOrigin());
     
    25782581            LayoutRect visibleRectRelativeToDocument = viewRect;
    25792582#endif
    2580 
    2581             LayoutRect r = getRectToExpose(viewRect, visibleRectRelativeToDocument, rect, alignX, alignY);
     2583            LayoutRect revealRect = getRectToExpose(viewRect, visibleRectRelativeToDocument, absoluteRect, insideFixed, alignX, alignY);
    25822584               
    2583             frameView.setScrollPosition(roundedIntPoint(r.location()));
     2585            frameView.setScrollPosition(roundedIntPoint(revealRect.location()));
    25842586
    25852587            // This is the outermost view of a web page, so after scrolling this view we
     
    25892591            // The canAutoscroll function in EventHandler also knows about this.
    25902592            if (Page* page = frameView.frame().page())
    2591                 page->chrome().scrollRectIntoView(snappedIntRect(rect));
     2593                page->chrome().scrollRectIntoView(snappedIntRect(absoluteRect));
    25922594        }
    25932595    }
    25942596   
    25952597    if (parentLayer)
    2596         parentLayer->scrollRectToVisible(revealMode, newRect, alignX, alignY);
     2598        parentLayer->scrollRectToVisible(revealMode, newRect, insideFixed, alignX, alignY);
    25972599}
    25982600
     
    26112613}
    26122614
    2613 LayoutRect RenderLayer::getRectToExpose(const LayoutRect &visibleRect, const LayoutRect &visibleRectRelativeToDocument, const LayoutRect &exposeRect, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
    2614 {
     2615LayoutRect RenderLayer::getRectToExpose(const LayoutRect &visibleRect, const LayoutRect &visibleRectRelativeToDocument, const LayoutRect &exposeRect, bool insideFixed, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
     2616{
     2617    FrameView& frameView = renderer().view().frameView();
     2618    if (insideFixed) {
     2619        // If the element is inside position:fixed and we're not scaled, no amount of scrolling is going to move things around.
     2620        if (frameView.frameScaleFactor() == 1)
     2621            return visibleRect;
     2622
     2623        if (frameView.frame().settings().visualViewportEnabled()) {
     2624            // exposeRect is in absolute coords, affected by page scale. Unscale it.
     2625            LayoutRect unscaledExposeRect = exposeRect;
     2626            unscaledExposeRect.scale(1 / frameView.frameScaleFactor());
     2627            // These are both in unscaled coordinates.
     2628            LayoutRect layoutViewport = frameView.layoutViewportRect();
     2629            LayoutRect visualViewport = frameView.visualViewportRect();
     2630
     2631            // The rect to expose may be partially offscreen, which we can't do anything about with position:fixed.
     2632            unscaledExposeRect.intersect(layoutViewport);
     2633            // Make sure it's not larger than the visual viewport; if so, we'll just move to the top left.
     2634            unscaledExposeRect.setSize(unscaledExposeRect.size().shrunkTo(visualViewport.size()));
     2635
     2636            // Compute how much we have to move the visualViewport to reveal the part of the layoutViewport that contains exposeRect.
     2637            LayoutRect requiredVisualViewport = getRectToExpose(visualViewport, visualViewport, unscaledExposeRect, false, alignX, alignY);
     2638            // Scale it back up.
     2639            requiredVisualViewport.scale(frameView.frameScaleFactor());
     2640            return requiredVisualViewport;
     2641        }
     2642    }
     2643
    26152644    // Determine the appropriate X behavior.
    26162645    ScrollAlignment::Behavior scrollX;
     
    26872716{
    26882717    IntPoint currentDocumentPosition = renderer().view().frameView().windowToContents(position);
    2689     scrollRectToVisible(SelectionRevealMode::Reveal, LayoutRect(currentDocumentPosition, LayoutSize(1, 1)), ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
     2718    scrollRectToVisible(SelectionRevealMode::Reveal, LayoutRect(currentDocumentPosition, LayoutSize(1, 1)), false, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
    26902719}
    26912720
  • trunk/Source/WebCore/rendering/RenderLayer.h

    r209348 r209411  
    205205    void availableContentSizeChanged(AvailableSizeChangeReason) override;
    206206
    207     void scrollRectToVisible(SelectionRevealMode, const LayoutRect&, const ScrollAlignment& alignX, const ScrollAlignment& alignY);
    208 
    209     LayoutRect getRectToExpose(const LayoutRect& visibleRect, const LayoutRect& visibleRectRelativeToDocument, const LayoutRect& exposeRect, const ScrollAlignment& alignX, const ScrollAlignment& alignY);
     207    void scrollRectToVisible(SelectionRevealMode, const LayoutRect& absoluteRect, bool insideFixed, const ScrollAlignment& alignX, const ScrollAlignment& alignY);
     208
     209    LayoutRect getRectToExpose(const LayoutRect& visibleRect, const LayoutRect& visibleRectRelativeToDocument, const LayoutRect& exposeRect, bool insideFixed, const ScrollAlignment& alignX, const ScrollAlignment& alignY);
    210210
    211211    bool scrollsOverflow() const;
  • trunk/Source/WebCore/rendering/RenderObject.cpp

    r209348 r209411  
    397397}
    398398
    399 bool RenderObject::scrollRectToVisible(SelectionRevealMode revealMode, const LayoutRect& rect, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
     399bool RenderObject::scrollRectToVisible(SelectionRevealMode revealMode, const LayoutRect& absoluteRect, bool insideFixed, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
    400400{
    401401    if (revealMode == SelectionRevealMode::DoNotReveal)
     
    406406        return false;
    407407
    408     enclosingLayer->scrollRectToVisible(revealMode, rect, alignX, alignY);
     408    enclosingLayer->scrollRectToVisible(revealMode, absoluteRect, insideFixed, alignX, alignY);
    409409    return true;
    410410}
  • trunk/Source/WebCore/rendering/RenderObject.h

    r209348 r209411  
    155155
    156156    // Scrolling is a RenderBox concept, however some code just cares about recursively scrolling our enclosing ScrollableArea(s).
    157     WEBCORE_EXPORT bool scrollRectToVisible(SelectionRevealMode, const LayoutRect&, const ScrollAlignment& alignX = ScrollAlignment::alignCenterIfNeeded, const ScrollAlignment& alignY = ScrollAlignment::alignCenterIfNeeded);
     157    WEBCORE_EXPORT bool scrollRectToVisible(SelectionRevealMode, const LayoutRect& absoluteRect, bool insideFixed, const ScrollAlignment& alignX = ScrollAlignment::alignCenterIfNeeded, const ScrollAlignment& alignY = ScrollAlignment::alignCenterIfNeeded);
    158158
    159159    // Convenience function for getting to the nearest enclosing box of a RenderObject.
  • trunk/Source/WebKit/mac/ChangeLog

    r209409 r209411  
     12016-12-05  Simon Fraser  <simon.fraser@apple.com>
     2
     3        Improve the behavior of scroll-into-view when the target is inside position:fixed
     4        https://bugs.webkit.org/show_bug.cgi?id=165354
     5
     6        Reviewed by Zalan Bujtas.
     7
     8        Plumb through 'insideFixed'. We don't get compute it, so behavior from
     9        these call sites won't change.
     10
     11        * WebView/WebFrame.mm:
     12        (-[WebFrame _scrollDOMRangeToVisible:]):
     13        (-[WebFrame _scrollDOMRangeToVisible:withInset:]):
     14
    1152016-12-06  Simon Fraser  <simon.fraser@apple.com>
    216
  • trunk/Source/WebKit/mac/WebView/WebFrame.mm

    r209348 r209411  
    712712- (void)_scrollDOMRangeToVisible:(DOMRange *)range
    713713{
     714    bool insideFixed = false; // FIXME: get via firstRectForRange().
    714715    NSRect rangeRect = [self _firstRectForDOMRange:range];   
    715716    Node *startNode = core([range startContainer]);
     
    717718    if (startNode && startNode->renderer()) {
    718719#if !PLATFORM(IOS)
    719         startNode->renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, enclosingIntRect(rangeRect), ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
     720        startNode->renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, enclosingIntRect(rangeRect), insideFixed, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
    720721#else
    721722        RenderLayer* layer = startNode->renderer()->enclosingLayer();
    722723        if (layer) {
    723724            layer->setAdjustForIOSCaretWhenScrolling(true);
    724             startNode->renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, enclosingIntRect(rangeRect), ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
     725            startNode->renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, enclosingIntRect(rangeRect), insideFixed, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
    725726            layer->setAdjustForIOSCaretWhenScrolling(false);
    726727            _private->coreFrame->selection().setCaretRectNeedsUpdate();
     
    734735- (void)_scrollDOMRangeToVisible:(DOMRange *)range withInset:(CGFloat)inset
    735736{
     737    bool insideFixed = false; // FIXME: get via firstRectForRange().
    736738    NSRect rangeRect = NSInsetRect([self _firstRectForDOMRange:range], inset, inset);
    737739    Node *startNode = core([range startContainer]);
     
    741743        if (layer) {
    742744            layer->setAdjustForIOSCaretWhenScrolling(true);
    743             startNode->renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, enclosingIntRect(rangeRect), ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
     745            startNode->renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, enclosingIntRect(rangeRect), insideFixed, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
    744746            layer->setAdjustForIOSCaretWhenScrolling(false);
    745747
Note: See TracChangeset for help on using the changeset viewer.