summaryrefslogtreecommitdiffstats
path: root/ui/aura/gestures/gesture_recognizer.cc
diff options
context:
space:
mode:
authorsadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-01-19 00:48:01 +0000
committersadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-01-19 00:48:01 +0000
commit912b6f3be7f1e31b4107ecb8b572245d9f65ff47 (patch)
treed43a9f10d01316cc817cd7619f1561e0ed279e04 /ui/aura/gestures/gesture_recognizer.cc
parent7d692835b4257b2621f969037f52e1dca67d833e (diff)
downloadchromium_src-912b6f3be7f1e31b4107ecb8b572245d9f65ff47.zip
chromium_src-912b6f3be7f1e31b4107ecb8b572245d9f65ff47.tar.gz
chromium_src-912b6f3be7f1e31b4107ecb8b572245d9f65ff47.tar.bz2
aura: Move GestureRecognizer from views into aura.
Remove deprecated GestureManager, and move the functional GestureRecognizer from views into aura. BUG=110227 TEST=views_unittests:GestureEvent, aura_unittests:GestureRecognizerTest Review URL: https://chromiumcodereview.appspot.com/9255019 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@118200 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/aura/gestures/gesture_recognizer.cc')
-rw-r--r--ui/aura/gestures/gesture_recognizer.cc289
1 files changed, 289 insertions, 0 deletions
diff --git a/ui/aura/gestures/gesture_recognizer.cc b/ui/aura/gestures/gesture_recognizer.cc
new file mode 100644
index 0000000..8787282
--- /dev/null
+++ b/ui/aura/gestures/gesture_recognizer.cc
@@ -0,0 +1,289 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/aura/gestures/gesture_recognizer.h"
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/time.h"
+#include "ui/aura/event.h"
+#include "ui/base/events.h"
+
+namespace {
+// TODO(Gajen): Make these configurable in sync with this CL http://code.google.
+// com/p/chromium/issues/detail?id=100773.
+const double kMaximumTouchDownDurationInSecondsForClick = 0.8;
+const double kMinimumTouchDownDurationInSecondsForClick = 0.01;
+const double kMaximumSecondsBetweenDoubleClick = 0.7;
+const int kMaximumTouchMoveInPixelsForClick = 20;
+const float kMinFlickSpeedSquared = 550.f * 550.f;
+
+} // namespace
+
+namespace aura {
+
+////////////////////////////////////////////////////////////////////////////////
+// GestureRecognizer Public:
+
+GestureRecognizer::GestureRecognizer()
+ : first_touch_time_(0.0),
+ state_(GestureRecognizer::GS_NO_GESTURE),
+ last_touch_time_(0.0),
+ last_click_time_(0.0),
+ x_velocity_(0.0),
+ y_velocity_(0.0),
+ flags_(0) {
+}
+
+GestureRecognizer::~GestureRecognizer() {
+}
+
+GestureRecognizer* GestureRecognizer::GetInstance() {
+ return Singleton<GestureRecognizer>::get();
+}
+
+GestureRecognizer::Gestures* GestureRecognizer::ProcessTouchEventForGesture(
+ const TouchEvent& event,
+ ui::TouchStatus status) {
+ if (status != ui::TOUCH_STATUS_UNKNOWN)
+ return NULL; // The event was consumed by a touch sequence.
+
+ scoped_ptr<Gestures> gestures(new Gestures());
+ UpdateValues(event);
+ switch (Signature(state_, event.touch_id(), event.type(), false)) {
+ case GST_NO_GESTURE_FIRST_PRESSED:
+ TouchDown(event, gestures.get());
+ break;
+ case GST_PENDING_SYNTHETIC_CLICK_FIRST_RELEASED:
+ Click(event, gestures.get());
+ break;
+ case GST_PENDING_SYNTHETIC_CLICK_FIRST_MOVED:
+ case GST_PENDING_SYNTHETIC_CLICK_FIRST_STATIONARY:
+ InClickOrScroll(event, gestures.get());
+ break;
+ case GST_PENDING_SYNTHETIC_CLICK_FIRST_CANCELLED:
+ NoGesture(event, gestures.get());
+ break;
+ case GST_SCROLL_FIRST_MOVED:
+ InScroll(event, gestures.get());
+ break;
+ case GST_SCROLL_FIRST_RELEASED:
+ case GST_SCROLL_FIRST_CANCELLED:
+ ScrollEnd(event, gestures.get());
+ break;
+ }
+ return gestures.release();
+}
+
+void GestureRecognizer::Reset() {
+ first_touch_time_ = 0.0;
+ state_ = GestureRecognizer::GS_NO_GESTURE;
+ last_touch_time_ = 0.0;
+ last_touch_position_.SetPoint(0, 0);
+ x_velocity_ = 0.0;
+ y_velocity_ = 0.0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// GestureRecognizer Private:
+
+// static
+GestureRecognizer::TouchState GestureRecognizer::TouchEventTypeToTouchState(
+ ui::EventType type) {
+ switch (type) {
+ case ui::ET_TOUCH_RELEASED: return TS_RELEASED;
+ case ui::ET_TOUCH_PRESSED: return TS_PRESSED;
+ case ui::ET_TOUCH_MOVED: return TS_MOVED;
+ case ui::ET_TOUCH_STATIONARY: return TS_STATIONARY;
+ case ui::ET_TOUCH_CANCELLED: return TS_CANCELLED;
+ default:
+ VLOG(1) << "Unknown Touch Event type";
+ }
+ return TS_UNKNOWN;
+}
+
+unsigned int GestureRecognizer::Signature(GestureState gesture_state,
+ unsigned int touch_id, ui::EventType type,
+ bool touch_handled) {
+ CHECK((touch_id & 0xfff) == touch_id);
+ TouchState touch_state = TouchEventTypeToTouchState(type);
+ return 1 + ((touch_state & 0x7) << 1 | (touch_handled ? 1 << 4 : 0) |
+ ((touch_id & 0xfff) << 5) | (gesture_state << 17));
+}
+
+bool GestureRecognizer::IsInClickTimeWindow() {
+ double duration(last_touch_time_ - first_touch_time_);
+ return duration >= kMinimumTouchDownDurationInSecondsForClick &&
+ duration < kMaximumTouchDownDurationInSecondsForClick;
+}
+
+bool GestureRecognizer::IsInSecondClickTimeWindow() {
+ double duration(last_touch_time_ - last_click_time_);
+ return duration < kMaximumSecondsBetweenDoubleClick;
+}
+
+bool GestureRecognizer::IsInsideManhattanSquare(const TouchEvent& event) {
+ int manhattanDistance = abs(event.x() - first_touch_position_.x()) +
+ abs(event.y() - first_touch_position_.y());
+ return manhattanDistance < kMaximumTouchMoveInPixelsForClick;
+}
+
+bool GestureRecognizer::IsSecondClickInsideManhattanSquare(
+ const TouchEvent& event) {
+ int manhattanDistance = abs(event.x() - last_click_position_.x()) +
+ abs(event.y() - last_click_position_.y());
+ return manhattanDistance < kMaximumTouchMoveInPixelsForClick;
+}
+
+bool GestureRecognizer::IsOverMinFlickSpeed() {
+ return (x_velocity_ * x_velocity_ + y_velocity_ * y_velocity_) >
+ kMinFlickSpeedSquared;
+}
+
+void GestureRecognizer::AppendTapDownGestureEvent(const TouchEvent& event,
+ Gestures* gestures) {
+ gestures->push_back(linked_ptr<GestureEvent>(new GestureEvent(
+ ui::ET_GESTURE_TAP_DOWN,
+ first_touch_position_.x(),
+ first_touch_position_.y(),
+ event.flags(),
+ base::Time::FromDoubleT(last_touch_time_),
+ 0.f, 0.f)));
+}
+
+void GestureRecognizer::AppendClickGestureEvent(const TouchEvent& event,
+ Gestures* gestures) {
+ gestures->push_back(linked_ptr<GestureEvent>(new GestureEvent(
+ ui::ET_GESTURE_TAP,
+ first_touch_position_.x(),
+ first_touch_position_.y(),
+ event.flags(),
+ base::Time::FromDoubleT(last_touch_time_),
+ 0.f, 0.f)));
+}
+
+void GestureRecognizer::AppendDoubleClickGestureEvent(const TouchEvent& event,
+ Gestures* gestures) {
+ gestures->push_back(linked_ptr<GestureEvent>(new GestureEvent(
+ ui::ET_GESTURE_DOUBLE_TAP,
+ first_touch_position_.x(),
+ first_touch_position_.y(),
+ event.flags(),
+ base::Time::FromDoubleT(last_touch_time_),
+ 0.f, 0.f)));
+}
+
+void GestureRecognizer::AppendScrollGestureBegin(const TouchEvent& event,
+ Gestures* gestures) {
+ gestures->push_back(linked_ptr<GestureEvent>(new GestureEvent(
+ ui::ET_GESTURE_SCROLL_BEGIN,
+ event.x(),
+ event.y(),
+ event.flags(),
+ base::Time::FromDoubleT(last_touch_time_),
+ 0.f, 0.f)));
+}
+
+void GestureRecognizer::AppendScrollGestureEnd(const TouchEvent& event,
+ Gestures* gestures,
+ float x_velocity,
+ float y_velocity) {
+ gestures->push_back(linked_ptr<GestureEvent>(new GestureEvent(
+ ui::ET_GESTURE_SCROLL_END,
+ event.x(),
+ event.y(),
+ event.flags(),
+ base::Time::FromDoubleT(last_touch_time_),
+ x_velocity, y_velocity)));
+}
+
+void GestureRecognizer:: AppendScrollGestureUpdate(const TouchEvent& event,
+ Gestures* gestures) {
+ float delta_x(event.x() - first_touch_position_.x());
+ float delta_y(event.y() - first_touch_position_.y());
+
+ gestures->push_back(linked_ptr<GestureEvent>(new GestureEvent(
+ ui::ET_GESTURE_SCROLL_UPDATE,
+ event.x(),
+ event.y(),
+ event.flags(),
+ base::Time::FromDoubleT(last_touch_time_),
+ delta_x, delta_y)));
+
+ first_touch_position_ = event.location();
+}
+
+void GestureRecognizer::UpdateValues(const TouchEvent& event) {
+ if (state_ != GS_NO_GESTURE && event.type() == ui::ET_TOUCH_MOVED) {
+ double interval(event.time_stamp().InSecondsF() - last_touch_time_);
+ x_velocity_ = (event.x() - last_touch_position_.x()) / interval;
+ y_velocity_ = (event.y() - last_touch_position_.y()) / interval;
+ }
+ last_touch_time_ = event.time_stamp().InSecondsF();
+ last_touch_position_ = event.location();
+ if (state_ == GS_NO_GESTURE) {
+ first_touch_time_ = last_touch_time_;
+ first_touch_position_ = event.location();
+ x_velocity_ = 0.0;
+ y_velocity_ = 0.0;
+ }
+}
+
+bool GestureRecognizer::Click(const TouchEvent& event, Gestures* gestures) {
+ bool gesture_added = false;
+ if (IsInClickTimeWindow() && IsInsideManhattanSquare(event)) {
+ gesture_added = true;
+ AppendClickGestureEvent(event, gestures);
+ if (IsInSecondClickTimeWindow() &&
+ IsSecondClickInsideManhattanSquare(event))
+ AppendDoubleClickGestureEvent(event, gestures);
+ last_click_time_ = last_touch_time_;
+ last_click_position_ = last_touch_position_;
+ }
+ Reset();
+ return gesture_added;
+}
+
+bool GestureRecognizer::InClickOrScroll(const TouchEvent& event,
+ Gestures* gestures) {
+ if (IsInClickTimeWindow() && IsInsideManhattanSquare(event)) {
+ SetState(GS_PENDING_SYNTHETIC_CLICK);
+ return false;
+ }
+ if (event.type() == ui::ET_TOUCH_MOVED && !IsInsideManhattanSquare(event)) {
+ AppendScrollGestureBegin(event, gestures);
+ AppendScrollGestureUpdate(event, gestures);
+ SetState(GS_SCROLL);
+ return true;
+ }
+ return false;
+}
+
+bool GestureRecognizer::InScroll(const TouchEvent& event, Gestures* gestures) {
+ AppendScrollGestureUpdate(event, gestures);
+ return true;
+}
+
+bool GestureRecognizer::NoGesture(const TouchEvent&, Gestures*) {
+ Reset();
+ return false;
+}
+
+bool GestureRecognizer::TouchDown(const TouchEvent& event, Gestures* gestures) {
+ AppendTapDownGestureEvent(event, gestures);
+ SetState(GS_PENDING_SYNTHETIC_CLICK);
+ return false;
+}
+
+bool GestureRecognizer::ScrollEnd(const TouchEvent& event, Gestures* gestures) {
+ if (IsOverMinFlickSpeed() && event.type() != ui::ET_TOUCH_CANCELLED)
+ AppendScrollGestureEnd(event, gestures, x_velocity_, y_velocity_);
+ else
+ AppendScrollGestureEnd(event, gestures, 0.f, 0.f);
+ SetState(GS_NO_GESTURE);
+ Reset();
+ return false;
+}
+
+} // namespace aura