~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Tools/DumpRenderTree/qt/EventSenderQt.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
 
3
 * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
 
4
 *
 
5
 * Redistribution and use in source and binary forms, with or without
 
6
 * modification, are permitted provided that the following conditions
 
7
 * are met:
 
8
 *
 
9
 * 1.  Redistributions of source code must retain the above copyright
 
10
 *     notice, this list of conditions and the following disclaimer.
 
11
 * 2.  Redistributions in binary form must reproduce the above copyright
 
12
 *     notice, this list of conditions and the following disclaimer in the
 
13
 *     documentation and/or other materials provided with the distribution.
 
14
 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
 
15
 *     its contributors may be used to endorse or promote products derived
 
16
 *     from this software without specific prior written permission.
 
17
 *
 
18
 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
 
19
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 
20
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 
21
 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 
22
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 
23
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 
24
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 
25
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
26
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 
27
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
28
 */
 
29
#include "config.h"
 
30
#include "EventSenderQt.h"
 
31
 
 
32
#include <QGestureEvent>
 
33
#include <QGraphicsSceneMouseEvent>
 
34
#include <QtTest/QtTest>
 
35
#if HAVE(QT5)
 
36
#include <qpa/qwindowsysteminterface.h>
 
37
#endif
 
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
// Ports like Gtk and Windows expose a different approach for their zooming
 
47
// API if compared to Qt: they have specific methods for zooming in and out,
 
48
// as well as a settable zoom factor, while Qt has only a 'setZoomValue' method.
 
49
// Hence Qt DRT adopts a fixed zoom-factor (1.2) for compatibility.
 
50
#define ZOOM_STEP           1.2
 
51
 
 
52
#define DRT_MESSAGE_DONE (QEvent::User + 1)
 
53
 
 
54
struct DRTEventQueue {
 
55
    QEvent* m_event;
 
56
    int m_delay;
 
57
};
 
58
 
 
59
static DRTEventQueue eventQueue[1024];
 
60
static unsigned endOfQueue;
 
61
static unsigned startOfQueue;
 
62
 
 
63
EventSender::EventSender(QWebPage* parent)
 
64
    : QObject(parent)
 
65
#ifndef QT_NO_GESTURES
 
66
    , m_tapGesture(parent)
 
67
    , m_tapAndHoldGesture(parent)
 
68
#endif
 
69
{
 
70
    m_page = parent;
 
71
    m_mouseButtonPressed = false;
 
72
    m_drag = false;
 
73
    memset(eventQueue, 0, sizeof(eventQueue));
 
74
    endOfQueue = 0;
 
75
    startOfQueue = 0;
 
76
    m_eventLoop = 0;
 
77
    m_currentButton = 0;
 
78
    m_currentDragActionsAllowed = 0;
 
79
    resetClickCount();
 
80
    m_page->view()->installEventFilter(this);
 
81
    // This is a hack that works because we normally scroll 60 pixels (3*20) per tick, but Apple scrolls 120.
 
82
    // But Apple also has a bug where they report lines instead of ticks in PlatformWheelEvent, making 2 lines = 40 pixels match.
 
83
    QApplication::setWheelScrollLines(2);
 
84
}
 
85
 
 
86
static Qt::KeyboardModifiers getModifiers(const QStringList& modifiers)
 
87
{
 
88
    Qt::KeyboardModifiers modifs = 0;
 
89
    for (int i = 0; i < modifiers.size(); ++i) {
 
90
        const QString& m = modifiers.at(i);
 
91
        if (m == "ctrlKey")
 
92
            modifs |= Qt::ControlModifier;
 
93
        else if (m == "shiftKey")
 
94
            modifs |= Qt::ShiftModifier;
 
95
        else if (m == "altKey")
 
96
            modifs |= Qt::AltModifier;
 
97
        else if (m == "metaKey")
 
98
            modifs |= Qt::MetaModifier;
 
99
    }
 
100
    return modifs;
 
101
}
 
102
 
 
103
void EventSender::mouseDown(int button, const QStringList& modifiers)
 
104
{
 
105
    Qt::KeyboardModifiers modifs = getModifiers(modifiers);
 
106
    Qt::MouseButton mouseButton;
 
107
    switch (button) {
 
108
    case 0:
 
109
        mouseButton = Qt::LeftButton;
 
110
        break;
 
111
    case 1:
 
112
        mouseButton = Qt::MidButton;
 
113
        break;
 
114
    case 2:
 
115
        mouseButton = Qt::RightButton;
 
116
        break;
 
117
    case 3:
 
118
        // fast/events/mouse-click-events expects the 4th button to be treated as the middle button
 
119
        mouseButton = Qt::MidButton;
 
120
        break;
 
121
    default:
 
122
        mouseButton = Qt::LeftButton;
 
123
        break;
 
124
    }
 
125
 
 
126
    // only consider a click to count, an event originated by the
 
127
    // same previous button and at the same position.
 
128
    if (m_currentButton == button
 
129
        && m_mousePos == m_clickPos
 
130
        && m_clickTimer.isActive())
 
131
        m_clickCount++;
 
132
    else
 
133
        m_clickCount = 1;
 
134
 
 
135
    m_currentButton = button;
 
136
    m_clickPos = m_mousePos;
 
137
    m_mouseButtons |= mouseButton;
 
138
 
 
139
//     qDebug() << "EventSender::mouseDown" << frame;
 
140
    QEvent* event;
 
141
    if (isGraphicsBased()) {
 
142
        event = createGraphicsSceneMouseEvent((m_clickCount == 2) ?
 
143
                    QEvent::GraphicsSceneMouseDoubleClick : QEvent::GraphicsSceneMousePress,
 
144
                    m_mousePos, m_mousePos, mouseButton, m_mouseButtons, modifs);
 
145
    } else {
 
146
        event = new QMouseEvent((m_clickCount == 2) ? QEvent::MouseButtonDblClick :
 
147
                    QEvent::MouseButtonPress, m_mousePos, m_mousePos,
 
148
                    mouseButton, m_mouseButtons, modifs);
 
149
    }
 
150
 
 
151
    sendOrQueueEvent(event);
 
152
 
 
153
    m_clickTimer.start(QApplication::doubleClickInterval(), this);
 
154
}
 
155
 
 
156
void EventSender::mouseUp(int button)
 
157
{
 
158
    Qt::MouseButton mouseButton;
 
159
    switch (button) {
 
160
    case 0:
 
161
        mouseButton = Qt::LeftButton;
 
162
        break;
 
163
    case 1:
 
164
        mouseButton = Qt::MidButton;
 
165
        break;
 
166
    case 2:
 
167
        mouseButton = Qt::RightButton;
 
168
        break;
 
169
    case 3:
 
170
        // fast/events/mouse-click-events expects the 4th button to be treated as the middle button
 
171
        mouseButton = Qt::MidButton;
 
172
        break;
 
173
    default:
 
174
        mouseButton = Qt::LeftButton;
 
175
        break;
 
176
    }
 
177
 
 
178
    m_mouseButtons &= ~mouseButton;
 
179
 
 
180
//     qDebug() << "EventSender::mouseUp" << frame;
 
181
    QEvent* event;
 
182
    if (isGraphicsBased()) {
 
183
        event = createGraphicsSceneMouseEvent(QEvent::GraphicsSceneMouseRelease,
 
184
                    m_mousePos, m_mousePos, mouseButton, m_mouseButtons, Qt::NoModifier);
 
185
    } else {
 
186
        event = new QMouseEvent(QEvent::MouseButtonRelease,
 
187
                    m_mousePos, m_mousePos, mouseButton, m_mouseButtons, Qt::NoModifier);
 
188
    }
 
189
 
 
190
    sendOrQueueEvent(event);
 
191
 
 
192
    if (m_currentDragData.urls().isEmpty())
 
193
        return;
 
194
 
 
195
    event = new QDropEvent(m_mousePos, m_currentDragActionsAllowed, &m_currentDragData, m_mouseButtons, Qt::NoModifier);
 
196
    sendEvent(m_page, event);
 
197
    m_currentDragData.clear();
 
198
}
 
199
 
 
200
void EventSender::mouseMoveTo(int x, int y)
 
201
{
 
202
//     qDebug() << "EventSender::mouseMoveTo" << x << y;
 
203
    m_mousePos = QPoint(x, y);
 
204
 
 
205
    QEvent* event;
 
206
    if (isGraphicsBased()) {
 
207
        event = createGraphicsSceneMouseEvent(QEvent::GraphicsSceneMouseMove,
 
208
                    m_mousePos, m_mousePos, Qt::NoButton, m_mouseButtons, Qt::NoModifier);
 
209
    } else {
 
210
        event = new QMouseEvent(QEvent::MouseMove,
 
211
                    m_mousePos, m_mousePos, Qt::NoButton, m_mouseButtons, Qt::NoModifier);
 
212
    }
 
213
 
 
214
    sendOrQueueEvent(event);
 
215
 
 
216
    if (m_currentDragData.urls().isEmpty())
 
217
        return;
 
218
 
 
219
    Qt::MouseButtons mouseButtons = m_mouseButtons | Qt::LeftButton;
 
220
    event = new QDragMoveEvent(m_mousePos, m_currentDragActionsAllowed, &m_currentDragData, mouseButtons, Qt::NoModifier);
 
221
    sendEvent(m_page, event);
 
222
}
 
223
 
 
224
// Simulates a mouse down event for drag without sending an actual mouse down event.
 
225
void EventSender::beginDragWithFiles(const QStringList& files)
 
226
{
 
227
    m_currentDragData.clear();
 
228
    QList<QUrl> fileUrls;
 
229
    QUrl baseUrl = m_page->mainFrame()->baseUrl();
 
230
    foreach (const QString& file, files) {
 
231
        QUrl resolvedUrl = baseUrl.resolved(file);
 
232
        fileUrls.append(resolvedUrl);
 
233
    }
 
234
 
 
235
    m_currentDragData.setUrls(fileUrls);
 
236
    m_currentDragActionsAllowed = Qt::CopyAction;
 
237
    Qt::MouseButtons mouseButtons = m_mouseButtons | Qt::LeftButton;
 
238
    QDragEnterEvent* event = new QDragEnterEvent(m_mousePos, m_currentDragActionsAllowed, &m_currentDragData, mouseButtons, Qt::NoModifier);
 
239
    sendEvent(m_page, event);
 
240
}
 
241
 
 
242
#ifndef QT_NO_WHEELEVENT
 
243
void EventSender::mouseScrollBy(int ticksX, int ticksY)
 
244
{
 
245
    const int tickStep = QApplication::wheelScrollLines() * 20;
 
246
    continuousMouseScrollBy((ticksX * tickStep), (ticksY * tickStep));
 
247
}
 
248
 
 
249
void EventSender::continuousMouseScrollBy(int x, int y)
 
250
{
 
251
    // continuousMouseScrollBy() mimics devices that send fine-grained scroll events where the 'delta' specified is not the usual
 
252
    // multiple of 120. See http://doc.qt.nokia.com/4.6/qwheelevent.html#delta for a good explanation of this.
 
253
 
 
254
    // A wheel delta of 120 (in 1/8 degrees) corresponds to one wheel tick, and we scroll tickStep pixels per wheel tick.
 
255
    const int tickStep = QApplication::wheelScrollLines() * 20;
 
256
    if (x) {
 
257
        QEvent* event;
 
258
        if (isGraphicsBased()) {
 
259
            event = createGraphicsSceneWheelEvent(QEvent::GraphicsSceneWheel,
 
260
                        m_mousePos, m_mousePos, (x * 120) / tickStep, Qt::NoModifier, Qt::Horizontal);
 
261
        } else
 
262
            event = new QWheelEvent(m_mousePos, m_mousePos, (x * 120) / tickStep, m_mouseButtons, Qt::NoModifier, Qt::Horizontal);
 
263
 
 
264
        sendOrQueueEvent(event);
 
265
    }
 
266
    if (y) {
 
267
        QEvent* event;
 
268
        if (isGraphicsBased()) {
 
269
            event = createGraphicsSceneWheelEvent(QEvent::GraphicsSceneWheel,
 
270
                        m_mousePos, m_mousePos, (y * 120) / tickStep, Qt::NoModifier, Qt::Vertical);
 
271
        } else
 
272
            event = new QWheelEvent(m_mousePos, m_mousePos, (y * 120) / tickStep, m_mouseButtons, Qt::NoModifier, Qt::Vertical);
 
273
 
 
274
        sendOrQueueEvent(event);
 
275
    }
 
276
}
 
277
#endif
 
278
 
 
279
void EventSender::leapForward(int ms)
 
280
{
 
281
    eventQueue[endOfQueue].m_delay = ms;
 
282
    //qDebug() << "EventSender::leapForward" << ms;
 
283
}
 
284
 
 
285
void EventSender::keyDown(const QString& string, const QStringList& modifiers, unsigned int location)
 
286
{
 
287
    QString s = string;
 
288
    Qt::KeyboardModifiers modifs = getModifiers(modifiers);
 
289
    if (location == 3)
 
290
        modifs |= Qt::KeypadModifier;
 
291
    int code = 0;
 
292
    if (string.length() == 1) {
 
293
        code = string.unicode()->unicode();
 
294
        //qDebug() << ">>>>>>>>> keyDown" << code << (char)code;
 
295
        // map special keycodes used by the tests to something that works for Qt/X11
 
296
        if (code == '\r') {
 
297
            code = Qt::Key_Return;
 
298
        } else if (code == '\t') {
 
299
            code = Qt::Key_Tab;
 
300
            if (modifs == Qt::ShiftModifier)
 
301
                code = Qt::Key_Backtab;
 
302
            s = QString();
 
303
        } else if (code == KEYCODE_DEL || code == KEYCODE_BACKSPACE) {
 
304
            code = Qt::Key_Backspace;
 
305
            if (modifs == Qt::AltModifier)
 
306
                modifs = Qt::ControlModifier;
 
307
            s = QString();
 
308
        } else if (code == 'o' && modifs == Qt::ControlModifier) {
 
309
            // Mimic the emacs ctrl-o binding on Mac by inserting a paragraph
 
310
            // separator and then putting the cursor back to its original
 
311
            // position. Allows us to pass emacs-ctrl-o.html
 
312
            s = QLatin1String("\n");
 
313
            code = '\n';
 
314
            modifs = 0;
 
315
            QKeyEvent event(QEvent::KeyPress, code, modifs, s);
 
316
            sendEvent(m_page, &event);
 
317
            QKeyEvent event2(QEvent::KeyRelease, code, modifs, s);
 
318
            sendEvent(m_page, &event2);
 
319
            s = QString();
 
320
            code = Qt::Key_Left;
 
321
        } else if (code == 'y' && modifs == Qt::ControlModifier) {
 
322
            s = QLatin1String("c");
 
323
            code = 'c';
 
324
        } else if (code == 'k' && modifs == Qt::ControlModifier) {
 
325
            s = QLatin1String("x");
 
326
            code = 'x';
 
327
        } else if (code == 'a' && modifs == Qt::ControlModifier) {
 
328
            s = QString();
 
329
            code = Qt::Key_Home;
 
330
            modifs = 0;
 
331
        } else if (code == KEYCODE_LEFTARROW) {
 
332
            s = QString();
 
333
            code = Qt::Key_Left;
 
334
            if (modifs & Qt::MetaModifier) {
 
335
                code = Qt::Key_Home;
 
336
                modifs &= ~Qt::MetaModifier;
 
337
            }
 
338
        } else if (code == KEYCODE_RIGHTARROW) {
 
339
            s = QString();
 
340
            code = Qt::Key_Right;
 
341
            if (modifs & Qt::MetaModifier) {
 
342
                code = Qt::Key_End;
 
343
                modifs &= ~Qt::MetaModifier;
 
344
            }
 
345
        } else if (code == KEYCODE_UPARROW) {
 
346
            s = QString();
 
347
            code = Qt::Key_Up;
 
348
            if (modifs & Qt::MetaModifier) {
 
349
                code = Qt::Key_PageUp;
 
350
                modifs &= ~Qt::MetaModifier;
 
351
            }
 
352
        } else if (code == KEYCODE_DOWNARROW) {
 
353
            s = QString();
 
354
            code = Qt::Key_Down;
 
355
            if (modifs & Qt::MetaModifier) {
 
356
                code = Qt::Key_PageDown;
 
357
                modifs &= ~Qt::MetaModifier;
 
358
            }
 
359
        } else if (code == 'a' && modifs == Qt::ControlModifier) {
 
360
            s = QString();
 
361
            code = Qt::Key_Home;
 
362
            modifs = 0;
 
363
        } else
 
364
            code = string.unicode()->toUpper().unicode();
 
365
    } else {
 
366
        //qDebug() << ">>>>>>>>> keyDown" << string;
 
367
 
 
368
        if (string.startsWith(QLatin1Char('F')) && string.count() <= 3) {
 
369
            s = s.mid(1);
 
370
            int functionKey = s.toInt();
 
371
            Q_ASSERT(functionKey >= 1 && functionKey <= 35);
 
372
            code = Qt::Key_F1 + (functionKey - 1);
 
373
        // map special keycode strings used by the tests to something that works for Qt/X11
 
374
        } else if (string == QLatin1String("leftArrow")) {
 
375
            s = QString();
 
376
            code = Qt::Key_Left;
 
377
        } else if (string == QLatin1String("rightArrow")) {
 
378
            s = QString();
 
379
            code = Qt::Key_Right;
 
380
        } else if (string == QLatin1String("upArrow")) {
 
381
            s = QString();
 
382
            code = Qt::Key_Up;
 
383
        } else if (string == QLatin1String("downArrow")) {
 
384
            s = QString();
 
385
            code = Qt::Key_Down;
 
386
        } else if (string == QLatin1String("pageUp")) {
 
387
            s = QString();
 
388
            code = Qt::Key_PageUp;
 
389
        } else if (string == QLatin1String("pageDown")) {
 
390
            s = QString();
 
391
            code = Qt::Key_PageDown;
 
392
        } else if (string == QLatin1String("home")) {
 
393
            s = QString();
 
394
            code = Qt::Key_Home;
 
395
        } else if (string == QLatin1String("end")) {
 
396
            s = QString();
 
397
            code = Qt::Key_End;
 
398
        } else if (string == QLatin1String("insert")) {
 
399
            s = QString();
 
400
            code = Qt::Key_Insert;
 
401
        } else if (string == QLatin1String("delete")) {
 
402
            s = QString();
 
403
            code = Qt::Key_Delete;
 
404
        } else if (string == QLatin1String("printScreen")) {
 
405
            s = QString();
 
406
            code = Qt::Key_Print;
 
407
        } else if (string == QLatin1String("menu")) {
 
408
            s = QString();
 
409
            code = Qt::Key_Menu;
 
410
        }
 
411
    }
 
412
    QKeyEvent event(QEvent::KeyPress, code, modifs, s);
 
413
    sendEvent(m_page, &event);
 
414
    QKeyEvent event2(QEvent::KeyRelease, code, modifs, s);
 
415
    sendEvent(m_page, &event2);
 
416
}
 
417
 
 
418
QStringList EventSender::contextClick()
 
419
{
 
420
    QMouseEvent event(QEvent::MouseButtonPress, m_mousePos, Qt::RightButton, Qt::RightButton, Qt::NoModifier);
 
421
    sendEvent(m_page, &event);
 
422
    QMouseEvent event2(QEvent::MouseButtonRelease, m_mousePos, Qt::RightButton, Qt::RightButton, Qt::NoModifier);
 
423
    sendEvent(m_page, &event2);
 
424
 
 
425
    if (isGraphicsBased()) {
 
426
        QGraphicsSceneContextMenuEvent ctxEvent(QEvent::GraphicsSceneContextMenu);
 
427
        ctxEvent.setReason(QGraphicsSceneContextMenuEvent::Mouse);
 
428
        ctxEvent.setPos(m_mousePos);
 
429
        WebCore::WebViewGraphicsBased* view = qobject_cast<WebCore::WebViewGraphicsBased*>(m_page->view());
 
430
        if (view)
 
431
            sendEvent(view->graphicsView(), &ctxEvent);
 
432
    } else {
 
433
        QContextMenuEvent ctxEvent(QContextMenuEvent::Mouse, m_mousePos);
 
434
        sendEvent(m_page->view(), &ctxEvent);
 
435
    }
 
436
    return DumpRenderTreeSupportQt::contextMenu(m_page);
 
437
}
 
438
 
 
439
void EventSender::scheduleAsynchronousClick()
 
440
{
 
441
    QMouseEvent* event = new QMouseEvent(QEvent::MouseButtonPress, m_mousePos, Qt::LeftButton, Qt::RightButton, Qt::NoModifier);
 
442
    postEvent(m_page, event);
 
443
    QMouseEvent* event2 = new QMouseEvent(QEvent::MouseButtonRelease, m_mousePos, Qt::LeftButton, Qt::RightButton, Qt::NoModifier);
 
444
    postEvent(m_page, event2);
 
445
}
 
446
 
 
447
void EventSender::addTouchPoint(int x, int y)
 
448
{
 
449
    const int id = m_touchPoints.isEmpty() ? 0 : m_touchPoints.last().id() + 1;
 
450
    const QPointF pos(x, y);
 
451
    QTouchEvent::TouchPoint point(id);
 
452
    point.setPos(pos);
 
453
    point.setStartPos(pos);
 
454
    point.setState(Qt::TouchPointPressed);
 
455
    if (!m_touchPointRadius.isNull())
 
456
        point.setRect(QRectF(pos - m_touchPointRadius, pos + m_touchPointRadius));
 
457
    m_touchPoints.append(point);
 
458
}
 
459
 
 
460
void EventSender::updateTouchPoint(int index, int x, int y)
 
461
{
 
462
    if (index < 0 || index >= m_touchPoints.count())
 
463
        return;
 
464
 
 
465
    const QPointF pos(x, y);
 
466
    QTouchEvent::TouchPoint &point = m_touchPoints[index];
 
467
    point.setPos(pos);
 
468
    point.setState(Qt::TouchPointMoved);
 
469
    if (!m_touchPointRadius.isNull())
 
470
        point.setRect(QRectF(pos - m_touchPointRadius, pos + m_touchPointRadius));
 
471
}
 
472
 
 
473
void EventSender::setTouchModifier(const QString &modifier, bool enable)
 
474
{
 
475
    Qt::KeyboardModifier mod = Qt::NoModifier;
 
476
    if (!modifier.compare(QLatin1String("shift"), Qt::CaseInsensitive))
 
477
        mod = Qt::ShiftModifier;
 
478
    else if (!modifier.compare(QLatin1String("alt"), Qt::CaseInsensitive))
 
479
        mod = Qt::AltModifier;
 
480
    else if (!modifier.compare(QLatin1String("meta"), Qt::CaseInsensitive))
 
481
        mod = Qt::MetaModifier;
 
482
    else if (!modifier.compare(QLatin1String("ctrl"), Qt::CaseInsensitive))
 
483
        mod = Qt::ControlModifier;
 
484
 
 
485
    if (enable)
 
486
        m_touchModifiers |= mod;
 
487
    else
 
488
        m_touchModifiers &= ~mod;
 
489
}
 
490
 
 
491
void EventSender::setTouchPointRadius(int radiusX, int radiusY)
 
492
{
 
493
    m_touchPointRadius = QPoint(radiusX, radiusY);
 
494
}
 
495
 
 
496
void EventSender::touchStart()
 
497
{
 
498
    if (!m_touchActive) {
 
499
        sendTouchEvent(QEvent::TouchBegin);
 
500
        m_touchActive = true;
 
501
    } else
 
502
        sendTouchEvent(QEvent::TouchUpdate);
 
503
}
 
504
 
 
505
void EventSender::touchMove()
 
506
{
 
507
    sendTouchEvent(QEvent::TouchUpdate);
 
508
}
 
509
 
 
510
void EventSender::touchEnd()
 
511
{
 
512
    for (int i = 0; i < m_touchPoints.count(); ++i)
 
513
        if (m_touchPoints[i].state() != Qt::TouchPointReleased) {
 
514
            sendTouchEvent(QEvent::TouchUpdate);
 
515
            return;
 
516
        }
 
517
    sendTouchEvent(QEvent::TouchEnd);
 
518
    m_touchActive = false;
 
519
}
 
520
 
 
521
#if QT_VERSION >= 0x050000
 
522
void EventSender::touchCancel()
 
523
{
 
524
    sendTouchEvent(QEvent::TouchCancel);
 
525
    m_touchActive = false;
 
526
}
 
527
#endif
 
528
 
 
529
void EventSender::clearTouchPoints()
 
530
{
 
531
    m_touchPoints.clear();
 
532
    m_touchModifiers = Qt::KeyboardModifiers();
 
533
    m_touchActive = false;
 
534
    m_touchPointRadius = QPoint();
 
535
}
 
536
 
 
537
void EventSender::releaseTouchPoint(int index)
 
538
{
 
539
    if (index < 0 || index >= m_touchPoints.count())
 
540
        return;
 
541
 
 
542
    m_touchPoints[index].setState(Qt::TouchPointReleased);
 
543
}
 
544
 
 
545
void EventSender::cancelTouchPoint(int index)
 
546
{
 
547
    // FIXME: No cancellation state in Qt 5, mapped to release instead.
 
548
    // PlatformTouchEvent conversion later will map all touch points to
 
549
    // cancelled.
 
550
    releaseTouchPoint(index);
 
551
}
 
552
 
 
553
void EventSender::sendTouchEvent(QEvent::Type type)
 
554
{
 
555
#if HAVE(QT5)
 
556
    static QTouchDevice* device = 0;
 
557
    if (!device) {
 
558
        device = new QTouchDevice;
 
559
        device->setType(QTouchDevice::TouchScreen);
 
560
        QWindowSystemInterface::registerTouchDevice(device);
 
561
    }
 
562
 
 
563
    QTouchEvent event(type, device, m_touchModifiers);
 
564
#else
 
565
    QTouchEvent event(type, QTouchEvent::TouchScreen, m_touchModifiers);
 
566
#endif
 
567
    event.setTouchPoints(m_touchPoints);
 
568
    sendEvent(m_page, &event);
 
569
    QList<QTouchEvent::TouchPoint>::Iterator it = m_touchPoints.begin();
 
570
    while (it != m_touchPoints.end()) {
 
571
        if (it->state() == Qt::TouchPointReleased)
 
572
            it = m_touchPoints.erase(it);
 
573
        else {
 
574
            it->setState(Qt::TouchPointStationary);
 
575
            ++it;
 
576
        }
 
577
    }
 
578
}
 
579
 
 
580
#ifndef QT_NO_GESTURES
 
581
void EventSender::gestureTap(int x, int y)
 
582
{
 
583
    m_tapGesture.setPosition(QPointF(x, y));
 
584
    m_gestures.clear();
 
585
    m_gestures.append(&m_tapGesture);
 
586
    QGestureEvent event(m_gestures);
 
587
#if !HAVE(QT5)
 
588
    event.setWidget(m_page->view());
 
589
#endif
 
590
    sendEvent(m_page, &event);
 
591
}
 
592
 
 
593
void EventSender::gestureLongPress(int x, int y)
 
594
{
 
595
    m_tapAndHoldGesture.setPosition(QPointF(x, y));
 
596
    m_gestures.clear();
 
597
    m_gestures.append(&m_tapAndHoldGesture);
 
598
    QGestureEvent event(m_gestures);
 
599
#if !HAVE(QT5)
 
600
    event.setWidget(m_page->view());
 
601
#endif
 
602
    sendEvent(m_page, &event);
 
603
}
 
604
#endif
 
605
 
 
606
void EventSender::zoomPageIn()
 
607
{
 
608
    if (QWebFrame* frame = m_page->mainFrame())
 
609
        frame->setZoomFactor(frame->zoomFactor() * ZOOM_STEP);
 
610
}
 
611
 
 
612
void EventSender::zoomPageOut()
 
613
{
 
614
    if (QWebFrame* frame = m_page->mainFrame())
 
615
        frame->setZoomFactor(frame->zoomFactor() / ZOOM_STEP);
 
616
}
 
617
 
 
618
void EventSender::textZoomIn()
 
619
{
 
620
    if (QWebFrame* frame = m_page->mainFrame())
 
621
        frame->setTextSizeMultiplier(frame->textSizeMultiplier() * ZOOM_STEP);
 
622
}
 
623
 
 
624
void EventSender::textZoomOut()
 
625
{
 
626
    if (QWebFrame* frame = m_page->mainFrame())
 
627
        frame->setTextSizeMultiplier(frame->textSizeMultiplier() / ZOOM_STEP);
 
628
}
 
629
 
 
630
void EventSender::scalePageBy(float scaleFactor, float x, float y)
 
631
{
 
632
    if (QWebFrame* frame = m_page->mainFrame())
 
633
        DumpRenderTreeSupportQt::scalePageBy(frame, scaleFactor, QPoint(x, y));
 
634
}
 
635
 
 
636
QWebFrame* EventSender::frameUnderMouse() const
 
637
{
 
638
    QWebFrame* frame = m_page->mainFrame();
 
639
 
 
640
redo:
 
641
    QList<QWebFrame*> children = frame->childFrames();
 
642
    for (int i = 0; i < children.size(); ++i) {
 
643
        if (children.at(i)->geometry().contains(m_mousePos)) {
 
644
            frame = children.at(i);
 
645
            goto redo;
 
646
        }
 
647
    }
 
648
    if (frame->geometry().contains(m_mousePos))
 
649
        return frame;
 
650
    return 0;
 
651
}
 
652
 
 
653
void EventSender::sendOrQueueEvent(QEvent* event)
 
654
{
 
655
    // Mouse move events are queued if
 
656
    // 1. A previous event was queued.
 
657
    // 2. A delay was set-up by leapForward().
 
658
    // 3. A call to mouseMoveTo while the mouse button is pressed could initiate a drag operation, and that does not return until mouseUp is processed.
 
659
    // To be safe and avoid a deadlock, this event is queued.
 
660
    if (endOfQueue == startOfQueue && !eventQueue[endOfQueue].m_delay && (!(m_mouseButtonPressed && (m_eventLoop && event->type() == QEvent::MouseButtonRelease)))) {
 
661
        sendEvent(m_page->view(), event);
 
662
        delete event;
 
663
        return;
 
664
    }
 
665
    eventQueue[endOfQueue++].m_event = event;
 
666
    eventQueue[endOfQueue].m_delay = 0;
 
667
    replaySavedEvents(event->type() != QEvent::MouseMove);
 
668
}
 
669
 
 
670
void EventSender::replaySavedEvents(bool flush)
 
671
{
 
672
    if (startOfQueue < endOfQueue) {
 
673
        // First send all the events that are ready to be sent
 
674
        while (!eventQueue[startOfQueue].m_delay && startOfQueue < endOfQueue) {
 
675
            QEvent* ev = eventQueue[startOfQueue++].m_event;
 
676
            postEvent(m_page->view(), ev);
 
677
        }
 
678
        if (startOfQueue == endOfQueue) {
 
679
            // Reset the queue
 
680
            startOfQueue = 0;
 
681
            endOfQueue = 0;
 
682
        } else {
 
683
            QTest::qWait(eventQueue[startOfQueue].m_delay);
 
684
            eventQueue[startOfQueue].m_delay = 0;
 
685
        }
 
686
    }
 
687
    if (!flush)
 
688
        return;
 
689
 
 
690
    // Send a marker event, it will tell us when it is safe to exit the new event loop
 
691
    QEvent* drtEvent = new QEvent((QEvent::Type)DRT_MESSAGE_DONE);
 
692
    QApplication::postEvent(m_page->view(), drtEvent);
 
693
 
 
694
    // Start an event loop for async handling of Drag & Drop
 
695
    m_eventLoop = new QEventLoop;
 
696
    m_eventLoop->exec();
 
697
    delete m_eventLoop;
 
698
    m_eventLoop = 0;
 
699
}
 
700
 
 
701
bool EventSender::eventFilter(QObject* watched, QEvent* event)
 
702
{
 
703
    if (watched != m_page->view())
 
704
        return false;
 
705
    switch (event->type()) {
 
706
    case QEvent::Leave:
 
707
        return true;
 
708
    case QEvent::MouseButtonPress:
 
709
    case QEvent::GraphicsSceneMousePress:
 
710
        m_mouseButtonPressed = true;
 
711
        break;
 
712
    case QEvent::MouseMove:
 
713
    case QEvent::GraphicsSceneMouseMove:
 
714
        if (m_mouseButtonPressed)
 
715
            m_drag = true;
 
716
        break;
 
717
    case QEvent::MouseButtonRelease:
 
718
    case QEvent::GraphicsSceneMouseRelease:
 
719
        m_mouseButtonPressed = false;
 
720
        m_drag = false;
 
721
        break;
 
722
    case DRT_MESSAGE_DONE:
 
723
        m_eventLoop->exit();
 
724
        return true;
 
725
    }
 
726
    return false;
 
727
}
 
728
 
 
729
void EventSender::timerEvent(QTimerEvent* ev)
 
730
{
 
731
    m_clickTimer.stop();
 
732
}
 
733
 
 
734
QGraphicsSceneMouseEvent* EventSender::createGraphicsSceneMouseEvent(QEvent::Type type, const QPoint& pos, const QPoint& screenPos, Qt::MouseButton button, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
 
735
{
 
736
    QGraphicsSceneMouseEvent* event;
 
737
    event = new QGraphicsSceneMouseEvent(type);
 
738
    event->setPos(pos);
 
739
    event->setScreenPos(screenPos);
 
740
    event->setButton(button);
 
741
    event->setButtons(buttons);
 
742
    event->setModifiers(modifiers);
 
743
 
 
744
    return event;
 
745
}
 
746
 
 
747
QGraphicsSceneWheelEvent* EventSender::createGraphicsSceneWheelEvent(QEvent::Type type, const QPoint& pos, const QPoint& screenPos, int delta, Qt::KeyboardModifiers modifiers, Qt::Orientation orientation)
 
748
{
 
749
    QGraphicsSceneWheelEvent* event;
 
750
    event = new QGraphicsSceneWheelEvent(type);
 
751
    event->setPos(pos);
 
752
    event->setScreenPos(screenPos);
 
753
    event->setDelta(delta);
 
754
    event->setModifiers(modifiers);
 
755
    event->setOrientation(orientation);
 
756
 
 
757
    return event;
 
758
}
 
759
 
 
760
void EventSender::sendEvent(QObject* receiver, QEvent* event)
 
761
{
 
762
    if (WebCore::WebViewGraphicsBased* view = qobject_cast<WebCore::WebViewGraphicsBased*>(receiver))
 
763
        view->scene()->sendEvent(view->graphicsView(), event);
 
764
    else
 
765
        QApplication::sendEvent(receiver, event);
 
766
}
 
767
 
 
768
void EventSender::postEvent(QObject* receiver, QEvent* event)
 
769
{
 
770
    // QGraphicsScene does not have a postEvent method, so send the event in this case
 
771
    // and delete it after that.
 
772
    if (WebCore::WebViewGraphicsBased* view = qobject_cast<WebCore::WebViewGraphicsBased*>(receiver)) {
 
773
        view->scene()->sendEvent(view->graphicsView(), event);
 
774
        delete event;
 
775
    } else
 
776
        QApplication::postEvent(receiver, event); // event deleted by the system
 
777
}