2 * Copyright (C) 2009 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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
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.
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.
32 #include "web/WebInputEventConversion.h"
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/VisualViewport.h"
44 #include "core/layout/LayoutObject.h"
45 #include "core/page/ChromeClient.h"
46 #include "core/page/Page.h"
47 #include "platform/KeyboardCodes.h"
48 #include "platform/Widget.h"
49 #include "public/platform/Platform.h"
53 static const double millisPerSecond
= 1000.0;
55 static float scaleDeltaToWindow(const Widget
* widget
, float delta
)
59 FrameView
* rootView
= toFrameView(widget
->root());
61 scale
= rootView
->inputEventsScaleFactor();
66 static FloatSize
scaleSizeToWindow(const Widget
* widget
, FloatSize size
)
68 return FloatSize(scaleDeltaToWindow(widget
, size
.width()), scaleDeltaToWindow(widget
, size
.height()));
71 static FloatPoint
convertHitPointToWindow(const Widget
* widget
, FloatPoint point
)
75 IntPoint visualViewport
;
76 FloatSize overscrollOffset
;
78 FrameView
* rootView
= toFrameView(widget
->root());
80 scale
= rootView
->inputEventsScaleFactor();
81 offset
= rootView
->inputEventsOffsetForEmulation();
82 visualViewport
= flooredIntPoint(rootView
->page()->frameHost().visualViewport().visibleRect().location());
83 overscrollOffset
= rootView
->page()->frameHost().chromeClient().elasticOverscroll();
87 (point
.x() - offset
.width()) / scale
+ visualViewport
.x() + overscrollOffset
.width(),
88 (point
.y() - offset
.height()) / scale
+ visualViewport
.y() + overscrollOffset
.height());
91 static unsigned toPlatformEventModifiers(int webModifiers
)
93 unsigned newModifiers
= 0;
94 if (webModifiers
& WebInputEvent::ShiftKey
)
95 newModifiers
|= PlatformEvent::ShiftKey
;
96 if (webModifiers
& WebInputEvent::ControlKey
)
97 newModifiers
|= PlatformEvent::CtrlKey
;
98 if (webModifiers
& WebInputEvent::AltKey
)
99 newModifiers
|= PlatformEvent::AltKey
;
100 if (webModifiers
& WebInputEvent::MetaKey
)
101 newModifiers
|= PlatformEvent::MetaKey
;
105 static unsigned toPlatformKeyboardEventModifiers(int webModifiers
)
107 unsigned newModifiers
= toPlatformEventModifiers(webModifiers
);
108 if (webModifiers
& WebInputEvent::IsKeyPad
)
109 newModifiers
|= PlatformEvent::IsKeyPad
;
110 if (webModifiers
& WebInputEvent::IsAutoRepeat
)
111 newModifiers
|= PlatformEvent::IsAutoRepeat
;
112 if (webModifiers
& WebInputEvent::IsLeft
)
113 newModifiers
|= PlatformEvent::IsLeft
;
114 if (webModifiers
& WebInputEvent::IsRight
)
115 newModifiers
|= PlatformEvent::IsRight
;
119 unsigned toPlatformMouseEventModifiers(int webModifiers
)
121 unsigned newModifiers
= toPlatformEventModifiers(webModifiers
);
122 if (webModifiers
& WebInputEvent::LeftButtonDown
)
123 newModifiers
|= PlatformEvent::LeftButtonDown
;
124 if (webModifiers
& WebInputEvent::MiddleButtonDown
)
125 newModifiers
|= PlatformEvent::MiddleButtonDown
;
126 if (webModifiers
& WebInputEvent::RightButtonDown
)
127 newModifiers
|= PlatformEvent::RightButtonDown
;
131 static unsigned toPlatformModifierFrom(WebMouseEvent::Button button
)
133 if (button
== WebMouseEvent::ButtonNone
)
136 unsigned webMouseButtonToPlatformModifier
[] = {
137 PlatformEvent::LeftButtonDown
,
138 PlatformEvent::MiddleButtonDown
,
139 PlatformEvent::RightButtonDown
142 return webMouseButtonToPlatformModifier
[button
];
145 // MakePlatformMouseEvent -----------------------------------------------------
147 PlatformMouseEventBuilder::PlatformMouseEventBuilder(Widget
* widget
, const WebMouseEvent
& e
)
149 // FIXME: Widget is always toplevel, unless it's a popup. We may be able
150 // to get rid of this once we abstract popups into a WebKit API.
151 m_position
= widget
->convertFromContainingWindow(flooredIntPoint(convertHitPointToWindow(widget
, IntPoint(e
.x
, e
.y
))));
152 m_globalPosition
= IntPoint(e
.globalX
, e
.globalY
);
153 m_movementDelta
= IntPoint(scaleDeltaToWindow(widget
, e
.movementX
), scaleDeltaToWindow(widget
, e
.movementY
));
154 m_button
= static_cast<MouseButton
>(e
.button
);
155 m_modifiers
= toPlatformMouseEventModifiers(e
.modifiers
);
157 m_timestamp
= e
.timeStampSeconds
;
158 m_clickCount
= e
.clickCount
;
161 case WebInputEvent::MouseMove
:
162 case WebInputEvent::MouseLeave
: // synthesize a move event
163 m_type
= PlatformEvent::MouseMoved
;
166 case WebInputEvent::MouseDown
:
167 m_type
= PlatformEvent::MousePressed
;
170 case WebInputEvent::MouseUp
:
171 m_type
= PlatformEvent::MouseReleased
;
173 // The MouseEvent spec requires that buttons indicates the state
174 // immediately after the event takes place. To ensure consistency
175 // between platforms here, we explicitly clear the button that is
176 // in the process of being released.
177 m_modifiers
&= ~toPlatformModifierFrom(e
.button
);
181 ASSERT_NOT_REACHED();
185 // PlatformWheelEventBuilder --------------------------------------------------
187 PlatformWheelEventBuilder::PlatformWheelEventBuilder(Widget
* widget
, const WebMouseWheelEvent
& e
)
189 m_position
= widget
->convertFromContainingWindow(flooredIntPoint(convertHitPointToWindow(widget
, FloatPoint(e
.x
, e
.y
))));
190 m_globalPosition
= IntPoint(e
.globalX
, e
.globalY
);
193 m_wheelTicksX
= e
.wheelTicksX
;
194 m_wheelTicksY
= e
.wheelTicksY
;
195 m_granularity
= e
.scrollByPage
?
196 ScrollByPageWheelEvent
: ScrollByPixelWheelEvent
;
198 m_type
= PlatformEvent::Wheel
;
200 m_modifiers
= toPlatformMouseEventModifiers(e
.modifiers
);
202 m_hasPreciseScrollingDeltas
= e
.hasPreciseScrollingDeltas
;
203 m_canScroll
= e
.canScroll
;
204 m_resendingPluginId
= e
.resendingPluginId
;
205 m_railsMode
= static_cast<PlatformEvent::RailsMode
>(e
.railsMode
);
207 m_phase
= static_cast<PlatformWheelEventPhase
>(e
.phase
);
208 m_momentumPhase
= static_cast<PlatformWheelEventPhase
>(e
.momentumPhase
);
209 m_timestamp
= e
.timeStampSeconds
;
210 m_canRubberbandLeft
= e
.canRubberbandLeft
;
211 m_canRubberbandRight
= e
.canRubberbandRight
;
215 // PlatformGestureEventBuilder --------------------------------------------------
217 PlatformGestureEventBuilder::PlatformGestureEventBuilder(Widget
* widget
, const WebGestureEvent
& e
)
220 case WebInputEvent::GestureScrollBegin
:
221 m_type
= PlatformEvent::GestureScrollBegin
;
222 m_data
.m_scroll
.m_resendingPluginId
= e
.resendingPluginId
;
224 case WebInputEvent::GestureScrollEnd
:
225 m_type
= PlatformEvent::GestureScrollEnd
;
226 m_data
.m_scroll
.m_resendingPluginId
= e
.resendingPluginId
;
228 case WebInputEvent::GestureFlingStart
:
229 m_type
= PlatformEvent::GestureFlingStart
;
230 m_data
.m_scroll
.m_velocityX
= e
.data
.flingStart
.velocityX
;
231 m_data
.m_scroll
.m_velocityY
= e
.data
.flingStart
.velocityY
;
233 case WebInputEvent::GestureScrollUpdate
:
234 m_type
= PlatformEvent::GestureScrollUpdate
;
235 m_data
.m_scroll
.m_resendingPluginId
= e
.resendingPluginId
;
236 m_data
.m_scroll
.m_deltaX
= scaleDeltaToWindow(widget
, e
.data
.scrollUpdate
.deltaX
);
237 m_data
.m_scroll
.m_deltaY
= scaleDeltaToWindow(widget
, e
.data
.scrollUpdate
.deltaY
);
238 m_data
.m_scroll
.m_velocityX
= e
.data
.scrollUpdate
.velocityX
;
239 m_data
.m_scroll
.m_velocityY
= e
.data
.scrollUpdate
.velocityY
;
240 m_data
.m_scroll
.m_preventPropagation
= e
.data
.scrollUpdate
.preventPropagation
;
241 m_data
.m_scroll
.m_inertial
= e
.data
.scrollUpdate
.inertial
;
243 case WebInputEvent::GestureTap
:
244 m_type
= PlatformEvent::GestureTap
;
245 m_area
= expandedIntSize(scaleSizeToWindow(widget
, FloatSize(e
.data
.tap
.width
, e
.data
.tap
.height
)));
246 m_data
.m_tap
.m_tapCount
= e
.data
.tap
.tapCount
;
248 case WebInputEvent::GestureTapUnconfirmed
:
249 m_type
= PlatformEvent::GestureTapUnconfirmed
;
250 m_area
= expandedIntSize(scaleSizeToWindow(widget
, FloatSize(e
.data
.tap
.width
, e
.data
.tap
.height
)));
252 case WebInputEvent::GestureTapDown
:
253 m_type
= PlatformEvent::GestureTapDown
;
254 m_area
= expandedIntSize(scaleSizeToWindow(widget
, FloatSize(e
.data
.tapDown
.width
, e
.data
.tapDown
.height
)));
256 case WebInputEvent::GestureShowPress
:
257 m_type
= PlatformEvent::GestureShowPress
;
258 m_area
= expandedIntSize(scaleSizeToWindow(widget
, FloatSize(e
.data
.showPress
.width
, e
.data
.showPress
.height
)));
260 case WebInputEvent::GestureTapCancel
:
261 m_type
= PlatformEvent::GestureTapDownCancel
;
263 case WebInputEvent::GestureDoubleTap
:
264 // DoubleTap gesture is now handled as PlatformEvent::GestureTap with tap_count = 2. So no
265 // need to convert to a Platfrom DoubleTap gesture. But in WebViewImpl::handleGestureEvent
266 // all WebGestureEvent are converted to PlatformGestureEvent, for completeness and not reach
267 // the ASSERT_NOT_REACHED() at the end, convert the DoubleTap to a NoType.
268 m_type
= PlatformEvent::NoType
;
270 case WebInputEvent::GestureTwoFingerTap
:
271 m_type
= PlatformEvent::GestureTwoFingerTap
;
272 m_area
= expandedIntSize(scaleSizeToWindow(widget
, FloatSize(e
.data
.twoFingerTap
.firstFingerWidth
, e
.data
.twoFingerTap
.firstFingerHeight
)));
274 case WebInputEvent::GestureLongPress
:
275 m_type
= PlatformEvent::GestureLongPress
;
276 m_area
= expandedIntSize(scaleSizeToWindow(widget
, FloatSize(e
.data
.longPress
.width
, e
.data
.longPress
.height
)));
278 case WebInputEvent::GestureLongTap
:
279 m_type
= PlatformEvent::GestureLongTap
;
280 m_area
= expandedIntSize(scaleSizeToWindow(widget
, FloatSize(e
.data
.longPress
.width
, e
.data
.longPress
.height
)));
282 case WebInputEvent::GesturePinchBegin
:
283 m_type
= PlatformEvent::GesturePinchBegin
;
285 case WebInputEvent::GesturePinchEnd
:
286 m_type
= PlatformEvent::GesturePinchEnd
;
288 case WebInputEvent::GesturePinchUpdate
:
289 m_type
= PlatformEvent::GesturePinchUpdate
;
290 m_data
.m_pinchUpdate
.m_scale
= e
.data
.pinchUpdate
.scale
;
293 ASSERT_NOT_REACHED();
295 m_position
= widget
->convertFromContainingWindow(flooredIntPoint(convertHitPointToWindow(widget
, FloatPoint(e
.x
, e
.y
))));
296 m_globalPosition
= IntPoint(e
.globalX
, e
.globalY
);
297 m_timestamp
= e
.timeStampSeconds
;
298 m_modifiers
= toPlatformEventModifiers(e
.modifiers
);
301 // MakePlatformKeyboardEvent --------------------------------------------------
303 inline PlatformEvent::Type
toPlatformKeyboardEventType(WebInputEvent::Type type
)
306 case WebInputEvent::KeyUp
:
307 return PlatformEvent::KeyUp
;
308 case WebInputEvent::KeyDown
:
309 return PlatformEvent::KeyDown
;
310 case WebInputEvent::RawKeyDown
:
311 return PlatformEvent::RawKeyDown
;
312 case WebInputEvent::Char
:
313 return PlatformEvent::Char
;
315 ASSERT_NOT_REACHED();
317 return PlatformEvent::KeyDown
;
320 PlatformKeyboardEventBuilder::PlatformKeyboardEventBuilder(const WebKeyboardEvent
& e
)
322 m_type
= toPlatformKeyboardEventType(e
.type
);
323 m_text
= String(e
.text
);
324 m_unmodifiedText
= String(e
.unmodifiedText
);
325 m_keyIdentifier
= String(e
.keyIdentifier
);
326 m_nativeVirtualKeyCode
= e
.nativeKeyCode
;
327 m_isSystemKey
= e
.isSystemKey
;
328 // TODO: BUG482880 Fix this initialization to lazy initialization.
329 m_code
= Platform::current()->domCodeStringFromEnum(e
.domCode
);
330 m_key
= Platform::current()->domKeyStringFromEnum(e
.domKey
);
332 m_modifiers
= toPlatformKeyboardEventModifiers(e
.modifiers
);
333 m_windowsVirtualKeyCode
= e
.windowsKeyCode
;
336 void PlatformKeyboardEventBuilder::setKeyType(Type type
)
338 // According to the behavior of Webkit in Windows platform,
339 // we need to convert KeyDown to RawKeydown and Char events
340 // See WebKit/WebKit/Win/WebView.cpp
341 ASSERT(m_type
== KeyDown
);
342 ASSERT(type
== RawKeyDown
|| type
== Char
);
345 if (type
== RawKeyDown
) {
347 m_unmodifiedText
= String();
349 m_keyIdentifier
= String();
350 m_windowsVirtualKeyCode
= 0;
354 // Please refer to bug http://b/issue?id=961192, which talks about Webkit
355 // keyboard event handling changes. It also mentions the list of keys
356 // which don't have associated character events.
357 bool PlatformKeyboardEventBuilder::isCharacterKey() const
359 switch (windowsVirtualKeyCode()) {
367 inline PlatformEvent::Type
toPlatformTouchEventType(const WebInputEvent::Type type
)
370 case WebInputEvent::TouchStart
:
371 return PlatformEvent::TouchStart
;
372 case WebInputEvent::TouchMove
:
373 return PlatformEvent::TouchMove
;
374 case WebInputEvent::TouchEnd
:
375 return PlatformEvent::TouchEnd
;
376 case WebInputEvent::TouchCancel
:
377 return PlatformEvent::TouchCancel
;
379 ASSERT_NOT_REACHED();
381 return PlatformEvent::TouchStart
;
384 inline PlatformTouchPoint::State
toPlatformTouchPointState(const WebTouchPoint::State state
)
387 case WebTouchPoint::StateReleased
:
388 return PlatformTouchPoint::TouchReleased
;
389 case WebTouchPoint::StatePressed
:
390 return PlatformTouchPoint::TouchPressed
;
391 case WebTouchPoint::StateMoved
:
392 return PlatformTouchPoint::TouchMoved
;
393 case WebTouchPoint::StateStationary
:
394 return PlatformTouchPoint::TouchStationary
;
395 case WebTouchPoint::StateCancelled
:
396 return PlatformTouchPoint::TouchCancelled
;
397 case WebTouchPoint::StateUndefined
:
398 ASSERT_NOT_REACHED();
400 return PlatformTouchPoint::TouchReleased
;
403 inline WebTouchPoint::State
toWebTouchPointState(const AtomicString
& type
)
405 if (type
== EventTypeNames::touchend
)
406 return WebTouchPoint::StateReleased
;
407 if (type
== EventTypeNames::touchcancel
)
408 return WebTouchPoint::StateCancelled
;
409 if (type
== EventTypeNames::touchstart
)
410 return WebTouchPoint::StatePressed
;
411 if (type
== EventTypeNames::touchmove
)
412 return WebTouchPoint::StateMoved
;
413 return WebTouchPoint::StateUndefined
;
416 PlatformTouchPointBuilder::PlatformTouchPointBuilder(Widget
* widget
, const WebTouchPoint
& point
)
418 m_pointerProperties
= point
;
419 m_state
= toPlatformTouchPointState(point
.state
);
421 // This assumes convertFromContainingWindow does only translations, not scales.
422 FloatPoint floatPos
= convertHitPointToWindow(widget
, point
.position
);
423 IntPoint flooredPoint
= flooredIntPoint(floatPos
);
424 m_pos
= widget
->convertFromContainingWindow(flooredPoint
) + (floatPos
- flooredPoint
);
426 m_screenPos
= FloatPoint(point
.screenPosition
.x
, point
.screenPosition
.y
);
427 m_radius
= scaleSizeToWindow(widget
, FloatSize(point
.radiusX
, point
.radiusY
));
428 m_rotationAngle
= point
.rotationAngle
;
431 PlatformTouchEventBuilder::PlatformTouchEventBuilder(Widget
* widget
, const WebTouchEvent
& event
)
433 m_type
= toPlatformTouchEventType(event
.type
);
434 m_modifiers
= toPlatformEventModifiers(event
.modifiers
);
435 m_timestamp
= event
.timeStampSeconds
;
436 m_causesScrollingIfUncanceled
= event
.causesScrollingIfUncanceled
;
438 for (unsigned i
= 0; i
< event
.touchesLength
; ++i
)
439 m_touchPoints
.append(PlatformTouchPointBuilder(widget
, event
.touches
[i
]));
441 m_cancelable
= event
.cancelable
;
444 static int getWebInputModifiers(const UIEventWithKeyState
& event
)
448 modifiers
|= WebInputEvent::ControlKey
;
449 if (event
.shiftKey())
450 modifiers
|= WebInputEvent::ShiftKey
;
452 modifiers
|= WebInputEvent::AltKey
;
454 modifiers
|= WebInputEvent::MetaKey
;
458 static FloatPoint
convertAbsoluteLocationForLayoutObjectFloat(const LayoutPoint
& location
, const LayoutObject
& layoutObject
)
460 return layoutObject
.absoluteToLocal(FloatPoint(location
), UseTransforms
);
463 static IntPoint
convertAbsoluteLocationForLayoutObject(const LayoutPoint
& location
, const LayoutObject
& layoutObject
)
465 return roundedIntPoint(convertAbsoluteLocationForLayoutObjectFloat(location
, layoutObject
));
468 // FIXME: Change |widget| to const Widget& after RemoteFrames get
470 static void updateWebMouseEventFromCoreMouseEvent(const MouseRelatedEvent
& event
, const Widget
* widget
, const LayoutObject
& layoutObject
, WebMouseEvent
& webEvent
)
472 webEvent
.timeStampSeconds
= event
.timeStamp() / millisPerSecond
;
473 webEvent
.modifiers
= getWebInputModifiers(event
);
475 FrameView
* view
= widget
? toFrameView(widget
->parent()) : 0;
476 // FIXME: If view == nullptr, pointInRootFrame will really be pointInRootContent.
477 IntPoint pointInRootFrame
= IntPoint(event
.absoluteLocation().x(), event
.absoluteLocation().y());
479 pointInRootFrame
= view
->contentsToRootFrame(pointInRootFrame
);
480 webEvent
.globalX
= event
.screenX();
481 webEvent
.globalY
= event
.screenY();
482 webEvent
.windowX
= pointInRootFrame
.x();
483 webEvent
.windowY
= pointInRootFrame
.y();
484 IntPoint localPoint
= convertAbsoluteLocationForLayoutObject(event
.absoluteLocation(), layoutObject
);
485 webEvent
.x
= localPoint
.x();
486 webEvent
.y
= localPoint
.y();
489 WebMouseEventBuilder::WebMouseEventBuilder(const Widget
* widget
, const LayoutObject
* layoutObject
, const MouseEvent
& event
)
491 if (event
.type() == EventTypeNames::mousemove
)
492 type
= WebInputEvent::MouseMove
;
493 else if (event
.type() == EventTypeNames::mouseout
)
494 type
= WebInputEvent::MouseLeave
;
495 else if (event
.type() == EventTypeNames::mouseover
)
496 type
= WebInputEvent::MouseEnter
;
497 else if (event
.type() == EventTypeNames::mousedown
)
498 type
= WebInputEvent::MouseDown
;
499 else if (event
.type() == EventTypeNames::mouseup
)
500 type
= WebInputEvent::MouseUp
;
501 else if (event
.type() == EventTypeNames::contextmenu
)
502 type
= WebInputEvent::ContextMenu
;
504 return; // Skip all other mouse events.
506 updateWebMouseEventFromCoreMouseEvent(event
, widget
, *layoutObject
, *this);
508 switch (event
.button()) {
510 button
= WebMouseEvent::ButtonLeft
;
513 button
= WebMouseEvent::ButtonMiddle
;
516 button
= WebMouseEvent::ButtonRight
;
519 if (event
.buttonDown()) {
520 switch (event
.button()) {
522 modifiers
|= WebInputEvent::LeftButtonDown
;
525 modifiers
|= WebInputEvent::MiddleButtonDown
;
528 modifiers
|= WebInputEvent::RightButtonDown
;
532 button
= WebMouseEvent::ButtonNone
;
533 movementX
= event
.movementX();
534 movementY
= event
.movementY();
535 clickCount
= event
.detail();
538 // Generate a synthetic WebMouseEvent given a TouchEvent (eg. for emulating a mouse
539 // with touch input for plugins that don't support touch input).
540 WebMouseEventBuilder::WebMouseEventBuilder(const Widget
* widget
, const LayoutObject
* layoutObject
, const TouchEvent
& event
)
542 if (!event
.touches())
544 if (event
.touches()->length() != 1) {
545 if (event
.touches()->length() || event
.type() != EventTypeNames::touchend
|| !event
.changedTouches() || event
.changedTouches()->length() != 1)
549 const Touch
* touch
= event
.touches()->length() == 1 ? event
.touches()->item(0) : event
.changedTouches()->item(0);
550 if (touch
->identifier())
553 if (event
.type() == EventTypeNames::touchstart
)
555 else if (event
.type() == EventTypeNames::touchmove
)
557 else if (event
.type() == EventTypeNames::touchend
)
562 timeStampSeconds
= event
.timeStamp() / millisPerSecond
;
563 modifiers
= getWebInputModifiers(event
);
565 // The mouse event co-ordinates should be generated from the co-ordinates of the touch point.
566 FrameView
* view
= toFrameView(widget
->parent());
567 // FIXME: if view == nullptr, pointInRootFrame will really be pointInRootContent.
568 IntPoint pointInRootFrame
= roundedIntPoint(touch
->absoluteLocation());
570 pointInRootFrame
= view
->contentsToRootFrame(pointInRootFrame
);
571 IntPoint screenPoint
= roundedIntPoint(touch
->screenLocation());
572 globalX
= screenPoint
.x();
573 globalY
= screenPoint
.y();
574 windowX
= pointInRootFrame
.x();
575 windowY
= pointInRootFrame
.y();
577 button
= WebMouseEvent::ButtonLeft
;
578 modifiers
|= WebInputEvent::LeftButtonDown
;
579 clickCount
= (type
== MouseDown
|| type
== MouseUp
);
581 IntPoint localPoint
= convertAbsoluteLocationForLayoutObject(touch
->absoluteLocation(), *layoutObject
);
586 WebMouseWheelEventBuilder::WebMouseWheelEventBuilder(const Widget
* widget
, const LayoutObject
* layoutObject
, const WheelEvent
& event
)
588 if (event
.type() != EventTypeNames::wheel
&& event
.type() != EventTypeNames::mousewheel
)
590 type
= WebInputEvent::MouseWheel
;
591 updateWebMouseEventFromCoreMouseEvent(event
, widget
, *layoutObject
, *this);
592 deltaX
= -event
.deltaX();
593 deltaY
= -event
.deltaY();
594 wheelTicksX
= event
.ticksX();
595 wheelTicksY
= event
.ticksY();
596 scrollByPage
= event
.deltaMode() == WheelEvent::DOM_DELTA_PAGE
;
597 canScroll
= event
.canScroll();
598 resendingPluginId
= event
.resendingPluginId();
599 railsMode
= static_cast<RailsMode
>(event
.railsMode());
602 WebKeyboardEventBuilder::WebKeyboardEventBuilder(const KeyboardEvent
& event
)
604 if (event
.type() == EventTypeNames::keydown
)
606 else if (event
.type() == EventTypeNames::keyup
)
607 type
= WebInputEvent::KeyUp
;
608 else if (event
.type() == EventTypeNames::keypress
)
609 type
= WebInputEvent::Char
;
611 return; // Skip all other keyboard events.
613 modifiers
= getWebInputModifiers(event
);
614 if (event
.location() == KeyboardEvent::DOM_KEY_LOCATION_NUMPAD
)
615 modifiers
|= WebInputEvent::IsKeyPad
;
616 else if (event
.location() == KeyboardEvent::DOM_KEY_LOCATION_LEFT
)
617 modifiers
|= WebInputEvent::IsLeft
;
618 else if (event
.location() == KeyboardEvent::DOM_KEY_LOCATION_RIGHT
)
619 modifiers
|= WebInputEvent::IsRight
;
621 timeStampSeconds
= event
.timeStamp() / millisPerSecond
;
622 windowsKeyCode
= event
.keyCode();
624 // The platform keyevent does not exist if the event was created using
625 // initKeyboardEvent.
626 if (!event
.keyEvent())
628 nativeKeyCode
= event
.keyEvent()->nativeVirtualKeyCode();
629 domCode
= Platform::current()->domEnumFromCodeString(event
.keyEvent()->code());
630 domKey
= Platform::current()->domKeyEnumFromString(event
.keyEvent()->key());
631 unsigned numberOfCharacters
= std::min(event
.keyEvent()->text().length(), static_cast<unsigned>(textLengthCap
));
632 for (unsigned i
= 0; i
< numberOfCharacters
; ++i
) {
633 text
[i
] = event
.keyEvent()->text()[i
];
634 unmodifiedText
[i
] = event
.keyEvent()->unmodifiedText()[i
];
636 memcpy(keyIdentifier
, event
.keyIdentifier().ascii().data(), event
.keyIdentifier().length());
639 WebInputEvent::Type
toWebKeyboardEventType(PlatformEvent::Type type
)
642 case PlatformEvent::KeyUp
:
643 return WebInputEvent::KeyUp
;
644 case PlatformEvent::KeyDown
:
645 return WebInputEvent::KeyDown
;
646 case PlatformEvent::RawKeyDown
:
647 return WebInputEvent::RawKeyDown
;
648 case PlatformEvent::Char
:
649 return WebInputEvent::Char
;
651 return WebInputEvent::Undefined
;
655 static WebTouchPoint
toWebTouchPoint(const Touch
* touch
, const LayoutObject
* layoutObject
, WebTouchPoint::State state
)
658 point
.id
= touch
->identifier();
659 point
.screenPosition
= touch
->screenLocation();
660 point
.position
= convertAbsoluteLocationForLayoutObjectFloat(touch
->absoluteLocation(), *layoutObject
);
661 point
.radiusX
= touch
->radiusX();
662 point
.radiusY
= touch
->radiusY();
663 point
.rotationAngle
= touch
->rotationAngle();
664 point
.force
= touch
->force();
669 static unsigned indexOfTouchPointWithId(const WebTouchPoint
* touchPoints
, unsigned touchPointsLength
, unsigned id
)
671 for (unsigned i
= 0; i
< touchPointsLength
; ++i
) {
672 if (touchPoints
[i
].id
== static_cast<int>(id
))
675 return std::numeric_limits
<unsigned>::max();
678 static void addTouchPointsUpdateStateIfNecessary(WebTouchPoint::State state
, TouchList
* touches
, WebTouchPoint
* touchPoints
, unsigned* touchPointsLength
, const LayoutObject
* layoutObject
)
680 unsigned initialTouchPointsLength
= *touchPointsLength
;
681 for (unsigned i
= 0; i
< touches
->length(); ++i
) {
682 const unsigned pointIndex
= *touchPointsLength
;
683 if (pointIndex
>= static_cast<unsigned>(WebTouchEvent::touchesLengthCap
))
686 const Touch
* touch
= touches
->item(i
);
687 unsigned existingPointIndex
= indexOfTouchPointWithId(touchPoints
, initialTouchPointsLength
, touch
->identifier());
688 if (existingPointIndex
!= std::numeric_limits
<unsigned>::max()) {
689 touchPoints
[existingPointIndex
].state
= state
;
691 touchPoints
[pointIndex
] = toWebTouchPoint(touch
, layoutObject
, state
);
692 ++(*touchPointsLength
);
697 WebTouchEventBuilder::WebTouchEventBuilder(const LayoutObject
* layoutObject
, const TouchEvent
& event
)
699 if (event
.type() == EventTypeNames::touchstart
)
701 else if (event
.type() == EventTypeNames::touchmove
)
703 else if (event
.type() == EventTypeNames::touchend
)
705 else if (event
.type() == EventTypeNames::touchcancel
)
708 ASSERT_NOT_REACHED();
713 modifiers
= getWebInputModifiers(event
);
714 timeStampSeconds
= event
.timeStamp() / millisPerSecond
;
715 cancelable
= event
.cancelable();
716 causesScrollingIfUncanceled
= event
.causesScrollingIfUncanceled();
718 // Currently touches[] is empty, add stationary points as-is.
719 for (unsigned i
= 0; i
< event
.touches()->length() && i
< static_cast<unsigned>(WebTouchEvent::touchesLengthCap
); ++i
) {
720 touches
[i
] = toWebTouchPoint(event
.touches()->item(i
), layoutObject
, WebTouchPoint::StateStationary
);
723 // If any existing points are also in the change list, we should update
724 // their state, otherwise just add the new points.
725 addTouchPointsUpdateStateIfNecessary(toWebTouchPointState(event
.type()), event
.changedTouches(), touches
, &touchesLength
, layoutObject
);
728 WebGestureEventBuilder::WebGestureEventBuilder(const LayoutObject
* layoutObject
, const GestureEvent
& event
)
730 if (event
.type() == EventTypeNames::gestureshowpress
) {
731 type
= GestureShowPress
;
732 } else if (event
.type() == EventTypeNames::gesturelongpress
) {
733 type
= GestureLongPress
;
734 } else if (event
.type() == EventTypeNames::gesturetapdown
) {
735 type
= GestureTapDown
;
736 } else if (event
.type() == EventTypeNames::gesturescrollstart
) {
737 type
= GestureScrollBegin
;
738 resendingPluginId
= event
.resendingPluginId();
739 } else if (event
.type() == EventTypeNames::gesturescrollend
) {
740 type
= GestureScrollEnd
;
741 resendingPluginId
= event
.resendingPluginId();
742 } else if (event
.type() == EventTypeNames::gesturescrollupdate
) {
743 type
= GestureScrollUpdate
;
744 data
.scrollUpdate
.deltaX
= event
.deltaX();
745 data
.scrollUpdate
.deltaY
= event
.deltaY();
746 data
.scrollUpdate
.inertial
= event
.inertial();
747 resendingPluginId
= event
.resendingPluginId();
748 } else if (event
.type() == EventTypeNames::gestureflingstart
) {
749 type
= GestureFlingStart
;
750 data
.flingStart
.velocityX
= event
.velocityX();
751 data
.flingStart
.velocityY
= event
.velocityY();
752 } else if (event
.type() == EventTypeNames::gesturetap
) {
754 data
.tap
.tapCount
= 1;
757 timeStampSeconds
= event
.timeStamp() / millisPerSecond
;
758 modifiers
= getWebInputModifiers(event
);
760 globalX
= event
.screenX();
761 globalY
= event
.screenY();
762 IntPoint localPoint
= convertAbsoluteLocationForLayoutObject(event
.absoluteLocation(), *layoutObject
);