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 float max_distance
=
95 GestureConfiguration::max_separation_for_gesture_touches_in_pixels();
97 gfx::PointF closest_point
;
98 int closest_touch_id
= 0;
99 double closest_distance_squared
= std::numeric_limits
<double>::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 double 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.
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();
141 if (i
->first
&& i
->first
!= new_consumer
&&
142 (i
->first
!= current_consumer
|| new_consumer
== NULL
)) {
143 consumers
.push_back(i
->first
);
146 for (std::vector
<GestureConsumer
*>::iterator iter
= consumers
.begin();
147 iter
!= consumers
.end();
149 CancelActiveTouches(*iter
);
151 // Transfer events from |current_consumer| to |new_consumer|.
152 if (current_consumer
&& new_consumer
) {
153 TransferTouchIdToConsumerMap(current_consumer
, new_consumer
,
155 TransferTouchIdToConsumerMap(current_consumer
, new_consumer
,
156 &touch_id_target_for_gestures_
);
158 current_consumer
, new_consumer
, &consumer_gesture_provider_
);
162 bool GestureRecognizerImpl::GetLastTouchPointForTarget(
163 GestureConsumer
* consumer
,
164 gfx::PointF
* point
) {
165 if (consumer_gesture_provider_
.count(consumer
) == 0)
167 const MotionEvent
& pointer_state
=
168 consumer_gesture_provider_
[consumer
]->pointer_state();
169 *point
= gfx::PointF(pointer_state
.GetX(), pointer_state
.GetY());
173 bool GestureRecognizerImpl::CancelActiveTouches(GestureConsumer
* consumer
) {
174 bool cancelled_touch
= false;
175 if (consumer_gesture_provider_
.count(consumer
) == 0)
177 const MotionEventAura
& pointer_state
=
178 consumer_gesture_provider_
[consumer
]->pointer_state();
179 if (pointer_state
.GetPointerCount() == 0)
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
,
188 ui::EF_IS_SYNTHESIZED
,
189 pointer_state_clone
->GetPointerId(i
),
190 ui::EventTimeForNow(),
195 GestureEventHelper
* helper
= FindDispatchHelperForConsumer(consumer
);
197 helper
->DispatchCancelTouchEvent(&touch_event
);
198 cancelled_touch
= true;
200 return cancelled_touch
;
203 ////////////////////////////////////////////////////////////////////////////////
204 // GestureRecognizerImpl, private:
206 GestureProviderAura
* 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
;
213 return gesture_provider
;
216 void 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
;
224 touch_id_target_for_gestures_
[event
.touch_id()] = target
;
228 void GestureRecognizerImpl::DispatchGestureEvent(GestureEvent
* event
) {
229 GestureConsumer
* consumer
= GetTargetForGestureEvent(*event
);
231 GestureEventHelper
* helper
= FindDispatchHelperForConsumer(consumer
);
233 helper
->DispatchGestureEvent(event
);
237 bool GestureRecognizerImpl::ProcessTouchEventPreDispatch(
238 const TouchEvent
& event
,
239 GestureConsumer
* consumer
) {
240 SetupTargets(event
, consumer
);
242 if (event
.result() & ER_CONSUMED
)
245 GestureProviderAura
* gesture_provider
=
246 GetGestureProviderForConsumer(consumer
);
247 return gesture_provider
->OnTouchEvent(event
);
250 GestureRecognizer::Gestures
*
251 GestureRecognizerImpl::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();
261 GestureRecognizer::Gestures
* GestureRecognizerImpl::ProcessTouchEventOnAsyncAck(
262 const TouchEvent
& event
,
263 ui::EventResult result
,
264 GestureConsumer
* consumer
) {
265 if (result
& ui::ER_CONSUMED
)
267 GestureProviderAura
* gesture_provider
=
268 GetGestureProviderForConsumer(consumer
);
269 gesture_provider
->OnTouchEventAck(result
!= ER_UNHANDLED
);
270 return gesture_provider
->GetAndResetPendingGestures();
273 bool GestureRecognizerImpl::CleanupStateForConsumer(
274 GestureConsumer
* consumer
) {
275 bool state_cleaned_up
= false;
277 if (consumer_gesture_provider_
.count(consumer
)) {
278 state_cleaned_up
= true;
279 delete consumer_gesture_provider_
[consumer
];
280 consumer_gesture_provider_
.erase(consumer
);
283 state_cleaned_up
|= RemoveConsumerFromMap(consumer
, &touch_id_target_
);
285 RemoveConsumerFromMap(consumer
, &touch_id_target_for_gestures_
);
286 return state_cleaned_up
;
289 void GestureRecognizerImpl::AddGestureEventHelper(GestureEventHelper
* helper
) {
290 helpers_
.push_back(helper
);
293 void GestureRecognizerImpl::RemoveGestureEventHelper(
294 GestureEventHelper
* helper
) {
295 std::vector
<GestureEventHelper
*>::iterator it
= std::find(helpers_
.begin(),
296 helpers_
.end(), helper
);
297 if (it
!= helpers_
.end())
301 void GestureRecognizerImpl::OnGestureEvent(GestureEvent
* event
) {
302 DispatchGestureEvent(event
);
305 GestureEventHelper
* 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
))
315 // GestureRecognizer, static
316 GestureRecognizer
* GestureRecognizer::Create() {
317 return new GestureRecognizerImpl();
320 static GestureRecognizerImpl
* g_gesture_recognizer_instance
= NULL
;
322 // GestureRecognizer, static
323 GestureRecognizer
* GestureRecognizer::Get() {
324 if (!g_gesture_recognizer_instance
)
325 g_gesture_recognizer_instance
= new GestureRecognizerImpl();
326 return g_gesture_recognizer_instance
;
329 // GestureRecognizer, static
330 void GestureRecognizer::Reset() {
331 delete g_gesture_recognizer_instance
;
332 g_gesture_recognizer_instance
= NULL
;
335 void 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
);
344 g_gesture_recognizer_instance
=
345 static_cast<GestureRecognizerImpl
*>(gesture_recognizer
);