Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / ui / events / gestures / gesture_recognizer_impl.cc
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_sequence.h"
20 #include "ui/events/gestures/gesture_types.h"
21
22 namespace ui {
23
24 namespace {
25
26 template <typename T>
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);
33   }
34 }
35
36 bool RemoveConsumerFromMap(GestureConsumer* consumer,
37                            GestureRecognizerImpl::TouchIdToConsumerMap* map) {
38   bool consumer_removed = false;
39   for (GestureRecognizerImpl::TouchIdToConsumerMap::iterator i = map->begin();
40        i != map->end();) {
41     if (i->second == consumer) {
42       map->erase(i++);
43       consumer_removed = true;
44     } else {
45       ++i;
46     }
47   }
48   return consumer_removed;
49 }
50
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;
59   }
60 }
61
62 GestureProviderAura* CreateGestureProvider(GestureProviderAuraClient* client) {
63   return new GestureProviderAura(client);
64 }
65
66 }  // namespace
67
68 ////////////////////////////////////////////////////////////////////////////////
69 // GestureRecognizerImpl, public:
70
71 GestureRecognizerImpl::GestureRecognizerImpl()
72     : use_unified_gesture_detector_(CommandLine::ForCurrentProcess()->HasSwitch(
73           switches::kUseUnifiedGestureDetector)) {
74 }
75
76 GestureRecognizerImpl::~GestureRecognizerImpl() {
77   STLDeleteValues(&consumer_sequence_);
78   STLDeleteValues(&consumer_gesture_provider_);
79 }
80
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()];
86 }
87
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];
93   return target;
94 }
95
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();
100
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()) {
110           continue;
111         }
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;
119         }
120       }
121     }
122
123     if (closest_distance_squared < max_distance * max_distance && closest_point)
124       return touch_id_target_[closest_point->touch_id()];
125     else
126       return NULL;
127   } else {
128     gfx::PointF closest_point;
129     int closest_touch_id;
130     float closest_distance_squared = std::numeric_limits<float>::infinity();
131
132     std::map<GestureConsumer*, GestureProviderAura*>::iterator i;
133     for (i = consumer_gesture_provider_.begin();
134          i != consumer_gesture_provider_.end();
135          ++i) {
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))
139           continue;
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;
148         }
149       }
150     }
151
152     if (closest_distance_squared < max_distance * max_distance)
153       return touch_id_target_[closest_touch_id];
154     else
155       return NULL;
156   }
157 }
158
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) &&
173         i->second) {
174       ids.push_back(std::make_pair(i->first, i->second));
175     }
176   }
177
178   CancelTouches(&ids);
179
180   // Transfer events from |current_consumer| to |new_consumer|.
181   if (current_consumer && new_consumer) {
182     TransferTouchIdToConsumerMap(current_consumer, new_consumer,
183                                  &touch_id_target_);
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_);
188     else
189       TransferConsumer(
190           current_consumer, new_consumer, &consumer_gesture_provider_);
191   }
192 }
193
194 bool GestureRecognizerImpl::GetLastTouchPointForTarget(
195     GestureConsumer* consumer,
196     gfx::PointF* point) {
197   if (!use_unified_gesture_detector_) {
198     if (consumer_sequence_.count(consumer) == 0)
199       return false;
200     *point = consumer_sequence_[consumer]->last_touch_location();
201     return true;
202   } else {
203     if (consumer_gesture_provider_.count(consumer) == 0)
204       return false;
205     const MotionEvent& pointer_state =
206         consumer_gesture_provider_[consumer]->pointer_state();
207     *point = gfx::PointF(pointer_state.GetX(), pointer_state.GetY());
208     return true;
209   }
210 }
211
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));
218   }
219   bool cancelled_touch = !ids.empty();
220   CancelTouches(&ids);
221   return cancelled_touch;
222 }
223
224 ////////////////////////////////////////////////////////////////////////////////
225 // GestureRecognizerImpl, protected:
226
227 GestureSequence* GestureRecognizerImpl::CreateSequence(
228     GestureSequenceDelegate* delegate) {
229   return new GestureSequence(delegate);
230 }
231
232 ////////////////////////////////////////////////////////////////////////////////
233 // GestureRecognizerImpl, private:
234
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;
241   }
242   return gesture_sequence;
243 }
244
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;
251   }
252   return gesture_provider;
253 }
254
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;
262     if (target)
263       touch_id_target_for_gestures_[event.touch_id()] = target;
264   }
265 }
266
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);
276     if (helper)
277       helper->DispatchCancelTouchEvent(&touch_event);
278     touches->erase(touches->begin());
279   }
280 }
281
282 void GestureRecognizerImpl::DispatchGestureEvent(GestureEvent* event) {
283   GestureConsumer* consumer = GetTargetForGestureEvent(*event);
284   if (consumer) {
285     GestureEventHelper* helper = FindDispatchHelperForConsumer(consumer);
286     if (helper)
287       helper->DispatchGestureEvent(event);
288   }
289 }
290
291 GestureSequence::Gestures* GestureRecognizerImpl::ProcessTouchEventForGesture(
292     const TouchEvent& event,
293     ui::EventResult result,
294     GestureConsumer* target) {
295   SetupTargets(event, target);
296
297   if (!use_unified_gesture_detector_) {
298     GestureSequence* gesture_sequence = GetGestureSequenceForConsumer(target);
299     return gesture_sequence->ProcessTouchEventForGesture(event, result);
300   } else {
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);
307     }
308     return NULL;
309   }
310 }
311
312 bool GestureRecognizerImpl::CleanupStateForConsumer(
313     GestureConsumer* consumer) {
314   bool state_cleaned_up = false;
315
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);
321     }
322   } else {
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);
330     }
331   }
332
333   state_cleaned_up |= RemoveConsumerFromMap(consumer, &touch_id_target_);
334   state_cleaned_up |=
335       RemoveConsumerFromMap(consumer, &touch_id_target_for_gestures_);
336   return state_cleaned_up;
337 }
338
339 void GestureRecognizerImpl::AddGestureEventHelper(GestureEventHelper* helper) {
340   helpers_.push_back(helper);
341 }
342
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())
348     helpers_.erase(it);
349 }
350
351 void GestureRecognizerImpl::DispatchPostponedGestureEvent(GestureEvent* event) {
352   DispatchGestureEvent(event);
353 }
354
355 void GestureRecognizerImpl::OnGestureEvent(GestureEvent* event) {
356   DispatchGestureEvent(event);
357 }
358
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))
364       return (*it);
365   }
366   return NULL;
367 }
368
369 // GestureRecognizer, static
370 GestureRecognizer* GestureRecognizer::Create() {
371   return new GestureRecognizerImpl();
372 }
373
374 static GestureRecognizerImpl* g_gesture_recognizer_instance = NULL;
375
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;
381 }
382
383 // GestureRecognizer, static
384 void GestureRecognizer::Reset() {
385   delete g_gesture_recognizer_instance;
386   g_gesture_recognizer_instance = NULL;
387 }
388
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);
396
397   helpers.clear();
398   g_gesture_recognizer_instance =
399       static_cast<GestureRecognizerImpl*>(gesture_recognizer);
400 }
401
402 }  // namespace ui