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 <limits>
      8 
      9 #include "base/command_line.h"
     10 #include "base/logging.h"
     11 #include "base/memory/scoped_ptr.h"
     12 #include "base/message_loop/message_loop.h"
     13 #include "base/time/time.h"
     14 #include "ui/events/event.h"
     15 #include "ui/events/event_constants.h"
     16 #include "ui/events/event_switches.h"
     17 #include "ui/events/event_utils.h"
     18 #include "ui/events/gestures/gesture_configuration.h"
     19 #include "ui/events/gestures/gesture_sequence.h"
     20 #include "ui/events/gestures/gesture_types.h"
     21 #include "ui/events/gestures/unified_gesture_detector_enabled.h"
     22 
     23 namespace ui {
     24 
     25 namespace {
     26 
     27 template <typename T>
     28 void TransferConsumer(GestureConsumer* current_consumer,
     29                       GestureConsumer* new_consumer,
     30                       std::map<GestureConsumer*, T>* map) {
     31   if (map->count(current_consumer)) {
     32     (*map)[new_consumer] = (*map)[current_consumer];
     33     map->erase(current_consumer);
     34   }
     35 }
     36 
     37 bool RemoveConsumerFromMap(GestureConsumer* consumer,
     38                            GestureRecognizerImpl::TouchIdToConsumerMap* map) {
     39   bool consumer_removed = false;
     40   for (GestureRecognizerImpl::TouchIdToConsumerMap::iterator i = map->begin();
     41        i != map->end();) {
     42     if (i->second == consumer) {
     43       map->erase(i++);
     44       consumer_removed = true;
     45     } else {
     46       ++i;
     47     }
     48   }
     49   return consumer_removed;
     50 }
     51 
     52 void TransferTouchIdToConsumerMap(
     53     GestureConsumer* old_consumer,
     54     GestureConsumer* new_consumer,
     55     GestureRecognizerImpl::TouchIdToConsumerMap* map) {
     56   for (GestureRecognizerImpl::TouchIdToConsumerMap::iterator i = map->begin();
     57        i != map->end(); ++i) {
     58     if (i->second == old_consumer)
     59       i->second = new_consumer;
     60   }
     61 }
     62 
     63 GestureProviderAura* CreateGestureProvider(GestureProviderAuraClient* client) {
     64   return new GestureProviderAura(client);
     65 }
     66 
     67 }  // namespace
     68 
     69 ////////////////////////////////////////////////////////////////////////////////
     70 // GestureRecognizerImpl, public:
     71 
     72 GestureRecognizerImpl::GestureRecognizerImpl() {
     73   use_unified_gesture_detector_ = IsUnifiedGestureDetectorEnabled();
     74 }
     75 
     76 GestureRecognizerImpl::~GestureRecognizerImpl() {
     77   STLDeleteValues(&consumer_sequence_);
     78   STLDeleteValues(&consumer_gesture_provider_);
     79 }
     80 
     81 // Checks if this finger is already down, if so, returns the current target.
     82 // Otherwise, returns NULL.
     83 GestureConsumer* GestureRecognizerImpl::GetTouchLockedTarget(
     84     const TouchEvent& event) {
     85   return touch_id_target_[event.touch_id()];
     86 }
     87 
     88 GestureConsumer* GestureRecognizerImpl::GetTargetForGestureEvent(
     89     const GestureEvent& event) {
     90   GestureConsumer* target = NULL;
     91   int touch_id = event.GetLowestTouchId();
     92   target = touch_id_target_for_gestures_[touch_id];
     93   return target;
     94 }
     95 
     96 GestureConsumer* GestureRecognizerImpl::GetTargetForLocation(
     97     const gfx::PointF& location, int source_device_id) {
     98   const int max_distance =
     99       GestureConfiguration::max_separation_for_gesture_touches_in_pixels();
    100 
    101   if (!use_unified_gesture_detector_) {
    102     const GesturePoint* closest_point = NULL;
    103     int64 closest_distance_squared = 0;
    104     std::map<GestureConsumer*, GestureSequence*>::iterator i;
    105     for (i = consumer_sequence_.begin(); i != consumer_sequence_.end(); ++i) {
    106       const GesturePoint* points = i->second->points();
    107       for (int j = 0; j < GestureSequence::kMaxGesturePoints; ++j) {
    108         if (!points[j].in_use() ||
    109             source_device_id != points[j].source_device_id()) {
    110           continue;
    111         }
    112         gfx::Vector2dF delta = points[j].last_touch_position() - location;
    113         // Relative distance is all we need here, so LengthSquared() is
    114         // appropriate, and cheaper than Length().
    115         int64 distance_squared = delta.LengthSquared();
    116         if (!closest_point || distance_squared < closest_distance_squared) {
    117           closest_point = &points[j];
    118           closest_distance_squared = distance_squared;
    119         }
    120       }
    121     }
    122 
    123     if (closest_distance_squared < max_distance * max_distance && closest_point)
    124       return touch_id_target_[closest_point->touch_id()];
    125     else
    126       return NULL;
    127   } else {
    128     gfx::PointF closest_point;
    129     int closest_touch_id;
    130     float closest_distance_squared = std::numeric_limits<float>::infinity();
    131 
    132     std::map<GestureConsumer*, GestureProviderAura*>::iterator i;
    133     for (i = consumer_gesture_provider_.begin();
    134          i != consumer_gesture_provider_.end();
    135          ++i) {
    136       const MotionEventAura& pointer_state = i->second->pointer_state();
    137       for (size_t j = 0; j < pointer_state.GetPointerCount(); ++j) {
    138         if (source_device_id != pointer_state.GetSourceDeviceId(j))
    139           continue;
    140         gfx::PointF point(pointer_state.GetX(j), pointer_state.GetY(j));
    141         // Relative distance is all we need here, so LengthSquared() is
    142         // appropriate, and cheaper than Length().
    143         float distance_squared = (point - location).LengthSquared();
    144         if (distance_squared < closest_distance_squared) {
    145           closest_point = point;
    146           closest_touch_id = pointer_state.GetPointerId(j);
    147           closest_distance_squared = distance_squared;
    148         }
    149       }
    150     }
    151 
    152     if (closest_distance_squared < max_distance * max_distance)
    153       return touch_id_target_[closest_touch_id];
    154     else
    155       return NULL;
    156   }
    157 }
    158 
    159 void GestureRecognizerImpl::TransferEventsTo(GestureConsumer* current_consumer,
    160                                              GestureConsumer* new_consumer) {
    161   // Send cancel to all those save |new_consumer| and |current_consumer|.
    162   // Don't send a cancel to |current_consumer|, unless |new_consumer| is NULL.
    163   // Dispatching a touch-cancel event can end up altering |touch_id_target_|
    164   // (e.g. when the target of the event is destroyed, causing it to be removed
    165   // from |touch_id_target_| in |CleanupStateForConsumer()|). So create a list
    166   // of the touch-ids that need to be cancelled, and dispatch the cancel events
    167   // for them at the end.
    168   std::vector<std::pair<int, GestureConsumer*> > ids;
    169   for (TouchIdToConsumerMap::iterator i = touch_id_target_.begin();
    170        i != touch_id_target_.end(); ++i) {
    171     if (i->second && i->second != new_consumer &&
    172         (i->second != current_consumer || new_consumer == NULL) &&
    173         i->second) {
    174       ids.push_back(std::make_pair(i->first, i->second));
    175     }
    176   }
    177 
    178   CancelTouches(&ids);
    179 
    180   // Transfer events from |current_consumer| to |new_consumer|.
    181   if (current_consumer && new_consumer) {
    182     TransferTouchIdToConsumerMap(current_consumer, new_consumer,
    183                                  &touch_id_target_);
    184     TransferTouchIdToConsumerMap(current_consumer, new_consumer,
    185                                  &touch_id_target_for_gestures_);
    186     if (!use_unified_gesture_detector_)
    187       TransferConsumer(current_consumer, new_consumer, &consumer_sequence_);
    188     else
    189       TransferConsumer(
    190           current_consumer, new_consumer, &consumer_gesture_provider_);
    191   }
    192 }
    193 
    194 bool GestureRecognizerImpl::GetLastTouchPointForTarget(
    195     GestureConsumer* consumer,
    196     gfx::PointF* point) {
    197   if (!use_unified_gesture_detector_) {
    198     if (consumer_sequence_.count(consumer) == 0)
    199       return false;
    200     *point = consumer_sequence_[consumer]->last_touch_location();
    201     return true;
    202   } else {
    203     if (consumer_gesture_provider_.count(consumer) == 0)
    204       return false;
    205     const MotionEvent& pointer_state =
    206         consumer_gesture_provider_[consumer]->pointer_state();
    207     *point = gfx::PointF(pointer_state.GetX(), pointer_state.GetY());
    208     return true;
    209   }
    210 }
    211 
    212 bool GestureRecognizerImpl::CancelActiveTouches(GestureConsumer* consumer) {
    213   std::vector<std::pair<int, GestureConsumer*> > ids;
    214   for (TouchIdToConsumerMap::const_iterator i = touch_id_target_.begin();
    215        i != touch_id_target_.end(); ++i) {
    216     if (i->second == consumer)
    217       ids.push_back(std::make_pair(i->first, i->second));
    218   }
    219   bool cancelled_touch = !ids.empty();
    220   CancelTouches(&ids);
    221   return cancelled_touch;
    222 }
    223 
    224 ////////////////////////////////////////////////////////////////////////////////
    225 // GestureRecognizerImpl, protected:
    226 
    227 GestureSequence* GestureRecognizerImpl::CreateSequence(
    228     GestureSequenceDelegate* delegate) {
    229   return new GestureSequence(delegate);
    230 }
    231 
    232 ////////////////////////////////////////////////////////////////////////////////
    233 // GestureRecognizerImpl, private:
    234 
    235 GestureSequence* GestureRecognizerImpl::GetGestureSequenceForConsumer(
    236     GestureConsumer* consumer) {
    237   GestureSequence* gesture_sequence = consumer_sequence_[consumer];
    238   if (!gesture_sequence) {
    239     gesture_sequence = CreateSequence(this);
    240     consumer_sequence_[consumer] = gesture_sequence;
    241   }
    242   return gesture_sequence;
    243 }
    244 
    245 GestureProviderAura* GestureRecognizerImpl::GetGestureProviderForConsumer(
    246     GestureConsumer* consumer) {
    247   GestureProviderAura* gesture_provider = consumer_gesture_provider_[consumer];
    248   if (!gesture_provider) {
    249     gesture_provider = CreateGestureProvider(this);
    250     consumer_gesture_provider_[consumer] = gesture_provider;
    251   }
    252   return gesture_provider;
    253 }
    254 
    255 void GestureRecognizerImpl::SetupTargets(const TouchEvent& event,
    256                                          GestureConsumer* target) {
    257   if (event.type() == ui::ET_TOUCH_RELEASED ||
    258       event.type() == ui::ET_TOUCH_CANCELLED) {
    259     touch_id_target_.erase(event.touch_id());
    260   } else if (event.type() == ui::ET_TOUCH_PRESSED) {
    261     touch_id_target_[event.touch_id()] = target;
    262     if (target)
    263       touch_id_target_for_gestures_[event.touch_id()] = target;
    264   }
    265 }
    266 
    267 void GestureRecognizerImpl::CancelTouches(
    268     std::vector<std::pair<int, GestureConsumer*> >* touches) {
    269   while (!touches->empty()) {
    270     int touch_id = touches->begin()->first;
    271     GestureConsumer* target = touches->begin()->second;
    272     TouchEvent touch_event(ui::ET_TOUCH_CANCELLED, gfx::PointF(0, 0),
    273                            ui::EF_IS_SYNTHESIZED, touch_id,
    274                            ui::EventTimeForNow(), 0.0f, 0.0f, 0.0f, 0.0f);
    275     GestureEventHelper* helper = FindDispatchHelperForConsumer(target);
    276     if (helper)
    277       helper->DispatchCancelTouchEvent(&touch_event);
    278     touches->erase(touches->begin());
    279   }
    280 }
    281 
    282 void GestureRecognizerImpl::DispatchGestureEvent(GestureEvent* event) {
    283   GestureConsumer* consumer = GetTargetForGestureEvent(*event);
    284   if (consumer) {
    285     GestureEventHelper* helper = FindDispatchHelperForConsumer(consumer);
    286     if (helper)
    287       helper->DispatchGestureEvent(event);
    288   }
    289 }
    290 
    291 ScopedVector<GestureEvent>* GestureRecognizerImpl::ProcessTouchEventForGesture(
    292     const TouchEvent& event,
    293     ui::EventResult result,
    294     GestureConsumer* target) {
    295   SetupTargets(event, target);
    296 
    297   if (!use_unified_gesture_detector_) {
    298     GestureSequence* gesture_sequence = GetGestureSequenceForConsumer(target);
    299     return gesture_sequence->ProcessTouchEventForGesture(event, result);
    300   } else {
    301     GestureProviderAura* gesture_provider =
    302         GetGestureProviderForConsumer(target);
    303     // TODO(tdresser) - detect gestures eagerly.
    304     if (!(result & ER_CONSUMED)) {
    305       if (gesture_provider->OnTouchEvent(event)) {
    306         gesture_provider->OnTouchEventAck(result != ER_UNHANDLED);
    307         return gesture_provider->GetAndResetPendingGestures();
    308       }
    309     }
    310     return NULL;
    311   }
    312 }
    313 
    314 bool GestureRecognizerImpl::CleanupStateForConsumer(
    315     GestureConsumer* consumer) {
    316   bool state_cleaned_up = false;
    317 
    318   if (!use_unified_gesture_detector_) {
    319     if (consumer_sequence_.count(consumer)) {
    320       state_cleaned_up = true;
    321       delete consumer_sequence_[consumer];
    322       consumer_sequence_.erase(consumer);
    323     }
    324   } else {
    325     if (consumer_gesture_provider_.count(consumer)) {
    326       state_cleaned_up = true;
    327       delete consumer_gesture_provider_[consumer];
    328       consumer_gesture_provider_.erase(consumer);
    329     }
    330   }
    331 
    332   state_cleaned_up |= RemoveConsumerFromMap(consumer, &touch_id_target_);
    333   state_cleaned_up |=
    334       RemoveConsumerFromMap(consumer, &touch_id_target_for_gestures_);
    335   return state_cleaned_up;
    336 }
    337 
    338 void GestureRecognizerImpl::AddGestureEventHelper(GestureEventHelper* helper) {
    339   helpers_.push_back(helper);
    340 }
    341 
    342 void GestureRecognizerImpl::RemoveGestureEventHelper(
    343     GestureEventHelper* helper) {
    344   std::vector<GestureEventHelper*>::iterator it = std::find(helpers_.begin(),
    345       helpers_.end(), helper);
    346   if (it != helpers_.end())
    347     helpers_.erase(it);
    348 }
    349 
    350 void GestureRecognizerImpl::DispatchPostponedGestureEvent(GestureEvent* event) {
    351   DispatchGestureEvent(event);
    352 }
    353 
    354 void GestureRecognizerImpl::OnGestureEvent(GestureEvent* event) {
    355   DispatchGestureEvent(event);
    356 }
    357 
    358 GestureEventHelper* GestureRecognizerImpl::FindDispatchHelperForConsumer(
    359     GestureConsumer* consumer) {
    360   std::vector<GestureEventHelper*>::iterator it;
    361   for (it = helpers_.begin(); it != helpers_.end(); ++it) {
    362     if ((*it)->CanDispatchToConsumer(consumer))
    363       return (*it);
    364   }
    365   return NULL;
    366 }
    367 
    368 // GestureRecognizer, static
    369 GestureRecognizer* GestureRecognizer::Create() {
    370   return new GestureRecognizerImpl();
    371 }
    372 
    373 static GestureRecognizerImpl* g_gesture_recognizer_instance = NULL;
    374 
    375 // GestureRecognizer, static
    376 GestureRecognizer* GestureRecognizer::Get() {
    377   if (!g_gesture_recognizer_instance)
    378     g_gesture_recognizer_instance = new GestureRecognizerImpl();
    379   return g_gesture_recognizer_instance;
    380 }
    381 
    382 // GestureRecognizer, static
    383 void GestureRecognizer::Reset() {
    384   delete g_gesture_recognizer_instance;
    385   g_gesture_recognizer_instance = NULL;
    386 }
    387 
    388 void SetGestureRecognizerForTesting(GestureRecognizer* gesture_recognizer) {
    389   // Transfer helpers to the new GR.
    390   std::vector<GestureEventHelper*>& helpers =
    391       g_gesture_recognizer_instance->helpers();
    392   std::vector<GestureEventHelper*>::iterator it;
    393   for (it = helpers.begin(); it != helpers.end(); ++it)
    394     gesture_recognizer->AddGestureEventHelper(*it);
    395 
    396   helpers.clear();
    397   g_gesture_recognizer_instance =
    398       static_cast<GestureRecognizerImpl*>(gesture_recognizer);
    399 }
    400 
    401 }  // namespace ui
    402