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 "base/logging.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/time/time.h"
10 #include "ui/events/event.h"
11 #include "ui/events/event_constants.h"
12 #include "ui/events/event_utils.h"
13 #include "ui/events/gestures/gesture_configuration.h"
14 #include "ui/events/gestures/gesture_sequence.h"
15 #include "ui/events/gestures/gesture_types.h"
22 void TransferConsumer(GestureConsumer* current_consumer,
23 GestureConsumer* new_consumer,
24 std::map<GestureConsumer*, T>* map) {
25 if (map->count(current_consumer)) {
26 (*map)[new_consumer] = (*map)[current_consumer];
27 map->erase(current_consumer);
31 void RemoveConsumerFromMap(GestureConsumer* consumer,
32 GestureRecognizerImpl::TouchIdToConsumerMap* map) {
33 for (GestureRecognizerImpl::TouchIdToConsumerMap::iterator i = map->begin();
35 if (i->second == consumer)
42 void TransferTouchIdToConsumerMap(
43 GestureConsumer* old_consumer,
44 GestureConsumer* new_consumer,
45 GestureRecognizerImpl::TouchIdToConsumerMap* map) {
46 for (GestureRecognizerImpl::TouchIdToConsumerMap::iterator i = map->begin();
47 i != map->end(); ++i) {
48 if (i->second == old_consumer)
49 i->second = new_consumer;
55 ////////////////////////////////////////////////////////////////////////////////
56 // GestureRecognizerImpl, public:
58 GestureRecognizerImpl::GestureRecognizerImpl() {
61 GestureRecognizerImpl::~GestureRecognizerImpl() {
62 STLDeleteValues(&consumer_sequence_);
65 // Checks if this finger is already down, if so, returns the current target.
66 // Otherwise, returns NULL.
67 GestureConsumer* GestureRecognizerImpl::GetTouchLockedTarget(
69 return touch_id_target_[event->touch_id()];
72 GestureConsumer* GestureRecognizerImpl::GetTargetForGestureEvent(
73 GestureEvent* event) {
74 GestureConsumer* target = NULL;
75 int touch_id = event->GetLowestTouchId();
76 target = touch_id_target_for_gestures_[touch_id];
80 GestureConsumer* GestureRecognizerImpl::GetTargetForLocation(
81 const gfx::Point& location) {
82 const GesturePoint* closest_point = NULL;
83 int64 closest_distance_squared = 0;
84 std::map<GestureConsumer*, GestureSequence*>::iterator i;
85 for (i = consumer_sequence_.begin(); i != consumer_sequence_.end(); ++i) {
86 const GesturePoint* points = i->second->points();
87 for (int j = 0; j < GestureSequence::kMaxGesturePoints; ++j) {
88 if (!points[j].in_use())
90 gfx::Vector2d delta = points[j].last_touch_position() - location;
91 // Relative distance is all we need here, so LengthSquared() is
92 // appropriate, and cheaper than Length().
93 int64 distance_squared = delta.LengthSquared();
94 if (!closest_point || distance_squared < closest_distance_squared) {
95 closest_point = &points[j];
96 closest_distance_squared = distance_squared;
101 const int max_distance =
102 GestureConfiguration::max_separation_for_gesture_touches_in_pixels();
104 if (closest_distance_squared < max_distance * max_distance && closest_point)
105 return touch_id_target_[closest_point->touch_id()];
110 void GestureRecognizerImpl::TransferEventsTo(GestureConsumer* current_consumer,
111 GestureConsumer* new_consumer) {
112 // Send cancel to all those save |new_consumer| and |current_consumer|.
113 // Don't send a cancel to |current_consumer|, unless |new_consumer| is NULL.
114 // Dispatching a touch-cancel event can end up altering |touch_id_target_|
115 // (e.g. when the target of the event is destroyed, causing it to be removed
116 // from |touch_id_target_| in |CleanupStateForConsumer()|). So create a list
117 // of the touch-ids that need to be cancelled, and dispatch the cancel events
118 // for them at the end.
119 std::vector<std::pair<int, GestureConsumer*> > ids;
120 for (TouchIdToConsumerMap::iterator i = touch_id_target_.begin();
121 i != touch_id_target_.end(); ++i) {
122 if (i->second && i->second != new_consumer &&
123 (i->second != current_consumer || new_consumer == NULL) &&
125 ids.push_back(std::make_pair(i->first, i->second));
129 while (!ids.empty()) {
130 int touch_id = ids.begin()->first;
131 GestureConsumer* target = ids.begin()->second;
132 TouchEvent touch_event(ui::ET_TOUCH_CANCELLED, gfx::Point(0, 0),
133 ui::EF_IS_SYNTHESIZED, touch_id,
134 ui::EventTimeForNow(), 0.0f, 0.0f, 0.0f, 0.0f);
135 GestureEventHelper* helper = FindDispatchHelperForConsumer(target);
137 helper->DispatchCancelTouchEvent(&touch_event);
138 ids.erase(ids.begin());
141 // Transfer events from |current_consumer| to |new_consumer|.
142 if (current_consumer && new_consumer) {
143 TransferTouchIdToConsumerMap(current_consumer, new_consumer,
145 TransferTouchIdToConsumerMap(current_consumer, new_consumer,
146 &touch_id_target_for_gestures_);
147 TransferConsumer(current_consumer, new_consumer, &consumer_sequence_);
151 bool GestureRecognizerImpl::GetLastTouchPointForTarget(
152 GestureConsumer* consumer,
154 if (consumer_sequence_.count(consumer) == 0)
157 *point = consumer_sequence_[consumer]->last_touch_location();
161 ////////////////////////////////////////////////////////////////////////////////
162 // GestureRecognizerImpl, protected:
164 GestureSequence* GestureRecognizerImpl::CreateSequence(
165 GestureSequenceDelegate* delegate) {
166 return new GestureSequence(delegate);
169 ////////////////////////////////////////////////////////////////////////////////
170 // GestureRecognizerImpl, private:
172 GestureSequence* GestureRecognizerImpl::GetGestureSequenceForConsumer(
173 GestureConsumer* consumer) {
174 GestureSequence* gesture_sequence = consumer_sequence_[consumer];
175 if (!gesture_sequence) {
176 gesture_sequence = CreateSequence(this);
177 consumer_sequence_[consumer] = gesture_sequence;
179 return gesture_sequence;
182 void GestureRecognizerImpl::SetupTargets(const TouchEvent& event,
183 GestureConsumer* target) {
184 if (event.type() == ui::ET_TOUCH_RELEASED ||
185 event.type() == ui::ET_TOUCH_CANCELLED) {
186 touch_id_target_.erase(event.touch_id());
188 touch_id_target_[event.touch_id()] = target;
190 touch_id_target_for_gestures_[event.touch_id()] = target;
194 GestureSequence::Gestures* GestureRecognizerImpl::ProcessTouchEventForGesture(
195 const TouchEvent& event,
196 ui::EventResult result,
197 GestureConsumer* target) {
198 SetupTargets(event, target);
199 GestureSequence* gesture_sequence = GetGestureSequenceForConsumer(target);
200 return gesture_sequence->ProcessTouchEventForGesture(event, result);
203 void GestureRecognizerImpl::CleanupStateForConsumer(GestureConsumer* consumer) {
204 if (consumer_sequence_.count(consumer)) {
205 delete consumer_sequence_[consumer];
206 consumer_sequence_.erase(consumer);
209 RemoveConsumerFromMap(consumer, &touch_id_target_);
210 RemoveConsumerFromMap(consumer, &touch_id_target_for_gestures_);
213 void GestureRecognizerImpl::AddGestureEventHelper(GestureEventHelper* helper) {
214 helpers_.push_back(helper);
217 void GestureRecognizerImpl::RemoveGestureEventHelper(
218 GestureEventHelper* helper) {
219 std::vector<GestureEventHelper*>::iterator it = std::find(helpers_.begin(),
220 helpers_.end(), helper);
221 if (it != helpers_.end())
225 void GestureRecognizerImpl::DispatchPostponedGestureEvent(GestureEvent* event) {
226 GestureConsumer* consumer = GetTargetForGestureEvent(event);
228 GestureEventHelper* helper = FindDispatchHelperForConsumer(consumer);
230 helper->DispatchPostponedGestureEvent(event);
234 GestureEventHelper* GestureRecognizerImpl::FindDispatchHelperForConsumer(
235 GestureConsumer* consumer) {
236 std::vector<GestureEventHelper*>::iterator it;
237 for (it = helpers_.begin(); it != helpers_.end(); ++it) {
238 if ((*it)->CanDispatchToConsumer(consumer))
244 // GestureRecognizer, static
245 GestureRecognizer* GestureRecognizer::Create() {
246 return new GestureRecognizerImpl();
249 static GestureRecognizerImpl* g_gesture_recognizer_instance = NULL;
251 // GestureRecognizer, static
252 GestureRecognizer* GestureRecognizer::Get() {
253 if (!g_gesture_recognizer_instance)
254 g_gesture_recognizer_instance = new GestureRecognizerImpl();
255 return g_gesture_recognizer_instance;
258 void SetGestureRecognizerForTesting(GestureRecognizer* gesture_recognizer) {
259 // Transfer helpers to the new GR.
260 std::vector<GestureEventHelper*>& helpers =
261 g_gesture_recognizer_instance->helpers();
262 std::vector<GestureEventHelper*>::iterator it;
263 for (it = helpers.begin(); it != helpers.end(); ++it)
264 gesture_recognizer->AddGestureEventHelper(*it);
267 g_gesture_recognizer_instance =
268 static_cast<GestureRecognizerImpl*>(gesture_recognizer);