Commit 12bb4250 authored by Rahul Arakeri's avatar Rahul Arakeri Committed by Commit Bot

New Windows root scroller overscroll - Part 3.

This CL implements the bounce forwards animation for when user performs
a fling. When the scroller reaches the bounds, the residual velocity
determines the extent of the overscroll. This then gets applied to the
scroller followed by the usual bounce back animation.

Bug: 1058071
Change-Id: Id14cfff5e99843bd9849d7122058dc16d929e74c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2337940
Commit-Queue: Rahul Arakeri <arakeri@microsoft.com>
Reviewed-by: default avatarRobert Flack <flackr@chromium.org>
Reviewed-by: default avatarPhilip Rogers <pdr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#795630}
parent c1577e45
...@@ -96,7 +96,8 @@ class PLATFORM_EXPORT ElasticOverscrollController { ...@@ -96,7 +96,8 @@ class PLATFORM_EXPORT ElasticOverscrollController {
virtual gfx::Vector2d AccumulatedOverscrollForStretchAmount( virtual gfx::Vector2d AccumulatedOverscrollForStretchAmount(
const gfx::Vector2dF& stretch_amount) const = 0; const gfx::Vector2dF& stretch_amount) const = 0;
gfx::Size GetScrollBounds() const { return helper_->ScrollBounds(); } gfx::Size scroll_bounds() const { return helper_->ScrollBounds(); }
gfx::Vector2dF scroll_velocity() const { return scroll_velocity_; }
// TODO (arakeri): Need to be cleared when we leave MomentumAnimated. // TODO (arakeri): Need to be cleared when we leave MomentumAnimated.
// Momentum animation state. This state is valid only while the state is // Momentum animation state. This state is valid only while the state is
...@@ -106,7 +107,9 @@ class PLATFORM_EXPORT ElasticOverscrollController { ...@@ -106,7 +107,9 @@ class PLATFORM_EXPORT ElasticOverscrollController {
private: private:
FRIEND_TEST_ALL_PREFIXES(ElasticOverscrollControllerBezierTest, FRIEND_TEST_ALL_PREFIXES(ElasticOverscrollControllerBezierTest,
VerifyAnimationTick); VerifyBackwardAnimationTick);
FRIEND_TEST_ALL_PREFIXES(ElasticOverscrollControllerBezierTest,
VerifyForwardAnimationTick);
enum State { enum State {
// The initial state, during which the overscroll amount is zero and // The initial state, during which the overscroll amount is zero and
......
...@@ -33,11 +33,24 @@ class PLATFORM_EXPORT ElasticOverscrollControllerBezier ...@@ -33,11 +33,24 @@ class PLATFORM_EXPORT ElasticOverscrollControllerBezier
gfx::Vector2d AccumulatedOverscrollForStretchAmount( gfx::Vector2d AccumulatedOverscrollForStretchAmount(
const gfx::Vector2dF& delta) const override; const gfx::Vector2dF& delta) const override;
gfx::Vector2dF OverscrollBoundary(const gfx::Size& scroller_bounds) const; gfx::Vector2dF OverscrollBoundary(const gfx::Size& scroller_bounds) const;
double StretchAmountForForwardBounce(
const base::TimeDelta& delta,
const base::TimeDelta& bounce_forwards_duration,
const double velocity,
const double initial_stretch,
const double bounce_forwards_distance) const;
double StretchAmountForBackwardBounce(
const base::TimeDelta& delta,
const base::TimeDelta& bounce_backwards_duration,
const double bounce_forwards_distance) const;
private: private:
const gfx::CubicBezier bounce_backwards_curve_; const gfx::CubicBezier bounce_forwards_curve_;
base::TimeDelta bounce_forwards_duration_x_;
base::TimeDelta bounce_forwards_duration_y_;
gfx::Vector2dF bounce_forwards_distance_;
// The following are used to track the duration of the bounce back animation. const gfx::CubicBezier bounce_backwards_curve_;
base::TimeDelta bounce_backwards_duration_x_; base::TimeDelta bounce_backwards_duration_x_;
base::TimeDelta bounce_backwards_duration_y_; base::TimeDelta bounce_backwards_duration_y_;
DISALLOW_COPY_AND_ASSIGN(ElasticOverscrollControllerBezier); DISALLOW_COPY_AND_ASSIGN(ElasticOverscrollControllerBezier);
......
...@@ -70,15 +70,11 @@ class ElasticOverscrollControllerBezierTest : public testing::Test { ...@@ -70,15 +70,11 @@ class ElasticOverscrollControllerBezierTest : public testing::Test {
} }
void SendGestureScrollUpdate(PhaseState inertialPhase, void SendGestureScrollUpdate(PhaseState inertialPhase,
const Vector2dF& scroll_delta,
const Vector2dF& unused_scroll_delta) { const Vector2dF& unused_scroll_delta) {
blink::WebGestureEvent event(WebInputEvent::Type::kGestureScrollUpdate, blink::WebGestureEvent event(WebInputEvent::Type::kGestureScrollUpdate,
WebInputEvent::kNoModifiers, base::TimeTicks(), WebInputEvent::kNoModifiers, base::TimeTicks(),
blink::WebGestureDevice::kTouchpad); blink::WebGestureDevice::kTouchpad);
event.data.scroll_update.inertial_phase = inertialPhase; event.data.scroll_update.inertial_phase = inertialPhase;
event.data.scroll_update.delta_x = -scroll_delta.x();
event.data.scroll_update.delta_y = -scroll_delta.y();
cc::InputHandlerScrollResult scroll_result; cc::InputHandlerScrollResult scroll_result;
scroll_result.did_overscroll_root = !unused_scroll_delta.IsZero(); scroll_result.did_overscroll_root = !unused_scroll_delta.IsZero();
scroll_result.unused_scroll_delta = unused_scroll_delta; scroll_result.unused_scroll_delta = unused_scroll_delta;
...@@ -103,22 +99,18 @@ TEST_F(ElasticOverscrollControllerBezierTest, VerifyOverscrollStretch) { ...@@ -103,22 +99,18 @@ TEST_F(ElasticOverscrollControllerBezierTest, VerifyOverscrollStretch) {
// Test vertical overscroll. // Test vertical overscroll.
SendGestureScrollBegin(PhaseState::kNonMomentum); SendGestureScrollBegin(PhaseState::kNonMomentum);
EXPECT_EQ(Vector2dF(0, 0), helper_.StretchAmount()); EXPECT_EQ(Vector2dF(0, 0), helper_.StretchAmount());
SendGestureScrollUpdate(PhaseState::kNonMomentum, Vector2dF(0, -10), SendGestureScrollUpdate(PhaseState::kNonMomentum, Vector2dF(0, -100));
Vector2dF(0, -100));
EXPECT_EQ(Vector2dF(0, -19), helper_.StretchAmount()); EXPECT_EQ(Vector2dF(0, -19), helper_.StretchAmount());
SendGestureScrollUpdate(PhaseState::kNonMomentum, Vector2dF(0, 10), SendGestureScrollUpdate(PhaseState::kNonMomentum, Vector2dF(0, 100));
Vector2dF(0, 100));
EXPECT_EQ(Vector2dF(0, 0), helper_.StretchAmount()); EXPECT_EQ(Vector2dF(0, 0), helper_.StretchAmount());
SendGestureScrollEnd(); SendGestureScrollEnd();
// Test horizontal overscroll. // Test horizontal overscroll.
SendGestureScrollBegin(PhaseState::kNonMomentum); SendGestureScrollBegin(PhaseState::kNonMomentum);
EXPECT_EQ(Vector2dF(0, 0), helper_.StretchAmount()); EXPECT_EQ(Vector2dF(0, 0), helper_.StretchAmount());
SendGestureScrollUpdate(PhaseState::kNonMomentum, Vector2dF(-10, 0), SendGestureScrollUpdate(PhaseState::kNonMomentum, Vector2dF(-100, 0));
Vector2dF(-100, 0));
EXPECT_EQ(Vector2dF(-19, 0), helper_.StretchAmount()); EXPECT_EQ(Vector2dF(-19, 0), helper_.StretchAmount());
SendGestureScrollUpdate(PhaseState::kNonMomentum, Vector2dF(10, 0), SendGestureScrollUpdate(PhaseState::kNonMomentum, Vector2dF(100, 0));
Vector2dF(100, 0));
EXPECT_EQ(Vector2dF(0, 0), helper_.StretchAmount()); EXPECT_EQ(Vector2dF(0, 0), helper_.StretchAmount());
SendGestureScrollEnd(); SendGestureScrollEnd();
} }
...@@ -129,8 +121,7 @@ TEST_F(ElasticOverscrollControllerBezierTest, ReconcileStretchAndScroll) { ...@@ -129,8 +121,7 @@ TEST_F(ElasticOverscrollControllerBezierTest, ReconcileStretchAndScroll) {
SendGestureScrollBegin(PhaseState::kNonMomentum); SendGestureScrollBegin(PhaseState::kNonMomentum);
helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(0, 0), helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(0, 0),
gfx::ScrollOffset(100, 100)); gfx::ScrollOffset(100, 100));
SendGestureScrollUpdate(PhaseState::kNonMomentum, Vector2dF(0, -50), SendGestureScrollUpdate(PhaseState::kNonMomentum, Vector2dF(0, -100));
Vector2dF(0, -100));
EXPECT_EQ(Vector2dF(0, -19), helper_.StretchAmount()); EXPECT_EQ(Vector2dF(0, -19), helper_.StretchAmount());
helper_.ScrollBy(Vector2dF(0, 1)); helper_.ScrollBy(Vector2dF(0, 1));
controller_.ReconcileStretchAndScroll(); controller_.ReconcileStretchAndScroll();
...@@ -144,8 +135,7 @@ TEST_F(ElasticOverscrollControllerBezierTest, ReconcileStretchAndScroll) { ...@@ -144,8 +135,7 @@ TEST_F(ElasticOverscrollControllerBezierTest, ReconcileStretchAndScroll) {
SendGestureScrollBegin(PhaseState::kNonMomentum); SendGestureScrollBegin(PhaseState::kNonMomentum);
helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(0, 0), helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(0, 0),
gfx::ScrollOffset(100, 100)); gfx::ScrollOffset(100, 100));
SendGestureScrollUpdate(PhaseState::kNonMomentum, Vector2dF(-50, 0), SendGestureScrollUpdate(PhaseState::kNonMomentum, Vector2dF(-100, 0));
Vector2dF(-100, 0));
EXPECT_EQ(Vector2dF(-19, 0), helper_.StretchAmount()); EXPECT_EQ(Vector2dF(-19, 0), helper_.StretchAmount());
helper_.ScrollBy(Vector2dF(1, 0)); helper_.ScrollBy(Vector2dF(1, 0));
controller_.ReconcileStretchAndScroll(); controller_.ReconcileStretchAndScroll();
...@@ -168,13 +158,12 @@ TEST_F(ElasticOverscrollControllerBezierTest, VerifyOverscrollBounceDistance) { ...@@ -168,13 +158,12 @@ TEST_F(ElasticOverscrollControllerBezierTest, VerifyOverscrollBounceDistance) {
// successfully created, the call to OverscrollBounceController::Animate should // successfully created, the call to OverscrollBounceController::Animate should
// tick the animation as expected. When the stretch amount is near 0, the // tick the animation as expected. When the stretch amount is near 0, the
// scroller should treat the bounce as "completed". // scroller should treat the bounce as "completed".
TEST_F(ElasticOverscrollControllerBezierTest, VerifyAnimationTick) { TEST_F(ElasticOverscrollControllerBezierTest, VerifyBackwardAnimationTick) {
// Test vertical overscroll. // Test vertical overscroll.
EXPECT_EQ(controller_.state_, ElasticOverscrollController::kStateInactive); EXPECT_EQ(controller_.state_, ElasticOverscrollController::kStateInactive);
SendGestureScrollBegin(PhaseState::kNonMomentum); SendGestureScrollBegin(PhaseState::kNonMomentum);
EXPECT_EQ(Vector2dF(0, 0), helper_.StretchAmount()); EXPECT_EQ(Vector2dF(0, 0), helper_.StretchAmount());
SendGestureScrollUpdate(PhaseState::kNonMomentum, Vector2dF(0, -50), SendGestureScrollUpdate(PhaseState::kNonMomentum, Vector2dF(0, -100));
Vector2dF(0, -100));
// This signals that the finger has lifted off which triggers the bounce back // This signals that the finger has lifted off which triggers the bounce back
// animation. // animation.
...@@ -200,8 +189,7 @@ TEST_F(ElasticOverscrollControllerBezierTest, VerifyAnimationTick) { ...@@ -200,8 +189,7 @@ TEST_F(ElasticOverscrollControllerBezierTest, VerifyAnimationTick) {
// Test horizontal overscroll. // Test horizontal overscroll.
SendGestureScrollBegin(PhaseState::kNonMomentum); SendGestureScrollBegin(PhaseState::kNonMomentum);
EXPECT_EQ(Vector2dF(0, 0), helper_.StretchAmount()); EXPECT_EQ(Vector2dF(0, 0), helper_.StretchAmount());
SendGestureScrollUpdate(PhaseState::kNonMomentum, Vector2dF(-25, 0), SendGestureScrollUpdate(PhaseState::kNonMomentum, Vector2dF(-80, 0));
Vector2dF(-80, 0));
SendGestureScrollEnd(now); SendGestureScrollEnd(now);
// Frame 2. // Frame 2.
...@@ -220,14 +208,40 @@ TEST_F(ElasticOverscrollControllerBezierTest, VerifyAnimationTick) { ...@@ -220,14 +208,40 @@ TEST_F(ElasticOverscrollControllerBezierTest, VerifyAnimationTick) {
EXPECT_EQ(controller_.state_, ElasticOverscrollController::kStateInactive); EXPECT_EQ(controller_.state_, ElasticOverscrollController::kStateInactive);
} }
// Tests that the bounce forward animation ticks as expected.
TEST_F(ElasticOverscrollControllerBezierTest, VerifyForwardAnimationTick) {
EXPECT_EQ(controller_.state_, ElasticOverscrollController::kStateInactive);
SendGestureScrollBegin(PhaseState::kNonMomentum);
EXPECT_EQ(Vector2dF(0, 0), helper_.StretchAmount());
SendGestureScrollUpdate(PhaseState::kNonMomentum, Vector2dF(0, -100));
controller_.scroll_velocity_ = gfx::Vector2dF(0.f, -500.f);
// This signals that the finger has lifted off which triggers a fling.
const base::TimeTicks now = base::TimeTicks::Now();
SendGestureScrollEnd(now);
const int SAMPLES = 7;
const int frames[SAMPLES] = {1, 2, 3, 4, 5, 8, 19};
const int stretch_amount[SAMPLES] = {-33, -40, -43, -40, -26, -11, 0};
for (int i = 0; i < SAMPLES; i++) {
controller_.Animate(now +
base::TimeDelta::FromMilliseconds(frames[i] * 16));
EXPECT_EQ(controller_.state_,
(stretch_amount[i] == 0
? ElasticOverscrollController::kStateInactive
: ElasticOverscrollController::kStateMomentumAnimated));
ASSERT_FLOAT_EQ(helper_.StretchAmount().y(), stretch_amount[i]);
}
}
// Tests initiating a scroll when a bounce back animation is in progress works // Tests initiating a scroll when a bounce back animation is in progress works
// as expected. // as expected.
TEST_F(ElasticOverscrollControllerBezierTest, VerifyScrollDuringBounceBack) { TEST_F(ElasticOverscrollControllerBezierTest, VerifyScrollDuringBounceBack) {
// Test vertical overscroll. // Test vertical overscroll.
SendGestureScrollBegin(PhaseState::kNonMomentum); SendGestureScrollBegin(PhaseState::kNonMomentum);
EXPECT_EQ(Vector2dF(0, 0), helper_.StretchAmount()); EXPECT_EQ(Vector2dF(0, 0), helper_.StretchAmount());
SendGestureScrollUpdate(PhaseState::kNonMomentum, Vector2dF(), SendGestureScrollUpdate(PhaseState::kNonMomentum, Vector2dF(0, -100));
Vector2dF(0, -100));
// This signals that the finger has lifted off which triggers the bounce back // This signals that the finger has lifted off which triggers the bounce back
// animation. // animation.
...@@ -245,8 +259,7 @@ TEST_F(ElasticOverscrollControllerBezierTest, VerifyScrollDuringBounceBack) { ...@@ -245,8 +259,7 @@ TEST_F(ElasticOverscrollControllerBezierTest, VerifyScrollDuringBounceBack) {
// While the animation is still ticking, initiate a scroll. // While the animation is still ticking, initiate a scroll.
SendGestureScrollBegin(PhaseState::kNonMomentum); SendGestureScrollBegin(PhaseState::kNonMomentum);
SendGestureScrollUpdate(PhaseState::kNonMomentum, Vector2dF(), SendGestureScrollUpdate(PhaseState::kNonMomentum, Vector2dF(0, -50));
Vector2dF(0, -50));
ASSERT_FLOAT_EQ(helper_.StretchAmount().y(), -13); ASSERT_FLOAT_EQ(helper_.StretchAmount().y(), -13);
} }
...@@ -258,8 +271,7 @@ TEST_F(ElasticOverscrollControllerBezierTest, VerifyAnimationNotCreated) { ...@@ -258,8 +271,7 @@ TEST_F(ElasticOverscrollControllerBezierTest, VerifyAnimationNotCreated) {
// state_ is kStateActiveScroll. unused_delta is 0 so overscroll should not // state_ is kStateActiveScroll. unused_delta is 0 so overscroll should not
// take place. // take place.
Vector2dF delta(-25, -50); SendGestureScrollUpdate(PhaseState::kNonMomentum, Vector2dF(0, 0));
SendGestureScrollUpdate(PhaseState::kNonMomentum, delta, Vector2dF(0, 0));
// This signals that the finger has lifted off which triggers the bounce back // This signals that the finger has lifted off which triggers the bounce back
// animation. // animation.
......
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