1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/events/gestures/gesture_point.h"
9 #include "base/basictypes.h"
10 #include "ui/events/event.h"
11 #include "ui/events/event_constants.h"
12 #include "ui/events/gestures/gesture_configuration.h"
13 #include "ui/events/gestures/gesture_types.h"
14 #include "ui/events/gestures/gesture_util.h"
18 GesturePoint::GesturePoint()
19 : first_touch_time_(0.0),
20 second_last_touch_time_(0.0),
21 last_touch_time_(0.0),
22 second_last_tap_time_(0.0),
25 GestureConfiguration::points_buffered_for_velocity()),
30 GesturePoint::~GesturePoint() {}
32 void GesturePoint::Reset() {
33 first_touch_time_ = second_last_touch_time_ = last_touch_time_ = 0.0;
36 clear_enclosing_rectangle();
39 void GesturePoint::ResetVelocity() {
40 velocity_calculator_.ClearHistory();
41 same_direction_count_ = gfx::Vector2d();
44 gfx::Vector2d GesturePoint::ScrollDelta() {
45 return last_touch_position_ - second_last_touch_position_;
48 void GesturePoint::UpdateValues(const TouchEvent& event) {
49 const int64 event_timestamp_microseconds =
50 event.time_stamp().InMicroseconds();
51 if (event.type() == ui::ET_TOUCH_MOVED) {
52 velocity_calculator_.PointSeen(event.location().x(),
54 event_timestamp_microseconds);
55 gfx::Vector2d sd(ScrollVelocityDirection(velocity_calculator_.XVelocity()),
56 ScrollVelocityDirection(velocity_calculator_.YVelocity()));
57 same_direction_count_ = same_direction_count_ + sd;
60 last_touch_time_ = event.time_stamp().InSecondsF();
61 last_touch_position_ = event.location();
63 if (event.type() == ui::ET_TOUCH_PRESSED) {
65 clear_enclosing_rectangle();
66 first_touch_time_ = last_touch_time_;
67 first_touch_position_ = event.location();
68 second_last_touch_position_ = last_touch_position_;
69 second_last_touch_time_ = last_touch_time_;
70 velocity_calculator_.PointSeen(event.location().x(),
72 event_timestamp_microseconds);
75 UpdateEnclosingRectangle(event);
78 void GesturePoint::UpdateForTap() {
79 // Update the tap-position and time, and reset every other state.
80 second_last_tap_position_ = last_tap_position_;
81 second_last_tap_time_ = last_tap_time_;
82 last_tap_time_ = last_touch_time_;
83 last_tap_position_ = last_touch_position_;
86 void GesturePoint::UpdateForScroll() {
87 second_last_touch_position_ = last_touch_position_;
88 second_last_touch_time_ = last_touch_time_;
89 same_direction_count_ = gfx::Vector2d();
92 bool GesturePoint::IsInClickWindow(const TouchEvent& event) const {
93 return IsInClickTimeWindow() && IsInsideManhattanSquare(event);
96 bool GesturePoint::IsInDoubleClickWindow(const TouchEvent& event) const {
97 return IsInClickAggregateTimeWindow(last_tap_time_, last_touch_time_) &&
98 IsPointInsideManhattanSquare(event.location(), last_tap_position_);
101 bool GesturePoint::IsInTripleClickWindow(const TouchEvent& event) const {
102 return IsInClickAggregateTimeWindow(last_tap_time_, last_touch_time_) &&
103 IsInClickAggregateTimeWindow(second_last_tap_time_, last_tap_time_) &&
104 IsPointInsideManhattanSquare(event.location(), last_tap_position_) &&
105 IsPointInsideManhattanSquare(last_tap_position_,
106 second_last_tap_position_);
109 bool GesturePoint::IsInScrollWindow(const TouchEvent& event) const {
110 if (IsConsistentScrollingActionUnderway())
112 return event.type() == ui::ET_TOUCH_MOVED &&
113 !IsInsideManhattanSquare(event);
116 bool GesturePoint::IsInFlickWindow(const TouchEvent& event) {
117 return IsOverMinFlickSpeed() &&
118 event.type() != ui::ET_TOUCH_CANCELLED;
121 int GesturePoint::ScrollVelocityDirection(float v) {
122 if (v < -GestureConfiguration::min_scroll_velocity())
124 else if (v > GestureConfiguration::min_scroll_velocity())
130 bool GesturePoint::DidScroll(const TouchEvent& event, int dist) const {
131 gfx::Vector2d d = last_touch_position_ - second_last_touch_position_;
132 return abs(d.x()) > dist || abs(d.y()) > dist;
135 bool GesturePoint::IsConsistentScrollingActionUnderway() const {
136 int me = GestureConfiguration::min_scroll_successive_velocity_events();
137 if (abs(same_direction_count_.x()) >= me ||
138 abs(same_direction_count_.y()) >= me)
143 bool GesturePoint::IsInHorizontalRailWindow() const {
144 gfx::Vector2d d = last_touch_position_ - second_last_touch_position_;
146 GestureConfiguration::rail_start_proportion() * abs(d.y());
149 bool GesturePoint::IsInVerticalRailWindow() const {
150 gfx::Vector2d d = last_touch_position_ - second_last_touch_position_;
152 GestureConfiguration::rail_start_proportion() * abs(d.x());
155 bool GesturePoint::BreaksHorizontalRail() {
156 float vx = XVelocity();
157 float vy = YVelocity();
158 return fabs(vy) > GestureConfiguration::rail_break_proportion() * fabs(vx) +
159 GestureConfiguration::min_rail_break_velocity();
162 bool GesturePoint::BreaksVerticalRail() {
163 float vx = XVelocity();
164 float vy = YVelocity();
165 return fabs(vx) > GestureConfiguration::rail_break_proportion() * fabs(vy) +
166 GestureConfiguration::min_rail_break_velocity();
169 bool GesturePoint::IsInClickTimeWindow() const {
170 double duration = last_touch_time_ - first_touch_time_;
172 GestureConfiguration::min_touch_down_duration_in_seconds_for_click() &&
174 GestureConfiguration::max_touch_down_duration_in_seconds_for_click();
177 bool GesturePoint::IsInClickAggregateTimeWindow(double before,
178 double after) const {
179 double duration = after - before;
180 return duration < GestureConfiguration::max_seconds_between_double_click();
183 bool GesturePoint::IsInsideManhattanSquare(const TouchEvent& event) const {
184 return ui::gestures::IsInsideManhattanSquare(event.location(),
185 first_touch_position_);
188 bool GesturePoint::IsPointInsideManhattanSquare(gfx::Point p1,
189 gfx::Point p2) const {
190 int manhattan_distance = abs(p1.x() - p2.x()) + abs(p1.y() - p2.y());
191 return manhattan_distance <
192 GestureConfiguration::max_distance_between_taps_for_double_tap();
195 bool GesturePoint::IsOverMinFlickSpeed() {
196 return velocity_calculator_.VelocitySquared() >
197 GestureConfiguration::min_flick_speed_squared();
200 void GesturePoint::UpdateEnclosingRectangle(const TouchEvent& event) {
203 // Ignore this TouchEvent if it has a radius larger than the maximum
204 // allowed radius size.
205 if (event.radius_x() > GestureConfiguration::max_radius() ||
206 event.radius_y() > GestureConfiguration::max_radius())
209 // If the device provides at least one of the radius values, take the larger
210 // of the two and use this as both the x radius and the y radius of the
211 // touch region. Otherwise use the default radius value.
212 // TODO(tdanderson): Implement a more specific check for the exact
213 // information provided by the device (0-2 radii values, force, angle) and
214 // use this to compute a more representative rectangular touch region.
215 if (event.radius_x() || event.radius_y())
216 radius = std::max(event.radius_x(), event.radius_y());
218 radius = GestureConfiguration::default_radius();
220 gfx::Rect rect(event.location().x() - radius,
221 event.location().y() - radius,
224 if (IsInClickWindow(event))
225 enclosing_rect_.Union(rect);
227 enclosing_rect_ = rect;