• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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