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. 4 5 #include "ui/events/gestures/gesture_recognizer_impl.h" 6 7 #include <limits> 8 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" 20 21 namespace ui { 22 23 namespace { 24 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); 32 } 33 } 34 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; 45 } 46 } 47 return consumer_removed; 48 } 49 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; 58 } 59 } 60 61 GestureProviderAura* CreateGestureProvider(GestureProviderAuraClient* client) { 62 return new GestureProviderAura(client); 63 } 64 65 } // namespace 66 67 //////////////////////////////////////////////////////////////////////////////// 68 // GestureRecognizerImpl, public: 69 70 GestureRecognizerImpl::GestureRecognizerImpl() { 71 } 72 73 GestureRecognizerImpl::~GestureRecognizerImpl() { 74 STLDeleteValues(&consumer_gesture_provider_); 75 } 76 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()]; 82 } 83 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]; 89 return target; 90 } 91 92 GestureConsumer* GestureRecognizerImpl::GetTargetForLocation( 93 const gfx::PointF& location, int source_device_id) { 94 const int max_distance = 95 GestureConfiguration::max_separation_for_gesture_touches_in_pixels(); 96 97 gfx::PointF closest_point; 98 int closest_touch_id; 99 float closest_distance_squared = std::numeric_limits<float>::infinity(); 100 101 std::map<GestureConsumer*, GestureProviderAura*>::iterator i; 102 for (i = consumer_gesture_provider_.begin(); 103 i != consumer_gesture_provider_.end(); 104 ++i) { 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)) 108 continue; 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 float 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; 117 } 118 } 119 } 120 121 if (closest_distance_squared < max_distance * max_distance) 122 return touch_id_target_[closest_touch_id]; 123 return NULL; 124 } 125 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. 135 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(); 140 ++i) { 141 if (i->first && i->first != new_consumer && 142 (i->first != current_consumer || new_consumer == NULL)) { 143 consumers.push_back(i->first); 144 } 145 } 146 for (std::vector<GestureConsumer*>::iterator iter = consumers.begin(); 147 iter != consumers.end(); 148 ++iter) { 149 CancelActiveTouches(*iter); 150 } 151 // Transfer events from |current_consumer| to |new_consumer|. 152 if (current_consumer && new_consumer) { 153 TransferTouchIdToConsumerMap(current_consumer, new_consumer, 154 &touch_id_target_); 155 TransferTouchIdToConsumerMap(current_consumer, new_consumer, 156 &touch_id_target_for_gestures_); 157 TransferConsumer( 158 current_consumer, new_consumer, &consumer_gesture_provider_); 159 } 160 } 161 162 bool GestureRecognizerImpl::GetLastTouchPointForTarget( 163 GestureConsumer* consumer, 164 gfx::PointF* point) { 165 if (consumer_gesture_provider_.count(consumer) == 0) 166 return false; 167 const MotionEvent& pointer_state = 168 consumer_gesture_provider_[consumer]->pointer_state(); 169 *point = gfx::PointF(pointer_state.GetX(), pointer_state.GetY()); 170 return true; 171 } 172 173 bool GestureRecognizerImpl::CancelActiveTouches(GestureConsumer* consumer) { 174 bool cancelled_touch = false; 175 if (consumer_gesture_provider_.count(consumer) == 0) 176 return false; 177 const MotionEventAura& pointer_state = 178 consumer_gesture_provider_[consumer]->pointer_state(); 179 if (pointer_state.GetPointerCount() == 0) 180 return false; 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, 187 point, 188 ui::EF_IS_SYNTHESIZED, 189 pointer_state_clone->GetPointerId(i), 190 ui::EventTimeForNow(), 191 0.0f, 192 0.0f, 193 0.0f, 194 0.0f); 195 GestureEventHelper* helper = FindDispatchHelperForConsumer(consumer); 196 if (helper) 197 helper->DispatchCancelTouchEvent(&touch_event); 198 cancelled_touch = true; 199 } 200 return cancelled_touch; 201 } 202 203 //////////////////////////////////////////////////////////////////////////////// 204 // GestureRecognizerImpl, private: 205 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; 212 } 213 return gesture_provider; 214 } 215 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; 223 if (target) 224 touch_id_target_for_gestures_[event.touch_id()] = target; 225 } 226 } 227 228 void GestureRecognizerImpl::DispatchGestureEvent(GestureEvent* event) { 229 GestureConsumer* consumer = GetTargetForGestureEvent(*event); 230 if (consumer) { 231 GestureEventHelper* helper = FindDispatchHelperForConsumer(consumer); 232 if (helper) 233 helper->DispatchGestureEvent(event); 234 } 235 } 236 237 bool GestureRecognizerImpl::ProcessTouchEventPreDispatch( 238 const TouchEvent& event, 239 GestureConsumer* consumer) { 240 SetupTargets(event, consumer); 241 242 if (event.result() & ER_CONSUMED) 243 return false; 244 245 GestureProviderAura* gesture_provider = 246 GetGestureProviderForConsumer(consumer); 247 return gesture_provider->OnTouchEvent(event); 248 } 249 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(); 259 } 260 261 GestureRecognizer::Gestures* GestureRecognizerImpl::ProcessTouchEventOnAsyncAck( 262 const TouchEvent& event, 263 ui::EventResult result, 264 GestureConsumer* consumer) { 265 if (result & ui::ER_CONSUMED) 266 return NULL; 267 GestureProviderAura* gesture_provider = 268 GetGestureProviderForConsumer(consumer); 269 gesture_provider->OnTouchEventAck(result != ER_UNHANDLED); 270 return gesture_provider->GetAndResetPendingGestures(); 271 } 272 273 bool GestureRecognizerImpl::CleanupStateForConsumer( 274 GestureConsumer* consumer) { 275 bool state_cleaned_up = false; 276 277 if (consumer_gesture_provider_.count(consumer)) { 278 state_cleaned_up = true; 279 delete consumer_gesture_provider_[consumer]; 280 consumer_gesture_provider_.erase(consumer); 281 } 282 283 state_cleaned_up |= RemoveConsumerFromMap(consumer, &touch_id_target_); 284 state_cleaned_up |= 285 RemoveConsumerFromMap(consumer, &touch_id_target_for_gestures_); 286 return state_cleaned_up; 287 } 288 289 void GestureRecognizerImpl::AddGestureEventHelper(GestureEventHelper* helper) { 290 helpers_.push_back(helper); 291 } 292 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()) 298 helpers_.erase(it); 299 } 300 301 void GestureRecognizerImpl::OnGestureEvent(GestureEvent* event) { 302 DispatchGestureEvent(event); 303 } 304 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)) 310 return (*it); 311 } 312 return NULL; 313 } 314 315 // GestureRecognizer, static 316 GestureRecognizer* GestureRecognizer::Create() { 317 return new GestureRecognizerImpl(); 318 } 319 320 static GestureRecognizerImpl* g_gesture_recognizer_instance = NULL; 321 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; 327 } 328 329 // GestureRecognizer, static 330 void GestureRecognizer::Reset() { 331 delete g_gesture_recognizer_instance; 332 g_gesture_recognizer_instance = NULL; 333 } 334 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); 342 343 helpers.clear(); 344 g_gesture_recognizer_instance = 345 static_cast<GestureRecognizerImpl*>(gesture_recognizer); 346 } 347 348 } // namespace ui 349