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 // TODO(tdresser): we should take a unique_event_id here, and validate
255 // that the correct event is being acked. See crbug.com/457669 for
257 GestureRecognizer::Gestures
*
258 GestureRecognizerImpl::AckAsyncTouchEvent(
259 ui::EventResult result
,
260 GestureConsumer
* consumer
) {
261 GestureProviderAura
* gesture_provider
=
262 GetGestureProviderForConsumer(consumer
);
263 gesture_provider
->OnAsyncTouchEventAck(result
!= ER_UNHANDLED
);
264 return gesture_provider
->GetAndResetPendingGestures();
267 GestureRecognizer::Gestures
* GestureRecognizerImpl::AckSyncTouchEvent(
268 const uint64 unique_event_id
,
269 ui::EventResult result
,
270 GestureConsumer
* consumer
) {
271 GestureProviderAura
* gesture_provider
=
272 GetGestureProviderForConsumer(consumer
);
273 gesture_provider
->OnSyncTouchEventAck(unique_event_id
,
274 result
!= ER_UNHANDLED
);
275 return gesture_provider
->GetAndResetPendingGestures();
278 bool GestureRecognizerImpl::CleanupStateForConsumer(
279 GestureConsumer
* consumer
) {
280 bool state_cleaned_up
= false;
282 if (consumer_gesture_provider_
.count(consumer
)) {
283 state_cleaned_up
= true;
284 delete consumer_gesture_provider_
[consumer
];
285 consumer_gesture_provider_
.erase(consumer
);
288 state_cleaned_up
|= RemoveConsumerFromMap(consumer
, &touch_id_target_
);
290 RemoveConsumerFromMap(consumer
, &touch_id_target_for_gestures_
);
291 return state_cleaned_up
;
294 void GestureRecognizerImpl::AddGestureEventHelper(GestureEventHelper
* helper
) {
295 helpers_
.push_back(helper
);
298 void GestureRecognizerImpl::RemoveGestureEventHelper(
299 GestureEventHelper
* helper
) {
300 std::vector
<GestureEventHelper
*>::iterator it
= std::find(helpers_
.begin(),
301 helpers_
.end(), helper
);
302 if (it
!= helpers_
.end())
306 void GestureRecognizerImpl::OnGestureEvent(GestureEvent
* event
) {
307 DispatchGestureEvent(event
);
310 GestureEventHelper
* GestureRecognizerImpl::FindDispatchHelperForConsumer(
311 GestureConsumer
* consumer
) {
312 std::vector
<GestureEventHelper
*>::iterator it
;
313 for (it
= helpers_
.begin(); it
!= helpers_
.end(); ++it
) {
314 if ((*it
)->CanDispatchToConsumer(consumer
))
320 // GestureRecognizer, static
321 GestureRecognizer
* GestureRecognizer::Create() {
322 return new GestureRecognizerImpl();
325 static GestureRecognizerImpl
* g_gesture_recognizer_instance
= NULL
;
327 // GestureRecognizer, static
328 GestureRecognizer
* GestureRecognizer::Get() {
329 if (!g_gesture_recognizer_instance
)
330 g_gesture_recognizer_instance
= new GestureRecognizerImpl();
331 return g_gesture_recognizer_instance
;
334 // GestureRecognizer, static
335 void GestureRecognizer::Reset() {
336 delete g_gesture_recognizer_instance
;
337 g_gesture_recognizer_instance
= NULL
;
340 void SetGestureRecognizerForTesting(GestureRecognizer
* gesture_recognizer
) {
341 // Transfer helpers to the new GR.
342 std::vector
<GestureEventHelper
*>& helpers
=
343 g_gesture_recognizer_instance
->helpers();
344 std::vector
<GestureEventHelper
*>::iterator it
;
345 for (it
= helpers
.begin(); it
!= helpers
.end(); ++it
)
346 gesture_recognizer
->AddGestureEventHelper(*it
);
349 g_gesture_recognizer_instance
=
350 static_cast<GestureRecognizerImpl
*>(gesture_recognizer
);