| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/aura/gestures/gesture_recognizer_aura.h" | 5 #include "ui/aura/gestures/gesture_recognizer_aura.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/memory/scoped_ptr.h" | 8 #include "base/memory/scoped_ptr.h" |
| 9 #include "base/time.h" | 9 #include "base/time.h" |
| 10 #include "ui/aura/event.h" | 10 #include "ui/aura/event.h" |
| 11 #include "ui/aura/gestures/gesture_sequence.h" |
| 11 #include "ui/base/events.h" | 12 #include "ui/base/events.h" |
| 12 | 13 |
| 13 namespace { | 14 namespace { |
| 14 // TODO(girard): Make these configurable in sync with this CL | |
| 15 // http://crbug.com/100773 | |
| 16 const double kMaximumTouchDownDurationInSecondsForClick = 0.8; | |
| 17 const double kMinimumTouchDownDurationInSecondsForClick = 0.01; | |
| 18 const double kMaximumSecondsBetweenDoubleClick = 0.7; | |
| 19 const int kMaximumTouchMoveInPixelsForClick = 20; | |
| 20 const float kMinFlickSpeedSquared = 550.f * 550.f; | |
| 21 | |
| 22 // This is used to pop a std::queue when returning from a function. | 15 // This is used to pop a std::queue when returning from a function. |
| 23 class ScopedPop { | 16 class ScopedPop { |
| 24 public: | 17 public: |
| 25 ScopedPop(std::queue<aura::TouchEvent*>* queue) : queue_(queue) { | 18 ScopedPop(std::queue<aura::TouchEvent*>* queue) : queue_(queue) { |
| 26 } | 19 } |
| 27 | 20 |
| 28 ~ScopedPop() { | 21 ~ScopedPop() { |
| 29 delete queue_->front(); | 22 delete queue_->front(); |
| 30 queue_->pop(); | 23 queue_->pop(); |
| 31 } | 24 } |
| 32 | 25 |
| 33 private: | 26 private: |
| 34 std::queue<aura::TouchEvent*>* queue_; | 27 std::queue<aura::TouchEvent*>* queue_; |
| 35 DISALLOW_COPY_AND_ASSIGN(ScopedPop); | 28 DISALLOW_COPY_AND_ASSIGN(ScopedPop); |
| 36 }; | 29 }; |
| 37 | 30 |
| 38 } // namespace | 31 } // namespace |
| 39 | 32 |
| 40 namespace aura { | 33 namespace aura { |
| 41 | 34 |
| 42 namespace { | |
| 43 | |
| 44 // Get equivalent TouchState from EventType |type|. | |
| 45 GestureSequence::TouchState TouchEventTypeToTouchState(ui::EventType type) { | |
| 46 switch (type) { | |
| 47 case ui::ET_TOUCH_RELEASED: | |
| 48 return GestureSequence::TS_RELEASED; | |
| 49 case ui::ET_TOUCH_PRESSED: | |
| 50 return GestureSequence::TS_PRESSED; | |
| 51 case ui::ET_TOUCH_MOVED: | |
| 52 return GestureSequence::TS_MOVED; | |
| 53 case ui::ET_TOUCH_STATIONARY: | |
| 54 return GestureSequence::TS_STATIONARY; | |
| 55 case ui::ET_TOUCH_CANCELLED: | |
| 56 return GestureSequence::TS_CANCELLED; | |
| 57 default: | |
| 58 VLOG(1) << "Unknown Touch Event type"; | |
| 59 } | |
| 60 return GestureSequence::TS_UNKNOWN; | |
| 61 } | |
| 62 | |
| 63 } // namespace | |
| 64 | |
| 65 //////////////////////////////////////////////////////////////////////////////// | |
| 66 // GestureSequence Public: | |
| 67 | |
| 68 GestureSequence::GestureSequence() | |
| 69 : first_touch_time_(0.0), | |
| 70 state_(GestureSequence::GS_NO_GESTURE), | |
| 71 last_touch_time_(0.0), | |
| 72 last_click_time_(0.0), | |
| 73 x_velocity_(0.0), | |
| 74 y_velocity_(0.0), | |
| 75 flags_(0) { | |
| 76 } | |
| 77 | |
| 78 GestureSequence::~GestureSequence() { | |
| 79 } | |
| 80 | |
| 81 GestureSequence::Gestures* GestureSequence::ProcessTouchEventForGesture( | |
| 82 const TouchEvent& event, | |
| 83 ui::TouchStatus status) { | |
| 84 if (status != ui::TOUCH_STATUS_UNKNOWN) | |
| 85 return NULL; // The event was consumed by a touch sequence. | |
| 86 | |
| 87 scoped_ptr<Gestures> gestures(new Gestures()); | |
| 88 UpdateValues(event); | |
| 89 switch (Signature(state_, event.touch_id(), event.type(), false)) { | |
| 90 case GST_NO_GESTURE_FIRST_PRESSED: | |
| 91 TouchDown(event, gestures.get()); | |
| 92 break; | |
| 93 case GST_PENDING_SYNTHETIC_CLICK_FIRST_RELEASED: | |
| 94 Click(event, gestures.get()); | |
| 95 break; | |
| 96 case GST_PENDING_SYNTHETIC_CLICK_FIRST_MOVED: | |
| 97 case GST_PENDING_SYNTHETIC_CLICK_FIRST_STATIONARY: | |
| 98 InClickOrScroll(event, gestures.get()); | |
| 99 break; | |
| 100 case GST_PENDING_SYNTHETIC_CLICK_FIRST_CANCELLED: | |
| 101 NoGesture(event, gestures.get()); | |
| 102 break; | |
| 103 case GST_SCROLL_FIRST_MOVED: | |
| 104 InScroll(event, gestures.get()); | |
| 105 break; | |
| 106 case GST_SCROLL_FIRST_RELEASED: | |
| 107 case GST_SCROLL_FIRST_CANCELLED: | |
| 108 ScrollEnd(event, gestures.get()); | |
| 109 break; | |
| 110 } | |
| 111 return gestures.release(); | |
| 112 } | |
| 113 | |
| 114 void GestureSequence::Reset() { | |
| 115 first_touch_time_ = 0.0; | |
| 116 state_ = GestureSequence::GS_NO_GESTURE; | |
| 117 last_touch_time_ = 0.0; | |
| 118 last_touch_position_.SetPoint(0, 0); | |
| 119 x_velocity_ = 0.0; | |
| 120 y_velocity_ = 0.0; | |
| 121 } | |
| 122 | |
| 123 //////////////////////////////////////////////////////////////////////////////// | |
| 124 // GestureSequence Private: | |
| 125 | |
| 126 unsigned int GestureSequence::Signature(GestureState gesture_state, | |
| 127 unsigned int touch_id, | |
| 128 ui::EventType type, | |
| 129 bool touch_handled) { | |
| 130 CHECK((touch_id & 0xfff) == touch_id); | |
| 131 TouchState touch_state = TouchEventTypeToTouchState(type); | |
| 132 return 1 + ((touch_state & 0x7) << 1 | (touch_handled ? 1 << 4 : 0) | | |
| 133 ((touch_id & 0xfff) << 5) | (gesture_state << 17)); | |
| 134 } | |
| 135 | |
| 136 bool GestureSequence::IsInClickTimeWindow() { | |
| 137 double duration(last_touch_time_ - first_touch_time_); | |
| 138 return duration >= kMinimumTouchDownDurationInSecondsForClick && | |
| 139 duration < kMaximumTouchDownDurationInSecondsForClick; | |
| 140 } | |
| 141 | |
| 142 bool GestureSequence::IsInSecondClickTimeWindow() { | |
| 143 double duration(last_touch_time_ - last_click_time_); | |
| 144 return duration < kMaximumSecondsBetweenDoubleClick; | |
| 145 } | |
| 146 | |
| 147 bool GestureSequence::IsInsideManhattanSquare(const TouchEvent& event) { | |
| 148 int manhattanDistance = abs(event.x() - first_touch_position_.x()) + | |
| 149 abs(event.y() - first_touch_position_.y()); | |
| 150 return manhattanDistance < kMaximumTouchMoveInPixelsForClick; | |
| 151 } | |
| 152 | |
| 153 bool GestureSequence::IsSecondClickInsideManhattanSquare( | |
| 154 const TouchEvent& event) { | |
| 155 int manhattanDistance = abs(event.x() - last_click_position_.x()) + | |
| 156 abs(event.y() - last_click_position_.y()); | |
| 157 return manhattanDistance < kMaximumTouchMoveInPixelsForClick; | |
| 158 } | |
| 159 | |
| 160 bool GestureSequence::IsOverMinFlickSpeed() { | |
| 161 return (x_velocity_ * x_velocity_ + y_velocity_ * y_velocity_) > | |
| 162 kMinFlickSpeedSquared; | |
| 163 } | |
| 164 | |
| 165 void GestureSequence::AppendTapDownGestureEvent(const TouchEvent& event, | |
| 166 Gestures* gestures) { | |
| 167 gestures->push_back(linked_ptr<GestureEvent>(new GestureEvent( | |
| 168 ui::ET_GESTURE_TAP_DOWN, | |
| 169 first_touch_position_.x(), | |
| 170 first_touch_position_.y(), | |
| 171 event.flags(), | |
| 172 base::Time::FromDoubleT(last_touch_time_), | |
| 173 0.f, 0.f))); | |
| 174 } | |
| 175 | |
| 176 void GestureSequence::AppendClickGestureEvent(const TouchEvent& event, | |
| 177 Gestures* gestures) { | |
| 178 gestures->push_back(linked_ptr<GestureEvent>(new GestureEvent( | |
| 179 ui::ET_GESTURE_TAP, | |
| 180 first_touch_position_.x(), | |
| 181 first_touch_position_.y(), | |
| 182 event.flags(), | |
| 183 base::Time::FromDoubleT(last_touch_time_), | |
| 184 0.f, 0.f))); | |
| 185 } | |
| 186 | |
| 187 void GestureSequence::AppendDoubleClickGestureEvent(const TouchEvent& event, | |
| 188 Gestures* gestures) { | |
| 189 gestures->push_back(linked_ptr<GestureEvent>(new GestureEvent( | |
| 190 ui::ET_GESTURE_DOUBLE_TAP, | |
| 191 first_touch_position_.x(), | |
| 192 first_touch_position_.y(), | |
| 193 event.flags(), | |
| 194 base::Time::FromDoubleT(last_touch_time_), | |
| 195 0.f, 0.f))); | |
| 196 } | |
| 197 | |
| 198 void GestureSequence::AppendScrollGestureBegin(const TouchEvent& event, | |
| 199 Gestures* gestures) { | |
| 200 gestures->push_back(linked_ptr<GestureEvent>(new GestureEvent( | |
| 201 ui::ET_GESTURE_SCROLL_BEGIN, | |
| 202 event.x(), | |
| 203 event.y(), | |
| 204 event.flags(), | |
| 205 base::Time::FromDoubleT(last_touch_time_), | |
| 206 0.f, 0.f))); | |
| 207 } | |
| 208 | |
| 209 void GestureSequence::AppendScrollGestureEnd(const TouchEvent& event, | |
| 210 Gestures* gestures, | |
| 211 float x_velocity, | |
| 212 float y_velocity) { | |
| 213 gestures->push_back(linked_ptr<GestureEvent>(new GestureEvent( | |
| 214 ui::ET_GESTURE_SCROLL_END, | |
| 215 event.x(), | |
| 216 event.y(), | |
| 217 event.flags(), | |
| 218 base::Time::FromDoubleT(last_touch_time_), | |
| 219 x_velocity, y_velocity))); | |
| 220 } | |
| 221 | |
| 222 void GestureSequence:: AppendScrollGestureUpdate(const TouchEvent& event, | |
| 223 Gestures* gestures) { | |
| 224 float delta_x(event.x() - first_touch_position_.x()); | |
| 225 float delta_y(event.y() - first_touch_position_.y()); | |
| 226 | |
| 227 gestures->push_back(linked_ptr<GestureEvent>(new GestureEvent( | |
| 228 ui::ET_GESTURE_SCROLL_UPDATE, | |
| 229 event.x(), | |
| 230 event.y(), | |
| 231 event.flags(), | |
| 232 base::Time::FromDoubleT(last_touch_time_), | |
| 233 delta_x, delta_y))); | |
| 234 | |
| 235 first_touch_position_ = event.location(); | |
| 236 } | |
| 237 | |
| 238 void GestureSequence::UpdateValues(const TouchEvent& event) { | |
| 239 if (state_ != GS_NO_GESTURE && event.type() == ui::ET_TOUCH_MOVED) { | |
| 240 double interval(event.time_stamp().InSecondsF() - last_touch_time_); | |
| 241 x_velocity_ = (event.x() - last_touch_position_.x()) / interval; | |
| 242 y_velocity_ = (event.y() - last_touch_position_.y()) / interval; | |
| 243 } | |
| 244 last_touch_time_ = event.time_stamp().InSecondsF(); | |
| 245 last_touch_position_ = event.location(); | |
| 246 if (state_ == GS_NO_GESTURE) { | |
| 247 first_touch_time_ = last_touch_time_; | |
| 248 first_touch_position_ = event.location(); | |
| 249 x_velocity_ = 0.0; | |
| 250 y_velocity_ = 0.0; | |
| 251 } | |
| 252 } | |
| 253 | |
| 254 bool GestureSequence::Click(const TouchEvent& event, Gestures* gestures) { | |
| 255 bool gesture_added = false; | |
| 256 if (IsInClickTimeWindow() && IsInsideManhattanSquare(event)) { | |
| 257 gesture_added = true; | |
| 258 AppendClickGestureEvent(event, gestures); | |
| 259 if (IsInSecondClickTimeWindow() && | |
| 260 IsSecondClickInsideManhattanSquare(event)) | |
| 261 AppendDoubleClickGestureEvent(event, gestures); | |
| 262 last_click_time_ = last_touch_time_; | |
| 263 last_click_position_ = last_touch_position_; | |
| 264 } | |
| 265 Reset(); | |
| 266 return gesture_added; | |
| 267 } | |
| 268 | |
| 269 bool GestureSequence::InClickOrScroll(const TouchEvent& event, | |
| 270 Gestures* gestures) { | |
| 271 if (IsInClickTimeWindow() && IsInsideManhattanSquare(event)) { | |
| 272 SetState(GS_PENDING_SYNTHETIC_CLICK); | |
| 273 return false; | |
| 274 } | |
| 275 if (event.type() == ui::ET_TOUCH_MOVED && !IsInsideManhattanSquare(event)) { | |
| 276 AppendScrollGestureBegin(event, gestures); | |
| 277 AppendScrollGestureUpdate(event, gestures); | |
| 278 SetState(GS_SCROLL); | |
| 279 return true; | |
| 280 } | |
| 281 return false; | |
| 282 } | |
| 283 | |
| 284 bool GestureSequence::InScroll(const TouchEvent& event, Gestures* gestures) { | |
| 285 AppendScrollGestureUpdate(event, gestures); | |
| 286 return true; | |
| 287 } | |
| 288 | |
| 289 bool GestureSequence::NoGesture(const TouchEvent&, Gestures*) { | |
| 290 Reset(); | |
| 291 return false; | |
| 292 } | |
| 293 | |
| 294 bool GestureSequence::TouchDown(const TouchEvent& event, Gestures* gestures) { | |
| 295 AppendTapDownGestureEvent(event, gestures); | |
| 296 SetState(GS_PENDING_SYNTHETIC_CLICK); | |
| 297 return false; | |
| 298 } | |
| 299 | |
| 300 bool GestureSequence::ScrollEnd(const TouchEvent& event, Gestures* gestures) { | |
| 301 if (IsOverMinFlickSpeed() && event.type() != ui::ET_TOUCH_CANCELLED) | |
| 302 AppendScrollGestureEnd(event, gestures, x_velocity_, y_velocity_); | |
| 303 else | |
| 304 AppendScrollGestureEnd(event, gestures, 0.f, 0.f); | |
| 305 SetState(GS_NO_GESTURE); | |
| 306 Reset(); | |
| 307 return false; | |
| 308 } | |
| 309 | |
| 310 //////////////////////////////////////////////////////////////////////////////// | 35 //////////////////////////////////////////////////////////////////////////////// |
| 311 // GestureRecognizerAura, public: | 36 // GestureRecognizerAura, public: |
| 312 | 37 |
| 313 GestureRecognizerAura::GestureRecognizerAura() | 38 GestureRecognizerAura::GestureRecognizerAura() |
| 314 : default_sequence_(new GestureSequence()) { | 39 : default_sequence_(new GestureSequence()) { |
| 315 } | 40 } |
| 316 | 41 |
| 317 GestureRecognizerAura::~GestureRecognizerAura() { | 42 GestureRecognizerAura::~GestureRecognizerAura() { |
| 318 } | 43 } |
| 319 | 44 |
| 45 //////////////////////////////////////////////////////////////////////////////// |
| 46 // GestureRecognizerAura, private: |
| 47 |
| 320 GestureSequence::Gestures* GestureRecognizerAura::ProcessTouchEventForGesture( | 48 GestureSequence::Gestures* GestureRecognizerAura::ProcessTouchEventForGesture( |
| 321 const TouchEvent& event, | 49 const TouchEvent& event, |
| 322 ui::TouchStatus status) { | 50 ui::TouchStatus status) { |
| 323 return default_sequence_->ProcessTouchEventForGesture(event, status); | 51 return default_sequence_->ProcessTouchEventForGesture(event, status); |
| 324 } | 52 } |
| 325 | 53 |
| 326 void GestureRecognizerAura::QueueTouchEventForGesture(Window* window, | 54 void GestureRecognizerAura::QueueTouchEventForGesture(Window* window, |
| 327 const TouchEvent& event) { | 55 const TouchEvent& event) { |
| 328 if (!event_queue_[window]) | 56 if (!event_queue_[window]) |
| 329 event_queue_[window] = new std::queue<TouchEvent*>(); | 57 event_queue_[window] = new std::queue<TouchEvent*>(); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 362 event_queue_.erase(window); | 90 event_queue_.erase(window); |
| 363 } | 91 } |
| 364 } | 92 } |
| 365 | 93 |
| 366 // GestureRecognizer, static | 94 // GestureRecognizer, static |
| 367 GestureRecognizer* GestureRecognizer::Create() { | 95 GestureRecognizer* GestureRecognizer::Create() { |
| 368 return new GestureRecognizerAura(); | 96 return new GestureRecognizerAura(); |
| 369 } | 97 } |
| 370 | 98 |
| 371 } // namespace aura | 99 } // namespace aura |
| OLD | NEW |