Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(35)

Side by Side Diff: ui/aura/gestures/gesture_recognizer_aura.cc

Issue 9104021: aura: Update GestureRecognizer to be able to process multi-point gestures. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « ui/aura/gestures/gesture_recognizer_aura.h ('k') | ui/aura/gestures/gesture_sequence.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/aura/gestures/gesture_recognizer_aura.h" 5 #include "ui/aura/gestures/gesture_recognizer_aura.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "base/memory/scoped_ptr.h" 8 #include "base/memory/scoped_ptr.h"
9 #include "base/time.h" 9 #include "base/time.h"
10 #include "ui/aura/event.h" 10 #include "ui/aura/event.h"
11 #include "ui/aura/gestures/gesture_sequence.h"
11 #include "ui/base/events.h" 12 #include "ui/base/events.h"
12 13
13 namespace { 14 namespace {
14 // TODO(girard): Make these configurable in sync with this CL
15 // http://crbug.com/100773
16 const double kMaximumTouchDownDurationInSecondsForClick = 0.8;
17 const double kMinimumTouchDownDurationInSecondsForClick = 0.01;
18 const double kMaximumSecondsBetweenDoubleClick = 0.7;
19 const int kMaximumTouchMoveInPixelsForClick = 20;
20 const float kMinFlickSpeedSquared = 550.f * 550.f;
21
22 // This is used to pop a std::queue when returning from a function. 15 // This is used to pop a std::queue when returning from a function.
23 class ScopedPop { 16 class ScopedPop {
24 public: 17 public:
25 ScopedPop(std::queue<aura::TouchEvent*>* queue) : queue_(queue) { 18 ScopedPop(std::queue<aura::TouchEvent*>* queue) : queue_(queue) {
26 } 19 }
27 20
28 ~ScopedPop() { 21 ~ScopedPop() {
29 delete queue_->front(); 22 delete queue_->front();
30 queue_->pop(); 23 queue_->pop();
31 } 24 }
32 25
33 private: 26 private:
34 std::queue<aura::TouchEvent*>* queue_; 27 std::queue<aura::TouchEvent*>* queue_;
35 DISALLOW_COPY_AND_ASSIGN(ScopedPop); 28 DISALLOW_COPY_AND_ASSIGN(ScopedPop);
36 }; 29 };
37 30
38 } // namespace 31 } // namespace
39 32
40 namespace aura { 33 namespace aura {
41 34
42 namespace {
43
44 // Get equivalent TouchState from EventType |type|.
45 GestureSequence::TouchState TouchEventTypeToTouchState(ui::EventType type) {
46 switch (type) {
47 case ui::ET_TOUCH_RELEASED:
48 return GestureSequence::TS_RELEASED;
49 case ui::ET_TOUCH_PRESSED:
50 return GestureSequence::TS_PRESSED;
51 case ui::ET_TOUCH_MOVED:
52 return GestureSequence::TS_MOVED;
53 case ui::ET_TOUCH_STATIONARY:
54 return GestureSequence::TS_STATIONARY;
55 case ui::ET_TOUCH_CANCELLED:
56 return GestureSequence::TS_CANCELLED;
57 default:
58 VLOG(1) << "Unknown Touch Event type";
59 }
60 return GestureSequence::TS_UNKNOWN;
61 }
62
63 } // namespace
64
65 ////////////////////////////////////////////////////////////////////////////////
66 // GestureSequence Public:
67
68 GestureSequence::GestureSequence()
69 : first_touch_time_(0.0),
70 state_(GestureSequence::GS_NO_GESTURE),
71 last_touch_time_(0.0),
72 last_click_time_(0.0),
73 x_velocity_(0.0),
74 y_velocity_(0.0),
75 flags_(0) {
76 }
77
78 GestureSequence::~GestureSequence() {
79 }
80
81 GestureSequence::Gestures* GestureSequence::ProcessTouchEventForGesture(
82 const TouchEvent& event,
83 ui::TouchStatus status) {
84 if (status != ui::TOUCH_STATUS_UNKNOWN)
85 return NULL; // The event was consumed by a touch sequence.
86
87 scoped_ptr<Gestures> gestures(new Gestures());
88 UpdateValues(event);
89 switch (Signature(state_, event.touch_id(), event.type(), false)) {
90 case GST_NO_GESTURE_FIRST_PRESSED:
91 TouchDown(event, gestures.get());
92 break;
93 case GST_PENDING_SYNTHETIC_CLICK_FIRST_RELEASED:
94 Click(event, gestures.get());
95 break;
96 case GST_PENDING_SYNTHETIC_CLICK_FIRST_MOVED:
97 case GST_PENDING_SYNTHETIC_CLICK_FIRST_STATIONARY:
98 InClickOrScroll(event, gestures.get());
99 break;
100 case GST_PENDING_SYNTHETIC_CLICK_FIRST_CANCELLED:
101 NoGesture(event, gestures.get());
102 break;
103 case GST_SCROLL_FIRST_MOVED:
104 InScroll(event, gestures.get());
105 break;
106 case GST_SCROLL_FIRST_RELEASED:
107 case GST_SCROLL_FIRST_CANCELLED:
108 ScrollEnd(event, gestures.get());
109 break;
110 }
111 return gestures.release();
112 }
113
114 void GestureSequence::Reset() {
115 first_touch_time_ = 0.0;
116 state_ = GestureSequence::GS_NO_GESTURE;
117 last_touch_time_ = 0.0;
118 last_touch_position_.SetPoint(0, 0);
119 x_velocity_ = 0.0;
120 y_velocity_ = 0.0;
121 }
122
123 ////////////////////////////////////////////////////////////////////////////////
124 // GestureSequence Private:
125
126 unsigned int GestureSequence::Signature(GestureState gesture_state,
127 unsigned int touch_id,
128 ui::EventType type,
129 bool touch_handled) {
130 CHECK((touch_id & 0xfff) == touch_id);
131 TouchState touch_state = TouchEventTypeToTouchState(type);
132 return 1 + ((touch_state & 0x7) << 1 | (touch_handled ? 1 << 4 : 0) |
133 ((touch_id & 0xfff) << 5) | (gesture_state << 17));
134 }
135
136 bool GestureSequence::IsInClickTimeWindow() {
137 double duration(last_touch_time_ - first_touch_time_);
138 return duration >= kMinimumTouchDownDurationInSecondsForClick &&
139 duration < kMaximumTouchDownDurationInSecondsForClick;
140 }
141
142 bool GestureSequence::IsInSecondClickTimeWindow() {
143 double duration(last_touch_time_ - last_click_time_);
144 return duration < kMaximumSecondsBetweenDoubleClick;
145 }
146
147 bool GestureSequence::IsInsideManhattanSquare(const TouchEvent& event) {
148 int manhattanDistance = abs(event.x() - first_touch_position_.x()) +
149 abs(event.y() - first_touch_position_.y());
150 return manhattanDistance < kMaximumTouchMoveInPixelsForClick;
151 }
152
153 bool GestureSequence::IsSecondClickInsideManhattanSquare(
154 const TouchEvent& event) {
155 int manhattanDistance = abs(event.x() - last_click_position_.x()) +
156 abs(event.y() - last_click_position_.y());
157 return manhattanDistance < kMaximumTouchMoveInPixelsForClick;
158 }
159
160 bool GestureSequence::IsOverMinFlickSpeed() {
161 return (x_velocity_ * x_velocity_ + y_velocity_ * y_velocity_) >
162 kMinFlickSpeedSquared;
163 }
164
165 void GestureSequence::AppendTapDownGestureEvent(const TouchEvent& event,
166 Gestures* gestures) {
167 gestures->push_back(linked_ptr<GestureEvent>(new GestureEvent(
168 ui::ET_GESTURE_TAP_DOWN,
169 first_touch_position_.x(),
170 first_touch_position_.y(),
171 event.flags(),
172 base::Time::FromDoubleT(last_touch_time_),
173 0.f, 0.f)));
174 }
175
176 void GestureSequence::AppendClickGestureEvent(const TouchEvent& event,
177 Gestures* gestures) {
178 gestures->push_back(linked_ptr<GestureEvent>(new GestureEvent(
179 ui::ET_GESTURE_TAP,
180 first_touch_position_.x(),
181 first_touch_position_.y(),
182 event.flags(),
183 base::Time::FromDoubleT(last_touch_time_),
184 0.f, 0.f)));
185 }
186
187 void GestureSequence::AppendDoubleClickGestureEvent(const TouchEvent& event,
188 Gestures* gestures) {
189 gestures->push_back(linked_ptr<GestureEvent>(new GestureEvent(
190 ui::ET_GESTURE_DOUBLE_TAP,
191 first_touch_position_.x(),
192 first_touch_position_.y(),
193 event.flags(),
194 base::Time::FromDoubleT(last_touch_time_),
195 0.f, 0.f)));
196 }
197
198 void GestureSequence::AppendScrollGestureBegin(const TouchEvent& event,
199 Gestures* gestures) {
200 gestures->push_back(linked_ptr<GestureEvent>(new GestureEvent(
201 ui::ET_GESTURE_SCROLL_BEGIN,
202 event.x(),
203 event.y(),
204 event.flags(),
205 base::Time::FromDoubleT(last_touch_time_),
206 0.f, 0.f)));
207 }
208
209 void GestureSequence::AppendScrollGestureEnd(const TouchEvent& event,
210 Gestures* gestures,
211 float x_velocity,
212 float y_velocity) {
213 gestures->push_back(linked_ptr<GestureEvent>(new GestureEvent(
214 ui::ET_GESTURE_SCROLL_END,
215 event.x(),
216 event.y(),
217 event.flags(),
218 base::Time::FromDoubleT(last_touch_time_),
219 x_velocity, y_velocity)));
220 }
221
222 void GestureSequence:: AppendScrollGestureUpdate(const TouchEvent& event,
223 Gestures* gestures) {
224 float delta_x(event.x() - first_touch_position_.x());
225 float delta_y(event.y() - first_touch_position_.y());
226
227 gestures->push_back(linked_ptr<GestureEvent>(new GestureEvent(
228 ui::ET_GESTURE_SCROLL_UPDATE,
229 event.x(),
230 event.y(),
231 event.flags(),
232 base::Time::FromDoubleT(last_touch_time_),
233 delta_x, delta_y)));
234
235 first_touch_position_ = event.location();
236 }
237
238 void GestureSequence::UpdateValues(const TouchEvent& event) {
239 if (state_ != GS_NO_GESTURE && event.type() == ui::ET_TOUCH_MOVED) {
240 double interval(event.time_stamp().InSecondsF() - last_touch_time_);
241 x_velocity_ = (event.x() - last_touch_position_.x()) / interval;
242 y_velocity_ = (event.y() - last_touch_position_.y()) / interval;
243 }
244 last_touch_time_ = event.time_stamp().InSecondsF();
245 last_touch_position_ = event.location();
246 if (state_ == GS_NO_GESTURE) {
247 first_touch_time_ = last_touch_time_;
248 first_touch_position_ = event.location();
249 x_velocity_ = 0.0;
250 y_velocity_ = 0.0;
251 }
252 }
253
254 bool GestureSequence::Click(const TouchEvent& event, Gestures* gestures) {
255 bool gesture_added = false;
256 if (IsInClickTimeWindow() && IsInsideManhattanSquare(event)) {
257 gesture_added = true;
258 AppendClickGestureEvent(event, gestures);
259 if (IsInSecondClickTimeWindow() &&
260 IsSecondClickInsideManhattanSquare(event))
261 AppendDoubleClickGestureEvent(event, gestures);
262 last_click_time_ = last_touch_time_;
263 last_click_position_ = last_touch_position_;
264 }
265 Reset();
266 return gesture_added;
267 }
268
269 bool GestureSequence::InClickOrScroll(const TouchEvent& event,
270 Gestures* gestures) {
271 if (IsInClickTimeWindow() && IsInsideManhattanSquare(event)) {
272 SetState(GS_PENDING_SYNTHETIC_CLICK);
273 return false;
274 }
275 if (event.type() == ui::ET_TOUCH_MOVED && !IsInsideManhattanSquare(event)) {
276 AppendScrollGestureBegin(event, gestures);
277 AppendScrollGestureUpdate(event, gestures);
278 SetState(GS_SCROLL);
279 return true;
280 }
281 return false;
282 }
283
284 bool GestureSequence::InScroll(const TouchEvent& event, Gestures* gestures) {
285 AppendScrollGestureUpdate(event, gestures);
286 return true;
287 }
288
289 bool GestureSequence::NoGesture(const TouchEvent&, Gestures*) {
290 Reset();
291 return false;
292 }
293
294 bool GestureSequence::TouchDown(const TouchEvent& event, Gestures* gestures) {
295 AppendTapDownGestureEvent(event, gestures);
296 SetState(GS_PENDING_SYNTHETIC_CLICK);
297 return false;
298 }
299
300 bool GestureSequence::ScrollEnd(const TouchEvent& event, Gestures* gestures) {
301 if (IsOverMinFlickSpeed() && event.type() != ui::ET_TOUCH_CANCELLED)
302 AppendScrollGestureEnd(event, gestures, x_velocity_, y_velocity_);
303 else
304 AppendScrollGestureEnd(event, gestures, 0.f, 0.f);
305 SetState(GS_NO_GESTURE);
306 Reset();
307 return false;
308 }
309
310 //////////////////////////////////////////////////////////////////////////////// 35 ////////////////////////////////////////////////////////////////////////////////
311 // GestureRecognizerAura, public: 36 // GestureRecognizerAura, public:
312 37
313 GestureRecognizerAura::GestureRecognizerAura() 38 GestureRecognizerAura::GestureRecognizerAura()
314 : default_sequence_(new GestureSequence()) { 39 : default_sequence_(new GestureSequence()) {
315 } 40 }
316 41
317 GestureRecognizerAura::~GestureRecognizerAura() { 42 GestureRecognizerAura::~GestureRecognizerAura() {
318 } 43 }
319 44
45 ////////////////////////////////////////////////////////////////////////////////
46 // GestureRecognizerAura, private:
47
320 GestureSequence::Gestures* GestureRecognizerAura::ProcessTouchEventForGesture( 48 GestureSequence::Gestures* GestureRecognizerAura::ProcessTouchEventForGesture(
321 const TouchEvent& event, 49 const TouchEvent& event,
322 ui::TouchStatus status) { 50 ui::TouchStatus status) {
323 return default_sequence_->ProcessTouchEventForGesture(event, status); 51 return default_sequence_->ProcessTouchEventForGesture(event, status);
324 } 52 }
325 53
326 void GestureRecognizerAura::QueueTouchEventForGesture(Window* window, 54 void GestureRecognizerAura::QueueTouchEventForGesture(Window* window,
327 const TouchEvent& event) { 55 const TouchEvent& event) {
328 if (!event_queue_[window]) 56 if (!event_queue_[window])
329 event_queue_[window] = new std::queue<TouchEvent*>(); 57 event_queue_[window] = new std::queue<TouchEvent*>();
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
362 event_queue_.erase(window); 90 event_queue_.erase(window);
363 } 91 }
364 } 92 }
365 93
366 // GestureRecognizer, static 94 // GestureRecognizer, static
367 GestureRecognizer* GestureRecognizer::Create() { 95 GestureRecognizer* GestureRecognizer::Create() {
368 return new GestureRecognizerAura(); 96 return new GestureRecognizerAura();
369 } 97 }
370 98
371 } // namespace aura 99 } // namespace aura
OLDNEW
« no previous file with comments | « ui/aura/gestures/gesture_recognizer_aura.h ('k') | ui/aura/gestures/gesture_sequence.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698