Index: ui/events/blink/input_scroll_elasticity_controller_unittest.cc |
diff --git a/ui/events/blink/input_scroll_elasticity_controller_unittest.cc b/ui/events/blink/input_scroll_elasticity_controller_unittest.cc |
index 82b94343f8e061a2c1f14cbdf687b9e7a1df060c..4ce7b9494ed7dee8c1255430b3f0eff45df377a7 100644 |
--- a/ui/events/blink/input_scroll_elasticity_controller_unittest.cc |
+++ b/ui/events/blink/input_scroll_elasticity_controller_unittest.cc |
@@ -99,6 +99,53 @@ class ScrollElasticityControllerTest : public testing::Test { |
input_event_count_ += 1; |
} |
+ void SendGestureScrollBegin(bool inertial) { |
+ blink::WebGestureEvent event; |
+ event.sourceDevice = blink::WebGestureDeviceTouchpad; |
+ event.type = blink::WebInputEvent::GestureScrollBegin; |
+ event.data.scrollBegin.inertial = inertial; |
+ TickCurrentTime(); |
+ event.timeStampSeconds = (current_time_ - base::TimeTicks()).InSecondsF(); |
+ |
+ controller_.ObserveGestureEventAndResult(event, |
+ cc::InputHandlerScrollResult()); |
+ input_event_count_ += 1; |
+ } |
+ |
+ void SendGestureScrollUpdate( |
+ bool inertial, |
+ const gfx::Vector2dF& event_delta = gfx::Vector2dF(), |
+ const gfx::Vector2dF& overscroll_delta = gfx::Vector2dF()) { |
+ blink::WebGestureEvent event; |
+ event.sourceDevice = blink::WebGestureDeviceTouchpad; |
+ event.type = blink::WebInputEvent::GestureScrollUpdate; |
+ event.data.scrollUpdate.inertial = inertial; |
+ event.data.scrollUpdate.deltaX = -event_delta.x(); |
+ event.data.scrollUpdate.deltaY = -event_delta.y(); |
+ TickCurrentTime(); |
+ event.timeStampSeconds = (current_time_ - base::TimeTicks()).InSecondsF(); |
+ |
+ cc::InputHandlerScrollResult scroll_result; |
+ scroll_result.did_overscroll_root = !overscroll_delta.IsZero(); |
+ scroll_result.unused_scroll_delta = overscroll_delta; |
+ |
+ controller_.ObserveGestureEventAndResult(event, scroll_result); |
+ input_event_count_ += 1; |
+ } |
+ |
+ void SendGestureScrollEnd() { |
+ blink::WebGestureEvent event; |
+ event.sourceDevice = blink::WebGestureDeviceTouchpad; |
+ event.type = blink::WebInputEvent::GestureScrollEnd; |
+ |
+ TickCurrentTime(); |
+ event.timeStampSeconds = (current_time_ - base::TimeTicks()).InSecondsF(); |
+ |
+ controller_.ObserveGestureEventAndResult(event, |
+ cc::InputHandlerScrollResult()); |
+ input_event_count_ += 1; |
+ } |
+ |
const base::TimeTicks& TickCurrentTime() { |
current_time_ += base::TimeDelta::FromSecondsD(1 / 60.f); |
return current_time_; |
@@ -148,6 +195,40 @@ TEST_F(ScrollElasticityControllerTest, Axis) { |
EXPECT_EQ(0, helper_.request_begin_frame_count()); |
} |
+// Verify that stretching only occurs in one axis at a time, and that it |
+// is biased to the Y axis. |
+TEST_F(ScrollElasticityControllerTest, GestureBased_Axis) { |
+ helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(0, 0), |
+ gfx::ScrollOffset(0, 0)); |
+ |
+ // If we push equally in the X and Y directions, we should see a stretch only |
+ // in the Y direction. |
+ SendGestureScrollBegin(false); |
+ SendGestureScrollUpdate(false, gfx::Vector2dF(10, 10), |
+ gfx::Vector2dF(10, 10)); |
+ EXPECT_EQ(1, helper_.set_stretch_amount_count()); |
+ EXPECT_EQ(0.f, helper_.StretchAmount().x()); |
+ EXPECT_LT(0.f, helper_.StretchAmount().y()); |
+ helper_.SetStretchAmount(gfx::Vector2dF()); |
+ EXPECT_EQ(2, helper_.set_stretch_amount_count()); |
+ SendGestureScrollEnd(); |
+ EXPECT_EQ(0, helper_.request_begin_frame_count()); |
+ |
+ // If we push more in the X direction than the Y direction, we should see a |
+ // stretch only in the X direction. This decision should be based on the |
+ // input delta, not the actual overscroll delta. |
+ SendGestureScrollBegin(false); |
+ SendGestureScrollUpdate(false, gfx::Vector2dF(-25, 10), |
+ gfx::Vector2dF(-25, 40)); |
+ EXPECT_EQ(3, helper_.set_stretch_amount_count()); |
+ EXPECT_GT(0.f, helper_.StretchAmount().x()); |
+ EXPECT_EQ(0.f, helper_.StretchAmount().y()); |
+ helper_.SetStretchAmount(gfx::Vector2dF()); |
+ EXPECT_EQ(4, helper_.set_stretch_amount_count()); |
+ SendGestureScrollEnd(); |
+ EXPECT_EQ(0, helper_.request_begin_frame_count()); |
+} |
+ |
// Verify that we need a total overscroll delta of at least 10 in a pinned |
// direction before we start stretching. |
TEST_F(ScrollElasticityControllerTest, MinimumDeltaBeforeStretch) { |
@@ -201,7 +282,54 @@ TEST_F(ScrollElasticityControllerTest, MinimumDeltaBeforeStretch) { |
EXPECT_EQ(1, helper_.request_begin_frame_count()); |
} |
-// Verify that an stretch caused by a momentum scroll will switch to the |
+// Verify that we need a total overscroll delta of at least 10 in a pinned |
+// direction before we start stretching. |
+TEST_F(ScrollElasticityControllerTest, GestureBased_MinimumDeltaBeforeStretch) { |
+ // We should not start stretching while we are not pinned in the direction |
+ // of the scroll (even if there is an overscroll delta). We have to wait for |
+ // the regular scroll to eat all of the events. |
+ helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(5, 5), |
+ gfx::ScrollOffset(10, 10)); |
+ SendGestureScrollBegin(false); |
+ SendGestureScrollUpdate(false, gfx::Vector2dF(0, 10), gfx::Vector2dF(0, 10)); |
+ SendGestureScrollUpdate(false, gfx::Vector2dF(0, 10), gfx::Vector2dF(0, 10)); |
+ EXPECT_EQ(0, helper_.set_stretch_amount_count()); |
+ |
+ // Now pin the -X and +Y direction. The first event will not generate a |
+ // stretch |
+ // because it is below the delta threshold of 10. |
+ helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(0, 10), |
+ gfx::ScrollOffset(10, 10)); |
+ SendGestureScrollUpdate(false, gfx::Vector2dF(0, 10), gfx::Vector2dF(0, 8)); |
+ EXPECT_EQ(0, helper_.set_stretch_amount_count()); |
+ |
+ // Make the next scroll be in the -X direction more than the +Y direction, |
+ // which will erase the memory of the previous unused delta of 8. |
+ SendGestureScrollUpdate(false, gfx::Vector2dF(-10, 5), |
+ gfx::Vector2dF(-8, 10)); |
+ EXPECT_EQ(0, helper_.set_stretch_amount_count()); |
+ |
+ // Now push against the pinned +Y direction again by 8. We reset the |
+ // previous delta, so this will not generate a stretch. |
+ SendGestureScrollUpdate(false, gfx::Vector2dF(0, 10), gfx::Vector2dF(0, 8)); |
+ EXPECT_EQ(0, helper_.set_stretch_amount_count()); |
+ |
+ // Push against +Y by another 8. This gets us above the delta threshold of |
+ // 10, so we should now have had the stretch set, and it should be in the |
+ // +Y direction. The scroll in the -X direction should have been forgotten. |
+ SendGestureScrollUpdate(false, gfx::Vector2dF(0, 10), gfx::Vector2dF(0, 8)); |
+ EXPECT_EQ(1, helper_.set_stretch_amount_count()); |
+ EXPECT_EQ(0.f, helper_.StretchAmount().x()); |
+ EXPECT_LT(0.f, helper_.StretchAmount().y()); |
+ |
+ // End the gesture. Because there is a non-zero stretch, we should be in the |
+ // animated state, and should have had a frame requested. |
+ EXPECT_EQ(0, helper_.request_begin_frame_count()); |
+ SendGestureScrollEnd(); |
+ EXPECT_EQ(1, helper_.request_begin_frame_count()); |
+} |
+ |
+// Verify that a stretch caused by a momentum scroll will switch to the |
// animating mode, where input events are ignored, and the stretch is updated |
// while animating. |
TEST_F(ScrollElasticityControllerTest, MomentumAnimate) { |
@@ -297,7 +425,93 @@ TEST_F(ScrollElasticityControllerTest, MomentumAnimate) { |
EXPECT_EQ(begin_frame_count, helper_.request_begin_frame_count()); |
} |
-// Verify that an stretch opposing a scroll is correctly resolved. |
+// Verify that a stretch caused by a momentum scroll will switch to the |
+// animating mode, where input events are ignored, and the stretch is updated |
+// while animating. |
+TEST_F(ScrollElasticityControllerTest, GestureBased_MomentumAnimate) { |
+ // Do an active scroll, then switch to the momentum phase and scroll for a |
+ // bit. |
+ helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(5, 5), |
+ gfx::ScrollOffset(10, 10)); |
+ SendGestureScrollBegin(false); |
+ SendGestureScrollUpdate(false, gfx::Vector2dF(0, -80), gfx::Vector2dF(0, 0)); |
+ SendGestureScrollUpdate(false, gfx::Vector2dF(0, -80), gfx::Vector2dF(0, 0)); |
+ SendGestureScrollUpdate(false, gfx::Vector2dF(0, -80), gfx::Vector2dF(0, 0)); |
+ SendGestureScrollEnd(); |
+ SendGestureScrollBegin(true); |
+ SendGestureScrollUpdate(true, gfx::Vector2dF(0, -80), gfx::Vector2dF(0, 0)); |
+ SendGestureScrollUpdate(true, gfx::Vector2dF(0, -80), gfx::Vector2dF(0, 0)); |
+ SendGestureScrollUpdate(true, gfx::Vector2dF(0, -80), gfx::Vector2dF(0, 0)); |
+ EXPECT_EQ(0, helper_.set_stretch_amount_count()); |
+ |
+ // Hit the -Y edge and overscroll slightly, but not enough to go over the |
+ // threshold to cause a stretch. |
+ helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(5, 0), |
+ gfx::ScrollOffset(10, 10)); |
+ SendGestureScrollUpdate(true, gfx::Vector2dF(0, -80), gfx::Vector2dF(0, -8)); |
+ EXPECT_EQ(0, helper_.set_stretch_amount_count()); |
+ EXPECT_EQ(0, helper_.request_begin_frame_count()); |
+ |
+ // Take another step, this time going over the threshold. This should update |
+ // the stretch amount, and then switch to the animating mode. |
+ SendGestureScrollUpdate(true, gfx::Vector2dF(0, -80), gfx::Vector2dF(0, -80)); |
+ EXPECT_EQ(1, helper_.set_stretch_amount_count()); |
+ EXPECT_EQ(1, helper_.request_begin_frame_count()); |
+ EXPECT_GT(-1.f, helper_.StretchAmount().y()); |
+ |
+ // Subsequent momentum events should do nothing. |
+ SendGestureScrollUpdate(true, gfx::Vector2dF(0, -80), gfx::Vector2dF(0, -80)); |
+ SendGestureScrollUpdate(true, gfx::Vector2dF(0, -80), gfx::Vector2dF(0, -80)); |
+ SendGestureScrollUpdate(true, gfx::Vector2dF(0, -80), gfx::Vector2dF(0, -80)); |
+ SendGestureScrollEnd(); |
+ EXPECT_EQ(1, helper_.set_stretch_amount_count()); |
+ EXPECT_EQ(1, helper_.request_begin_frame_count()); |
+ |
+ // Subsequent animate events should update the stretch amount and request |
+ // another frame. |
+ TickCurrentTimeAndAnimate(); |
+ EXPECT_EQ(2, helper_.set_stretch_amount_count()); |
+ EXPECT_EQ(2, helper_.request_begin_frame_count()); |
+ EXPECT_GT(-1.f, helper_.StretchAmount().y()); |
+ |
+ // Touching the trackpad (a PhaseMayBegin event) should disable animation. |
+ SendGestureScrollBegin(false); |
+ TickCurrentTimeAndAnimate(); |
+ EXPECT_EQ(2, helper_.set_stretch_amount_count()); |
+ EXPECT_EQ(2, helper_.request_begin_frame_count()); |
+ |
+ // Releasing the trackpad should re-enable animation. |
+ SendGestureScrollEnd(); |
+ EXPECT_EQ(2, helper_.set_stretch_amount_count()); |
+ EXPECT_EQ(3, helper_.request_begin_frame_count()); |
+ TickCurrentTimeAndAnimate(); |
+ EXPECT_EQ(3, helper_.set_stretch_amount_count()); |
+ EXPECT_EQ(4, helper_.request_begin_frame_count()); |
+ |
+ // Keep animating frames until the stretch returns to rest. |
+ int stretch_count = 3; |
+ int begin_frame_count = 4; |
+ while (1) { |
+ TickCurrentTimeAndAnimate(); |
+ if (helper_.StretchAmount().IsZero()) { |
+ stretch_count += 1; |
+ EXPECT_EQ(stretch_count, helper_.set_stretch_amount_count()); |
+ EXPECT_EQ(begin_frame_count, helper_.request_begin_frame_count()); |
+ break; |
+ } |
+ stretch_count += 1; |
+ begin_frame_count += 1; |
+ EXPECT_EQ(stretch_count, helper_.set_stretch_amount_count()); |
+ EXPECT_EQ(begin_frame_count, helper_.request_begin_frame_count()); |
+ } |
+ |
+ // After coming to rest, no subsequent animate calls change anything. |
+ TickCurrentTimeAndAnimate(); |
+ EXPECT_EQ(stretch_count, helper_.set_stretch_amount_count()); |
+ EXPECT_EQ(begin_frame_count, helper_.request_begin_frame_count()); |
+} |
+ |
+// Verify that a stretch opposing a scroll is correctly resolved. |
TEST_F(ScrollElasticityControllerTest, ReconcileStretchAndScroll) { |
SendMouseWheelEvent(PhaseBegan, PhaseNone); |
@@ -334,14 +548,50 @@ TEST_F(ScrollElasticityControllerTest, ReconcileStretchAndScroll) { |
EXPECT_EQ(helper_.ScrollOffset(), gfx::ScrollOffset(7, 8)); |
} |
+// Verify that a stretch opposing a scroll is correctly resolved. |
+TEST_F(ScrollElasticityControllerTest, GestureBased_ReconcileStretchAndScroll) { |
+ SendGestureScrollBegin(false); |
+ |
+ // Verify completely knocking out the scroll in the -Y direction. |
+ helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(5, 5), |
+ gfx::ScrollOffset(10, 10)); |
+ helper_.SetStretchAmount(gfx::Vector2dF(0, -10)); |
+ controller_.ReconcileStretchAndScroll(); |
+ EXPECT_EQ(helper_.StretchAmount(), gfx::Vector2dF(0, -5)); |
+ EXPECT_EQ(helper_.ScrollOffset(), gfx::ScrollOffset(5, 0)); |
+ |
+ // Verify partially knocking out the scroll in the -Y direction. |
+ helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(5, 8), |
+ gfx::ScrollOffset(10, 10)); |
+ helper_.SetStretchAmount(gfx::Vector2dF(0, -5)); |
+ controller_.ReconcileStretchAndScroll(); |
+ EXPECT_EQ(helper_.StretchAmount(), gfx::Vector2dF(0, 0)); |
+ EXPECT_EQ(helper_.ScrollOffset(), gfx::ScrollOffset(5, 3)); |
+ |
+ // Verify completely knocking out the scroll in the +X direction. |
+ helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(5, 5), |
+ gfx::ScrollOffset(10, 10)); |
+ helper_.SetStretchAmount(gfx::Vector2dF(10, 0)); |
+ controller_.ReconcileStretchAndScroll(); |
+ EXPECT_EQ(helper_.StretchAmount(), gfx::Vector2dF(5, 0)); |
+ EXPECT_EQ(helper_.ScrollOffset(), gfx::ScrollOffset(10, 5)); |
+ |
+ // Verify partially knocking out the scroll in the +X and +Y directions. |
+ helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(2, 3), |
+ gfx::ScrollOffset(10, 10)); |
+ helper_.SetStretchAmount(gfx::Vector2dF(5, 5)); |
+ controller_.ReconcileStretchAndScroll(); |
+ EXPECT_EQ(helper_.StretchAmount(), gfx::Vector2dF(0, 0)); |
+ EXPECT_EQ(helper_.ScrollOffset(), gfx::ScrollOffset(7, 8)); |
+} |
+ |
// Verify that stretching only happens when the area is user scrollable. |
TEST_F(ScrollElasticityControllerTest, UserScrollableRequiredForStretch) { |
helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(0, 0), |
gfx::ScrollOffset(10, 10)); |
gfx::Vector2dF delta(0, -15); |
- // Do an active scroll, and ensure that the stretch amount doesn't change, |
- // and also that the stretch amount isn't even ever changed. |
+ // Do an active scroll, and ensure that the stretch amount doesn't change. |
helper_.SetUserScrollable(false); |
SendMouseWheelEvent(PhaseBegan, PhaseNone); |
SendMouseWheelEvent(PhaseChanged, PhaseNone, delta, delta); |
@@ -384,5 +634,55 @@ TEST_F(ScrollElasticityControllerTest, UserScrollableRequiredForStretch) { |
EXPECT_GT(ticks_to_zero, 3); |
} |
+// Verify that stretching only happens when the area is user scrollable. |
+TEST_F(ScrollElasticityControllerTest, |
+ GestureBased_UserScrollableRequiredForStretch) { |
+ helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(0, 0), |
+ gfx::ScrollOffset(10, 10)); |
+ gfx::Vector2dF delta(0, -15); |
+ |
+ // Do an active scroll, and ensure that the stretch amount doesn't change. |
+ helper_.SetUserScrollable(false); |
+ SendGestureScrollBegin(false); |
+ SendGestureScrollUpdate(false, delta, delta); |
+ SendGestureScrollUpdate(false, delta, delta); |
+ SendGestureScrollEnd(); |
+ EXPECT_EQ(helper_.StretchAmount(), gfx::Vector2dF(0, 0)); |
+ EXPECT_EQ(0, helper_.set_stretch_amount_count()); |
+ SendGestureScrollBegin(true); |
+ SendGestureScrollUpdate(true, delta, delta); |
+ SendGestureScrollUpdate(true, delta, delta); |
+ SendGestureScrollEnd(); |
+ EXPECT_EQ(helper_.StretchAmount(), gfx::Vector2dF(0, 0)); |
+ EXPECT_EQ(0, helper_.set_stretch_amount_count()); |
+ |
+ // Re-enable user scrolling and ensure that stretching is re-enabled. |
+ helper_.SetUserScrollable(true); |
+ SendGestureScrollBegin(false); |
+ SendGestureScrollUpdate(false, delta, delta); |
+ SendGestureScrollUpdate(false, delta, delta); |
+ SendGestureScrollEnd(); |
+ EXPECT_NE(helper_.StretchAmount(), gfx::Vector2dF(0, 0)); |
+ EXPECT_GT(helper_.set_stretch_amount_count(), 0); |
+ SendGestureScrollBegin(true); |
+ SendGestureScrollUpdate(true, delta, delta); |
+ SendGestureScrollUpdate(true, delta, delta); |
+ SendGestureScrollEnd(); |
+ EXPECT_NE(helper_.StretchAmount(), gfx::Vector2dF(0, 0)); |
+ EXPECT_GT(helper_.set_stretch_amount_count(), 0); |
+ |
+ // Disable user scrolling and tick the timer until the stretch goes back |
+ // to zero. Ensure that the return to zero doesn't happen immediately. |
+ helper_.SetUserScrollable(false); |
+ int ticks_to_zero = 0; |
+ while (1) { |
+ TickCurrentTimeAndAnimate(); |
+ if (helper_.StretchAmount().IsZero()) |
+ break; |
+ ticks_to_zero += 1; |
+ } |
+ EXPECT_GT(ticks_to_zero, 3); |
+} |
+ |
} // namespace |
} // namespace ui |