base: Change DCHECK_IS_ON to a macro DCHECK_IS_ON().
[chromium-blink-merge.git] / ui / events / gestures / gesture_recognizer_impl.cc
blob7250bf220580e260c7ed74d4cd89377f578d7028
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/gesture_detection/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 int touch_id = event.details().oldest_touch_id();
87 if (!touch_id_target_for_gestures_.count(touch_id)) {
88 NOTREACHED() << "Touch ID does not map to a valid GestureConsumer.";
89 return nullptr;
92 return touch_id_target_for_gestures_.at(touch_id);
95 GestureConsumer* GestureRecognizerImpl::GetTargetForLocation(
96 const gfx::PointF& location, int source_device_id) {
97 const float max_distance =
98 GestureConfiguration::GetInstance()
99 ->max_separation_for_gesture_touches_in_pixels();
101 gfx::PointF closest_point;
102 int closest_touch_id = 0;
103 double closest_distance_squared = std::numeric_limits<double>::infinity();
105 std::map<GestureConsumer*, GestureProviderAura*>::iterator i;
106 for (i = consumer_gesture_provider_.begin();
107 i != consumer_gesture_provider_.end();
108 ++i) {
109 const MotionEventAura& pointer_state = i->second->pointer_state();
110 for (size_t j = 0; j < pointer_state.GetPointerCount(); ++j) {
111 if (source_device_id != pointer_state.GetSourceDeviceId(j))
112 continue;
113 gfx::PointF point(pointer_state.GetX(j), pointer_state.GetY(j));
114 // Relative distance is all we need here, so LengthSquared() is
115 // appropriate, and cheaper than Length().
116 double distance_squared = (point - location).LengthSquared();
117 if (distance_squared < closest_distance_squared) {
118 closest_point = point;
119 closest_touch_id = pointer_state.GetPointerId(j);
120 closest_distance_squared = distance_squared;
125 if (closest_distance_squared < max_distance * max_distance)
126 return touch_id_target_[closest_touch_id];
127 return NULL;
130 void GestureRecognizerImpl::TransferEventsTo(GestureConsumer* current_consumer,
131 GestureConsumer* new_consumer) {
132 // Send cancel to all those save |new_consumer| and |current_consumer|.
133 // Don't send a cancel to |current_consumer|, unless |new_consumer| is NULL.
134 // Dispatching a touch-cancel event can end up altering |touch_id_target_|
135 // (e.g. when the target of the event is destroyed, causing it to be removed
136 // from |touch_id_target_| in |CleanupStateForConsumer()|). So create a list
137 // of the touch-ids that need to be cancelled, and dispatch the cancel events
138 // for them at the end.
140 std::vector<GestureConsumer*> consumers;
141 std::map<GestureConsumer*, GestureProviderAura*>::iterator i;
142 for (i = consumer_gesture_provider_.begin();
143 i != consumer_gesture_provider_.end();
144 ++i) {
145 if (i->first && i->first != new_consumer &&
146 (i->first != current_consumer || new_consumer == NULL)) {
147 consumers.push_back(i->first);
150 for (std::vector<GestureConsumer*>::iterator iter = consumers.begin();
151 iter != consumers.end();
152 ++iter) {
153 CancelActiveTouches(*iter);
155 // Transfer events from |current_consumer| to |new_consumer|.
156 if (current_consumer && new_consumer) {
157 TransferTouchIdToConsumerMap(current_consumer, new_consumer,
158 &touch_id_target_);
159 TransferTouchIdToConsumerMap(current_consumer, new_consumer,
160 &touch_id_target_for_gestures_);
161 TransferConsumer(
162 current_consumer, new_consumer, &consumer_gesture_provider_);
166 bool GestureRecognizerImpl::GetLastTouchPointForTarget(
167 GestureConsumer* consumer,
168 gfx::PointF* point) {
169 if (consumer_gesture_provider_.count(consumer) == 0)
170 return false;
171 const MotionEvent& pointer_state =
172 consumer_gesture_provider_[consumer]->pointer_state();
173 *point = gfx::PointF(pointer_state.GetX(), pointer_state.GetY());
174 return true;
177 bool GestureRecognizerImpl::CancelActiveTouches(GestureConsumer* consumer) {
178 bool cancelled_touch = false;
179 if (consumer_gesture_provider_.count(consumer) == 0)
180 return false;
181 const MotionEventAura& pointer_state =
182 consumer_gesture_provider_[consumer]->pointer_state();
183 if (pointer_state.GetPointerCount() == 0)
184 return false;
185 // Pointer_state is modified every time after DispatchCancelTouchEvent.
186 scoped_ptr<MotionEvent> pointer_state_clone = pointer_state.Clone();
187 for (size_t i = 0; i < pointer_state_clone->GetPointerCount(); ++i) {
188 gfx::PointF point(pointer_state_clone->GetX(i),
189 pointer_state_clone->GetY(i));
190 TouchEvent touch_event(ui::ET_TOUCH_CANCELLED,
191 point,
192 ui::EF_IS_SYNTHESIZED,
193 pointer_state_clone->GetPointerId(i),
194 ui::EventTimeForNow(),
195 0.0f,
196 0.0f,
197 0.0f,
198 0.0f);
199 GestureEventHelper* helper = FindDispatchHelperForConsumer(consumer);
200 if (helper)
201 helper->DispatchCancelTouchEvent(&touch_event);
202 cancelled_touch = true;
204 return cancelled_touch;
207 ////////////////////////////////////////////////////////////////////////////////
208 // GestureRecognizerImpl, private:
210 GestureProviderAura* GestureRecognizerImpl::GetGestureProviderForConsumer(
211 GestureConsumer* consumer) {
212 GestureProviderAura* gesture_provider = consumer_gesture_provider_[consumer];
213 if (!gesture_provider) {
214 gesture_provider = CreateGestureProvider(this);
215 consumer_gesture_provider_[consumer] = gesture_provider;
217 return gesture_provider;
220 void GestureRecognizerImpl::SetupTargets(const TouchEvent& event,
221 GestureConsumer* target) {
222 if (event.type() == ui::ET_TOUCH_RELEASED ||
223 event.type() == ui::ET_TOUCH_CANCELLED) {
224 touch_id_target_.erase(event.touch_id());
225 } else if (event.type() == ui::ET_TOUCH_PRESSED) {
226 touch_id_target_[event.touch_id()] = target;
227 if (target)
228 touch_id_target_for_gestures_[event.touch_id()] = target;
232 void GestureRecognizerImpl::DispatchGestureEvent(GestureEvent* event) {
233 GestureConsumer* consumer = GetTargetForGestureEvent(*event);
234 if (consumer) {
235 GestureEventHelper* helper = FindDispatchHelperForConsumer(consumer);
236 if (helper)
237 helper->DispatchGestureEvent(event);
241 bool GestureRecognizerImpl::ProcessTouchEventPreDispatch(
242 TouchEvent* event,
243 GestureConsumer* consumer) {
244 SetupTargets(*event, consumer);
246 if (event->result() & ER_CONSUMED)
247 return false;
249 GestureProviderAura* gesture_provider =
250 GetGestureProviderForConsumer(consumer);
251 return gesture_provider->OnTouchEvent(event);
254 GestureRecognizer::Gestures*
255 GestureRecognizerImpl::AckAsyncTouchEvent(
256 const TouchEvent& event,
257 ui::EventResult result,
258 GestureConsumer* consumer) {
259 GestureProviderAura* gesture_provider =
260 GetGestureProviderForConsumer(consumer);
261 gesture_provider->OnAsyncTouchEventAck(result != ER_UNHANDLED);
262 return gesture_provider->GetAndResetPendingGestures();
265 GestureRecognizer::Gestures* GestureRecognizerImpl::AckSyncTouchEvent(
266 const uint64 unique_event_id,
267 ui::EventResult result,
268 GestureConsumer* consumer) {
269 GestureProviderAura* gesture_provider =
270 GetGestureProviderForConsumer(consumer);
271 gesture_provider->OnSyncTouchEventAck(unique_event_id,
272 result != ER_UNHANDLED);
273 return gesture_provider->GetAndResetPendingGestures();
276 bool GestureRecognizerImpl::CleanupStateForConsumer(
277 GestureConsumer* consumer) {
278 bool state_cleaned_up = false;
280 if (consumer_gesture_provider_.count(consumer)) {
281 state_cleaned_up = true;
282 delete consumer_gesture_provider_[consumer];
283 consumer_gesture_provider_.erase(consumer);
286 state_cleaned_up |= RemoveConsumerFromMap(consumer, &touch_id_target_);
287 state_cleaned_up |=
288 RemoveConsumerFromMap(consumer, &touch_id_target_for_gestures_);
289 return state_cleaned_up;
292 void GestureRecognizerImpl::AddGestureEventHelper(GestureEventHelper* helper) {
293 helpers_.push_back(helper);
296 void GestureRecognizerImpl::RemoveGestureEventHelper(
297 GestureEventHelper* helper) {
298 std::vector<GestureEventHelper*>::iterator it = std::find(helpers_.begin(),
299 helpers_.end(), helper);
300 if (it != helpers_.end())
301 helpers_.erase(it);
304 void GestureRecognizerImpl::OnGestureEvent(GestureEvent* event) {
305 DispatchGestureEvent(event);
308 GestureEventHelper* GestureRecognizerImpl::FindDispatchHelperForConsumer(
309 GestureConsumer* consumer) {
310 std::vector<GestureEventHelper*>::iterator it;
311 for (it = helpers_.begin(); it != helpers_.end(); ++it) {
312 if ((*it)->CanDispatchToConsumer(consumer))
313 return (*it);
315 return NULL;
318 // GestureRecognizer, static
319 GestureRecognizer* GestureRecognizer::Create() {
320 return new GestureRecognizerImpl();
323 static GestureRecognizerImpl* g_gesture_recognizer_instance = NULL;
325 // GestureRecognizer, static
326 GestureRecognizer* GestureRecognizer::Get() {
327 if (!g_gesture_recognizer_instance)
328 g_gesture_recognizer_instance = new GestureRecognizerImpl();
329 return g_gesture_recognizer_instance;
332 // GestureRecognizer, static
333 void GestureRecognizer::Reset() {
334 delete g_gesture_recognizer_instance;
335 g_gesture_recognizer_instance = NULL;
338 void SetGestureRecognizerForTesting(GestureRecognizer* gesture_recognizer) {
339 // Transfer helpers to the new GR.
340 std::vector<GestureEventHelper*>& helpers =
341 g_gesture_recognizer_instance->helpers();
342 std::vector<GestureEventHelper*>::iterator it;
343 for (it = helpers.begin(); it != helpers.end(); ++it)
344 gesture_recognizer->AddGestureEventHelper(*it);
346 helpers.clear();
347 g_gesture_recognizer_instance =
348 static_cast<GestureRecognizerImpl*>(gesture_recognizer);
351 } // namespace ui