Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / ui / events / gestures / gesture_recognizer_impl.cc
blobfe3de2c67a37e29e4c2e8a4eab530b4140dc17ba
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"
7 #include <limits>
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"
21 namespace ui {
23 namespace {
25 template <typename T>
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();
39 i != map->end();) {
40 if (i->second == consumer) {
41 map->erase(i++);
42 consumer_removed = true;
43 } else {
44 ++i;
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);
65 } // namespace
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.";
89 return nullptr;
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();
108 ++i) {
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))
112 continue;
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];
127 return NULL;
130 void GestureRecognizerImpl::CancelActiveTouchesExcept(
131 GestureConsumer* not_cancelled) {
132 for (const auto& consumer_provider : consumer_gesture_provider_) {
133 if (consumer_provider.first == not_cancelled)
134 continue;
135 CancelActiveTouches(consumer_provider.first);
139 void GestureRecognizerImpl::TransferEventsTo(GestureConsumer* current_consumer,
140 GestureConsumer* new_consumer) {
141 DCHECK(current_consumer);
142 DCHECK(new_consumer);
144 CancelActiveTouchesExcept(current_consumer);
146 TransferTouchIdToConsumerMap(current_consumer, new_consumer,
147 &touch_id_target_);
148 TransferTouchIdToConsumerMap(current_consumer, new_consumer,
149 &touch_id_target_for_gestures_);
150 TransferConsumer(current_consumer, new_consumer, &consumer_gesture_provider_);
153 bool GestureRecognizerImpl::GetLastTouchPointForTarget(
154 GestureConsumer* consumer,
155 gfx::PointF* point) {
156 if (consumer_gesture_provider_.count(consumer) == 0)
157 return false;
158 const MotionEvent& pointer_state =
159 consumer_gesture_provider_[consumer]->pointer_state();
160 *point = gfx::PointF(pointer_state.GetX(), pointer_state.GetY());
161 return true;
164 bool GestureRecognizerImpl::CancelActiveTouches(GestureConsumer* consumer) {
165 bool cancelled_touch = false;
166 if (consumer_gesture_provider_.count(consumer) == 0)
167 return false;
168 const MotionEventAura& pointer_state =
169 consumer_gesture_provider_[consumer]->pointer_state();
170 if (pointer_state.GetPointerCount() == 0)
171 return false;
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,
178 point,
179 ui::EF_IS_SYNTHESIZED,
180 pointer_state_clone->GetPointerId(i),
181 ui::EventTimeForNow(),
182 0.0f,
183 0.0f,
184 0.0f,
185 0.0f);
186 GestureEventHelper* helper = FindDispatchHelperForConsumer(consumer);
187 if (helper)
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;
214 if (target)
215 touch_id_target_for_gestures_[event.touch_id()] = target;
219 void GestureRecognizerImpl::DispatchGestureEvent(GestureEvent* event) {
220 GestureConsumer* consumer = GetTargetForGestureEvent(*event);
221 if (consumer) {
222 GestureEventHelper* helper = FindDispatchHelperForConsumer(consumer);
223 if (helper)
224 helper->DispatchGestureEvent(event);
228 bool GestureRecognizerImpl::ProcessTouchEventPreDispatch(
229 TouchEvent* event,
230 GestureConsumer* consumer) {
231 SetupTargets(*event, consumer);
233 if (event->result() & ER_CONSUMED)
234 return false;
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_);
262 state_cleaned_up |=
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())
276 helpers_.erase(it);
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))
288 return (*it);
290 return NULL;
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);
321 helpers.clear();
322 g_gesture_recognizer_instance =
323 static_cast<GestureRecognizerImpl*>(gesture_recognizer);
326 } // namespace ui