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.
4
5 #include "ui/events/gestures/gesture_recognizer_impl.h"
6
7 #include <limits>
8
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"
20
21 namespace ui {
22
23 namespace {
24
25 template <typename T>
TransferConsumer(GestureConsumer * current_consumer,GestureConsumer * new_consumer,std::map<GestureConsumer *,T> * map)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);
32 }
33 }
34
RemoveConsumerFromMap(GestureConsumer * consumer,GestureRecognizerImpl::TouchIdToConsumerMap * map)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;
45 }
46 }
47 return consumer_removed;
48 }
49
TransferTouchIdToConsumerMap(GestureConsumer * old_consumer,GestureConsumer * new_consumer,GestureRecognizerImpl::TouchIdToConsumerMap * map)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;
58 }
59 }
60
CreateGestureProvider(GestureProviderAuraClient * client)61 GestureProviderAura* CreateGestureProvider(GestureProviderAuraClient* client) {
62 return new GestureProviderAura(client);
63 }
64
65 } // namespace
66
67 ////////////////////////////////////////////////////////////////////////////////
68 // GestureRecognizerImpl, public:
69
GestureRecognizerImpl()70 GestureRecognizerImpl::GestureRecognizerImpl() {
71 }
72
~GestureRecognizerImpl()73 GestureRecognizerImpl::~GestureRecognizerImpl() {
74 STLDeleteValues(&consumer_gesture_provider_);
75 }
76
77 // Checks if this finger is already down, if so, returns the current target.
78 // Otherwise, returns NULL.
GetTouchLockedTarget(const TouchEvent & event)79 GestureConsumer* GestureRecognizerImpl::GetTouchLockedTarget(
80 const TouchEvent& event) {
81 return touch_id_target_[event.touch_id()];
82 }
83
GetTargetForGestureEvent(const GestureEvent & event)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;
90 }
91
GetTargetForLocation(const gfx::PointF & location,int source_device_id)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();
96
97 gfx::PointF closest_point;
98 int closest_touch_id;
99 float closest_distance_squared = std::numeric_limits<float>::infinity();
100
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;
117 }
118 }
119 }
120
121 if (closest_distance_squared < max_distance * max_distance)
122 return touch_id_target_[closest_touch_id];
123 return NULL;
124 }
125
TransferEventsTo(GestureConsumer * current_consumer,GestureConsumer * new_consumer)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
136 std::vector<GestureConsumer*> consumers;
137 std::map<GestureConsumer*, GestureProviderAura*>::iterator i;
138 for (i = consumer_gesture_provider_.begin();
139 i != consumer_gesture_provider_.end();
140 ++i) {
141 if (i->first && i->first != new_consumer &&
142 (i->first != current_consumer || new_consumer == NULL)) {
143 consumers.push_back(i->first);
144 }
145 }
146 for (std::vector<GestureConsumer*>::iterator iter = consumers.begin();
147 iter != consumers.end();
148 ++iter) {
149 CancelActiveTouches(*iter);
150 }
151 // Transfer events from |current_consumer| to |new_consumer|.
152 if (current_consumer && new_consumer) {
153 TransferTouchIdToConsumerMap(current_consumer, new_consumer,
154 &touch_id_target_);
155 TransferTouchIdToConsumerMap(current_consumer, new_consumer,
156 &touch_id_target_for_gestures_);
157 TransferConsumer(
158 current_consumer, new_consumer, &consumer_gesture_provider_);
159 }
160 }
161
GetLastTouchPointForTarget(GestureConsumer * consumer,gfx::PointF * point)162 bool GestureRecognizerImpl::GetLastTouchPointForTarget(
163 GestureConsumer* consumer,
164 gfx::PointF* point) {
165 if (consumer_gesture_provider_.count(consumer) == 0)
166 return false;
167 const MotionEvent& pointer_state =
168 consumer_gesture_provider_[consumer]->pointer_state();
169 *point = gfx::PointF(pointer_state.GetX(), pointer_state.GetY());
170 return true;
171 }
172
CancelActiveTouches(GestureConsumer * consumer)173 bool GestureRecognizerImpl::CancelActiveTouches(GestureConsumer* consumer) {
174 bool cancelled_touch = false;
175 if (consumer_gesture_provider_.count(consumer) == 0)
176 return false;
177 const MotionEventAura& pointer_state =
178 consumer_gesture_provider_[consumer]->pointer_state();
179 if (pointer_state.GetPointerCount() == 0)
180 return false;
181 // Pointer_state is modified every time after DispatchCancelTouchEvent.
182 scoped_ptr<MotionEvent> pointer_state_clone = pointer_state.Clone();
183 for (size_t i = 0; i < pointer_state_clone->GetPointerCount(); ++i) {
184 gfx::PointF point(pointer_state_clone->GetX(i),
185 pointer_state_clone->GetY(i));
186 TouchEvent touch_event(ui::ET_TOUCH_CANCELLED,
187 point,
188 ui::EF_IS_SYNTHESIZED,
189 pointer_state_clone->GetPointerId(i),
190 ui::EventTimeForNow(),
191 0.0f,
192 0.0f,
193 0.0f,
194 0.0f);
195 GestureEventHelper* helper = FindDispatchHelperForConsumer(consumer);
196 if (helper)
197 helper->DispatchCancelTouchEvent(&touch_event);
198 cancelled_touch = true;
199 }
200 return cancelled_touch;
201 }
202
203 ////////////////////////////////////////////////////////////////////////////////
204 // GestureRecognizerImpl, private:
205
GetGestureProviderForConsumer(GestureConsumer * consumer)206 GestureProviderAura* GestureRecognizerImpl::GetGestureProviderForConsumer(
207 GestureConsumer* consumer) {
208 GestureProviderAura* gesture_provider = consumer_gesture_provider_[consumer];
209 if (!gesture_provider) {
210 gesture_provider = CreateGestureProvider(this);
211 consumer_gesture_provider_[consumer] = gesture_provider;
212 }
213 return gesture_provider;
214 }
215
SetupTargets(const TouchEvent & event,GestureConsumer * target)216 void GestureRecognizerImpl::SetupTargets(const TouchEvent& event,
217 GestureConsumer* target) {
218 if (event.type() == ui::ET_TOUCH_RELEASED ||
219 event.type() == ui::ET_TOUCH_CANCELLED) {
220 touch_id_target_.erase(event.touch_id());
221 } else if (event.type() == ui::ET_TOUCH_PRESSED) {
222 touch_id_target_[event.touch_id()] = target;
223 if (target)
224 touch_id_target_for_gestures_[event.touch_id()] = target;
225 }
226 }
227
DispatchGestureEvent(GestureEvent * event)228 void GestureRecognizerImpl::DispatchGestureEvent(GestureEvent* event) {
229 GestureConsumer* consumer = GetTargetForGestureEvent(*event);
230 if (consumer) {
231 GestureEventHelper* helper = FindDispatchHelperForConsumer(consumer);
232 if (helper)
233 helper->DispatchGestureEvent(event);
234 }
235 }
236
ProcessTouchEventPreDispatch(const TouchEvent & event,GestureConsumer * consumer)237 bool GestureRecognizerImpl::ProcessTouchEventPreDispatch(
238 const TouchEvent& event,
239 GestureConsumer* consumer) {
240 SetupTargets(event, consumer);
241
242 if (event.result() & ER_CONSUMED)
243 return false;
244
245 GestureProviderAura* gesture_provider =
246 GetGestureProviderForConsumer(consumer);
247 return gesture_provider->OnTouchEvent(event);
248 }
249
250 GestureRecognizer::Gestures*
ProcessTouchEventPostDispatch(const TouchEvent & event,ui::EventResult result,GestureConsumer * consumer)251 GestureRecognizerImpl::ProcessTouchEventPostDispatch(
252 const TouchEvent& event,
253 ui::EventResult result,
254 GestureConsumer* consumer) {
255 GestureProviderAura* gesture_provider =
256 GetGestureProviderForConsumer(consumer);
257 gesture_provider->OnTouchEventAck(result != ER_UNHANDLED);
258 return gesture_provider->GetAndResetPendingGestures();
259 }
260
ProcessTouchEventOnAsyncAck(const TouchEvent & event,ui::EventResult result,GestureConsumer * consumer)261 GestureRecognizer::Gestures* GestureRecognizerImpl::ProcessTouchEventOnAsyncAck(
262 const TouchEvent& event,
263 ui::EventResult result,
264 GestureConsumer* consumer) {
265 if (result & ui::ER_CONSUMED)
266 return NULL;
267 GestureProviderAura* gesture_provider =
268 GetGestureProviderForConsumer(consumer);
269 gesture_provider->OnTouchEventAck(result != ER_UNHANDLED);
270 return gesture_provider->GetAndResetPendingGestures();
271 }
272
CleanupStateForConsumer(GestureConsumer * consumer)273 bool GestureRecognizerImpl::CleanupStateForConsumer(
274 GestureConsumer* consumer) {
275 bool state_cleaned_up = false;
276
277 if (consumer_gesture_provider_.count(consumer)) {
278 state_cleaned_up = true;
279 delete consumer_gesture_provider_[consumer];
280 consumer_gesture_provider_.erase(consumer);
281 }
282
283 state_cleaned_up |= RemoveConsumerFromMap(consumer, &touch_id_target_);
284 state_cleaned_up |=
285 RemoveConsumerFromMap(consumer, &touch_id_target_for_gestures_);
286 return state_cleaned_up;
287 }
288
AddGestureEventHelper(GestureEventHelper * helper)289 void GestureRecognizerImpl::AddGestureEventHelper(GestureEventHelper* helper) {
290 helpers_.push_back(helper);
291 }
292
RemoveGestureEventHelper(GestureEventHelper * helper)293 void GestureRecognizerImpl::RemoveGestureEventHelper(
294 GestureEventHelper* helper) {
295 std::vector<GestureEventHelper*>::iterator it = std::find(helpers_.begin(),
296 helpers_.end(), helper);
297 if (it != helpers_.end())
298 helpers_.erase(it);
299 }
300
OnGestureEvent(GestureEvent * event)301 void GestureRecognizerImpl::OnGestureEvent(GestureEvent* event) {
302 DispatchGestureEvent(event);
303 }
304
FindDispatchHelperForConsumer(GestureConsumer * consumer)305 GestureEventHelper* GestureRecognizerImpl::FindDispatchHelperForConsumer(
306 GestureConsumer* consumer) {
307 std::vector<GestureEventHelper*>::iterator it;
308 for (it = helpers_.begin(); it != helpers_.end(); ++it) {
309 if ((*it)->CanDispatchToConsumer(consumer))
310 return (*it);
311 }
312 return NULL;
313 }
314
315 // GestureRecognizer, static
Create()316 GestureRecognizer* GestureRecognizer::Create() {
317 return new GestureRecognizerImpl();
318 }
319
320 static GestureRecognizerImpl* g_gesture_recognizer_instance = NULL;
321
322 // GestureRecognizer, static
Get()323 GestureRecognizer* GestureRecognizer::Get() {
324 if (!g_gesture_recognizer_instance)
325 g_gesture_recognizer_instance = new GestureRecognizerImpl();
326 return g_gesture_recognizer_instance;
327 }
328
329 // GestureRecognizer, static
Reset()330 void GestureRecognizer::Reset() {
331 delete g_gesture_recognizer_instance;
332 g_gesture_recognizer_instance = NULL;
333 }
334
SetGestureRecognizerForTesting(GestureRecognizer * gesture_recognizer)335 void SetGestureRecognizerForTesting(GestureRecognizer* gesture_recognizer) {
336 // Transfer helpers to the new GR.
337 std::vector<GestureEventHelper*>& helpers =
338 g_gesture_recognizer_instance->helpers();
339 std::vector<GestureEventHelper*>::iterator it;
340 for (it = helpers.begin(); it != helpers.end(); ++it)
341 gesture_recognizer->AddGestureEventHelper(*it);
342
343 helpers.clear();
344 g_gesture_recognizer_instance =
345 static_cast<GestureRecognizerImpl*>(gesture_recognizer);
346 }
347
348 } // namespace ui
349