diff options
author | xiyuan@chromium.org <xiyuan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-12-08 04:55:06 +0000 |
---|---|---|
committer | xiyuan@chromium.org <xiyuan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-12-08 04:55:06 +0000 |
commit | a17888c90c9bdd641f53ef8a9eea6a5361d518e4 (patch) | |
tree | 9860f67e5ddd1fb45750c68f7ecde4b0aec98c8d /ui | |
parent | 2ef9960c1302cdb0ef78ed54957fda504fe9681d (diff) | |
download | chromium_src-a17888c90c9bdd641f53ef8a9eea6a5361d518e4.zip chromium_src-a17888c90c9bdd641f53ef8a9eea6a5361d518e4.tar.gz chromium_src-a17888c90c9bdd641f53ef8a9eea6a5361d518e4.tar.bz2 |
Revert 171934
> Use consistent velocity trend to start a touch scroll gesture.
>
> In the GestureRecognizer, we previously inititated scrolling when the finger leaves a L1-norm box surrounding the position of the touch down point. As a result, the page would seem to leap by the size of the L1-norm on the first paint after entering a scrolling gesture.
>
> This CL replaces the L1-norm box mechanism with a new mechanism for determining the start of a scroll: watch for the establishment of a consistent velocity trend across multiple touch moves. This permits determining that a scroll should start with a much smaller displacement than is needed with the L1-norm technique and eliminates the "leap" effect.
>
> BUG=141653
>
>
> Review URL: https://chromiumcodereview.appspot.com/11469005
TBR=rjkroege@chromium.org
Review URL: https://codereview.chromium.org/11472046
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@171937 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui')
-rw-r--r-- | ui/aura/gestures/gesture_recognizer_unittest.cc | 34 | ||||
-rw-r--r-- | ui/base/gestures/gesture_configuration.cc | 9 | ||||
-rw-r--r-- | ui/base/gestures/gesture_configuration.h | 15 | ||||
-rw-r--r-- | ui/base/gestures/gesture_point.cc | 31 | ||||
-rw-r--r-- | ui/base/gestures/gesture_point.h | 12 | ||||
-rw-r--r-- | ui/base/gestures/gesture_sequence.cc | 9 | ||||
-rw-r--r-- | ui/base/gestures/velocity_calculator.cc | 25 |
7 files changed, 45 insertions, 90 deletions
diff --git a/ui/aura/gestures/gesture_recognizer_unittest.cc b/ui/aura/gestures/gesture_recognizer_unittest.cc index 68a36d6..44399dc 100644 --- a/ui/aura/gestures/gesture_recognizer_unittest.cc +++ b/ui/aura/gestures/gesture_recognizer_unittest.cc @@ -481,10 +481,6 @@ base::TimeDelta GetTime() { return base::Time::NowFromSystemTime() - base::Time(); } -base::TimeDelta AbsTime(int timeInMillis) { - return base::TimeDelta::FromMilliseconds(timeInMillis); -} - void SendScrollEvents(RootWindow* root_window, int x_start, int y_start, @@ -860,6 +856,8 @@ TEST_F(GestureRecognizerTest, GestureEventScroll) { ui::ET_GESTURE_SCROLL_UPDATE); EXPECT_EQ(29, delegate->scroll_x()); EXPECT_EQ(29, delegate->scroll_y()); + EXPECT_EQ(0, delegate->scroll_velocity_x()); + EXPECT_EQ(0, delegate->scroll_velocity_y()); EXPECT_EQ(gfx::Point(1, 1).ToString(), delegate->scroll_begin_position().ToString()); @@ -887,7 +885,7 @@ TEST_F(GestureRecognizerTest, GestureEventScroll) { base::TimeDelta::FromMilliseconds(50)); root_window()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release); EXPECT_2_EVENTS(delegate->events(), - ui::ET_SCROLL_FLING_START, + ui::ET_GESTURE_SCROLL_END, ui::ET_GESTURE_END); EXPECT_TRUE(delegate->bounding_box().IsEmpty()); } @@ -1008,6 +1006,7 @@ TEST_F(GestureRecognizerTest, GestureEventVerticalRailFling) { EXPECT_EQ(20, delegate->scroll_y()); EXPECT_EQ(0, delegate->scroll_x()); EXPECT_EQ(0, delegate->scroll_velocity_x()); + EXPECT_EQ(0, delegate->scroll_velocity_y()); // Get a high y velocity, while still staying on the rail SendScrollEvents(root_window(), 1, 1, press.time_stamp(), @@ -1276,6 +1275,8 @@ TEST_F(GestureRecognizerTest, GestureEventHorizontalRailScroll) { EXPECT_EQ(5, delegate->scroll_x()); // y shouldn't change, as we're on a horizontal rail. EXPECT_EQ(0, delegate->scroll_y()); + EXPECT_EQ(0, delegate->scroll_velocity_x()); + EXPECT_EQ(0, delegate->scroll_velocity_y()); // Send enough information that a velocity can be calculated for the gesture, // and we can break the rail @@ -1323,6 +1324,7 @@ TEST_F(GestureRecognizerTest, GestureEventVerticalRailScroll) { // x shouldn't change, as we're on a vertical rail. EXPECT_EQ(0, delegate->scroll_x()); EXPECT_EQ(0, delegate->scroll_velocity_x()); + EXPECT_EQ(0, delegate->scroll_velocity_y()); // Send enough information that a velocity can be calculated for the gesture, // and we can break the rail @@ -1676,7 +1678,7 @@ TEST_F(GestureRecognizerTest, GestureEventPinchFromScroll) { delegate->Reset(); ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), - kTouchId1, AbsTime(0)); + kTouchId1, GetTime()); root->AsRootWindowHostDelegate()->OnHostTouchEvent(&press); EXPECT_2_EVENTS(delegate->events(), ui::ET_GESTURE_BEGIN, @@ -1686,7 +1688,7 @@ TEST_F(GestureRecognizerTest, GestureEventPinchFromScroll) { // should generate both SCROLL_BEGIN and SCROLL_UPDATE gestures. delegate->Reset(); ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(130, 301), - kTouchId1, AbsTime(10)); + kTouchId1, GetTime()); root->AsRootWindowHostDelegate()->OnHostTouchEvent(&move); EXPECT_3_EVENTS(delegate->events(), ui::ET_GESTURE_TAP_CANCEL, @@ -1697,7 +1699,7 @@ TEST_F(GestureRecognizerTest, GestureEventPinchFromScroll) { // transition to two finger tap here because the touch points are far enough. delegate->Reset(); ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), - kTouchId2, AbsTime(20)); + kTouchId2, GetTime()); root->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2); EXPECT_2_EVENTS(delegate->events(), ui::ET_GESTURE_BEGIN, @@ -1708,7 +1710,7 @@ TEST_F(GestureRecognizerTest, GestureEventPinchFromScroll) { // Move the first finger. delegate->Reset(); ui::TouchEvent move3(ui::ET_TOUCH_MOVED, gfx::Point(95, 201), - kTouchId1, AbsTime(30)); + kTouchId1, GetTime()); root->AsRootWindowHostDelegate()->OnHostTouchEvent(&move3); EXPECT_2_EVENTS(delegate->events(), ui::ET_GESTURE_PINCH_UPDATE, @@ -1719,7 +1721,7 @@ TEST_F(GestureRecognizerTest, GestureEventPinchFromScroll) { // Now move the second finger. delegate->Reset(); ui::TouchEvent move4(ui::ET_TOUCH_MOVED, gfx::Point(55, 15), - kTouchId2, AbsTime(40)); + kTouchId2, GetTime()); root->AsRootWindowHostDelegate()->OnHostTouchEvent(&move4); EXPECT_2_EVENTS(delegate->events(), ui::ET_GESTURE_PINCH_UPDATE, @@ -1730,7 +1732,8 @@ TEST_F(GestureRecognizerTest, GestureEventPinchFromScroll) { // Release the first finger. This should end pinch. delegate->Reset(); ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201), - kTouchId1, AbsTime(50)); + kTouchId1, press.time_stamp() + + base::TimeDelta::FromMilliseconds(50)); root->AsRootWindowHostDelegate()->OnHostTouchEvent(&release); EXPECT_2_EVENTS(delegate->events(), ui::ET_GESTURE_PINCH_END, @@ -1741,7 +1744,7 @@ TEST_F(GestureRecognizerTest, GestureEventPinchFromScroll) { // Move the second finger. This should still generate a scroll. delegate->Reset(); ui::TouchEvent move5(ui::ET_TOUCH_MOVED, gfx::Point(25, 10), - kTouchId2, AbsTime(60)); + kTouchId2, GetTime()); root->AsRootWindowHostDelegate()->OnHostTouchEvent(&move5); EXPECT_1_EVENT(delegate->events(), ui::ET_GESTURE_SCROLL_UPDATE); EXPECT_TRUE(delegate->bounding_box().IsEmpty()); @@ -2259,8 +2262,7 @@ TEST_F(GestureRecognizerTest, TwoFingerTap) { EXPECT_FALSE(delegate->double_tap()); EXPECT_FALSE(delegate->scroll_begin()); EXPECT_FALSE(delegate->scroll_update()); - EXPECT_FALSE(delegate->scroll_end()); - EXPECT_TRUE(delegate->fling()); + EXPECT_TRUE(delegate->scroll_end()); EXPECT_FALSE(delegate->two_finger_tap()); } @@ -2775,9 +2777,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTouchMovePartialConsumed) { EXPECT_FALSE(delegate->double_tap()); EXPECT_FALSE(delegate->scroll_begin()); EXPECT_FALSE(delegate->scroll_update()); - EXPECT_FALSE(delegate->scroll_end()); - // Moves arrive without delays and hence have high velocity. - EXPECT_TRUE(delegate->fling()); + EXPECT_TRUE(delegate->scroll_end()); } // Check that appropriate touch events generate double tap gesture events. diff --git a/ui/base/gestures/gesture_configuration.cc b/ui/base/gestures/gesture_configuration.cc index ccd7958..39847830 100644 --- a/ui/base/gestures/gesture_configuration.cc +++ b/ui/base/gestures/gesture_configuration.cc @@ -24,16 +24,15 @@ double GestureConfiguration::min_distance_for_pinch_scroll_in_pixels_ = 20; double GestureConfiguration::min_flick_speed_squared_ = 550.f * 550.f; double GestureConfiguration::min_pinch_update_distance_in_pixels_ = 5; double GestureConfiguration::min_rail_break_velocity_ = 200; -double GestureConfiguration::min_scroll_delta_squared_ = 4 * 4; -int GestureConfiguration::min_scroll_successive_velocity_events_ = 3; -float GestureConfiguration::min_scroll_velocity_ = 30.0f; +double GestureConfiguration::min_scroll_delta_squared_ = 5 * 5; double GestureConfiguration::min_swipe_speed_ = 20; double GestureConfiguration::min_touch_down_duration_in_seconds_for_click_ = 0.01; // The number of points used in the linear regression which determines -// touch velocity. Velocity is reported for 2 or more touch move events. -int GestureConfiguration::points_buffered_for_velocity_ = 8; +// touch velocity. If fewer than this number of points have been seen, +// velocity is reported as 0. +int GestureConfiguration::points_buffered_for_velocity_ = 3; double GestureConfiguration::rail_break_proportion_ = 15; double GestureConfiguration::rail_start_proportion_ = 2; diff --git a/ui/base/gestures/gesture_configuration.h b/ui/base/gestures/gesture_configuration.h index db46d95..2fc5470 100644 --- a/ui/base/gestures/gesture_configuration.h +++ b/ui/base/gestures/gesture_configuration.h @@ -113,18 +113,6 @@ class UI_EXPORT GestureConfiguration { static void set_min_scroll_delta_squared(double val) { min_scroll_delta_squared_ = val; } - static int min_scroll_successive_velocity_events() { - return min_scroll_successive_velocity_events_; - } - static void set_min_scroll_successive_velocity_events(int val) { - min_scroll_successive_velocity_events_ = val; - } - static float min_scroll_velocity() { - return min_scroll_velocity_; - } - static void set_min_scroll_velocity(float val) { - min_scroll_velocity_ = val; - } static double min_swipe_speed() { return min_swipe_speed_; } @@ -199,9 +187,6 @@ class UI_EXPORT GestureConfiguration { static double min_pinch_update_distance_in_pixels_; static double min_rail_break_velocity_; static double min_scroll_delta_squared_; - // TODO(rjkroege): Expose these in chrome://gesture - static int min_scroll_successive_velocity_events_; - static float min_scroll_velocity_; static double min_swipe_speed_; static double min_touch_down_duration_in_seconds_for_click_; static int points_buffered_for_velocity_; diff --git a/ui/base/gestures/gesture_point.cc b/ui/base/gestures/gesture_point.cc index 765ffd9..a95b297 100644 --- a/ui/base/gestures/gesture_point.cc +++ b/ui/base/gestures/gesture_point.cc @@ -30,14 +30,13 @@ GesturePoint::~GesturePoint() {} void GesturePoint::Reset() { first_touch_time_ = second_last_touch_time_ = last_touch_time_ = 0.0; - ResetVelocity(); + velocity_calculator_.ClearHistory(); point_id_ = -1; clear_enclosing_rectangle(); } void GesturePoint::ResetVelocity() { velocity_calculator_.ClearHistory(); - same_direction_count_ = gfx::Vector2d(); } gfx::Vector2d GesturePoint::ScrollDelta() { @@ -51,24 +50,22 @@ void GesturePoint::UpdateValues(const TouchEvent& event) { velocity_calculator_.PointSeen(event.location().x(), event.location().y(), event_timestamp_microseconds); - gfx::Vector2d sd(ScrollVelocityDirection(velocity_calculator_.XVelocity()), - ScrollVelocityDirection(velocity_calculator_.YVelocity())); - same_direction_count_ = same_direction_count_ + sd; } last_touch_time_ = event.time_stamp().InSecondsF(); last_touch_position_ = event.location(); if (event.type() == ui::ET_TOUCH_PRESSED) { - ResetVelocity(); - clear_enclosing_rectangle(); first_touch_time_ = last_touch_time_; first_touch_position_ = event.location(); second_last_touch_position_ = last_touch_position_; second_last_touch_time_ = last_touch_time_; + + velocity_calculator_.ClearHistory(); velocity_calculator_.PointSeen(event.location().x(), event.location().y(), event_timestamp_microseconds); + clear_enclosing_rectangle(); } UpdateEnclosingRectangle(event); @@ -83,7 +80,6 @@ void GesturePoint::UpdateForTap() { void GesturePoint::UpdateForScroll() { second_last_touch_position_ = last_touch_position_; second_last_touch_time_ = last_touch_time_; - same_direction_count_ = gfx::Vector2d(); } bool GesturePoint::IsInClickWindow(const TouchEvent& event) const { @@ -105,26 +101,15 @@ bool GesturePoint::IsInFlickWindow(const TouchEvent& event) { event.type() != ui::ET_TOUCH_CANCELLED; } -int GesturePoint::ScrollVelocityDirection(float v) { - if (v < -GestureConfiguration::min_scroll_velocity()) - return -1; - else if (v > GestureConfiguration::min_scroll_velocity()) - return 1; - else - return 0; -} - bool GesturePoint::DidScroll(const TouchEvent& event, int dist) const { gfx::Vector2d d = last_touch_position_ - second_last_touch_position_; return abs(d.x()) > dist || abs(d.y()) > dist; } -bool GesturePoint::IsConsistentScrollingActionUnderway() { - int me = GestureConfiguration::min_scroll_successive_velocity_events(); - if (abs(same_direction_count_.x()) >= me || - abs(same_direction_count_.y()) >= me) - return true; - return false; +bool GesturePoint::HasEnoughDataToEstablishRail() const { + gfx::Vector2d d = last_touch_position_ - first_touch_position_; + int64 delta_squared = d.LengthSquared(); + return delta_squared > GestureConfiguration::min_scroll_delta_squared(); } bool GesturePoint::IsInHorizontalRailWindow() const { diff --git a/ui/base/gestures/gesture_point.h b/ui/base/gestures/gesture_point.h index f52fece4..0e77fd2 100644 --- a/ui/base/gestures/gesture_point.h +++ b/ui/base/gestures/gesture_point.h @@ -44,6 +44,7 @@ class GesturePoint { bool IsInHorizontalRailWindow() const; bool IsInVerticalRailWindow() const; bool IsInsideManhattanSquare(const TouchEvent& event) const; + bool HasEnoughDataToEstablishRail() const; bool BreaksHorizontalRail(); bool BreaksVerticalRail(); bool DidScroll(const TouchEvent& event, int distance) const; @@ -78,10 +79,6 @@ class GesturePoint { const gfx::Rect& enclosing_rectangle() const { return enclosing_rect_; } - // Tests if the point has a consistent scroll vector across a window of touch - // move events. - bool IsConsistentScrollingActionUnderway(); - private: // Various statistical functions to manipulate gestures. bool IsInClickTimeWindow() const; @@ -89,10 +86,6 @@ class GesturePoint { bool IsSecondClickInsideManhattanSquare(const TouchEvent& event) const; bool IsOverMinFlickSpeed(); - // Returns -1, 0, 1 for |v| below the negative velocity threshold, - // in [-threshold, threshold] or above respectively. - int ScrollVelocityDirection(float v); - // The enclosing rectangle represents a rectangular touch region generated // by a sequence of ET_TOUCH_PRESSED, ET_TOUCH_MOVED, and ET_TOUCH_RELEASED // events forming a GESTURE_TAP event. The enclosing rectangle is updated @@ -124,9 +117,6 @@ class GesturePoint { // generated by a sequence of touch events gfx::Rect enclosing_rect_; - // Count of the number of events with same direction. - gfx::Vector2d same_direction_count_; - DISALLOW_COPY_AND_ASSIGN(GesturePoint); }; diff --git a/ui/base/gestures/gesture_sequence.cc b/ui/base/gestures/gesture_sequence.cc index 75932ec..5029d76 100644 --- a/ui/base/gestures/gesture_sequence.cc +++ b/ui/base/gestures/gesture_sequence.cc @@ -846,8 +846,9 @@ bool GestureSequence::ScrollStart(const TouchEvent& event, GesturePoint& point, Gestures* gestures) { DCHECK(state_ == GS_PENDING_SYNTHETIC_CLICK); - if (!point.IsConsistentScrollingActionUnderway() && - !point.IsInScrollWindow(event)) + if (point.IsInClickWindow(event) || + !point.IsInScrollWindow(event) || + !point.HasEnoughDataToEstablishRail()) return false; AppendScrollGestureBegin(point, point.first_touch_position(), gestures); if (point.IsInHorizontalRailWindow()) @@ -1066,8 +1067,8 @@ bool GestureSequence::MaybeSwipe(const TouchEvent& event, velocity_x = points_[i].XVelocity(); velocity_y = points_[i].YVelocity(); - sign_x = velocity_x < 0.f ? -1 : 1; - sign_y = velocity_y < 0.f ? -1 : 1; + sign_x = velocity_x < 0 ? -1 : 1; + sign_y = velocity_y < 0 ? -1 : 1; for (++i; i < kMaxGesturePoints; ++i) { if (!points_[i].in_use()) diff --git a/ui/base/gestures/velocity_calculator.cc b/ui/base/gestures/velocity_calculator.cc index f4db08ac..ca862cd 100644 --- a/ui/base/gestures/velocity_calculator.cc +++ b/ui/base/gestures/velocity_calculator.cc @@ -50,7 +50,7 @@ float VelocityCalculator::VelocitySquared() { void VelocityCalculator::UpdateVelocity() { // We don't have enough data to make a good estimate of the velocity. - if (num_valid_entries_ < 2) + if (num_valid_entries_ < buffer_size_) return; // Where A_i = A[i] - mean(A) @@ -61,23 +61,23 @@ void VelocityCalculator::UpdateVelocity() { float mean_y = 0; int64 mean_time = 0; - for (size_t i = 0; i < num_valid_entries_; ++i) { + for (size_t i = 0; i < buffer_size_; ++i) { mean_x += buffer_[i].x; mean_y += buffer_[i].y; mean_time += buffer_[i].time; } // Minimize number of divides. - const float num_valid_entries_i = 1.0f / num_valid_entries_; + const float buffer_size_i = 1.0f / buffer_size_; - mean_x *= num_valid_entries_i; - mean_y *= num_valid_entries_i; + mean_x *= buffer_size_i; + mean_y *= buffer_size_i; // The loss in accuracy due to rounding is insignificant compared to // the error due to the resolution of the timer. // Use integer division to avoid the cast to double, which would cause // VelocityCalculatorTest.IsAccurateWithLargeTimes to fail. - mean_time /= num_valid_entries_; + mean_time /= buffer_size_; float xt = 0; // sum_i(x_i * t_i) float yt = 0; // sum_i(y_i * t_i) @@ -85,21 +85,16 @@ void VelocityCalculator::UpdateVelocity() { int64 t_i; - for (size_t i = 0; i < num_valid_entries_; ++i) { + for (size_t i = 0; i < buffer_size_; ++i) { t_i = (buffer_[i].time - mean_time); xt += (buffer_[i].x - mean_x) * t_i; yt += (buffer_[i].y - mean_y) * t_i; tt += t_i * t_i; } - if (tt > 0) { - // Convert time from microseconds to seconds. - x_velocity_ = xt / (tt / 1000000.0f); - y_velocity_ = yt / (tt / 1000000.0f); - } else { - x_velocity_ = 0.0f; - y_velocity_ = 0.0f; - } + // Convert time from microseconds to seconds. + x_velocity_ = xt / (tt / 1000000.0f); + y_velocity_ = yt / (tt / 1000000.0f); velocities_stale_ = false; } |