WebKitTools/DumpRenderTree/chromium/EventSender.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 /*
       
     2  * Copyright (C) 2010 Google Inc. All rights reserved.
       
     3  *
       
     4  * Redistribution and use in source and binary forms, with or without
       
     5  * modification, are permitted provided that the following conditions are
       
     6  * met:
       
     7  *
       
     8  *     * Redistributions of source code must retain the above copyright
       
     9  * notice, this list of conditions and the following disclaimer.
       
    10  *     * Redistributions in binary form must reproduce the above
       
    11  * copyright notice, this list of conditions and the following disclaimer
       
    12  * in the documentation and/or other materials provided with the
       
    13  * distribution.
       
    14  *     * Neither the name of Google Inc. nor the names of its
       
    15  * contributors may be used to endorse or promote products derived from
       
    16  * this software without specific prior written permission.
       
    17  *
       
    18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
       
    19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
       
    20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
       
    21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
       
    22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
       
    23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
       
    24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
       
    25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
       
    26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
       
    27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
       
    28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    29  */
       
    30 
       
    31 // This file contains the definition for EventSender.
       
    32 //
       
    33 // Some notes about drag and drop handling:
       
    34 // Windows drag and drop goes through a system call to doDragDrop.  At that
       
    35 // point, program control is given to Windows which then periodically makes
       
    36 // callbacks into the webview.  This won't work for layout tests, so instead,
       
    37 // we queue up all the mouse move and mouse up events.  When the test tries to
       
    38 // start a drag (by calling EvenSendingController::doDragDrop), we take the
       
    39 // events in the queue and replay them.
       
    40 // The behavior of queuing events and replaying them can be disabled by a
       
    41 // layout test by setting eventSender.dragMode to false.
       
    42 
       
    43 #include "config.h"
       
    44 #include "EventSender.h"
       
    45 
       
    46 #include "TestShell.h"
       
    47 #include "base/keyboard_codes.h"
       
    48 #include "base/time.h"
       
    49 #include "public/WebDragData.h"
       
    50 #include "public/WebDragOperation.h"
       
    51 #include "public/WebPoint.h"
       
    52 #include "public/WebString.h"
       
    53 #include "public/WebTouchPoint.h"
       
    54 #include "public/WebView.h"
       
    55 #include "webkit/support/webkit_support.h"
       
    56 #include <wtf/Deque.h>
       
    57 #include <wtf/StringExtras.h>
       
    58 
       
    59 #if OS(WINDOWS)
       
    60 #include "public/win/WebInputEventFactory.h"
       
    61 #endif
       
    62 
       
    63 // FIXME: layout before each event?
       
    64 
       
    65 using namespace base;
       
    66 using namespace std;
       
    67 using namespace WebKit;
       
    68 
       
    69 WebPoint EventSender::lastMousePos;
       
    70 WebMouseEvent::Button EventSender::pressedButton = WebMouseEvent::ButtonNone;
       
    71 WebMouseEvent::Button EventSender::lastButtonType = WebMouseEvent::ButtonNone;
       
    72 
       
    73 struct SavedEvent {
       
    74     enum SavedEventType {
       
    75         Unspecified,
       
    76         MouseUp,
       
    77         MouseMove,
       
    78         LeapForward
       
    79     };
       
    80 
       
    81     SavedEventType type;
       
    82     WebMouseEvent::Button buttonType; // For MouseUp.
       
    83     WebPoint pos; // For MouseMove.
       
    84     int milliseconds; // For LeapForward.
       
    85 
       
    86     SavedEvent()
       
    87         : type(Unspecified)
       
    88         , buttonType(WebMouseEvent::ButtonNone)
       
    89         , milliseconds(0) {}
       
    90 };
       
    91 
       
    92 static WebDragData currentDragData;
       
    93 static WebDragOperation currentDragEffect;
       
    94 static WebDragOperationsMask currentDragEffectsAllowed;
       
    95 static bool replayingSavedEvents = false;
       
    96 static Deque<SavedEvent> mouseEventQueue;
       
    97 static int touchModifiers;
       
    98 static Vector<WebTouchPoint> touchPoints;
       
    99 
       
   100 // Time and place of the last mouse up event.
       
   101 static double lastClickTimeSec = 0;
       
   102 static WebPoint lastClickPos;
       
   103 static int clickCount = 0;
       
   104 
       
   105 // maximum distance (in space and time) for a mouse click
       
   106 // to register as a double or triple click
       
   107 static const double multipleClickTimeSec = 1;
       
   108 static const int multipleClickRadiusPixels = 5;
       
   109 
       
   110 // How much we should scroll per event - the value here is chosen to
       
   111 // match the WebKit impl and layout test results.
       
   112 static const float scrollbarPixelsPerTick = 40.0f;
       
   113 
       
   114 inline bool outsideMultiClickRadius(const WebPoint& a, const WebPoint& b)
       
   115 {
       
   116     return ((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)) >
       
   117         multipleClickRadiusPixels * multipleClickRadiusPixels;
       
   118 }
       
   119 
       
   120 // Used to offset the time the event hander things an event happened.  This is
       
   121 // done so tests can run without a delay, but bypass checks that are time
       
   122 // dependent (e.g., dragging has a timeout vs selection).
       
   123 static uint32 timeOffsetMs = 0;
       
   124 
       
   125 static double getCurrentEventTimeSec()
       
   126 {
       
   127     return (TimeTicks::Now().ToInternalValue() / Time::kMicrosecondsPerMillisecond + timeOffsetMs) / 1000.0;
       
   128 }
       
   129 
       
   130 static void advanceEventTime(int32_t deltaMs)
       
   131 {
       
   132     timeOffsetMs += deltaMs;
       
   133 }
       
   134 
       
   135 static void initMouseEvent(WebInputEvent::Type t, WebMouseEvent::Button b,
       
   136                            const gfx::Point& pos, WebMouseEvent* e)
       
   137 {
       
   138     e->type = t;
       
   139     e->button = b;
       
   140     e->modifiers = 0;
       
   141     e->x = pos.x();
       
   142     e->y = pos.y();
       
   143     e->globalX = pos.x();
       
   144     e->globalY = pos.y();
       
   145     e->timeStampSeconds = getCurrentEventTimeSec();
       
   146     e->clickCount = clickCount;
       
   147 }
       
   148 
       
   149 // Returns true if the specified key is the system key.
       
   150 static bool applyKeyModifier(const string& modifierName, WebInputEvent* event)
       
   151 {
       
   152     bool isSystemKey = false;
       
   153     const char* characters = modifierName.c_str();
       
   154     if (!strcmp(characters, "ctrlKey")
       
   155 #if !OS(MAC_OS_X)
       
   156         || !strcmp(characters, "addSelectionKey")
       
   157 #endif
       
   158         ) {
       
   159         event->modifiers |= WebInputEvent::ControlKey;
       
   160     } else if (!strcmp(characters, "shiftKey") || !strcmp(characters, "rangeSelectionKey"))
       
   161         event->modifiers |= WebInputEvent::ShiftKey;
       
   162     else if (!strcmp(characters, "altKey")) {
       
   163         event->modifiers |= WebInputEvent::AltKey;
       
   164 #if !OS(MAC_OS_X)
       
   165         // On Windows all keys with Alt modifier will be marked as system key.
       
   166         // We keep the same behavior on Linux and everywhere non-Mac, see:
       
   167         // WebKit/chromium/src/gtk/WebInputEventFactory.cpp
       
   168         // If we want to change this behavior on Linux, this piece of code must be
       
   169         // kept in sync with the related code in above file.
       
   170         isSystemKey = true;
       
   171 #endif
       
   172 #if OS(MAC_OS_X)
       
   173     } else if (!strcmp(characters, "metaKey") || !strcmp(characters, "addSelectionKey")) {
       
   174         event->modifiers |= WebInputEvent::MetaKey;
       
   175         // On Mac only command key presses are marked as system key.
       
   176         // See the related code in: WebKit/chromium/src/mac/WebInputEventFactory.cpp
       
   177         // It must be kept in sync with the related code in above file.
       
   178         isSystemKey = true;
       
   179 #else
       
   180     } else if (!strcmp(characters, "metaKey")) {
       
   181         event->modifiers |= WebInputEvent::MetaKey;
       
   182 #endif
       
   183     }
       
   184     return isSystemKey;
       
   185 }
       
   186 
       
   187 static bool applyKeyModifiers(const CppVariant* argument, WebInputEvent* event)
       
   188 {
       
   189     bool isSystemKey = false;
       
   190     if (argument->isObject()) {
       
   191         Vector<string> modifiers = argument->toStringVector();
       
   192         for (Vector<string>::const_iterator i = modifiers.begin(); i != modifiers.end(); ++i)
       
   193             isSystemKey |= applyKeyModifier(*i, event);
       
   194     } else if (argument->isString())
       
   195         isSystemKey = applyKeyModifier(argument->toString(), event);
       
   196     return isSystemKey;
       
   197 }
       
   198 
       
   199 // Get the edit command corresponding to a keyboard event.
       
   200 // Returns true if the specified event corresponds to an edit command, the name
       
   201 // of the edit command will be stored in |*name|.
       
   202 bool getEditCommand(const WebKeyboardEvent& event, string* name)
       
   203 {
       
   204 #if OS(MAC_OS_X)
       
   205     // We only cares about Left,Right,Up,Down keys with Command or Command+Shift
       
   206     // modifiers. These key events correspond to some special movement and
       
   207     // selection editor commands, and was supposed to be handled in
       
   208     // WebKit/chromium/src/EditorClientImpl.cpp. But these keys will be marked
       
   209     // as system key, which prevents them from being handled. Thus they must be
       
   210     // handled specially.
       
   211     if ((event.modifiers & ~WebKeyboardEvent::ShiftKey) != WebKeyboardEvent::MetaKey)
       
   212         return false;
       
   213 
       
   214     switch (event.windowsKeyCode) {
       
   215     case base::VKEY_LEFT:
       
   216         *name = "MoveToBeginningOfLine";
       
   217         break;
       
   218     case base::VKEY_RIGHT:
       
   219         *name = "MoveToEndOfLine";
       
   220         break;
       
   221     case base::VKEY_UP:
       
   222         *name = "MoveToBeginningOfDocument";
       
   223         break;
       
   224     case base::VKEY_DOWN:
       
   225         *name = "MoveToEndOfDocument";
       
   226         break;
       
   227     default:
       
   228         return false;
       
   229     }
       
   230 
       
   231     if (event.modifiers & WebKeyboardEvent::ShiftKey)
       
   232         name->append("AndModifySelection");
       
   233 
       
   234     return true;
       
   235 #else
       
   236     return false;
       
   237 #endif
       
   238 }
       
   239 
       
   240 // Key event location code introduced in DOM Level 3.
       
   241 // See also: http://www.w3.org/TR/DOM-Level-3-Events/#events-keyboardevents
       
   242 enum KeyLocationCode {
       
   243     DOMKeyLocationStandard      = 0x00,
       
   244     DOMKeyLocationLeft          = 0x01,
       
   245     DOMKeyLocationRight         = 0x02,
       
   246     DOMKeyLocationNumpad        = 0x03
       
   247 };
       
   248 
       
   249 EventSender::EventSender(TestShell* shell)
       
   250     : m_methodFactory(this)
       
   251     , m_shell(shell)
       
   252 {
       
   253     // Initialize the map that associates methods of this class with the names
       
   254     // they will use when called by JavaScript.  The actual binding of those
       
   255     // names to their methods will be done by calling bindToJavaScript() (defined
       
   256     // by CppBoundClass, the parent to EventSender).
       
   257     bindMethod("mouseDown", &EventSender::mouseDown);
       
   258     bindMethod("mouseUp", &EventSender::mouseUp);
       
   259     bindMethod("contextClick", &EventSender::contextClick);
       
   260     bindMethod("mouseMoveTo", &EventSender::mouseMoveTo);
       
   261     bindMethod("mouseWheelTo", &EventSender::mouseWheelTo);
       
   262     bindMethod("leapForward", &EventSender::leapForward);
       
   263     bindMethod("keyDown", &EventSender::keyDown);
       
   264     bindMethod("dispatchMessage", &EventSender::dispatchMessage);
       
   265     bindMethod("enableDOMUIEventLogging", &EventSender::enableDOMUIEventLogging);
       
   266     bindMethod("fireKeyboardEventsToElement", &EventSender::fireKeyboardEventsToElement);
       
   267     bindMethod("clearKillRing", &EventSender::clearKillRing);
       
   268     bindMethod("textZoomIn", &EventSender::textZoomIn);
       
   269     bindMethod("textZoomOut", &EventSender::textZoomOut);
       
   270     bindMethod("zoomPageIn", &EventSender::zoomPageIn);
       
   271     bindMethod("zoomPageOut", &EventSender::zoomPageOut);
       
   272     bindMethod("scheduleAsynchronousClick", &EventSender::scheduleAsynchronousClick);
       
   273     bindMethod("beginDragWithFiles", &EventSender::beginDragWithFiles);
       
   274     bindMethod("addTouchPoint", &EventSender::addTouchPoint);
       
   275     bindMethod("cancelTouchPoint", &EventSender::cancelTouchPoint);
       
   276     bindMethod("clearTouchPoints", &EventSender::clearTouchPoints);
       
   277     bindMethod("releaseTouchPoint", &EventSender::releaseTouchPoint);
       
   278     bindMethod("updateTouchPoint", &EventSender::updateTouchPoint);
       
   279     bindMethod("setTouchModifier", &EventSender::setTouchModifier);
       
   280     bindMethod("touchCancel", &EventSender::touchCancel);
       
   281     bindMethod("touchEnd", &EventSender::touchEnd);
       
   282     bindMethod("touchMove", &EventSender::touchMove);
       
   283     bindMethod("touchStart", &EventSender::touchStart);
       
   284 
       
   285     // When set to true (the default value), we batch mouse move and mouse up
       
   286     // events so we can simulate drag & drop.
       
   287     bindProperty("dragMode", &dragMode);
       
   288 #if OS(WINDOWS)
       
   289     bindProperty("WM_KEYDOWN", &wmKeyDown);
       
   290     bindProperty("WM_KEYUP", &wmKeyUp);
       
   291     bindProperty("WM_CHAR", &wmChar);
       
   292     bindProperty("WM_DEADCHAR", &wmDeadChar);
       
   293     bindProperty("WM_SYSKEYDOWN", &wmSysKeyDown);
       
   294     bindProperty("WM_SYSKEYUP", &wmSysKeyUp);
       
   295     bindProperty("WM_SYSCHAR", &wmSysChar);
       
   296     bindProperty("WM_SYSDEADCHAR", &wmSysDeadChar);
       
   297 #endif
       
   298 }
       
   299 
       
   300 void EventSender::reset()
       
   301 {
       
   302     // The test should have finished a drag and the mouse button state.
       
   303     ASSERT(currentDragData.isNull());
       
   304     currentDragData.reset();
       
   305     currentDragEffect = WebKit::WebDragOperationNone;
       
   306     currentDragEffectsAllowed = WebKit::WebDragOperationNone;
       
   307     pressedButton = WebMouseEvent::ButtonNone;
       
   308     dragMode.set(true);
       
   309 #if OS(WINDOWS)
       
   310     wmKeyDown.set(WM_KEYDOWN);
       
   311     wmKeyUp.set(WM_KEYUP);
       
   312     wmChar.set(WM_CHAR);
       
   313     wmDeadChar.set(WM_DEADCHAR);
       
   314     wmSysKeyDown.set(WM_SYSKEYDOWN);
       
   315     wmSysKeyUp.set(WM_SYSKEYUP);
       
   316     wmSysChar.set(WM_SYSCHAR);
       
   317     wmSysDeadChar.set(WM_SYSDEADCHAR);
       
   318 #endif
       
   319     lastMousePos = WebPoint(0, 0);
       
   320     lastClickTimeSec = 0;
       
   321     lastClickPos = WebPoint(0, 0);
       
   322     clickCount = 0;
       
   323     lastButtonType = WebMouseEvent::ButtonNone;
       
   324     timeOffsetMs = 0;
       
   325     touchModifiers = 0;
       
   326     touchPoints.clear();
       
   327 }
       
   328 
       
   329 WebView* EventSender::webview()
       
   330 {
       
   331     return m_shell->webView();
       
   332 }
       
   333 
       
   334 void EventSender::doDragDrop(const WebDragData& dragData, WebDragOperationsMask mask)
       
   335 {
       
   336     WebMouseEvent event;
       
   337     initMouseEvent(WebInputEvent::MouseDown, pressedButton, lastMousePos, &event);
       
   338     WebPoint clientPoint(event.x, event.y);
       
   339     WebPoint screenPoint(event.globalX, event.globalY);
       
   340     currentDragData = dragData;
       
   341     currentDragEffectsAllowed = mask;
       
   342     currentDragEffect = webview()->dragTargetDragEnter(dragData, 0, clientPoint, screenPoint, currentDragEffectsAllowed);
       
   343 
       
   344     // Finish processing events.
       
   345     replaySavedEvents();
       
   346 }
       
   347 
       
   348 WebMouseEvent::Button EventSender::getButtonTypeFromButtonNumber(int buttonCode)
       
   349 {
       
   350     if (!buttonCode)
       
   351         return WebMouseEvent::ButtonLeft;
       
   352     if (buttonCode == 2)
       
   353         return WebMouseEvent::ButtonRight;
       
   354     return WebMouseEvent::ButtonMiddle;
       
   355 }
       
   356 
       
   357 int EventSender::getButtonNumberFromSingleArg(const CppArgumentList& arguments)
       
   358 {
       
   359     int buttonCode = 0;
       
   360     if (arguments.size() > 0 && arguments[0].isNumber())
       
   361         buttonCode = arguments[0].toInt32();
       
   362     return buttonCode;
       
   363 }
       
   364 
       
   365 void EventSender::updateClickCountForButton(WebMouseEvent::Button buttonType)
       
   366 {
       
   367     if ((getCurrentEventTimeSec() - lastClickTimeSec < multipleClickTimeSec)
       
   368         && (!outsideMultiClickRadius(lastMousePos, lastClickPos))
       
   369         && (buttonType == lastButtonType))
       
   370         ++clickCount;
       
   371     else {
       
   372         clickCount = 1;
       
   373         lastButtonType = buttonType;
       
   374     }
       
   375 }
       
   376 
       
   377 //
       
   378 // Implemented javascript methods.
       
   379 //
       
   380 
       
   381 void EventSender::mouseDown(const CppArgumentList& arguments, CppVariant* result)
       
   382 {
       
   383     if (result) // Could be 0 if invoked asynchronously.
       
   384         result->setNull();
       
   385 
       
   386     webview()->layout();
       
   387 
       
   388     int buttonNumber = getButtonNumberFromSingleArg(arguments);
       
   389     ASSERT(buttonNumber != -1);
       
   390 
       
   391     WebMouseEvent::Button buttonType = getButtonTypeFromButtonNumber(buttonNumber);
       
   392 
       
   393     updateClickCountForButton(buttonType);
       
   394 
       
   395     WebMouseEvent event;
       
   396     pressedButton = buttonType;
       
   397     initMouseEvent(WebInputEvent::MouseDown, buttonType, lastMousePos, &event);
       
   398     if (arguments.size() >= 2 && (arguments[1].isObject() || arguments[1].isString()))
       
   399         applyKeyModifiers(&(arguments[1]), &event);
       
   400     webview()->handleInputEvent(event);
       
   401 }
       
   402 
       
   403 void EventSender::mouseUp(const CppArgumentList& arguments, CppVariant* result)
       
   404 {
       
   405     if (result) // Could be 0 if invoked asynchronously.
       
   406         result->setNull();
       
   407 
       
   408     webview()->layout();
       
   409 
       
   410     int buttonNumber = getButtonNumberFromSingleArg(arguments);
       
   411     ASSERT(buttonNumber != -1);
       
   412 
       
   413     WebMouseEvent::Button buttonType = getButtonTypeFromButtonNumber(buttonNumber);
       
   414 
       
   415     if (isDragMode() && !replayingSavedEvents) {
       
   416         SavedEvent savedEvent;
       
   417         savedEvent.type = SavedEvent::MouseUp;
       
   418         savedEvent.buttonType = buttonType;
       
   419         mouseEventQueue.append(savedEvent);
       
   420         replaySavedEvents();
       
   421     } else {
       
   422         WebMouseEvent event;
       
   423         initMouseEvent(WebInputEvent::MouseUp, buttonType, lastMousePos, &event);
       
   424         if (arguments.size() >= 2 && (arguments[1].isObject() || arguments[1].isString()))
       
   425             applyKeyModifiers(&(arguments[1]), &event);
       
   426         doMouseUp(event);
       
   427     }
       
   428 }
       
   429 
       
   430 void EventSender::doMouseUp(const WebMouseEvent& e)
       
   431 {
       
   432     webview()->handleInputEvent(e);
       
   433 
       
   434     pressedButton = WebMouseEvent::ButtonNone;
       
   435     lastClickTimeSec = e.timeStampSeconds;
       
   436     lastClickPos = lastMousePos;
       
   437 
       
   438     // If we're in a drag operation, complete it.
       
   439     if (currentDragData.isNull())
       
   440         return;
       
   441     WebPoint clientPoint(e.x, e.y);
       
   442     WebPoint screenPoint(e.globalX, e.globalY);
       
   443 
       
   444     currentDragEffect = webview()->dragTargetDragOver(clientPoint, screenPoint, currentDragEffectsAllowed);
       
   445     if (currentDragEffect)
       
   446         webview()->dragTargetDrop(clientPoint, screenPoint);
       
   447     else
       
   448         webview()->dragTargetDragLeave();
       
   449     webview()->dragSourceEndedAt(clientPoint, screenPoint, currentDragEffect);
       
   450     webview()->dragSourceSystemDragEnded();
       
   451 
       
   452     currentDragData.reset();
       
   453 }
       
   454 
       
   455 void EventSender::mouseMoveTo(const CppArgumentList& arguments, CppVariant* result)
       
   456 {
       
   457     result->setNull();
       
   458 
       
   459     if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isNumber())
       
   460         return;
       
   461     webview()->layout();
       
   462 
       
   463     WebPoint mousePos(arguments[0].toInt32(), arguments[1].toInt32());
       
   464 
       
   465     if (isDragMode() && pressedButton == WebMouseEvent::ButtonLeft && !replayingSavedEvents) {
       
   466         SavedEvent savedEvent;
       
   467         savedEvent.type = SavedEvent::MouseMove;
       
   468         savedEvent.pos = mousePos;
       
   469         mouseEventQueue.append(savedEvent);
       
   470     } else {
       
   471         WebMouseEvent event;
       
   472         initMouseEvent(WebInputEvent::MouseMove, pressedButton, mousePos, &event);
       
   473         doMouseMove(event);
       
   474     }
       
   475 }
       
   476 
       
   477 void EventSender::mouseWheelTo(const CppArgumentList& arguments, CppVariant* result)
       
   478 {
       
   479     result->setNull();
       
   480 
       
   481     if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isNumber())
       
   482         return;
       
   483 
       
   484     // Force a layout here just to make sure every position has been
       
   485     // determined before we send events (as well as all the other methods
       
   486     // that send an event do). The layout test calling this
       
   487     // (scrollbars/overflow-scrollbar-horizontal-wheel-scroll.html, only one
       
   488     // for now) does not rely on this though.
       
   489     webview()->layout();
       
   490 
       
   491     int horizontal = arguments[0].toInt32();
       
   492     int vertical = arguments[1].toInt32();
       
   493 
       
   494     WebMouseWheelEvent event;
       
   495     initMouseEvent(WebInputEvent::MouseWheel, pressedButton, lastMousePos, &event);
       
   496     event.wheelTicksX = static_cast<float>(horizontal);
       
   497     event.wheelTicksY = static_cast<float>(vertical);
       
   498     event.deltaX = -horizontal * scrollbarPixelsPerTick;
       
   499     event.deltaY = -vertical * scrollbarPixelsPerTick;
       
   500     webview()->handleInputEvent(event);
       
   501 }
       
   502 
       
   503 void EventSender::doMouseMove(const WebMouseEvent& e)
       
   504 {
       
   505     lastMousePos = WebPoint(e.x, e.y);
       
   506 
       
   507     webview()->handleInputEvent(e);
       
   508 
       
   509     if (pressedButton == WebMouseEvent::ButtonNone || currentDragData.isNull())
       
   510         return;
       
   511     WebPoint clientPoint(e.x, e.y);
       
   512     WebPoint screenPoint(e.globalX, e.globalY);
       
   513     currentDragEffect = webview()->dragTargetDragOver(clientPoint, screenPoint, currentDragEffectsAllowed);
       
   514 }
       
   515 
       
   516 void EventSender::keyDown(const CppArgumentList& arguments, CppVariant* result)
       
   517 {
       
   518     result->setNull();
       
   519     if (arguments.size() < 1 || !arguments[0].isString())
       
   520         return;
       
   521     bool generateChar = false;
       
   522 
       
   523     // FIXME: I'm not exactly sure how we should convert the string to a key
       
   524     // event. This seems to work in the cases I tested.
       
   525     // FIXME: Should we also generate a KEY_UP?
       
   526     string codeStr = arguments[0].toString();
       
   527 
       
   528     // Convert \n -> VK_RETURN.  Some layout tests use \n to mean "Enter", when
       
   529     // Windows uses \r for "Enter".
       
   530     int code = 0;
       
   531     int text = 0;
       
   532     bool needsShiftKeyModifier = false;
       
   533     if ("\n" == codeStr) {
       
   534         generateChar = true;
       
   535         text = code = base::VKEY_RETURN;
       
   536     } else if ("rightArrow" == codeStr)
       
   537         code = base::VKEY_RIGHT;
       
   538     else if ("downArrow" == codeStr)
       
   539         code = base::VKEY_DOWN;
       
   540     else if ("leftArrow" == codeStr)
       
   541         code = base::VKEY_LEFT;
       
   542     else if ("upArrow" == codeStr)
       
   543         code = base::VKEY_UP;
       
   544     else if ("delete" == codeStr)
       
   545         code = base::VKEY_DELETE;
       
   546     else if ("pageUp" == codeStr)
       
   547         code = base::VKEY_PRIOR;
       
   548     else if ("pageDown" == codeStr)
       
   549         code = base::VKEY_NEXT;
       
   550     else if ("home" == codeStr)
       
   551         code = base::VKEY_HOME;
       
   552     else if ("end" == codeStr)
       
   553         code = base::VKEY_END;
       
   554     else {
       
   555         // Compare the input string with the function-key names defined by the
       
   556         // DOM spec (i.e. "F1",...,"F24"). If the input string is a function-key
       
   557         // name, set its key code.
       
   558         for (int i = 1; i <= 24; ++i) {
       
   559             char functionChars[10];
       
   560             snprintf(functionChars, 10, "F%d", i);
       
   561             string functionKeyName(functionChars);
       
   562             if (functionKeyName == codeStr) {
       
   563                 code = base::VKEY_F1 + (i - 1);
       
   564                 break;
       
   565             }
       
   566         }
       
   567         if (!code) {
       
   568             WebString webCodeStr = WebString::fromUTF8(codeStr.data(), codeStr.size());
       
   569             ASSERT(webCodeStr.length() == 1);
       
   570             text = code = webCodeStr.data()[0];
       
   571             needsShiftKeyModifier = needsShiftModifier(code);
       
   572             if ((code & 0xFF) >= 'a' && (code & 0xFF) <= 'z')
       
   573                 code -= 'a' - 'A';
       
   574             generateChar = true;
       
   575         }
       
   576     }
       
   577 
       
   578     // For one generated keyboard event, we need to generate a keyDown/keyUp
       
   579     // pair; refer to EventSender.cpp in WebKit/WebKitTools/DumpRenderTree/win.
       
   580     // On Windows, we might also need to generate a char event to mimic the
       
   581     // Windows event flow; on other platforms we create a merged event and test
       
   582     // the event flow that that platform provides.
       
   583     WebKeyboardEvent eventDown, eventChar, eventUp;
       
   584     eventDown.type = WebInputEvent::RawKeyDown;
       
   585     eventDown.modifiers = 0;
       
   586     eventDown.windowsKeyCode = code;
       
   587     if (generateChar) {
       
   588         eventDown.text[0] = text;
       
   589         eventDown.unmodifiedText[0] = text;
       
   590     }
       
   591     eventDown.setKeyIdentifierFromWindowsKeyCode();
       
   592 
       
   593     if (arguments.size() >= 2 && (arguments[1].isObject() || arguments[1].isString()))
       
   594         eventDown.isSystemKey = applyKeyModifiers(&(arguments[1]), &eventDown);
       
   595 
       
   596     if (needsShiftKeyModifier)
       
   597         eventDown.modifiers |= WebInputEvent::ShiftKey;
       
   598 
       
   599     // See if KeyLocation argument is given.
       
   600     if (arguments.size() >= 3 && arguments[2].isNumber()) {
       
   601         int location = arguments[2].toInt32();
       
   602         if (location == DOMKeyLocationNumpad)
       
   603             eventDown.modifiers |= WebInputEvent::IsKeyPad;
       
   604     }
       
   605 
       
   606     eventChar = eventUp = eventDown;
       
   607     eventUp.type = WebInputEvent::KeyUp;
       
   608     // EventSender.m forces a layout here, with at least one
       
   609     // test (fast/forms/focus-control-to-page.html) relying on this.
       
   610     webview()->layout();
       
   611 
       
   612     // In the browser, if a keyboard event corresponds to an editor command,
       
   613     // the command will be dispatched to the renderer just before dispatching
       
   614     // the keyboard event, and then it will be executed in the
       
   615     // RenderView::handleCurrentKeyboardEvent() method, which is called from
       
   616     // third_party/WebKit/WebKit/chromium/src/EditorClientImpl.cpp.
       
   617     // We just simulate the same behavior here.
       
   618     string editCommand;
       
   619     if (getEditCommand(eventDown, &editCommand))
       
   620         m_shell->webViewHost()->setEditCommand(editCommand, "");
       
   621 
       
   622     webview()->handleInputEvent(eventDown);
       
   623 
       
   624     m_shell->webViewHost()->clearEditCommand();
       
   625 
       
   626     if (generateChar) {
       
   627         eventChar.type = WebInputEvent::Char;
       
   628         eventChar.keyIdentifier[0] = '\0';
       
   629         webview()->handleInputEvent(eventChar);
       
   630     }
       
   631 
       
   632     webview()->handleInputEvent(eventUp);
       
   633 }
       
   634 
       
   635 void EventSender::dispatchMessage(const CppArgumentList& arguments, CppVariant* result)
       
   636 {
       
   637     result->setNull();
       
   638 
       
   639 #if OS(WINDOWS)
       
   640     if (arguments.size() == 3) {
       
   641         // Grab the message id to see if we need to dispatch it.
       
   642         int msg = arguments[0].toInt32();
       
   643 
       
   644         // WebKit's version of this function stuffs a MSG struct and uses
       
   645         // TranslateMessage and DispatchMessage. We use a WebKeyboardEvent, which
       
   646         // doesn't need to receive the DeadChar and SysDeadChar messages.
       
   647         if (msg == WM_DEADCHAR || msg == WM_SYSDEADCHAR)
       
   648             return;
       
   649 
       
   650         webview()->layout();
       
   651 
       
   652         unsigned long lparam = static_cast<unsigned long>(arguments[2].toDouble());
       
   653         webview()->handleInputEvent(WebInputEventFactory::keyboardEvent(0, msg, arguments[1].toInt32(), lparam));
       
   654     } else
       
   655         ASSERT_NOT_REACHED();
       
   656 #endif
       
   657 }
       
   658 
       
   659 bool EventSender::needsShiftModifier(int keyCode)
       
   660 {
       
   661     // If code is an uppercase letter, assign a SHIFT key to
       
   662     // eventDown.modifier, this logic comes from
       
   663     // WebKit/WebKitTools/DumpRenderTree/Win/EventSender.cpp
       
   664     return (keyCode & 0xFF) >= 'A' && (keyCode & 0xFF) <= 'Z';
       
   665 }
       
   666 
       
   667 void EventSender::leapForward(const CppArgumentList& arguments, CppVariant* result)
       
   668 {
       
   669     result->setNull();
       
   670 
       
   671     if (arguments.size() < 1 || !arguments[0].isNumber())
       
   672         return;
       
   673 
       
   674     int milliseconds = arguments[0].toInt32();
       
   675     if (isDragMode() && pressedButton == WebMouseEvent::ButtonLeft && !replayingSavedEvents) {
       
   676         SavedEvent savedEvent;
       
   677         savedEvent.type = SavedEvent::LeapForward;
       
   678         savedEvent.milliseconds = milliseconds;
       
   679         mouseEventQueue.append(savedEvent);
       
   680     } else
       
   681         doLeapForward(milliseconds);
       
   682 }
       
   683 
       
   684 void EventSender::doLeapForward(int milliseconds)
       
   685 {
       
   686     advanceEventTime(milliseconds);
       
   687 }
       
   688 
       
   689 // Apple's port of WebKit zooms by a factor of 1.2 (see
       
   690 // WebKit/WebView/WebView.mm)
       
   691 void EventSender::textZoomIn(const CppArgumentList&, CppVariant* result)
       
   692 {
       
   693     webview()->setZoomLevel(true, webview()->zoomLevel() + 1);
       
   694     result->setNull();
       
   695 }
       
   696 
       
   697 void EventSender::textZoomOut(const CppArgumentList&, CppVariant* result)
       
   698 {
       
   699     webview()->setZoomLevel(true, webview()->zoomLevel() - 1);
       
   700     result->setNull();
       
   701 }
       
   702 
       
   703 void EventSender::zoomPageIn(const CppArgumentList&, CppVariant* result)
       
   704 {
       
   705     webview()->setZoomLevel(false, webview()->zoomLevel() + 1);
       
   706     result->setNull();
       
   707 }
       
   708 
       
   709 void EventSender::zoomPageOut(const CppArgumentList&, CppVariant* result)
       
   710 {
       
   711     webview()->setZoomLevel(false, webview()->zoomLevel() - 1);
       
   712     result->setNull();
       
   713 }
       
   714 
       
   715 void EventSender::replaySavedEvents()
       
   716 {
       
   717     replayingSavedEvents = true;
       
   718     while (!mouseEventQueue.isEmpty()) {
       
   719         SavedEvent e = mouseEventQueue.takeFirst();
       
   720 
       
   721         switch (e.type) {
       
   722         case SavedEvent::MouseMove: {
       
   723             WebMouseEvent event;
       
   724             initMouseEvent(WebInputEvent::MouseMove, pressedButton, e.pos, &event);
       
   725             doMouseMove(event);
       
   726             break;
       
   727         }
       
   728         case SavedEvent::LeapForward:
       
   729             doLeapForward(e.milliseconds);
       
   730             break;
       
   731         case SavedEvent::MouseUp: {
       
   732             WebMouseEvent event;
       
   733             initMouseEvent(WebInputEvent::MouseUp, e.buttonType, lastMousePos, &event);
       
   734             doMouseUp(event);
       
   735             break;
       
   736         }
       
   737         default:
       
   738             ASSERT_NOT_REACHED();
       
   739         }
       
   740     }
       
   741 
       
   742     replayingSavedEvents = false;
       
   743 }
       
   744 
       
   745 void EventSender::contextClick(const CppArgumentList& arguments, CppVariant* result)
       
   746 {
       
   747     result->setNull();
       
   748 
       
   749     webview()->layout();
       
   750 
       
   751     updateClickCountForButton(WebMouseEvent::ButtonRight);
       
   752 
       
   753     // Generate right mouse down and up.
       
   754 
       
   755     WebMouseEvent event;
       
   756     pressedButton = WebMouseEvent::ButtonRight;
       
   757     initMouseEvent(WebInputEvent::MouseDown, WebMouseEvent::ButtonRight, lastMousePos, &event);
       
   758     webview()->handleInputEvent(event);
       
   759 
       
   760     initMouseEvent(WebInputEvent::MouseUp, WebMouseEvent::ButtonRight, lastMousePos, &event);
       
   761     webview()->handleInputEvent(event);
       
   762 
       
   763     pressedButton = WebMouseEvent::ButtonNone;
       
   764 }
       
   765 
       
   766 void EventSender::scheduleAsynchronousClick(const CppArgumentList& arguments, CppVariant* result)
       
   767 {
       
   768     result->setNull();
       
   769 
       
   770     webkit_support::PostTaskFromHere(m_methodFactory.NewRunnableMethod(
       
   771             &EventSender::mouseDown, arguments, static_cast<CppVariant*>(0)));
       
   772     webkit_support::PostTaskFromHere(m_methodFactory.NewRunnableMethod(
       
   773             &EventSender::mouseUp, arguments, static_cast<CppVariant*>(0)));
       
   774 }
       
   775 
       
   776 void EventSender::beginDragWithFiles(const CppArgumentList& arguments, CppVariant* result)
       
   777 {
       
   778     currentDragData.initialize();
       
   779     Vector<string> files = arguments[0].toStringVector();
       
   780     for (size_t i = 0; i < files.size(); ++i)
       
   781         currentDragData.appendToFileNames(webkit_support::GetAbsoluteWebStringFromUTF8Path(files[i]));
       
   782     currentDragEffectsAllowed = WebKit::WebDragOperationCopy;
       
   783 
       
   784     // Provide a drag source.
       
   785     webview()->dragTargetDragEnter(currentDragData, 0, lastMousePos, lastMousePos, currentDragEffectsAllowed);
       
   786 
       
   787     // dragMode saves events and then replays them later. We don't need/want that.
       
   788     dragMode.set(false);
       
   789 
       
   790     // Make the rest of eventSender think a drag is in progress.
       
   791     pressedButton = WebMouseEvent::ButtonLeft;
       
   792 
       
   793     result->setNull();
       
   794 }
       
   795 
       
   796 void EventSender::addTouchPoint(const CppArgumentList& arguments, CppVariant* result)
       
   797 {
       
   798     result->setNull();
       
   799 
       
   800     WebTouchPoint touchPoint;
       
   801     touchPoint.state = WebTouchPoint::StatePressed;
       
   802     touchPoint.position = WebPoint(arguments[0].toInt32(), arguments[1].toInt32());
       
   803     touchPoint.id = touchPoints.size();
       
   804     touchPoints.append(touchPoint);
       
   805 }
       
   806 
       
   807 void EventSender::clearTouchPoints(const CppArgumentList&, CppVariant* result)
       
   808 {
       
   809     result->setNull();
       
   810     touchPoints.clear();
       
   811 }
       
   812 
       
   813 void EventSender::releaseTouchPoint(const CppArgumentList& arguments, CppVariant* result)
       
   814 {
       
   815     result->setNull();
       
   816 
       
   817     const unsigned index = arguments[0].toInt32();
       
   818     ASSERT(index < touchPoints.size());
       
   819 
       
   820     WebTouchPoint* touchPoint = &touchPoints[index];
       
   821     touchPoint->state = WebTouchPoint::StateReleased;
       
   822 }
       
   823 
       
   824 void EventSender::setTouchModifier(const CppArgumentList& arguments, CppVariant* result)
       
   825 {
       
   826     result->setNull();
       
   827 
       
   828     int mask = 0;
       
   829     const string keyName = arguments[0].toString();
       
   830     if (keyName == "shift")
       
   831         mask = WebInputEvent::ShiftKey;
       
   832     else if (keyName == "alt")
       
   833         mask = WebInputEvent::AltKey;
       
   834     else if (keyName == "ctrl")
       
   835         mask = WebInputEvent::ControlKey;
       
   836     else if (keyName == "meta")
       
   837         mask = WebInputEvent::MetaKey;
       
   838 
       
   839     if (arguments[1].toBoolean())
       
   840         touchModifiers |= mask;
       
   841     else
       
   842         touchModifiers &= ~mask;
       
   843 }
       
   844 
       
   845 void EventSender::updateTouchPoint(const CppArgumentList& arguments, CppVariant* result)
       
   846 {
       
   847     result->setNull();
       
   848 
       
   849     const unsigned index = arguments[0].toInt32();
       
   850     ASSERT(index < touchPoints.size());
       
   851 
       
   852     WebPoint position(arguments[1].toInt32(), arguments[2].toInt32());
       
   853     WebTouchPoint* touchPoint = &touchPoints[index];
       
   854     touchPoint->state = WebTouchPoint::StateMoved;
       
   855     touchPoint->position = position;
       
   856 }
       
   857 
       
   858 void EventSender::cancelTouchPoint(const CppArgumentList& arguments, CppVariant* result)
       
   859 {
       
   860     result->setNull();
       
   861 
       
   862     const unsigned index = arguments[0].toInt32();
       
   863     ASSERT(index < touchPoints.size());
       
   864 
       
   865     WebTouchPoint* touchPoint = &touchPoints[index];
       
   866     touchPoint->state = WebTouchPoint::StateCancelled;
       
   867 }
       
   868 
       
   869 void EventSender::sendCurrentTouchEvent(const WebInputEvent::Type type)
       
   870 {
       
   871     ASSERT(static_cast<unsigned>(WebTouchEvent::touchPointsLengthCap) > touchPoints.size());
       
   872     WebTouchEvent touchEvent;
       
   873     touchEvent.type = type;
       
   874     touchEvent.modifiers = touchModifiers;
       
   875     touchEvent.touchPointsLength = touchPoints.size();
       
   876     for (unsigned i = 0; i < touchPoints.size(); ++i)
       
   877         touchEvent.touchPoints[i] = touchPoints[i];
       
   878     webview()->handleInputEvent(touchEvent);
       
   879 
       
   880     for (unsigned i = 0; i < touchPoints.size(); ++i) {
       
   881         WebTouchPoint* touchPoint = &touchPoints[i];
       
   882         if (touchPoint->state == WebTouchPoint::StateReleased) {
       
   883             touchPoints.remove(i);
       
   884             --i;
       
   885         } else
       
   886             touchPoint->state = WebTouchPoint::StateStationary;
       
   887     }
       
   888 }
       
   889 
       
   890 void EventSender::touchEnd(const CppArgumentList&, CppVariant* result)
       
   891 {
       
   892     result->setNull();
       
   893     sendCurrentTouchEvent(WebInputEvent::TouchEnd);
       
   894 }
       
   895 
       
   896 void EventSender::touchMove(const CppArgumentList&, CppVariant* result)
       
   897 {
       
   898     result->setNull();
       
   899     sendCurrentTouchEvent(WebInputEvent::TouchMove);
       
   900 }
       
   901 
       
   902 void EventSender::touchStart(const CppArgumentList&, CppVariant* result)
       
   903 {
       
   904     result->setNull();
       
   905     sendCurrentTouchEvent(WebInputEvent::TouchStart);
       
   906 }
       
   907 
       
   908 void EventSender::touchCancel(const CppArgumentList&, CppVariant* result)
       
   909 {
       
   910     result->setNull();
       
   911     sendCurrentTouchEvent(WebInputEvent::TouchCancel);
       
   912 }
       
   913 
       
   914 //
       
   915 // Unimplemented stubs
       
   916 //
       
   917 
       
   918 void EventSender::enableDOMUIEventLogging(const CppArgumentList&, CppVariant* result)
       
   919 {
       
   920     result->setNull();
       
   921 }
       
   922 
       
   923 void EventSender::fireKeyboardEventsToElement(const CppArgumentList&, CppVariant* result)
       
   924 {
       
   925     result->setNull();
       
   926 }
       
   927 
       
   928 void EventSender::clearKillRing(const CppArgumentList&, CppVariant* result)
       
   929 {
       
   930     result->setNull();
       
   931 }