Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / WebKit / Source / web / WebInputEventConversion.cpp
blob6083b1e06df1648808cb2e5877611b1019e7f5a9
1 /*
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
6 * met:
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.
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.
31 #include "config.h"
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"
51 namespace blink {
53 static const double millisPerSecond = 1000.0;
55 static float scaleDeltaToWindow(const Widget* widget, float delta)
57 float scale = 1;
58 if (widget) {
59 FrameView* rootView = toFrameView(widget->root());
60 if (rootView)
61 scale = rootView->inputEventsScaleFactor();
63 return delta / scale;
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)
73 float scale = 1;
74 IntSize offset;
75 IntPoint visualViewport;
76 FloatSize overscrollOffset;
77 if (widget) {
78 FrameView* rootView = toFrameView(widget->root());
79 if (rootView) {
80 scale = rootView->inputEventsScaleFactor();
81 offset = rootView->inputEventsOffsetForEmulation();
82 visualViewport = flooredIntPoint(rootView->page()->frameHost().visualViewport().visibleRect().location());
83 overscrollOffset = rootView->page()->frameHost().chromeClient().elasticOverscroll();
86 return FloatPoint(
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;
102 return newModifiers;
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;
116 return newModifiers;
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;
128 return newModifiers;
131 static unsigned toPlatformModifierFrom(WebMouseEvent::Button button)
133 if (button == WebMouseEvent::ButtonNone)
134 return 0;
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;
160 switch (e.type) {
161 case WebInputEvent::MouseMove:
162 case WebInputEvent::MouseLeave: // synthesize a move event
163 m_type = PlatformEvent::MouseMoved;
164 break;
166 case WebInputEvent::MouseDown:
167 m_type = PlatformEvent::MousePressed;
168 break;
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);
178 break;
180 default:
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);
191 m_deltaX = e.deltaX;
192 m_deltaY = e.deltaY;
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);
206 #if OS(MACOSX)
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;
212 #endif
215 // PlatformGestureEventBuilder --------------------------------------------------
217 PlatformGestureEventBuilder::PlatformGestureEventBuilder(Widget* widget, const WebGestureEvent& e)
219 switch (e.type) {
220 case WebInputEvent::GestureScrollBegin:
221 m_type = PlatformEvent::GestureScrollBegin;
222 m_data.m_scroll.m_resendingPluginId = e.resendingPluginId;
223 break;
224 case WebInputEvent::GestureScrollEnd:
225 m_type = PlatformEvent::GestureScrollEnd;
226 m_data.m_scroll.m_resendingPluginId = e.resendingPluginId;
227 break;
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;
232 break;
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;
242 break;
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;
247 break;
248 case WebInputEvent::GestureTapUnconfirmed:
249 m_type = PlatformEvent::GestureTapUnconfirmed;
250 m_area = expandedIntSize(scaleSizeToWindow(widget, FloatSize(e.data.tap.width, e.data.tap.height)));
251 break;
252 case WebInputEvent::GestureTapDown:
253 m_type = PlatformEvent::GestureTapDown;
254 m_area = expandedIntSize(scaleSizeToWindow(widget, FloatSize(e.data.tapDown.width, e.data.tapDown.height)));
255 break;
256 case WebInputEvent::GestureShowPress:
257 m_type = PlatformEvent::GestureShowPress;
258 m_area = expandedIntSize(scaleSizeToWindow(widget, FloatSize(e.data.showPress.width, e.data.showPress.height)));
259 break;
260 case WebInputEvent::GestureTapCancel:
261 m_type = PlatformEvent::GestureTapDownCancel;
262 break;
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;
269 break;
270 case WebInputEvent::GestureTwoFingerTap:
271 m_type = PlatformEvent::GestureTwoFingerTap;
272 m_area = expandedIntSize(scaleSizeToWindow(widget, FloatSize(e.data.twoFingerTap.firstFingerWidth, e.data.twoFingerTap.firstFingerHeight)));
273 break;
274 case WebInputEvent::GestureLongPress:
275 m_type = PlatformEvent::GestureLongPress;
276 m_area = expandedIntSize(scaleSizeToWindow(widget, FloatSize(e.data.longPress.width, e.data.longPress.height)));
277 break;
278 case WebInputEvent::GestureLongTap:
279 m_type = PlatformEvent::GestureLongTap;
280 m_area = expandedIntSize(scaleSizeToWindow(widget, FloatSize(e.data.longPress.width, e.data.longPress.height)));
281 break;
282 case WebInputEvent::GesturePinchBegin:
283 m_type = PlatformEvent::GesturePinchBegin;
284 break;
285 case WebInputEvent::GesturePinchEnd:
286 m_type = PlatformEvent::GesturePinchEnd;
287 break;
288 case WebInputEvent::GesturePinchUpdate:
289 m_type = PlatformEvent::GesturePinchUpdate;
290 m_data.m_pinchUpdate.m_scale = e.data.pinchUpdate.scale;
291 break;
292 default:
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)
305 switch (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;
314 default:
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);
343 m_type = type;
345 if (type == RawKeyDown) {
346 m_text = String();
347 m_unmodifiedText = String();
348 } else {
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()) {
360 case VKEY_BACK:
361 case VKEY_ESCAPE:
362 return false;
364 return true;
367 inline PlatformEvent::Type toPlatformTouchEventType(const WebInputEvent::Type type)
369 switch (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;
378 default:
379 ASSERT_NOT_REACHED();
381 return PlatformEvent::TouchStart;
384 inline PlatformTouchPoint::State toPlatformTouchPointState(const WebTouchPoint::State state)
386 switch (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)
446 int modifiers = 0;
447 if (event.ctrlKey())
448 modifiers |= WebInputEvent::ControlKey;
449 if (event.shiftKey())
450 modifiers |= WebInputEvent::ShiftKey;
451 if (event.altKey())
452 modifiers |= WebInputEvent::AltKey;
453 if (event.metaKey())
454 modifiers |= WebInputEvent::MetaKey;
455 return modifiers;
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
469 // RemoteFrameViews.
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());
478 if (view)
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;
503 else
504 return; // Skip all other mouse events.
506 updateWebMouseEventFromCoreMouseEvent(event, widget, *layoutObject, *this);
508 switch (event.button()) {
509 case LeftButton:
510 button = WebMouseEvent::ButtonLeft;
511 break;
512 case MiddleButton:
513 button = WebMouseEvent::ButtonMiddle;
514 break;
515 case RightButton:
516 button = WebMouseEvent::ButtonRight;
517 break;
519 if (event.buttonDown()) {
520 switch (event.button()) {
521 case LeftButton:
522 modifiers |= WebInputEvent::LeftButtonDown;
523 break;
524 case MiddleButton:
525 modifiers |= WebInputEvent::MiddleButtonDown;
526 break;
527 case RightButton:
528 modifiers |= WebInputEvent::RightButtonDown;
529 break;
531 } else
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())
543 return;
544 if (event.touches()->length() != 1) {
545 if (event.touches()->length() || event.type() != EventTypeNames::touchend || !event.changedTouches() || event.changedTouches()->length() != 1)
546 return;
549 const Touch* touch = event.touches()->length() == 1 ? event.touches()->item(0) : event.changedTouches()->item(0);
550 if (touch->identifier())
551 return;
553 if (event.type() == EventTypeNames::touchstart)
554 type = MouseDown;
555 else if (event.type() == EventTypeNames::touchmove)
556 type = MouseMove;
557 else if (event.type() == EventTypeNames::touchend)
558 type = MouseUp;
559 else
560 return;
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());
569 if (view)
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);
582 x = localPoint.x();
583 y = localPoint.y();
586 WebMouseWheelEventBuilder::WebMouseWheelEventBuilder(const Widget* widget, const LayoutObject* layoutObject, const WheelEvent& event)
588 if (event.type() != EventTypeNames::wheel && event.type() != EventTypeNames::mousewheel)
589 return;
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)
605 type = KeyDown;
606 else if (event.type() == EventTypeNames::keyup)
607 type = WebInputEvent::KeyUp;
608 else if (event.type() == EventTypeNames::keypress)
609 type = WebInputEvent::Char;
610 else
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())
627 return;
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)
641 switch (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;
650 default:
651 return WebInputEvent::Undefined;
655 static WebTouchPoint toWebTouchPoint(const Touch* touch, const LayoutObject* layoutObject, WebTouchPoint::State state)
657 WebTouchPoint point;
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();
665 point.state = state;
666 return point;
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))
673 return i;
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))
684 return;
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;
690 } else {
691 touchPoints[pointIndex] = toWebTouchPoint(touch, layoutObject, state);
692 ++(*touchPointsLength);
697 WebTouchEventBuilder::WebTouchEventBuilder(const LayoutObject* layoutObject, const TouchEvent& event)
699 if (event.type() == EventTypeNames::touchstart)
700 type = TouchStart;
701 else if (event.type() == EventTypeNames::touchmove)
702 type = TouchMove;
703 else if (event.type() == EventTypeNames::touchend)
704 type = TouchEnd;
705 else if (event.type() == EventTypeNames::touchcancel)
706 type = TouchCancel;
707 else {
708 ASSERT_NOT_REACHED();
709 type = Undefined;
710 return;
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);
721 ++touchesLength;
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) {
753 type = 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);
763 x = localPoint.x();
764 y = localPoint.y();
767 } // namespace blink