Changeset 185606 in webkit


Ignore:
Timestamp:
Jun 16, 2015 1:44:18 PM (9 years ago)
Author:
Brent Fulgham
Message:

CSS Scroll Snap - support snapping to nested elements
https://bugs.webkit.org/show_bug.cgi?id=145843
<rdar://problem/21339581>

Reviewed by Darin Adler.

Source/WebCore:

Tested by css3/scroll-snap/nested-elements.html

The Scroll Snap Point implementation was not properly handling nested elements.
This could be resolved by recursively calling 'appendChildSnapOffsets', but this
seemed like an inefficient approach, especially considering how often this method
is called during various scaling and other operations.

Instead, do the following:
(1) Add a new HashSet to RenderView that holds a collection of RenderElements that

have scroll-snap-coordinates.

(2) During RenderElement::styleWillChange, register all elements that have the

scroll-snap-coordinates style with the RenderView.

(3) When performing 'appendChildSnapOffsets', refer to the HashSet of elements, select the

subset of these entries relevant to the current scrolling container, and build up the
set of scroll-snap-coordinates needed for the current scrolling container.

  • page/scrolling/AxisScrollSnapOffsets.cpp:

(WebCore::appendChildSnapOffsets): Check the scroll-snap-coordinate RenderElement HashSet
for the RenderView to find all elements that are children of the current scrolling container.
Add the scroll-snap-coordinates for these RenderElements to the current set of snap points.

  • rendering/RenderElement.cpp:

(WebCore::findEnclosingScrollableContainer): New helper function.
(WebCore::RenderElement::styleWillChange): If the current element has scroll-snap-coordinate
defined, remember it for later so we can use it with the relevant scrolling container
after layout completes.
(WebCore::RenderElement::willBeRemovedFromTree): Unregister the current element from the
RenderView.
(WebCore::RenderElement::findEnclosingScrollableContainer): Added. Locate the relevant
scrolling container for the current object.

  • rendering/RenderElement.h:
  • rendering/RenderView.cpp:

(WebCore::Document::registerRenderElementWithScrollSnapCoordinates): Added.
(WebCore::Document::unregisterRenderElementWithScrollSnapCoordinates): Added.

  • rendering/RenderView.h:

LayoutTests:

  • css3/scroll-snap/nested-elements-expected.txt: Added.
  • css3/scroll-snap/nested-elements.html: Added.
  • css3/scroll-snap/scroll-snap-offsets-expected.txt: Updated to account for 50%/50% scroll-snap-coordinates.
Location:
trunk
Files:
2 added
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r185604 r185606  
     12015-06-16  Brent Fulgham  <bfulgham@apple.com>
     2
     3        CSS Scroll Snap - support snapping to nested elements
     4        https://bugs.webkit.org/show_bug.cgi?id=145843
     5        <rdar://problem/21339581>
     6
     7        Reviewed by Darin Adler.
     8
     9        * css3/scroll-snap/nested-elements-expected.txt: Added.
     10        * css3/scroll-snap/nested-elements.html: Added.
     11        * css3/scroll-snap/scroll-snap-offsets-expected.txt: Updated to
     12          account for 50%/50% scroll-snap-coordinates.
     13
    1142015-06-16  Brady Eidson  <beidson@apple.com>
    215
  • trunk/LayoutTests/css3/scroll-snap/scroll-snap-offsets-expected.txt

    r183906 r185606  
    33
    44TEST COMPLETE
    5 Scroll-snap offsets for horizontalTarget: horizontal = { 0, 30, 60, 90, 120, 150 }, vertical = { 0, 15 }
    6 Scroll-snap offsets for verticalTarget: horizontal = { 0, 15 }, vertical = { 0, 30, 60, 90, 120, 150 }
    7 Scroll-snap offsets for horizontalBorderedTarget: horizontal = { 0, 30, 60, 90, 120, 150 }, vertical = { 0, 15 }
    8 Scroll-snap offsets for verticalBorderedTarget: horizontal = { 0, 15 }, vertical = { 0, 30, 60, 90, 120, 150 }
    9 Scroll-snap offsets for horizontalPaddedTarget: horizontal = { 0, 30, 60, 90, 120, 150, 170 }, vertical = { 0, 39 }
    10 Scroll-snap offsets for verticalPaddedTarget: horizontal = { 0, 35 }, vertical = { 0, 30, 60, 90, 120, 150, 174 }
    11 Scroll-snap offsets for horizontalBorderedPaddedTarget: horizontal = { 0, 30, 60, 90, 120, 150, 170 }, vertical = { 0, 39 }
    12 Scroll-snap offsets for verticalBorderedPaddedTarget: horizontal = { 0, 35 }, vertical = { 0, 30, 60, 90, 120, 150, 174 }
    13 Scroll-snap offsets for horizontalRotatedTarget: horizontal = { 0, 30, 60, 90, 120, 150, 170 }, vertical = { 0, 39 }
    14 Scroll-snap offsets for verticalRotatedTarget: horizontal = { 0, 35 }, vertical = { 0, 30, 60, 90, 120, 150, 174 }
     5Scroll-snap offsets for horizontalTarget: horizontal = { 0, 30, 60, 90, 120, 150 }, vertical = { 0, 7, 15 }
     6Scroll-snap offsets for verticalTarget: horizontal = { 0, 7, 15 }, vertical = { 0, 30, 60, 90, 120, 150 }
     7Scroll-snap offsets for horizontalBorderedTarget: horizontal = { 0, 30, 60, 90, 120, 150 }, vertical = { 0, 7, 15 }
     8Scroll-snap offsets for verticalBorderedTarget: horizontal = { 0, 7, 15 }, vertical = { 0, 30, 60, 90, 120, 150 }
     9Scroll-snap offsets for horizontalPaddedTarget: horizontal = { 0, 30, 60, 90, 120, 150, 170 }, vertical = { 0, 7, 39 }
     10Scroll-snap offsets for verticalPaddedTarget: horizontal = { 0, 7, 35 }, vertical = { 0, 30, 60, 90, 120, 150, 174 }
     11Scroll-snap offsets for horizontalBorderedPaddedTarget: horizontal = { 0, 30, 60, 90, 120, 150, 170 }, vertical = { 0, 7, 39 }
     12Scroll-snap offsets for verticalBorderedPaddedTarget: horizontal = { 0, 7, 35 }, vertical = { 0, 30, 60, 90, 120, 150, 174 }
     13Scroll-snap offsets for horizontalRotatedTarget: horizontal = { 0, 30, 60, 90, 120, 150, 170 }, vertical = { 0, 7, 39 }
     14Scroll-snap offsets for verticalRotatedTarget: horizontal = { 0, 7, 35 }, vertical = { 0, 30, 60, 90, 120, 150, 174 }
    1515PASS successfullyParsed is true
    1616
  • trunk/Source/WebCore/ChangeLog

    r185604 r185606  
     12015-06-16  Brent Fulgham  <bfulgham@apple.com>
     2
     3        CSS Scroll Snap - support snapping to nested elements
     4        https://bugs.webkit.org/show_bug.cgi?id=145843
     5        <rdar://problem/21339581>
     6
     7        Reviewed by Darin Adler.
     8
     9        Tested by css3/scroll-snap/nested-elements.html
     10
     11        The Scroll Snap Point implementation was not properly handling nested elements.
     12        This could be resolved by recursively calling 'appendChildSnapOffsets', but this
     13        seemed like an inefficient approach, especially considering how often this method
     14        is called during various scaling and other operations.
     15       
     16        Instead, do the following:
     17        (1) Add a new HashSet to RenderView that holds a collection of RenderElements that
     18            have scroll-snap-coordinates.
     19        (2) During RenderElement::styleWillChange, register all elements that have the
     20            scroll-snap-coordinates style with the RenderView.
     21        (3) When performing 'appendChildSnapOffsets', refer to the HashSet of elements, select the
     22            subset of these entries relevant to the current scrolling container, and build up the
     23            set of scroll-snap-coordinates needed for the current scrolling container.
     24
     25        * page/scrolling/AxisScrollSnapOffsets.cpp:
     26        (WebCore::appendChildSnapOffsets): Check the scroll-snap-coordinate RenderElement HashSet
     27        for the RenderView to find all elements that are children of the current scrolling container.
     28        Add the scroll-snap-coordinates for these RenderElements to the current set of snap points.
     29        * rendering/RenderElement.cpp:
     30        (WebCore::findEnclosingScrollableContainer): New helper function.
     31        (WebCore::RenderElement::styleWillChange): If the current element has scroll-snap-coordinate
     32        defined, remember it for later so we can use it with the relevant scrolling container
     33        after layout completes.
     34        (WebCore::RenderElement::willBeRemovedFromTree): Unregister the current element from the
     35        RenderView.
     36        (WebCore::RenderElement::findEnclosingScrollableContainer): Added. Locate the relevant
     37        scrolling container for the current object.
     38        * rendering/RenderElement.h:
     39        * rendering/RenderView.cpp:
     40        (WebCore::Document::registerRenderElementWithScrollSnapCoordinates): Added.
     41        (WebCore::Document::unregisterRenderElementWithScrollSnapCoordinates): Added.
     42        * rendering/RenderView.h:
     43
    1442015-06-16  Brady Eidson  <beidson@apple.com>
    245
  • trunk/Source/WebCore/page/scrolling/AxisScrollSnapOffsets.cpp

    r183906 r185606  
    3232#include "Length.h"
    3333#include "RenderBox.h"
     34#include "RenderView.h"
    3435#include "ScrollableArea.h"
    3536#include "StyleScrollSnapPoints.h"
     
    4142static void appendChildSnapOffsets(HTMLElement& parent, bool shouldAddHorizontalChildOffsets, Vector<LayoutUnit>& horizontalSnapOffsetSubsequence, bool shouldAddVerticalChildOffsets, Vector<LayoutUnit>& verticalSnapOffsetSubsequence)
    4243{
    43     // FIXME: Instead of traversing all children, register children with snap coordinates before appending to snapOffsetSubsequence.
    44     for (auto& child : childrenOfType<Element>(parent)) {
    45         if (RenderBox* box = child.renderBox()) {
    46             const auto& scrollSnapCoordinates = box->style().scrollSnapCoordinates();
    47             if (scrollSnapCoordinates.isEmpty())
    48                 continue;
     44    RenderElement* scrollContainer = parent.renderer();
     45    ASSERT(scrollContainer);
     46   
     47    RenderView& renderView = scrollContainer->view();
    4948
    50             LayoutRect viewSize = box->contentBoxRect();
    51             LayoutUnit viewWidth = viewSize.width();
    52             LayoutUnit viewHeight = viewSize.height();
    53             FloatPoint position = box->localToContainerPoint(FloatPoint(), parent.renderBox());
    54             LayoutUnit left = position.x();
    55             LayoutUnit top = position.y();
    56             for (auto& coordinate : scrollSnapCoordinates) {
    57                 LayoutUnit lastPotentialSnapPositionX = left + valueForLength(coordinate.width(), viewWidth);
    58                 if (shouldAddHorizontalChildOffsets && lastPotentialSnapPositionX > 0)
    59                     horizontalSnapOffsetSubsequence.append(lastPotentialSnapPositionX);
     49    Vector<const RenderBox*> elements;
     50    for (auto& element : renderView.boxesWithScrollSnapCoordinates()) {
     51        if (element->findEnclosingScrollableContainer() != scrollContainer)
     52            continue;
    6053
    61                 LayoutUnit lastPotentialSnapPositionY = top + valueForLength(coordinate.height(), viewHeight);
    62                 if (shouldAddVerticalChildOffsets && lastPotentialSnapPositionY > 0)
    63                     verticalSnapOffsetSubsequence.append(lastPotentialSnapPositionY);
    64             }
     54        elements.append(element);
     55    }
     56
     57    for (auto& box : elements) {
     58        auto& scrollSnapCoordinates = box->style().scrollSnapCoordinates();
     59        if (scrollSnapCoordinates.isEmpty())
     60            continue;
     61       
     62        LayoutRect viewSize = box->contentBoxRect();
     63        FloatPoint position = box->localToContainerPoint(FloatPoint(), parent.renderBox());
     64        for (auto& coordinate : scrollSnapCoordinates) {
     65            LayoutUnit lastPotentialSnapPositionX = position.x() + valueForLength(coordinate.width(), viewSize.width());
     66            if (shouldAddHorizontalChildOffsets && lastPotentialSnapPositionX > 0)
     67                horizontalSnapOffsetSubsequence.append(lastPotentialSnapPositionX);
     68           
     69            LayoutUnit lastPotentialSnapPositionY = position.y() + valueForLength(coordinate.height(), viewSize.height());
     70            if (shouldAddVerticalChildOffsets && lastPotentialSnapPositionY > 0)
     71                verticalSnapOffsetSubsequence.append(lastPotentialSnapPositionY);
    6572        }
    6673    }
  • trunk/Source/WebCore/rendering/RenderBox.cpp

    r185201 r185606  
    49494949}
    49504950
     4951const RenderBox* RenderBox::findEnclosingScrollableContainer() const
     4952{
     4953    for (auto& candidate : lineageOfType<RenderBox>(*this)) {
     4954        if (candidate.hasOverflowClip())
     4955            return &candidate;
     4956    }
     4957   
     4958    return nullptr;
     4959}
     4960
    49514961} // namespace WebCore
  • trunk/Source/WebCore/rendering/RenderBox.h

    r185201 r185606  
    626626    virtual bool needsLayoutAfterRegionRangeChange() const { return false; }
    627627
     628    const RenderBox* findEnclosingScrollableContainer() const;
     629
    628630protected:
    629631    RenderBox(Element&, Ref<RenderStyle>&&, unsigned baseTypeFlags);
  • trunk/Source/WebCore/rendering/RenderElement.cpp

    r185593 r185606  
    44 *           (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
    55 *           (C) 2005, 2006 Samuel Weinig (sam.weinig@gmail.com)
    6  * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2013 Apple Inc. All rights reserved.
     6 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2013, 2015 Apple Inc. All rights reserved.
    77 * Copyright (C) 2010, 2012 Google Inc. All rights reserved.
    88 *
     
    905905    }
    906906
     907#if ENABLE(CSS_SCROLL_SNAP)
     908    if (!newStyle.scrollSnapCoordinates().isEmpty() || (oldStyle && !oldStyle->scrollSnapCoordinates().isEmpty())) {
     909        ASSERT(is<RenderBox>(this));
     910        if (newStyle.scrollSnapCoordinates().isEmpty())
     911            view().unregisterBoxWithScrollSnapCoordinates(downcast<RenderBox>(*this));
     912        else
     913            view().registerBoxWithScrollSnapCoordinates(downcast<RenderBox>(*this));
     914    }
     915#endif
     916
    907917    if (isRoot() || isBody())
    908918        view().frameView().updateExtendBackgroundIfNecessary();
     
    10581068    if (auto* containerFlowThread = parent()->renderNamedFlowThreadWrapper())
    10591069        containerFlowThread->removeFlowChild(*this);
     1070
     1071   
     1072#if ENABLE(CSS_SCROLL_SNAP)
     1073    if (!m_style->scrollSnapCoordinates().isEmpty()) {
     1074        ASSERT(is<RenderBox>(this));
     1075        view().unregisterBoxWithScrollSnapCoordinates(downcast<RenderBox>(*this));
     1076    }
     1077#endif
    10601078
    10611079    RenderObject::willBeRemovedFromTree();
  • trunk/Source/WebCore/rendering/RenderView.cpp

    r184055 r185606  
    14291429}
    14301430
     1431#if ENABLE(CSS_SCROLL_SNAP)
     1432void RenderView::registerBoxWithScrollSnapCoordinates(const RenderBox& box)
     1433{
     1434    m_boxesWithScrollSnapCoordinates.add(&box);
     1435}
     1436
     1437void RenderView::unregisterBoxWithScrollSnapCoordinates(const RenderBox& box)
     1438{
     1439    m_boxesWithScrollSnapCoordinates.remove(&box);
     1440}
     1441#endif
     1442
    14311443} // namespace WebCore
  • trunk/Source/WebCore/rendering/RenderView.h

    r183885 r185606  
    11/*
    22 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
    3  * Copyright (C) 2006 Apple Inc.
     3 * Copyright (C) 2006, 2015 Apple Inc.
    44 *
    55 * This library is free software; you can redistribute it and/or
     
    246246    void releaseProtectedRenderWidgets() { m_protectedRenderWidgets.clear(); }
    247247
     248#if ENABLE(CSS_SCROLL_SNAP)
     249    void registerBoxWithScrollSnapCoordinates(const RenderBox&);
     250    void unregisterBoxWithScrollSnapCoordinates(const RenderBox&);
     251    const HashSet<const RenderBox*>& boxesWithScrollSnapCoordinates() { return m_boxesWithScrollSnapCoordinates; }
     252#endif
     253
    248254protected:
    249255    virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags, bool* wasFixed) const override;
     
    367373#if ENABLE(SERVICE_CONTROLS)
    368374    SelectionRectGatherer m_selectionRectGatherer;
     375#endif
     376#if ENABLE(CSS_SCROLL_SNAP)
     377    HashSet<const RenderBox*> m_boxesWithScrollSnapCoordinates;
    369378#endif
    370379};
  • trunk/WebKit.xcworkspace/xcshareddata/xcschemes/All Source (target WebProcess).xcscheme

    r174034 r185606  
    154154         </BuildableReference>
    155155      </MacroExpansion>
     156      <AdditionalOptions>
     157      </AdditionalOptions>
    156158   </TestAction>
    157159   <LaunchAction
     
    163165      ignoresPersistentStateOnLaunch = "NO"
    164166      debugDocumentVersioning = "YES"
     167      debugServiceExtension = "internal"
    165168      allowLocationSimulation = "YES">
    166       <BuildableProductRunnable>
     169      <BuildableProductRunnable
     170         runnableDebuggingMode = "0">
    167171         <BuildableReference
    168172            BuildableIdentifier = "primary"
Note: See TracChangeset for help on using the changeset viewer.