summaryrefslogtreecommitdiffstats
path: root/content/renderer/input
diff options
context:
space:
mode:
authorjdduke@chromium.org <jdduke@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-30 08:08:20 +0000
committerjdduke@chromium.org <jdduke@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-30 08:08:20 +0000
commit10c97c2f378a0d227aef4419e786e02d350ce75c (patch)
tree6c102fa6376f650c03844e92311f59638bccef0c /content/renderer/input
parentdd6ca97cf2a95384ae05896ecdc50a4a48265c24 (diff)
downloadchromium_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.cc37
-rw-r--r--content/renderer/input/input_handler_proxy.h4
-rw-r--r--content/renderer/input/input_handler_proxy_unittest.cc63
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.