Commit cc65aa54 authored by Kaan Alsan's avatar Kaan Alsan Committed by Commit Bot

[scroll-snap] Handle fractional offsets for directional snap strategies

When the currently snapped area's offset is a float number it would not
get ignored when exectuing a directional scroll. This happened because
the scrollable area's current scroll offset would be rounded, while the
snap area's position offset was not.

Now when DirectionStrategy compares the snap area's offset to the
the current offset for determining whether to snap, it will round the
difference to an int.

Bug: 959859,989738
Change-Id: I41f79182e923ea7104f678142d9fc4e971a3b881
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1969052Reviewed-by: default avatarMajid Valipour <majidvp@chromium.org>
Reviewed-by: default avatarDavid Bokan <bokan@chromium.org>
Reviewed-by: default avatarYi Gu <yigu@chromium.org>
Commit-Queue: Kaan Alsan <alsan@google.com>
Cr-Commit-Position: refs/heads/master@{#725992}
parent fce34299
...@@ -255,7 +255,7 @@ base::Optional<SnapSearchResult> SnapContainerData::FindClosestValidArea( ...@@ -255,7 +255,7 @@ base::Optional<SnapSearchResult> SnapContainerData::FindClosestValidArea(
SnapSelectionStrategy::CreateForDirection( SnapSelectionStrategy::CreateForDirection(
strategy.current_position(), strategy.current_position(),
strategy.intended_position() - strategy.current_position(), strategy.intended_position() - strategy.current_position(),
SnapStopAlwaysFilter::kRequire); strategy.UsingFractionalOffsets(), SnapStopAlwaysFilter::kRequire);
base::Optional<SnapSearchResult> must_only_result = base::Optional<SnapSearchResult> must_only_result =
FindClosestValidAreaInternal(axis, *must_only_strategy, FindClosestValidAreaInternal(axis, *must_only_strategy,
cross_axis_snap_result, false); cross_axis_snap_result, false);
......
...@@ -275,8 +275,9 @@ TEST_F(ScrollSnapDataTest, MandatoryReturnsToCurrentIfNoValidAreaForward) { ...@@ -275,8 +275,9 @@ TEST_F(ScrollSnapDataTest, MandatoryReturnsToCurrentIfNoValidAreaForward) {
gfx::ScrollOffset snap_position; gfx::ScrollOffset snap_position;
std::unique_ptr<SnapSelectionStrategy> direction_strategy = std::unique_ptr<SnapSelectionStrategy> direction_strategy =
SnapSelectionStrategy::CreateForDirection(gfx::ScrollOffset(600, 0), SnapSelectionStrategy::CreateForDirection(
gfx::ScrollOffset(5, 0)); gfx::ScrollOffset(600, 0), gfx::ScrollOffset(5, 0),
false /* use_fractional_deltas */);
EXPECT_TRUE(container.FindSnapPosition(*direction_strategy, &snap_position, EXPECT_TRUE(container.FindSnapPosition(*direction_strategy, &snap_position,
&target_elements)); &target_elements));
// The snap direction is right. However, there is no valid snap position on // The snap direction is right. However, there is no valid snap position on
...@@ -289,7 +290,8 @@ TEST_F(ScrollSnapDataTest, MandatoryReturnsToCurrentIfNoValidAreaForward) { ...@@ -289,7 +290,8 @@ TEST_F(ScrollSnapDataTest, MandatoryReturnsToCurrentIfNoValidAreaForward) {
std::unique_ptr<SnapSelectionStrategy> end_direction_strategy = std::unique_ptr<SnapSelectionStrategy> end_direction_strategy =
SnapSelectionStrategy::CreateForEndAndDirection( SnapSelectionStrategy::CreateForEndAndDirection(
gfx::ScrollOffset(600, 0), gfx::ScrollOffset(15, 15)); gfx::ScrollOffset(600, 0), gfx::ScrollOffset(15, 15),
false /* use_fractional_deltas */);
EXPECT_TRUE(container.FindSnapPosition(*end_direction_strategy, EXPECT_TRUE(container.FindSnapPosition(*end_direction_strategy,
&snap_position, &target_elements)); &snap_position, &target_elements));
// The snap direction is down and right. However, there is no valid snap // The snap direction is down and right. However, there is no valid snap
...@@ -321,8 +323,9 @@ TEST_F(ScrollSnapDataTest, MandatorySnapsBackwardIfNoValidAreaForward) { ...@@ -321,8 +323,9 @@ TEST_F(ScrollSnapDataTest, MandatorySnapsBackwardIfNoValidAreaForward) {
gfx::ScrollOffset snap_position; gfx::ScrollOffset snap_position;
std::unique_ptr<SnapSelectionStrategy> direction_strategy = std::unique_ptr<SnapSelectionStrategy> direction_strategy =
SnapSelectionStrategy::CreateForDirection(gfx::ScrollOffset(650, 0), SnapSelectionStrategy::CreateForDirection(
gfx::ScrollOffset(5, 0)); gfx::ScrollOffset(650, 0), gfx::ScrollOffset(5, 0),
false /* use_fractional_deltas */);
EXPECT_TRUE(container.FindSnapPosition(*direction_strategy, &snap_position, EXPECT_TRUE(container.FindSnapPosition(*direction_strategy, &snap_position,
&target_elements)); &target_elements));
// The snap direction is right. However, there is no valid snap position on // The snap direction is right. However, there is no valid snap position on
...@@ -335,7 +338,8 @@ TEST_F(ScrollSnapDataTest, MandatorySnapsBackwardIfNoValidAreaForward) { ...@@ -335,7 +338,8 @@ TEST_F(ScrollSnapDataTest, MandatorySnapsBackwardIfNoValidAreaForward) {
std::unique_ptr<SnapSelectionStrategy> end_direction_strategy = std::unique_ptr<SnapSelectionStrategy> end_direction_strategy =
SnapSelectionStrategy::CreateForEndAndDirection( SnapSelectionStrategy::CreateForEndAndDirection(
gfx::ScrollOffset(650, 10), gfx::ScrollOffset(15, 15)); gfx::ScrollOffset(650, 10), gfx::ScrollOffset(15, 15),
false /* use_fractional_deltas */);
EXPECT_TRUE(container.FindSnapPosition(*end_direction_strategy, EXPECT_TRUE(container.FindSnapPosition(*end_direction_strategy,
&snap_position, &target_elements)); &snap_position, &target_elements));
// The snap direction is down and right. However, there is no valid snap // The snap direction is down and right. However, there is no valid snap
...@@ -375,7 +379,8 @@ TEST_F(ScrollSnapDataTest, ShouldNotPassScrollSnapStopAlwaysElement) { ...@@ -375,7 +379,8 @@ TEST_F(ScrollSnapDataTest, ShouldNotPassScrollSnapStopAlwaysElement) {
std::unique_ptr<SnapSelectionStrategy> end_direction_strategy = std::unique_ptr<SnapSelectionStrategy> end_direction_strategy =
SnapSelectionStrategy::CreateForEndAndDirection( SnapSelectionStrategy::CreateForEndAndDirection(
gfx::ScrollOffset(0, 0), gfx::ScrollOffset(600, 0)); gfx::ScrollOffset(0, 0), gfx::ScrollOffset(600, 0),
false /* use_fractional_deltas */);
EXPECT_TRUE(container.FindSnapPosition(*end_direction_strategy, EXPECT_TRUE(container.FindSnapPosition(*end_direction_strategy,
&snap_position, &target_elements)); &snap_position, &target_elements));
...@@ -404,7 +409,8 @@ TEST_F(ScrollSnapDataTest, SnapStopAlwaysOverridesCoveringSnapArea) { ...@@ -404,7 +409,8 @@ TEST_F(ScrollSnapDataTest, SnapStopAlwaysOverridesCoveringSnapArea) {
gfx::ScrollOffset snap_position; gfx::ScrollOffset snap_position;
std::unique_ptr<SnapSelectionStrategy> strategy = std::unique_ptr<SnapSelectionStrategy> strategy =
SnapSelectionStrategy::CreateForEndAndDirection( SnapSelectionStrategy::CreateForEndAndDirection(
gfx::ScrollOffset(0, 0), gfx::ScrollOffset(300, 0)); gfx::ScrollOffset(0, 0), gfx::ScrollOffset(300, 0),
false /* use_fractional_deltas */);
// The fling is from (0, 0) to (300, 0), and the destination would make // The fling is from (0, 0) to (300, 0), and the destination would make
// the |covering_area| perfectly cover the snapport. However, another area // the |covering_area| perfectly cover the snapport. However, another area
...@@ -429,7 +435,8 @@ TEST_F(ScrollSnapDataTest, SnapStopAlwaysInReverseDirection) { ...@@ -429,7 +435,8 @@ TEST_F(ScrollSnapDataTest, SnapStopAlwaysInReverseDirection) {
gfx::ScrollOffset snap_position; gfx::ScrollOffset snap_position;
std::unique_ptr<SnapSelectionStrategy> strategy = std::unique_ptr<SnapSelectionStrategy> strategy =
SnapSelectionStrategy::CreateForEndAndDirection( SnapSelectionStrategy::CreateForEndAndDirection(
gfx::ScrollOffset(150, 0), gfx::ScrollOffset(200, 0)); gfx::ScrollOffset(150, 0), gfx::ScrollOffset(200, 0),
false /* use_fractional_deltas */);
// The fling is from (150, 0) to (350, 0), but the snap position is in the // The fling is from (150, 0) to (350, 0), but the snap position is in the
// reverse direction at (100, 0). Since the container has mandatory for // reverse direction at (100, 0). Since the container has mandatory for
...@@ -457,8 +464,9 @@ TEST_F(ScrollSnapDataTest, SnapStopAlwaysNotInterferingWithDirectionStrategy) { ...@@ -457,8 +464,9 @@ TEST_F(ScrollSnapDataTest, SnapStopAlwaysNotInterferingWithDirectionStrategy) {
// regardless its scroll-snap-stop value. // regardless its scroll-snap-stop value.
gfx::ScrollOffset snap_position; gfx::ScrollOffset snap_position;
std::unique_ptr<SnapSelectionStrategy> direction_strategy = std::unique_ptr<SnapSelectionStrategy> direction_strategy =
SnapSelectionStrategy::CreateForDirection(gfx::ScrollOffset(90, 0), SnapSelectionStrategy::CreateForDirection(
gfx::ScrollOffset(50, 0)); gfx::ScrollOffset(90, 0), gfx::ScrollOffset(50, 0),
false /* use_fractional_deltas */);
snap_position = gfx::ScrollOffset(); snap_position = gfx::ScrollOffset();
EXPECT_TRUE(container.FindSnapPosition(*direction_strategy, &snap_position, EXPECT_TRUE(container.FindSnapPosition(*direction_strategy, &snap_position,
&target_elements)); &target_elements));
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include "cc/input/snap_selection_strategy.h" #include "cc/input/snap_selection_strategy.h"
#include <cmath>
namespace cc { namespace cc {
std::unique_ptr<SnapSelectionStrategy> std::unique_ptr<SnapSelectionStrategy>
...@@ -19,16 +21,19 @@ SnapSelectionStrategy::CreateForEndPosition( ...@@ -19,16 +21,19 @@ SnapSelectionStrategy::CreateForEndPosition(
std::unique_ptr<SnapSelectionStrategy> std::unique_ptr<SnapSelectionStrategy>
SnapSelectionStrategy::CreateForDirection(gfx::ScrollOffset current_position, SnapSelectionStrategy::CreateForDirection(gfx::ScrollOffset current_position,
gfx::ScrollOffset step, gfx::ScrollOffset step,
bool use_fractional_offsets,
SnapStopAlwaysFilter filter) { SnapStopAlwaysFilter filter) {
return std::make_unique<DirectionStrategy>(current_position, step, filter); return std::make_unique<DirectionStrategy>(current_position, step, filter,
use_fractional_offsets);
} }
std::unique_ptr<SnapSelectionStrategy> std::unique_ptr<SnapSelectionStrategy>
SnapSelectionStrategy::CreateForEndAndDirection( SnapSelectionStrategy::CreateForEndAndDirection(
gfx::ScrollOffset current_position, gfx::ScrollOffset current_position,
gfx::ScrollOffset displacement) { gfx::ScrollOffset displacement,
return std::make_unique<EndAndDirectionStrategy>(current_position, bool use_fractional_offsets) {
displacement); return std::make_unique<EndAndDirectionStrategy>(
current_position, displacement, use_fractional_offsets);
} }
std::unique_ptr<SnapSelectionStrategy> std::unique_ptr<SnapSelectionStrategy>
...@@ -58,6 +63,10 @@ bool SnapSelectionStrategy::ShouldPrioritizeSnapTargets() const { ...@@ -58,6 +63,10 @@ bool SnapSelectionStrategy::ShouldPrioritizeSnapTargets() const {
return false; return false;
} }
bool SnapSelectionStrategy::UsingFractionalOffsets() const {
return false;
}
bool EndPositionStrategy::ShouldSnapOnX() const { bool EndPositionStrategy::ShouldSnapOnX() const {
return scrolled_x_; return scrolled_x_;
} }
...@@ -113,14 +122,22 @@ gfx::ScrollOffset DirectionStrategy::base_position() const { ...@@ -113,14 +122,22 @@ gfx::ScrollOffset DirectionStrategy::base_position() const {
bool DirectionStrategy::IsValidSnapPosition(SearchAxis axis, bool DirectionStrategy::IsValidSnapPosition(SearchAxis axis,
float position) const { float position) const {
// If not using fractional offsets then it is possible for the currently
// snapped area's offset, which is fractional, to not be equal to the current
// scroll offset, which is not fractional. Therefore we round the offsets so
// that any position within 0.5 of the current position is ignored.
if (axis == SearchAxis::kX) { if (axis == SearchAxis::kX) {
return (step_.x() > 0 && float delta = position - current_position_.x();
position > current_position_.x()) || // "Right" arrow if (!use_fractional_offsets_)
(step_.x() < 0 && position < current_position_.x()); // "Left" arrow delta = std::round(delta);
return (step_.x() > 0 && delta > 0) || // "Right" arrow
(step_.x() < 0 && delta < 0); // "Left" arrow
} else { } else {
return (step_.y() > 0 && float delta = position - current_position_.y();
position > current_position_.y()) || // "Down" arrow if (!use_fractional_offsets_)
(step_.y() < 0 && position < current_position_.y()); // "Up" arrow delta = std::round(delta);
return (step_.y() > 0 && delta > 0) || // "Down" arrow
(step_.y() < 0 && delta < 0); // "Up" arrow
} }
} }
...@@ -157,6 +174,10 @@ const base::Optional<SnapSearchResult>& DirectionStrategy::PickBestResult( ...@@ -157,6 +174,10 @@ const base::Optional<SnapSearchResult>& DirectionStrategy::PickBestResult(
return covering; return covering;
} }
bool DirectionStrategy::UsingFractionalOffsets() const {
return use_fractional_offsets_;
}
bool EndAndDirectionStrategy::ShouldSnapOnX() const { bool EndAndDirectionStrategy::ShouldSnapOnX() const {
return displacement_.x() != 0; return displacement_.x() != 0;
} }
...@@ -175,14 +196,22 @@ gfx::ScrollOffset EndAndDirectionStrategy::base_position() const { ...@@ -175,14 +196,22 @@ gfx::ScrollOffset EndAndDirectionStrategy::base_position() const {
bool EndAndDirectionStrategy::IsValidSnapPosition(SearchAxis axis, bool EndAndDirectionStrategy::IsValidSnapPosition(SearchAxis axis,
float position) const { float position) const {
// If not using fractional offsets then it is possible for the currently
// snapped area's offset, which is fractional, to not be equal to the current
// scroll offset, which is not fractional. Therefore we round the offsets so
// that any position within 0.5 of the current position is ignored.
if (axis == SearchAxis::kX) { if (axis == SearchAxis::kX) {
return (displacement_.x() > 0 && float delta = position - current_position_.x();
position > current_position_.x()) || // Right if (!use_fractional_offsets_)
(displacement_.x() < 0 && position < current_position_.x()); // Left delta = std::round(delta);
return (displacement_.x() > 0 && delta > 0) || // Right
(displacement_.x() < 0 && delta < 0); // Left
} else { } else {
return (displacement_.y() > 0 && float delta = position - current_position_.y();
position > current_position_.y()) || // Down if (!use_fractional_offsets_)
(displacement_.y() < 0 && position < current_position_.y()); // Up delta = std::round(delta);
return (displacement_.y() > 0 && delta > 0) || // Down
(displacement_.y() < 0 && delta < 0); // Up
} }
} }
...@@ -196,4 +225,8 @@ const base::Optional<SnapSearchResult>& EndAndDirectionStrategy::PickBestResult( ...@@ -196,4 +225,8 @@ const base::Optional<SnapSearchResult>& EndAndDirectionStrategy::PickBestResult(
return covering.has_value() ? covering : closest; return covering.has_value() ? covering : closest;
} }
bool EndAndDirectionStrategy::UsingFractionalOffsets() const {
return use_fractional_offsets_;
}
} // namespace cc } // namespace cc
...@@ -28,13 +28,18 @@ class CC_EXPORT SnapSelectionStrategy { ...@@ -28,13 +28,18 @@ class CC_EXPORT SnapSelectionStrategy {
bool scrolled_y, bool scrolled_y,
SnapTargetsPrioritization prioritization = SnapTargetsPrioritization prioritization =
SnapTargetsPrioritization::kIgnore); SnapTargetsPrioritization::kIgnore);
// |use_fractional_offsets| should be true when the current position is
// provided in fractional pixels.
static std::unique_ptr<SnapSelectionStrategy> CreateForDirection( static std::unique_ptr<SnapSelectionStrategy> CreateForDirection(
gfx::ScrollOffset current_position, gfx::ScrollOffset current_position,
gfx::ScrollOffset step, gfx::ScrollOffset step,
bool use_fractional_offsets,
SnapStopAlwaysFilter filter = SnapStopAlwaysFilter::kIgnore); SnapStopAlwaysFilter filter = SnapStopAlwaysFilter::kIgnore);
static std::unique_ptr<SnapSelectionStrategy> CreateForEndAndDirection( static std::unique_ptr<SnapSelectionStrategy> CreateForEndAndDirection(
gfx::ScrollOffset current_position, gfx::ScrollOffset current_position,
gfx::ScrollOffset displacement); gfx::ScrollOffset displacement,
bool use_fractional_offsets);
// Creates a selection strategy that attempts to snap to previously snapped // Creates a selection strategy that attempts to snap to previously snapped
// targets if possible, but defaults to finding the closest snap point if // targets if possible, but defaults to finding the closest snap point if
...@@ -81,6 +86,10 @@ class CC_EXPORT SnapSelectionStrategy { ...@@ -81,6 +86,10 @@ class CC_EXPORT SnapSelectionStrategy {
const base::Optional<SnapSearchResult>& closest, const base::Optional<SnapSearchResult>& closest,
const base::Optional<SnapSearchResult>& covering) const = 0; const base::Optional<SnapSearchResult>& covering) const = 0;
// Returns true when the current scroll offset is provided in fractional
// pixels.
virtual bool UsingFractionalOffsets() const;
protected: protected:
explicit SnapSelectionStrategy(const gfx::ScrollOffset& current_position) explicit SnapSelectionStrategy(const gfx::ScrollOffset& current_position)
: current_position_(current_position) {} : current_position_(current_position) {}
...@@ -140,12 +149,16 @@ class EndPositionStrategy : public SnapSelectionStrategy { ...@@ -140,12 +149,16 @@ class EndPositionStrategy : public SnapSelectionStrategy {
// a snap area covers the snapport. // a snap area covers the snapport.
class DirectionStrategy : public SnapSelectionStrategy { class DirectionStrategy : public SnapSelectionStrategy {
public: public:
// |use_fractional_offsets| should be true when the current position is
// provided in fractional pixels.
DirectionStrategy(const gfx::ScrollOffset& current_position, DirectionStrategy(const gfx::ScrollOffset& current_position,
const gfx::ScrollOffset& step, const gfx::ScrollOffset& step,
SnapStopAlwaysFilter filter) SnapStopAlwaysFilter filter,
bool use_fractional_offsets)
: SnapSelectionStrategy(current_position), : SnapSelectionStrategy(current_position),
step_(step), step_(step),
snap_stop_always_filter_(filter) {} snap_stop_always_filter_(filter),
use_fractional_offsets_(use_fractional_offsets) {}
~DirectionStrategy() override = default; ~DirectionStrategy() override = default;
bool ShouldSnapOnX() const override; bool ShouldSnapOnX() const override;
...@@ -162,10 +175,13 @@ class DirectionStrategy : public SnapSelectionStrategy { ...@@ -162,10 +175,13 @@ class DirectionStrategy : public SnapSelectionStrategy {
const base::Optional<SnapSearchResult>& closest, const base::Optional<SnapSearchResult>& closest,
const base::Optional<SnapSearchResult>& covering) const override; const base::Optional<SnapSearchResult>& covering) const override;
bool UsingFractionalOffsets() const override;
private: private:
// The default step for this DirectionStrategy. // The default step for this DirectionStrategy.
const gfx::ScrollOffset step_; const gfx::ScrollOffset step_;
SnapStopAlwaysFilter snap_stop_always_filter_; SnapStopAlwaysFilter snap_stop_always_filter_;
bool use_fractional_offsets_;
}; };
// Examples for intended direction and end position scrolls include // Examples for intended direction and end position scrolls include
...@@ -178,9 +194,14 @@ class DirectionStrategy : public SnapSelectionStrategy { ...@@ -178,9 +194,14 @@ class DirectionStrategy : public SnapSelectionStrategy {
// * Return the end position if that makes a snap area covers the snapport. // * Return the end position if that makes a snap area covers the snapport.
class EndAndDirectionStrategy : public SnapSelectionStrategy { class EndAndDirectionStrategy : public SnapSelectionStrategy {
public: public:
// |use_fractional_offsets| should be true when the current position is
// provided in fractional pixels.
EndAndDirectionStrategy(const gfx::ScrollOffset& current_position, EndAndDirectionStrategy(const gfx::ScrollOffset& current_position,
const gfx::ScrollOffset& displacement) const gfx::ScrollOffset& displacement,
: SnapSelectionStrategy(current_position), displacement_(displacement) {} bool use_fractional_offsets)
: SnapSelectionStrategy(current_position),
displacement_(displacement),
use_fractional_offsets_(use_fractional_offsets) {}
~EndAndDirectionStrategy() override = default; ~EndAndDirectionStrategy() override = default;
bool ShouldSnapOnX() const override; bool ShouldSnapOnX() const override;
...@@ -197,8 +218,11 @@ class EndAndDirectionStrategy : public SnapSelectionStrategy { ...@@ -197,8 +218,11 @@ class EndAndDirectionStrategy : public SnapSelectionStrategy {
const base::Optional<SnapSearchResult>& closest, const base::Optional<SnapSearchResult>& closest,
const base::Optional<SnapSearchResult>& covering) const override; const base::Optional<SnapSearchResult>& covering) const override;
bool UsingFractionalOffsets() const override;
private: private:
const gfx::ScrollOffset displacement_; const gfx::ScrollOffset displacement_;
bool use_fractional_offsets_;
}; };
} // namespace cc } // namespace cc
......
...@@ -4958,12 +4958,14 @@ bool LayerTreeHostImpl::GetSnapFlingInfoAndSetAnimatingSnapTarget( ...@@ -4958,12 +4958,14 @@ bool LayerTreeHostImpl::GetSnapFlingInfoAndSetAnimatingSnapTarget(
gfx::ScrollOffset current_offset = GetVisualScrollOffset(*scroll_node); gfx::ScrollOffset current_offset = GetVisualScrollOffset(*scroll_node);
*out_initial_position = ScrollOffsetToVector2dF(current_offset); *out_initial_position = ScrollOffsetToVector2dF(current_offset);
// CC side always uses fractional scroll deltas.
bool use_fractional_offsets = true;
gfx::ScrollOffset snap_offset; gfx::ScrollOffset snap_offset;
TargetSnapAreaElementIds snap_target_ids; TargetSnapAreaElementIds snap_target_ids;
std::unique_ptr<SnapSelectionStrategy> strategy = std::unique_ptr<SnapSelectionStrategy> strategy =
SnapSelectionStrategy::CreateForEndAndDirection( SnapSelectionStrategy::CreateForEndAndDirection(
current_offset, gfx::ScrollOffset(natural_displacement_in_content)); current_offset, gfx::ScrollOffset(natural_displacement_in_content),
use_fractional_offsets);
if (!data.FindSnapPosition(*strategy, &snap_offset, &snap_target_ids)) if (!data.FindSnapPosition(*strategy, &snap_offset, &snap_target_ids))
return false; return false;
scroll_animating_snap_target_ids_ = snap_target_ids; scroll_animating_snap_target_ids_ = snap_target_ids;
......
...@@ -1637,8 +1637,9 @@ void Element::ScrollLayoutBoxBy(const ScrollToOptions* scroll_to_options) { ...@@ -1637,8 +1637,9 @@ void Element::ScrollLayoutBoxBy(const ScrollToOptions* scroll_to_options) {
FloatPoint new_position(new_offset.x(), new_offset.y()); FloatPoint new_position(new_offset.x(), new_offset.y());
std::unique_ptr<cc::SnapSelectionStrategy> strategy = std::unique_ptr<cc::SnapSelectionStrategy> strategy =
cc::SnapSelectionStrategy::CreateForEndAndDirection(current_position, cc::SnapSelectionStrategy::CreateForEndAndDirection(
displacement); current_position, displacement,
RuntimeEnabledFeatures::FractionalScrollOffsetsEnabled());
new_position = new_position =
scrollable_area->GetSnapPositionAndSetTarget(*strategy).value_or( scrollable_area->GetSnapPositionAndSetTarget(*strategy).value_or(
new_position); new_position);
...@@ -1764,8 +1765,9 @@ void Element::ScrollFrameBy(const ScrollToOptions* scroll_to_options) { ...@@ -1764,8 +1765,9 @@ void Element::ScrollFrameBy(const ScrollToOptions* scroll_to_options) {
gfx::ScrollOffset current_position(viewport->ScrollPosition()); gfx::ScrollOffset current_position(viewport->ScrollPosition());
std::unique_ptr<cc::SnapSelectionStrategy> strategy = std::unique_ptr<cc::SnapSelectionStrategy> strategy =
cc::SnapSelectionStrategy::CreateForEndAndDirection(current_position, cc::SnapSelectionStrategy::CreateForEndAndDirection(
displacement); current_position, displacement,
RuntimeEnabledFeatures::FractionalScrollOffsetsEnabled());
new_position = new_position =
viewport->GetSnapPositionAndSetTarget(*strategy).value_or(new_position); viewport->GetSnapPositionAndSetTarget(*strategy).value_or(new_position);
viewport->SetScrollOffset(viewport->ScrollPositionToOffset(new_position), viewport->SetScrollOffset(viewport->ScrollPositionToOffset(new_position),
......
...@@ -1090,7 +1090,8 @@ void LocalDOMWindow::scrollBy(const ScrollToOptions* scroll_to_options) const { ...@@ -1090,7 +1090,8 @@ void LocalDOMWindow::scrollBy(const ScrollToOptions* scroll_to_options) const {
std::unique_ptr<cc::SnapSelectionStrategy> strategy = std::unique_ptr<cc::SnapSelectionStrategy> strategy =
cc::SnapSelectionStrategy::CreateForEndAndDirection( cc::SnapSelectionStrategy::CreateForEndAndDirection(
gfx::ScrollOffset(current_position), gfx::ScrollOffset(scaled_delta)); gfx::ScrollOffset(current_position), gfx::ScrollOffset(scaled_delta),
RuntimeEnabledFeatures::FractionalScrollOffsetsEnabled());
new_scaled_position = new_scaled_position =
viewport->GetSnapPositionAndSetTarget(*strategy).value_or( viewport->GetSnapPositionAndSetTarget(*strategy).value_or(
new_scaled_position); new_scaled_position);
......
...@@ -792,7 +792,8 @@ bool ScrollManager::GetSnapFlingInfoAndSetAnimatingSnapTarget( ...@@ -792,7 +792,8 @@ bool ScrollManager::GetSnapFlingInfoAndSetAnimatingSnapTarget(
std::unique_ptr<cc::SnapSelectionStrategy> strategy = std::unique_ptr<cc::SnapSelectionStrategy> strategy =
cc::SnapSelectionStrategy::CreateForEndAndDirection( cc::SnapSelectionStrategy::CreateForEndAndDirection(
gfx::ScrollOffset(*out_initial_position), gfx::ScrollOffset(*out_initial_position),
gfx::ScrollOffset(natural_displacement)); gfx::ScrollOffset(natural_displacement),
RuntimeEnabledFeatures::FractionalScrollOffsetsEnabled());
base::Optional<FloatPoint> snap_end = base::Optional<FloatPoint> snap_end =
scrollable_area->GetSnapPositionAndSetTarget(*strategy); scrollable_area->GetSnapPositionAndSetTarget(*strategy);
if (!snap_end.has_value()) if (!snap_end.has_value())
......
...@@ -853,7 +853,8 @@ bool ScrollableArea::SnapForDirection(const ScrollOffset& delta, ...@@ -853,7 +853,8 @@ bool ScrollableArea::SnapForDirection(const ScrollOffset& delta,
std::unique_ptr<cc::SnapSelectionStrategy> strategy = std::unique_ptr<cc::SnapSelectionStrategy> strategy =
cc::SnapSelectionStrategy::CreateForDirection( cc::SnapSelectionStrategy::CreateForDirection(
gfx::ScrollOffset(current_position), gfx::ScrollOffset(current_position),
gfx::ScrollOffset(delta.Width(), delta.Height())); gfx::ScrollOffset(delta.Width(), delta.Height()),
RuntimeEnabledFeatures::FractionalScrollOffsetsEnabled());
return PerformSnapping(*strategy, kScrollBehaviorSmooth, return PerformSnapping(*strategy, kScrollBehaviorSmooth,
std::move(on_finish)); std::move(on_finish));
} }
...@@ -864,7 +865,8 @@ bool ScrollableArea::SnapForEndAndDirection(const ScrollOffset& delta) { ...@@ -864,7 +865,8 @@ bool ScrollableArea::SnapForEndAndDirection(const ScrollOffset& delta) {
std::unique_ptr<cc::SnapSelectionStrategy> strategy = std::unique_ptr<cc::SnapSelectionStrategy> strategy =
cc::SnapSelectionStrategy::CreateForEndAndDirection( cc::SnapSelectionStrategy::CreateForEndAndDirection(
gfx::ScrollOffset(current_position), gfx::ScrollOffset(current_position),
gfx::ScrollOffset(delta.Width(), delta.Height())); gfx::ScrollOffset(delta.Width(), delta.Height()),
RuntimeEnabledFeatures::FractionalScrollOffsetsEnabled());
return PerformSnapping(*strategy); return PerformSnapping(*strategy);
} }
......
<!DOCTYPE html>
<script src="../../resources/gesture-util.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<style>
html {
scroll-snap-type: y mandatory;
}
body {
overflow: scroll;
height: 300px;
width: 300px;
margin: 0;
padding: 0;
}
#container {
margin: 0;
padding: 0;
width: 600px;
height: 1833px; /* use a percentage of this to make snap offsets float numbers */
}
#initial-area {
position: relative;
top: 10%; /* ~183.3 */
width: 200px;
height: 200px;
background-color: blue;
scroll-snap-align: start;
}
#target-area {
position: relative;
top: 30%; /* ~549.9 */
width: 200px;
height: 200px;
background-color: blue;
scroll-snap-align: start;
}
</style>
<div id="container">
<div id="initial-area"></div>
<div id="target-area"></div>
</div>
<script>
const scroller = document.scrollingElement;
const initial_area = document.getElementById('initial-area');
const target_area = document.getElementById('target-area');
function cleanup() {
scroller.scrollTo(0, 183);
}
function keyPress(key) {
return new Promise((resolve, reject) => {
if (window.eventSender) {
eventSender.keyDown(key);
resolve();
}
else {
reject('This test requires window.eventSender');
}
})
}
promise_test (async t => {
t.add_cleanup(cleanup);
scroller.scrollTo(0,183);
assert_approx_equals(scroller.scrollTop, initial_area.offsetTop, 1);
await mouseClickOn(10, 10);
await keyPress('ArrowDown');
await waitForAnimationEnd(() => { return scroller.scrollTop; }, 500, 15);
assert_approx_equals(scroller.scrollTop, target_area.offsetTop, 1);
await keyPress('ArrowUp');
await waitForAnimationEnd(() => { return scroller.scrollTop; }, 500, 15);
assert_approx_equals(scroller.scrollTop, initial_area.offsetTop, 1);
}, "Keyboard scrolling should ignore the current snapped element even when its"
+ " offset is a fractional number.");
promise_test (async t => {
t.add_cleanup(cleanup);
assert_approx_equals(scroller.scrollTop, initial_area.offsetTop, 1);
scroller.scrollBy(0, 10);
await waitForAnimationEnd(() => { return scroller.scrollTop; }, 500, 15);
assert_approx_equals(scroller.scrollTop, target_area.offsetTop, 1);
scroller.scrollBy(0, -10);
await waitForAnimationEnd(() => { return scroller.scrollTop; }, 500, 15);
assert_approx_equals(scroller.scrollTop, initial_area.offsetTop, 1);
}, "Programmatic directional scrolling should ignore the current snapped element"
+ " even when its offset is a fractional number.");
</script>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment