Changeset 170541 in webkit


Ignore:
Timestamp:
Jun 27, 2014 11:28:39 AM (10 years ago)
Author:
Simon Fraser
Message:

[iOS WK2] Fix touch-scrollable elements with overflow:scroll on just one axis, and RTL scrolling
https://bugs.webkit.org/show_bug.cgi?id=134377
<rdar://problem/16762224>

Reviewed by Tim Horton.

Source/WebCore:

Make -webkit-overflow-scrolling:touch scrolling work correctly when one axis
has overflow:scroll and the other overflow:hidden. Also fix scrolling in RTL
contexts.

An RTL scroller with overflow-x:hidden will have a non-zero scroll origin,
and needs to truncate the scrolled content on the left side. To pass the
correct geometry to the UI process, we need to introduce the concept of
"reachable" size as well as total content size; normally these are the same,
but will differ when scrolling is only allowed on one axis but there is overflow
on both axes.

To get the reachable size, add RenderLayer::scrollableContentsSize().

RenderLayer::visibleSize() was wrong; the function should return the size of the
scrollable portion, but used layer size which includes borders. Fix to use pixelSnappedClientWidth()/Height(),
which is what we use for scrollbar computations.

  • WebCore.exp.in:
  • page/scrolling/AsyncScrollingCoordinator.cpp:

(WebCore::AsyncScrollingCoordinator::frameViewLayoutUpdated):
(WebCore::AsyncScrollingCoordinator::updateFrameScrollingNode):
(WebCore::AsyncScrollingCoordinator::updateOverflowScrollingNode):

  • page/scrolling/ScrollingCoordinator.h:
  • page/scrolling/ScrollingStateScrollingNode.cpp:

(WebCore::ScrollingStateScrollingNode::ScrollingStateScrollingNode):
(WebCore::ScrollingStateScrollingNode::setReachableContentsSize):

  • page/scrolling/ScrollingStateScrollingNode.h:

(WebCore::ScrollingStateScrollingNode::reachableContentsSize):

  • page/scrolling/ScrollingTreeScrollingNode.cpp:

(WebCore::ScrollingTreeScrollingNode::updateBeforeChildren):

  • page/scrolling/ScrollingTreeScrollingNode.h:

(WebCore::ScrollingTreeScrollingNode::reachableContentsSize):

  • rendering/RenderLayer.cpp:

(WebCore::RenderLayer::visibleSize):
(WebCore::RenderLayer::scrollableContentsSize):

  • rendering/RenderLayer.h:
  • rendering/RenderLayerCompositor.cpp:

(WebCore::updateScrollingLayerWithClient):
(WebCore::RenderLayerCompositor::updateScrollCoordinatedLayer):

Source/WebKit2:

Make -webkit-overflow-scrolling:touch scrolling work correctly when one axis
has overflow:scroll and the other overflow:hidden. Also fix scrolling in RTL
contexts.

An RTL scroller with overflow-x:hidden will have a non-zero scroll origin,
and needs to truncate the scrolled content on the left side. To pass the
correct geometry to the UI process, we need to introduce the concept of
"reachable" size as well as total content size; normally these are the same,
but will differ when scrolling is only allowed on one axis but there is overflow
on both axes.

ScrollingTreeOverflowScrollingNodeIOS::updateAfterChildren() uses the total and
reachable content sizes to set a negative edge inset on the left (for RTL) or top
(for bottom-to-top) so prevent scrolling into these areas.

  • Shared/Scrolling/RemoteScrollingCoordinatorTransaction.cpp:

(ArgumentCoder<ScrollingStateScrollingNode>::encode):
(ArgumentCoder<ScrollingStateScrollingNode>::decode):
(WebKit::RemoteScrollingTreeTextStream::dump):

  • UIProcess/Scrolling/ios/ScrollingTreeOverflowScrollingNodeIOS.mm:

(WebKit::ScrollingTreeOverflowScrollingNodeIOS::updateAfterChildren):

Location:
trunk/Source
Files:
14 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r170539 r170541  
     12014-06-26  Simon Fraser  <simon.fraser@apple.com>
     2
     3        [iOS WK2] Fix touch-scrollable elements with overflow:scroll on just one axis, and RTL scrolling
     4        https://bugs.webkit.org/show_bug.cgi?id=134377
     5        <rdar://problem/16762224>
     6
     7        Reviewed by Tim Horton.
     8       
     9        Make -webkit-overflow-scrolling:touch scrolling work correctly when one axis
     10        has overflow:scroll and the other overflow:hidden. Also fix scrolling in RTL
     11        contexts.
     12       
     13        An RTL scroller with overflow-x:hidden will have a non-zero scroll origin,
     14        and needs to truncate the scrolled content on the left side. To pass the
     15        correct geometry to the UI process, we need to introduce the concept of
     16        "reachable" size as well as total content size; normally these are the same,
     17        but will differ when scrolling is only allowed on one axis but there is overflow
     18        on both axes.
     19       
     20        To get the reachable size, add RenderLayer::scrollableContentsSize().
     21       
     22        RenderLayer::visibleSize() was wrong; the function should return the size of the
     23        scrollable portion, but used layer size which includes borders. Fix to use pixelSnappedClientWidth()/Height(),
     24        which is what we use for scrollbar computations.
     25
     26        * WebCore.exp.in:
     27        * page/scrolling/AsyncScrollingCoordinator.cpp:
     28        (WebCore::AsyncScrollingCoordinator::frameViewLayoutUpdated):
     29        (WebCore::AsyncScrollingCoordinator::updateFrameScrollingNode):
     30        (WebCore::AsyncScrollingCoordinator::updateOverflowScrollingNode):
     31        * page/scrolling/ScrollingCoordinator.h:
     32        * page/scrolling/ScrollingStateScrollingNode.cpp:
     33        (WebCore::ScrollingStateScrollingNode::ScrollingStateScrollingNode):
     34        (WebCore::ScrollingStateScrollingNode::setReachableContentsSize):
     35        * page/scrolling/ScrollingStateScrollingNode.h:
     36        (WebCore::ScrollingStateScrollingNode::reachableContentsSize):
     37        * page/scrolling/ScrollingTreeScrollingNode.cpp:
     38        (WebCore::ScrollingTreeScrollingNode::updateBeforeChildren):
     39        * page/scrolling/ScrollingTreeScrollingNode.h:
     40        (WebCore::ScrollingTreeScrollingNode::reachableContentsSize):
     41        * rendering/RenderLayer.cpp:
     42        (WebCore::RenderLayer::visibleSize):
     43        (WebCore::RenderLayer::scrollableContentsSize):
     44        * rendering/RenderLayer.h:
     45        * rendering/RenderLayerCompositor.cpp:
     46        (WebCore::updateScrollingLayerWithClient):
     47        (WebCore::RenderLayerCompositor::updateScrollCoordinatedLayer):
     48
    1492014-06-27  Bear Travis  <betravis@adobe.com>
    250
  • trunk/Source/WebCore/WebCore.exp.in

    r170514 r170541  
    28842884__ZN7WebCore27ScrollingStateScrollingNode20setTotalContentsSizeERKNS_9FloatSizeE
    28852885__ZN7WebCore27ScrollingStateScrollingNode21setScrollableAreaSizeERKNS_9FloatSizeE
     2886__ZN7WebCore27ScrollingStateScrollingNode24setReachableContentsSizeERKNS_9FloatSizeE
    28862887__ZN7WebCore27ScrollingStateScrollingNode26setRequestedScrollPositionERKNS_10FloatPointEb
    28872888__ZN7WebCore27ScrollingStateScrollingNode27setScrollableAreaParametersERKNS_24ScrollableAreaParametersE
  • trunk/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.cpp

    r170118 r170541  
    9595    node->setScrollableAreaSize(frameView->visibleContentRect().size());
    9696    node->setTotalContentsSize(frameView->totalContentsSize());
     97    node->setReachableContentsSize(frameView->totalContentsSize());
    9798
    9899    ScrollableAreaParameters scrollParameters;
     
    376377        node->setScrollPosition(scrollingGeometry->scrollPosition);
    377378        node->setTotalContentsSize(scrollingGeometry->contentSize);
     379        node->setReachableContentsSize(scrollingGeometry->reachableContentSize);
    378380        node->setScrollableAreaSize(scrollingGeometry->scrollableAreaSize);
    379381    }
     
    394396        node->setScrollPosition(scrollingGeometry->scrollPosition);
    395397        node->setTotalContentsSize(scrollingGeometry->contentSize);
     398        node->setReachableContentsSize(scrollingGeometry->reachableContentSize);
    396399        node->setScrollableAreaSize(scrollingGeometry->scrollableAreaSize);
    397400    }
  • trunk/Source/WebCore/page/scrolling/ScrollingCoordinator.h

    r169733 r170541  
    162162        FloatSize scrollableAreaSize;
    163163        FloatSize contentSize;
     164        FloatSize reachableContentSize; // Smaller than contentSize when overflow is hidden on one axis.
    164165        FloatPoint scrollPosition;
    165166        IntPoint scrollOrigin;
  • trunk/Source/WebCore/page/scrolling/ScrollingStateScrollingNode.cpp

    r169063 r170541  
    4545    , m_scrollableAreaSize(stateNode.scrollableAreaSize())
    4646    , m_totalContentsSize(stateNode.totalContentsSize())
     47    , m_reachableContentsSize(stateNode.reachableContentsSize())
    4748    , m_scrollPosition(stateNode.scrollPosition())
    4849    , m_requestedScrollPosition(stateNode.requestedScrollPosition())
     
    7374    m_totalContentsSize = totalContentsSize;
    7475    setPropertyChanged(TotalContentsSize);
     76}
     77
     78void ScrollingStateScrollingNode::setReachableContentsSize(const FloatSize& reachableContentsSize)
     79{
     80    if (m_reachableContentsSize == reachableContentsSize)
     81        return;
     82
     83    m_reachableContentsSize = reachableContentsSize;
     84    setPropertyChanged(ReachableContentsSize);
    7585}
    7686
  • trunk/Source/WebCore/page/scrolling/ScrollingStateScrollingNode.h

    r169063 r170541  
    4343        ScrollableAreaSize = NumStateNodeBits,
    4444        TotalContentsSize,
     45        ReachableContentsSize,
    4546        ScrollPosition,
    4647        ScrollOrigin,
     
    5556    const FloatSize& totalContentsSize() const { return m_totalContentsSize; }
    5657    void setTotalContentsSize(const FloatSize&);
     58
     59    const FloatSize& reachableContentsSize() const { return m_reachableContentsSize; }
     60    void setReachableContentsSize(const FloatSize&);
    5761
    5862    const FloatPoint& scrollPosition() const { return m_scrollPosition; }
     
    7882    FloatSize m_scrollableAreaSize;
    7983    FloatSize m_totalContentsSize;
     84    FloatSize m_reachableContentsSize;
    8085    FloatPoint m_scrollPosition;
    8186    FloatPoint m_requestedScrollPosition;
  • trunk/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.cpp

    r169313 r170541  
    5959    }
    6060
     61    if (state.hasChangedProperty(ScrollingStateScrollingNode::ReachableContentsSize))
     62        m_reachableContentsSize = state.reachableContentsSize();
     63
    6164    if (state.hasChangedProperty(ScrollingStateScrollingNode::ScrollPosition))
    6265        m_lastCommittedScrollPosition = state.scrollPosition();
  • trunk/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.h

    r169411 r170541  
    7070    const FloatSize& scrollableAreaSize() const { return m_scrollableAreaSize; }
    7171    const FloatSize& totalContentsSize() const { return m_totalContentsSize; }
     72    const FloatSize& reachableContentsSize() const { return m_reachableContentsSize; }
    7273    const IntPoint& scrollOrigin() const { return m_scrollOrigin; }
    7374
     
    9091    FloatSize m_totalContentsSize;
    9192    FloatSize m_totalContentsSizeForRubberBand;
     93    FloatSize m_reachableContentsSize;
    9294    FloatPoint m_lastCommittedScrollPosition;
    9395    IntPoint m_scrollOrigin;
  • trunk/Source/WebCore/rendering/RenderLayer.cpp

    r170532 r170541  
    27352735}
    27362736
     2737IntSize RenderLayer::visibleSize() const
     2738{
     2739    if (!renderer().isBox())
     2740        return IntSize();
     2741
     2742    return IntSize(renderBox()->pixelSnappedClientWidth(), renderBox()->pixelSnappedClientHeight());
     2743}
     2744
    27372745IntSize RenderLayer::contentsSize() const
    27382746{
    27392747    return IntSize(scrollWidth(), scrollHeight());
     2748}
     2749
     2750IntSize RenderLayer::scrollableContentsSize() const
     2751{
     2752    IntSize contentsSize = this->contentsSize();
     2753
     2754    if (!hasScrollableHorizontalOverflow())
     2755        contentsSize.setWidth(std::min(contentsSize.width(), visibleSize().width()));
     2756
     2757    if (!hasScrollableVerticalOverflow())
     2758        contentsSize.setHeight(std::min(contentsSize.height(), visibleSize().height()));
     2759
     2760    return contentsSize;
    27402761}
    27412762
  • trunk/Source/WebCore/rendering/RenderLayer.h

    r170381 r170541  
    345345
    346346    RenderLayerModelObject& renderer() const { return m_renderer; }
    347     RenderBox* renderBox() const { return renderer().isBox() ? &toRenderBox(renderer()) : 0; }
     347    RenderBox* renderBox() const { return renderer().isBox() ? &toRenderBox(renderer()) : nullptr; }
    348348    RenderLayer* parent() const { return m_parent; }
    349349    RenderLayer* previousSibling() const { return m_previous; }
     
    421421    int scrollYOffset() const { return m_scrollOffset.height() + scrollOrigin().y(); }
    422422    IntSize scrollOffset() const { return IntSize(scrollXOffset(), scrollYOffset()); }
     423    IntSize scrollableContentsSize() const;
    423424
    424425    void scrollRectToVisible(const LayoutRect&, const ScrollAlignment& alignX, const ScrollAlignment& alignY);
     
    10781079    virtual IntPoint maximumScrollPosition() const override;
    10791080    virtual IntRect visibleContentRectInternal(VisibleContentRectIncludesScrollbars, VisibleContentRectBehavior) const override;
    1080     virtual IntSize visibleSize() const override { return m_layerSize; }
     1081    virtual IntSize visibleSize() const override;
    10811082    virtual IntSize contentsSize() const override;
    10821083    virtual IntSize overhangAmount() const override;
  • trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp

    r170514 r170541  
    509509    bool allowVerticalScrollbar = !scrollbarHasDisplayNone(layer.verticalScrollbar());
    510510    client->addOrUpdateScrollingLayer(layer.renderer().element(), backing->scrollingLayer()->platformLayer(), backing->scrollingContentsLayer()->platformLayer(),
    511         IntSize(layer.scrollWidth(), layer.scrollHeight()), allowHorizontalScrollbar, allowVerticalScrollbar);
     511        layer.scrollableContentsSize(), allowHorizontalScrollbar, allowVerticalScrollbar);
    512512}
    513513
     
    37403740            updateScrollCoordinationForThisFrame(parentNodeID);
    37413741        else {
    3742             ScrollingNodeType nodeType = isRootLayer ? FrameScrollingNode : OverflowScrollingNode;
     3742            ScrollingNodeType nodeType = OverflowScrollingNode;
    37433743            ScrollingNodeID nodeID = attachScrollingNode(layer, nodeType, parentNodeID);
    37443744            if (!nodeID)
     
    37503750            scrollingGeometry.scrollableAreaSize = layer.visibleSize();
    37513751            scrollingGeometry.contentSize = layer.contentsSize();
     3752            scrollingGeometry.reachableContentSize = layer.scrollableContentsSize();
    37523753            scrollingCoordinator->updateOverflowScrollingNode(nodeID, backing->scrollingLayer(), backing->scrollingContentsLayer(), &scrollingGeometry);
    37533754        }
  • trunk/Source/WebKit2/ChangeLog

    r170540 r170541  
     12014-06-26  Simon Fraser  <simon.fraser@apple.com>
     2
     3        [iOS WK2] Fix touch-scrollable elements with overflow:scroll on just one axis, and RTL scrolling
     4        https://bugs.webkit.org/show_bug.cgi?id=134377
     5        <rdar://problem/16762224>
     6
     7        Reviewed by Tim Horton.
     8
     9        Make -webkit-overflow-scrolling:touch scrolling work correctly when one axis
     10        has overflow:scroll and the other overflow:hidden. Also fix scrolling in RTL
     11        contexts.
     12       
     13        An RTL scroller with overflow-x:hidden will have a non-zero scroll origin,
     14        and needs to truncate the scrolled content on the left side. To pass the
     15        correct geometry to the UI process, we need to introduce the concept of
     16        "reachable" size as well as total content size; normally these are the same,
     17        but will differ when scrolling is only allowed on one axis but there is overflow
     18        on both axes.
     19       
     20        ScrollingTreeOverflowScrollingNodeIOS::updateAfterChildren() uses the total and
     21        reachable content sizes to set a negative edge inset on the left (for RTL) or top
     22        (for bottom-to-top) so prevent scrolling into these areas.
     23
     24        * Shared/Scrolling/RemoteScrollingCoordinatorTransaction.cpp:
     25        (ArgumentCoder<ScrollingStateScrollingNode>::encode):
     26        (ArgumentCoder<ScrollingStateScrollingNode>::decode):
     27        (WebKit::RemoteScrollingTreeTextStream::dump):
     28        * UIProcess/Scrolling/ios/ScrollingTreeOverflowScrollingNodeIOS.mm:
     29        (WebKit::ScrollingTreeOverflowScrollingNodeIOS::updateAfterChildren):
     30
    1312014-06-27  Joseph Pecoraro  <pecoraro@apple.com>
    232
  • trunk/Source/WebKit2/Shared/Scrolling/RemoteScrollingCoordinatorTransaction.cpp

    r170267 r170541  
    126126    SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::ScrollableAreaSize, scrollableAreaSize)
    127127    SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::TotalContentsSize, totalContentsSize)
     128    SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::ReachableContentsSize, reachableContentsSize)
    128129    SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::ScrollPosition, scrollPosition)
    129130    SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::ScrollOrigin, scrollOrigin)
     
    190191    SCROLLING_NODE_DECODE(ScrollingStateScrollingNode::ScrollableAreaSize, FloatSize, setScrollableAreaSize);
    191192    SCROLLING_NODE_DECODE(ScrollingStateScrollingNode::TotalContentsSize, FloatSize, setTotalContentsSize);
     193    SCROLLING_NODE_DECODE(ScrollingStateScrollingNode::ReachableContentsSize, FloatSize, setReachableContentsSize);
    192194    SCROLLING_NODE_DECODE(ScrollingStateScrollingNode::ScrollPosition, FloatPoint, setScrollPosition);
    193195    SCROLLING_NODE_DECODE(ScrollingStateScrollingNode::ScrollOrigin, IntPoint, setScrollOrigin);
     
    566568   
    567569    if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateScrollingNode::ScrollableAreaSize))
    568         dumpProperty(ts, "scrollable-area-size", node.totalContentsSize());
     570        dumpProperty(ts, "scrollable-area-size", node.scrollableAreaSize());
    569571
    570572    if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateScrollingNode::TotalContentsSize))
    571573        dumpProperty(ts, "total-contents-size", node.totalContentsSize());
     574
     575    if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateScrollingNode::ReachableContentsSize))
     576        dumpProperty(ts, "reachable-contents-size", node.reachableContentsSize());
    572577
    573578    if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateScrollingNode::ScrollPosition))
  • trunk/Source/WebKit2/UIProcess/Scrolling/ios/ScrollingTreeOverflowScrollingNodeIOS.mm

    r170466 r170541  
    141141    if (scrollingStateNode.hasChangedProperty(ScrollingStateScrollingNode::ScrollLayer)
    142142        || scrollingStateNode.hasChangedProperty(ScrollingStateScrollingNode::TotalContentsSize)
    143         || scrollingStateNode.hasChangedProperty(ScrollingStateScrollingNode::ScrollPosition)) {
     143        || scrollingStateNode.hasChangedProperty(ScrollingStateScrollingNode::ReachableContentsSize)
     144        || scrollingStateNode.hasChangedProperty(ScrollingStateScrollingNode::ScrollPosition)
     145        || scrollingStateNode.hasChangedProperty(ScrollingStateScrollingNode::ScrollOrigin)) {
    144146        BEGIN_BLOCK_OBJC_EXCEPTIONS
    145147        UIScrollView *scrollView = (UIScrollView *)[scrollLayer() delegate];
     
    153155        }
    154156
    155         if (scrollingStateNode.hasChangedProperty(ScrollingStateScrollingNode::TotalContentsSize))
    156             scrollView.contentSize = scrollingStateNode.totalContentsSize();
    157 
    158         if (scrollingStateNode.hasChangedProperty(ScrollingStateScrollingNode::ScrollPosition) && ![m_scrollViewDelegate _isInUserInteraction])
    159             scrollView.contentOffset = scrollingStateNode.scrollPosition();
    160 
     157        bool recomputeInsets = scrollingStateNode.hasChangedProperty(ScrollingStateScrollingNode::TotalContentsSize);
     158        if (scrollingStateNode.hasChangedProperty(ScrollingStateScrollingNode::ReachableContentsSize)) {
     159            scrollView.contentSize = scrollingStateNode.reachableContentsSize();
     160            recomputeInsets = true;
     161        }
     162
     163        if ((scrollingStateNode.hasChangedProperty(ScrollingStateScrollingNode::ScrollPosition)
     164            || scrollingStateNode.hasChangedProperty(ScrollingStateScrollingNode::ScrollOrigin))
     165            && ![m_scrollViewDelegate _isInUserInteraction]) {
     166            scrollView.contentOffset = scrollingStateNode.scrollPosition() + scrollOrigin();
     167            recomputeInsets = true;
     168        }
     169       
     170        if (recomputeInsets) {
     171            UIEdgeInsets insets = UIEdgeInsetsMake(0, 0, 0, 0);
     172            // With RTL or bottom-to-top scrolling (non-zero origin), we need extra space on the left or top.
     173            if (scrollOrigin().x())
     174                insets.left = reachableContentsSize().width() - totalContentsSize().width();
     175
     176            if (scrollOrigin().y())
     177                insets.top = reachableContentsSize().height() - totalContentsSize().height();
     178
     179            scrollView.contentInset = insets;
     180        }
     181           
    161182        END_BLOCK_OBJC_EXCEPTIONS
    162183    }
Note: See TracChangeset for help on using the changeset viewer.