Index: chrome/renderer/gesture_manager.cc |
diff --git a/chrome/renderer/gesture_manager.cc b/chrome/renderer/gesture_manager.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..7f57a84dbfa7ba406498d5580571c749c5a7760d |
--- /dev/null |
+++ b/chrome/renderer/gesture_manager.cc |
@@ -0,0 +1,151 @@ |
+// Copyright (c) 2010 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 "chrome/renderer/gesture_manager.h" |
+ |
+#include "chrome/renderer/render_widget.h" |
+#include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h" |
+#include "third_party/WebKit/WebKit/chromium/public/WebWidget.h" |
+ |
+using WebKit::WebInputEvent; |
+using WebKit::WebMouseEvent; |
+using WebKit::WebPoint; |
+using WebKit::WebTouchEvent; |
+using WebKit::WebTouchPoint; |
+using WebKit::WebWidget; |
+ |
+ |
+// TODO(rjkroege): Make these configurable programmatically. |
+// Maximum hold down (s) for a touch to be treated as a click. |
+static const double kMaxClickDownTime = .8; |
+ |
+// Minimum hold down (s) for a touch to be treated as a click. |
+static const double kMinClickDownTime = .01; |
+ |
+// Maximum manhattan displacement for touch motion to |
+// still be considered as a click. |
+static const int kMaxManhattanDistance = 20; |
+ |
+GestureManager::~GestureManager() { |
+} |
+ |
+GestureManager* GestureManager::Get() { |
+ return Singleton<GestureManager>::get(); |
+} |
+ |
+bool GestureManager::ProcessTouchEventForGesture(const WebTouchEvent& event, |
+ RenderWidget* source, |
+ bool previouslyHandled) { |
+ bool handled = false; |
+ for (int i = 0; i < event.touchPointsLength; i++) { |
+ const WebTouchPoint& p = event.touchPoints[i]; |
+ switch (candidate_gesture_) { |
+ case NO_GESTURE: |
+ if (!previouslyHandled && p.state == WebTouchPoint::StatePressed) { |
+ candidate_gesture_ = PENDING_SYNTHETIC_CLICK; |
+ first_touch_time_ = event.timeStampSeconds; |
+ first_touch_position_ = p.position; |
+ } |
+ break; |
+ case PENDING_SYNTHETIC_CLICK: |
+ if (p.state == WebTouchPoint::StateCancelled) { |
+ candidate_gesture_ = NO_GESTURE; |
+ } else if (p.state == WebTouchPoint::StatePressed) { |
+ NOTREACHED(); |
+ // Cleanup? Possibly not necessary. |
+ candidate_gesture_ = NO_GESTURE; |
+ } else if (p.state == WebTouchPoint::StateReleased |
+ && IsInClickTimeWindow(event.timeStampSeconds) |
+ && IsInsideManhattanSquare(p) |
+ && !previouslyHandled) { |
+ candidate_gesture_ = NO_GESTURE; |
+ DispatchSyntheticClick(source, event, p); |
+ handled = true; |
+ } else if ((p.state == WebTouchPoint::StateStationary |
+ || p.state == WebTouchPoint::StateMoved) |
+ && IsInClickTimeWindow(event.timeStampSeconds) |
+ && IsInsideManhattanSquare(p) |
+ && !previouslyHandled) { |
+ candidate_gesture_ = PENDING_SYNTHETIC_CLICK; |
+ } else if (p.state == WebTouchPoint::StateMoved |
+ && !IsInsideManhattanSquare(p) |
+ && !previouslyHandled) { |
+ ScrollViaTouchMotion(p, source); |
+ candidate_gesture_ = SCROLL; |
+ handled = true; |
+ } else if (p.state == WebTouchPoint::StateReleased) { |
+ candidate_gesture_ = NO_GESTURE; |
+ } |
+ break; |
+ case SCROLL: |
+ if (p.state == WebTouchPoint::StateMoved && !previouslyHandled) { |
+ ScrollViaTouchMotion(p, source); |
+ handled = true; |
+ } else if (p.state == WebTouchPoint::StateReleased) { |
+ candidate_gesture_ = NO_GESTURE; |
+ } else if (p.state == WebTouchPoint::StateCancelled) { |
+ // It may be necessary to anul the scroll here. |
+ candidate_gesture_ = NO_GESTURE; |
+ } |
+ break; |
+ } |
+ } |
+ return handled; |
+} |
+ |
+GestureManager::GestureManager() |
+ : candidate_gesture_(GestureManager::NO_GESTURE), |
+ first_touch_time_(0.0) { |
+} |
+ |
+void GestureManager::DispatchSyntheticClick(RenderWidget* w, |
+ const WebTouchEvent& event, |
+ const WebTouchPoint& p) { |
+ WebMouseEvent fake_mouse_down, fake_mouse_up; |
+ |
+ fake_mouse_down.type = WebInputEvent::MouseDown; |
+ fake_mouse_down.timeStampSeconds = event.timeStampSeconds; |
+ fake_mouse_down.button = WebMouseEvent::ButtonLeft; |
+ fake_mouse_down.clickCount = 1; |
+ fake_mouse_down.x = p.position.x; |
+ fake_mouse_down.y = p.position.y; |
+ fake_mouse_down.windowX = p.position.x; |
+ fake_mouse_down.windowY = p.position.y; |
+ fake_mouse_down.globalX = p.screenPosition.x; |
+ fake_mouse_down.globalY = p.screenPosition.y; |
+ |
+ fake_mouse_up.type = WebInputEvent::MouseUp; |
+ fake_mouse_up.timeStampSeconds = event.timeStampSeconds; |
+ fake_mouse_up.button = WebMouseEvent::ButtonLeft; |
+ fake_mouse_up.clickCount = 1; |
+ fake_mouse_up.x = p.position.x; |
+ fake_mouse_up.y = p.position.y; |
+ fake_mouse_up.windowX = p.position.x; |
+ fake_mouse_up.windowY = p.position.y; |
+ fake_mouse_up.globalX = p.screenPosition.x; |
+ fake_mouse_up.globalY = p.screenPosition.y; |
+ |
+ w->webwidget()->handleInputEvent(fake_mouse_down); |
+ w->webwidget()->handleInputEvent(fake_mouse_up); |
+} |
+ |
+bool GestureManager::IsInClickTimeWindow(const double ts) { |
+ double delta = ts - first_touch_time_; |
+ return delta >= kMinClickDownTime |
+ && delta < kMaxClickDownTime; |
+} |
+ |
+bool GestureManager::IsInsideManhattanSquare(const WebTouchPoint& p) { |
+ int manhattanDistance = abs(p.position.x - first_touch_position_.x) + |
+ abs(p.position.y - first_touch_position_.y); |
+ return manhattanDistance < kMaxManhattanDistance; |
+} |
+ |
+void GestureManager::ScrollViaTouchMotion(const WebTouchPoint& tp, |
+ RenderWidget *rw) { |
+ rw->webwidget()->gestureScroll(tp.position, tp.screenPosition, |
+ tp.position.x - first_touch_position_.x, |
+ tp.position.y - first_touch_position_.y); |
+ first_touch_position_ = tp.position; |
+} |