diff options
author | rjkroege@chromium.org <rjkroege@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-12-08 04:17:50 +0000 |
---|---|---|
committer | rjkroege@chromium.org <rjkroege@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-12-08 04:17:50 +0000 |
commit | 0a5b7e27fc80da622864c98ee42a722c3160bcfa (patch) | |
tree | 65dbaef8cc56e2dbe71fbfe023ffd1c085162e28 /ui/base | |
parent | 3220d1bc79f230a576ef77de5c626796d8a92b89 (diff) | |
download | chromium_src-0a5b7e27fc80da622864c98ee42a722c3160bcfa.zip chromium_src-0a5b7e27fc80da622864c98ee42a722c3160bcfa.tar.gz chromium_src-0a5b7e27fc80da622864c98ee42a722c3160bcfa.tar.bz2 |
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
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@171934 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/base')
-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 |
6 files changed, 73 insertions, 28 deletions
diff --git a/ui/base/gestures/gesture_configuration.cc b/ui/base/gestures/gesture_configuration.cc index 39847830..ccd7958 100644 --- a/ui/base/gestures/gesture_configuration.cc +++ b/ui/base/gestures/gesture_configuration.cc @@ -24,15 +24,16 @@ 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_ = 5 * 5; +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_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. If fewer than this number of points have been seen, -// velocity is reported as 0. -int GestureConfiguration::points_buffered_for_velocity_ = 3; +// touch velocity. Velocity is reported for 2 or more touch move events. +int GestureConfiguration::points_buffered_for_velocity_ = 8; 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 2fc5470..db46d95 100644 --- a/ui/base/gestures/gesture_configuration.h +++ b/ui/base/gestures/gesture_configuration.h @@ -113,6 +113,18 @@ 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_; } @@ -187,6 +199,9 @@ 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 a95b297..765ffd9 100644 --- a/ui/base/gestures/gesture_point.cc +++ b/ui/base/gestures/gesture_point.cc @@ -30,13 +30,14 @@ GesturePoint::~GesturePoint() {} void GesturePoint::Reset() { first_touch_time_ = second_last_touch_time_ = last_touch_time_ = 0.0; - velocity_calculator_.ClearHistory(); + ResetVelocity(); point_id_ = -1; clear_enclosing_rectangle(); } void GesturePoint::ResetVelocity() { velocity_calculator_.ClearHistory(); + same_direction_count_ = gfx::Vector2d(); } gfx::Vector2d GesturePoint::ScrollDelta() { @@ -50,22 +51,24 @@ 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); @@ -80,6 +83,7 @@ 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 { @@ -101,15 +105,26 @@ 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::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::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::IsInHorizontalRailWindow() const { diff --git a/ui/base/gestures/gesture_point.h b/ui/base/gestures/gesture_point.h index 0e77fd2..f52fece4 100644 --- a/ui/base/gestures/gesture_point.h +++ b/ui/base/gestures/gesture_point.h @@ -44,7 +44,6 @@ 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; @@ -79,6 +78,10 @@ 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; @@ -86,6 +89,10 @@ 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 @@ -117,6 +124,9 @@ 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 5029d76..75932ec 100644 --- a/ui/base/gestures/gesture_sequence.cc +++ b/ui/base/gestures/gesture_sequence.cc @@ -846,9 +846,8 @@ bool GestureSequence::ScrollStart(const TouchEvent& event, GesturePoint& point, Gestures* gestures) { DCHECK(state_ == GS_PENDING_SYNTHETIC_CLICK); - if (point.IsInClickWindow(event) || - !point.IsInScrollWindow(event) || - !point.HasEnoughDataToEstablishRail()) + if (!point.IsConsistentScrollingActionUnderway() && + !point.IsInScrollWindow(event)) return false; AppendScrollGestureBegin(point, point.first_touch_position(), gestures); if (point.IsInHorizontalRailWindow()) @@ -1067,8 +1066,8 @@ bool GestureSequence::MaybeSwipe(const TouchEvent& event, velocity_x = points_[i].XVelocity(); velocity_y = points_[i].YVelocity(); - sign_x = velocity_x < 0 ? -1 : 1; - sign_y = velocity_y < 0 ? -1 : 1; + sign_x = velocity_x < 0.f ? -1 : 1; + sign_y = velocity_y < 0.f ? -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 ca862cd..f4db08ac 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_ < buffer_size_) + if (num_valid_entries_ < 2) 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 < buffer_size_; ++i) { + for (size_t i = 0; i < num_valid_entries_; ++i) { mean_x += buffer_[i].x; mean_y += buffer_[i].y; mean_time += buffer_[i].time; } // Minimize number of divides. - const float buffer_size_i = 1.0f / buffer_size_; + const float num_valid_entries_i = 1.0f / num_valid_entries_; - mean_x *= buffer_size_i; - mean_y *= buffer_size_i; + mean_x *= num_valid_entries_i; + mean_y *= num_valid_entries_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 /= buffer_size_; + mean_time /= num_valid_entries_; float xt = 0; // sum_i(x_i * t_i) float yt = 0; // sum_i(y_i * t_i) @@ -85,16 +85,21 @@ void VelocityCalculator::UpdateVelocity() { int64 t_i; - for (size_t i = 0; i < buffer_size_; ++i) { + for (size_t i = 0; i < num_valid_entries_; ++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; } - // Convert time from microseconds to seconds. - x_velocity_ = xt / (tt / 1000000.0f); - y_velocity_ = yt / (tt / 1000000.0f); + 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; + } velocities_stale_ = false; } |