OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2010 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 "chrome/renderer/gesture_manager.h" |
| 6 |
| 7 #include "chrome/renderer/render_widget.h" |
| 8 #include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h" |
| 9 #include "third_party/WebKit/WebKit/chromium/public/WebWidget.h" |
| 10 |
| 11 using WebKit::WebInputEvent; |
| 12 using WebKit::WebMouseEvent; |
| 13 using WebKit::WebPoint; |
| 14 using WebKit::WebTouchEvent; |
| 15 using WebKit::WebTouchPoint; |
| 16 using WebKit::WebWidget; |
| 17 |
| 18 |
| 19 // TODO(rjkroege): Make these configurable programmatically. |
| 20 // Maximum hold down (s) for a touch to be treated as a click. |
| 21 static const double kMaxClickDownTime = .8; |
| 22 |
| 23 // Minimum hold down (s) for a touch to be treated as a click. |
| 24 static const double kMinClickDownTime = .01; |
| 25 |
| 26 // Maximum manhattan displacement for touch motion to |
| 27 // still be considered as a click. |
| 28 static const int kMaxManhattanDistance = 20; |
| 29 |
| 30 GestureManager::~GestureManager() { |
| 31 } |
| 32 |
| 33 GestureManager* GestureManager::Get() { |
| 34 return Singleton<GestureManager>::get(); |
| 35 } |
| 36 |
| 37 bool GestureManager::ProcessTouchEventForGesture(const WebTouchEvent& event, |
| 38 RenderWidget* source, |
| 39 bool previouslyHandled) { |
| 40 bool handled = false; |
| 41 for (int i = 0; i < event.touchPointsLength; i++) { |
| 42 const WebTouchPoint& p = event.touchPoints[i]; |
| 43 switch (candidate_gesture_) { |
| 44 case NO_GESTURE: |
| 45 if (!previouslyHandled && p.state == WebTouchPoint::StatePressed) { |
| 46 candidate_gesture_ = PENDING_SYNTHETIC_CLICK; |
| 47 first_touch_time_ = event.timeStampSeconds; |
| 48 first_touch_position_ = p.position; |
| 49 } |
| 50 break; |
| 51 case PENDING_SYNTHETIC_CLICK: |
| 52 if (p.state == WebTouchPoint::StateCancelled) { |
| 53 candidate_gesture_ = NO_GESTURE; |
| 54 } else if (p.state == WebTouchPoint::StatePressed) { |
| 55 NOTREACHED(); |
| 56 // Cleanup? Possibly not necessary. |
| 57 candidate_gesture_ = NO_GESTURE; |
| 58 } else if (p.state == WebTouchPoint::StateReleased |
| 59 && IsInClickTimeWindow(event.timeStampSeconds) |
| 60 && IsInsideManhattanSquare(p) |
| 61 && !previouslyHandled) { |
| 62 candidate_gesture_ = NO_GESTURE; |
| 63 DispatchSyntheticClick(source, event, p); |
| 64 handled = true; |
| 65 } else if ((p.state == WebTouchPoint::StateStationary |
| 66 || p.state == WebTouchPoint::StateMoved) |
| 67 && IsInClickTimeWindow(event.timeStampSeconds) |
| 68 && IsInsideManhattanSquare(p) |
| 69 && !previouslyHandled) { |
| 70 candidate_gesture_ = PENDING_SYNTHETIC_CLICK; |
| 71 } else if (p.state == WebTouchPoint::StateMoved |
| 72 && !IsInsideManhattanSquare(p) |
| 73 && !previouslyHandled) { |
| 74 ScrollViaTouchMotion(p, source); |
| 75 candidate_gesture_ = SCROLL; |
| 76 handled = true; |
| 77 } else if (p.state == WebTouchPoint::StateReleased) { |
| 78 candidate_gesture_ = NO_GESTURE; |
| 79 } |
| 80 break; |
| 81 case SCROLL: |
| 82 if (p.state == WebTouchPoint::StateMoved && !previouslyHandled) { |
| 83 ScrollViaTouchMotion(p, source); |
| 84 handled = true; |
| 85 } else if (p.state == WebTouchPoint::StateReleased) { |
| 86 candidate_gesture_ = NO_GESTURE; |
| 87 } else if (p.state == WebTouchPoint::StateCancelled) { |
| 88 // It may be necessary to anul the scroll here. |
| 89 candidate_gesture_ = NO_GESTURE; |
| 90 } |
| 91 break; |
| 92 } |
| 93 } |
| 94 return handled; |
| 95 } |
| 96 |
| 97 GestureManager::GestureManager() |
| 98 : candidate_gesture_(GestureManager::NO_GESTURE), |
| 99 first_touch_time_(0.0) { |
| 100 } |
| 101 |
| 102 void GestureManager::DispatchSyntheticClick(RenderWidget* w, |
| 103 const WebTouchEvent& event, |
| 104 const WebTouchPoint& p) { |
| 105 WebMouseEvent fake_mouse_down, fake_mouse_up; |
| 106 |
| 107 fake_mouse_down.type = WebInputEvent::MouseDown; |
| 108 fake_mouse_down.timeStampSeconds = event.timeStampSeconds; |
| 109 fake_mouse_down.button = WebMouseEvent::ButtonLeft; |
| 110 fake_mouse_down.clickCount = 1; |
| 111 fake_mouse_down.x = p.position.x; |
| 112 fake_mouse_down.y = p.position.y; |
| 113 fake_mouse_down.windowX = p.position.x; |
| 114 fake_mouse_down.windowY = p.position.y; |
| 115 fake_mouse_down.globalX = p.screenPosition.x; |
| 116 fake_mouse_down.globalY = p.screenPosition.y; |
| 117 |
| 118 fake_mouse_up.type = WebInputEvent::MouseUp; |
| 119 fake_mouse_up.timeStampSeconds = event.timeStampSeconds; |
| 120 fake_mouse_up.button = WebMouseEvent::ButtonLeft; |
| 121 fake_mouse_up.clickCount = 1; |
| 122 fake_mouse_up.x = p.position.x; |
| 123 fake_mouse_up.y = p.position.y; |
| 124 fake_mouse_up.windowX = p.position.x; |
| 125 fake_mouse_up.windowY = p.position.y; |
| 126 fake_mouse_up.globalX = p.screenPosition.x; |
| 127 fake_mouse_up.globalY = p.screenPosition.y; |
| 128 |
| 129 w->webwidget()->handleInputEvent(fake_mouse_down); |
| 130 w->webwidget()->handleInputEvent(fake_mouse_up); |
| 131 } |
| 132 |
| 133 bool GestureManager::IsInClickTimeWindow(const double ts) { |
| 134 double delta = ts - first_touch_time_; |
| 135 return delta >= kMinClickDownTime |
| 136 && delta < kMaxClickDownTime; |
| 137 } |
| 138 |
| 139 bool GestureManager::IsInsideManhattanSquare(const WebTouchPoint& p) { |
| 140 int manhattanDistance = abs(p.position.x - first_touch_position_.x) + |
| 141 abs(p.position.y - first_touch_position_.y); |
| 142 return manhattanDistance < kMaxManhattanDistance; |
| 143 } |
| 144 |
| 145 void GestureManager::ScrollViaTouchMotion(const WebTouchPoint& tp, |
| 146 RenderWidget *rw) { |
| 147 rw->webwidget()->gestureScroll(tp.position, tp.screenPosition, |
| 148 tp.position.x - first_touch_position_.x, |
| 149 tp.position.y - first_touch_position_.y); |
| 150 first_touch_position_ = tp.position; |
| 151 } |
OLD | NEW |