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

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: Most review comments addressed 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/public/common/content_client.h"
10 #include "content/public/common/content_switches.h"
11 #include "grit/content_resources.h"
12 #include "third_party/WebKit/public/platform/WebCursorInfo.h"
13 #include "ui/events/gesture_detection/gesture_config_helper.h"
14 #include "ui/gfx/image/image.h"
15
16 using blink::WebGestureEvent;
17 using blink::WebInputEvent;
18 using blink::WebKeyboardEvent;
19 using blink::WebMouseEvent;
20 using blink::WebMouseWheelEvent;
21 using blink::WebTouchEvent;
22 using blink::WebTouchPoint;
23
24 namespace content {
25
26 namespace {
27
28 ui::GestureProvider::Config GetGestureProviderConfig() {
29 // TODO(dgozman): Use different configs to emulate mobile/desktop as
30 // requested by renderer.
31 ui::GestureProvider::Config config = ui::DefaultGestureProviderConfig();
32 config.gesture_begin_end_types_enabled = false;
33 return config;
34 }
35
36 } // namespace
jdduke (slow) 2014/04/08 19:14:11 Nit: 2 spaces before //
37
38 TouchEmulator::TouchEmulator(TouchEmulatorClient* client)
39 : client_(client),
40 gesture_provider_(GetGestureProviderConfig(), this) {
41 Init();
42 }
43
44 TouchEmulator::TouchEmulator(TouchEmulatorClient* client,
45 ui::GestureProvider::Config gesture_config)
jdduke (slow) 2014/04/08 19:14:11 Nit: While the Config is fairly simple, we should
46 : client_(client),
47 gesture_provider_(gesture_config, this) {
48 Init();
49 }
50
51 void TouchEmulator::Init() {
52 DCHECK(client_);
53 mouse_pressed_ = false;
54 shift_pressed_ = false;
55 touch_active_ = false;
56 scroll_gesture_active_ = false;
57 fling_start_suppressed_ = false;
58 pinch_scale_ = 1.f;
59 pinch_gesture_active_ = false;
60 InitCursorFromResource(&touch_cursor_, IDR_DEVTOOLS_TOUCH_CURSOR_ICON);
61 InitCursorFromResource(&pinch_cursor_, IDR_DEVTOOLS_PINCH_CURSOR_ICON);
62 UpdateCursor();
63 // TODO(dgozman): Use synthetic secondary touch to support multi-touch.
64 gesture_provider_.SetMultiTouchSupportEnabled(false);
65 // TODO(dgozman): Enable double tap if requested by the renderer.
66 // TODO(dgozman): Don't break double-tap-based pinch with shift handling.
67 gesture_provider_.SetDoubleTapSupportForPlatformEnabled(false);
68 }
69
70 TouchEmulator::~TouchEmulator() {
71 WebCursor::CursorInfo cursor_info;
72 cursor_info.type = blink::WebCursorInfo::TypePointer;
73 WebCursor cursor;
74 cursor.InitFromCursorInfo(cursor_info);
75 client_->SetCursor(cursor);
76
77 if (pinch_gesture_active_) {
78 pinch_event_.timeStampSeconds = base::Time::Now().ToDoubleT();
79 PinchEnd(pinch_event_);
80 }
81 if (scroll_gesture_active_) {
82 pinch_event_.timeStampSeconds = base::Time::Now().ToDoubleT();
83 ScrollEnd(pinch_event_);
84 }
85 // We can also cancel touch, but that only has an effect on gesture provider,
86 // which will be deleted along with emulator anyway.
87 }
88
89 void TouchEmulator::InitCursorFromResource(WebCursor* cursor, int resource_id) {
90 gfx::Image& cursor_image =
91 content::GetContentClient()->GetNativeImageNamed(resource_id);
92 WebCursor::CursorInfo cursor_info;
93 cursor_info.type = blink::WebCursorInfo::TypeCustom;
94 // TODO(dgozman): Add HiDPI cursors.
95 cursor_info.image_scale_factor = 1.f;
96 cursor_info.custom_image = cursor_image.AsBitmap();
97 cursor_info.hotspot =
98 gfx::Point(cursor_image.Width() / 2, cursor_image.Height() / 2);
99 #if defined(OS_WIN)
100 cursor_info.external_handle = 0;
101 #endif
102
103 cursor->InitFromCursorInfo(cursor_info);
104 }
105
106 bool TouchEmulator::HandleMouseEvent(const WebMouseEvent& mouse_event) {
107 if (mouse_event.button != WebMouseEvent::ButtonLeft)
108 return true;
109
110 if (mouse_event.type == WebInputEvent::MouseDown)
111 mouse_pressed_ = true;
112 if (mouse_event.type == WebInputEvent::MouseUp)
113 mouse_pressed_ = false;
114
115 UpdateShiftPressed((mouse_event.modifiers & WebInputEvent::ShiftKey) != 0);
116
117 if (FillTouchEventAndPoint(mouse_event) &&
118 gesture_provider_.OnTouchEvent(MotionEventWeb(touch_event_))) {
119 client_->ForwardTouchEvent(touch_event_);
120 }
121
122 // Do not pass mouse events to the renderer.
123 return true;
124 }
125
126 bool TouchEmulator::HandleMouseWheelEvent(const WebMouseWheelEvent& event) {
127 // No mouse wheel events for the renderer.
128 return true;
129 }
130
131 bool TouchEmulator::HandleKeyboardEvent(const WebKeyboardEvent& event) {
132 if (!UpdateShiftPressed((event.modifiers & WebInputEvent::ShiftKey) != 0))
133 return false;
134
135 if (!mouse_pressed_)
136 return false;
137
138 // Note: The necessary pinch events will be lazily inserted by
139 // |OnGestureEvent| depending on the state of |shift_pressed_|, using the
140 // scroll stream as the event driver.
141 if (shift_pressed_) {
142 // TODO(dgozman): Add secondary touch point and set anchor.
143 } else {
144 // TODO(dgozman): Remove secondary touch point and anchor.
145 }
146
147 // Never block keyboard events.
148 return false;
149 }
150
151 bool TouchEmulator::HandleTouchEventAck(InputEventAckState ack_result) {
152 const bool event_consumed = ack_result == INPUT_EVENT_ACK_STATE_CONSUMED;
153 gesture_provider_.OnTouchEventAck(event_consumed);
154 // TODO(dgozman): Disable emulation when real touch events are available.
155 return true;
156 }
157
158 void TouchEmulator::OnGestureEvent(const ui::GestureEventData& gesture) {
159 WebGestureEvent gesture_event =
160 CreateWebGestureEventFromGestureEventData(gesture, 1);
161
162 // Convert scrolls to pinches while shift is pressed.
163 if (gesture_event.type == WebInputEvent::GestureScrollUpdate) {
164 if (InPinchGestureMode()) {
165 if (!pinch_gesture_active_)
166 PinchBegin(gesture_event);
167 else
168 PinchUpdate(gesture_event);
169 return;
170 } else {
171 if (pinch_gesture_active_)
172 PinchEnd(gesture_event);
173 }
174 }
175
176 if ((gesture_event.type == WebInputEvent::GestureScrollEnd ||
177 gesture_event.type == WebInputEvent::GestureFlingStart)) {
178 scroll_gesture_active_ = false;
179 // PinchEnd must always precede ScrollEnd/FlingStart.
180 if (pinch_gesture_active_)
181 PinchEnd(gesture_event);
182 }
183
184 if (gesture_event.type == WebInputEvent::GestureFlingStart &&
185 InPinchGestureMode()) {
186 // No fling in pinch mode. Forward scroll end instead of fling start.
187 fling_start_suppressed_ = true;
188 ScrollEnd(gesture_event);
189 } else {
190 bool suppress_fling_cancel =
191 gesture_event.type == WebInputEvent::GestureFlingCancel &&
192 fling_start_suppressed_;
193 if (!suppress_fling_cancel)
194 client_->ForwardGestureEvent(gesture_event);
195 if (gesture_event.type == WebInputEvent::GestureFlingStart ||
196 gesture_event.type == WebInputEvent::GestureFlingCancel)
197 fling_start_suppressed_ = false;
198 // TODO(dgozman): sometimes we hit a race, where keyboard event cancels
199 // fling in browser process, but does not in renderer process.
200 }
201
202 if (gesture_event.type == WebInputEvent::GestureScrollBegin) {
203 scroll_gesture_active_ = true;
204 // PinchBegin must always follow ScrollBegin.
205 if (InPinchGestureMode())
206 PinchBegin(gesture_event);
207 }
208 }
209
210 void TouchEmulator::CancelTouch() {
211 if (!touch_active_)
212 return;
213
214 touch_event_.timeStampSeconds = base::Time::Now().ToDoubleT();
215 touch_event_.type = WebInputEvent::TouchCancel;
216 touch_event_.touches[0].state = WebTouchPoint::StateCancelled;
217 touch_active_ = false;
218 if (gesture_provider_.OnTouchEvent(MotionEventWeb(touch_event_)))
219 client_->ForwardTouchEvent(touch_event_);
220 }
221
222 void TouchEmulator::UpdateCursor() {
223 client_->SetCursor(InPinchGestureMode() ? pinch_cursor_ : touch_cursor_);
224 }
225
226 bool TouchEmulator::UpdateShiftPressed(bool shift_pressed) {
227 if (shift_pressed_ == shift_pressed)
228 return false;
229 shift_pressed_ = shift_pressed;
230 UpdateCursor();
231 return true;
232 }
233
234 void TouchEmulator::PinchBegin(const WebGestureEvent& event) {
235 DCHECK(InPinchGestureMode());
236 DCHECK(!pinch_gesture_active_);
237 pinch_gesture_active_ = true;
238 pinch_anchor_ = gfx::Point(event.x, event.y);
239 pinch_scale_ = 1.f;
240 FillPinchEvent(event);
241 pinch_event_.type = WebInputEvent::GesturePinchBegin;
242 client_->ForwardGestureEvent(pinch_event_);
243 }
244
245 void TouchEmulator::PinchUpdate(const WebGestureEvent& event) {
246 DCHECK(pinch_gesture_active_);
247 int dy = pinch_anchor_.y() - event.y;
248 float scale = exp(dy * 0.002f);
249 FillPinchEvent(event);
250 pinch_event_.type = WebInputEvent::GesturePinchUpdate;
251 pinch_event_.data.pinchUpdate.scale = scale / pinch_scale_;
252 client_->ForwardGestureEvent(pinch_event_);
253 pinch_scale_ = scale;
254 }
255
256 void TouchEmulator::PinchEnd(const WebGestureEvent& event) {
257 DCHECK(pinch_gesture_active_);
258 pinch_gesture_active_ = false;
259 FillPinchEvent(event);
260 pinch_event_.type = WebInputEvent::GesturePinchEnd;
261 client_->ForwardGestureEvent(pinch_event_);
262 }
263
264 void TouchEmulator::FillPinchEvent(const WebInputEvent& event) {
265 pinch_event_.timeStampSeconds = event.timeStampSeconds;
266 pinch_event_.modifiers = event.modifiers;
267 pinch_event_.sourceDevice = blink::WebGestureEvent::Touchscreen;
268 pinch_event_.x = pinch_anchor_.x();
269 pinch_event_.y = pinch_anchor_.y();
270 }
271
272 void TouchEmulator::ScrollEnd(const WebGestureEvent& event) {
273 WebGestureEvent scroll_event;
274 scroll_event.timeStampSeconds = event.timeStampSeconds;
275 scroll_event.modifiers = event.modifiers;
276 scroll_event.sourceDevice = blink::WebGestureEvent::Touchscreen;
277 scroll_event.type = WebInputEvent::GestureScrollEnd;
278 client_->ForwardGestureEvent(scroll_event);
279 }
280
281 bool TouchEmulator::FillTouchEventAndPoint(const WebMouseEvent& mouse_event) {
282 if (mouse_event.type != WebInputEvent::MouseDown &&
283 mouse_event.type != WebInputEvent::MouseMove &&
284 mouse_event.type != WebInputEvent::MouseUp) {
285 return false;
286 }
287
288 touch_event_.touchesLength = 1;
289 touch_event_.timeStampSeconds = mouse_event.timeStampSeconds;
290 touch_event_.modifiers = mouse_event.modifiers;
291
292 WebTouchPoint& point = touch_event_.touches[0];
293 point.id = 0;
294 point.radiusX = point.radiusY = 1.f;
295 point.force = 1.f;
296 point.rotationAngle = 0.f;
297 point.position.x = mouse_event.x;
298 point.screenPosition.x = mouse_event.globalX;
299 point.position.y = mouse_event.y;
300 point.screenPosition.y = mouse_event.globalY;
301
302 switch (mouse_event.type) {
303 case WebInputEvent::MouseDown:
304 touch_event_.type = WebInputEvent::TouchStart;
305 touch_active_ = true;
306 point.state = WebTouchPoint::StatePressed;
307 break;
308 case WebInputEvent::MouseMove:
309 touch_event_.type = WebInputEvent::TouchMove;
310 point.state = WebTouchPoint::StateMoved;
311 break;
312 case WebInputEvent::MouseUp:
313 touch_event_.type = WebInputEvent::TouchEnd;
314 touch_active_ = false;
315 point.state = WebTouchPoint::StateReleased;
316 break;
317 default:
318 NOTREACHED();
319 }
320 return true;
321 }
322
323 bool TouchEmulator::InPinchGestureMode() const {
324 return shift_pressed_;
325 }
326
327 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/renderer_host/input/touch_emulator.h ('k') | content/browser/renderer_host/input/touch_emulator_client.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698