tizen beta release
[profile/ivi/webkit-efl.git] / Tools / WebKitTestRunner / qt / EventSenderProxyQt.cpp
1 /*
2  * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "EventSenderProxy.h"
28
29 #include "PlatformWebView.h"
30 #include "TestController.h"
31 #include <QGraphicsSceneMouseEvent>
32 #include <QKeyEvent>
33 #include <QtTest/QtTest>
34 #include <WebKit2/WKPagePrivate.h>
35 #include <WebKit2/WKStringQt.h>
36
37 namespace WTR {
38
39 #define KEYCODE_DEL         127
40 #define KEYCODE_BACKSPACE   8
41 #define KEYCODE_LEFTARROW   0xf702
42 #define KEYCODE_RIGHTARROW  0xf703
43 #define KEYCODE_UPARROW     0xf700
44 #define KEYCODE_DOWNARROW   0xf701
45
46 struct WTREventQueue {
47     QEvent* m_event;
48     int m_delay;
49 };
50
51 static WTREventQueue eventQueue[1024];
52 static unsigned endOfQueue;
53 static unsigned startOfQueue;
54
55 EventSenderProxy::EventSenderProxy(TestController* testController)
56     : m_testController(testController)
57     , m_time(0)
58     , m_position()
59     , m_leftMouseButtonDown(false)
60     , m_clickCount(0)
61     , m_clickTime(0)
62     , m_clickPosition()
63     , m_clickButton(kWKEventMouseButtonNoButton)
64     , m_mouseButtons(0)
65 #if ENABLE(TOUCH_EVENTS)
66     , m_touchActive(false)
67 #endif
68 {
69     memset(eventQueue, 0, sizeof(eventQueue));
70     endOfQueue = 0;
71     startOfQueue = 0;
72 }
73
74 static Qt::MouseButton getMouseButton(unsigned button)
75 {
76     Qt::MouseButton mouseButton;
77     switch (button) {
78     case 0:
79         mouseButton = Qt::LeftButton;
80         break;
81     case 1:
82         mouseButton = Qt::MidButton;
83         break;
84     case 2:
85         mouseButton = Qt::RightButton;
86         break;
87     case 3:
88         // fast/events/mouse-click-events expects the 4th button to be treated as the middle button
89         mouseButton = Qt::MidButton;
90         break;
91     default:
92         mouseButton = Qt::LeftButton;
93         break;
94     }
95     return mouseButton;
96 }
97
98 static Qt::KeyboardModifiers getModifiers(WKEventModifiers modifiersRef)
99 {
100     Qt::KeyboardModifiers modifiers = 0;
101
102     if (modifiersRef & kWKEventModifiersControlKey)
103         modifiers |= Qt::ControlModifier;
104     if (modifiersRef & kWKEventModifiersShiftKey)
105         modifiers |= Qt::ShiftModifier;
106     if (modifiersRef & kWKEventModifiersAltKey)
107         modifiers |= Qt::AltModifier;
108     if (modifiersRef & kWKEventModifiersMetaKey)
109         modifiers |= Qt::MetaModifier;
110
111     return modifiers;
112 }
113
114 void EventSenderProxy::keyDown(WKStringRef keyRef, WKEventModifiers modifiersRef, unsigned location)
115 {
116     const QString key = WKStringCopyQString(keyRef);
117     QString keyText = key;
118
119     Qt::KeyboardModifiers modifiers = getModifiers(modifiersRef);
120
121     if (location == 3)
122         modifiers |= Qt::KeypadModifier;
123     int code = 0;
124     if (key.length() == 1) {
125         code = key.unicode()->unicode();
126         // map special keycodes used by the tests to something that works for Qt/X11
127         if (code == '\r') {
128             code = Qt::Key_Return;
129         } else if (code == '\t') {
130             code = Qt::Key_Tab;
131             if (modifiers == Qt::ShiftModifier)
132                 code = Qt::Key_Backtab;
133             keyText = QString();
134         } else if (code == KEYCODE_DEL || code == KEYCODE_BACKSPACE) {
135             code = Qt::Key_Backspace;
136             if (modifiers == Qt::AltModifier)
137                 modifiers = Qt::ControlModifier;
138             keyText = QString();
139         } else if (code == 'o' && modifiers == Qt::ControlModifier) {
140             // Mimic the emacs ctrl-o binding on Mac by inserting a paragraph
141             // separator and then putting the cursor back to its original
142             // position. Allows us to pass emacs-ctrl-o.html
143             keyText = QLatin1String("\n");
144             code = '\n';
145             modifiers = 0;
146             QKeyEvent event(QEvent::KeyPress, code, modifiers, keyText);
147             m_testController->mainWebView()->sendEvent(&event);
148             QKeyEvent event2(QEvent::KeyRelease, code, modifiers, keyText);
149             m_testController->mainWebView()->sendEvent(&event2);
150             keyText = QString();
151             code = Qt::Key_Left;
152         } else if (code == 'y' && modifiers == Qt::ControlModifier) {
153             keyText = QLatin1String("c");
154             code = 'c';
155         } else if (code == 'k' && modifiers == Qt::ControlModifier) {
156             keyText = QLatin1String("x");
157             code = 'x';
158         } else if (code == 'a' && modifiers == Qt::ControlModifier) {
159             keyText = QString();
160             code = Qt::Key_Home;
161             modifiers = 0;
162         } else if (code == KEYCODE_LEFTARROW) {
163             keyText = QString();
164             code = Qt::Key_Left;
165             if (modifiers & Qt::MetaModifier) {
166                 code = Qt::Key_Home;
167                 modifiers &= ~Qt::MetaModifier;
168             }
169         } else if (code == KEYCODE_RIGHTARROW) {
170             keyText = QString();
171             code = Qt::Key_Right;
172             if (modifiers & Qt::MetaModifier) {
173                 code = Qt::Key_End;
174                 modifiers &= ~Qt::MetaModifier;
175             }
176         } else if (code == KEYCODE_UPARROW) {
177             keyText = QString();
178             code = Qt::Key_Up;
179             if (modifiers & Qt::MetaModifier) {
180                 code = Qt::Key_PageUp;
181                 modifiers &= ~Qt::MetaModifier;
182             }
183         } else if (code == KEYCODE_DOWNARROW) {
184             keyText = QString();
185             code = Qt::Key_Down;
186             if (modifiers & Qt::MetaModifier) {
187                 code = Qt::Key_PageDown;
188                 modifiers &= ~Qt::MetaModifier;
189             }
190         } else if (code == 'a' && modifiers == Qt::ControlModifier) {
191             keyText = QString();
192             code = Qt::Key_Home;
193             modifiers = 0;
194         } else
195             code = key.unicode()->toUpper().unicode();
196     } else {
197         if (key.startsWith(QLatin1Char('F')) && key.count() <= 3) {
198             keyText = keyText.mid(1);
199             int functionKey = keyText.toInt();
200             Q_ASSERT(functionKey >= 1 && functionKey <= 35);
201             code = Qt::Key_F1 + (functionKey - 1);
202         // map special keycode strings used by the tests to something that works for Qt/X11
203         } else if (key == QLatin1String("leftArrow")) {
204             keyText = QString();
205             code = Qt::Key_Left;
206         } else if (key == QLatin1String("rightArrow")) {
207             keyText = QString();
208             code = Qt::Key_Right;
209         } else if (key == QLatin1String("upArrow")) {
210             keyText = QString();
211             code = Qt::Key_Up;
212         } else if (key == QLatin1String("downArrow")) {
213             keyText = QString();
214             code = Qt::Key_Down;
215         } else if (key == QLatin1String("pageUp")) {
216             keyText = QString();
217             code = Qt::Key_PageUp;
218         } else if (key == QLatin1String("pageDown")) {
219             keyText = QString();
220             code = Qt::Key_PageDown;
221         } else if (key == QLatin1String("home")) {
222             keyText = QString();
223             code = Qt::Key_Home;
224         } else if (key == QLatin1String("end")) {
225             keyText = QString();
226             code = Qt::Key_End;
227         } else if (key == QLatin1String("insert")) {
228             keyText = QString();
229             code = Qt::Key_Insert;
230         } else if (key == QLatin1String("delete")) {
231             keyText = QString();
232             code = Qt::Key_Delete;
233         } else if (key == QLatin1String("printScreen")) {
234             keyText = QString();
235             code = Qt::Key_Print;
236         } else if (key == QLatin1String("menu")) {
237             keyText = QString();
238             code = Qt::Key_Menu;
239         }
240     }
241     QKeyEvent event(QEvent::KeyPress, code, modifiers, keyText);
242     m_testController->mainWebView()->sendEvent(&event);
243     QKeyEvent event2(QEvent::KeyRelease, code, modifiers, keyText);
244     m_testController->mainWebView()->sendEvent(&event2);
245 }
246
247 void EventSenderProxy::updateClickCountForButton(int button)
248 {
249     if (m_time - m_clickTime < QApplication::doubleClickInterval() / 1000.0 && m_position == m_clickPosition && button == m_clickButton) {
250         ++m_clickCount;
251         m_clickTime = m_time;
252         return;
253     }
254
255     m_clickCount = 1;
256     m_clickTime = m_time;
257     m_clickPosition = m_position;
258     m_clickButton = button;
259 }
260
261 void EventSenderProxy::mouseDown(unsigned button, WKEventModifiers wkModifiers)
262 {
263     Qt::KeyboardModifiers modifiers = getModifiers(wkModifiers);
264     Qt::MouseButton mouseButton = getMouseButton(button);
265
266     updateClickCountForButton(button);
267
268     m_mouseButtons |= mouseButton;
269
270     QPoint mousePos(m_position.x, m_position.y);
271     QMouseEvent* event = new QMouseEvent((m_clickCount == 2) ? QEvent::MouseButtonDblClick : QEvent::MouseButtonPress,
272         mousePos, mousePos, mouseButton, m_mouseButtons, modifiers);
273
274     sendOrQueueEvent(event);
275 }
276
277 void EventSenderProxy::mouseUp(unsigned button, WKEventModifiers)
278 {
279     Qt::MouseButton mouseButton = getMouseButton(button);
280     m_mouseButtons &= ~mouseButton;
281
282     QPoint mousePos(m_position.x, m_position.y);
283     QMouseEvent* event = new QMouseEvent(QEvent::MouseButtonRelease,
284         mousePos, mousePos, mouseButton, m_mouseButtons, Qt::NoModifier);
285
286     sendOrQueueEvent(event);
287 }
288
289 void EventSenderProxy::mouseMoveTo(double x, double y)
290 {
291     m_position.x = x;
292     m_position.y = y;
293
294     QPoint mousePos(m_position.x, m_position.y);
295     QMouseEvent* event = new QMouseEvent(QEvent::MouseMove,
296         mousePos, mousePos, Qt::NoButton, m_mouseButtons, Qt::NoModifier);
297
298     sendOrQueueEvent(event);
299 }
300
301 void EventSenderProxy::mouseScrollBy(int, int)
302 {
303     // FIXME: Implement this.
304 }
305
306 void EventSenderProxy::leapForward(int ms)
307 {
308     eventQueue[endOfQueue].m_delay = ms;
309 }
310
311 #if ENABLE(TOUCH_EVENTS)
312 void EventSenderProxy::addTouchPoint(int x, int y)
313 {
314     const int id = m_touchPoints.isEmpty() ? 0 : m_touchPoints.last().id() + 1;
315     const QPointF pos(x, y);
316     QTouchEvent::TouchPoint point(id);
317     point.setPos(pos);
318     point.setStartPos(pos);
319     point.setState(Qt::TouchPointPressed);
320     m_touchPoints.append(point);
321 }
322
323 void EventSenderProxy::updateTouchPoint(int index, int x, int y)
324 {
325     ASSERT(index >= 0 && index < m_touchPoints.count());
326     QTouchEvent::TouchPoint &p = m_touchPoints[index];
327     p.setPos(QPointF(x, y));
328     p.setState(Qt::TouchPointMoved);
329 }
330
331 void EventSenderProxy::setTouchModifier(WKEventModifiers modifier, bool enable)
332 {
333     Qt::KeyboardModifiers mod = getModifiers(modifier);
334
335     if (enable)
336         m_touchModifiers |= mod;
337     else
338         m_touchModifiers &= ~mod;
339 }
340
341 void EventSenderProxy::touchStart()
342 {
343     if (!m_touchActive) {
344         sendTouchEvent(QEvent::TouchBegin);
345         m_touchActive = true;
346     } else
347         sendTouchEvent(QEvent::TouchUpdate);
348 }
349
350 void EventSenderProxy::touchMove()
351 {
352     sendTouchEvent(QEvent::TouchUpdate);
353 }
354
355 void EventSenderProxy::touchEnd()
356 {
357     for (int i = 0; i < m_touchPoints.count(); ++i) {
358         if (m_touchPoints[i].state() != Qt::TouchPointReleased) {
359             sendTouchEvent(QEvent::TouchUpdate);
360             return;
361         }
362     }
363     sendTouchEvent(QEvent::TouchEnd);
364     m_touchActive = false;
365 }
366
367 void EventSenderProxy::clearTouchPoints()
368 {
369     m_touchPoints.clear();
370     m_touchModifiers = Qt::KeyboardModifiers();
371     m_touchActive = false;
372 }
373
374 void EventSenderProxy::releaseTouchPoint(int index)
375 {
376     if (index < 0 || index >= m_touchPoints.count())
377         return;
378
379     m_touchPoints[index].setState(Qt::TouchPointReleased);
380 }
381
382 void EventSenderProxy::sendTouchEvent(QEvent::Type type)
383 {
384     QTouchEvent event(type, QTouchEvent::TouchScreen, m_touchModifiers);
385     event.setTouchPoints(m_touchPoints);
386     m_testController->mainWebView()->sendEvent(&event);
387     QList<QTouchEvent::TouchPoint>::Iterator it = m_touchPoints.begin();
388     while (it != m_touchPoints.end()) {
389         if (it->state() == Qt::TouchPointReleased)
390             it = m_touchPoints.erase(it);
391         else {
392             it->setState(Qt::TouchPointStationary);
393             ++it;
394         }
395     }
396 }
397 #endif
398
399 void EventSenderProxy::sendOrQueueEvent(QEvent* event)
400 {
401     if (endOfQueue == startOfQueue && !eventQueue[endOfQueue].m_delay) {
402         m_testController->mainWebView()->sendEvent(event);
403         delete event;
404         return;
405     }
406
407     eventQueue[endOfQueue++].m_event = event;
408     eventQueue[endOfQueue].m_delay = 0;
409     replaySavedEvents();
410 }
411
412 void EventSenderProxy::replaySavedEvents()
413 {
414     if (startOfQueue < endOfQueue) {
415         while (!eventQueue[startOfQueue].m_delay && startOfQueue < endOfQueue) {
416             QEvent* ev = eventQueue[startOfQueue++].m_event;
417             m_testController->mainWebView()->postEvent(ev);
418         }
419         if (startOfQueue == endOfQueue) {
420             startOfQueue = 0;
421             endOfQueue = 0;
422         } else {
423             QTest::qWait(eventQueue[startOfQueue].m_delay);
424             eventQueue[startOfQueue].m_delay = 0;
425         }
426     }
427 }
428
429 } // namespace WTR