Source/WebKit/chromium: Use new type-specific WebGestureEvent fields
[WebKit-https.git] / Source / WebKit / chromium / src / 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 "WebInputEventConversion.h"
33
34 #include "EventNames.h"
35 #include "GestureEvent.h"
36 #include "KeyboardCodes.h"
37 #include "KeyboardEvent.h"
38 #include "MouseEvent.h"
39 #include "PlatformKeyboardEvent.h"
40 #include "PlatformMouseEvent.h"
41 #include "PlatformWheelEvent.h"
42 #include "ScrollView.h"
43 #include "Touch.h"
44 #include "TouchEvent.h"
45 #include "TouchList.h"
46 #include "WebInputEvent.h"
47 #include "WheelEvent.h"
48 #include "Widget.h"
49
50 using namespace WebCore;
51
52 namespace WebKit {
53
54 static const double millisPerSecond = 1000.0;
55
56 // MakePlatformMouseEvent -----------------------------------------------------
57
58 PlatformMouseEventBuilder::PlatformMouseEventBuilder(Widget* widget, const WebMouseEvent& e)
59 {
60     // FIXME: widget is always toplevel, unless it's a popup.  We may be able
61     // to get rid of this once we abstract popups into a WebKit API.
62     m_position = widget->convertFromContainingWindow(IntPoint(e.x, e.y));
63     m_globalPosition = IntPoint(e.globalX, e.globalY);
64 #if ENABLE(POINTER_LOCK)
65     m_movementDelta = IntPoint(e.movementX, e.movementY);
66 #endif
67     m_button = static_cast<MouseButton>(e.button);
68
69     m_modifiers = 0;
70     if (e.modifiers & WebInputEvent::ShiftKey)
71         m_modifiers |= PlatformEvent::ShiftKey;
72     if (e.modifiers & WebInputEvent::ControlKey)
73         m_modifiers |= PlatformEvent::CtrlKey;
74     if (e.modifiers & WebInputEvent::AltKey)
75         m_modifiers |= PlatformEvent::AltKey;
76     if (e.modifiers & WebInputEvent::MetaKey)
77         m_modifiers |= PlatformEvent::MetaKey;
78
79     m_modifierFlags = e.modifiers;
80     m_timestamp = e.timeStampSeconds;
81     m_clickCount = e.clickCount;
82
83     switch (e.type) {
84     case WebInputEvent::MouseMove:
85     case WebInputEvent::MouseLeave:  // synthesize a move event
86         m_type = PlatformEvent::MouseMoved;
87         break;
88
89     case WebInputEvent::MouseDown:
90         m_type = PlatformEvent::MousePressed;
91         break;
92
93     case WebInputEvent::MouseUp:
94         m_type = PlatformEvent::MouseReleased;
95         break;
96
97     default:
98         ASSERT_NOT_REACHED();
99     }
100 }
101
102 // PlatformWheelEventBuilder --------------------------------------------------
103
104 PlatformWheelEventBuilder::PlatformWheelEventBuilder(Widget* widget, const WebMouseWheelEvent& e)
105 {
106     m_position = widget->convertFromContainingWindow(IntPoint(e.x, e.y));
107     m_globalPosition = IntPoint(e.globalX, e.globalY);
108     m_deltaX = e.deltaX;
109     m_deltaY = e.deltaY;
110     m_wheelTicksX = e.wheelTicksX;
111     m_wheelTicksY = e.wheelTicksY;
112     m_granularity = e.scrollByPage ?
113         ScrollByPageWheelEvent : ScrollByPixelWheelEvent;
114     
115     m_type = PlatformEvent::Wheel;
116
117     m_modifiers = 0;
118     if (e.modifiers & WebInputEvent::ShiftKey)
119         m_modifiers |= PlatformEvent::ShiftKey;
120     if (e.modifiers & WebInputEvent::ControlKey)
121         m_modifiers |= PlatformEvent::CtrlKey;
122     if (e.modifiers & WebInputEvent::AltKey)
123         m_modifiers |= PlatformEvent::AltKey;
124     if (e.modifiers & WebInputEvent::MetaKey)
125         m_modifiers |= PlatformEvent::MetaKey;
126
127     m_hasPreciseScrollingDeltas = e.hasPreciseScrollingDeltas;
128 #if OS(DARWIN)
129     m_phase = static_cast<WebCore::PlatformWheelEventPhase>(e.phase);
130     m_momentumPhase = static_cast<WebCore::PlatformWheelEventPhase>(e.momentumPhase);
131     m_timestamp = e.timeStampSeconds;
132     m_scrollCount = 0;
133     m_unacceleratedScrollingDeltaX = e.deltaX;
134     m_unacceleratedScrollingDeltaY = e.deltaY;
135 #endif
136 }
137
138 // PlatformGestureEventBuilder --------------------------------------------------
139
140 #if ENABLE(GESTURE_EVENTS)
141 PlatformGestureEventBuilder::PlatformGestureEventBuilder(Widget* widget, const WebGestureEvent& e)
142 {
143     switch (e.type) {
144     case WebInputEvent::GestureScrollBegin:
145         m_type = PlatformEvent::GestureScrollBegin;
146         break;
147     case WebInputEvent::GestureScrollEnd:
148         m_type = PlatformEvent::GestureScrollEnd;
149         break;
150     case WebInputEvent::GestureScrollUpdate:
151         m_type = PlatformEvent::GestureScrollUpdate;
152         m_deltaX = e.data.scrollUpdate.deltaX;
153         m_deltaY = e.data.scrollUpdate.deltaY;
154         break;
155     case WebInputEvent::GestureTap:
156         m_type = PlatformEvent::GestureTap;
157         m_area = IntSize(e.data.tap.width, e.data.tap.height);
158         // FIXME: PlatformGestureEvent deltaX is overloaded - wkb.ug/93123
159         m_deltaX = static_cast<int>(e.data.tap.tapCount);
160         break;
161     case WebInputEvent::GestureTapDown:
162         m_type = PlatformEvent::GestureTapDown;
163         break;
164     case WebInputEvent::GestureDoubleTap:
165         m_type = PlatformEvent::GestureDoubleTap;
166         break;
167     case WebInputEvent::GestureTwoFingerTap:
168         m_type = PlatformEvent::GestureTwoFingerTap;
169         break;
170     case WebInputEvent::GestureLongPress:
171         m_type = PlatformEvent::GestureLongPress;
172         m_area = IntSize(e.data.longPress.width, e.data.longPress.height);
173         break;
174     case WebInputEvent::GesturePinchBegin:
175         m_type = PlatformEvent::GesturePinchBegin;
176         break;
177     case WebInputEvent::GesturePinchEnd:
178         m_type = PlatformEvent::GesturePinchEnd;
179         break;
180     case WebInputEvent::GesturePinchUpdate:
181         m_type = PlatformEvent::GesturePinchUpdate;
182         // FIXME: PlatformGestureEvent deltaX is overloaded - wkb.ug/93123
183         m_deltaX = e.data.pinchUpdate.scale;
184         break;
185     default:
186         ASSERT_NOT_REACHED();
187     }
188     m_position = widget->convertFromContainingWindow(IntPoint(e.x, e.y));
189     m_globalPosition = IntPoint(e.globalX, e.globalY);
190     m_timestamp = e.timeStampSeconds;
191
192     m_modifiers = 0;
193     if (e.modifiers & WebInputEvent::ShiftKey)
194         m_modifiers |= PlatformEvent::ShiftKey;
195     if (e.modifiers & WebInputEvent::ControlKey)
196         m_modifiers |= PlatformEvent::CtrlKey;
197     if (e.modifiers & WebInputEvent::AltKey)
198         m_modifiers |= PlatformEvent::AltKey;
199     if (e.modifiers & WebInputEvent::MetaKey)
200         m_modifiers |= PlatformEvent::MetaKey;
201 }
202 #endif
203
204 // MakePlatformKeyboardEvent --------------------------------------------------
205
206 static inline PlatformEvent::Type toPlatformKeyboardEventType(WebInputEvent::Type type)
207 {
208     switch (type) {
209     case WebInputEvent::KeyUp:
210         return PlatformEvent::KeyUp;
211     case WebInputEvent::KeyDown:
212         return PlatformEvent::KeyDown;
213     case WebInputEvent::RawKeyDown:
214         return PlatformEvent::RawKeyDown;
215     case WebInputEvent::Char:
216         return PlatformEvent::Char;
217     default:
218         ASSERT_NOT_REACHED();
219     }
220     return PlatformEvent::KeyDown;
221 }
222
223 PlatformKeyboardEventBuilder::PlatformKeyboardEventBuilder(const WebKeyboardEvent& e)
224 {
225     m_type = toPlatformKeyboardEventType(e.type);
226     m_text = String(e.text);
227     m_unmodifiedText = String(e.unmodifiedText);
228     m_keyIdentifier = String(e.keyIdentifier);
229     m_autoRepeat = (e.modifiers & WebInputEvent::IsAutoRepeat);
230     m_windowsVirtualKeyCode = e.windowsKeyCode;
231     m_nativeVirtualKeyCode = e.nativeKeyCode;
232     m_isKeypad = (e.modifiers & WebInputEvent::IsKeyPad);
233     m_isSystemKey = e.isSystemKey;
234
235     m_modifiers = 0;
236     if (e.modifiers & WebInputEvent::ShiftKey)
237         m_modifiers |= PlatformEvent::ShiftKey;
238     if (e.modifiers & WebInputEvent::ControlKey)
239         m_modifiers |= PlatformEvent::CtrlKey;
240     if (e.modifiers & WebInputEvent::AltKey)
241         m_modifiers |= PlatformEvent::AltKey;
242     if (e.modifiers & WebInputEvent::MetaKey)
243         m_modifiers |= PlatformEvent::MetaKey;
244 }
245
246 void PlatformKeyboardEventBuilder::setKeyType(Type type)
247 {
248     // According to the behavior of Webkit in Windows platform,
249     // we need to convert KeyDown to RawKeydown and Char events
250     // See WebKit/WebKit/Win/WebView.cpp
251     ASSERT(m_type == KeyDown);
252     ASSERT(type == RawKeyDown || type == Char);
253     m_type = type;
254
255     if (type == RawKeyDown) {
256         m_text = String();
257         m_unmodifiedText = String();
258     } else {
259         m_keyIdentifier = String();
260         m_windowsVirtualKeyCode = 0;
261     }
262 }
263
264 // Please refer to bug http://b/issue?id=961192, which talks about Webkit
265 // keyboard event handling changes. It also mentions the list of keys
266 // which don't have associated character events.
267 bool PlatformKeyboardEventBuilder::isCharacterKey() const
268 {
269     switch (windowsVirtualKeyCode()) {
270     case VKEY_BACK:
271     case VKEY_ESCAPE:
272         return false;
273     }
274     return true;
275 }
276
277 #if ENABLE(TOUCH_EVENTS)
278 static inline PlatformEvent::Type toPlatformTouchEventType(const WebInputEvent::Type type)
279 {
280     switch (type) {
281     case WebInputEvent::TouchStart:
282         return PlatformEvent::TouchStart;
283     case WebInputEvent::TouchMove:
284         return PlatformEvent::TouchMove;
285     case WebInputEvent::TouchEnd:
286         return PlatformEvent::TouchEnd;
287     case WebInputEvent::TouchCancel:
288         return PlatformEvent::TouchCancel;
289     default:
290         ASSERT_NOT_REACHED();
291     }
292     return PlatformEvent::TouchStart;
293 }
294
295 static inline PlatformTouchPoint::State toPlatformTouchPointState(const WebTouchPoint::State state)
296 {
297     switch (state) {
298     case WebTouchPoint::StateReleased:
299         return PlatformTouchPoint::TouchReleased;
300     case WebTouchPoint::StatePressed:
301         return PlatformTouchPoint::TouchPressed;
302     case WebTouchPoint::StateMoved:
303         return PlatformTouchPoint::TouchMoved;
304     case WebTouchPoint::StateStationary:
305         return PlatformTouchPoint::TouchStationary;
306     case WebTouchPoint::StateCancelled:
307         return PlatformTouchPoint::TouchCancelled;
308     case WebTouchPoint::StateUndefined:
309         ASSERT_NOT_REACHED();
310     }
311     return PlatformTouchPoint::TouchReleased;
312 }
313
314 PlatformTouchPointBuilder::PlatformTouchPointBuilder(Widget* widget, const WebTouchPoint& point)
315 {
316     m_id = point.id;
317     m_state = toPlatformTouchPointState(point.state);
318     m_pos = widget->convertFromContainingWindow(point.position);
319     m_screenPos = point.screenPosition;
320     m_radiusY = point.radiusY;
321     m_radiusX = point.radiusX;
322     m_rotationAngle = point.rotationAngle;
323     m_force = point.force;
324 }
325
326 PlatformTouchEventBuilder::PlatformTouchEventBuilder(Widget* widget, const WebTouchEvent& event)
327 {
328     m_type = toPlatformTouchEventType(event.type);
329
330     m_modifiers = 0;
331     if (event.modifiers & WebInputEvent::ShiftKey)
332         m_modifiers |= PlatformEvent::ShiftKey;
333     if (event.modifiers & WebInputEvent::ControlKey)
334         m_modifiers |= PlatformEvent::CtrlKey;
335     if (event.modifiers & WebInputEvent::AltKey)
336         m_modifiers |= PlatformEvent::AltKey;
337     if (event.modifiers & WebInputEvent::MetaKey)
338         m_modifiers |= PlatformEvent::MetaKey;
339
340     m_timestamp = event.timeStampSeconds;
341
342     for (unsigned i = 0; i < event.touchesLength; ++i)
343         m_touchPoints.append(PlatformTouchPointBuilder(widget, event.touches[i]));
344 }
345 #endif
346
347 static int getWebInputModifiers(const UIEventWithKeyState& event)
348 {
349     int modifiers = 0;
350     if (event.ctrlKey())
351         modifiers |= WebInputEvent::ControlKey;
352     if (event.shiftKey())
353         modifiers |= WebInputEvent::ShiftKey;
354     if (event.altKey())
355         modifiers |= WebInputEvent::AltKey;
356     if (event.metaKey())
357         modifiers |= WebInputEvent::MetaKey;
358     return modifiers;
359 }
360
361 WebMouseEventBuilder::WebMouseEventBuilder(const Widget* widget, const MouseEvent& event)
362 {
363     if (event.type() == eventNames().mousemoveEvent)
364         type = WebInputEvent::MouseMove;
365     else if (event.type() == eventNames().mouseoutEvent)
366         type = WebInputEvent::MouseLeave;
367     else if (event.type() == eventNames().mouseoverEvent)
368         type = WebInputEvent::MouseEnter;
369     else if (event.type() == eventNames().mousedownEvent)
370         type = WebInputEvent::MouseDown;
371     else if (event.type() == eventNames().mouseupEvent)
372         type = WebInputEvent::MouseUp;
373     else if (event.type() == eventNames().contextmenuEvent)
374         type = WebInputEvent::ContextMenu;
375     else
376         return; // Skip all other mouse events.
377     timeStampSeconds = event.timeStamp() / millisPerSecond;
378     switch (event.button()) {
379     case LeftButton:
380         button = WebMouseEvent::ButtonLeft;
381         break;
382     case MiddleButton:
383         button = WebMouseEvent::ButtonMiddle;
384         break;
385     case RightButton:
386         button = WebMouseEvent::ButtonRight;
387         break;
388     }
389     modifiers = getWebInputModifiers(event);
390     if (event.buttonDown()) {
391         switch (event.button()) {
392         case LeftButton:
393             modifiers |= WebInputEvent::LeftButtonDown;
394             break;
395         case MiddleButton:
396             modifiers |= WebInputEvent::MiddleButtonDown;
397             break;
398         case RightButton:
399             modifiers |= WebInputEvent::RightButtonDown;
400             break;
401         }
402     }
403     ScrollView* view = widget->parent();
404     IntPoint p = view->contentsToWindow(
405         IntPoint(event.absoluteLocation().x(), event.absoluteLocation().y()));
406     globalX = event.screenX();
407     globalY = event.screenY();
408     windowX = p.x();
409     windowY = p.y();
410     x = event.absoluteLocation().x() - widget->location().x();
411     y = event.absoluteLocation().y() - widget->location().y();
412 #if ENABLE(POINTER_LOCK)
413     movementX = event.webkitMovementX();
414     movementY = event.webkitMovementY();
415 #endif
416     clickCount = event.detail();
417 }
418
419 WebMouseWheelEventBuilder::WebMouseWheelEventBuilder(const Widget* widget, const WheelEvent& event)
420 {
421     if (event.type() != eventNames().mousewheelEvent)
422         return;
423     type = WebInputEvent::MouseWheel;
424     timeStampSeconds = event.timeStamp() / millisPerSecond;
425     modifiers = getWebInputModifiers(event);
426     ScrollView* view = widget->parent();
427     IntPoint p = view->contentsToWindow(
428         IntPoint(event.absoluteLocation().x(), event.absoluteLocation().y()));
429     globalX = event.screenX();
430     globalY = event.screenY();
431     windowX = p.x();
432     windowY = p.y();
433     x = event.absoluteLocation().x() - widget->location().x();
434     y = event.absoluteLocation().y() - widget->location().y();
435     deltaX = static_cast<float>(event.rawDeltaX());
436     deltaY = static_cast<float>(event.rawDeltaY());
437     // The 120 is from WheelEvent::initWheelEvent().
438     wheelTicksX = static_cast<float>(event.wheelDeltaX()) / 120;
439     wheelTicksY = static_cast<float>(event.wheelDeltaY()) / 120;
440     scrollByPage = event.granularity() == WheelEvent::Page;
441 }
442
443 WebKeyboardEventBuilder::WebKeyboardEventBuilder(const KeyboardEvent& event)
444 {
445     if (event.type() == eventNames().keydownEvent)
446         type = KeyDown;
447     else if (event.type() == eventNames().keyupEvent)
448         type = WebInputEvent::KeyUp;
449     else if (event.type() == eventNames().keypressEvent)
450         type = WebInputEvent::Char;
451     else
452         return; // Skip all other keyboard events.
453
454     modifiers = getWebInputModifiers(event);
455     if (event.keyLocation() & KeyboardEvent::DOM_KEY_LOCATION_NUMPAD)
456         modifiers |= WebInputEvent::IsKeyPad;
457
458     timeStampSeconds = event.timeStamp() / millisPerSecond;
459     windowsKeyCode = event.keyCode();
460
461     // The platform keyevent does not exist if the event was created using
462     // initKeyboardEvent.
463     if (!event.keyEvent())
464         return;
465     nativeKeyCode = event.keyEvent()->nativeVirtualKeyCode();
466     unsigned numberOfCharacters = std::min(event.keyEvent()->text().length(), static_cast<unsigned>(textLengthCap));
467     for (unsigned i = 0; i < numberOfCharacters; ++i) {
468         text[i] = event.keyEvent()->text()[i];
469         unmodifiedText[i] = event.keyEvent()->unmodifiedText()[i];
470     }
471     memcpy(keyIdentifier, event.keyIdentifier().ascii().data(), event.keyIdentifier().length());
472 }
473
474 #if ENABLE(TOUCH_EVENTS)
475
476 static void addTouchPoints(TouchList* touches, const IntPoint& offset, WebTouchPoint* touchPoints, unsigned* touchPointsLength)
477 {
478     unsigned numberOfTouches = std::min(touches->length(), static_cast<unsigned>(WebTouchEvent::touchesLengthCap));
479     for (unsigned i = 0; i < numberOfTouches; ++i) {
480         const Touch* touch = touches->item(i);
481
482         WebTouchPoint point;
483         point.id = touch->identifier();
484         point.screenPosition = WebPoint(touch->screenX(), touch->screenY());
485         point.position = WebPoint(touch->pageX() - offset.x(), touch->pageY() - offset.y());
486         point.radiusX = touch->webkitRadiusX();
487         point.radiusY = touch->webkitRadiusY();
488         point.rotationAngle = touch->webkitRotationAngle();
489         point.force = touch->webkitForce();
490
491         touchPoints[i] = point;
492     }
493     *touchPointsLength = numberOfTouches;
494 }
495
496 WebTouchEventBuilder::WebTouchEventBuilder(const Widget* widget, const TouchEvent& event)
497 {
498     if (event.type() == eventNames().touchstartEvent)
499         type = TouchStart;
500     else if (event.type() == eventNames().touchmoveEvent)
501         type = TouchMove;
502     else if (event.type() == eventNames().touchendEvent)
503         type = TouchEnd;
504     else if (event.type() == eventNames().touchcancelEvent)
505         type = TouchCancel;
506     else {
507         ASSERT_NOT_REACHED();
508         type = Undefined;
509         return;
510     }
511
512     modifiers = getWebInputModifiers(event);
513     timeStampSeconds = event.timeStamp() / millisPerSecond;
514
515     addTouchPoints(event.touches(), widget->location(), touches, &touchesLength);
516     addTouchPoints(event.changedTouches(), widget->location(), changedTouches, &changedTouchesLength);
517     addTouchPoints(event.targetTouches(), widget->location(), targetTouches, &targetTouchesLength);
518 }
519
520 #endif // ENABLE(TOUCH_EVENTS)
521
522 #if ENABLE(GESTURE_EVENTS)
523 WebGestureEventBuilder::WebGestureEventBuilder(const Widget* widget, const GestureEvent& event)
524 {
525     if (event.type() == eventNames().gesturetapEvent)
526         type = GestureTap;
527     else if (event.type() == eventNames().gesturetapdownEvent)
528         type = GestureTapDown;
529     else if (event.type() == eventNames().gesturescrollstartEvent)
530         type = GestureScrollBegin;
531     else if (event.type() == eventNames().gesturescrollendEvent)
532         type = GestureScrollEnd;
533     else if (event.type() == eventNames().gesturescrollupdateEvent) {
534         type = GestureScrollUpdate;
535         data.scrollUpdate.deltaX = event.deltaX();
536         data.scrollUpdate.deltaY = event.deltaY();
537     }
538
539     timeStampSeconds = event.timeStamp() / millisPerSecond;
540     modifiers = getWebInputModifiers(event);
541
542     globalX = event.screenX();
543     globalY = event.screenY();
544     x = event.absoluteLocation().x() - widget->location().x();
545     y = event.absoluteLocation().y() - widget->location().y();
546 }
547 #endif // ENABLE(GESTURE_EVENTS)
548
549 } // namespace WebKit