Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / content / shell / renderer / test_runner / EventSender.cpp
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // This file contains the definition for EventSender.
6 //
7 // Some notes about drag and drop handling:
8 // Windows drag and drop goes through a system call to doDragDrop. At that
9 // point, program control is given to Windows which then periodically makes
10 // callbacks into the webview. This won't work for layout tests, so instead,
11 // we queue up all the mouse move and mouse up events. When the test tries to
12 // start a drag (by calling EvenSendingController::doDragDrop), we take the
13 // events in the queue and replay them.
14 // The behavior of queuing events and replaying them can be disabled by a
15 // layout test by setting eventSender.dragMode to false.
16
17 #include "content/shell/renderer/test_runner/EventSender.h"
18
19 #include <deque>
20
21 #include "content/shell/renderer/test_runner/KeyCodeMapping.h"
22 #include "content/shell/renderer/test_runner/MockSpellCheck.h"
23 #include "content/shell/renderer/test_runner/TestCommon.h"
24 #include "content/shell/renderer/test_runner/TestInterfaces.h"
25 #include "content/shell/renderer/test_runner/WebTestDelegate.h"
26 #include "content/shell/renderer/test_runner/WebTestProxy.h"
27 #include "third_party/WebKit/public/platform/WebDragData.h"
28 #include "third_party/WebKit/public/platform/WebString.h"
29 #include "third_party/WebKit/public/platform/WebVector.h"
30 #include "third_party/WebKit/public/web/WebContextMenuData.h"
31 #include "third_party/WebKit/public/web/WebTouchPoint.h"
32 #include "third_party/WebKit/public/web/WebView.h"
33
34 #ifdef WIN32
35 #include "third_party/WebKit/public/web/win/WebInputEventFactory.h"
36 #elif __APPLE__
37 #include "third_party/WebKit/public/web/mac/WebInputEventFactory.h"
38 #elif defined(ANDROID)
39 #include "third_party/WebKit/public/web/android/WebInputEventFactory.h"
40 #elif defined(TOOLKIT_GTK)
41 #include "third_party/WebKit/public/web/gtk/WebInputEventFactory.h"
42 #endif
43
44 // FIXME: layout before each event?
45
46 using namespace std;
47 using namespace blink;
48
49 namespace WebTestRunner {
50
51 WebPoint EventSender::lastMousePos;
52 WebMouseEvent::Button EventSender::pressedButton = WebMouseEvent::ButtonNone;
53 WebMouseEvent::Button EventSender::lastButtonType = WebMouseEvent::ButtonNone;
54
55 namespace {
56
57 struct SavedEvent {
58     enum SavedEventType {
59         Unspecified,
60         MouseUp,
61         MouseMove,
62         LeapForward
63     };
64
65     SavedEventType type;
66     WebMouseEvent::Button buttonType; // For MouseUp.
67     WebPoint pos; // For MouseMove.
68     int milliseconds; // For LeapForward.
69
70     SavedEvent()
71         : type(Unspecified)
72         , buttonType(WebMouseEvent::ButtonNone)
73         , milliseconds(0) { }
74 };
75
76 WebDragData currentDragData;
77 WebDragOperation currentDragEffect;
78 WebDragOperationsMask currentDragEffectsAllowed;
79 bool replayingSavedEvents = false;
80 deque<SavedEvent> mouseEventQueue;
81 int touchModifiers;
82 vector<WebTouchPoint> touchPoints;
83
84 // Time and place of the last mouse up event.
85 double lastClickTimeSec = 0;
86 WebPoint lastClickPos;
87 int clickCount = 0;
88
89 // maximum distance (in space and time) for a mouse click
90 // to register as a double or triple click
91 const double multipleClickTimeSec = 1;
92 const int multipleClickRadiusPixels = 5;
93
94 // How much we should scroll per event - the value here is chosen to
95 // match the WebKit impl and layout test results.
96 const float scrollbarPixelsPerTick = 40.0f;
97
98 inline bool outsideMultiClickRadius(const WebPoint& a, const WebPoint& b)
99 {
100     return ((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)) >
101         multipleClickRadiusPixels * multipleClickRadiusPixels;
102 }
103
104 // Used to offset the time the event hander things an event happened. This is
105 // done so tests can run without a delay, but bypass checks that are time
106 // dependent (e.g., dragging has a timeout vs selection).
107 uint32 timeOffsetMs = 0;
108
109 double getCurrentEventTimeSec(WebTestDelegate* delegate)
110 {
111     return (delegate->getCurrentTimeInMillisecond() + timeOffsetMs) / 1000.0;
112 }
113
114 void advanceEventTime(int32_t deltaMs)
115 {
116     timeOffsetMs += deltaMs;
117 }
118
119 void initMouseEvent(WebInputEvent::Type t, WebMouseEvent::Button b, const WebPoint& pos, WebMouseEvent* e, double ts)
120 {
121     e->type = t;
122     e->button = b;
123     e->modifiers = 0;
124     e->x = pos.x;
125     e->y = pos.y;
126     e->globalX = pos.x;
127     e->globalY = pos.y;
128     e->timeStampSeconds = ts;
129     e->clickCount = clickCount;
130 }
131
132 void applyKeyModifier(const string& modifierName, WebInputEvent* event)
133 {
134     const char* characters = modifierName.c_str();
135     if (!strcmp(characters, "ctrlKey")
136 #ifndef __APPLE__
137         || !strcmp(characters, "addSelectionKey")
138 #endif
139         ) {
140         event->modifiers |= WebInputEvent::ControlKey;
141     } else if (!strcmp(characters, "shiftKey") || !strcmp(characters, "rangeSelectionKey"))
142         event->modifiers |= WebInputEvent::ShiftKey;
143     else if (!strcmp(characters, "altKey")) {
144         event->modifiers |= WebInputEvent::AltKey;
145 #ifdef __APPLE__
146     } else if (!strcmp(characters, "metaKey") || !strcmp(characters, "addSelectionKey")) {
147         event->modifiers |= WebInputEvent::MetaKey;
148 #else
149     } else if (!strcmp(characters, "metaKey")) {
150         event->modifiers |= WebInputEvent::MetaKey;
151 #endif
152     } else if (!strcmp(characters, "autoRepeat")) {
153         event->modifiers |= WebInputEvent::IsAutoRepeat;
154     }
155 }
156
157 void applyKeyModifiers(const CppVariant* argument, WebInputEvent* event)
158 {
159     if (argument->isObject()) {
160         vector<string> modifiers = argument->toStringVector();
161         for (vector<string>::const_iterator i = modifiers.begin(); i != modifiers.end(); ++i)
162             applyKeyModifier(*i, event);
163     } else if (argument->isString()) {
164         applyKeyModifier(argument->toString(), event);
165     }
166 }
167
168 // Get the edit command corresponding to a keyboard event.
169 // Returns true if the specified event corresponds to an edit command, the name
170 // of the edit command will be stored in |*name|.
171 bool getEditCommand(const WebKeyboardEvent& event, string* name)
172 {
173 #ifdef __APPLE__
174     // We only cares about Left,Right,Up,Down keys with Command or Command+Shift
175     // modifiers. These key events correspond to some special movement and
176     // selection editor commands, and was supposed to be handled in
177     // WebKit/chromium/src/EditorClientImpl.cpp. But these keys will be marked
178     // as system key, which prevents them from being handled. Thus they must be
179     // handled specially.
180     if ((event.modifiers & ~WebKeyboardEvent::ShiftKey) != WebKeyboardEvent::MetaKey)
181         return false;
182
183     switch (event.windowsKeyCode) {
184     case VKEY_LEFT:
185         *name = "MoveToBeginningOfLine";
186         break;
187     case VKEY_RIGHT:
188         *name = "MoveToEndOfLine";
189         break;
190     case VKEY_UP:
191         *name = "MoveToBeginningOfDocument";
192         break;
193     case VKEY_DOWN:
194         *name = "MoveToEndOfDocument";
195         break;
196     default:
197         return false;
198     }
199
200     if (event.modifiers & WebKeyboardEvent::ShiftKey)
201         name->append("AndModifySelection");
202
203     return true;
204 #else
205     return false;
206 #endif
207 }
208
209 // Key event location code introduced in DOM Level 3.
210 // See also: http://www.w3.org/TR/DOM-Level-3-Events/#events-keyboardevents
211 enum KeyLocationCode {
212     DOMKeyLocationStandard      = 0x00,
213     DOMKeyLocationLeft          = 0x01,
214     DOMKeyLocationRight         = 0x02,
215     DOMKeyLocationNumpad        = 0x03
216 };
217
218 }
219
220 EventSender::EventSender(TestInterfaces* interfaces)
221     : m_testInterfaces(interfaces)
222     , m_delegate(0)
223 {
224     // Initialize the map that associates methods of this class with the names
225     // they will use when called by JavaScript. The actual binding of those
226     // names to their methods will be done by calling bindToJavaScript() (defined
227     // by CppBoundClass, the parent to EventSender).
228     bindMethod("addTouchPoint", &EventSender::addTouchPoint);
229     bindMethod("beginDragWithFiles", &EventSender::beginDragWithFiles);
230     bindMethod("cancelTouchPoint", &EventSender::cancelTouchPoint);
231     bindMethod("clearKillRing", &EventSender::clearKillRing);
232     bindMethod("clearTouchPoints", &EventSender::clearTouchPoints);
233     bindMethod("contextClick", &EventSender::contextClick);
234     bindMethod("continuousMouseScrollBy", &EventSender::continuousMouseScrollBy);
235     bindMethod("dispatchMessage", &EventSender::dispatchMessage);
236     bindMethod("dumpFilenameBeingDragged", &EventSender::dumpFilenameBeingDragged);
237     bindMethod("enableDOMUIEventLogging", &EventSender::enableDOMUIEventLogging);
238     bindMethod("fireKeyboardEventsToElement", &EventSender::fireKeyboardEventsToElement);
239     bindMethod("keyDown", &EventSender::keyDown);
240     bindMethod("leapForward", &EventSender::leapForward);
241     bindMethod("mouseDown", &EventSender::mouseDown);
242     bindMethod("mouseMoveTo", &EventSender::mouseMoveTo);
243     bindMethod("mouseScrollBy", &EventSender::mouseScrollBy);
244     bindMethod("mouseUp", &EventSender::mouseUp);
245     bindMethod("mouseDragBegin", &EventSender::mouseDragBegin);
246     bindMethod("mouseDragEnd", &EventSender::mouseDragEnd);
247     bindMethod("mouseMomentumBegin", &EventSender::mouseMomentumBegin);
248     bindMethod("mouseMomentumScrollBy", &EventSender::mouseMomentumScrollBy);
249     bindMethod("mouseMomentumEnd", &EventSender::mouseMomentumEnd);
250     bindMethod("releaseTouchPoint", &EventSender::releaseTouchPoint);
251     bindMethod("scheduleAsynchronousClick", &EventSender::scheduleAsynchronousClick);
252     bindMethod("scheduleAsynchronousKeyDown", &EventSender::scheduleAsynchronousKeyDown);
253     bindMethod("setTouchModifier", &EventSender::setTouchModifier);
254     bindMethod("textZoomIn", &EventSender::textZoomIn);
255     bindMethod("textZoomOut", &EventSender::textZoomOut);
256     bindMethod("touchCancel", &EventSender::touchCancel);
257     bindMethod("touchEnd", &EventSender::touchEnd);
258     bindMethod("touchMove", &EventSender::touchMove);
259     bindMethod("touchStart", &EventSender::touchStart);
260     bindMethod("updateTouchPoint", &EventSender::updateTouchPoint);
261     bindMethod("gestureFlingCancel", &EventSender::gestureFlingCancel);
262     bindMethod("gestureFlingStart", &EventSender::gestureFlingStart);
263     bindMethod("gestureScrollBegin", &EventSender::gestureScrollBegin);
264     bindMethod("gestureScrollEnd", &EventSender::gestureScrollEnd);
265     bindMethod("gestureScrollFirstPoint", &EventSender::gestureScrollFirstPoint);
266     bindMethod("gestureScrollUpdate", &EventSender::gestureScrollUpdate);
267     bindMethod("gestureScrollUpdateWithoutPropagation", &EventSender::gestureScrollUpdateWithoutPropagation);
268     bindMethod("gestureTap", &EventSender::gestureTap);
269     bindMethod("gestureTapDown", &EventSender::gestureTapDown);
270     bindMethod("gestureShowPress", &EventSender::gestureShowPress);
271     bindMethod("gestureTapCancel", &EventSender::gestureTapCancel);
272     bindMethod("gestureLongPress", &EventSender::gestureLongPress);
273     bindMethod("gestureLongTap", &EventSender::gestureLongTap);
274     bindMethod("gestureTwoFingerTap", &EventSender::gestureTwoFingerTap);
275     bindMethod("zoomPageIn", &EventSender::zoomPageIn);
276     bindMethod("zoomPageOut", &EventSender::zoomPageOut);
277     bindMethod("setPageScaleFactor", &EventSender::setPageScaleFactor);
278
279     bindProperty("forceLayoutOnEvents", &forceLayoutOnEvents);
280
281     // When set to true (the default value), we batch mouse move and mouse up
282     // events so we can simulate drag & drop.
283     bindProperty("dragMode", &dragMode);
284 #ifdef WIN32
285     bindProperty("WM_KEYDOWN", &wmKeyDown);
286     bindProperty("WM_KEYUP", &wmKeyUp);
287     bindProperty("WM_CHAR", &wmChar);
288     bindProperty("WM_DEADCHAR", &wmDeadChar);
289     bindProperty("WM_SYSKEYDOWN", &wmSysKeyDown);
290     bindProperty("WM_SYSKEYUP", &wmSysKeyUp);
291     bindProperty("WM_SYSCHAR", &wmSysChar);
292     bindProperty("WM_SYSDEADCHAR", &wmSysDeadChar);
293 #endif
294 }
295
296 EventSender::~EventSender()
297 {
298 }
299
300 void EventSender::setContextMenuData(const WebContextMenuData& contextMenuData)
301 {
302     m_lastContextMenuData = scoped_ptr<WebContextMenuData>(new WebContextMenuData(contextMenuData));
303 }
304
305 void EventSender::reset()
306 {
307     // The test should have finished a drag and the mouse button state.
308     BLINK_ASSERT(currentDragData.isNull());
309     currentDragData.reset();
310     currentDragEffect = blink::WebDragOperationNone;
311     currentDragEffectsAllowed = blink::WebDragOperationNone;
312     if (webview() && pressedButton != WebMouseEvent::ButtonNone)
313         webview()->mouseCaptureLost();
314     pressedButton = WebMouseEvent::ButtonNone;
315     dragMode.set(true);
316     forceLayoutOnEvents.set(true);
317 #ifdef WIN32
318     wmKeyDown.set(WM_KEYDOWN);
319     wmKeyUp.set(WM_KEYUP);
320     wmChar.set(WM_CHAR);
321     wmDeadChar.set(WM_DEADCHAR);
322     wmSysKeyDown.set(WM_SYSKEYDOWN);
323     wmSysKeyUp.set(WM_SYSKEYUP);
324     wmSysChar.set(WM_SYSCHAR);
325     wmSysDeadChar.set(WM_SYSDEADCHAR);
326 #endif
327     lastMousePos = WebPoint(0, 0);
328     lastClickTimeSec = 0;
329     lastClickPos = WebPoint(0, 0);
330     clickCount = 0;
331     lastButtonType = WebMouseEvent::ButtonNone;
332     timeOffsetMs = 0;
333     touchModifiers = 0;
334     touchPoints.clear();
335     m_taskList.revokeAll();
336     m_currentGestureLocation = WebPoint(0, 0);
337     mouseEventQueue.clear();
338 }
339
340 void EventSender::doDragDrop(const WebDragData& dragData, WebDragOperationsMask mask)
341 {
342     WebMouseEvent event;
343     initMouseEvent(WebInputEvent::MouseDown, pressedButton, lastMousePos, &event, getCurrentEventTimeSec(m_delegate));
344     WebPoint clientPoint(event.x, event.y);
345     WebPoint screenPoint(event.globalX, event.globalY);
346     currentDragData = dragData;
347     currentDragEffectsAllowed = mask;
348     currentDragEffect = webview()->dragTargetDragEnter(dragData, clientPoint, screenPoint, currentDragEffectsAllowed, 0);
349
350     // Finish processing events.
351     replaySavedEvents();
352 }
353
354 void EventSender::dumpFilenameBeingDragged(const CppArgumentList&, CppVariant*)
355 {
356     WebString filename;
357     WebVector<WebDragData::Item> items = currentDragData.items();
358     for (size_t i = 0; i < items.size(); ++i) {
359         if (items[i].storageType == WebDragData::Item::StorageTypeBinaryData) {
360             filename = items[i].title;
361             break;
362         }
363     }
364     m_delegate->printMessage(std::string("Filename being dragged: ") + filename.utf8().data() + "\n");
365 }
366
367 WebMouseEvent::Button EventSender::getButtonTypeFromButtonNumber(int buttonCode)
368 {
369     if (!buttonCode)
370         return WebMouseEvent::ButtonLeft;
371     if (buttonCode == 2)
372         return WebMouseEvent::ButtonRight;
373     return WebMouseEvent::ButtonMiddle;
374 }
375
376 int EventSender::getButtonNumberFromSingleArg(const CppArgumentList& arguments)
377 {
378     int buttonCode = 0;
379     if (arguments.size() > 0 && arguments[0].isNumber())
380         buttonCode = arguments[0].toInt32();
381     return buttonCode;
382 }
383
384 void EventSender::updateClickCountForButton(WebMouseEvent::Button buttonType)
385 {
386     if ((getCurrentEventTimeSec(m_delegate) - lastClickTimeSec < multipleClickTimeSec)
387         && (!outsideMultiClickRadius(lastMousePos, lastClickPos))
388         && (buttonType == lastButtonType))
389         ++clickCount;
390     else {
391         clickCount = 1;
392         lastButtonType = buttonType;
393     }
394 }
395
396 //
397 // Implemented javascript methods.
398 //
399
400 void EventSender::mouseDown(const CppArgumentList& arguments, CppVariant* result)
401 {
402     if (result) // Could be 0 if invoked asynchronously.
403         result->setNull();
404
405     if (shouldForceLayoutOnEvents())
406         webview()->layout();
407
408     int buttonNumber = getButtonNumberFromSingleArg(arguments);
409     BLINK_ASSERT(buttonNumber != -1);
410
411     WebMouseEvent::Button buttonType = getButtonTypeFromButtonNumber(buttonNumber);
412
413     updateClickCountForButton(buttonType);
414
415     WebMouseEvent event;
416     pressedButton = buttonType;
417     initMouseEvent(WebInputEvent::MouseDown, buttonType, lastMousePos, &event, getCurrentEventTimeSec(m_delegate));
418     if (arguments.size() >= 2 && (arguments[1].isObject() || arguments[1].isString()))
419         applyKeyModifiers(&(arguments[1]), &event);
420     webview()->handleInputEvent(event);
421 }
422
423 void EventSender::mouseUp(const CppArgumentList& arguments, CppVariant* result)
424 {
425     if (result) // Could be 0 if invoked asynchronously.
426         result->setNull();
427
428     if (shouldForceLayoutOnEvents())
429         webview()->layout();
430
431     int buttonNumber = getButtonNumberFromSingleArg(arguments);
432     BLINK_ASSERT(buttonNumber != -1);
433
434     WebMouseEvent::Button buttonType = getButtonTypeFromButtonNumber(buttonNumber);
435
436     if (isDragMode() && !replayingSavedEvents) {
437         SavedEvent savedEvent;
438         savedEvent.type = SavedEvent::MouseUp;
439         savedEvent.buttonType = buttonType;
440         mouseEventQueue.push_back(savedEvent);
441         replaySavedEvents();
442     } else {
443         WebMouseEvent event;
444         initMouseEvent(WebInputEvent::MouseUp, buttonType, lastMousePos, &event, getCurrentEventTimeSec(m_delegate));
445         if (arguments.size() >= 2 && (arguments[1].isObject() || arguments[1].isString()))
446             applyKeyModifiers(&(arguments[1]), &event);
447         doMouseUp(event);
448     }
449 }
450
451 void EventSender::doMouseUp(const WebMouseEvent& e)
452 {
453     webview()->handleInputEvent(e);
454
455     pressedButton = WebMouseEvent::ButtonNone;
456     lastClickTimeSec = e.timeStampSeconds;
457     lastClickPos = lastMousePos;
458
459     // If we're in a drag operation, complete it.
460     if (currentDragData.isNull())
461         return;
462
463     WebPoint clientPoint(e.x, e.y);
464     WebPoint screenPoint(e.globalX, e.globalY);
465     finishDragAndDrop(e, webview()->dragTargetDragOver(clientPoint, screenPoint, currentDragEffectsAllowed, 0));
466 }
467
468 void EventSender::finishDragAndDrop(const WebMouseEvent& e, blink::WebDragOperation dragEffect)
469 {
470     WebPoint clientPoint(e.x, e.y);
471     WebPoint screenPoint(e.globalX, e.globalY);
472     currentDragEffect = dragEffect;
473     if (currentDragEffect)
474         webview()->dragTargetDrop(clientPoint, screenPoint, 0);
475     else
476         webview()->dragTargetDragLeave();
477     webview()->dragSourceEndedAt(clientPoint, screenPoint, currentDragEffect);
478     webview()->dragSourceSystemDragEnded();
479
480     currentDragData.reset();
481 }
482
483 void EventSender::mouseMoveTo(const CppArgumentList& arguments, CppVariant* result)
484 {
485     result->setNull();
486
487     if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isNumber())
488         return;
489     if (shouldForceLayoutOnEvents())
490         webview()->layout();
491
492     WebPoint mousePos(arguments[0].toInt32(), arguments[1].toInt32());
493
494     if (isDragMode() && pressedButton == WebMouseEvent::ButtonLeft && !replayingSavedEvents) {
495         SavedEvent savedEvent;
496         savedEvent.type = SavedEvent::MouseMove;
497         savedEvent.pos = mousePos;
498         mouseEventQueue.push_back(savedEvent);
499     } else {
500         WebMouseEvent event;
501         initMouseEvent(WebInputEvent::MouseMove, pressedButton, mousePos, &event, getCurrentEventTimeSec(m_delegate));
502         if (arguments.size() >= 3 && (arguments[2].isObject() || arguments[2].isString()))
503             applyKeyModifiers(&(arguments[2]), &event);
504         doMouseMove(event);
505     }
506 }
507
508 void EventSender::doMouseMove(const WebMouseEvent& e)
509 {
510     lastMousePos = WebPoint(e.x, e.y);
511
512     webview()->handleInputEvent(e);
513
514     if (pressedButton == WebMouseEvent::ButtonNone || currentDragData.isNull())
515         return;
516     WebPoint clientPoint(e.x, e.y);
517     WebPoint screenPoint(e.globalX, e.globalY);
518     currentDragEffect = webview()->dragTargetDragOver(clientPoint, screenPoint, currentDragEffectsAllowed, 0);
519 }
520
521 void EventSender::keyDown(const CppArgumentList& arguments, CppVariant* result)
522 {
523     if (result)
524         result->setNull();
525     if (arguments.size() < 1 || !arguments[0].isString())
526         return;
527     bool generateChar = false;
528
529     // FIXME: I'm not exactly sure how we should convert the string to a key
530     // event. This seems to work in the cases I tested.
531     // FIXME: Should we also generate a KEY_UP?
532     string codeStr = arguments[0].toString();
533
534     // Convert \n -> VK_RETURN. Some layout tests use \n to mean "Enter", when
535     // Windows uses \r for "Enter".
536     int code = 0;
537     int text = 0;
538     bool needsShiftKeyModifier = false;
539     if ("\n" == codeStr) {
540         generateChar = true;
541         text = code = VKEY_RETURN;
542     } else if ("rightArrow" == codeStr)
543         code = VKEY_RIGHT;
544     else if ("downArrow" == codeStr)
545         code = VKEY_DOWN;
546     else if ("leftArrow" == codeStr)
547         code = VKEY_LEFT;
548     else if ("upArrow" == codeStr)
549         code = VKEY_UP;
550     else if ("insert" == codeStr)
551         code = VKEY_INSERT;
552     else if ("delete" == codeStr)
553         code = VKEY_DELETE;
554     else if ("pageUp" == codeStr)
555         code = VKEY_PRIOR;
556     else if ("pageDown" == codeStr)
557         code = VKEY_NEXT;
558     else if ("home" == codeStr)
559         code = VKEY_HOME;
560     else if ("end" == codeStr)
561         code = VKEY_END;
562     else if ("printScreen" == codeStr)
563         code = VKEY_SNAPSHOT;
564     else if ("menu" == codeStr)
565         code = VKEY_APPS;
566     else if ("leftControl" == codeStr)
567         code = VKEY_LCONTROL;
568     else if ("rightControl" == codeStr)
569         code = VKEY_RCONTROL;
570     else if ("leftShift" == codeStr)
571         code = VKEY_LSHIFT;
572     else if ("rightShift" == codeStr)
573         code = VKEY_RSHIFT;
574     else if ("leftAlt" == codeStr)
575         code = VKEY_LMENU;
576     else if ("rightAlt" == codeStr)
577         code = VKEY_RMENU;
578     else if ("numLock" == codeStr)
579         code = VKEY_NUMLOCK;
580     else {
581         // Compare the input string with the function-key names defined by the
582         // DOM spec (i.e. "F1",...,"F24"). If the input string is a function-key
583         // name, set its key code.
584         for (int i = 1; i <= 24; ++i) {
585             char functionChars[10];
586             snprintf(functionChars, 10, "F%d", i);
587             string functionKeyName(functionChars);
588             if (functionKeyName == codeStr) {
589                 code = VKEY_F1 + (i - 1);
590                 break;
591             }
592         }
593         if (!code) {
594             WebString webCodeStr = WebString::fromUTF8(codeStr.data(), codeStr.size());
595             BLINK_ASSERT(webCodeStr.length() == 1);
596             text = code = webCodeStr.at(0);
597             needsShiftKeyModifier = needsShiftModifier(code);
598             if ((code & 0xFF) >= 'a' && (code & 0xFF) <= 'z')
599                 code -= 'a' - 'A';
600             generateChar = true;
601         }
602
603         if ("(" == codeStr) {
604             code = '9';
605             needsShiftKeyModifier = true;
606         }
607     }
608
609     // For one generated keyboard event, we need to generate a keyDown/keyUp
610     // pair; refer to EventSender.cpp in Tools/DumpRenderTree/win.
611     // On Windows, we might also need to generate a char event to mimic the
612     // Windows event flow; on other platforms we create a merged event and test
613     // the event flow that that platform provides.
614     WebKeyboardEvent eventDown, eventChar, eventUp;
615     eventDown.type = WebInputEvent::RawKeyDown;
616     eventDown.modifiers = 0;
617     eventDown.windowsKeyCode = code;
618 #if defined(__linux__) && defined(TOOLKIT_GTK)
619     eventDown.nativeKeyCode = NativeKeyCodeForWindowsKeyCode(code);
620 #endif
621
622     if (generateChar) {
623         eventDown.text[0] = text;
624         eventDown.unmodifiedText[0] = text;
625     }
626     eventDown.setKeyIdentifierFromWindowsKeyCode();
627
628     if (arguments.size() >= 2 && (arguments[1].isObject() || arguments[1].isString())) {
629         applyKeyModifiers(&(arguments[1]), &eventDown);
630 #if WIN32 || __APPLE__ || defined(ANDROID) || defined(TOOLKIT_GTK)
631         eventDown.isSystemKey = WebInputEventFactory::isSystemKeyEvent(eventDown);
632 #endif
633     }
634
635     if (needsShiftKeyModifier)
636         eventDown.modifiers |= WebInputEvent::ShiftKey;
637
638     // See if KeyLocation argument is given.
639     if (arguments.size() >= 3 && arguments[2].isNumber()) {
640         int location = arguments[2].toInt32();
641         if (location == DOMKeyLocationNumpad)
642             eventDown.modifiers |= WebInputEvent::IsKeyPad;
643     }
644
645     eventChar = eventUp = eventDown;
646     eventUp.type = WebInputEvent::KeyUp;
647     // EventSender.m forces a layout here, with at least one
648     // test (fast/forms/focus-control-to-page.html) relying on this.
649     if (shouldForceLayoutOnEvents())
650         webview()->layout();
651
652     // In the browser, if a keyboard event corresponds to an editor command,
653     // the command will be dispatched to the renderer just before dispatching
654     // the keyboard event, and then it will be executed in the
655     // RenderView::handleCurrentKeyboardEvent() method, which is called from
656     // third_party/WebKit/Source/WebKit/chromium/src/EditorClientImpl.cpp.
657     // We just simulate the same behavior here.
658     string editCommand;
659     if (getEditCommand(eventDown, &editCommand))
660         m_delegate->setEditCommand(editCommand, "");
661
662     webview()->handleInputEvent(eventDown);
663
664     if (code == VKEY_ESCAPE && !currentDragData.isNull()) {
665         WebMouseEvent event;
666         initMouseEvent(WebInputEvent::MouseDown, pressedButton, lastMousePos, &event, getCurrentEventTimeSec(m_delegate));
667         finishDragAndDrop(event, blink::WebDragOperationNone);
668     }
669
670     m_delegate->clearEditCommand();
671
672     if (generateChar) {
673         eventChar.type = WebInputEvent::Char;
674         eventChar.keyIdentifier[0] = '\0';
675         webview()->handleInputEvent(eventChar);
676     }
677
678     webview()->handleInputEvent(eventUp);
679 }
680
681 void EventSender::dispatchMessage(const CppArgumentList& arguments, CppVariant* result)
682 {
683     result->setNull();
684
685 #ifdef WIN32
686     if (arguments.size() == 3) {
687         // Grab the message id to see if we need to dispatch it.
688         int msg = arguments[0].toInt32();
689
690         // WebKit's version of this function stuffs a MSG struct and uses
691         // TranslateMessage and DispatchMessage. We use a WebKeyboardEvent, which
692         // doesn't need to receive the DeadChar and SysDeadChar messages.
693         if (msg == WM_DEADCHAR || msg == WM_SYSDEADCHAR)
694             return;
695
696         if (shouldForceLayoutOnEvents())
697             webview()->layout();
698
699         unsigned long lparam = static_cast<unsigned long>(arguments[2].toDouble());
700         webview()->handleInputEvent(WebInputEventFactory::keyboardEvent(0, msg, arguments[1].toInt32(), lparam));
701     } else
702         BLINK_ASSERT_NOT_REACHED();
703 #endif
704 }
705
706 bool EventSender::needsShiftModifier(int keyCode)
707 {
708     // If code is an uppercase letter, assign a SHIFT key to
709     // eventDown.modifier, this logic comes from
710     // Tools/DumpRenderTree/win/EventSender.cpp
711     return (keyCode & 0xFF) >= 'A' && (keyCode & 0xFF) <= 'Z';
712 }
713
714 void EventSender::leapForward(const CppArgumentList& arguments, CppVariant* result)
715 {
716     result->setNull();
717
718     if (arguments.size() < 1 || !arguments[0].isNumber())
719         return;
720
721     int milliseconds = arguments[0].toInt32();
722     if (isDragMode() && pressedButton == WebMouseEvent::ButtonLeft && !replayingSavedEvents) {
723         SavedEvent savedEvent;
724         savedEvent.type = SavedEvent::LeapForward;
725         savedEvent.milliseconds = milliseconds;
726         mouseEventQueue.push_back(savedEvent);
727     } else
728         doLeapForward(milliseconds);
729 }
730
731 void EventSender::doLeapForward(int milliseconds)
732 {
733     advanceEventTime(milliseconds);
734 }
735
736 // Apple's port of WebKit zooms by a factor of 1.2 (see
737 // WebKit/WebView/WebView.mm)
738 void EventSender::textZoomIn(const CppArgumentList&, CppVariant* result)
739 {
740     webview()->setTextZoomFactor(webview()->textZoomFactor() * 1.2f);
741     result->setNull();
742 }
743
744 void EventSender::textZoomOut(const CppArgumentList&, CppVariant* result)
745 {
746     webview()->setTextZoomFactor(webview()->textZoomFactor() / 1.2f);
747     result->setNull();
748 }
749
750 void EventSender::zoomPageIn(const CppArgumentList&, CppVariant* result)
751 {
752     const vector<WebTestProxyBase*>& windowList = m_testInterfaces->windowList();
753
754     for (size_t i = 0; i < windowList.size(); ++i)
755         windowList.at(i)->webView()->setZoomLevel(windowList.at(i)->webView()->zoomLevel() + 1);
756     result->setNull();
757 }
758
759 void EventSender::zoomPageOut(const CppArgumentList&, CppVariant* result)
760 {
761     const vector<WebTestProxyBase*>& windowList = m_testInterfaces->windowList();
762
763     for (size_t i = 0; i < windowList.size(); ++i)
764         windowList.at(i)->webView()->setZoomLevel(windowList.at(i)->webView()->zoomLevel() - 1);
765     result->setNull();
766 }
767
768 void EventSender::setPageScaleFactor(const CppArgumentList& arguments, CppVariant* result)
769 {
770     if (arguments.size() < 3 || !arguments[0].isNumber() || !arguments[1].isNumber() || !arguments[2].isNumber())
771         return;
772
773     float scaleFactor = static_cast<float>(arguments[0].toDouble());
774     int x = arguments[1].toInt32();
775     int y = arguments[2].toInt32();
776     webview()->setPageScaleFactorLimits(scaleFactor, scaleFactor);
777     webview()->setPageScaleFactor(scaleFactor, WebPoint(x, y));
778     result->setNull();
779 }
780
781 void EventSender::mouseScrollBy(const CppArgumentList& arguments, CppVariant* result)
782 {
783     WebMouseWheelEvent event;
784     initMouseWheelEvent(arguments, result, false, &event);
785     webview()->handleInputEvent(event);
786 }
787
788 void EventSender::continuousMouseScrollBy(const CppArgumentList& arguments, CppVariant* result)
789 {
790     WebMouseWheelEvent event;
791     initMouseWheelEvent(arguments, result, true, &event);
792     webview()->handleInputEvent(event);
793 }
794
795 void EventSender::replaySavedEvents()
796 {
797     replayingSavedEvents = true;
798     while (!mouseEventQueue.empty()) {
799         SavedEvent e = mouseEventQueue.front();
800         mouseEventQueue.pop_front();
801
802         switch (e.type) {
803         case SavedEvent::MouseMove: {
804             WebMouseEvent event;
805             initMouseEvent(WebInputEvent::MouseMove, pressedButton, e.pos, &event, getCurrentEventTimeSec(m_delegate));
806             doMouseMove(event);
807             break;
808         }
809         case SavedEvent::LeapForward:
810             doLeapForward(e.milliseconds);
811             break;
812         case SavedEvent::MouseUp: {
813             WebMouseEvent event;
814             initMouseEvent(WebInputEvent::MouseUp, e.buttonType, lastMousePos, &event, getCurrentEventTimeSec(m_delegate));
815             doMouseUp(event);
816             break;
817         }
818         default:
819             BLINK_ASSERT_NOT_REACHED();
820         }
821     }
822
823     replayingSavedEvents = false;
824 }
825
826 // Because actual context menu is implemented by the browser side,
827 // this function does only what LayoutTests are expecting:
828 // - Many test checks the count of items. So returning non-zero value makes sense.
829 // - Some test compares the count before and after some action. So changing the count based on flags
830 //   also makes sense. This function is doing such for some flags.
831 // - Some test even checks actual string content. So providing it would be also helpful.
832 //
833 static vector<WebString> makeMenuItemStringsFor(WebContextMenuData* contextMenu, WebTestDelegate* delegate)
834 {
835     // These constants are based on Safari's context menu because tests are made for it.
836     static const char* nonEditableMenuStrings[] = { "Back", "Reload Page", "Open in Dashbaord", "<separator>", "View Source", "Save Page As", "Print Page", "Inspect Element", 0 };
837     static const char* editableMenuStrings[] = { "Cut", "Copy", "<separator>", "Paste", "Spelling and Grammar", "Substitutions, Transformations", "Font", "Speech", "Paragraph Direction", "<separator>", 0 };
838
839     // This is possible because mouse events are cancelleable.
840     if (!contextMenu)
841         return vector<WebString>();
842
843     vector<WebString> strings;
844
845     if (contextMenu->isEditable) {
846         for (const char** item = editableMenuStrings; *item; ++item)
847             strings.push_back(WebString::fromUTF8(*item));
848         WebVector<WebString> suggestions;
849         MockSpellCheck::fillSuggestionList(contextMenu->misspelledWord, &suggestions);
850         for (size_t i = 0; i < suggestions.size(); ++i)
851             strings.push_back(suggestions[i]);
852     } else {
853         for (const char** item = nonEditableMenuStrings; *item; ++item)
854             strings.push_back(WebString::fromUTF8(*item));
855     }
856
857     return strings;
858 }
859
860 void EventSender::contextClick(const CppArgumentList& arguments, CppVariant* result)
861 {
862     if (shouldForceLayoutOnEvents())
863         webview()->layout();
864
865     updateClickCountForButton(WebMouseEvent::ButtonRight);
866
867     // Clears last context menu data because we need to know if the context menu be requested
868     // after following mouse events.
869     m_lastContextMenuData.reset();
870
871     // Generate right mouse down and up.
872     WebMouseEvent event;
873     // This is a hack to work around only allowing a single pressed button since we want to
874     // test the case where both the left and right mouse buttons are pressed.
875     if (pressedButton == WebMouseEvent::ButtonNone)
876         pressedButton = WebMouseEvent::ButtonRight;
877     initMouseEvent(WebInputEvent::MouseDown, WebMouseEvent::ButtonRight, lastMousePos, &event, getCurrentEventTimeSec(m_delegate));
878     webview()->handleInputEvent(event);
879
880 #ifdef WIN32
881     initMouseEvent(WebInputEvent::MouseUp, WebMouseEvent::ButtonRight, lastMousePos, &event, getCurrentEventTimeSec(m_delegate));
882     webview()->handleInputEvent(event);
883
884     pressedButton = WebMouseEvent::ButtonNone;
885 #endif
886
887     NPObject* resultArray = WebBindings::makeStringArray(makeMenuItemStringsFor(m_lastContextMenuData.get(), m_delegate));
888     result->set(resultArray);
889     WebBindings::releaseObject(resultArray);
890
891     m_lastContextMenuData.reset();
892 }
893
894 class MouseDownTask: public WebMethodTask<EventSender> {
895 public:
896     MouseDownTask(EventSender* obj, const CppArgumentList& arg)
897         : WebMethodTask<EventSender>(obj), m_arguments(arg) { }
898     virtual void runIfValid() OVERRIDE { m_object->mouseDown(m_arguments, 0); }
899
900 private:
901     CppArgumentList m_arguments;
902 };
903
904 class MouseUpTask: public WebMethodTask<EventSender> {
905 public:
906     MouseUpTask(EventSender* obj, const CppArgumentList& arg)
907         : WebMethodTask<EventSender>(obj), m_arguments(arg) { }
908     virtual void runIfValid() OVERRIDE { m_object->mouseUp(m_arguments, 0); }
909
910 private:
911     CppArgumentList m_arguments;
912 };
913
914 void EventSender::scheduleAsynchronousClick(const CppArgumentList& arguments, CppVariant* result)
915 {
916     result->setNull();
917     m_delegate->postTask(new MouseDownTask(this, arguments));
918     m_delegate->postTask(new MouseUpTask(this, arguments));
919 }
920
921 class KeyDownTask : public WebMethodTask<EventSender> {
922 public:
923     KeyDownTask(EventSender* obj, const CppArgumentList& arg)
924         : WebMethodTask<EventSender>(obj), m_arguments(arg) { }
925     virtual void runIfValid() OVERRIDE { m_object->keyDown(m_arguments, 0); }
926
927 private:
928     CppArgumentList m_arguments;
929 };
930
931 void EventSender::scheduleAsynchronousKeyDown(const CppArgumentList& arguments, CppVariant* result)
932 {
933     result->setNull();
934     m_delegate->postTask(new KeyDownTask(this, arguments));
935 }
936
937 void EventSender::beginDragWithFiles(const CppArgumentList& arguments, CppVariant* result)
938 {
939     currentDragData.initialize();
940     vector<string> files = arguments[0].toStringVector();
941     WebVector<WebString> absoluteFilenames(files.size());
942     for (size_t i = 0; i < files.size(); ++i) {
943         WebDragData::Item item;
944         item.storageType = WebDragData::Item::StorageTypeFilename;
945         item.filenameData = m_delegate->getAbsoluteWebStringFromUTF8Path(files[i]);
946         currentDragData.addItem(item);
947         absoluteFilenames[i] = item.filenameData;
948     }
949     currentDragData.setFilesystemId(m_delegate->registerIsolatedFileSystem(absoluteFilenames));
950     currentDragEffectsAllowed = blink::WebDragOperationCopy;
951
952     // Provide a drag source.
953     webview()->dragTargetDragEnter(currentDragData, lastMousePos, lastMousePos, currentDragEffectsAllowed, 0);
954
955     // dragMode saves events and then replays them later. We don't need/want that.
956     dragMode.set(false);
957
958     // Make the rest of eventSender think a drag is in progress.
959     pressedButton = WebMouseEvent::ButtonLeft;
960
961     result->setNull();
962 }
963
964 void EventSender::addTouchPoint(const CppArgumentList& arguments, CppVariant* result)
965 {
966     result->setNull();
967
968     WebTouchPoint touchPoint;
969     touchPoint.state = WebTouchPoint::StatePressed;
970     touchPoint.position = WebPoint(arguments[0].toInt32(), arguments[1].toInt32());
971     touchPoint.screenPosition = touchPoint.position;
972
973     if (arguments.size() > 2) {
974         int radiusX = arguments[2].toInt32();
975         int radiusY = radiusX;
976         if (arguments.size() > 3)
977             radiusY = arguments[3].toInt32();
978
979         touchPoint.radiusX = radiusX;
980         touchPoint.radiusY = radiusY;
981     }
982
983     int lowestId = 0;
984     for (size_t i = 0; i < touchPoints.size(); i++) {
985         if (touchPoints[i].id == lowestId)
986             lowestId++;
987     }
988     touchPoint.id = lowestId;
989     touchPoints.push_back(touchPoint);
990 }
991
992 void EventSender::clearTouchPoints(const CppArgumentList&, CppVariant* result)
993 {
994     result->setNull();
995     touchPoints.clear();
996 }
997
998 void EventSender::releaseTouchPoint(const CppArgumentList& arguments, CppVariant* result)
999 {
1000     result->setNull();
1001
1002     const unsigned index = arguments[0].toInt32();
1003     BLINK_ASSERT(index < touchPoints.size());
1004
1005     WebTouchPoint* touchPoint = &touchPoints[index];
1006     touchPoint->state = WebTouchPoint::StateReleased;
1007 }
1008
1009 void EventSender::setTouchModifier(const CppArgumentList& arguments, CppVariant* result)
1010 {
1011     result->setNull();
1012
1013     int mask = 0;
1014     const string keyName = arguments[0].toString();
1015     if (keyName == "shift")
1016         mask = WebInputEvent::ShiftKey;
1017     else if (keyName == "alt")
1018         mask = WebInputEvent::AltKey;
1019     else if (keyName == "ctrl")
1020         mask = WebInputEvent::ControlKey;
1021     else if (keyName == "meta")
1022         mask = WebInputEvent::MetaKey;
1023
1024     if (arguments[1].toBoolean())
1025         touchModifiers |= mask;
1026     else
1027         touchModifiers &= ~mask;
1028 }
1029
1030 void EventSender::updateTouchPoint(const CppArgumentList& arguments, CppVariant* result)
1031 {
1032     result->setNull();
1033
1034     const unsigned index = arguments[0].toInt32();
1035     BLINK_ASSERT(index < touchPoints.size());
1036
1037     WebPoint position(arguments[1].toInt32(), arguments[2].toInt32());
1038     WebTouchPoint* touchPoint = &touchPoints[index];
1039     touchPoint->state = WebTouchPoint::StateMoved;
1040     touchPoint->position = position;
1041     touchPoint->screenPosition = position;
1042 }
1043
1044 void EventSender::cancelTouchPoint(const CppArgumentList& arguments, CppVariant* result)
1045 {
1046     result->setNull();
1047
1048     const unsigned index = arguments[0].toInt32();
1049     BLINK_ASSERT(index < touchPoints.size());
1050
1051     WebTouchPoint* touchPoint = &touchPoints[index];
1052     touchPoint->state = WebTouchPoint::StateCancelled;
1053 }
1054
1055 void EventSender::sendCurrentTouchEvent(const WebInputEvent::Type type)
1056 {
1057     BLINK_ASSERT(static_cast<unsigned>(WebTouchEvent::touchesLengthCap) > touchPoints.size());
1058     if (shouldForceLayoutOnEvents())
1059         webview()->layout();
1060
1061     WebTouchEvent touchEvent;
1062     touchEvent.type = type;
1063     touchEvent.modifiers = touchModifiers;
1064     touchEvent.timeStampSeconds = getCurrentEventTimeSec(m_delegate);
1065     touchEvent.touchesLength = touchPoints.size();
1066     for (unsigned i = 0; i < touchPoints.size(); ++i)
1067         touchEvent.touches[i] = touchPoints[i];
1068     webview()->handleInputEvent(touchEvent);
1069
1070     for (unsigned i = 0; i < touchPoints.size(); ++i) {
1071         WebTouchPoint* touchPoint = &touchPoints[i];
1072         if (touchPoint->state == WebTouchPoint::StateReleased) {
1073             touchPoints.erase(touchPoints.begin() + i);
1074             --i;
1075         } else
1076             touchPoint->state = WebTouchPoint::StateStationary;
1077     }
1078 }
1079
1080 void EventSender::mouseDragBegin(const CppArgumentList& arguments, CppVariant* result)
1081 {
1082     WebMouseWheelEvent event;
1083     initMouseEvent(WebInputEvent::MouseWheel, WebMouseEvent::ButtonNone, lastMousePos, &event, getCurrentEventTimeSec(m_delegate));
1084     event.phase = WebMouseWheelEvent::PhaseBegan;
1085     event.hasPreciseScrollingDeltas = true;
1086     webview()->handleInputEvent(event);
1087 }
1088
1089 void EventSender::mouseDragEnd(const CppArgumentList& arguments, CppVariant* result)
1090 {
1091     WebMouseWheelEvent event;
1092     initMouseEvent(WebInputEvent::MouseWheel, WebMouseEvent::ButtonNone, lastMousePos, &event, getCurrentEventTimeSec(m_delegate));
1093     event.phase = WebMouseWheelEvent::PhaseEnded;
1094     event.hasPreciseScrollingDeltas = true;
1095     webview()->handleInputEvent(event);
1096 }
1097
1098 void EventSender::mouseMomentumBegin(const CppArgumentList& arguments, CppVariant* result)
1099 {
1100     WebMouseWheelEvent event;
1101     initMouseEvent(WebInputEvent::MouseWheel, WebMouseEvent::ButtonNone, lastMousePos, &event, getCurrentEventTimeSec(m_delegate));
1102     event.momentumPhase = WebMouseWheelEvent::PhaseBegan;
1103     event.hasPreciseScrollingDeltas = true;
1104     webview()->handleInputEvent(event);
1105 }
1106
1107 void EventSender::mouseMomentumScrollBy(const CppArgumentList& arguments, CppVariant* result)
1108 {
1109     WebMouseWheelEvent event;
1110     initMouseWheelEvent(arguments, result, true, &event);
1111     event.momentumPhase = WebMouseWheelEvent::PhaseChanged;
1112     event.hasPreciseScrollingDeltas = true;
1113     webview()->handleInputEvent(event);
1114 }
1115
1116 void EventSender::mouseMomentumEnd(const CppArgumentList& arguments, CppVariant* result)
1117 {
1118     WebMouseWheelEvent event;
1119     initMouseEvent(WebInputEvent::MouseWheel, WebMouseEvent::ButtonNone, lastMousePos, &event, getCurrentEventTimeSec(m_delegate));
1120     event.momentumPhase = WebMouseWheelEvent::PhaseEnded;
1121     event.hasPreciseScrollingDeltas = true;
1122     webview()->handleInputEvent(event);
1123 }
1124
1125 void EventSender::initMouseWheelEvent(const CppArgumentList& arguments, CppVariant* result, bool continuous, WebMouseWheelEvent* event)
1126 {
1127     result->setNull();
1128
1129     if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isNumber())
1130         return;
1131
1132     // Force a layout here just to make sure every position has been
1133     // determined before we send events (as well as all the other methods
1134     // that send an event do).
1135     if (shouldForceLayoutOnEvents())
1136         webview()->layout();
1137
1138     int horizontal = arguments[0].toInt32();
1139     int vertical = arguments[1].toInt32();
1140     int paged = false;
1141     int hasPreciseScrollingDeltas = false;
1142
1143     if (arguments.size() > 2 && arguments[2].isBool())
1144         paged = arguments[2].toBoolean();
1145
1146     if (arguments.size() > 3 && arguments[3].isBool())
1147         hasPreciseScrollingDeltas = arguments[3].toBoolean();
1148
1149     initMouseEvent(WebInputEvent::MouseWheel, pressedButton, lastMousePos, event, getCurrentEventTimeSec(m_delegate));
1150     event->wheelTicksX = static_cast<float>(horizontal);
1151     event->wheelTicksY = static_cast<float>(vertical);
1152     event->deltaX = event->wheelTicksX;
1153     event->deltaY = event->wheelTicksY;
1154     event->scrollByPage = paged;
1155     event->hasPreciseScrollingDeltas = hasPreciseScrollingDeltas;
1156
1157     if (continuous) {
1158         event->wheelTicksX /= scrollbarPixelsPerTick;
1159         event->wheelTicksY /= scrollbarPixelsPerTick;
1160     } else {
1161         event->deltaX *= scrollbarPixelsPerTick;
1162         event->deltaY *= scrollbarPixelsPerTick;
1163     }
1164 }
1165
1166 void EventSender::touchEnd(const CppArgumentList&, CppVariant* result)
1167 {
1168     result->setNull();
1169     sendCurrentTouchEvent(WebInputEvent::TouchEnd);
1170 }
1171
1172 void EventSender::touchMove(const CppArgumentList&, CppVariant* result)
1173 {
1174     result->setNull();
1175     sendCurrentTouchEvent(WebInputEvent::TouchMove);
1176 }
1177
1178 void EventSender::touchStart(const CppArgumentList&, CppVariant* result)
1179 {
1180     result->setNull();
1181     sendCurrentTouchEvent(WebInputEvent::TouchStart);
1182 }
1183
1184 void EventSender::touchCancel(const CppArgumentList&, CppVariant* result)
1185 {
1186     result->setNull();
1187     sendCurrentTouchEvent(WebInputEvent::TouchCancel);
1188 }
1189
1190 void EventSender::gestureScrollBegin(const CppArgumentList& arguments, CppVariant* result)
1191 {
1192     result->setNull();
1193     gestureEvent(WebInputEvent::GestureScrollBegin, arguments);
1194 }
1195
1196 void EventSender::gestureScrollEnd(const CppArgumentList& arguments, CppVariant* result)
1197 {
1198     result->setNull();
1199     gestureEvent(WebInputEvent::GestureScrollEnd, arguments);
1200 }
1201
1202 void EventSender::gestureScrollUpdate(const CppArgumentList& arguments, CppVariant* result)
1203 {
1204     result->setNull();
1205     gestureEvent(WebInputEvent::GestureScrollUpdate, arguments);
1206 }
1207
1208 void EventSender::gestureScrollUpdateWithoutPropagation(const CppArgumentList& arguments, CppVariant* result)
1209 {
1210     result->setNull();
1211     gestureEvent(WebInputEvent::GestureScrollUpdateWithoutPropagation, arguments);
1212 }
1213
1214 void EventSender::gestureTap(const CppArgumentList& arguments, CppVariant* result)
1215 {
1216     result->setNull();
1217     gestureEvent(WebInputEvent::GestureTap, arguments);
1218 }
1219
1220 void EventSender::gestureTapDown(const CppArgumentList& arguments, CppVariant* result)
1221 {
1222     result->setNull();
1223     gestureEvent(WebInputEvent::GestureTapDown, arguments);
1224 }
1225
1226 void EventSender::gestureShowPress(const CppArgumentList& arguments, CppVariant* result)
1227 {
1228     result->setNull();
1229     gestureEvent(WebInputEvent::GestureShowPress, arguments);
1230 }
1231
1232 void EventSender::gestureTapCancel(const CppArgumentList& arguments, CppVariant* result)
1233 {
1234     result->setNull();
1235     gestureEvent(WebInputEvent::GestureTapCancel, arguments);
1236 }
1237
1238 void EventSender::gestureLongPress(const CppArgumentList& arguments, CppVariant* result)
1239 {
1240     result->setNull();
1241     gestureEvent(WebInputEvent::GestureLongPress, arguments);
1242 }
1243
1244 void EventSender::gestureLongTap(const CppArgumentList& arguments, CppVariant* result)
1245 {
1246     result->setNull();
1247     gestureEvent(WebInputEvent::GestureLongTap, arguments);
1248 }
1249
1250 void EventSender::gestureTwoFingerTap(const CppArgumentList& arguments, CppVariant* result)
1251 {
1252     result->setNull();
1253     gestureEvent(WebInputEvent::GestureTwoFingerTap, arguments);
1254 }
1255
1256 void EventSender::gestureScrollFirstPoint(const CppArgumentList& arguments, CppVariant* result)
1257 {
1258     result->setNull();
1259     if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isNumber())
1260         return;
1261
1262     WebPoint point(arguments[0].toInt32(), arguments[1].toInt32());
1263     m_currentGestureLocation = point;
1264 }
1265
1266 void EventSender::gestureEvent(WebInputEvent::Type type, const CppArgumentList& arguments)
1267 {
1268     if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isNumber())
1269         return;
1270
1271     WebPoint point(arguments[0].toInt32(), arguments[1].toInt32());
1272
1273     WebGestureEvent event;
1274     event.type = type;
1275
1276     switch (type) {
1277     case WebInputEvent::GestureScrollUpdate:
1278     case WebInputEvent::GestureScrollUpdateWithoutPropagation:
1279         event.data.scrollUpdate.deltaX = static_cast<float>(arguments[0].toDouble());
1280         event.data.scrollUpdate.deltaY = static_cast<float>(arguments[1].toDouble());
1281         event.x = m_currentGestureLocation.x;
1282         event.y = m_currentGestureLocation.y;
1283         m_currentGestureLocation.x = m_currentGestureLocation.x + event.data.scrollUpdate.deltaX;
1284         m_currentGestureLocation.y = m_currentGestureLocation.y + event.data.scrollUpdate.deltaY;
1285         break;
1286
1287     case WebInputEvent::GestureScrollBegin:
1288         m_currentGestureLocation = WebPoint(point.x, point.y);
1289         event.x = m_currentGestureLocation.x;
1290         event.y = m_currentGestureLocation.y;
1291         break;
1292     case WebInputEvent::GestureScrollEnd:
1293     case WebInputEvent::GestureFlingStart:
1294         event.x = m_currentGestureLocation.x;
1295         event.y = m_currentGestureLocation.y;
1296         break;
1297     case WebInputEvent::GestureTap:
1298         if (arguments.size() >= 3)
1299             event.data.tap.tapCount = static_cast<float>(arguments[2].toDouble());
1300         else
1301           event.data.tap.tapCount = 1;
1302         event.x = point.x;
1303         event.y = point.y;
1304         break;
1305     case WebInputEvent::GestureTapUnconfirmed:
1306         if (arguments.size() >= 3)
1307             event.data.tap.tapCount = static_cast<float>(arguments[2].toDouble());
1308         else
1309           event.data.tap.tapCount = 1;
1310         event.x = point.x;
1311         event.y = point.y;
1312         break;
1313     case WebInputEvent::GestureTapDown:
1314         event.x = point.x;
1315         event.y = point.y;
1316         if (arguments.size() >= 4) {
1317             event.data.tapDown.width = static_cast<float>(arguments[2].toDouble());
1318             event.data.tapDown.height = static_cast<float>(arguments[3].toDouble());
1319         }
1320         break;
1321     case WebInputEvent::GestureShowPress:
1322         event.x = point.x;
1323         event.y = point.y;
1324         if (arguments.size() >= 4) {
1325             event.data.showPress.width = static_cast<float>(arguments[2].toDouble());
1326             event.data.showPress.height = static_cast<float>(arguments[3].toDouble());
1327         }
1328         break;
1329     case WebInputEvent::GestureTapCancel:
1330         event.x = point.x;
1331         event.y = point.y;
1332         break;
1333     case WebInputEvent::GestureLongPress:
1334         event.x = point.x;
1335         event.y = point.y;
1336         if (arguments.size() >= 4) {
1337             event.data.longPress.width = static_cast<float>(arguments[2].toDouble());
1338             event.data.longPress.height = static_cast<float>(arguments[3].toDouble());
1339         }
1340         break;
1341     case WebInputEvent::GestureLongTap:
1342         event.x = point.x;
1343         event.y = point.y;
1344         if (arguments.size() >= 4) {
1345             event.data.longPress.width = static_cast<float>(arguments[2].toDouble());
1346             event.data.longPress.height = static_cast<float>(arguments[3].toDouble());
1347         }
1348         break;
1349     case WebInputEvent::GestureTwoFingerTap:
1350         event.x = point.x;
1351         event.y = point.y;
1352         if (arguments.size() >= 4) {
1353             event.data.twoFingerTap.firstFingerWidth = static_cast<float>(arguments[2].toDouble());
1354             event.data.twoFingerTap.firstFingerHeight = static_cast<float>(arguments[3].toDouble());
1355         }
1356         break;
1357     default:
1358         BLINK_ASSERT_NOT_REACHED();
1359     }
1360
1361     event.globalX = event.x;
1362     event.globalY = event.y;
1363     event.timeStampSeconds = getCurrentEventTimeSec(m_delegate);
1364
1365     if (shouldForceLayoutOnEvents())
1366         webview()->layout();
1367
1368     webview()->handleInputEvent(event);
1369
1370     // Long press might start a drag drop session. Complete it if so.
1371     if (type == WebInputEvent::GestureLongPress && !currentDragData.isNull()) {
1372         WebMouseEvent mouseEvent;
1373         initMouseEvent(WebInputEvent::MouseDown, pressedButton, point, &mouseEvent, getCurrentEventTimeSec(m_delegate));
1374         finishDragAndDrop(mouseEvent, blink::WebDragOperationNone);
1375     }
1376 }
1377
1378 void EventSender::gestureFlingCancel(const CppArgumentList&, CppVariant* result)
1379 {
1380     result->setNull();
1381
1382     WebGestureEvent event;
1383     event.type = WebInputEvent::GestureFlingCancel;
1384     event.timeStampSeconds = getCurrentEventTimeSec(m_delegate);
1385
1386     if (shouldForceLayoutOnEvents())
1387         webview()->layout();
1388
1389     webview()->handleInputEvent(event);
1390 }
1391
1392 void EventSender::gestureFlingStart(const CppArgumentList& arguments, CppVariant* result)
1393 {
1394     result->setNull();
1395     if (arguments.size() < 4)
1396         return;
1397
1398     for (int i = 0; i < 4; i++)
1399         if (!arguments[i].isNumber())
1400             return;
1401
1402     WebGestureEvent event;
1403     event.type = WebInputEvent::GestureFlingStart;
1404
1405     event.x = static_cast<float>(arguments[0].toDouble());
1406     event.y = static_cast<float>(arguments[1].toDouble());
1407     event.globalX = event.x;
1408     event.globalY = event.y;
1409
1410     event.data.flingStart.velocityX = static_cast<float>(arguments[2].toDouble());
1411     event.data.flingStart.velocityY = static_cast<float>(arguments[3].toDouble());
1412     event.timeStampSeconds = getCurrentEventTimeSec(m_delegate);
1413
1414     if (shouldForceLayoutOnEvents())
1415         webview()->layout();
1416
1417     webview()->handleInputEvent(event);
1418 }
1419
1420 //
1421 // Unimplemented stubs
1422 //
1423
1424 void EventSender::enableDOMUIEventLogging(const CppArgumentList&, CppVariant* result)
1425 {
1426     result->setNull();
1427 }
1428
1429 void EventSender::fireKeyboardEventsToElement(const CppArgumentList&, CppVariant* result)
1430 {
1431     result->setNull();
1432 }
1433
1434 void EventSender::clearKillRing(const CppArgumentList&, CppVariant* result)
1435 {
1436     result->setNull();
1437 }
1438
1439 }