| 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;
|
| +}
|
|
|