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
21namespace ui {
22
23namespace {
24
25template <typename T>
26void 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
35bool 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
50void 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
61GestureProviderAura* CreateGestureProvider(GestureProviderAuraClient* client) {
62  return new GestureProviderAura(client);
63}
64
65}  // namespace
66
67////////////////////////////////////////////////////////////////////////////////
68// GestureRecognizerImpl, public:
69
70GestureRecognizerImpl::GestureRecognizerImpl() {
71}
72
73GestureRecognizerImpl::~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.
79GestureConsumer* GestureRecognizerImpl::GetTouchLockedTarget(
80    const TouchEvent& event) {
81  return touch_id_target_[event.touch_id()];
82}
83
84GestureConsumer* 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
92GestureConsumer* 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
126void 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
162bool 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
173bool 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
206GestureProviderAura* 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
216void 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
228void 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
237bool 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
250GestureRecognizer::Gestures*
251GestureRecognizerImpl::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
261GestureRecognizer::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
273bool 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
289void GestureRecognizerImpl::AddGestureEventHelper(GestureEventHelper* helper) {
290  helpers_.push_back(helper);
291}
292
293void 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
301void GestureRecognizerImpl::OnGestureEvent(GestureEvent* event) {
302  DispatchGestureEvent(event);
303}
304
305GestureEventHelper* 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
316GestureRecognizer* GestureRecognizer::Create() {
317  return new GestureRecognizerImpl();
318}
319
320static GestureRecognizerImpl* g_gesture_recognizer_instance = NULL;
321
322// GestureRecognizer, static
323GestureRecognizer* 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
330void GestureRecognizer::Reset() {
331  delete g_gesture_recognizer_instance;
332  g_gesture_recognizer_instance = NULL;
333}
334
335void 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