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