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