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
))
90 return touch_id_target_for_gestures_
.at(touch_id
);
93 GestureConsumer
* GestureRecognizerImpl::GetTargetForLocation(
94 const gfx::PointF
& location
, int source_device_id
) {
95 const float max_distance
=
96 GestureConfiguration::GetInstance()
97 ->max_separation_for_gesture_touches_in_pixels();
99 gfx::PointF closest_point
;
100 int closest_touch_id
= 0;
101 double closest_distance_squared
= std::numeric_limits
<double>::infinity();
103 std::map
<GestureConsumer
*, GestureProviderAura
*>::iterator i
;
104 for (i
= consumer_gesture_provider_
.begin();
105 i
!= consumer_gesture_provider_
.end();
107 const MotionEventAura
& pointer_state
= i
->second
->pointer_state();
108 for (size_t j
= 0; j
< pointer_state
.GetPointerCount(); ++j
) {
109 if (source_device_id
!= pointer_state
.GetSourceDeviceId(j
))
111 gfx::PointF
point(pointer_state
.GetX(j
), pointer_state
.GetY(j
));
112 // Relative distance is all we need here, so LengthSquared() is
113 // appropriate, and cheaper than Length().
114 double distance_squared
= (point
- location
).LengthSquared();
115 if (distance_squared
< closest_distance_squared
) {
116 closest_point
= point
;
117 closest_touch_id
= pointer_state
.GetPointerId(j
);
118 closest_distance_squared
= distance_squared
;
123 if (closest_distance_squared
< max_distance
* max_distance
)
124 return touch_id_target_
[closest_touch_id
];
128 void GestureRecognizerImpl::CancelActiveTouchesExcept(
129 GestureConsumer
* not_cancelled
) {
130 for (const auto& consumer_provider
: consumer_gesture_provider_
) {
131 if (consumer_provider
.first
== not_cancelled
)
133 CancelActiveTouches(consumer_provider
.first
);
137 void GestureRecognizerImpl::TransferEventsTo(GestureConsumer
* current_consumer
,
138 GestureConsumer
* new_consumer
) {
139 DCHECK(current_consumer
);
140 DCHECK(new_consumer
);
142 CancelActiveTouchesExcept(current_consumer
);
144 TransferTouchIdToConsumerMap(current_consumer
, new_consumer
,
146 TransferTouchIdToConsumerMap(current_consumer
, new_consumer
,
147 &touch_id_target_for_gestures_
);
148 TransferConsumer(current_consumer
, new_consumer
, &consumer_gesture_provider_
);
151 bool GestureRecognizerImpl::GetLastTouchPointForTarget(
152 GestureConsumer
* consumer
,
153 gfx::PointF
* point
) {
154 if (consumer_gesture_provider_
.count(consumer
) == 0)
156 const MotionEvent
& pointer_state
=
157 consumer_gesture_provider_
[consumer
]->pointer_state();
158 if (!pointer_state
.GetPointerCount())
160 *point
= gfx::PointF(pointer_state
.GetX(), pointer_state
.GetY());
164 bool GestureRecognizerImpl::CancelActiveTouches(GestureConsumer
* consumer
) {
165 bool cancelled_touch
= false;
166 if (consumer_gesture_provider_
.count(consumer
) == 0)
168 const MotionEventAura
& pointer_state
=
169 consumer_gesture_provider_
[consumer
]->pointer_state();
170 if (pointer_state
.GetPointerCount() == 0)
172 // pointer_state is modified every time after DispatchCancelTouchEvent.
173 scoped_ptr
<MotionEvent
> pointer_state_clone
= pointer_state
.Clone();
174 for (size_t i
= 0; i
< pointer_state_clone
->GetPointerCount(); ++i
) {
175 gfx::PointF
point(pointer_state_clone
->GetX(i
),
176 pointer_state_clone
->GetY(i
));
177 TouchEvent
touch_event(ui::ET_TOUCH_CANCELLED
,
179 ui::EF_IS_SYNTHESIZED
,
180 pointer_state_clone
->GetPointerId(i
),
181 ui::EventTimeForNow(),
186 GestureEventHelper
* helper
= FindDispatchHelperForConsumer(consumer
);
188 helper
->DispatchCancelTouchEvent(&touch_event
);
189 cancelled_touch
= true;
191 return cancelled_touch
;
194 ////////////////////////////////////////////////////////////////////////////////
195 // GestureRecognizerImpl, private:
197 GestureProviderAura
* GestureRecognizerImpl::GetGestureProviderForConsumer(
198 GestureConsumer
* consumer
) {
199 GestureProviderAura
* gesture_provider
= consumer_gesture_provider_
[consumer
];
200 if (!gesture_provider
) {
201 gesture_provider
= CreateGestureProvider(this);
202 consumer_gesture_provider_
[consumer
] = gesture_provider
;
204 return gesture_provider
;
207 void GestureRecognizerImpl::SetupTargets(const TouchEvent
& event
,
208 GestureConsumer
* target
) {
209 if (event
.type() == ui::ET_TOUCH_RELEASED
||
210 event
.type() == ui::ET_TOUCH_CANCELLED
) {
211 touch_id_target_
.erase(event
.touch_id());
212 } else if (event
.type() == ui::ET_TOUCH_PRESSED
) {
213 touch_id_target_
[event
.touch_id()] = target
;
215 touch_id_target_for_gestures_
[event
.touch_id()] = target
;
219 void GestureRecognizerImpl::DispatchGestureEvent(GestureEvent
* event
) {
220 GestureConsumer
* consumer
= GetTargetForGestureEvent(*event
);
222 GestureEventHelper
* helper
= FindDispatchHelperForConsumer(consumer
);
224 helper
->DispatchGestureEvent(event
);
228 bool GestureRecognizerImpl::ProcessTouchEventPreDispatch(
230 GestureConsumer
* consumer
) {
231 SetupTargets(*event
, consumer
);
233 if (event
->result() & ER_CONSUMED
)
236 GestureProviderAura
* gesture_provider
=
237 GetGestureProviderForConsumer(consumer
);
238 return gesture_provider
->OnTouchEvent(event
);
241 GestureRecognizer::Gestures
* GestureRecognizerImpl::AckTouchEvent(
242 uint32 unique_event_id
,
243 ui::EventResult result
,
244 GestureConsumer
* consumer
) {
245 GestureProviderAura
* gesture_provider
=
246 GetGestureProviderForConsumer(consumer
);
247 gesture_provider
->OnTouchEventAck(unique_event_id
, result
!= ER_UNHANDLED
);
248 return gesture_provider
->GetAndResetPendingGestures();
251 bool GestureRecognizerImpl::CleanupStateForConsumer(
252 GestureConsumer
* consumer
) {
253 bool state_cleaned_up
= false;
255 if (consumer_gesture_provider_
.count(consumer
)) {
256 state_cleaned_up
= true;
257 delete consumer_gesture_provider_
[consumer
];
258 consumer_gesture_provider_
.erase(consumer
);
261 state_cleaned_up
|= RemoveConsumerFromMap(consumer
, &touch_id_target_
);
263 RemoveConsumerFromMap(consumer
, &touch_id_target_for_gestures_
);
264 return state_cleaned_up
;
267 void GestureRecognizerImpl::AddGestureEventHelper(GestureEventHelper
* helper
) {
268 helpers_
.push_back(helper
);
271 void GestureRecognizerImpl::RemoveGestureEventHelper(
272 GestureEventHelper
* helper
) {
273 std::vector
<GestureEventHelper
*>::iterator it
= std::find(helpers_
.begin(),
274 helpers_
.end(), helper
);
275 if (it
!= helpers_
.end())
279 void GestureRecognizerImpl::OnGestureEvent(GestureEvent
* event
) {
280 DispatchGestureEvent(event
);
283 GestureEventHelper
* GestureRecognizerImpl::FindDispatchHelperForConsumer(
284 GestureConsumer
* consumer
) {
285 std::vector
<GestureEventHelper
*>::iterator it
;
286 for (it
= helpers_
.begin(); it
!= helpers_
.end(); ++it
) {
287 if ((*it
)->CanDispatchToConsumer(consumer
))
293 // GestureRecognizer, static
294 GestureRecognizer
* GestureRecognizer::Create() {
295 return new GestureRecognizerImpl();
298 static GestureRecognizerImpl
* g_gesture_recognizer_instance
= NULL
;
300 // GestureRecognizer, static
301 GestureRecognizer
* GestureRecognizer::Get() {
302 if (!g_gesture_recognizer_instance
)
303 g_gesture_recognizer_instance
= new GestureRecognizerImpl();
304 return g_gesture_recognizer_instance
;
307 // GestureRecognizer, static
308 void GestureRecognizer::Reset() {
309 delete g_gesture_recognizer_instance
;
310 g_gesture_recognizer_instance
= NULL
;
313 void SetGestureRecognizerForTesting(GestureRecognizer
* gesture_recognizer
) {
314 // Transfer helpers to the new GR.
315 std::vector
<GestureEventHelper
*>& helpers
=
316 g_gesture_recognizer_instance
->helpers();
317 std::vector
<GestureEventHelper
*>::iterator it
;
318 for (it
= helpers
.begin(); it
!= helpers
.end(); ++it
)
319 gesture_recognizer
->AddGestureEventHelper(*it
);
322 g_gesture_recognizer_instance
=
323 static_cast<GestureRecognizerImpl
*>(gesture_recognizer
);