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/gesture_detection/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 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.";
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();
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
))
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
];
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();
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();
153 CancelActiveTouches(*iter
);
155 // Transfer events from |current_consumer| to |new_consumer|.
156 if (current_consumer
&& new_consumer
) {
157 TransferTouchIdToConsumerMap(current_consumer
, new_consumer
,
159 TransferTouchIdToConsumerMap(current_consumer
, new_consumer
,
160 &touch_id_target_for_gestures_
);
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)
171 const MotionEvent
& pointer_state
=
172 consumer_gesture_provider_
[consumer
]->pointer_state();
173 *point
= gfx::PointF(pointer_state
.GetX(), pointer_state
.GetY());
177 bool GestureRecognizerImpl::CancelActiveTouches(GestureConsumer
* consumer
) {
178 bool cancelled_touch
= false;
179 if (consumer_gesture_provider_
.count(consumer
) == 0)
181 const MotionEventAura
& pointer_state
=
182 consumer_gesture_provider_
[consumer
]->pointer_state();
183 if (pointer_state
.GetPointerCount() == 0)
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
,
192 ui::EF_IS_SYNTHESIZED
,
193 pointer_state_clone
->GetPointerId(i
),
194 ui::EventTimeForNow(),
199 GestureEventHelper
* helper
= FindDispatchHelperForConsumer(consumer
);
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
;
228 touch_id_target_for_gestures_
[event
.touch_id()] = target
;
232 void GestureRecognizerImpl::DispatchGestureEvent(GestureEvent
* event
) {
233 GestureConsumer
* consumer
= GetTargetForGestureEvent(*event
);
235 GestureEventHelper
* helper
= FindDispatchHelperForConsumer(consumer
);
237 helper
->DispatchGestureEvent(event
);
241 bool GestureRecognizerImpl::ProcessTouchEventPreDispatch(
243 GestureConsumer
* consumer
) {
244 SetupTargets(*event
, consumer
);
246 if (event
->result() & ER_CONSUMED
)
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_
);
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())
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
))
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
);
347 g_gesture_recognizer_instance
=
348 static_cast<GestureRecognizerImpl
*>(gesture_recognizer
);