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"
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"
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();
40 if (i
->second
== consumer
) {
42 consumer_removed
= true;
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
);
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 GestureConsumer
* target
= NULL
;
87 int touch_id
= event
.details().oldest_touch_id();
88 target
= touch_id_target_for_gestures_
[touch_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();
97 gfx::PointF closest_point
;
99 float closest_distance_squared
= std::numeric_limits
<float>::infinity();
101 std::map
<GestureConsumer
*, GestureProviderAura
*>::iterator i
;
102 for (i
= consumer_gesture_provider_
.begin();
103 i
!= consumer_gesture_provider_
.end();
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
))
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
;
121 if (closest_distance_squared
< max_distance
* max_distance
)
122 return touch_id_target_
[closest_touch_id
];
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 std::vector
<std::pair
<int, GestureConsumer
*> > ids
;
136 for (TouchIdToConsumerMap::iterator i
= touch_id_target_
.begin();
137 i
!= touch_id_target_
.end(); ++i
) {
138 if (i
->second
&& i
->second
!= new_consumer
&&
139 (i
->second
!= current_consumer
|| new_consumer
== NULL
) &&
141 ids
.push_back(std::make_pair(i
->first
, i
->second
));
147 // Transfer events from |current_consumer| to |new_consumer|.
148 if (current_consumer
&& new_consumer
) {
149 TransferTouchIdToConsumerMap(current_consumer
, new_consumer
,
151 TransferTouchIdToConsumerMap(current_consumer
, new_consumer
,
152 &touch_id_target_for_gestures_
);
154 current_consumer
, new_consumer
, &consumer_gesture_provider_
);
158 bool GestureRecognizerImpl::GetLastTouchPointForTarget(
159 GestureConsumer
* consumer
,
160 gfx::PointF
* point
) {
161 if (consumer_gesture_provider_
.count(consumer
) == 0)
163 const MotionEvent
& pointer_state
=
164 consumer_gesture_provider_
[consumer
]->pointer_state();
165 *point
= gfx::PointF(pointer_state
.GetX(), pointer_state
.GetY());
169 bool GestureRecognizerImpl::CancelActiveTouches(GestureConsumer
* consumer
) {
170 std::vector
<std::pair
<int, GestureConsumer
*> > ids
;
171 for (TouchIdToConsumerMap::const_iterator i
= touch_id_target_
.begin();
172 i
!= touch_id_target_
.end(); ++i
) {
173 if (i
->second
== consumer
)
174 ids
.push_back(std::make_pair(i
->first
, i
->second
));
176 bool cancelled_touch
= !ids
.empty();
178 return cancelled_touch
;
181 ////////////////////////////////////////////////////////////////////////////////
182 // GestureRecognizerImpl, private:
184 GestureProviderAura
* GestureRecognizerImpl::GetGestureProviderForConsumer(
185 GestureConsumer
* consumer
) {
186 GestureProviderAura
* gesture_provider
= consumer_gesture_provider_
[consumer
];
187 if (!gesture_provider
) {
188 gesture_provider
= CreateGestureProvider(this);
189 consumer_gesture_provider_
[consumer
] = gesture_provider
;
191 return gesture_provider
;
194 void GestureRecognizerImpl::SetupTargets(const TouchEvent
& event
,
195 GestureConsumer
* target
) {
196 if (event
.type() == ui::ET_TOUCH_RELEASED
||
197 event
.type() == ui::ET_TOUCH_CANCELLED
) {
198 touch_id_target_
.erase(event
.touch_id());
199 } else if (event
.type() == ui::ET_TOUCH_PRESSED
) {
200 touch_id_target_
[event
.touch_id()] = target
;
202 touch_id_target_for_gestures_
[event
.touch_id()] = target
;
206 void GestureRecognizerImpl::CancelTouches(
207 std::vector
<std::pair
<int, GestureConsumer
*> >* touches
) {
208 while (!touches
->empty()) {
209 int touch_id
= touches
->begin()->first
;
210 GestureConsumer
* target
= touches
->begin()->second
;
211 TouchEvent
touch_event(ui::ET_TOUCH_CANCELLED
, gfx::PointF(0, 0),
212 ui::EF_IS_SYNTHESIZED
, touch_id
,
213 ui::EventTimeForNow(), 0.0f
, 0.0f
, 0.0f
, 0.0f
);
214 GestureEventHelper
* helper
= FindDispatchHelperForConsumer(target
);
216 helper
->DispatchCancelTouchEvent(&touch_event
);
217 touches
->erase(touches
->begin());
221 void GestureRecognizerImpl::DispatchGestureEvent(GestureEvent
* event
) {
222 GestureConsumer
* consumer
= GetTargetForGestureEvent(*event
);
224 GestureEventHelper
* helper
= FindDispatchHelperForConsumer(consumer
);
226 helper
->DispatchGestureEvent(event
);
230 bool GestureRecognizerImpl::ProcessTouchEventPreDispatch(
231 const TouchEvent
& event
,
232 GestureConsumer
* consumer
) {
233 SetupTargets(event
, consumer
);
235 if (event
.result() & ER_CONSUMED
)
238 GestureProviderAura
* gesture_provider
=
239 GetGestureProviderForConsumer(consumer
);
240 return gesture_provider
->OnTouchEvent(event
);
243 GestureRecognizer::Gestures
*
244 GestureRecognizerImpl::ProcessTouchEventPostDispatch(
245 const TouchEvent
& event
,
246 ui::EventResult result
,
247 GestureConsumer
* consumer
) {
248 GestureProviderAura
* gesture_provider
=
249 GetGestureProviderForConsumer(consumer
);
250 gesture_provider
->OnTouchEventAck(result
!= ER_UNHANDLED
);
251 return gesture_provider
->GetAndResetPendingGestures();
254 GestureRecognizer::Gestures
* GestureRecognizerImpl::ProcessTouchEventOnAsyncAck(
255 const TouchEvent
& event
,
256 ui::EventResult result
,
257 GestureConsumer
* consumer
) {
258 if (result
& ui::ER_CONSUMED
)
260 GestureProviderAura
* gesture_provider
=
261 GetGestureProviderForConsumer(consumer
);
262 gesture_provider
->OnTouchEventAck(result
!= ER_UNHANDLED
);
263 return gesture_provider
->GetAndResetPendingGestures();
266 bool GestureRecognizerImpl::CleanupStateForConsumer(
267 GestureConsumer
* consumer
) {
268 bool state_cleaned_up
= false;
270 if (consumer_gesture_provider_
.count(consumer
)) {
271 state_cleaned_up
= true;
272 delete consumer_gesture_provider_
[consumer
];
273 consumer_gesture_provider_
.erase(consumer
);
276 state_cleaned_up
|= RemoveConsumerFromMap(consumer
, &touch_id_target_
);
278 RemoveConsumerFromMap(consumer
, &touch_id_target_for_gestures_
);
279 return state_cleaned_up
;
282 void GestureRecognizerImpl::AddGestureEventHelper(GestureEventHelper
* helper
) {
283 helpers_
.push_back(helper
);
286 void GestureRecognizerImpl::RemoveGestureEventHelper(
287 GestureEventHelper
* helper
) {
288 std::vector
<GestureEventHelper
*>::iterator it
= std::find(helpers_
.begin(),
289 helpers_
.end(), helper
);
290 if (it
!= helpers_
.end())
294 void GestureRecognizerImpl::OnGestureEvent(GestureEvent
* event
) {
295 DispatchGestureEvent(event
);
298 GestureEventHelper
* GestureRecognizerImpl::FindDispatchHelperForConsumer(
299 GestureConsumer
* consumer
) {
300 std::vector
<GestureEventHelper
*>::iterator it
;
301 for (it
= helpers_
.begin(); it
!= helpers_
.end(); ++it
) {
302 if ((*it
)->CanDispatchToConsumer(consumer
))
308 // GestureRecognizer, static
309 GestureRecognizer
* GestureRecognizer::Create() {
310 return new GestureRecognizerImpl();
313 static GestureRecognizerImpl
* g_gesture_recognizer_instance
= NULL
;
315 // GestureRecognizer, static
316 GestureRecognizer
* GestureRecognizer::Get() {
317 if (!g_gesture_recognizer_instance
)
318 g_gesture_recognizer_instance
= new GestureRecognizerImpl();
319 return g_gesture_recognizer_instance
;
322 // GestureRecognizer, static
323 void GestureRecognizer::Reset() {
324 delete g_gesture_recognizer_instance
;
325 g_gesture_recognizer_instance
= NULL
;
328 void SetGestureRecognizerForTesting(GestureRecognizer
* gesture_recognizer
) {
329 // Transfer helpers to the new GR.
330 std::vector
<GestureEventHelper
*>& helpers
=
331 g_gesture_recognizer_instance
->helpers();
332 std::vector
<GestureEventHelper
*>::iterator it
;
333 for (it
= helpers
.begin(); it
!= helpers
.end(); ++it
)
334 gesture_recognizer
->AddGestureEventHelper(*it
);
337 g_gesture_recognizer_instance
=
338 static_cast<GestureRecognizerImpl
*>(gesture_recognizer
);