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/base/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/base/events/event.h"
     11 #include "ui/base/events/event_constants.h"
     12 #include "ui/base/events/event_utils.h"
     13 #include "ui/base/gestures/gesture_configuration.h"
     14 #include "ui/base/gestures/gesture_sequence.h"
     15 #include "ui/base/gestures/gesture_types.h"
     16 
     17 namespace ui {
     18 
     19 namespace {
     20 
     21 // CancelledTouchEvent mirrors a TouchEvent object.
     22 class MirroredTouchEvent : public TouchEvent {
     23  public:
     24   explicit MirroredTouchEvent(const TouchEvent* real)
     25       : TouchEvent(real->type(),
     26                    real->location(),
     27                    real->touch_id(),
     28                    real->time_stamp()) {
     29     set_flags(real->flags());
     30     set_radius(real->radius_x(), real->radius_y());
     31     set_rotation_angle(real->rotation_angle());
     32     set_force(real->force());
     33   }
     34 
     35   virtual ~MirroredTouchEvent() {
     36   }
     37 
     38  private:
     39   DISALLOW_COPY_AND_ASSIGN(MirroredTouchEvent);
     40 };
     41 
     42 // A mirrored event, except for the type, which is always ET_TOUCH_CANCELLED.
     43 class CancelledTouchEvent : public MirroredTouchEvent {
     44  public:
     45   explicit CancelledTouchEvent(const TouchEvent* src)
     46       : MirroredTouchEvent(src) {
     47     SetType(ET_TOUCH_CANCELLED);
     48   }
     49 
     50   virtual ~CancelledTouchEvent() {}
     51 
     52  private:
     53   DISALLOW_COPY_AND_ASSIGN(CancelledTouchEvent);
     54 };
     55 
     56 // Touches which are cancelled by a touch capture are routed to a
     57 // GestureEventIgnorer, which ignores them.
     58 class GestureConsumerIgnorer : public GestureConsumer {
     59  public:
     60   GestureConsumerIgnorer()
     61       : GestureConsumer(true) {
     62   }
     63 };
     64 
     65 template <typename T>
     66 void TransferConsumer(GestureConsumer* current_consumer,
     67                       GestureConsumer* new_consumer,
     68                       std::map<GestureConsumer*, T>* map) {
     69   if (map->count(current_consumer)) {
     70     (*map)[new_consumer] = (*map)[current_consumer];
     71     map->erase(current_consumer);
     72   }
     73 }
     74 
     75 void RemoveConsumerFromMap(GestureConsumer* consumer,
     76                            GestureRecognizerImpl::TouchIdToConsumerMap* map) {
     77   for (GestureRecognizerImpl::TouchIdToConsumerMap::iterator i = map->begin();
     78        i != map->end();) {
     79     if (i->second == consumer)
     80       map->erase(i++);
     81     else
     82       ++i;
     83   }
     84 }
     85 
     86 void TransferTouchIdToConsumerMap(
     87     GestureConsumer* old_consumer,
     88     GestureConsumer* new_consumer,
     89     GestureRecognizerImpl::TouchIdToConsumerMap* map) {
     90   for (GestureRecognizerImpl::TouchIdToConsumerMap::iterator i = map->begin();
     91        i != map->end(); ++i) {
     92     if (i->second == old_consumer)
     93       i->second = new_consumer;
     94   }
     95 }
     96 
     97 }  // namespace
     98 
     99 ////////////////////////////////////////////////////////////////////////////////
    100 // GestureRecognizerImpl, public:
    101 
    102 GestureRecognizerImpl::GestureRecognizerImpl(GestureEventHelper* helper)
    103     : helper_(helper) {
    104   gesture_consumer_ignorer_.reset(new GestureConsumerIgnorer());
    105 }
    106 
    107 GestureRecognizerImpl::~GestureRecognizerImpl() {
    108   STLDeleteValues(&consumer_sequence_);
    109 }
    110 
    111 // Checks if this finger is already down, if so, returns the current target.
    112 // Otherwise, returns NULL.
    113 GestureConsumer* GestureRecognizerImpl::GetTouchLockedTarget(
    114     TouchEvent* event) {
    115   return touch_id_target_[event->touch_id()];
    116 }
    117 
    118 GestureConsumer* GestureRecognizerImpl::GetTargetForGestureEvent(
    119     GestureEvent* event) {
    120   GestureConsumer* target = NULL;
    121   int touch_id = event->GetLowestTouchId();
    122   target = touch_id_target_for_gestures_[touch_id];
    123   return target;
    124 }
    125 
    126 GestureConsumer* GestureRecognizerImpl::GetTargetForLocation(
    127     const gfx::Point& location) {
    128   const GesturePoint* closest_point = NULL;
    129   int64 closest_distance_squared = 0;
    130   std::map<GestureConsumer*, GestureSequence*>::iterator i;
    131   for (i = consumer_sequence_.begin(); i != consumer_sequence_.end(); ++i) {
    132     const GesturePoint* points = i->second->points();
    133     for (int j = 0; j < GestureSequence::kMaxGesturePoints; ++j) {
    134       if (!points[j].in_use())
    135         continue;
    136       gfx::Vector2d delta = points[j].last_touch_position() - location;
    137       // Relative distance is all we need here, so LengthSquared() is
    138       // appropriate, and cheaper than Length().
    139       int64 distance_squared = delta.LengthSquared();
    140       if (!closest_point || distance_squared < closest_distance_squared) {
    141         closest_point = &points[j];
    142         closest_distance_squared = distance_squared;
    143       }
    144     }
    145   }
    146 
    147   const int max_distance =
    148       GestureConfiguration::max_separation_for_gesture_touches_in_pixels();
    149 
    150   if (closest_distance_squared < max_distance * max_distance && closest_point)
    151     return touch_id_target_[closest_point->touch_id()];
    152   else
    153     return NULL;
    154 }
    155 
    156 void GestureRecognizerImpl::TransferEventsTo(GestureConsumer* current_consumer,
    157                                              GestureConsumer* new_consumer) {
    158   // Send cancel to all those save |new_consumer| and |current_consumer|.
    159   // Don't send a cancel to |current_consumer|, unless |new_consumer| is NULL.
    160   for (TouchIdToConsumerMap::iterator i = touch_id_target_.begin();
    161        i != touch_id_target_.end(); ++i) {
    162     if (i->second != new_consumer &&
    163         (i->second != current_consumer || new_consumer == NULL) &&
    164         i->second != gesture_consumer_ignorer_.get()) {
    165       TouchEvent touch_event(ui::ET_TOUCH_CANCELLED, gfx::Point(0, 0),
    166                              ui::EF_IS_SYNTHESIZED, i->first,
    167                              ui::EventTimeForNow(), 0.0f, 0.0f, 0.0f, 0.0f);
    168       helper_->DispatchCancelTouchEvent(&touch_event);
    169       DCHECK_EQ(gesture_consumer_ignorer_.get(), i->second);
    170     }
    171   }
    172 
    173   // Transfer events from |current_consumer| to |new_consumer|.
    174   if (current_consumer && new_consumer) {
    175     TransferTouchIdToConsumerMap(current_consumer, new_consumer,
    176                                  &touch_id_target_);
    177     TransferTouchIdToConsumerMap(current_consumer, new_consumer,
    178                                  &touch_id_target_for_gestures_);
    179     TransferConsumer(current_consumer, new_consumer, &consumer_sequence_);
    180   }
    181 }
    182 
    183 bool GestureRecognizerImpl::GetLastTouchPointForTarget(
    184     GestureConsumer* consumer,
    185     gfx::Point* point) {
    186   if (consumer_sequence_.count(consumer) == 0)
    187     return false;
    188 
    189   *point = consumer_sequence_[consumer]->last_touch_location();
    190   return true;
    191 }
    192 
    193 ////////////////////////////////////////////////////////////////////////////////
    194 // GestureRecognizerImpl, protected:
    195 
    196 GestureSequence* GestureRecognizerImpl::CreateSequence(
    197     GestureEventHelper* helper) {
    198   return new GestureSequence(helper);
    199 }
    200 
    201 ////////////////////////////////////////////////////////////////////////////////
    202 // GestureRecognizerImpl, private:
    203 
    204 GestureSequence* GestureRecognizerImpl::GetGestureSequenceForConsumer(
    205     GestureConsumer* consumer) {
    206   GestureSequence* gesture_sequence = consumer_sequence_[consumer];
    207   if (!gesture_sequence) {
    208     gesture_sequence = CreateSequence(helper_);
    209     consumer_sequence_[consumer] = gesture_sequence;
    210   }
    211   return gesture_sequence;
    212 }
    213 
    214 void GestureRecognizerImpl::SetupTargets(const TouchEvent& event,
    215                                          GestureConsumer* target) {
    216   if (event.type() == ui::ET_TOUCH_RELEASED) {
    217     touch_id_target_.erase(event.touch_id());
    218   } else if (event.type() == ui::ET_TOUCH_CANCELLED) {
    219     touch_id_target_[event.touch_id()] = gesture_consumer_ignorer_.get();
    220   } else {
    221     touch_id_target_[event.touch_id()] = target;
    222     if (target)
    223       touch_id_target_for_gestures_[event.touch_id()] = target;
    224   }
    225 }
    226 
    227 GestureSequence::Gestures* GestureRecognizerImpl::ProcessTouchEventForGesture(
    228     const TouchEvent& event,
    229     ui::EventResult result,
    230     GestureConsumer* target) {
    231   SetupTargets(event, target);
    232   GestureSequence* gesture_sequence = GetGestureSequenceForConsumer(target);
    233   return gesture_sequence->ProcessTouchEventForGesture(event, result);
    234 }
    235 
    236 void GestureRecognizerImpl::CleanupStateForConsumer(GestureConsumer* consumer) {
    237   if (consumer_sequence_.count(consumer)) {
    238     delete consumer_sequence_[consumer];
    239     consumer_sequence_.erase(consumer);
    240   }
    241 
    242   RemoveConsumerFromMap(consumer, &touch_id_target_);
    243   RemoveConsumerFromMap(consumer, &touch_id_target_for_gestures_);
    244 }
    245 
    246 // GestureRecognizer, static
    247 GestureRecognizer* GestureRecognizer::Create(GestureEventHelper* helper) {
    248   return new GestureRecognizerImpl(helper);
    249 }
    250 
    251 }  // namespace ui
    252