Changeset 281189 in webkit


Ignore:
Timestamp:
Aug 18, 2021 8:59:48 AM (11 months ago)
Author:
Martin Robinson
Message:

[css-scroll-snap] Don't snap to offscreen snap areas in unidirectional scrolls
https://bugs.webkit.org/show_bug.cgi?id=227949
<rdar://problem/80895783>

Reviewed by Frédéric Wang.

LayoutTests/imported/w3c:

  • web-platform-tests/css/css-scroll-snap/snap-to-visible-areas-both-expected.txt: This bidirectional

scrolling test no longer snaps because we don't have support for choosing between two candidates
properly yet.

  • web-platform-tests/css/css-scroll-snap/snap-to-visible-areas-x-axis-expected.txt: Updated to show newly passing test.
  • web-platform-tests/css/css-scroll-snap/snap-to-visible-areas-y-axis-expected.txt: Ditto.

Source/WebCore:

No new tests. This is covered by two existing WPT tests.

  • page/scrolling/ScrollSnapOffsetsInfo.cpp:

(WebCore::componentForAxis): Added this helper.
(WebCore::hasCompatibleSnapArea): Added this helper that checks to see if any of the snap areas
at a given scroll snap position are compatible with the viewport.
(WebCore::adjustPreviousAndNextForOnscreenSnapAreas): Adjusts the selected previous and next snap
positions by looking backward and forward for the first compatible snap position.
(WebCore::closestSnapOffsetWithInfoAndAxis): Use the new helper.

Location:
trunk
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/imported/w3c/ChangeLog

    r281147 r281189  
     12021-08-18  Martin Robinson  <mrobinson@webkit.org>
     2
     3        [css-scroll-snap] Don't snap to offscreen snap areas in unidirectional scrolls
     4        https://bugs.webkit.org/show_bug.cgi?id=227949
     5        <rdar://problem/80895783>
     6
     7        Reviewed by Frédéric Wang.
     8
     9        * web-platform-tests/css/css-scroll-snap/snap-to-visible-areas-both-expected.txt: This bidirectional
     10        scrolling test no longer snaps because we don't have support for choosing between two candidates
     11        properly yet.
     12        * web-platform-tests/css/css-scroll-snap/snap-to-visible-areas-x-axis-expected.txt: Updated to show newly passing test.
     13        * web-platform-tests/css/css-scroll-snap/snap-to-visible-areas-y-axis-expected.txt: Ditto.
     14
    1152021-08-17  Alex Christensen  <achristensen@webkit.org>
    216
  • trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-scroll-snap/snap-to-visible-areas-both-expected.txt

    r271439 r281189  
    11
    2 FAIL Only snap to visible areas in the case where taking the closest snap point of   each axis does not snap to a visible area assert_equals: expected 0 but got 800
     2FAIL Only snap to visible areas in the case where taking the closest snap point of   each axis does not snap to a visible area assert_equals: expected 800 but got 0
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-scroll-snap/snap-to-visible-areas-x-axis-expected.txt

    r271439 r281189  
    11
    2 FAIL Only snap to visible area on X axis, even when the non-visible ones are closer assert_equals: expected 800 but got 700
     2PASS Only snap to visible area on X axis, even when the non-visible ones are closer
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-scroll-snap/snap-to-visible-areas-y-axis-expected.txt

    r271439 r281189  
    11
    2 FAIL Only snap to visible area on Y axis, even when the non-visible ones are closer assert_equals: expected 800 but got 700
     2PASS Only snap to visible area on Y axis, even when the non-visible ones are closer
    33
  • trunk/Source/WebCore/ChangeLog

    r281188 r281189  
     12021-08-18  Martin Robinson  <mrobinson@webkit.org>
     2
     3        [css-scroll-snap] Don't snap to offscreen snap areas in unidirectional scrolls
     4        https://bugs.webkit.org/show_bug.cgi?id=227949
     5        <rdar://problem/80895783>
     6
     7        Reviewed by Frédéric Wang.
     8
     9        No new tests. This is covered by two existing WPT tests.
     10
     11        * page/scrolling/ScrollSnapOffsetsInfo.cpp:
     12        (WebCore::componentForAxis): Added this helper.
     13        (WebCore::hasCompatibleSnapArea): Added this helper that checks to see if any of the snap areas
     14        at a given scroll snap position are compatible with the viewport.
     15        (WebCore::adjustPreviousAndNextForOnscreenSnapAreas): Adjusts the selected previous and next snap
     16        positions by looking backward and forward for the first compatible snap position.
     17        (WebCore::closestSnapOffsetWithInfoAndAxis): Use the new helper.
     18
    1192021-08-18  Chris Dumez  <cdumez@apple.com>
    220
  • trunk/Source/WebCore/page/scrolling/ScrollSnapOffsetsInfo.cpp

    r280632 r281189  
    101101}
    102102
     103template <typename UnitType, typename PointType>
     104static UnitType componentForAxis(PointType point, ScrollEventAxis axis)
     105{
     106    return axis == ScrollEventAxis::Horizontal ? point.x() : point.y();
     107}
     108
     109template <typename InfoType, typename UnitType, typename PointType, typename SizeType>
     110static bool hasCompatibleSnapArea(const InfoType& info, const SnapOffset<UnitType>& snapOffset, ScrollEventAxis axis, const SizeType& viewportSize, PointType destinationOffsetPoint)
     111{
     112    auto otherAxis = axis == ScrollEventAxis::Horizontal ? ScrollEventAxis::Vertical : ScrollEventAxis::Horizontal;
     113    auto scrollDestinationInOtherAxis = componentForAxis<UnitType, PointType>(destinationOffsetPoint, otherAxis);
     114    auto viewportLengthInOtherAxis = axis == ScrollEventAxis::Horizontal ? viewportSize.height() : viewportSize.width();
     115
     116    return snapOffset.snapAreaIndices.findMatching([&] (auto index) {
     117        const auto& snapArea = info.snapAreas[index];
     118        auto [otherAxisMin, otherAxisMax] = rangeForAxis<UnitType>(snapArea, otherAxis);
     119        return (scrollDestinationInOtherAxis + viewportLengthInOtherAxis) > otherAxisMin && scrollDestinationInOtherAxis < otherAxisMax;
     120    }) != notFound;
     121}
     122
     123template <typename InfoType, typename UnitType, typename PointType, typename SizeType>
     124static void adjustPreviousAndNextForOnScreenSnapAreas(const InfoType& info, ScrollEventAxis axis, const SizeType& viewportSize, PointType destinationOffsetPoint, PotentialSnapPointSearchResult<UnitType>& searchResult)
     125{
     126    // hasCompatibleSnapArea needs to look at all compatible snap areas, which might be a large
     127    // number for snap areas arranged in a grid. Since this might be expensive, this code tries
     128    // to look at the mostly closest compatible snap areas first.
     129    const auto& snapOffsets = info.offsetsForAxis(axis);
     130    if (searchResult.previous) {
     131        unsigned oldIndex = (*searchResult.previous).second;
     132        searchResult.previous.reset();
     133        for (unsigned offset = 0; offset <= oldIndex; offset++) {
     134            unsigned index = oldIndex - offset;
     135            const auto& snapOffset = snapOffsets[index];
     136            if (hasCompatibleSnapArea(info, snapOffset, axis, viewportSize, destinationOffsetPoint)) {
     137                searchResult.previous = { snapOffset.offset, index };
     138                break;
     139            }
     140        }
     141    }
     142
     143    if (searchResult.next) {
     144        unsigned oldIndex = (*searchResult.next).second;
     145        searchResult.next.reset();
     146        for (unsigned index = oldIndex; index < snapOffsets.size(); index++) {
     147            const auto& snapOffset = snapOffsets[index];
     148            if (hasCompatibleSnapArea(info, snapOffset, axis, viewportSize, destinationOffsetPoint)) {
     149                searchResult.next = { snapOffset.offset, index };
     150                break;
     151            }
     152        }
     153    }
     154}
     155
    103156template <typename InfoType, typename SizeType, typename LayoutType, typename PointType>
    104157static std::pair<LayoutType, std::optional<unsigned>> closestSnapOffsetWithInfoAndAxis(const InfoType& info, ScrollEventAxis axis, const SizeType& viewportSize, PointType scrollDestinationOffsetPoint, float velocity, std::optional<LayoutType> originalOffsetForDirectionalSnapping)
     
    111164
    112165    auto viewportLength = axis == ScrollEventAxis::Horizontal ? viewportSize.width() : viewportSize.height();
    113     auto [previous, next, snapStop, landedInsideSnapAreaThatConsumesViewport] = searchForPotentialSnapPoints(info, axis, viewportLength, scrollDestinationOffset, originalOffsetForDirectionalSnapping);
    114     if (snapStop)
    115         return *snapStop;
     166    auto searchResult = searchForPotentialSnapPoints(info, axis, viewportLength, scrollDestinationOffset, originalOffsetForDirectionalSnapping);
     167    if (searchResult.snapStop)
     168        return *(searchResult.snapStop);
     169
     170    adjustPreviousAndNextForOnScreenSnapAreas<InfoType, LayoutType, PointType, SizeType>(info, axis, viewportSize, scrollDestinationOffsetPoint, searchResult);
     171    auto& previous = searchResult.previous;
     172    auto& next = searchResult.next;
    116173
    117174    // From https://www.w3.org/TR/css-scroll-snap-1/#snap-overflow
     
    121178    // that axis, is a valid snap position in that axis. The UA may use the specified alignment as a
    122179    // more precise target for certain scroll operations (e.g. explicit paging)."
    123     if (landedInsideSnapAreaThatConsumesViewport && (!previous || !next || ((*next).first - (*previous).first) >= viewportLength))
     180    if (searchResult.landedInsideSnapAreaThatConsumesViewport && (!previous || !next || ((*next).first - (*previous).first) >= viewportLength))
    124181        return pairForNoSnapping;
    125182
Note: See TracChangeset for help on using the changeset viewer.