Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(245)

Side by Side Diff: content/browser/renderer_host/input/touch_emulator.cc

Issue 138163016: [DevTools] Touch emulation in content. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 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 "content/browser/renderer_host/input/touch_emulator.h"
6
7 #include "content/browser/renderer_host/input/motion_event_web.h"
8 #include "content/browser/renderer_host/input/web_input_event_util.h"
9 #include "content/browser/renderer_host/render_widget_host_impl.h"
10 #include "content/public/browser/native_web_keyboard_event.h"
11 #include "content/public/common/content_client.h"
12 #include "content/public/common/content_switches.h"
13 #include "grit/content_resources.h"
14 #include "third_party/WebKit/public/platform/WebCursorInfo.h"
15 #include "ui/events/gesture_detection/gesture_config_helper.h"
16 #include "ui/gfx/image/image.h"
17
18 using blink::WebGestureEvent;
19 using blink::WebInputEvent;
20 using blink::WebMouseEvent;
21 using blink::WebMouseWheelEvent;
22 using blink::WebTouchEvent;
23 using blink::WebTouchPoint;
24
25 namespace content {
26
27 TouchEmulator::TouchEmulator(RenderWidgetHostImpl* host)
28 : host_(host),
29 gesture_provider_(ui::DefaultGestureProviderConfig(), this),
30 mouse_pressed_(false),
31 shift_pressed_(false),
32 touch_active_(false),
33 scroll_gesture_active_(false),
34 pinch_scale_(1.f),
35 pinch_gesture_active_(false) {
36 DCHECK(host);
37 InitCursorFromResource(&touch_cursor_, IDR_DEVTOOLS_TOUCH_CURSOR_ICON);
38 InitCursorFromResource(&pinch_cursor_, IDR_DEVTOOLS_PINCH_CURSOR_ICON);
jdduke (slow) 2014/04/04 16:11:28 I noticed that the icons would occasionally revert
dgozman 2014/04/07 16:54:55 I've fixed that in blink, where sometimes cursor w
39 UpdateCursor();
40 // TODO(dgozman): Use synthetic secondary touch to support multi-touch.
41 gesture_provider_.SetMultiTouchSupportEnabled(false);
42 // TODO(dgozman): Enable double tap if requested by the renderer.
43 // TODO(dgozman): Don't break double-tap-based pinch with shift handling.
44 gesture_provider_.SetDoubleTapSupportForPlatformEnabled(false);
45 }
46
47 TouchEmulator::~TouchEmulator() {
48 WebCursor::CursorInfo cursor_info;
49 cursor_info.type = blink::WebCursorInfo::TypePointer;
50 WebCursor cursor;
51 cursor.InitFromCursorInfo(cursor_info);
52 host_->SetCursor(cursor);
53
54 if (pinch_gesture_active_) {
55 pinch_event_.timeStampSeconds = base::Time::Now().ToDoubleT();
56 PinchEnd(pinch_event_);
57 }
58 if (scroll_gesture_active_) {
59 pinch_event_.timeStampSeconds = base::Time::Now().ToDoubleT();
60 ScrollEnd(pinch_event_);
61 }
62 // TODO(dgozman): Should we also send TouchCancel?
jdduke (slow) 2014/04/04 16:11:28 You should be able to accomplish the pinch/scroll
dgozman 2014/04/07 16:54:55 Looks like canceling touch does not initiate a syn
jdduke (slow) 2014/04/07 18:07:26 It should, but only if there's an active touch (mo
63 }
64
65 void TouchEmulator::InitCursorFromResource(WebCursor* cursor, int resource_id) {
66 gfx::Image& cursor_image =
67 content::GetContentClient()->GetNativeImageNamed(resource_id);
68 WebCursor::CursorInfo cursor_info;
69 cursor_info.type = blink::WebCursorInfo::TypeCustom;
70 // TODO(dgozman): Add HiDPI cursors.
71 cursor_info.image_scale_factor = 1.f;
72 cursor_info.custom_image = cursor_image.AsBitmap();
73 cursor_info.hotspot =
74 gfx::Point(cursor_image.Width() / 2, cursor_image.Height() / 2);
75 #if defined(OS_WIN)
76 cursor_info.external_handle = 0;
77 #endif
78
79 cursor->InitFromCursorInfo(cursor_info);
80 }
81
82 bool TouchEmulator::HandleMouseEvent(const WebMouseEvent& mouse_event) {
83 if (mouse_event.button != WebMouseEvent::ButtonLeft)
84 return true;
85
86 if (mouse_event.type == WebInputEvent::MouseDown)
87 mouse_pressed_ = true;
88 if (mouse_event.type == WebInputEvent::MouseUp)
89 mouse_pressed_ = false;
90
91 UpdateShiftPressed((mouse_event.modifiers & WebInputEvent::ShiftKey) != 0);
92
93 if (FillTouchEventAndPoint(mouse_event) &&
94 gesture_provider_.OnTouchEvent(MotionEventWeb(touch_event_))) {
95 host_->ForwardTouchEventWithLatencyInfo(touch_event_, ui::LatencyInfo());
96 }
97
98 // Do not pass mouse events to the renderer.
99 return true;
100 }
101
102 bool TouchEmulator::HandleMouseWheelEvent(const WebMouseWheelEvent& event) {
103 // No mouse wheel events for the renderer.
104 return true;
105 }
106
107 bool TouchEmulator::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {
jdduke (slow) 2014/04/04 16:21:11 Let's use a "blink::WebKeyboardEvent" type here to
dgozman 2014/04/07 16:54:55 Done.
108 if (!UpdateShiftPressed((event.modifiers & WebInputEvent::ShiftKey) != 0))
109 return false;
110
111 if (!mouse_pressed_)
112 return false;
113
114 // Note: The necessary pinch events will be lazily inserted by
115 // |OnGestureEvent| depending on the state of |shift_pressed_|, using the
116 // scroll stream as the event driver.
117 if (shift_pressed_) {
118 // TODO(dgozman): Add secondary touch point and set anchor.
119 } else {
120 // TODO(dgozman): Remove secondary touch point and anchor.
121 }
122
123 // Never block keyboard events.
124 return false;
125 }
126
127 bool TouchEmulator::HandleTouchEventAck(InputEventAckState ack_result) {
128 const bool event_consumed = ack_result == INPUT_EVENT_ACK_STATE_CONSUMED;
129 gesture_provider_.OnTouchEventAck(event_consumed);
130 // TODO(dgozman): Disable emulation when real touch events are available.
131 return true;
132 }
133
134 void TouchEmulator::OnGestureEvent(const ui::GestureEventData& gesture) {
135 WebGestureEvent gesture_event =
136 CreateWebGestureEventFromGestureEventData(gesture, 1);
137
138 // Convert scrolls to pinches while shift is pressed.
139 if (gesture_event.type == WebInputEvent::GestureScrollUpdate) {
140 if (InPinchGestureMode()) {
141 if (!pinch_gesture_active_)
142 PinchBegin(gesture_event);
143 else
144 PinchUpdate(gesture_event);
145 return;
146 } else {
147 if (pinch_gesture_active_)
148 PinchEnd(gesture_event);
149 }
150 }
151
152 if ((gesture_event.type == WebInputEvent::GestureScrollEnd ||
153 gesture_event.type == WebInputEvent::GestureFlingStart)) {
154 scroll_gesture_active_ = false;
155 // PinchEnd must always precede ScrollEnd/FlingStart.
156 if (pinch_gesture_active_)
157 PinchEnd(gesture_event);
158 }
159
160 if ((gesture_event.type == WebInputEvent::GestureFlingStart ||
161 gesture_event.type == WebInputEvent::GestureFlingCancel) &&
162 InPinchGestureMode()) {
163 // No fling in pinch mode. Forward scroll end instead of fling start and
164 // drop fling cancel.
165 if (gesture_event.type == WebInputEvent::GestureFlingStart)
166 ScrollEnd(gesture_event);
167 } else {
168 host_->ForwardGestureEvent(gesture_event);
169 }
170
171 if (gesture_event.type == WebInputEvent::GestureScrollBegin) {
172 scroll_gesture_active_ = true;
173 // PinchBegin must always follow ScrollBegin.
174 if (InPinchGestureMode())
175 PinchBegin(gesture_event);
176 }
177 }
178
179 void TouchEmulator::CancelTouch() {
180 touch_event_.timeStampSeconds = base::Time::Now().ToDoubleT();
181 touch_event_.type = WebInputEvent::TouchCancel;
182 touch_event_.touches[0].state = WebTouchPoint::StateCancelled;
183 touch_active_ = false;
184 if (gesture_provider_.OnTouchEvent(MotionEventWeb(touch_event_)))
185 host_->ForwardTouchEventWithLatencyInfo(touch_event_, ui::LatencyInfo());
186 }
187
188 void TouchEmulator::UpdateCursor() {
189 host_->SetCursor(InPinchGestureMode() ? pinch_cursor_ : touch_cursor_);
190 }
191
192 bool TouchEmulator::UpdateShiftPressed(bool shift_pressed) {
193 if (shift_pressed_ == shift_pressed)
194 return false;
195 shift_pressed_ = shift_pressed;
196 UpdateCursor();
197 return true;
198 }
199
200 void TouchEmulator::PinchBegin(const WebGestureEvent& event) {
201 DCHECK(InPinchGestureMode());
202 DCHECK(!pinch_gesture_active_);
203 pinch_gesture_active_ = true;
204 pinch_anchor_ = gfx::Point(event.x, event.y);
205 pinch_scale_ = 1.f;
206 FillPinchEvent(event);
207 pinch_event_.type = WebInputEvent::GesturePinchBegin;
208 host_->ForwardGestureEvent(pinch_event_);
209 }
210
211 void TouchEmulator::PinchUpdate(const WebGestureEvent& event) {
212 DCHECK(pinch_gesture_active_);
213 int dy = pinch_anchor_.y() - event.y;
214 float scale = exp(dy * 0.002f);
215 FillPinchEvent(event);
216 pinch_event_.type = WebInputEvent::GesturePinchUpdate;
217 pinch_event_.data.pinchUpdate.scale = scale / pinch_scale_;
218 host_->ForwardGestureEvent(pinch_event_);
219 pinch_scale_ = scale;
220 }
221
222 void TouchEmulator::PinchEnd(const WebGestureEvent& event) {
223 DCHECK(pinch_gesture_active_);
224 pinch_gesture_active_ = false;
225 FillPinchEvent(event);
226 pinch_event_.type = WebInputEvent::GesturePinchEnd;
227 host_->ForwardGestureEvent(pinch_event_);
228 }
229
230 void TouchEmulator::FillPinchEvent(const WebInputEvent& event) {
231 pinch_event_.timeStampSeconds = event.timeStampSeconds;
232 pinch_event_.modifiers = event.modifiers;
233 pinch_event_.sourceDevice = blink::WebGestureEvent::Touchscreen;
234 pinch_event_.x = pinch_anchor_.x();
235 pinch_event_.y = pinch_anchor_.y();
236 }
237
238 void TouchEmulator::ScrollEnd(const WebGestureEvent& event) {
239 WebGestureEvent scroll_event;
240 scroll_event.timeStampSeconds = event.timeStampSeconds;
241 scroll_event.modifiers = event.modifiers;
242 scroll_event.sourceDevice = blink::WebGestureEvent::Touchscreen;
243 scroll_event.type = WebInputEvent::GestureScrollEnd;
244 host_->ForwardGestureEvent(scroll_event);
245 }
246
247 bool TouchEmulator::FillTouchEventAndPoint(const WebMouseEvent& mouse_event) {
248 if (mouse_event.type != WebInputEvent::MouseDown &&
249 mouse_event.type != WebInputEvent::MouseMove &&
250 mouse_event.type != WebInputEvent::MouseUp) {
251 return false;
252 }
253
254 touch_event_.touchesLength = 1;
255 touch_event_.timeStampSeconds = mouse_event.timeStampSeconds;
256 touch_event_.modifiers = mouse_event.modifiers;
257
258 WebTouchPoint& point = touch_event_.touches[0];
259 point.id = 0;
260 point.radiusX = point.radiusY = 1.f;
261 point.force = 1.f;
262 point.rotationAngle = 0.f;
263 point.position.x = mouse_event.x;
264 point.screenPosition.x = mouse_event.globalX;
265 point.position.y = mouse_event.y;
266 point.screenPosition.y = mouse_event.globalY;
267
268 switch (mouse_event.type) {
269 case WebInputEvent::MouseDown:
270 touch_event_.type = WebInputEvent::TouchStart;
271 touch_active_ = true;
272 point.state = WebTouchPoint::StatePressed;
273 break;
274 case WebInputEvent::MouseMove:
275 touch_event_.type = WebInputEvent::TouchMove;
276 point.state = WebTouchPoint::StateMoved;
277 break;
278 case WebInputEvent::MouseUp:
279 touch_event_.type = WebInputEvent::TouchEnd;
280 touch_active_ = false;
281 point.state = WebTouchPoint::StateReleased;
282 break;
283 default:
284 NOTREACHED();
285 }
286 return true;
287 }
288
289 bool TouchEmulator::InPinchGestureMode() const {
290 return shift_pressed_;
291 }
292
293 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698