- add sources.
[platform/framework/web/crosswalk.git] / src / ui / events / gestures / gesture_recognizer_impl.cc
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>
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
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
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
58 GestureRecognizerImpl::GestureRecognizerImpl() {
59 }
60
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.
67 GestureConsumer* GestureRecognizerImpl::GetTouchLockedTarget(
68     TouchEvent* event) {
69   return touch_id_target_[event->touch_id()];
70 }
71
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];
77   return target;
78 }
79
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
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   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);
136     if (helper)
137       helper->DispatchCancelTouchEvent(&touch_event);
138     ids.erase(ids.begin());
139   }
140
141   // Transfer events from |current_consumer| to |new_consumer|.
142   if (current_consumer && new_consumer) {
143     TransferTouchIdToConsumerMap(current_consumer, new_consumer,
144                                  &touch_id_target_);
145     TransferTouchIdToConsumerMap(current_consumer, new_consumer,
146                                  &touch_id_target_for_gestures_);
147     TransferConsumer(current_consumer, new_consumer, &consumer_sequence_);
148   }
149 }
150
151 bool GestureRecognizerImpl::GetLastTouchPointForTarget(
152     GestureConsumer* consumer,
153     gfx::Point* point) {
154   if (consumer_sequence_.count(consumer) == 0)
155     return false;
156
157   *point = consumer_sequence_[consumer]->last_touch_location();
158   return true;
159 }
160
161 ////////////////////////////////////////////////////////////////////////////////
162 // GestureRecognizerImpl, protected:
163
164 GestureSequence* GestureRecognizerImpl::CreateSequence(
165     GestureSequenceDelegate* delegate) {
166   return new GestureSequence(delegate);
167 }
168
169 ////////////////////////////////////////////////////////////////////////////////
170 // GestureRecognizerImpl, private:
171
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;
178   }
179   return gesture_sequence;
180 }
181
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());
187   } else {
188     touch_id_target_[event.touch_id()] = target;
189     if (target)
190       touch_id_target_for_gestures_[event.touch_id()] = target;
191   }
192 }
193
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);
201 }
202
203 void GestureRecognizerImpl::CleanupStateForConsumer(GestureConsumer* consumer) {
204   if (consumer_sequence_.count(consumer)) {
205     delete consumer_sequence_[consumer];
206     consumer_sequence_.erase(consumer);
207   }
208
209   RemoveConsumerFromMap(consumer, &touch_id_target_);
210   RemoveConsumerFromMap(consumer, &touch_id_target_for_gestures_);
211 }
212
213 void GestureRecognizerImpl::AddGestureEventHelper(GestureEventHelper* helper) {
214   helpers_.push_back(helper);
215 }
216
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())
222     helpers_.erase(it);
223 }
224
225 void GestureRecognizerImpl::DispatchPostponedGestureEvent(GestureEvent* event) {
226   GestureConsumer* consumer = GetTargetForGestureEvent(event);
227   if (consumer) {
228     GestureEventHelper* helper = FindDispatchHelperForConsumer(consumer);
229     if (helper)
230       helper->DispatchPostponedGestureEvent(event);
231   }
232 }
233
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))
239       return (*it);
240   }
241   return NULL;
242 }
243
244 // GestureRecognizer, static
245 GestureRecognizer* GestureRecognizer::Create() {
246   return new GestureRecognizerImpl();
247 }
248
249 static GestureRecognizerImpl* g_gesture_recognizer_instance = NULL;
250
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;
256 }
257
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);
265
266   helpers.clear();
267   g_gesture_recognizer_instance =
268       static_cast<GestureRecognizerImpl*>(gesture_recognizer);
269 }
270
271 }  // namespace ui