1 /*
2 * Copyright (C) 2009 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "config.h"
32 #include "web/WebInputEventConversion.h"
33
34 #include "core/dom/Touch.h"
35 #include "core/dom/TouchList.h"
36 #include "core/events/GestureEvent.h"
37 #include "core/events/KeyboardEvent.h"
38 #include "core/events/MouseEvent.h"
39 #include "core/events/TouchEvent.h"
40 #include "core/events/WheelEvent.h"
41 #include "core/frame/FrameHost.h"
42 #include "core/frame/FrameView.h"
43 #include "core/frame/PinchViewport.h"
44 #include "core/page/Page.h"
45 #include "core/rendering/RenderObject.h"
46 #include "platform/KeyboardCodes.h"
47 #include "platform/Widget.h"
48 #include "platform/scroll/ScrollView.h"
49
50 namespace blink {
51
52 static const double millisPerSecond = 1000.0;
53
widgetInputEventsScaleFactor(const Widget * widget)54 static float widgetInputEventsScaleFactor(const Widget* widget)
55 {
56 if (!widget)
57 return 1;
58
59 ScrollView* rootView = toScrollView(widget->root());
60 if (!rootView)
61 return 1;
62
63 return rootView->inputEventsScaleFactor();
64 }
65
widgetInputEventsOffset(const Widget * widget)66 static IntSize widgetInputEventsOffset(const Widget* widget)
67 {
68 if (!widget)
69 return IntSize();
70 ScrollView* rootView = toScrollView(widget->root());
71 if (!rootView)
72 return IntSize();
73
74 return rootView->inputEventsOffsetForEmulation();
75 }
76
pinchViewportOffset(const Widget * widget)77 static IntPoint pinchViewportOffset(const Widget* widget)
78 {
79 // Event position needs to be adjusted by the pinch viewport's offset within the
80 // main frame before being passed into the widget's convertFromContainingWindow.
81 FrameView* rootView = toFrameView(widget->root());
82 if (!rootView)
83 return IntPoint();
84
85 return flooredIntPoint(rootView->page()->frameHost().pinchViewport().visibleRect().location());
86 }
87
88 // MakePlatformMouseEvent -----------------------------------------------------
89
PlatformMouseEventBuilder(Widget * widget,const WebMouseEvent & e)90 PlatformMouseEventBuilder::PlatformMouseEventBuilder(Widget* widget, const WebMouseEvent& e)
91 {
92 float scale = widgetInputEventsScaleFactor(widget);
93 IntSize offset = widgetInputEventsOffset(widget);
94 IntPoint pinchViewport = pinchViewportOffset(widget);
95
96 // FIXME: Widget is always toplevel, unless it's a popup. We may be able
97 // to get rid of this once we abstract popups into a WebKit API.
98 m_position = widget->convertFromContainingWindow(
99 IntPoint((e.x - offset.width()) / scale + pinchViewport.x(), (e.y - offset.height()) / scale + pinchViewport.y()));
100 m_globalPosition = IntPoint(e.globalX, e.globalY);
101 m_movementDelta = IntPoint(e.movementX / scale, e.movementY / scale);
102 m_button = static_cast<MouseButton>(e.button);
103
104 m_modifiers = 0;
105 if (e.modifiers & WebInputEvent::ShiftKey)
106 m_modifiers |= PlatformEvent::ShiftKey;
107 if (e.modifiers & WebInputEvent::ControlKey)
108 m_modifiers |= PlatformEvent::CtrlKey;
109 if (e.modifiers & WebInputEvent::AltKey)
110 m_modifiers |= PlatformEvent::AltKey;
111 if (e.modifiers & WebInputEvent::MetaKey)
112 m_modifiers |= PlatformEvent::MetaKey;
113
114 m_modifierFlags = e.modifiers;
115 m_timestamp = e.timeStampSeconds;
116 m_clickCount = e.clickCount;
117
118 switch (e.type) {
119 case WebInputEvent::MouseMove:
120 case WebInputEvent::MouseLeave: // synthesize a move event
121 m_type = PlatformEvent::MouseMoved;
122 break;
123
124 case WebInputEvent::MouseDown:
125 m_type = PlatformEvent::MousePressed;
126 break;
127
128 case WebInputEvent::MouseUp:
129 m_type = PlatformEvent::MouseReleased;
130 break;
131
132 default:
133 ASSERT_NOT_REACHED();
134 }
135 }
136
137 // PlatformWheelEventBuilder --------------------------------------------------
138
PlatformWheelEventBuilder(Widget * widget,const WebMouseWheelEvent & e)139 PlatformWheelEventBuilder::PlatformWheelEventBuilder(Widget* widget, const WebMouseWheelEvent& e)
140 {
141 float scale = widgetInputEventsScaleFactor(widget);
142 IntSize offset = widgetInputEventsOffset(widget);
143 IntPoint pinchViewport = pinchViewportOffset(widget);
144
145 m_position = widget->convertFromContainingWindow(
146 IntPoint((e.x - offset.width()) / scale + pinchViewport.x(), (e.y - offset.height()) / scale + pinchViewport.y()));
147 m_globalPosition = IntPoint(e.globalX, e.globalY);
148 m_deltaX = e.deltaX;
149 m_deltaY = e.deltaY;
150 m_wheelTicksX = e.wheelTicksX;
151 m_wheelTicksY = e.wheelTicksY;
152 m_granularity = e.scrollByPage ?
153 ScrollByPageWheelEvent : ScrollByPixelWheelEvent;
154
155 m_type = PlatformEvent::Wheel;
156
157 m_modifiers = 0;
158 if (e.modifiers & WebInputEvent::ShiftKey)
159 m_modifiers |= PlatformEvent::ShiftKey;
160 if (e.modifiers & WebInputEvent::ControlKey)
161 m_modifiers |= PlatformEvent::CtrlKey;
162 if (e.modifiers & WebInputEvent::AltKey)
163 m_modifiers |= PlatformEvent::AltKey;
164 if (e.modifiers & WebInputEvent::MetaKey)
165 m_modifiers |= PlatformEvent::MetaKey;
166
167 m_hasPreciseScrollingDeltas = e.hasPreciseScrollingDeltas;
168 #if OS(MACOSX)
169 m_phase = static_cast<PlatformWheelEventPhase>(e.phase);
170 m_momentumPhase = static_cast<PlatformWheelEventPhase>(e.momentumPhase);
171 m_timestamp = e.timeStampSeconds;
172 m_scrollCount = 0;
173 m_unacceleratedScrollingDeltaX = e.deltaX;
174 m_unacceleratedScrollingDeltaY = e.deltaY;
175 m_canRubberbandLeft = e.canRubberbandLeft;
176 m_canRubberbandRight = e.canRubberbandRight;
177 #endif
178 }
179
180 // PlatformGestureEventBuilder --------------------------------------------------
181
PlatformGestureEventBuilder(Widget * widget,const WebGestureEvent & e)182 PlatformGestureEventBuilder::PlatformGestureEventBuilder(Widget* widget, const WebGestureEvent& e)
183 {
184 float scale = widgetInputEventsScaleFactor(widget);
185 IntSize offset = widgetInputEventsOffset(widget);
186 IntPoint pinchViewport = pinchViewportOffset(widget);
187
188 switch (e.type) {
189 case WebInputEvent::GestureScrollBegin:
190 m_type = PlatformEvent::GestureScrollBegin;
191 break;
192 case WebInputEvent::GestureScrollEnd:
193 m_type = PlatformEvent::GestureScrollEnd;
194 break;
195 case WebInputEvent::GestureFlingStart:
196 m_type = PlatformEvent::GestureFlingStart;
197 break;
198 case WebInputEvent::GestureScrollUpdate:
199 m_type = PlatformEvent::GestureScrollUpdate;
200 m_data.m_scrollUpdate.m_deltaX = e.data.scrollUpdate.deltaX / scale;
201 m_data.m_scrollUpdate.m_deltaY = e.data.scrollUpdate.deltaY / scale;
202 m_data.m_scrollUpdate.m_velocityX = e.data.scrollUpdate.velocityX;
203 m_data.m_scrollUpdate.m_velocityY = e.data.scrollUpdate.velocityY;
204 break;
205 case WebInputEvent::GestureScrollUpdateWithoutPropagation:
206 m_type = PlatformEvent::GestureScrollUpdateWithoutPropagation;
207 m_data.m_scrollUpdate.m_deltaX = e.data.scrollUpdate.deltaX / scale;
208 m_data.m_scrollUpdate.m_deltaY = e.data.scrollUpdate.deltaY / scale;
209 m_data.m_scrollUpdate.m_velocityX = e.data.scrollUpdate.velocityX;
210 m_data.m_scrollUpdate.m_velocityY = e.data.scrollUpdate.velocityY;
211 break;
212 case WebInputEvent::GestureTap:
213 m_type = PlatformEvent::GestureTap;
214 m_area = expandedIntSize(FloatSize(e.data.tap.width / scale, e.data.tap.height / scale));
215 m_data.m_tap.m_tapCount = e.data.tap.tapCount;
216 break;
217 case WebInputEvent::GestureTapUnconfirmed:
218 m_type = PlatformEvent::GestureTapUnconfirmed;
219 m_area = expandedIntSize(FloatSize(e.data.tap.width / scale, e.data.tap.height / scale));
220 break;
221 case WebInputEvent::GestureTapDown:
222 m_type = PlatformEvent::GestureTapDown;
223 m_area = expandedIntSize(FloatSize(e.data.tapDown.width / scale, e.data.tapDown.height / scale));
224 break;
225 case WebInputEvent::GestureShowPress:
226 m_type = PlatformEvent::GestureShowPress;
227 m_area = expandedIntSize(FloatSize(e.data.showPress.width / scale, e.data.showPress.height / scale));
228 break;
229 case WebInputEvent::GestureTapCancel:
230 m_type = PlatformEvent::GestureTapDownCancel;
231 break;
232 case WebInputEvent::GestureDoubleTap:
233 // DoubleTap gesture is now handled as PlatformEvent::GestureTap with tap_count = 2. So no
234 // need to convert to a Platfrom DoubleTap gesture. But in WebViewImpl::handleGestureEvent
235 // all WebGestureEvent are converted to PlatformGestureEvent, for completeness and not reach
236 // the ASSERT_NOT_REACHED() at the end, convert the DoubleTap to a NoType.
237 m_type = PlatformEvent::NoType;
238 break;
239 case WebInputEvent::GestureTwoFingerTap:
240 m_type = PlatformEvent::GestureTwoFingerTap;
241 m_area = expandedIntSize(FloatSize(e.data.twoFingerTap.firstFingerWidth / scale, e.data.twoFingerTap.firstFingerHeight / scale));
242 break;
243 case WebInputEvent::GestureLongPress:
244 m_type = PlatformEvent::GestureLongPress;
245 m_area = expandedIntSize(FloatSize(e.data.longPress.width / scale, e.data.longPress.height / scale));
246 break;
247 case WebInputEvent::GestureLongTap:
248 m_type = PlatformEvent::GestureLongTap;
249 m_area = expandedIntSize(FloatSize(e.data.longPress.width / scale, e.data.longPress.height / scale));
250 break;
251 case WebInputEvent::GesturePinchBegin:
252 m_type = PlatformEvent::GesturePinchBegin;
253 break;
254 case WebInputEvent::GesturePinchEnd:
255 m_type = PlatformEvent::GesturePinchEnd;
256 break;
257 case WebInputEvent::GesturePinchUpdate:
258 m_type = PlatformEvent::GesturePinchUpdate;
259 m_data.m_pinchUpdate.m_scale = e.data.pinchUpdate.scale;
260 break;
261 default:
262 ASSERT_NOT_REACHED();
263 }
264 m_position = widget->convertFromContainingWindow(
265 IntPoint((e.x - offset.width()) / scale + pinchViewport.x(), (e.y - offset.height()) / scale + pinchViewport.y()));
266 m_globalPosition = IntPoint(e.globalX, e.globalY);
267 m_timestamp = e.timeStampSeconds;
268
269 m_modifiers = 0;
270 if (e.modifiers & WebInputEvent::ShiftKey)
271 m_modifiers |= PlatformEvent::ShiftKey;
272 if (e.modifiers & WebInputEvent::ControlKey)
273 m_modifiers |= PlatformEvent::CtrlKey;
274 if (e.modifiers & WebInputEvent::AltKey)
275 m_modifiers |= PlatformEvent::AltKey;
276 if (e.modifiers & WebInputEvent::MetaKey)
277 m_modifiers |= PlatformEvent::MetaKey;
278 }
279
280 // MakePlatformKeyboardEvent --------------------------------------------------
281
toPlatformKeyboardEventType(WebInputEvent::Type type)282 inline PlatformEvent::Type toPlatformKeyboardEventType(WebInputEvent::Type type)
283 {
284 switch (type) {
285 case WebInputEvent::KeyUp:
286 return PlatformEvent::KeyUp;
287 case WebInputEvent::KeyDown:
288 return PlatformEvent::KeyDown;
289 case WebInputEvent::RawKeyDown:
290 return PlatformEvent::RawKeyDown;
291 case WebInputEvent::Char:
292 return PlatformEvent::Char;
293 default:
294 ASSERT_NOT_REACHED();
295 }
296 return PlatformEvent::KeyDown;
297 }
298
PlatformKeyboardEventBuilder(const WebKeyboardEvent & e)299 PlatformKeyboardEventBuilder::PlatformKeyboardEventBuilder(const WebKeyboardEvent& e)
300 {
301 m_type = toPlatformKeyboardEventType(e.type);
302 m_text = String(e.text);
303 m_unmodifiedText = String(e.unmodifiedText);
304 m_keyIdentifier = String(e.keyIdentifier);
305 m_autoRepeat = (e.modifiers & WebInputEvent::IsAutoRepeat);
306 m_nativeVirtualKeyCode = e.nativeKeyCode;
307 m_isKeypad = (e.modifiers & WebInputEvent::IsKeyPad);
308 m_isSystemKey = e.isSystemKey;
309
310 m_modifiers = 0;
311 if (e.modifiers & WebInputEvent::ShiftKey)
312 m_modifiers |= PlatformEvent::ShiftKey;
313 if (e.modifiers & WebInputEvent::ControlKey)
314 m_modifiers |= PlatformEvent::CtrlKey;
315 if (e.modifiers & WebInputEvent::AltKey)
316 m_modifiers |= PlatformEvent::AltKey;
317 if (e.modifiers & WebInputEvent::MetaKey)
318 m_modifiers |= PlatformEvent::MetaKey;
319
320 // FIXME: PlatformKeyboardEvents expect a locational version of the keycode (e.g. VK_LSHIFT
321 // instead of VK_SHIFT). This should be changed so the location/keycode are stored separately,
322 // as in other places in the code.
323 m_windowsVirtualKeyCode = e.windowsKeyCode;
324 if (e.windowsKeyCode == VK_SHIFT) {
325 if (e.modifiers & WebInputEvent::IsLeft)
326 m_windowsVirtualKeyCode = VK_LSHIFT;
327 else if (e.modifiers & WebInputEvent::IsRight)
328 m_windowsVirtualKeyCode = VK_RSHIFT;
329 } else if (e.windowsKeyCode == VK_CONTROL) {
330 if (e.modifiers & WebInputEvent::IsLeft)
331 m_windowsVirtualKeyCode = VK_LCONTROL;
332 else if (e.modifiers & WebInputEvent::IsRight)
333 m_windowsVirtualKeyCode = VK_RCONTROL;
334 } else if (e.windowsKeyCode == VK_MENU) {
335 if (e.modifiers & WebInputEvent::IsLeft)
336 m_windowsVirtualKeyCode = VK_LMENU;
337 else if (e.modifiers & WebInputEvent::IsRight)
338 m_windowsVirtualKeyCode = VK_RMENU;
339 }
340
341 }
342
setKeyType(Type type)343 void PlatformKeyboardEventBuilder::setKeyType(Type type)
344 {
345 // According to the behavior of Webkit in Windows platform,
346 // we need to convert KeyDown to RawKeydown and Char events
347 // See WebKit/WebKit/Win/WebView.cpp
348 ASSERT(m_type == KeyDown);
349 ASSERT(type == RawKeyDown || type == Char);
350 m_type = type;
351
352 if (type == RawKeyDown) {
353 m_text = String();
354 m_unmodifiedText = String();
355 } else {
356 m_keyIdentifier = String();
357 m_windowsVirtualKeyCode = 0;
358 }
359 }
360
361 // Please refer to bug http://b/issue?id=961192, which talks about Webkit
362 // keyboard event handling changes. It also mentions the list of keys
363 // which don't have associated character events.
isCharacterKey() const364 bool PlatformKeyboardEventBuilder::isCharacterKey() const
365 {
366 switch (windowsVirtualKeyCode()) {
367 case VKEY_BACK:
368 case VKEY_ESCAPE:
369 return false;
370 }
371 return true;
372 }
373
toPlatformTouchEventType(const WebInputEvent::Type type)374 inline PlatformEvent::Type toPlatformTouchEventType(const WebInputEvent::Type type)
375 {
376 switch (type) {
377 case WebInputEvent::TouchStart:
378 return PlatformEvent::TouchStart;
379 case WebInputEvent::TouchMove:
380 return PlatformEvent::TouchMove;
381 case WebInputEvent::TouchEnd:
382 return PlatformEvent::TouchEnd;
383 case WebInputEvent::TouchCancel:
384 return PlatformEvent::TouchCancel;
385 default:
386 ASSERT_NOT_REACHED();
387 }
388 return PlatformEvent::TouchStart;
389 }
390
toPlatformTouchPointState(const WebTouchPoint::State state)391 inline PlatformTouchPoint::State toPlatformTouchPointState(const WebTouchPoint::State state)
392 {
393 switch (state) {
394 case WebTouchPoint::StateReleased:
395 return PlatformTouchPoint::TouchReleased;
396 case WebTouchPoint::StatePressed:
397 return PlatformTouchPoint::TouchPressed;
398 case WebTouchPoint::StateMoved:
399 return PlatformTouchPoint::TouchMoved;
400 case WebTouchPoint::StateStationary:
401 return PlatformTouchPoint::TouchStationary;
402 case WebTouchPoint::StateCancelled:
403 return PlatformTouchPoint::TouchCancelled;
404 case WebTouchPoint::StateUndefined:
405 ASSERT_NOT_REACHED();
406 }
407 return PlatformTouchPoint::TouchReleased;
408 }
409
toWebTouchPointState(const AtomicString & type)410 inline WebTouchPoint::State toWebTouchPointState(const AtomicString& type)
411 {
412 if (type == EventTypeNames::touchend)
413 return WebTouchPoint::StateReleased;
414 if (type == EventTypeNames::touchcancel)
415 return WebTouchPoint::StateCancelled;
416 if (type == EventTypeNames::touchstart)
417 return WebTouchPoint::StatePressed;
418 if (type == EventTypeNames::touchmove)
419 return WebTouchPoint::StateMoved;
420 return WebTouchPoint::StateUndefined;
421 }
422
PlatformTouchPointBuilder(Widget * widget,const WebTouchPoint & point)423 PlatformTouchPointBuilder::PlatformTouchPointBuilder(Widget* widget, const WebTouchPoint& point)
424 {
425 float scale = 1.0f / widgetInputEventsScaleFactor(widget);
426 IntSize offset = widgetInputEventsOffset(widget);
427 IntPoint pinchViewport = pinchViewportOffset(widget);
428 m_id = point.id;
429 m_state = toPlatformTouchPointState(point.state);
430 FloatPoint pos = (point.position - offset).scaledBy(scale);
431 pos.moveBy(pinchViewport);
432 IntPoint flooredPoint = flooredIntPoint(pos);
433 // This assumes convertFromContainingWindow does only translations, not scales.
434 m_pos = widget->convertFromContainingWindow(flooredPoint) + (pos - flooredPoint);
435 m_screenPos = FloatPoint(point.screenPosition.x, point.screenPosition.y);
436 m_radius = FloatSize(point.radiusX, point.radiusY).scaledBy(scale);
437 m_rotationAngle = point.rotationAngle;
438 m_force = point.force;
439 }
440
PlatformTouchEventBuilder(Widget * widget,const WebTouchEvent & event)441 PlatformTouchEventBuilder::PlatformTouchEventBuilder(Widget* widget, const WebTouchEvent& event)
442 {
443 m_type = toPlatformTouchEventType(event.type);
444
445 m_modifiers = 0;
446 if (event.modifiers & WebInputEvent::ShiftKey)
447 m_modifiers |= PlatformEvent::ShiftKey;
448 if (event.modifiers & WebInputEvent::ControlKey)
449 m_modifiers |= PlatformEvent::CtrlKey;
450 if (event.modifiers & WebInputEvent::AltKey)
451 m_modifiers |= PlatformEvent::AltKey;
452 if (event.modifiers & WebInputEvent::MetaKey)
453 m_modifiers |= PlatformEvent::MetaKey;
454
455 m_timestamp = event.timeStampSeconds;
456
457 for (unsigned i = 0; i < event.touchesLength; ++i)
458 m_touchPoints.append(PlatformTouchPointBuilder(widget, event.touches[i]));
459
460 m_cancelable = event.cancelable;
461 }
462
getWebInputModifiers(const UIEventWithKeyState & event)463 static int getWebInputModifiers(const UIEventWithKeyState& event)
464 {
465 int modifiers = 0;
466 if (event.ctrlKey())
467 modifiers |= WebInputEvent::ControlKey;
468 if (event.shiftKey())
469 modifiers |= WebInputEvent::ShiftKey;
470 if (event.altKey())
471 modifiers |= WebInputEvent::AltKey;
472 if (event.metaKey())
473 modifiers |= WebInputEvent::MetaKey;
474 return modifiers;
475 }
476
convertAbsoluteLocationForRenderObjectFloat(const LayoutPoint & location,const RenderObject & renderObject)477 static FloatPoint convertAbsoluteLocationForRenderObjectFloat(const LayoutPoint& location, const RenderObject& renderObject)
478 {
479 return renderObject.absoluteToLocal(location, UseTransforms);
480 }
481
convertAbsoluteLocationForRenderObject(const LayoutPoint & location,const RenderObject & renderObject)482 static IntPoint convertAbsoluteLocationForRenderObject(const LayoutPoint& location, const RenderObject& renderObject)
483 {
484 return roundedIntPoint(convertAbsoluteLocationForRenderObjectFloat(location, renderObject));
485 }
486
updateWebMouseEventFromCoreMouseEvent(const MouseRelatedEvent & event,const Widget & widget,const RenderObject & renderObject,WebMouseEvent & webEvent)487 static void updateWebMouseEventFromCoreMouseEvent(const MouseRelatedEvent& event, const Widget& widget, const RenderObject& renderObject, WebMouseEvent& webEvent)
488 {
489 webEvent.timeStampSeconds = event.timeStamp() / millisPerSecond;
490 webEvent.modifiers = getWebInputModifiers(event);
491
492 ScrollView* view = toScrollView(widget.parent());
493 IntPoint windowPoint = IntPoint(event.absoluteLocation().x(), event.absoluteLocation().y());
494 if (view)
495 windowPoint = view->contentsToWindow(windowPoint);
496 webEvent.globalX = event.screenX();
497 webEvent.globalY = event.screenY();
498 webEvent.windowX = windowPoint.x();
499 webEvent.windowY = windowPoint.y();
500 IntPoint localPoint = convertAbsoluteLocationForRenderObject(event.absoluteLocation(), renderObject);
501 webEvent.x = localPoint.x();
502 webEvent.y = localPoint.y();
503 }
504
WebMouseEventBuilder(const Widget * widget,const RenderObject * renderObject,const MouseEvent & event)505 WebMouseEventBuilder::WebMouseEventBuilder(const Widget* widget, const RenderObject* renderObject, const MouseEvent& event)
506 {
507 if (event.type() == EventTypeNames::mousemove)
508 type = WebInputEvent::MouseMove;
509 else if (event.type() == EventTypeNames::mouseout)
510 type = WebInputEvent::MouseLeave;
511 else if (event.type() == EventTypeNames::mouseover)
512 type = WebInputEvent::MouseEnter;
513 else if (event.type() == EventTypeNames::mousedown)
514 type = WebInputEvent::MouseDown;
515 else if (event.type() == EventTypeNames::mouseup)
516 type = WebInputEvent::MouseUp;
517 else if (event.type() == EventTypeNames::contextmenu)
518 type = WebInputEvent::ContextMenu;
519 else
520 return; // Skip all other mouse events.
521
522 updateWebMouseEventFromCoreMouseEvent(event, *widget, *renderObject, *this);
523
524 switch (event.button()) {
525 case LeftButton:
526 button = WebMouseEvent::ButtonLeft;
527 break;
528 case MiddleButton:
529 button = WebMouseEvent::ButtonMiddle;
530 break;
531 case RightButton:
532 button = WebMouseEvent::ButtonRight;
533 break;
534 }
535 if (event.buttonDown()) {
536 switch (event.button()) {
537 case LeftButton:
538 modifiers |= WebInputEvent::LeftButtonDown;
539 break;
540 case MiddleButton:
541 modifiers |= WebInputEvent::MiddleButtonDown;
542 break;
543 case RightButton:
544 modifiers |= WebInputEvent::RightButtonDown;
545 break;
546 }
547 } else
548 button = WebMouseEvent::ButtonNone;
549 movementX = event.movementX();
550 movementY = event.movementY();
551 clickCount = event.detail();
552 }
553
554 // Generate a synthetic WebMouseEvent given a TouchEvent (eg. for emulating a mouse
555 // with touch input for plugins that don't support touch input).
WebMouseEventBuilder(const Widget * widget,const RenderObject * renderObject,const TouchEvent & event)556 WebMouseEventBuilder::WebMouseEventBuilder(const Widget* widget, const RenderObject* renderObject, const TouchEvent& event)
557 {
558 if (!event.touches())
559 return;
560 if (event.touches()->length() != 1) {
561 if (event.touches()->length() || event.type() != EventTypeNames::touchend || !event.changedTouches() || event.changedTouches()->length() != 1)
562 return;
563 }
564
565 const Touch* touch = event.touches()->length() == 1 ? event.touches()->item(0) : event.changedTouches()->item(0);
566 if (touch->identifier())
567 return;
568
569 if (event.type() == EventTypeNames::touchstart)
570 type = MouseDown;
571 else if (event.type() == EventTypeNames::touchmove)
572 type = MouseMove;
573 else if (event.type() == EventTypeNames::touchend)
574 type = MouseUp;
575 else
576 return;
577
578 timeStampSeconds = event.timeStamp() / millisPerSecond;
579 modifiers = getWebInputModifiers(event);
580
581 // The mouse event co-ordinates should be generated from the co-ordinates of the touch point.
582 ScrollView* view = toScrollView(widget->parent());
583 IntPoint windowPoint = roundedIntPoint(touch->absoluteLocation());
584 if (view)
585 windowPoint = view->contentsToWindow(windowPoint);
586 IntPoint screenPoint = roundedIntPoint(touch->screenLocation());
587 globalX = screenPoint.x();
588 globalY = screenPoint.y();
589 windowX = windowPoint.x();
590 windowY = windowPoint.y();
591
592 button = WebMouseEvent::ButtonLeft;
593 modifiers |= WebInputEvent::LeftButtonDown;
594 clickCount = (type == MouseDown || type == MouseUp);
595
596 IntPoint localPoint = convertAbsoluteLocationForRenderObject(touch->absoluteLocation(), *renderObject);
597 x = localPoint.x();
598 y = localPoint.y();
599 }
600
WebMouseEventBuilder(const Widget * widget,const PlatformMouseEvent & event)601 WebMouseEventBuilder::WebMouseEventBuilder(const Widget* widget, const PlatformMouseEvent& event)
602 {
603 switch (event.type()) {
604 case PlatformEvent::MouseMoved:
605 type = MouseMove;
606 break;
607 case PlatformEvent::MousePressed:
608 type = MouseDown;
609 break;
610 case PlatformEvent::MouseReleased:
611 type = MouseUp;
612 break;
613 default:
614 ASSERT_NOT_REACHED();
615 type = Undefined;
616 return;
617 }
618
619 modifiers = 0;
620 if (event.modifiers() & PlatformEvent::ShiftKey)
621 modifiers |= ShiftKey;
622 if (event.modifiers() & PlatformEvent::CtrlKey)
623 modifiers |= ControlKey;
624 if (event.modifiers() & PlatformEvent::AltKey)
625 modifiers |= AltKey;
626 if (event.modifiers() & PlatformEvent::MetaKey)
627 modifiers |= MetaKey;
628
629 timeStampSeconds = event.timestamp();
630
631 // FIXME: Widget is always toplevel, unless it's a popup. We may be able
632 // to get rid of this once we abstract popups into a WebKit API.
633 IntPoint position = widget->convertToContainingWindow(event.position());
634 float scale = widgetInputEventsScaleFactor(widget);
635 position.scale(scale, scale);
636 x = position.x();
637 y = position.y();
638 globalX = event.globalPosition().x();
639 globalY = event.globalPosition().y();
640 movementX = event.movementDelta().x() * scale;
641 movementY = event.movementDelta().y() * scale;
642
643 button = static_cast<Button>(event.button());
644 clickCount = event.clickCount();
645 }
646
WebMouseWheelEventBuilder(const Widget * widget,const RenderObject * renderObject,const WheelEvent & event)647 WebMouseWheelEventBuilder::WebMouseWheelEventBuilder(const Widget* widget, const RenderObject* renderObject, const WheelEvent& event)
648 {
649 if (event.type() != EventTypeNames::wheel && event.type() != EventTypeNames::mousewheel)
650 return;
651 type = WebInputEvent::MouseWheel;
652 updateWebMouseEventFromCoreMouseEvent(event, *widget, *renderObject, *this);
653 deltaX = -event.deltaX();
654 deltaY = -event.deltaY();
655 wheelTicksX = event.ticksX();
656 wheelTicksY = event.ticksY();
657 scrollByPage = event.deltaMode() == WheelEvent::DOM_DELTA_PAGE;
658 }
659
WebKeyboardEventBuilder(const KeyboardEvent & event)660 WebKeyboardEventBuilder::WebKeyboardEventBuilder(const KeyboardEvent& event)
661 {
662 if (event.type() == EventTypeNames::keydown)
663 type = KeyDown;
664 else if (event.type() == EventTypeNames::keyup)
665 type = WebInputEvent::KeyUp;
666 else if (event.type() == EventTypeNames::keypress)
667 type = WebInputEvent::Char;
668 else
669 return; // Skip all other keyboard events.
670
671 modifiers = getWebInputModifiers(event);
672 if (event.location() == KeyboardEvent::DOM_KEY_LOCATION_NUMPAD)
673 modifiers |= WebInputEvent::IsKeyPad;
674 else if (event.location() == KeyboardEvent::DOM_KEY_LOCATION_LEFT)
675 modifiers |= WebInputEvent::IsLeft;
676 else if (event.location() == KeyboardEvent::DOM_KEY_LOCATION_RIGHT)
677 modifiers |= WebInputEvent::IsRight;
678
679 timeStampSeconds = event.timeStamp() / millisPerSecond;
680 windowsKeyCode = event.keyCode();
681
682 // The platform keyevent does not exist if the event was created using
683 // initKeyboardEvent.
684 if (!event.keyEvent())
685 return;
686 nativeKeyCode = event.keyEvent()->nativeVirtualKeyCode();
687 unsigned numberOfCharacters = std::min(event.keyEvent()->text().length(), static_cast<unsigned>(textLengthCap));
688 for (unsigned i = 0; i < numberOfCharacters; ++i) {
689 text[i] = event.keyEvent()->text()[i];
690 unmodifiedText[i] = event.keyEvent()->unmodifiedText()[i];
691 }
692 memcpy(keyIdentifier, event.keyIdentifier().ascii().data(), event.keyIdentifier().length());
693 }
694
toWebKeyboardEventType(PlatformEvent::Type type)695 WebInputEvent::Type toWebKeyboardEventType(PlatformEvent::Type type)
696 {
697 switch (type) {
698 case PlatformEvent::KeyUp:
699 return WebInputEvent::KeyUp;
700 case PlatformEvent::KeyDown:
701 return WebInputEvent::KeyDown;
702 case PlatformEvent::RawKeyDown:
703 return WebInputEvent::RawKeyDown;
704 case PlatformEvent::Char:
705 return WebInputEvent::Char;
706 default:
707 return WebInputEvent::Undefined;
708 }
709 }
710
toWebKeyboardEventModifiers(int modifiers)711 int toWebKeyboardEventModifiers(int modifiers)
712 {
713 int newModifiers = 0;
714 if (modifiers & PlatformEvent::ShiftKey)
715 newModifiers |= WebInputEvent::ShiftKey;
716 if (modifiers & PlatformEvent::CtrlKey)
717 newModifiers |= WebInputEvent::ControlKey;
718 if (modifiers & PlatformEvent::AltKey)
719 newModifiers |= WebInputEvent::AltKey;
720 if (modifiers & PlatformEvent::MetaKey)
721 newModifiers |= WebInputEvent::MetaKey;
722 return newModifiers;
723 }
724
WebKeyboardEventBuilder(const PlatformKeyboardEvent & event)725 WebKeyboardEventBuilder::WebKeyboardEventBuilder(const PlatformKeyboardEvent& event)
726 {
727 type = toWebKeyboardEventType(event.type());
728 modifiers = toWebKeyboardEventModifiers(event.modifiers());
729 if (event.isAutoRepeat())
730 modifiers |= WebInputEvent::IsAutoRepeat;
731 if (event.isKeypad())
732 modifiers |= WebInputEvent::IsKeyPad;
733 isSystemKey = event.isSystemKey();
734 nativeKeyCode = event.nativeVirtualKeyCode();
735
736 windowsKeyCode = windowsKeyCodeWithoutLocation(event.windowsVirtualKeyCode());
737 modifiers |= locationModifiersFromWindowsKeyCode(event.windowsVirtualKeyCode());
738
739 event.text().copyTo(text, 0, textLengthCap);
740 event.unmodifiedText().copyTo(unmodifiedText, 0, textLengthCap);
741 memcpy(keyIdentifier, event.keyIdentifier().ascii().data(), std::min(static_cast<unsigned>(keyIdentifierLengthCap), event.keyIdentifier().length()));
742 }
743
toWebTouchPoint(const Touch * touch,const RenderObject * renderObject,WebTouchPoint::State state)744 static WebTouchPoint toWebTouchPoint(const Touch* touch, const RenderObject* renderObject, WebTouchPoint::State state)
745 {
746 WebTouchPoint point;
747 point.id = touch->identifier();
748 point.screenPosition = touch->screenLocation();
749 point.position = convertAbsoluteLocationForRenderObjectFloat(touch->absoluteLocation(), *renderObject);
750 point.radiusX = touch->radiusX();
751 point.radiusY = touch->radiusY();
752 point.rotationAngle = touch->webkitRotationAngle();
753 point.force = touch->force();
754 point.state = state;
755 return point;
756 }
757
hasTouchPointWithId(const WebTouchPoint * touchPoints,unsigned touchPointsLength,unsigned id)758 static bool hasTouchPointWithId(const WebTouchPoint* touchPoints, unsigned touchPointsLength, unsigned id)
759 {
760 for (unsigned i = 0; i < touchPointsLength; ++i) {
761 if (touchPoints[i].id == static_cast<int>(id))
762 return true;
763 }
764 return false;
765 }
766
addTouchPointsIfNotYetAdded(const Widget * widget,WebTouchPoint::State state,TouchList * touches,WebTouchPoint * touchPoints,unsigned * touchPointsLength,const RenderObject * renderObject)767 static void addTouchPointsIfNotYetAdded(const Widget* widget, WebTouchPoint::State state, TouchList* touches, WebTouchPoint* touchPoints, unsigned* touchPointsLength, const RenderObject* renderObject)
768 {
769 unsigned initialTouchPointsLength = *touchPointsLength;
770 for (unsigned i = 0; i < touches->length(); ++i) {
771 const unsigned pointIndex = *touchPointsLength;
772 if (pointIndex >= static_cast<unsigned>(WebTouchEvent::touchesLengthCap))
773 return;
774
775 const Touch* touch = touches->item(i);
776 if (hasTouchPointWithId(touchPoints, initialTouchPointsLength, touch->identifier()))
777 continue;
778
779 touchPoints[pointIndex] = toWebTouchPoint(touch, renderObject, state);
780 ++(*touchPointsLength);
781 }
782 }
783
WebTouchEventBuilder(const Widget * widget,const RenderObject * renderObject,const TouchEvent & event)784 WebTouchEventBuilder::WebTouchEventBuilder(const Widget* widget, const RenderObject* renderObject, const TouchEvent& event)
785 {
786 if (event.type() == EventTypeNames::touchstart)
787 type = TouchStart;
788 else if (event.type() == EventTypeNames::touchmove)
789 type = TouchMove;
790 else if (event.type() == EventTypeNames::touchend)
791 type = TouchEnd;
792 else if (event.type() == EventTypeNames::touchcancel)
793 type = TouchCancel;
794 else {
795 ASSERT_NOT_REACHED();
796 type = Undefined;
797 return;
798 }
799
800 modifiers = getWebInputModifiers(event);
801 timeStampSeconds = event.timeStamp() / millisPerSecond;
802 cancelable = event.cancelable();
803
804 addTouchPointsIfNotYetAdded(widget, toWebTouchPointState(event.type()), event.changedTouches(), touches, &touchesLength, renderObject);
805 addTouchPointsIfNotYetAdded(widget, WebTouchPoint::StateStationary, event.touches(), touches, &touchesLength, renderObject);
806 }
807
WebGestureEventBuilder(const Widget * widget,const RenderObject * renderObject,const GestureEvent & event)808 WebGestureEventBuilder::WebGestureEventBuilder(const Widget* widget, const RenderObject* renderObject, const GestureEvent& event)
809 {
810 if (event.type() == EventTypeNames::gestureshowpress)
811 type = GestureShowPress;
812 else if (event.type() == EventTypeNames::gesturetapdown)
813 type = GestureTapDown;
814 else if (event.type() == EventTypeNames::gesturescrollstart)
815 type = GestureScrollBegin;
816 else if (event.type() == EventTypeNames::gesturescrollend)
817 type = GestureScrollEnd;
818 else if (event.type() == EventTypeNames::gesturescrollupdate) {
819 type = GestureScrollUpdate;
820 data.scrollUpdate.deltaX = event.deltaX();
821 data.scrollUpdate.deltaY = event.deltaY();
822 } else if (event.type() == EventTypeNames::gesturetap) {
823 type = GestureTap;
824 data.tap.tapCount = 1;
825 }
826
827 timeStampSeconds = event.timeStamp() / millisPerSecond;
828 modifiers = getWebInputModifiers(event);
829
830 globalX = event.screenX();
831 globalY = event.screenY();
832 IntPoint localPoint = convertAbsoluteLocationForRenderObject(event.absoluteLocation(), *renderObject);
833 x = localPoint.x();
834 y = localPoint.y();
835 }
836
837 } // namespace blink
838