Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / ui / events / gestures / gesture_recognizer_impl.cc
blobc4033dd8e57fb559c2222dd040166ae57b46c7f6
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"
7 #include <limits>
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_types.h"
21 namespace ui {
23 namespace {
25 template <typename T>
26 void TransferConsumer(GestureConsumer* current_consumer,
27 GestureConsumer* new_consumer,
28 std::map<GestureConsumer*, T>* map) {
29 if (map->count(current_consumer)) {
30 (*map)[new_consumer] = (*map)[current_consumer];
31 map->erase(current_consumer);
35 bool RemoveConsumerFromMap(GestureConsumer* consumer,
36 GestureRecognizerImpl::TouchIdToConsumerMap* map) {
37 bool consumer_removed = false;
38 for (GestureRecognizerImpl::TouchIdToConsumerMap::iterator i = map->begin();
39 i != map->end();) {
40 if (i->second == consumer) {
41 map->erase(i++);
42 consumer_removed = true;
43 } else {
44 ++i;
47 return consumer_removed;
50 void TransferTouchIdToConsumerMap(
51 GestureConsumer* old_consumer,
52 GestureConsumer* new_consumer,
53 GestureRecognizerImpl::TouchIdToConsumerMap* map) {
54 for (GestureRecognizerImpl::TouchIdToConsumerMap::iterator i = map->begin();
55 i != map->end(); ++i) {
56 if (i->second == old_consumer)
57 i->second = new_consumer;
61 GestureProviderAura* CreateGestureProvider(GestureProviderAuraClient* client) {
62 return new GestureProviderAura(client);
65 } // namespace
67 ////////////////////////////////////////////////////////////////////////////////
68 // GestureRecognizerImpl, public:
70 GestureRecognizerImpl::GestureRecognizerImpl() {
73 GestureRecognizerImpl::~GestureRecognizerImpl() {
74 STLDeleteValues(&consumer_gesture_provider_);
77 // Checks if this finger is already down, if so, returns the current target.
78 // Otherwise, returns NULL.
79 GestureConsumer* GestureRecognizerImpl::GetTouchLockedTarget(
80 const TouchEvent& event) {
81 return touch_id_target_[event.touch_id()];
84 GestureConsumer* GestureRecognizerImpl::GetTargetForGestureEvent(
85 const GestureEvent& event) {
86 GestureConsumer* target = NULL;
87 int touch_id = event.details().oldest_touch_id();
88 target = touch_id_target_for_gestures_[touch_id];
89 return target;
92 GestureConsumer* GestureRecognizerImpl::GetTargetForLocation(
93 const gfx::PointF& location, int source_device_id) {
94 const int max_distance =
95 GestureConfiguration::max_separation_for_gesture_touches_in_pixels();
97 gfx::PointF closest_point;
98 int closest_touch_id;
99 float closest_distance_squared = std::numeric_limits<float>::infinity();
101 std::map<GestureConsumer*, GestureProviderAura*>::iterator i;
102 for (i = consumer_gesture_provider_.begin();
103 i != consumer_gesture_provider_.end();
104 ++i) {
105 const MotionEventAura& pointer_state = i->second->pointer_state();
106 for (size_t j = 0; j < pointer_state.GetPointerCount(); ++j) {
107 if (source_device_id != pointer_state.GetSourceDeviceId(j))
108 continue;
109 gfx::PointF point(pointer_state.GetX(j), pointer_state.GetY(j));
110 // Relative distance is all we need here, so LengthSquared() is
111 // appropriate, and cheaper than Length().
112 float distance_squared = (point - location).LengthSquared();
113 if (distance_squared < closest_distance_squared) {
114 closest_point = point;
115 closest_touch_id = pointer_state.GetPointerId(j);
116 closest_distance_squared = distance_squared;
121 if (closest_distance_squared < max_distance * max_distance)
122 return touch_id_target_[closest_touch_id];
123 return NULL;
126 void GestureRecognizerImpl::TransferEventsTo(GestureConsumer* current_consumer,
127 GestureConsumer* new_consumer) {
128 // Send cancel to all those save |new_consumer| and |current_consumer|.
129 // Don't send a cancel to |current_consumer|, unless |new_consumer| is NULL.
130 // Dispatching a touch-cancel event can end up altering |touch_id_target_|
131 // (e.g. when the target of the event is destroyed, causing it to be removed
132 // from |touch_id_target_| in |CleanupStateForConsumer()|). So create a list
133 // of the touch-ids that need to be cancelled, and dispatch the cancel events
134 // for them at the end.
135 std::vector<std::pair<int, GestureConsumer*> > ids;
136 for (TouchIdToConsumerMap::iterator i = touch_id_target_.begin();
137 i != touch_id_target_.end(); ++i) {
138 if (i->second && i->second != new_consumer &&
139 (i->second != current_consumer || new_consumer == NULL) &&
140 i->second) {
141 ids.push_back(std::make_pair(i->first, i->second));
145 CancelTouches(&ids);
147 // Transfer events from |current_consumer| to |new_consumer|.
148 if (current_consumer && new_consumer) {
149 TransferTouchIdToConsumerMap(current_consumer, new_consumer,
150 &touch_id_target_);
151 TransferTouchIdToConsumerMap(current_consumer, new_consumer,
152 &touch_id_target_for_gestures_);
153 TransferConsumer(
154 current_consumer, new_consumer, &consumer_gesture_provider_);
158 bool GestureRecognizerImpl::GetLastTouchPointForTarget(
159 GestureConsumer* consumer,
160 gfx::PointF* point) {
161 if (consumer_gesture_provider_.count(consumer) == 0)
162 return false;
163 const MotionEvent& pointer_state =
164 consumer_gesture_provider_[consumer]->pointer_state();
165 *point = gfx::PointF(pointer_state.GetX(), pointer_state.GetY());
166 return true;
169 bool GestureRecognizerImpl::CancelActiveTouches(GestureConsumer* consumer) {
170 std::vector<std::pair<int, GestureConsumer*> > ids;
171 for (TouchIdToConsumerMap::const_iterator i = touch_id_target_.begin();
172 i != touch_id_target_.end(); ++i) {
173 if (i->second == consumer)
174 ids.push_back(std::make_pair(i->first, i->second));
176 bool cancelled_touch = !ids.empty();
177 CancelTouches(&ids);
178 return cancelled_touch;
181 ////////////////////////////////////////////////////////////////////////////////
182 // GestureRecognizerImpl, private:
184 GestureProviderAura* GestureRecognizerImpl::GetGestureProviderForConsumer(
185 GestureConsumer* consumer) {
186 GestureProviderAura* gesture_provider = consumer_gesture_provider_[consumer];
187 if (!gesture_provider) {
188 gesture_provider = CreateGestureProvider(this);
189 consumer_gesture_provider_[consumer] = gesture_provider;
191 return gesture_provider;
194 void GestureRecognizerImpl::SetupTargets(const TouchEvent& event,
195 GestureConsumer* target) {
196 if (event.type() == ui::ET_TOUCH_RELEASED ||
197 event.type() == ui::ET_TOUCH_CANCELLED) {
198 touch_id_target_.erase(event.touch_id());
199 } else if (event.type() == ui::ET_TOUCH_PRESSED) {
200 touch_id_target_[event.touch_id()] = target;
201 if (target)
202 touch_id_target_for_gestures_[event.touch_id()] = target;
206 void GestureRecognizerImpl::CancelTouches(
207 std::vector<std::pair<int, GestureConsumer*> >* touches) {
208 while (!touches->empty()) {
209 int touch_id = touches->begin()->first;
210 GestureConsumer* target = touches->begin()->second;
211 TouchEvent touch_event(ui::ET_TOUCH_CANCELLED, gfx::PointF(0, 0),
212 ui::EF_IS_SYNTHESIZED, touch_id,
213 ui::EventTimeForNow(), 0.0f, 0.0f, 0.0f, 0.0f);
214 GestureEventHelper* helper = FindDispatchHelperForConsumer(target);
215 if (helper)
216 helper->DispatchCancelTouchEvent(&touch_event);
217 touches->erase(touches->begin());
221 void GestureRecognizerImpl::DispatchGestureEvent(GestureEvent* event) {
222 GestureConsumer* consumer = GetTargetForGestureEvent(*event);
223 if (consumer) {
224 GestureEventHelper* helper = FindDispatchHelperForConsumer(consumer);
225 if (helper)
226 helper->DispatchGestureEvent(event);
230 bool GestureRecognizerImpl::ProcessTouchEventPreDispatch(
231 const TouchEvent& event,
232 GestureConsumer* consumer) {
233 SetupTargets(event, consumer);
235 if (event.result() & ER_CONSUMED)
236 return false;
238 GestureProviderAura* gesture_provider =
239 GetGestureProviderForConsumer(consumer);
240 return gesture_provider->OnTouchEvent(event);
243 GestureRecognizer::Gestures*
244 GestureRecognizerImpl::ProcessTouchEventPostDispatch(
245 const TouchEvent& event,
246 ui::EventResult result,
247 GestureConsumer* consumer) {
248 GestureProviderAura* gesture_provider =
249 GetGestureProviderForConsumer(consumer);
250 gesture_provider->OnTouchEventAck(result != ER_UNHANDLED);
251 return gesture_provider->GetAndResetPendingGestures();
254 GestureRecognizer::Gestures* GestureRecognizerImpl::ProcessTouchEventOnAsyncAck(
255 const TouchEvent& event,
256 ui::EventResult result,
257 GestureConsumer* consumer) {
258 if (result & ui::ER_CONSUMED)
259 return NULL;
260 GestureProviderAura* gesture_provider =
261 GetGestureProviderForConsumer(consumer);
262 gesture_provider->OnTouchEventAck(result != ER_UNHANDLED);
263 return gesture_provider->GetAndResetPendingGestures();
266 bool GestureRecognizerImpl::CleanupStateForConsumer(
267 GestureConsumer* consumer) {
268 bool state_cleaned_up = false;
270 if (consumer_gesture_provider_.count(consumer)) {
271 state_cleaned_up = true;
272 delete consumer_gesture_provider_[consumer];
273 consumer_gesture_provider_.erase(consumer);
276 state_cleaned_up |= RemoveConsumerFromMap(consumer, &touch_id_target_);
277 state_cleaned_up |=
278 RemoveConsumerFromMap(consumer, &touch_id_target_for_gestures_);
279 return state_cleaned_up;
282 void GestureRecognizerImpl::AddGestureEventHelper(GestureEventHelper* helper) {
283 helpers_.push_back(helper);
286 void GestureRecognizerImpl::RemoveGestureEventHelper(
287 GestureEventHelper* helper) {
288 std::vector<GestureEventHelper*>::iterator it = std::find(helpers_.begin(),
289 helpers_.end(), helper);
290 if (it != helpers_.end())
291 helpers_.erase(it);
294 void GestureRecognizerImpl::OnGestureEvent(GestureEvent* event) {
295 DispatchGestureEvent(event);
298 GestureEventHelper* GestureRecognizerImpl::FindDispatchHelperForConsumer(
299 GestureConsumer* consumer) {
300 std::vector<GestureEventHelper*>::iterator it;
301 for (it = helpers_.begin(); it != helpers_.end(); ++it) {
302 if ((*it)->CanDispatchToConsumer(consumer))
303 return (*it);
305 return NULL;
308 // GestureRecognizer, static
309 GestureRecognizer* GestureRecognizer::Create() {
310 return new GestureRecognizerImpl();
313 static GestureRecognizerImpl* g_gesture_recognizer_instance = NULL;
315 // GestureRecognizer, static
316 GestureRecognizer* GestureRecognizer::Get() {
317 if (!g_gesture_recognizer_instance)
318 g_gesture_recognizer_instance = new GestureRecognizerImpl();
319 return g_gesture_recognizer_instance;
322 // GestureRecognizer, static
323 void GestureRecognizer::Reset() {
324 delete g_gesture_recognizer_instance;
325 g_gesture_recognizer_instance = NULL;
328 void SetGestureRecognizerForTesting(GestureRecognizer* gesture_recognizer) {
329 // Transfer helpers to the new GR.
330 std::vector<GestureEventHelper*>& helpers =
331 g_gesture_recognizer_instance->helpers();
332 std::vector<GestureEventHelper*>::iterator it;
333 for (it = helpers.begin(); it != helpers.end(); ++it)
334 gesture_recognizer->AddGestureEventHelper(*it);
336 helpers.clear();
337 g_gesture_recognizer_instance =
338 static_cast<GestureRecognizerImpl*>(gesture_recognizer);
341 } // namespace ui