diff options
author | jdduke@chromium.org <jdduke@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-04-30 08:08:20 +0000 |
---|---|---|
committer | jdduke@chromium.org <jdduke@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-04-30 08:08:20 +0000 |
commit | 10c97c2f378a0d227aef4419e786e02d350ce75c (patch) | |
tree | 6c102fa6376f650c03844e92311f59638bccef0c /content/renderer/input | |
parent | dd6ca97cf2a95384ae05896ecdc50a4a48265c24 (diff) | |
download | chromium_src-10c97c2f378a0d227aef4419e786e02d350ce75c.zip chromium_src-10c97c2f378a0d227aef4419e786e02d350ce75c.tar.gz chromium_src-10c97c2f378a0d227aef4419e786e02d350ce75c.tar.bz2 |
[Android] Use cc timestamps for fling animation
Historically, Android's fling curve animation used a Java object that relied on
the equivalent of TimeTicks::Now() for animation updates. When the curve was
ported to C++, this approach continued as timestamps from cc's animation system
proved too erratic. This variability appears to have been fixed, so plumb cc's
timestamps to the Android fling curve appropriately.
Also tighten allowances for using a GestureFlingStart event's timestamp to
kickstart the animation, fixing cases where either the animation or the fling
receipt in the renderer are severely delayed.
BUG=345459,367156
Review URL: https://codereview.chromium.org/255243003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@267133 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/renderer/input')
-rw-r--r-- | content/renderer/input/input_handler_proxy.cc | 37 | ||||
-rw-r--r-- | content/renderer/input/input_handler_proxy.h | 4 | ||||
-rw-r--r-- | content/renderer/input/input_handler_proxy_unittest.cc | 63 |
3 files changed, 90 insertions, 14 deletions
diff --git a/content/renderer/input/input_handler_proxy.cc b/content/renderer/input/input_handler_proxy.cc index d7b594d..f0d6b6c 100644 --- a/content/renderer/input/input_handler_proxy.cc +++ b/content/renderer/input/input_handler_proxy.cc @@ -29,8 +29,10 @@ using blink::WebTouchPoint; namespace { -// Validate provided event timestamps that interact with animation timestamps. -const double kBadTimestampDeltaFromNowInS = 60. * 60. * 24. * 7.; +// Maximum time between a fling event's timestamp and the first |Animate| call +// for the fling curve to use the fling timestamp as the initial animation time. +// Two frames allows a minor delay between event creation and the first animate. +const double kMaxSecondsFromFlingTimestampToFirstAnimate = 2. / 60.; // Threshold for determining whether a fling scroll delta should have caused the // client to scroll. @@ -79,7 +81,8 @@ InputHandlerProxy::InputHandlerProxy(cc::InputHandler* input_handler) gesture_pinch_on_impl_thread_(false), fling_may_be_active_on_main_thread_(false), disallow_horizontal_fling_scroll_(false), - disallow_vertical_fling_scroll_(false) { + disallow_vertical_fling_scroll_(false), + has_fling_animation_started_(false) { input_handler_->BindToClient(this); } @@ -324,12 +327,10 @@ InputHandlerProxy::HandleGestureFling( gesture_event.data.flingStart.velocityX, "vy", gesture_event.data.flingStart.velocityY); - if (gesture_event.timeStampSeconds) { - fling_parameters_.startTime = gesture_event.timeStampSeconds; - DCHECK_LT(fling_parameters_.startTime - - InSecondsF(gfx::FrameTime::Now()), - kBadTimestampDeltaFromNowInS); - } + // Note that the timestamp will only be used to kickstart the animation if + // its sufficiently close to the timestamp of the first call |Animate()|. + has_fling_animation_started_ = false; + fling_parameters_.startTime = gesture_event.timeStampSeconds; fling_parameters_.delta = WebFloatPoint(gesture_event.data.flingStart.velocityX, gesture_event.data.flingStart.velocityY); @@ -375,11 +376,18 @@ void InputHandlerProxy::Animate(base::TimeTicks time) { return; double monotonic_time_sec = InSecondsF(time); - if (!fling_parameters_.startTime || - monotonic_time_sec <= fling_parameters_.startTime) { - fling_parameters_.startTime = monotonic_time_sec; - input_handler_->ScheduleAnimation(); - return; + if (!has_fling_animation_started_) { + has_fling_animation_started_ = true; + // Guard against invalid, future or sufficiently stale start times, as there + // are no guarantees fling event and animation timestamps are compatible. + if (!fling_parameters_.startTime || + monotonic_time_sec <= fling_parameters_.startTime || + monotonic_time_sec >= fling_parameters_.startTime + + kMaxSecondsFromFlingTimestampToFirstAnimate) { + fling_parameters_.startTime = monotonic_time_sec; + input_handler_->ScheduleAnimation(); + return; + } } bool fling_is_active = @@ -452,6 +460,7 @@ bool InputHandlerProxy::CancelCurrentFling( "had_fling_animation", had_fling_animation); fling_curve_.reset(); + has_fling_animation_started_ = false; gesture_scroll_on_impl_thread_ = false; current_fling_velocity_ = gfx::Vector2dF(); fling_parameters_ = blink::WebActiveWheelFlingParameters(); diff --git a/content/renderer/input/input_handler_proxy.h b/content/renderer/input/input_handler_proxy.h index b480d45..d9147a5 100644 --- a/content/renderer/input/input_handler_proxy.h +++ b/content/renderer/input/input_handler_proxy.h @@ -90,6 +90,10 @@ class CONTENT_EXPORT InputHandlerProxy bool disallow_horizontal_fling_scroll_; bool disallow_vertical_fling_scroll_; + // Whether an active fling has seen an |Animate()| call. This is useful for + // determining if the fling start time should be re-initialized. + bool has_fling_animation_started_; + // Non-zero only within the scope of |scrollBy|. gfx::Vector2dF current_fling_velocity_; diff --git a/content/renderer/input/input_handler_proxy_unittest.cc b/content/renderer/input/input_handler_proxy_unittest.cc index 48f98fe..6ee2be07 100644 --- a/content/renderer/input/input_handler_proxy_unittest.cc +++ b/content/renderer/input/input_handler_proxy_unittest.cc @@ -971,6 +971,69 @@ TEST_F(InputHandlerProxyTest, GestureFlingWithValidTimestamp) { EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); } +TEST_F(InputHandlerProxyTest, GestureFlingWithInvalidTimestamp) { + // We shouldn't send any events to the widget for this gesture. + expected_disposition_ = InputHandlerProxy::DID_HANDLE; + VERIFY_AND_RESET_MOCKS(); + + EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) + .WillOnce(testing::Return(cc::InputHandler::ScrollStarted)); + + gesture_.type = WebInputEvent::GestureScrollBegin; + gesture_.sourceDevice = WebGestureEvent::Touchscreen; + EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); + + VERIFY_AND_RESET_MOCKS(); + + // On the fling start, we should schedule an animation but not actually start + // scrolling. + base::TimeDelta start_time_offset = base::TimeDelta::FromMilliseconds(10); + gesture_.type = WebInputEvent::GestureFlingStart; + WebFloatPoint fling_delta = WebFloatPoint(1000, 0); + WebPoint fling_point = WebPoint(7, 13); + WebPoint fling_global_point = WebPoint(17, 23); + int modifiers = WebInputEvent::ControlKey; + gesture_.timeStampSeconds = start_time_offset.InSecondsF(); + gesture_.data.flingStart.velocityX = fling_delta.x; + gesture_.data.flingStart.velocityY = fling_delta.y; + gesture_.sourceDevice = WebGestureEvent::Touchscreen; + gesture_.x = fling_point.x; + gesture_.y = fling_point.y; + gesture_.globalX = fling_global_point.x; + gesture_.globalY = fling_global_point.y; + gesture_.modifiers = modifiers; + EXPECT_CALL(mock_input_handler_, ScheduleAnimation()); + EXPECT_CALL(mock_input_handler_, FlingScrollBegin()) + .WillOnce(testing::Return(cc::InputHandler::ScrollStarted)); + EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); + + testing::Mock::VerifyAndClearExpectations(&mock_input_handler_); + // Event though a time stamp was provided for the fling event, it will be + // ignored as its too far in the past relative to the first animate call's + // timestamp. + EXPECT_CALL(mock_input_handler_, ScheduleAnimation()); + base::TimeTicks time = + base::TimeTicks() + start_time_offset + base::TimeDelta::FromSeconds(1); + input_handler_->Animate(time); + + testing::Mock::VerifyAndClearExpectations(&mock_input_handler_); + + // Further animation ticks should update the fling as usual. + EXPECT_CALL(mock_input_handler_, ScheduleAnimation()); + EXPECT_CALL(mock_input_handler_, + ScrollBy(testing::_, + testing::Property(&gfx::Vector2dF::x, testing::Lt(0)))) + .WillOnce(testing::Return(true)); + time += base::TimeDelta::FromMilliseconds(10); + input_handler_->Animate(time); + + testing::Mock::VerifyAndClearExpectations(&mock_input_handler_); + + EXPECT_CALL(mock_input_handler_, ScrollEnd()); + gesture_.type = WebInputEvent::GestureFlingCancel; + EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); +} + TEST_F(InputHandlerProxyTest, GestureScrollOnImplThreadFlagClearedAfterFling) { // We shouldn't send any events to the widget for this gesture. |