summaryrefslogtreecommitdiffstats
path: root/ui/base
diff options
context:
space:
mode:
authorrjkroege@chromium.org <rjkroege@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-12-08 04:17:50 +0000
committerrjkroege@chromium.org <rjkroege@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-12-08 04:17:50 +0000
commit0a5b7e27fc80da622864c98ee42a722c3160bcfa (patch)
tree65dbaef8cc56e2dbe71fbfe023ffd1c085162e28 /ui/base
parent3220d1bc79f230a576ef77de5c626796d8a92b89 (diff)
downloadchromium_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.cc9
-rw-r--r--ui/base/gestures/gesture_configuration.h15
-rw-r--r--ui/base/gestures/gesture_point.cc31
-rw-r--r--ui/base/gestures/gesture_point.h12
-rw-r--r--ui/base/gestures/gesture_sequence.cc9
-rw-r--r--ui/base/gestures/velocity_calculator.cc25
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;
}