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/base/gestures/gesture_recognizer_impl.h" 6 7 #include "base/logging.h" 8 #include "base/memory/scoped_ptr.h" 9 #include "base/time/time.h" 10 #include "ui/base/events/event.h" 11 #include "ui/base/events/event_constants.h" 12 #include "ui/base/events/event_utils.h" 13 #include "ui/base/gestures/gesture_configuration.h" 14 #include "ui/base/gestures/gesture_sequence.h" 15 #include "ui/base/gestures/gesture_types.h" 16 17 namespace ui { 18 19 namespace { 20 21 // CancelledTouchEvent mirrors a TouchEvent object. 22 class MirroredTouchEvent : public TouchEvent { 23 public: 24 explicit MirroredTouchEvent(const TouchEvent* real) 25 : TouchEvent(real->type(), 26 real->location(), 27 real->touch_id(), 28 real->time_stamp()) { 29 set_flags(real->flags()); 30 set_radius(real->radius_x(), real->radius_y()); 31 set_rotation_angle(real->rotation_angle()); 32 set_force(real->force()); 33 } 34 35 virtual ~MirroredTouchEvent() { 36 } 37 38 private: 39 DISALLOW_COPY_AND_ASSIGN(MirroredTouchEvent); 40 }; 41 42 // A mirrored event, except for the type, which is always ET_TOUCH_CANCELLED. 43 class CancelledTouchEvent : public MirroredTouchEvent { 44 public: 45 explicit CancelledTouchEvent(const TouchEvent* src) 46 : MirroredTouchEvent(src) { 47 SetType(ET_TOUCH_CANCELLED); 48 } 49 50 virtual ~CancelledTouchEvent() {} 51 52 private: 53 DISALLOW_COPY_AND_ASSIGN(CancelledTouchEvent); 54 }; 55 56 // Touches which are cancelled by a touch capture are routed to a 57 // GestureEventIgnorer, which ignores them. 58 class GestureConsumerIgnorer : public GestureConsumer { 59 public: 60 GestureConsumerIgnorer() 61 : GestureConsumer(true) { 62 } 63 }; 64 65 template <typename T> 66 void TransferConsumer(GestureConsumer* current_consumer, 67 GestureConsumer* new_consumer, 68 std::map<GestureConsumer*, T>* map) { 69 if (map->count(current_consumer)) { 70 (*map)[new_consumer] = (*map)[current_consumer]; 71 map->erase(current_consumer); 72 } 73 } 74 75 void RemoveConsumerFromMap(GestureConsumer* consumer, 76 GestureRecognizerImpl::TouchIdToConsumerMap* map) { 77 for (GestureRecognizerImpl::TouchIdToConsumerMap::iterator i = map->begin(); 78 i != map->end();) { 79 if (i->second == consumer) 80 map->erase(i++); 81 else 82 ++i; 83 } 84 } 85 86 void TransferTouchIdToConsumerMap( 87 GestureConsumer* old_consumer, 88 GestureConsumer* new_consumer, 89 GestureRecognizerImpl::TouchIdToConsumerMap* map) { 90 for (GestureRecognizerImpl::TouchIdToConsumerMap::iterator i = map->begin(); 91 i != map->end(); ++i) { 92 if (i->second == old_consumer) 93 i->second = new_consumer; 94 } 95 } 96 97 } // namespace 98 99 //////////////////////////////////////////////////////////////////////////////// 100 // GestureRecognizerImpl, public: 101 102 GestureRecognizerImpl::GestureRecognizerImpl(GestureEventHelper* helper) 103 : helper_(helper) { 104 gesture_consumer_ignorer_.reset(new GestureConsumerIgnorer()); 105 } 106 107 GestureRecognizerImpl::~GestureRecognizerImpl() { 108 STLDeleteValues(&consumer_sequence_); 109 } 110 111 // Checks if this finger is already down, if so, returns the current target. 112 // Otherwise, returns NULL. 113 GestureConsumer* GestureRecognizerImpl::GetTouchLockedTarget( 114 TouchEvent* event) { 115 return touch_id_target_[event->touch_id()]; 116 } 117 118 GestureConsumer* GestureRecognizerImpl::GetTargetForGestureEvent( 119 GestureEvent* event) { 120 GestureConsumer* target = NULL; 121 int touch_id = event->GetLowestTouchId(); 122 target = touch_id_target_for_gestures_[touch_id]; 123 return target; 124 } 125 126 GestureConsumer* GestureRecognizerImpl::GetTargetForLocation( 127 const gfx::Point& location) { 128 const GesturePoint* closest_point = NULL; 129 int64 closest_distance_squared = 0; 130 std::map<GestureConsumer*, GestureSequence*>::iterator i; 131 for (i = consumer_sequence_.begin(); i != consumer_sequence_.end(); ++i) { 132 const GesturePoint* points = i->second->points(); 133 for (int j = 0; j < GestureSequence::kMaxGesturePoints; ++j) { 134 if (!points[j].in_use()) 135 continue; 136 gfx::Vector2d delta = points[j].last_touch_position() - location; 137 // Relative distance is all we need here, so LengthSquared() is 138 // appropriate, and cheaper than Length(). 139 int64 distance_squared = delta.LengthSquared(); 140 if (!closest_point || distance_squared < closest_distance_squared) { 141 closest_point = &points[j]; 142 closest_distance_squared = distance_squared; 143 } 144 } 145 } 146 147 const int max_distance = 148 GestureConfiguration::max_separation_for_gesture_touches_in_pixels(); 149 150 if (closest_distance_squared < max_distance * max_distance && closest_point) 151 return touch_id_target_[closest_point->touch_id()]; 152 else 153 return NULL; 154 } 155 156 void GestureRecognizerImpl::TransferEventsTo(GestureConsumer* current_consumer, 157 GestureConsumer* new_consumer) { 158 // Send cancel to all those save |new_consumer| and |current_consumer|. 159 // Don't send a cancel to |current_consumer|, unless |new_consumer| is NULL. 160 for (TouchIdToConsumerMap::iterator i = touch_id_target_.begin(); 161 i != touch_id_target_.end(); ++i) { 162 if (i->second != new_consumer && 163 (i->second != current_consumer || new_consumer == NULL) && 164 i->second != gesture_consumer_ignorer_.get()) { 165 TouchEvent touch_event(ui::ET_TOUCH_CANCELLED, gfx::Point(0, 0), 166 ui::EF_IS_SYNTHESIZED, i->first, 167 ui::EventTimeForNow(), 0.0f, 0.0f, 0.0f, 0.0f); 168 helper_->DispatchCancelTouchEvent(&touch_event); 169 DCHECK_EQ(gesture_consumer_ignorer_.get(), i->second); 170 } 171 } 172 173 // Transfer events from |current_consumer| to |new_consumer|. 174 if (current_consumer && new_consumer) { 175 TransferTouchIdToConsumerMap(current_consumer, new_consumer, 176 &touch_id_target_); 177 TransferTouchIdToConsumerMap(current_consumer, new_consumer, 178 &touch_id_target_for_gestures_); 179 TransferConsumer(current_consumer, new_consumer, &consumer_sequence_); 180 } 181 } 182 183 bool GestureRecognizerImpl::GetLastTouchPointForTarget( 184 GestureConsumer* consumer, 185 gfx::Point* point) { 186 if (consumer_sequence_.count(consumer) == 0) 187 return false; 188 189 *point = consumer_sequence_[consumer]->last_touch_location(); 190 return true; 191 } 192 193 //////////////////////////////////////////////////////////////////////////////// 194 // GestureRecognizerImpl, protected: 195 196 GestureSequence* GestureRecognizerImpl::CreateSequence( 197 GestureEventHelper* helper) { 198 return new GestureSequence(helper); 199 } 200 201 //////////////////////////////////////////////////////////////////////////////// 202 // GestureRecognizerImpl, private: 203 204 GestureSequence* GestureRecognizerImpl::GetGestureSequenceForConsumer( 205 GestureConsumer* consumer) { 206 GestureSequence* gesture_sequence = consumer_sequence_[consumer]; 207 if (!gesture_sequence) { 208 gesture_sequence = CreateSequence(helper_); 209 consumer_sequence_[consumer] = gesture_sequence; 210 } 211 return gesture_sequence; 212 } 213 214 void GestureRecognizerImpl::SetupTargets(const TouchEvent& event, 215 GestureConsumer* target) { 216 if (event.type() == ui::ET_TOUCH_RELEASED) { 217 touch_id_target_.erase(event.touch_id()); 218 } else if (event.type() == ui::ET_TOUCH_CANCELLED) { 219 touch_id_target_[event.touch_id()] = gesture_consumer_ignorer_.get(); 220 } else { 221 touch_id_target_[event.touch_id()] = target; 222 if (target) 223 touch_id_target_for_gestures_[event.touch_id()] = target; 224 } 225 } 226 227 GestureSequence::Gestures* GestureRecognizerImpl::ProcessTouchEventForGesture( 228 const TouchEvent& event, 229 ui::EventResult result, 230 GestureConsumer* target) { 231 SetupTargets(event, target); 232 GestureSequence* gesture_sequence = GetGestureSequenceForConsumer(target); 233 return gesture_sequence->ProcessTouchEventForGesture(event, result); 234 } 235 236 void GestureRecognizerImpl::CleanupStateForConsumer(GestureConsumer* consumer) { 237 if (consumer_sequence_.count(consumer)) { 238 delete consumer_sequence_[consumer]; 239 consumer_sequence_.erase(consumer); 240 } 241 242 RemoveConsumerFromMap(consumer, &touch_id_target_); 243 RemoveConsumerFromMap(consumer, &touch_id_target_for_gestures_); 244 } 245 246 // GestureRecognizer, static 247 GestureRecognizer* GestureRecognizer::Create(GestureEventHelper* helper) { 248 return new GestureRecognizerImpl(helper); 249 } 250 251 } // namespace ui 252