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_recognizer_impl.h"
9 #include "base/command_line.h"
10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/time/time.h"
14 #include "ui/events/event.h"
15 #include "ui/events/event_constants.h"
16 #include "ui/events/event_switches.h"
17 #include "ui/events/event_utils.h"
18 #include "ui/events/gestures/gesture_configuration.h"
19 #include "ui/events/gestures/gesture_sequence.h"
20 #include "ui/events/gestures/gesture_types.h"
27 void TransferConsumer(GestureConsumer* current_consumer,
28 GestureConsumer* new_consumer,
29 std::map<GestureConsumer*, T>* map) {
30 if (map->count(current_consumer)) {
31 (*map)[new_consumer] = (*map)[current_consumer];
32 map->erase(current_consumer);
36 bool RemoveConsumerFromMap(GestureConsumer* consumer,
37 GestureRecognizerImpl::TouchIdToConsumerMap* map) {
38 bool consumer_removed = false;
39 for (GestureRecognizerImpl::TouchIdToConsumerMap::iterator i = map->begin();
41 if (i->second == consumer) {
43 consumer_removed = true;
48 return consumer_removed;
51 void TransferTouchIdToConsumerMap(
52 GestureConsumer* old_consumer,
53 GestureConsumer* new_consumer,
54 GestureRecognizerImpl::TouchIdToConsumerMap* map) {
55 for (GestureRecognizerImpl::TouchIdToConsumerMap::iterator i = map->begin();
56 i != map->end(); ++i) {
57 if (i->second == old_consumer)
58 i->second = new_consumer;
62 GestureProviderAura* CreateGestureProvider(GestureProviderAuraClient* client) {
63 return new GestureProviderAura(client);
68 ////////////////////////////////////////////////////////////////////////////////
69 // GestureRecognizerImpl, public:
71 GestureRecognizerImpl::GestureRecognizerImpl()
72 : use_unified_gesture_detector_(CommandLine::ForCurrentProcess()->HasSwitch(
73 switches::kUseUnifiedGestureDetector)) {
76 GestureRecognizerImpl::~GestureRecognizerImpl() {
77 STLDeleteValues(&consumer_sequence_);
78 STLDeleteValues(&consumer_gesture_provider_);
81 // Checks if this finger is already down, if so, returns the current target.
82 // Otherwise, returns NULL.
83 GestureConsumer* GestureRecognizerImpl::GetTouchLockedTarget(
84 const TouchEvent& event) {
85 return touch_id_target_[event.touch_id()];
88 GestureConsumer* GestureRecognizerImpl::GetTargetForGestureEvent(
89 const GestureEvent& event) {
90 GestureConsumer* target = NULL;
91 int touch_id = event.GetLowestTouchId();
92 target = touch_id_target_for_gestures_[touch_id];
96 GestureConsumer* GestureRecognizerImpl::GetTargetForLocation(
97 const gfx::PointF& location, int source_device_id) {
98 const int max_distance =
99 GestureConfiguration::max_separation_for_gesture_touches_in_pixels();
101 if (!use_unified_gesture_detector_) {
102 const GesturePoint* closest_point = NULL;
103 int64 closest_distance_squared = 0;
104 std::map<GestureConsumer*, GestureSequence*>::iterator i;
105 for (i = consumer_sequence_.begin(); i != consumer_sequence_.end(); ++i) {
106 const GesturePoint* points = i->second->points();
107 for (int j = 0; j < GestureSequence::kMaxGesturePoints; ++j) {
108 if (!points[j].in_use() ||
109 source_device_id != points[j].source_device_id()) {
112 gfx::Vector2dF delta = points[j].last_touch_position() - location;
113 // Relative distance is all we need here, so LengthSquared() is
114 // appropriate, and cheaper than Length().
115 int64 distance_squared = delta.LengthSquared();
116 if (!closest_point || distance_squared < closest_distance_squared) {
117 closest_point = &points[j];
118 closest_distance_squared = distance_squared;
123 if (closest_distance_squared < max_distance * max_distance && closest_point)
124 return touch_id_target_[closest_point->touch_id()];
128 gfx::PointF closest_point;
129 int closest_touch_id;
130 float closest_distance_squared = std::numeric_limits<float>::infinity();
132 std::map<GestureConsumer*, GestureProviderAura*>::iterator i;
133 for (i = consumer_gesture_provider_.begin();
134 i != consumer_gesture_provider_.end();
136 const MotionEventAura& pointer_state = i->second->pointer_state();
137 for (size_t j = 0; j < pointer_state.GetPointerCount(); ++j) {
138 if (source_device_id != pointer_state.GetSourceDeviceId(j))
140 gfx::PointF point(pointer_state.GetX(j), pointer_state.GetY(j));
141 // Relative distance is all we need here, so LengthSquared() is
142 // appropriate, and cheaper than Length().
143 float distance_squared = (point - location).LengthSquared();
144 if (distance_squared < closest_distance_squared) {
145 closest_point = point;
146 closest_touch_id = pointer_state.GetPointerId(j);
147 closest_distance_squared = distance_squared;
152 if (closest_distance_squared < max_distance * max_distance)
153 return touch_id_target_[closest_touch_id];
159 void GestureRecognizerImpl::TransferEventsTo(GestureConsumer* current_consumer,
160 GestureConsumer* new_consumer) {
161 // Send cancel to all those save |new_consumer| and |current_consumer|.
162 // Don't send a cancel to |current_consumer|, unless |new_consumer| is NULL.
163 // Dispatching a touch-cancel event can end up altering |touch_id_target_|
164 // (e.g. when the target of the event is destroyed, causing it to be removed
165 // from |touch_id_target_| in |CleanupStateForConsumer()|). So create a list
166 // of the touch-ids that need to be cancelled, and dispatch the cancel events
167 // for them at the end.
168 std::vector<std::pair<int, GestureConsumer*> > ids;
169 for (TouchIdToConsumerMap::iterator i = touch_id_target_.begin();
170 i != touch_id_target_.end(); ++i) {
171 if (i->second && i->second != new_consumer &&
172 (i->second != current_consumer || new_consumer == NULL) &&
174 ids.push_back(std::make_pair(i->first, i->second));
180 // Transfer events from |current_consumer| to |new_consumer|.
181 if (current_consumer && new_consumer) {
182 TransferTouchIdToConsumerMap(current_consumer, new_consumer,
184 TransferTouchIdToConsumerMap(current_consumer, new_consumer,
185 &touch_id_target_for_gestures_);
186 if (!use_unified_gesture_detector_)
187 TransferConsumer(current_consumer, new_consumer, &consumer_sequence_);
190 current_consumer, new_consumer, &consumer_gesture_provider_);
194 bool GestureRecognizerImpl::GetLastTouchPointForTarget(
195 GestureConsumer* consumer,
196 gfx::PointF* point) {
197 if (!use_unified_gesture_detector_) {
198 if (consumer_sequence_.count(consumer) == 0)
200 *point = consumer_sequence_[consumer]->last_touch_location();
203 if (consumer_gesture_provider_.count(consumer) == 0)
205 const MotionEvent& pointer_state =
206 consumer_gesture_provider_[consumer]->pointer_state();
207 *point = gfx::PointF(pointer_state.GetX(), pointer_state.GetY());
212 bool GestureRecognizerImpl::CancelActiveTouches(GestureConsumer* consumer) {
213 std::vector<std::pair<int, GestureConsumer*> > ids;
214 for (TouchIdToConsumerMap::const_iterator i = touch_id_target_.begin();
215 i != touch_id_target_.end(); ++i) {
216 if (i->second == consumer)
217 ids.push_back(std::make_pair(i->first, i->second));
219 bool cancelled_touch = !ids.empty();
221 return cancelled_touch;
224 ////////////////////////////////////////////////////////////////////////////////
225 // GestureRecognizerImpl, protected:
227 GestureSequence* GestureRecognizerImpl::CreateSequence(
228 GestureSequenceDelegate* delegate) {
229 return new GestureSequence(delegate);
232 ////////////////////////////////////////////////////////////////////////////////
233 // GestureRecognizerImpl, private:
235 GestureSequence* GestureRecognizerImpl::GetGestureSequenceForConsumer(
236 GestureConsumer* consumer) {
237 GestureSequence* gesture_sequence = consumer_sequence_[consumer];
238 if (!gesture_sequence) {
239 gesture_sequence = CreateSequence(this);
240 consumer_sequence_[consumer] = gesture_sequence;
242 return gesture_sequence;
245 GestureProviderAura* GestureRecognizerImpl::GetGestureProviderForConsumer(
246 GestureConsumer* consumer) {
247 GestureProviderAura* gesture_provider = consumer_gesture_provider_[consumer];
248 if (!gesture_provider) {
249 gesture_provider = CreateGestureProvider(this);
250 consumer_gesture_provider_[consumer] = gesture_provider;
252 return gesture_provider;
255 void GestureRecognizerImpl::SetupTargets(const TouchEvent& event,
256 GestureConsumer* target) {
257 if (event.type() == ui::ET_TOUCH_RELEASED ||
258 event.type() == ui::ET_TOUCH_CANCELLED) {
259 touch_id_target_.erase(event.touch_id());
260 } else if (event.type() == ui::ET_TOUCH_PRESSED) {
261 touch_id_target_[event.touch_id()] = target;
263 touch_id_target_for_gestures_[event.touch_id()] = target;
267 void GestureRecognizerImpl::CancelTouches(
268 std::vector<std::pair<int, GestureConsumer*> >* touches) {
269 while (!touches->empty()) {
270 int touch_id = touches->begin()->first;
271 GestureConsumer* target = touches->begin()->second;
272 TouchEvent touch_event(ui::ET_TOUCH_CANCELLED, gfx::PointF(0, 0),
273 ui::EF_IS_SYNTHESIZED, touch_id,
274 ui::EventTimeForNow(), 0.0f, 0.0f, 0.0f, 0.0f);
275 GestureEventHelper* helper = FindDispatchHelperForConsumer(target);
277 helper->DispatchCancelTouchEvent(&touch_event);
278 touches->erase(touches->begin());
282 void GestureRecognizerImpl::DispatchGestureEvent(GestureEvent* event) {
283 GestureConsumer* consumer = GetTargetForGestureEvent(*event);
285 GestureEventHelper* helper = FindDispatchHelperForConsumer(consumer);
287 helper->DispatchGestureEvent(event);
291 GestureSequence::Gestures* GestureRecognizerImpl::ProcessTouchEventForGesture(
292 const TouchEvent& event,
293 ui::EventResult result,
294 GestureConsumer* target) {
295 SetupTargets(event, target);
297 if (!use_unified_gesture_detector_) {
298 GestureSequence* gesture_sequence = GetGestureSequenceForConsumer(target);
299 return gesture_sequence->ProcessTouchEventForGesture(event, result);
301 GestureProviderAura* gesture_provider =
302 GetGestureProviderForConsumer(target);
303 // TODO(tdresser) - detect gestures eagerly.
304 if (!(result & ER_CONSUMED)) {
305 if (gesture_provider->OnTouchEvent(event))
306 gesture_provider->OnTouchEventAck(result != ER_UNHANDLED);
312 bool GestureRecognizerImpl::CleanupStateForConsumer(
313 GestureConsumer* consumer) {
314 bool state_cleaned_up = false;
316 if (!use_unified_gesture_detector_) {
317 if (consumer_sequence_.count(consumer)) {
318 state_cleaned_up = true;
319 delete consumer_sequence_[consumer];
320 consumer_sequence_.erase(consumer);
323 if (consumer_gesture_provider_.count(consumer)) {
324 state_cleaned_up = true;
325 // Don't immediately delete the GestureProvider, as we could be in the
326 // middle of dispatching a set of gestures.
327 base::MessageLoop::current()->DeleteSoon(
328 FROM_HERE, consumer_gesture_provider_[consumer]);
329 consumer_gesture_provider_.erase(consumer);
333 state_cleaned_up |= RemoveConsumerFromMap(consumer, &touch_id_target_);
335 RemoveConsumerFromMap(consumer, &touch_id_target_for_gestures_);
336 return state_cleaned_up;
339 void GestureRecognizerImpl::AddGestureEventHelper(GestureEventHelper* helper) {
340 helpers_.push_back(helper);
343 void GestureRecognizerImpl::RemoveGestureEventHelper(
344 GestureEventHelper* helper) {
345 std::vector<GestureEventHelper*>::iterator it = std::find(helpers_.begin(),
346 helpers_.end(), helper);
347 if (it != helpers_.end())
351 void GestureRecognizerImpl::DispatchPostponedGestureEvent(GestureEvent* event) {
352 DispatchGestureEvent(event);
355 void GestureRecognizerImpl::OnGestureEvent(GestureEvent* event) {
356 DispatchGestureEvent(event);
359 GestureEventHelper* GestureRecognizerImpl::FindDispatchHelperForConsumer(
360 GestureConsumer* consumer) {
361 std::vector<GestureEventHelper*>::iterator it;
362 for (it = helpers_.begin(); it != helpers_.end(); ++it) {
363 if ((*it)->CanDispatchToConsumer(consumer))
369 // GestureRecognizer, static
370 GestureRecognizer* GestureRecognizer::Create() {
371 return new GestureRecognizerImpl();
374 static GestureRecognizerImpl* g_gesture_recognizer_instance = NULL;
376 // GestureRecognizer, static
377 GestureRecognizer* GestureRecognizer::Get() {
378 if (!g_gesture_recognizer_instance)
379 g_gesture_recognizer_instance = new GestureRecognizerImpl();
380 return g_gesture_recognizer_instance;
383 // GestureRecognizer, static
384 void GestureRecognizer::Reset() {
385 delete g_gesture_recognizer_instance;
386 g_gesture_recognizer_instance = NULL;
389 void SetGestureRecognizerForTesting(GestureRecognizer* gesture_recognizer) {
390 // Transfer helpers to the new GR.
391 std::vector<GestureEventHelper*>& helpers =
392 g_gesture_recognizer_instance->helpers();
393 std::vector<GestureEventHelper*>::iterator it;
394 for (it = helpers.begin(); it != helpers.end(); ++it)
395 gesture_recognizer->AddGestureEventHelper(*it);
398 g_gesture_recognizer_instance =
399 static_cast<GestureRecognizerImpl*>(gesture_recognizer);