Home | History | Annotate | Download | only in gestures
      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     const TouchEvent& event) {
     69   return touch_id_target_[event.touch_id()];
     70 }
     71 
     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 
     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   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 
    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 
    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 
    165 GestureSequence* GestureRecognizerImpl::CreateSequence(
    166     GestureSequenceDelegate* delegate) {
    167   return new GestureSequence(delegate);
    168 }
    169 
    170 ////////////////////////////////////////////////////////////////////////////////
    171 // GestureRecognizerImpl, private:
    172 
    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 
    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 
    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 
    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 
    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 
    229 void GestureRecognizerImpl::AddGestureEventHelper(GestureEventHelper* helper) {
    230   helpers_.push_back(helper);
    231 }
    232 
    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 
    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 
    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
    261 GestureRecognizer* GestureRecognizer::Create() {
    262   return new GestureRecognizerImpl();
    263 }
    264 
    265 static GestureRecognizerImpl* g_gesture_recognizer_instance = NULL;
    266 
    267 // GestureRecognizer, static
    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 
    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