• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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