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 "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"
16
17 namespace ui {
18
19 namespace {
20
21 template <typename T>
TransferConsumer(GestureConsumer * current_consumer,GestureConsumer * new_consumer,std::map<GestureConsumer *,T> * map)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);
28 }
29 }
30
RemoveConsumerFromMap(GestureConsumer * consumer,GestureRecognizerImpl::TouchIdToConsumerMap * map)31 void RemoveConsumerFromMap(GestureConsumer* consumer,
32 GestureRecognizerImpl::TouchIdToConsumerMap* map) {
33 for (GestureRecognizerImpl::TouchIdToConsumerMap::iterator i = map->begin();
34 i != map->end();) {
35 if (i->second == consumer)
36 map->erase(i++);
37 else
38 ++i;
39 }
40 }
41
TransferTouchIdToConsumerMap(GestureConsumer * old_consumer,GestureConsumer * new_consumer,GestureRecognizerImpl::TouchIdToConsumerMap * map)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;
50 }
51 }
52
53 } // namespace
54
55 ////////////////////////////////////////////////////////////////////////////////
56 // GestureRecognizerImpl, public:
57
GestureRecognizerImpl()58 GestureRecognizerImpl::GestureRecognizerImpl() {
59 }
60
~GestureRecognizerImpl()61 GestureRecognizerImpl::~GestureRecognizerImpl() {
62 STLDeleteValues(&consumer_sequence_);
63 }
64
65 // Checks if this finger is already down, if so, returns the current target.
66 // Otherwise, returns NULL.
GetTouchLockedTarget(const TouchEvent & event)67 GestureConsumer* GestureRecognizerImpl::GetTouchLockedTarget(
68 const TouchEvent& event) {
69 return touch_id_target_[event.touch_id()];
70 }
71
GetTargetForGestureEvent(const GestureEvent & event)72 GestureConsumer* GestureRecognizerImpl::GetTargetForGestureEvent(
73 const GestureEvent& event) {
74 GestureConsumer* target = NULL;
75 int touch_id = event.GetLowestTouchId();
76 target = touch_id_target_for_gestures_[touch_id];
77 return target;
78 }
79
GetTargetForLocation(const gfx::Point & location)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())
89 continue;
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;
97 }
98 }
99 }
100
101 const int max_distance =
102 GestureConfiguration::max_separation_for_gesture_touches_in_pixels();
103
104 if (closest_distance_squared < max_distance * max_distance && closest_point)
105 return touch_id_target_[closest_point->touch_id()];
106 else
107 return NULL;
108 }
109
TransferEventsTo(GestureConsumer * current_consumer,GestureConsumer * new_consumer)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) &&
124 i->second) {
125 ids.push_back(std::make_pair(i->first, i->second));
126 }
127 }
128
129 CancelTouches(&ids);
130
131 // Transfer events from |current_consumer| to |new_consumer|.
132 if (current_consumer && new_consumer) {
133 TransferTouchIdToConsumerMap(current_consumer, new_consumer,
134 &touch_id_target_);
135 TransferTouchIdToConsumerMap(current_consumer, new_consumer,
136 &touch_id_target_for_gestures_);
137 TransferConsumer(current_consumer, new_consumer, &consumer_sequence_);
138 }
139 }
140
GetLastTouchPointForTarget(GestureConsumer * consumer,gfx::Point * point)141 bool GestureRecognizerImpl::GetLastTouchPointForTarget(
142 GestureConsumer* consumer,
143 gfx::Point* point) {
144 if (consumer_sequence_.count(consumer) == 0)
145 return false;
146
147 *point = consumer_sequence_[consumer]->last_touch_location();
148 return true;
149 }
150
CancelActiveTouches(GestureConsumer * consumer)151 void GestureRecognizerImpl::CancelActiveTouches(
152 GestureConsumer* consumer) {
153 std::vector<std::pair<int, GestureConsumer*> > ids;
154 for (TouchIdToConsumerMap::const_iterator i = touch_id_target_.begin();
155 i != touch_id_target_.end(); ++i) {
156 if (i->second == consumer)
157 ids.push_back(std::make_pair(i->first, i->second));
158 }
159 CancelTouches(&ids);
160 }
161
162 ////////////////////////////////////////////////////////////////////////////////
163 // GestureRecognizerImpl, protected:
164
CreateSequence(GestureSequenceDelegate * delegate)165 GestureSequence* GestureRecognizerImpl::CreateSequence(
166 GestureSequenceDelegate* delegate) {
167 return new GestureSequence(delegate);
168 }
169
170 ////////////////////////////////////////////////////////////////////////////////
171 // GestureRecognizerImpl, private:
172
GetGestureSequenceForConsumer(GestureConsumer * consumer)173 GestureSequence* GestureRecognizerImpl::GetGestureSequenceForConsumer(
174 GestureConsumer* consumer) {
175 GestureSequence* gesture_sequence = consumer_sequence_[consumer];
176 if (!gesture_sequence) {
177 gesture_sequence = CreateSequence(this);
178 consumer_sequence_[consumer] = gesture_sequence;
179 }
180 return gesture_sequence;
181 }
182
SetupTargets(const TouchEvent & event,GestureConsumer * target)183 void GestureRecognizerImpl::SetupTargets(const TouchEvent& event,
184 GestureConsumer* target) {
185 if (event.type() == ui::ET_TOUCH_RELEASED ||
186 event.type() == ui::ET_TOUCH_CANCELLED) {
187 touch_id_target_.erase(event.touch_id());
188 } else if (event.type() == ui::ET_TOUCH_PRESSED) {
189 touch_id_target_[event.touch_id()] = target;
190 if (target)
191 touch_id_target_for_gestures_[event.touch_id()] = target;
192 }
193 }
194
CancelTouches(std::vector<std::pair<int,GestureConsumer * >> * touches)195 void GestureRecognizerImpl::CancelTouches(
196 std::vector<std::pair<int, GestureConsumer*> >* touches) {
197 while (!touches->empty()) {
198 int touch_id = touches->begin()->first;
199 GestureConsumer* target = touches->begin()->second;
200 TouchEvent touch_event(ui::ET_TOUCH_CANCELLED, gfx::Point(0, 0),
201 ui::EF_IS_SYNTHESIZED, touch_id,
202 ui::EventTimeForNow(), 0.0f, 0.0f, 0.0f, 0.0f);
203 GestureEventHelper* helper = FindDispatchHelperForConsumer(target);
204 if (helper)
205 helper->DispatchCancelTouchEvent(&touch_event);
206 touches->erase(touches->begin());
207 }
208 }
209
ProcessTouchEventForGesture(const TouchEvent & event,ui::EventResult result,GestureConsumer * target)210 GestureSequence::Gestures* GestureRecognizerImpl::ProcessTouchEventForGesture(
211 const TouchEvent& event,
212 ui::EventResult result,
213 GestureConsumer* target) {
214 SetupTargets(event, target);
215 GestureSequence* gesture_sequence = GetGestureSequenceForConsumer(target);
216 return gesture_sequence->ProcessTouchEventForGesture(event, result);
217 }
218
CleanupStateForConsumer(GestureConsumer * consumer)219 void GestureRecognizerImpl::CleanupStateForConsumer(GestureConsumer* consumer) {
220 if (consumer_sequence_.count(consumer)) {
221 delete consumer_sequence_[consumer];
222 consumer_sequence_.erase(consumer);
223 }
224
225 RemoveConsumerFromMap(consumer, &touch_id_target_);
226 RemoveConsumerFromMap(consumer, &touch_id_target_for_gestures_);
227 }
228
AddGestureEventHelper(GestureEventHelper * helper)229 void GestureRecognizerImpl::AddGestureEventHelper(GestureEventHelper* helper) {
230 helpers_.push_back(helper);
231 }
232
RemoveGestureEventHelper(GestureEventHelper * helper)233 void GestureRecognizerImpl::RemoveGestureEventHelper(
234 GestureEventHelper* helper) {
235 std::vector<GestureEventHelper*>::iterator it = std::find(helpers_.begin(),
236 helpers_.end(), helper);
237 if (it != helpers_.end())
238 helpers_.erase(it);
239 }
240
DispatchPostponedGestureEvent(GestureEvent * event)241 void GestureRecognizerImpl::DispatchPostponedGestureEvent(GestureEvent* event) {
242 GestureConsumer* consumer = GetTargetForGestureEvent(*event);
243 if (consumer) {
244 GestureEventHelper* helper = FindDispatchHelperForConsumer(consumer);
245 if (helper)
246 helper->DispatchPostponedGestureEvent(event);
247 }
248 }
249
FindDispatchHelperForConsumer(GestureConsumer * consumer)250 GestureEventHelper* GestureRecognizerImpl::FindDispatchHelperForConsumer(
251 GestureConsumer* consumer) {
252 std::vector<GestureEventHelper*>::iterator it;
253 for (it = helpers_.begin(); it != helpers_.end(); ++it) {
254 if ((*it)->CanDispatchToConsumer(consumer))
255 return (*it);
256 }
257 return NULL;
258 }
259
260 // GestureRecognizer, static
Create()261 GestureRecognizer* GestureRecognizer::Create() {
262 return new GestureRecognizerImpl();
263 }
264
265 static GestureRecognizerImpl* g_gesture_recognizer_instance = NULL;
266
267 // GestureRecognizer, static
Get()268 GestureRecognizer* GestureRecognizer::Get() {
269 if (!g_gesture_recognizer_instance)
270 g_gesture_recognizer_instance = new GestureRecognizerImpl();
271 return g_gesture_recognizer_instance;
272 }
273
SetGestureRecognizerForTesting(GestureRecognizer * gesture_recognizer)274 void SetGestureRecognizerForTesting(GestureRecognizer* gesture_recognizer) {
275 // Transfer helpers to the new GR.
276 std::vector<GestureEventHelper*>& helpers =
277 g_gesture_recognizer_instance->helpers();
278 std::vector<GestureEventHelper*>::iterator it;
279 for (it = helpers.begin(); it != helpers.end(); ++it)
280 gesture_recognizer->AddGestureEventHelper(*it);
281
282 helpers.clear();
283 g_gesture_recognizer_instance =
284 static_cast<GestureRecognizerImpl*>(gesture_recognizer);
285 }
286
287 } // namespace ui
288