diff options
author | tfarina@chromium.org <tfarina@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-03-24 20:23:27 +0000 |
---|---|---|
committer | tfarina@chromium.org <tfarina@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-03-24 20:23:27 +0000 |
commit | a8b7fd108babab7d0fd3eee124cbe1509d04e9cc (patch) | |
tree | fb9fbcef79eb6bb4eb4c6c093f5d4e4c7ae91464 /content/shell | |
parent | 885b6449b7078f0d0b2c4e3ed900f792bf80433e (diff) | |
download | chromium_src-a8b7fd108babab7d0fd3eee124cbe1509d04e9cc.zip chromium_src-a8b7fd108babab7d0fd3eee124cbe1509d04e9cc.tar.gz chromium_src-a8b7fd108babab7d0fd3eee124cbe1509d04e9cc.tar.bz2 |
Move EventSender from CppBoundClass to gin::Wrappable.
BUG=297480, 331301
COLLABORATOR=hajimehoshi@chromium.org
R=jochen@chromium.org
Review URL: https://codereview.chromium.org/166903009
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@259001 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/shell')
-rw-r--r-- | content/shell/renderer/test_runner/EventSender.cpp | 1465 | ||||
-rw-r--r-- | content/shell/renderer/test_runner/EventSender.h | 188 | ||||
-rw-r--r-- | content/shell/renderer/test_runner/TestInterfaces.cpp | 18 | ||||
-rw-r--r-- | content/shell/renderer/test_runner/TestInterfaces.h | 6 | ||||
-rw-r--r-- | content/shell/renderer/test_runner/WebTestProxy.cpp | 6 | ||||
-rw-r--r-- | content/shell/renderer/test_runner/event_sender.cc | 2085 | ||||
-rw-r--r-- | content/shell/renderer/test_runner/event_sender.h | 276 |
7 files changed, 2376 insertions, 1668 deletions
diff --git a/content/shell/renderer/test_runner/EventSender.cpp b/content/shell/renderer/test_runner/EventSender.cpp deleted file mode 100644 index 3106396..0000000 --- a/content/shell/renderer/test_runner/EventSender.cpp +++ /dev/null @@ -1,1465 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file contains the definition for EventSender. -// -// Some notes about drag and drop handling: -// Windows drag and drop goes through a system call to doDragDrop. At that -// point, program control is given to Windows which then periodically makes -// callbacks into the webview. This won't work for layout tests, so instead, -// we queue up all the mouse move and mouse up events. When the test tries to -// start a drag (by calling EvenSendingController::doDragDrop), we take the -// events in the queue and replay them. -// The behavior of queuing events and replaying them can be disabled by a -// layout test by setting eventSender.dragMode to false. - -#include "content/shell/renderer/test_runner/EventSender.h" - -#include <deque> - -#include "content/shell/renderer/test_runner/KeyCodeMapping.h" -#include "content/shell/renderer/test_runner/MockSpellCheck.h" -#include "content/shell/renderer/test_runner/TestCommon.h" -#include "content/shell/renderer/test_runner/TestInterfaces.h" -#include "content/shell/renderer/test_runner/WebTestDelegate.h" -#include "content/shell/renderer/test_runner/WebTestProxy.h" -#include "third_party/WebKit/public/platform/WebDragData.h" -#include "third_party/WebKit/public/platform/WebString.h" -#include "third_party/WebKit/public/platform/WebVector.h" -#include "third_party/WebKit/public/web/WebContextMenuData.h" -#include "third_party/WebKit/public/web/WebTouchPoint.h" -#include "third_party/WebKit/public/web/WebView.h" - -#ifdef WIN32 -#include "third_party/WebKit/public/web/win/WebInputEventFactory.h" -#elif __APPLE__ -#include "third_party/WebKit/public/web/mac/WebInputEventFactory.h" -#elif defined(ANDROID) -#include "third_party/WebKit/public/web/android/WebInputEventFactory.h" -#elif defined(TOOLKIT_GTK) -#include "third_party/WebKit/public/web/gtk/WebInputEventFactory.h" -#endif - -// FIXME: layout before each event? - -using namespace std; -using namespace blink; - -namespace WebTestRunner { - -WebPoint EventSender::lastMousePos; -WebMouseEvent::Button EventSender::pressedButton = WebMouseEvent::ButtonNone; -WebMouseEvent::Button EventSender::lastButtonType = WebMouseEvent::ButtonNone; - -namespace { - -struct SavedEvent { - enum SavedEventType { - Unspecified, - MouseUp, - MouseMove, - LeapForward - }; - - SavedEventType type; - WebMouseEvent::Button buttonType; // For MouseUp. - WebPoint pos; // For MouseMove. - int milliseconds; // For LeapForward. - int modifiers; - - SavedEvent() - : type(Unspecified) - , buttonType(WebMouseEvent::ButtonNone) - , milliseconds(0) - , modifiers(0) { } -}; - -WebDragData currentDragData; -WebDragOperation currentDragEffect; -WebDragOperationsMask currentDragEffectsAllowed; -bool replayingSavedEvents = false; -deque<SavedEvent> mouseEventQueue; -int touchModifiers; -vector<WebTouchPoint> touchPoints; - -// Time and place of the last mouse up event. -double lastClickTimeSec = 0; -WebPoint lastClickPos; -int clickCount = 0; - -// maximum distance (in space and time) for a mouse click -// to register as a double or triple click -const double multipleClickTimeSec = 1; -const int multipleClickRadiusPixels = 5; - -// How much we should scroll per event - the value here is chosen to -// match the WebKit impl and layout test results. -const float scrollbarPixelsPerTick = 40.0f; - -inline bool outsideMultiClickRadius(const WebPoint& a, const WebPoint& b) -{ - return ((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)) > - multipleClickRadiusPixels * multipleClickRadiusPixels; -} - -// Used to offset the time the event hander things an event happened. This is -// done so tests can run without a delay, but bypass checks that are time -// dependent (e.g., dragging has a timeout vs selection). -uint32 timeOffsetMs = 0; - -double getCurrentEventTimeSec(WebTestDelegate* delegate) -{ - return (delegate->getCurrentTimeInMillisecond() + timeOffsetMs) / 1000.0; -} - -void advanceEventTime(int32_t deltaMs) -{ - timeOffsetMs += deltaMs; -} - -void initMouseEvent(WebInputEvent::Type t, WebMouseEvent::Button b, const WebPoint& pos, WebMouseEvent* e, double ts, int modifiers) -{ - e->type = t; - e->button = b; - e->modifiers = modifiers; - e->x = pos.x; - e->y = pos.y; - e->globalX = pos.x; - e->globalY = pos.y; - e->timeStampSeconds = ts; - e->clickCount = clickCount; -} - -int getKeyModifier(const string& modifierName) -{ - const char* characters = modifierName.c_str(); - if (!strcmp(characters, "ctrlKey") -#ifndef __APPLE__ - || !strcmp(characters, "addSelectionKey") -#endif - ) { - return WebInputEvent::ControlKey; - } else if (!strcmp(characters, "shiftKey") || !strcmp(characters, "rangeSelectionKey")) { - return WebInputEvent::ShiftKey; - } else if (!strcmp(characters, "altKey")) { - return WebInputEvent::AltKey; -#ifdef __APPLE__ - } else if (!strcmp(characters, "metaKey") || !strcmp(characters, "addSelectionKey")) { - return WebInputEvent::MetaKey; -#else - } else if (!strcmp(characters, "metaKey")) { - return WebInputEvent::MetaKey; -#endif - } else if (!strcmp(characters, "autoRepeat")) { - return WebInputEvent::IsAutoRepeat; - } else if (!strcmp(characters, "copyKey")) { -#ifdef __APPLE__ - return WebInputEvent::AltKey; -#else - return WebInputEvent::ControlKey; -#endif - } - - return 0; -} - -int getKeyModifiers(const CppVariant* argument) -{ - int modifiers = 0; - if (argument->isObject()) { - vector<string> modifierNames = argument->toStringVector(); - for (vector<string>::const_iterator i = modifierNames.begin(); i != modifierNames.end(); ++i) - modifiers |= getKeyModifier(*i); - } else if (argument->isString()) { - modifiers |= getKeyModifier(argument->toString()); - } - return modifiers; -} - -// Get the edit command corresponding to a keyboard event. -// Returns true if the specified event corresponds to an edit command, the name -// of the edit command will be stored in |*name|. -bool getEditCommand(const WebKeyboardEvent& event, string* name) -{ -#ifdef __APPLE__ - // We only cares about Left,Right,Up,Down keys with Command or Command+Shift - // modifiers. These key events correspond to some special movement and - // selection editor commands, and was supposed to be handled in - // WebKit/chromium/src/EditorClientImpl.cpp. But these keys will be marked - // as system key, which prevents them from being handled. Thus they must be - // handled specially. - if ((event.modifiers & ~WebKeyboardEvent::ShiftKey) != WebKeyboardEvent::MetaKey) - return false; - - switch (event.windowsKeyCode) { - case VKEY_LEFT: - *name = "MoveToBeginningOfLine"; - break; - case VKEY_RIGHT: - *name = "MoveToEndOfLine"; - break; - case VKEY_UP: - *name = "MoveToBeginningOfDocument"; - break; - case VKEY_DOWN: - *name = "MoveToEndOfDocument"; - break; - default: - return false; - } - - if (event.modifiers & WebKeyboardEvent::ShiftKey) - name->append("AndModifySelection"); - - return true; -#else - return false; -#endif -} - -// Key event location code introduced in DOM Level 3. -// See also: http://www.w3.org/TR/DOM-Level-3-Events/#events-keyboardevents -enum KeyLocationCode { - DOMKeyLocationStandard = 0x00, - DOMKeyLocationLeft = 0x01, - DOMKeyLocationRight = 0x02, - DOMKeyLocationNumpad = 0x03 -}; - -} - -EventSender::EventSender(TestInterfaces* interfaces) - : m_testInterfaces(interfaces) - , m_delegate(0) -{ - // Initialize the map that associates methods of this class with the names - // they will use when called by JavaScript. The actual binding of those - // names to their methods will be done by calling bindToJavaScript() (defined - // by CppBoundClass, the parent to EventSender). - bindMethod("addTouchPoint", &EventSender::addTouchPoint); - bindMethod("beginDragWithFiles", &EventSender::beginDragWithFiles); - bindMethod("cancelTouchPoint", &EventSender::cancelTouchPoint); - bindMethod("clearKillRing", &EventSender::clearKillRing); - bindMethod("clearTouchPoints", &EventSender::clearTouchPoints); - bindMethod("contextClick", &EventSender::contextClick); - bindMethod("continuousMouseScrollBy", &EventSender::continuousMouseScrollBy); - bindMethod("dispatchMessage", &EventSender::dispatchMessage); - bindMethod("dumpFilenameBeingDragged", &EventSender::dumpFilenameBeingDragged); - bindMethod("enableDOMUIEventLogging", &EventSender::enableDOMUIEventLogging); - bindMethod("fireKeyboardEventsToElement", &EventSender::fireKeyboardEventsToElement); - bindMethod("keyDown", &EventSender::keyDown); - bindMethod("leapForward", &EventSender::leapForward); - bindMethod("mouseDown", &EventSender::mouseDown); - bindMethod("mouseMoveTo", &EventSender::mouseMoveTo); - bindMethod("mouseScrollBy", &EventSender::mouseScrollBy); - bindMethod("mouseUp", &EventSender::mouseUp); - bindMethod("mouseDragBegin", &EventSender::mouseDragBegin); - bindMethod("mouseDragEnd", &EventSender::mouseDragEnd); - bindMethod("mouseMomentumBegin", &EventSender::mouseMomentumBegin); - bindMethod("mouseMomentumScrollBy", &EventSender::mouseMomentumScrollBy); - bindMethod("mouseMomentumEnd", &EventSender::mouseMomentumEnd); - bindMethod("releaseTouchPoint", &EventSender::releaseTouchPoint); - bindMethod("scheduleAsynchronousClick", &EventSender::scheduleAsynchronousClick); - bindMethod("scheduleAsynchronousKeyDown", &EventSender::scheduleAsynchronousKeyDown); - bindMethod("setTouchModifier", &EventSender::setTouchModifier); - bindMethod("textZoomIn", &EventSender::textZoomIn); - bindMethod("textZoomOut", &EventSender::textZoomOut); - bindMethod("touchCancel", &EventSender::touchCancel); - bindMethod("touchEnd", &EventSender::touchEnd); - bindMethod("touchMove", &EventSender::touchMove); - bindMethod("touchStart", &EventSender::touchStart); - bindMethod("updateTouchPoint", &EventSender::updateTouchPoint); - bindMethod("gestureFlingCancel", &EventSender::gestureFlingCancel); - bindMethod("gestureFlingStart", &EventSender::gestureFlingStart); - bindMethod("gestureScrollBegin", &EventSender::gestureScrollBegin); - bindMethod("gestureScrollEnd", &EventSender::gestureScrollEnd); - bindMethod("gestureScrollFirstPoint", &EventSender::gestureScrollFirstPoint); - bindMethod("gestureScrollUpdate", &EventSender::gestureScrollUpdate); - bindMethod("gestureScrollUpdateWithoutPropagation", &EventSender::gestureScrollUpdateWithoutPropagation); - bindMethod("gestureTap", &EventSender::gestureTap); - bindMethod("gestureTapDown", &EventSender::gestureTapDown); - bindMethod("gestureShowPress", &EventSender::gestureShowPress); - bindMethod("gestureTapCancel", &EventSender::gestureTapCancel); - bindMethod("gestureLongPress", &EventSender::gestureLongPress); - bindMethod("gestureLongTap", &EventSender::gestureLongTap); - bindMethod("gestureTwoFingerTap", &EventSender::gestureTwoFingerTap); - bindMethod("zoomPageIn", &EventSender::zoomPageIn); - bindMethod("zoomPageOut", &EventSender::zoomPageOut); - bindMethod("setPageScaleFactor", &EventSender::setPageScaleFactor); - - bindProperty("forceLayoutOnEvents", &forceLayoutOnEvents); - - // When set to true (the default value), we batch mouse move and mouse up - // events so we can simulate drag & drop. - bindProperty("dragMode", &dragMode); -#ifdef WIN32 - bindProperty("WM_KEYDOWN", &wmKeyDown); - bindProperty("WM_KEYUP", &wmKeyUp); - bindProperty("WM_CHAR", &wmChar); - bindProperty("WM_DEADCHAR", &wmDeadChar); - bindProperty("WM_SYSKEYDOWN", &wmSysKeyDown); - bindProperty("WM_SYSKEYUP", &wmSysKeyUp); - bindProperty("WM_SYSCHAR", &wmSysChar); - bindProperty("WM_SYSDEADCHAR", &wmSysDeadChar); -#endif -} - -EventSender::~EventSender() -{ -} - -void EventSender::setContextMenuData(const WebContextMenuData& contextMenuData) -{ - m_lastContextMenuData = scoped_ptr<WebContextMenuData>(new WebContextMenuData(contextMenuData)); -} - -void EventSender::reset() -{ - // The test should have finished a drag and the mouse button state. - BLINK_ASSERT(currentDragData.isNull()); - currentDragData.reset(); - currentDragEffect = blink::WebDragOperationNone; - currentDragEffectsAllowed = blink::WebDragOperationNone; - if (webview() && pressedButton != WebMouseEvent::ButtonNone) - webview()->mouseCaptureLost(); - pressedButton = WebMouseEvent::ButtonNone; - dragMode.set(true); - forceLayoutOnEvents.set(true); -#ifdef WIN32 - wmKeyDown.set(WM_KEYDOWN); - wmKeyUp.set(WM_KEYUP); - wmChar.set(WM_CHAR); - wmDeadChar.set(WM_DEADCHAR); - wmSysKeyDown.set(WM_SYSKEYDOWN); - wmSysKeyUp.set(WM_SYSKEYUP); - wmSysChar.set(WM_SYSCHAR); - wmSysDeadChar.set(WM_SYSDEADCHAR); -#endif - lastMousePos = WebPoint(0, 0); - lastClickTimeSec = 0; - lastClickPos = WebPoint(0, 0); - clickCount = 0; - lastButtonType = WebMouseEvent::ButtonNone; - timeOffsetMs = 0; - touchModifiers = 0; - touchPoints.clear(); - m_taskList.revokeAll(); - m_currentGestureLocation = WebPoint(0, 0); - mouseEventQueue.clear(); -} - -void EventSender::doDragDrop(const WebDragData& dragData, WebDragOperationsMask mask) -{ - WebMouseEvent event; - initMouseEvent(WebInputEvent::MouseDown, pressedButton, lastMousePos, &event, getCurrentEventTimeSec(m_delegate), 0); - WebPoint clientPoint(event.x, event.y); - WebPoint screenPoint(event.globalX, event.globalY); - currentDragData = dragData; - currentDragEffectsAllowed = mask; - currentDragEffect = webview()->dragTargetDragEnter(dragData, clientPoint, screenPoint, currentDragEffectsAllowed, 0); - - // Finish processing events. - replaySavedEvents(); -} - -void EventSender::dumpFilenameBeingDragged(const CppArgumentList&, CppVariant*) -{ - WebString filename; - WebVector<WebDragData::Item> items = currentDragData.items(); - for (size_t i = 0; i < items.size(); ++i) { - if (items[i].storageType == WebDragData::Item::StorageTypeBinaryData) { - filename = items[i].title; - break; - } - } - m_delegate->printMessage(std::string("Filename being dragged: ") + filename.utf8().data() + "\n"); -} - -WebMouseEvent::Button EventSender::getButtonTypeFromButtonNumber(int buttonCode) -{ - if (!buttonCode) - return WebMouseEvent::ButtonLeft; - if (buttonCode == 2) - return WebMouseEvent::ButtonRight; - return WebMouseEvent::ButtonMiddle; -} - -int EventSender::getButtonNumberFromSingleArg(const CppArgumentList& arguments) -{ - int buttonCode = 0; - if (arguments.size() > 0 && arguments[0].isNumber()) - buttonCode = arguments[0].toInt32(); - return buttonCode; -} - -void EventSender::updateClickCountForButton(WebMouseEvent::Button buttonType) -{ - if ((getCurrentEventTimeSec(m_delegate) - lastClickTimeSec < multipleClickTimeSec) - && (!outsideMultiClickRadius(lastMousePos, lastClickPos)) - && (buttonType == lastButtonType)) - ++clickCount; - else { - clickCount = 1; - lastButtonType = buttonType; - } -} - -// -// Implemented javascript methods. -// - -void EventSender::mouseDown(const CppArgumentList& arguments, CppVariant* result) -{ - if (result) // Could be 0 if invoked asynchronously. - result->setNull(); - - if (shouldForceLayoutOnEvents()) - webview()->layout(); - - int buttonNumber = getButtonNumberFromSingleArg(arguments); - BLINK_ASSERT(buttonNumber != -1); - - WebMouseEvent::Button buttonType = getButtonTypeFromButtonNumber(buttonNumber); - - updateClickCountForButton(buttonType); - - WebMouseEvent event; - pressedButton = buttonType; - int modifiers = 0; - if (arguments.size() >= 2 && (arguments[1].isObject() || arguments[1].isString())) - modifiers = getKeyModifiers(&(arguments[1])); - initMouseEvent(WebInputEvent::MouseDown, buttonType, lastMousePos, &event, getCurrentEventTimeSec(m_delegate), modifiers); - webview()->handleInputEvent(event); -} - -void EventSender::mouseUp(const CppArgumentList& arguments, CppVariant* result) -{ - if (result) // Could be 0 if invoked asynchronously. - result->setNull(); - - if (shouldForceLayoutOnEvents()) - webview()->layout(); - - int buttonNumber = getButtonNumberFromSingleArg(arguments); - BLINK_ASSERT(buttonNumber != -1); - - WebMouseEvent::Button buttonType = getButtonTypeFromButtonNumber(buttonNumber); - - int modifiers = 0; - if (arguments.size() >= 2 && (arguments[1].isObject() || arguments[1].isString())) - modifiers = getKeyModifiers(&(arguments[1])); - - if (isDragMode() && !replayingSavedEvents) { - SavedEvent savedEvent; - savedEvent.type = SavedEvent::MouseUp; - savedEvent.buttonType = buttonType; - savedEvent.modifiers = modifiers; - mouseEventQueue.push_back(savedEvent); - replaySavedEvents(); - } else { - WebMouseEvent event; - initMouseEvent(WebInputEvent::MouseUp, buttonType, lastMousePos, &event, getCurrentEventTimeSec(m_delegate), modifiers); - doMouseUp(event); - } -} - -void EventSender::doMouseUp(const WebMouseEvent& e) -{ - webview()->handleInputEvent(e); - - pressedButton = WebMouseEvent::ButtonNone; - lastClickTimeSec = e.timeStampSeconds; - lastClickPos = lastMousePos; - - // If we're in a drag operation, complete it. - if (currentDragData.isNull()) - return; - - WebPoint clientPoint(e.x, e.y); - WebPoint screenPoint(e.globalX, e.globalY); - finishDragAndDrop(e, webview()->dragTargetDragOver(clientPoint, screenPoint, currentDragEffectsAllowed, 0)); -} - -void EventSender::finishDragAndDrop(const WebMouseEvent& e, blink::WebDragOperation dragEffect) -{ - WebPoint clientPoint(e.x, e.y); - WebPoint screenPoint(e.globalX, e.globalY); - currentDragEffect = dragEffect; - if (currentDragEffect) { - // Specifically pass any keyboard modifiers to the drop - // method. This allows tests to control the drop type - // (i.e. copy or move). - webview()->dragTargetDrop(clientPoint, screenPoint, e.modifiers); - } else { - webview()->dragTargetDragLeave(); - } - webview()->dragSourceEndedAt(clientPoint, screenPoint, currentDragEffect); - webview()->dragSourceSystemDragEnded(); - - currentDragData.reset(); -} - -void EventSender::mouseMoveTo(const CppArgumentList& arguments, CppVariant* result) -{ - result->setNull(); - - if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isNumber()) - return; - if (shouldForceLayoutOnEvents()) - webview()->layout(); - - WebPoint mousePos(arguments[0].toInt32(), arguments[1].toInt32()); - - int modifiers = 0; - if (arguments.size() >= 3 && (arguments[2].isObject() || arguments[2].isString())) - modifiers = getKeyModifiers(&(arguments[2])); - - if (isDragMode() && pressedButton == WebMouseEvent::ButtonLeft && !replayingSavedEvents) { - SavedEvent savedEvent; - savedEvent.type = SavedEvent::MouseMove; - savedEvent.pos = mousePos; - savedEvent.modifiers = modifiers; - mouseEventQueue.push_back(savedEvent); - } else { - WebMouseEvent event; - initMouseEvent(WebInputEvent::MouseMove, pressedButton, mousePos, &event, getCurrentEventTimeSec(m_delegate), modifiers); - doMouseMove(event); - } -} - -void EventSender::doMouseMove(const WebMouseEvent& e) -{ - lastMousePos = WebPoint(e.x, e.y); - - webview()->handleInputEvent(e); - - if (pressedButton == WebMouseEvent::ButtonNone || currentDragData.isNull()) - return; - WebPoint clientPoint(e.x, e.y); - WebPoint screenPoint(e.globalX, e.globalY); - currentDragEffect = webview()->dragTargetDragOver(clientPoint, screenPoint, currentDragEffectsAllowed, 0); -} - -void EventSender::keyDown(const CppArgumentList& arguments, CppVariant* result) -{ - if (result) - result->setNull(); - if (arguments.size() < 1 || !arguments[0].isString()) - return; - bool generateChar = false; - - // FIXME: I'm not exactly sure how we should convert the string to a key - // event. This seems to work in the cases I tested. - // FIXME: Should we also generate a KEY_UP? - string codeStr = arguments[0].toString(); - - // Convert \n -> VK_RETURN. Some layout tests use \n to mean "Enter", when - // Windows uses \r for "Enter". - int code = 0; - int text = 0; - bool needsShiftKeyModifier = false; - if ("\n" == codeStr) { - generateChar = true; - text = code = VKEY_RETURN; - } else if ("rightArrow" == codeStr) - code = VKEY_RIGHT; - else if ("downArrow" == codeStr) - code = VKEY_DOWN; - else if ("leftArrow" == codeStr) - code = VKEY_LEFT; - else if ("upArrow" == codeStr) - code = VKEY_UP; - else if ("insert" == codeStr) - code = VKEY_INSERT; - else if ("delete" == codeStr) - code = VKEY_DELETE; - else if ("pageUp" == codeStr) - code = VKEY_PRIOR; - else if ("pageDown" == codeStr) - code = VKEY_NEXT; - else if ("home" == codeStr) - code = VKEY_HOME; - else if ("end" == codeStr) - code = VKEY_END; - else if ("printScreen" == codeStr) - code = VKEY_SNAPSHOT; - else if ("menu" == codeStr) - code = VKEY_APPS; - else if ("leftControl" == codeStr) - code = VKEY_LCONTROL; - else if ("rightControl" == codeStr) - code = VKEY_RCONTROL; - else if ("leftShift" == codeStr) - code = VKEY_LSHIFT; - else if ("rightShift" == codeStr) - code = VKEY_RSHIFT; - else if ("leftAlt" == codeStr) - code = VKEY_LMENU; - else if ("rightAlt" == codeStr) - code = VKEY_RMENU; - else if ("numLock" == codeStr) - code = VKEY_NUMLOCK; - else { - // Compare the input string with the function-key names defined by the - // DOM spec (i.e. "F1",...,"F24"). If the input string is a function-key - // name, set its key code. - for (int i = 1; i <= 24; ++i) { - char functionChars[10]; - snprintf(functionChars, 10, "F%d", i); - string functionKeyName(functionChars); - if (functionKeyName == codeStr) { - code = VKEY_F1 + (i - 1); - break; - } - } - if (!code) { - WebString webCodeStr = WebString::fromUTF8(codeStr.data(), codeStr.size()); - BLINK_ASSERT(webCodeStr.length() == 1); - text = code = webCodeStr.at(0); - needsShiftKeyModifier = needsShiftModifier(code); - if ((code & 0xFF) >= 'a' && (code & 0xFF) <= 'z') - code -= 'a' - 'A'; - generateChar = true; - } - - if ("(" == codeStr) { - code = '9'; - needsShiftKeyModifier = true; - } - } - - // For one generated keyboard event, we need to generate a keyDown/keyUp - // pair; refer to EventSender.cpp in Tools/DumpRenderTree/win. - // On Windows, we might also need to generate a char event to mimic the - // Windows event flow; on other platforms we create a merged event and test - // the event flow that that platform provides. - WebKeyboardEvent eventDown, eventChar, eventUp; - eventDown.type = WebInputEvent::RawKeyDown; - eventDown.modifiers = 0; - eventDown.windowsKeyCode = code; -#if defined(__linux__) && defined(TOOLKIT_GTK) - eventDown.nativeKeyCode = NativeKeyCodeForWindowsKeyCode(code); -#endif - - if (generateChar) { - eventDown.text[0] = text; - eventDown.unmodifiedText[0] = text; - } - eventDown.setKeyIdentifierFromWindowsKeyCode(); - - if (arguments.size() >= 2 && (arguments[1].isObject() || arguments[1].isString())) { - eventDown.modifiers = getKeyModifiers(&(arguments[1])); -#if WIN32 || __APPLE__ || defined(ANDROID) || defined(TOOLKIT_GTK) - eventDown.isSystemKey = WebInputEventFactory::isSystemKeyEvent(eventDown); -#endif - } - - if (needsShiftKeyModifier) - eventDown.modifiers |= WebInputEvent::ShiftKey; - - // See if KeyLocation argument is given. - if (arguments.size() >= 3 && arguments[2].isNumber()) { - int location = arguments[2].toInt32(); - if (location == DOMKeyLocationNumpad) - eventDown.modifiers |= WebInputEvent::IsKeyPad; - } - - eventChar = eventUp = eventDown; - eventUp.type = WebInputEvent::KeyUp; - // EventSender.m forces a layout here, with at least one - // test (fast/forms/focus-control-to-page.html) relying on this. - if (shouldForceLayoutOnEvents()) - webview()->layout(); - - // In the browser, if a keyboard event corresponds to an editor command, - // the command will be dispatched to the renderer just before dispatching - // the keyboard event, and then it will be executed in the - // RenderView::handleCurrentKeyboardEvent() method, which is called from - // third_party/WebKit/Source/WebKit/chromium/src/EditorClientImpl.cpp. - // We just simulate the same behavior here. - string editCommand; - if (getEditCommand(eventDown, &editCommand)) - m_delegate->setEditCommand(editCommand, ""); - - webview()->handleInputEvent(eventDown); - - if (code == VKEY_ESCAPE && !currentDragData.isNull()) { - WebMouseEvent event; - initMouseEvent(WebInputEvent::MouseDown, pressedButton, lastMousePos, &event, getCurrentEventTimeSec(m_delegate), 0); - finishDragAndDrop(event, blink::WebDragOperationNone); - } - - m_delegate->clearEditCommand(); - - if (generateChar) { - eventChar.type = WebInputEvent::Char; - eventChar.keyIdentifier[0] = '\0'; - webview()->handleInputEvent(eventChar); - } - - webview()->handleInputEvent(eventUp); -} - -void EventSender::dispatchMessage(const CppArgumentList& arguments, CppVariant* result) -{ - result->setNull(); - -#ifdef WIN32 - if (arguments.size() == 3) { - // Grab the message id to see if we need to dispatch it. - int msg = arguments[0].toInt32(); - - // WebKit's version of this function stuffs a MSG struct and uses - // TranslateMessage and DispatchMessage. We use a WebKeyboardEvent, which - // doesn't need to receive the DeadChar and SysDeadChar messages. - if (msg == WM_DEADCHAR || msg == WM_SYSDEADCHAR) - return; - - if (shouldForceLayoutOnEvents()) - webview()->layout(); - - unsigned long lparam = static_cast<unsigned long>(arguments[2].toDouble()); - webview()->handleInputEvent(WebInputEventFactory::keyboardEvent(0, msg, arguments[1].toInt32(), lparam)); - } else - BLINK_ASSERT_NOT_REACHED(); -#endif -} - -bool EventSender::needsShiftModifier(int keyCode) -{ - // If code is an uppercase letter, assign a SHIFT key to - // eventDown.modifier, this logic comes from - // Tools/DumpRenderTree/win/EventSender.cpp - return (keyCode & 0xFF) >= 'A' && (keyCode & 0xFF) <= 'Z'; -} - -void EventSender::leapForward(const CppArgumentList& arguments, CppVariant* result) -{ - result->setNull(); - - if (arguments.size() < 1 || !arguments[0].isNumber()) - return; - - int milliseconds = arguments[0].toInt32(); - if (isDragMode() && pressedButton == WebMouseEvent::ButtonLeft && !replayingSavedEvents) { - SavedEvent savedEvent; - savedEvent.type = SavedEvent::LeapForward; - savedEvent.milliseconds = milliseconds; - mouseEventQueue.push_back(savedEvent); - } else - doLeapForward(milliseconds); -} - -void EventSender::doLeapForward(int milliseconds) -{ - advanceEventTime(milliseconds); -} - -// Apple's port of WebKit zooms by a factor of 1.2 (see -// WebKit/WebView/WebView.mm) -void EventSender::textZoomIn(const CppArgumentList&, CppVariant* result) -{ - webview()->setTextZoomFactor(webview()->textZoomFactor() * 1.2f); - result->setNull(); -} - -void EventSender::textZoomOut(const CppArgumentList&, CppVariant* result) -{ - webview()->setTextZoomFactor(webview()->textZoomFactor() / 1.2f); - result->setNull(); -} - -void EventSender::zoomPageIn(const CppArgumentList&, CppVariant* result) -{ - const vector<WebTestProxyBase*>& windowList = m_testInterfaces->windowList(); - - for (size_t i = 0; i < windowList.size(); ++i) - windowList.at(i)->webView()->setZoomLevel(windowList.at(i)->webView()->zoomLevel() + 1); - result->setNull(); -} - -void EventSender::zoomPageOut(const CppArgumentList&, CppVariant* result) -{ - const vector<WebTestProxyBase*>& windowList = m_testInterfaces->windowList(); - - for (size_t i = 0; i < windowList.size(); ++i) - windowList.at(i)->webView()->setZoomLevel(windowList.at(i)->webView()->zoomLevel() - 1); - result->setNull(); -} - -void EventSender::setPageScaleFactor(const CppArgumentList& arguments, CppVariant* result) -{ - if (arguments.size() < 3 || !arguments[0].isNumber() || !arguments[1].isNumber() || !arguments[2].isNumber()) - return; - - float scaleFactor = static_cast<float>(arguments[0].toDouble()); - int x = arguments[1].toInt32(); - int y = arguments[2].toInt32(); - webview()->setPageScaleFactorLimits(scaleFactor, scaleFactor); - webview()->setPageScaleFactor(scaleFactor, WebPoint(x, y)); - result->setNull(); -} - -void EventSender::mouseScrollBy(const CppArgumentList& arguments, CppVariant* result) -{ - WebMouseWheelEvent event; - initMouseWheelEvent(arguments, result, false, &event); - webview()->handleInputEvent(event); -} - -void EventSender::continuousMouseScrollBy(const CppArgumentList& arguments, CppVariant* result) -{ - WebMouseWheelEvent event; - initMouseWheelEvent(arguments, result, true, &event); - webview()->handleInputEvent(event); -} - -void EventSender::replaySavedEvents() -{ - replayingSavedEvents = true; - while (!mouseEventQueue.empty()) { - SavedEvent e = mouseEventQueue.front(); - mouseEventQueue.pop_front(); - - switch (e.type) { - case SavedEvent::MouseMove: { - WebMouseEvent event; - initMouseEvent(WebInputEvent::MouseMove, pressedButton, e.pos, &event, getCurrentEventTimeSec(m_delegate), e.modifiers); - doMouseMove(event); - break; - } - case SavedEvent::LeapForward: - doLeapForward(e.milliseconds); - break; - case SavedEvent::MouseUp: { - WebMouseEvent event; - initMouseEvent(WebInputEvent::MouseUp, e.buttonType, lastMousePos, &event, getCurrentEventTimeSec(m_delegate), e.modifiers); - doMouseUp(event); - break; - } - default: - BLINK_ASSERT_NOT_REACHED(); - } - } - - replayingSavedEvents = false; -} - -// Because actual context menu is implemented by the browser side, -// this function does only what LayoutTests are expecting: -// - Many test checks the count of items. So returning non-zero value makes sense. -// - Some test compares the count before and after some action. So changing the count based on flags -// also makes sense. This function is doing such for some flags. -// - Some test even checks actual string content. So providing it would be also helpful. -// -static vector<WebString> makeMenuItemStringsFor(WebContextMenuData* contextMenu, WebTestDelegate* delegate) -{ - // These constants are based on Safari's context menu because tests are made for it. - static const char* nonEditableMenuStrings[] = { "Back", "Reload Page", "Open in Dashbaord", "<separator>", "View Source", "Save Page As", "Print Page", "Inspect Element", 0 }; - static const char* editableMenuStrings[] = { "Cut", "Copy", "<separator>", "Paste", "Spelling and Grammar", "Substitutions, Transformations", "Font", "Speech", "Paragraph Direction", "<separator>", 0 }; - - // This is possible because mouse events are cancelleable. - if (!contextMenu) - return vector<WebString>(); - - vector<WebString> strings; - - if (contextMenu->isEditable) { - for (const char** item = editableMenuStrings; *item; ++item) - strings.push_back(WebString::fromUTF8(*item)); - WebVector<WebString> suggestions; - MockSpellCheck::fillSuggestionList(contextMenu->misspelledWord, &suggestions); - for (size_t i = 0; i < suggestions.size(); ++i) - strings.push_back(suggestions[i]); - } else { - for (const char** item = nonEditableMenuStrings; *item; ++item) - strings.push_back(WebString::fromUTF8(*item)); - } - - return strings; -} - -void EventSender::contextClick(const CppArgumentList& arguments, CppVariant* result) -{ - if (shouldForceLayoutOnEvents()) - webview()->layout(); - - updateClickCountForButton(WebMouseEvent::ButtonRight); - - // Clears last context menu data because we need to know if the context menu be requested - // after following mouse events. - m_lastContextMenuData.reset(); - - // Generate right mouse down and up. - WebMouseEvent event; - // This is a hack to work around only allowing a single pressed button since we want to - // test the case where both the left and right mouse buttons are pressed. - if (pressedButton == WebMouseEvent::ButtonNone) - pressedButton = WebMouseEvent::ButtonRight; - initMouseEvent(WebInputEvent::MouseDown, WebMouseEvent::ButtonRight, lastMousePos, &event, getCurrentEventTimeSec(m_delegate), 0); - webview()->handleInputEvent(event); - -#ifdef WIN32 - initMouseEvent(WebInputEvent::MouseUp, WebMouseEvent::ButtonRight, lastMousePos, &event, getCurrentEventTimeSec(m_delegate), 0); - webview()->handleInputEvent(event); - - pressedButton = WebMouseEvent::ButtonNone; -#endif - - NPObject* resultArray = WebBindings::makeStringArray(makeMenuItemStringsFor(m_lastContextMenuData.get(), m_delegate)); - result->set(resultArray); - WebBindings::releaseObject(resultArray); - - m_lastContextMenuData.reset(); -} - -class MouseDownTask: public WebMethodTask<EventSender> { -public: - MouseDownTask(EventSender* obj, const CppArgumentList& arg) - : WebMethodTask<EventSender>(obj), m_arguments(arg) { } - virtual void runIfValid() OVERRIDE { m_object->mouseDown(m_arguments, 0); } - -private: - CppArgumentList m_arguments; -}; - -class MouseUpTask: public WebMethodTask<EventSender> { -public: - MouseUpTask(EventSender* obj, const CppArgumentList& arg) - : WebMethodTask<EventSender>(obj), m_arguments(arg) { } - virtual void runIfValid() OVERRIDE { m_object->mouseUp(m_arguments, 0); } - -private: - CppArgumentList m_arguments; -}; - -void EventSender::scheduleAsynchronousClick(const CppArgumentList& arguments, CppVariant* result) -{ - result->setNull(); - m_delegate->postTask(new MouseDownTask(this, arguments)); - m_delegate->postTask(new MouseUpTask(this, arguments)); -} - -class KeyDownTask : public WebMethodTask<EventSender> { -public: - KeyDownTask(EventSender* obj, const CppArgumentList& arg) - : WebMethodTask<EventSender>(obj), m_arguments(arg) { } - virtual void runIfValid() OVERRIDE { m_object->keyDown(m_arguments, 0); } - -private: - CppArgumentList m_arguments; -}; - -void EventSender::scheduleAsynchronousKeyDown(const CppArgumentList& arguments, CppVariant* result) -{ - result->setNull(); - m_delegate->postTask(new KeyDownTask(this, arguments)); -} - -void EventSender::beginDragWithFiles(const CppArgumentList& arguments, CppVariant* result) -{ - currentDragData.initialize(); - vector<string> files = arguments[0].toStringVector(); - WebVector<WebString> absoluteFilenames(files.size()); - for (size_t i = 0; i < files.size(); ++i) { - WebDragData::Item item; - item.storageType = WebDragData::Item::StorageTypeFilename; - item.filenameData = m_delegate->getAbsoluteWebStringFromUTF8Path(files[i]); - currentDragData.addItem(item); - absoluteFilenames[i] = item.filenameData; - } - currentDragData.setFilesystemId(m_delegate->registerIsolatedFileSystem(absoluteFilenames)); - currentDragEffectsAllowed = blink::WebDragOperationCopy; - - // Provide a drag source. - webview()->dragTargetDragEnter(currentDragData, lastMousePos, lastMousePos, currentDragEffectsAllowed, 0); - - // dragMode saves events and then replays them later. We don't need/want that. - dragMode.set(false); - - // Make the rest of eventSender think a drag is in progress. - pressedButton = WebMouseEvent::ButtonLeft; - - result->setNull(); -} - -void EventSender::addTouchPoint(const CppArgumentList& arguments, CppVariant* result) -{ - result->setNull(); - - WebTouchPoint touchPoint; - touchPoint.state = WebTouchPoint::StatePressed; - touchPoint.position = WebFloatPoint(arguments[0].toInt32(), arguments[1].toInt32()); - touchPoint.screenPosition = touchPoint.position; - - if (arguments.size() > 2) { - int radiusX = arguments[2].toInt32(); - int radiusY = radiusX; - if (arguments.size() > 3) - radiusY = arguments[3].toInt32(); - - touchPoint.radiusX = radiusX; - touchPoint.radiusY = radiusY; - } - - int lowestId = 0; - for (size_t i = 0; i < touchPoints.size(); i++) { - if (touchPoints[i].id == lowestId) - lowestId++; - } - touchPoint.id = lowestId; - touchPoints.push_back(touchPoint); -} - -void EventSender::clearTouchPoints(const CppArgumentList&, CppVariant* result) -{ - result->setNull(); - touchPoints.clear(); -} - -void EventSender::releaseTouchPoint(const CppArgumentList& arguments, CppVariant* result) -{ - result->setNull(); - - const unsigned index = arguments[0].toInt32(); - BLINK_ASSERT(index < touchPoints.size()); - - WebTouchPoint* touchPoint = &touchPoints[index]; - touchPoint->state = WebTouchPoint::StateReleased; -} - -void EventSender::setTouchModifier(const CppArgumentList& arguments, CppVariant* result) -{ - result->setNull(); - - int mask = 0; - const string keyName = arguments[0].toString(); - if (keyName == "shift") - mask = WebInputEvent::ShiftKey; - else if (keyName == "alt") - mask = WebInputEvent::AltKey; - else if (keyName == "ctrl") - mask = WebInputEvent::ControlKey; - else if (keyName == "meta") - mask = WebInputEvent::MetaKey; - - if (arguments[1].toBoolean()) - touchModifiers |= mask; - else - touchModifiers &= ~mask; -} - -void EventSender::updateTouchPoint(const CppArgumentList& arguments, CppVariant* result) -{ - result->setNull(); - - const unsigned index = arguments[0].toInt32(); - BLINK_ASSERT(index < touchPoints.size()); - - WebTouchPoint* touchPoint = &touchPoints[index]; - touchPoint->state = WebTouchPoint::StateMoved; - touchPoint->position = WebFloatPoint(arguments[1].toInt32(), arguments[2].toInt32()); - touchPoint->screenPosition = touchPoint->position; -} - -void EventSender::cancelTouchPoint(const CppArgumentList& arguments, CppVariant* result) -{ - result->setNull(); - - const unsigned index = arguments[0].toInt32(); - BLINK_ASSERT(index < touchPoints.size()); - - WebTouchPoint* touchPoint = &touchPoints[index]; - touchPoint->state = WebTouchPoint::StateCancelled; -} - -void EventSender::sendCurrentTouchEvent(const WebInputEvent::Type type) -{ - BLINK_ASSERT(static_cast<unsigned>(WebTouchEvent::touchesLengthCap) > touchPoints.size()); - if (shouldForceLayoutOnEvents()) - webview()->layout(); - - WebTouchEvent touchEvent; - touchEvent.type = type; - touchEvent.modifiers = touchModifiers; - touchEvent.timeStampSeconds = getCurrentEventTimeSec(m_delegate); - touchEvent.touchesLength = touchPoints.size(); - for (unsigned i = 0; i < touchPoints.size(); ++i) - touchEvent.touches[i] = touchPoints[i]; - webview()->handleInputEvent(touchEvent); - - for (unsigned i = 0; i < touchPoints.size(); ++i) { - WebTouchPoint* touchPoint = &touchPoints[i]; - if (touchPoint->state == WebTouchPoint::StateReleased) { - touchPoints.erase(touchPoints.begin() + i); - --i; - } else - touchPoint->state = WebTouchPoint::StateStationary; - } -} - -void EventSender::mouseDragBegin(const CppArgumentList& arguments, CppVariant* result) -{ - WebMouseWheelEvent event; - initMouseEvent(WebInputEvent::MouseWheel, WebMouseEvent::ButtonNone, lastMousePos, &event, getCurrentEventTimeSec(m_delegate), 0); - event.phase = WebMouseWheelEvent::PhaseBegan; - event.hasPreciseScrollingDeltas = true; - webview()->handleInputEvent(event); -} - -void EventSender::mouseDragEnd(const CppArgumentList& arguments, CppVariant* result) -{ - WebMouseWheelEvent event; - initMouseEvent(WebInputEvent::MouseWheel, WebMouseEvent::ButtonNone, lastMousePos, &event, getCurrentEventTimeSec(m_delegate), 0); - event.phase = WebMouseWheelEvent::PhaseEnded; - event.hasPreciseScrollingDeltas = true; - webview()->handleInputEvent(event); -} - -void EventSender::mouseMomentumBegin(const CppArgumentList& arguments, CppVariant* result) -{ - WebMouseWheelEvent event; - initMouseEvent(WebInputEvent::MouseWheel, WebMouseEvent::ButtonNone, lastMousePos, &event, getCurrentEventTimeSec(m_delegate), 0); - event.momentumPhase = WebMouseWheelEvent::PhaseBegan; - event.hasPreciseScrollingDeltas = true; - webview()->handleInputEvent(event); -} - -void EventSender::mouseMomentumScrollBy(const CppArgumentList& arguments, CppVariant* result) -{ - WebMouseWheelEvent event; - initMouseWheelEvent(arguments, result, true, &event); - event.momentumPhase = WebMouseWheelEvent::PhaseChanged; - event.hasPreciseScrollingDeltas = true; - webview()->handleInputEvent(event); -} - -void EventSender::mouseMomentumEnd(const CppArgumentList& arguments, CppVariant* result) -{ - WebMouseWheelEvent event; - initMouseEvent(WebInputEvent::MouseWheel, WebMouseEvent::ButtonNone, lastMousePos, &event, getCurrentEventTimeSec(m_delegate), 0); - event.momentumPhase = WebMouseWheelEvent::PhaseEnded; - event.hasPreciseScrollingDeltas = true; - webview()->handleInputEvent(event); -} - -void EventSender::initMouseWheelEvent(const CppArgumentList& arguments, CppVariant* result, bool continuous, WebMouseWheelEvent* event) -{ - result->setNull(); - - if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isNumber()) - return; - - // Force a layout here just to make sure every position has been - // determined before we send events (as well as all the other methods - // that send an event do). - if (shouldForceLayoutOnEvents()) - webview()->layout(); - - int horizontal = arguments[0].toInt32(); - int vertical = arguments[1].toInt32(); - int paged = false; - int hasPreciseScrollingDeltas = false; - int modifiers = 0; - - if (arguments.size() > 2 && arguments[2].isBool()) - paged = arguments[2].toBoolean(); - - if (arguments.size() > 3 && arguments[3].isBool()) - hasPreciseScrollingDeltas = arguments[3].toBoolean(); - - if (arguments.size() > 4 && (arguments[4].isObject() || arguments[4].isString())) - modifiers = getKeyModifiers(&(arguments[4])); - - initMouseEvent(WebInputEvent::MouseWheel, pressedButton, lastMousePos, event, getCurrentEventTimeSec(m_delegate), modifiers); - event->wheelTicksX = static_cast<float>(horizontal); - event->wheelTicksY = static_cast<float>(vertical); - event->deltaX = event->wheelTicksX; - event->deltaY = event->wheelTicksY; - event->scrollByPage = paged; - event->hasPreciseScrollingDeltas = hasPreciseScrollingDeltas; - - if (continuous) { - event->wheelTicksX /= scrollbarPixelsPerTick; - event->wheelTicksY /= scrollbarPixelsPerTick; - } else { - event->deltaX *= scrollbarPixelsPerTick; - event->deltaY *= scrollbarPixelsPerTick; - } -} - -void EventSender::touchEnd(const CppArgumentList&, CppVariant* result) -{ - result->setNull(); - sendCurrentTouchEvent(WebInputEvent::TouchEnd); -} - -void EventSender::touchMove(const CppArgumentList&, CppVariant* result) -{ - result->setNull(); - sendCurrentTouchEvent(WebInputEvent::TouchMove); -} - -void EventSender::touchStart(const CppArgumentList&, CppVariant* result) -{ - result->setNull(); - sendCurrentTouchEvent(WebInputEvent::TouchStart); -} - -void EventSender::touchCancel(const CppArgumentList&, CppVariant* result) -{ - result->setNull(); - sendCurrentTouchEvent(WebInputEvent::TouchCancel); -} - -void EventSender::gestureScrollBegin(const CppArgumentList& arguments, CppVariant* result) -{ - result->setNull(); - gestureEvent(WebInputEvent::GestureScrollBegin, arguments); -} - -void EventSender::gestureScrollEnd(const CppArgumentList& arguments, CppVariant* result) -{ - result->setNull(); - gestureEvent(WebInputEvent::GestureScrollEnd, arguments); -} - -void EventSender::gestureScrollUpdate(const CppArgumentList& arguments, CppVariant* result) -{ - result->setNull(); - gestureEvent(WebInputEvent::GestureScrollUpdate, arguments); -} - -void EventSender::gestureScrollUpdateWithoutPropagation(const CppArgumentList& arguments, CppVariant* result) -{ - result->setNull(); - gestureEvent(WebInputEvent::GestureScrollUpdateWithoutPropagation, arguments); -} - -void EventSender::gestureTap(const CppArgumentList& arguments, CppVariant* result) -{ - result->setNull(); - gestureEvent(WebInputEvent::GestureTap, arguments); -} - -void EventSender::gestureTapDown(const CppArgumentList& arguments, CppVariant* result) -{ - result->setNull(); - gestureEvent(WebInputEvent::GestureTapDown, arguments); -} - -void EventSender::gestureShowPress(const CppArgumentList& arguments, CppVariant* result) -{ - result->setNull(); - gestureEvent(WebInputEvent::GestureShowPress, arguments); -} - -void EventSender::gestureTapCancel(const CppArgumentList& arguments, CppVariant* result) -{ - result->setNull(); - gestureEvent(WebInputEvent::GestureTapCancel, arguments); -} - -void EventSender::gestureLongPress(const CppArgumentList& arguments, CppVariant* result) -{ - result->setNull(); - gestureEvent(WebInputEvent::GestureLongPress, arguments); -} - -void EventSender::gestureLongTap(const CppArgumentList& arguments, CppVariant* result) -{ - result->setNull(); - gestureEvent(WebInputEvent::GestureLongTap, arguments); -} - -void EventSender::gestureTwoFingerTap(const CppArgumentList& arguments, CppVariant* result) -{ - result->setNull(); - gestureEvent(WebInputEvent::GestureTwoFingerTap, arguments); -} - -void EventSender::gestureScrollFirstPoint(const CppArgumentList& arguments, CppVariant* result) -{ - result->setNull(); - if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isNumber()) - return; - - WebPoint point(arguments[0].toInt32(), arguments[1].toInt32()); - m_currentGestureLocation = point; -} - -void EventSender::gestureEvent(WebInputEvent::Type type, const CppArgumentList& arguments) -{ - if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isNumber()) - return; - - WebPoint point(arguments[0].toInt32(), arguments[1].toInt32()); - - WebGestureEvent event; - event.type = type; - - switch (type) { - case WebInputEvent::GestureScrollUpdate: - case WebInputEvent::GestureScrollUpdateWithoutPropagation: - event.data.scrollUpdate.deltaX = static_cast<float>(arguments[0].toDouble()); - event.data.scrollUpdate.deltaY = static_cast<float>(arguments[1].toDouble()); - event.x = m_currentGestureLocation.x; - event.y = m_currentGestureLocation.y; - m_currentGestureLocation.x = m_currentGestureLocation.x + event.data.scrollUpdate.deltaX; - m_currentGestureLocation.y = m_currentGestureLocation.y + event.data.scrollUpdate.deltaY; - break; - - case WebInputEvent::GestureScrollBegin: - m_currentGestureLocation = WebPoint(point.x, point.y); - event.x = m_currentGestureLocation.x; - event.y = m_currentGestureLocation.y; - break; - case WebInputEvent::GestureScrollEnd: - case WebInputEvent::GestureFlingStart: - event.x = m_currentGestureLocation.x; - event.y = m_currentGestureLocation.y; - break; - case WebInputEvent::GestureTap: - if (arguments.size() >= 3) - event.data.tap.tapCount = static_cast<float>(arguments[2].toDouble()); - else - event.data.tap.tapCount = 1; - event.x = point.x; - event.y = point.y; - break; - case WebInputEvent::GestureTapUnconfirmed: - if (arguments.size() >= 3) - event.data.tap.tapCount = static_cast<float>(arguments[2].toDouble()); - else - event.data.tap.tapCount = 1; - event.x = point.x; - event.y = point.y; - break; - case WebInputEvent::GestureTapDown: - event.x = point.x; - event.y = point.y; - if (arguments.size() >= 4) { - event.data.tapDown.width = static_cast<float>(arguments[2].toDouble()); - event.data.tapDown.height = static_cast<float>(arguments[3].toDouble()); - } - break; - case WebInputEvent::GestureShowPress: - event.x = point.x; - event.y = point.y; - if (arguments.size() >= 4) { - event.data.showPress.width = static_cast<float>(arguments[2].toDouble()); - event.data.showPress.height = static_cast<float>(arguments[3].toDouble()); - } - break; - case WebInputEvent::GestureTapCancel: - event.x = point.x; - event.y = point.y; - break; - case WebInputEvent::GestureLongPress: - event.x = point.x; - event.y = point.y; - if (arguments.size() >= 4) { - event.data.longPress.width = static_cast<float>(arguments[2].toDouble()); - event.data.longPress.height = static_cast<float>(arguments[3].toDouble()); - } - break; - case WebInputEvent::GestureLongTap: - event.x = point.x; - event.y = point.y; - if (arguments.size() >= 4) { - event.data.longPress.width = static_cast<float>(arguments[2].toDouble()); - event.data.longPress.height = static_cast<float>(arguments[3].toDouble()); - } - break; - case WebInputEvent::GestureTwoFingerTap: - event.x = point.x; - event.y = point.y; - if (arguments.size() >= 4) { - event.data.twoFingerTap.firstFingerWidth = static_cast<float>(arguments[2].toDouble()); - event.data.twoFingerTap.firstFingerHeight = static_cast<float>(arguments[3].toDouble()); - } - break; - default: - BLINK_ASSERT_NOT_REACHED(); - } - - event.globalX = event.x; - event.globalY = event.y; - event.timeStampSeconds = getCurrentEventTimeSec(m_delegate); - - if (shouldForceLayoutOnEvents()) - webview()->layout(); - - webview()->handleInputEvent(event); - - // Long press might start a drag drop session. Complete it if so. - if (type == WebInputEvent::GestureLongPress && !currentDragData.isNull()) { - WebMouseEvent mouseEvent; - initMouseEvent(WebInputEvent::MouseDown, pressedButton, point, &mouseEvent, getCurrentEventTimeSec(m_delegate), 0); - finishDragAndDrop(mouseEvent, blink::WebDragOperationNone); - } -} - -void EventSender::gestureFlingCancel(const CppArgumentList&, CppVariant* result) -{ - result->setNull(); - - WebGestureEvent event; - event.type = WebInputEvent::GestureFlingCancel; - event.timeStampSeconds = getCurrentEventTimeSec(m_delegate); - - if (shouldForceLayoutOnEvents()) - webview()->layout(); - - webview()->handleInputEvent(event); -} - -void EventSender::gestureFlingStart(const CppArgumentList& arguments, CppVariant* result) -{ - result->setNull(); - if (arguments.size() < 4) - return; - - for (int i = 0; i < 4; i++) - if (!arguments[i].isNumber()) - return; - - WebGestureEvent event; - event.type = WebInputEvent::GestureFlingStart; - - event.x = static_cast<float>(arguments[0].toDouble()); - event.y = static_cast<float>(arguments[1].toDouble()); - event.globalX = event.x; - event.globalY = event.y; - - event.data.flingStart.velocityX = static_cast<float>(arguments[2].toDouble()); - event.data.flingStart.velocityY = static_cast<float>(arguments[3].toDouble()); - event.timeStampSeconds = getCurrentEventTimeSec(m_delegate); - - if (shouldForceLayoutOnEvents()) - webview()->layout(); - - webview()->handleInputEvent(event); -} - -// -// Unimplemented stubs -// - -void EventSender::enableDOMUIEventLogging(const CppArgumentList&, CppVariant* result) -{ - result->setNull(); -} - -void EventSender::fireKeyboardEventsToElement(const CppArgumentList&, CppVariant* result) -{ - result->setNull(); -} - -void EventSender::clearKillRing(const CppArgumentList&, CppVariant* result) -{ - result->setNull(); -} - -} diff --git a/content/shell/renderer/test_runner/EventSender.h b/content/shell/renderer/test_runner/EventSender.h deleted file mode 100644 index 1f5244f..0000000 --- a/content/shell/renderer/test_runner/EventSender.h +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/* - EventSender class: - Bound to a JavaScript window.eventSender object using - CppBoundClass::bindToJavascript(), this allows layout tests to fire DOM events. -*/ - -#ifndef CONTENT_SHELL_RENDERER_TEST_RUNNER_EVENTSENDER_H_ -#define CONTENT_SHELL_RENDERER_TEST_RUNNER_EVENTSENDER_H_ - -#include "base/memory/scoped_ptr.h" -#include "content/shell/renderer/test_runner/CppBoundClass.h" -#include "content/shell/renderer/test_runner/WebTask.h" -#include "third_party/WebKit/public/platform/WebPoint.h" -#include "third_party/WebKit/public/web/WebDragOperation.h" -#include "third_party/WebKit/public/web/WebInputEvent.h" - -namespace blink { -class WebDragData; -class WebView; -struct WebContextMenuData; -} - -namespace WebTestRunner { - -class TestInterfaces; -class WebTestDelegate; - -class EventSender : public CppBoundClass { -public: - explicit EventSender(TestInterfaces*); - virtual ~EventSender(); - - void setDelegate(WebTestDelegate* delegate) { m_delegate = delegate; } - void setWebView(blink::WebView* webView) { m_webView = webView; } - - void setContextMenuData(const blink::WebContextMenuData&); - - // Resets some static variable state. - void reset(); - - // Simulate drag&drop system call. - void doDragDrop(const blink::WebDragData&, blink::WebDragOperationsMask); - - // Test helper for dragging out images. - void dumpFilenameBeingDragged(const CppArgumentList&, CppVariant*); - - // JS callback methods. - void contextClick(const CppArgumentList&, CppVariant*); - void mouseDown(const CppArgumentList&, CppVariant*); - void mouseUp(const CppArgumentList&, CppVariant*); - void mouseMoveTo(const CppArgumentList&, CppVariant*); - void leapForward(const CppArgumentList&, CppVariant*); - void keyDown(const CppArgumentList&, CppVariant*); - void dispatchMessage(const CppArgumentList&, CppVariant*); - // FIXME: These aren't really events. They should be moved to layout controller. - void textZoomIn(const CppArgumentList&, CppVariant*); - void textZoomOut(const CppArgumentList&, CppVariant*); - void zoomPageIn(const CppArgumentList&, CppVariant*); - void zoomPageOut(const CppArgumentList&, CppVariant*); - void setPageScaleFactor(const CppArgumentList&, CppVariant*); - - void mouseDragBegin(const CppArgumentList&, CppVariant*); - void mouseDragEnd(const CppArgumentList&, CppVariant*); - void mouseMomentumBegin(const CppArgumentList&, CppVariant*); - void mouseMomentumScrollBy(const CppArgumentList&, CppVariant*); - void mouseMomentumEnd(const CppArgumentList&, CppVariant*); - void mouseScrollBy(const CppArgumentList&, CppVariant*); - void continuousMouseScrollBy(const CppArgumentList&, CppVariant*); - void scheduleAsynchronousClick(const CppArgumentList&, CppVariant*); - void scheduleAsynchronousKeyDown(const CppArgumentList&, CppVariant*); - void beginDragWithFiles(const CppArgumentList&, CppVariant*); - CppVariant dragMode; - - void addTouchPoint(const CppArgumentList&, CppVariant*); - void cancelTouchPoint(const CppArgumentList&, CppVariant*); - void clearTouchPoints(const CppArgumentList&, CppVariant*); - void releaseTouchPoint(const CppArgumentList&, CppVariant*); - void setTouchModifier(const CppArgumentList&, CppVariant*); - void touchCancel(const CppArgumentList&, CppVariant*); - void touchEnd(const CppArgumentList&, CppVariant*); - void touchMove(const CppArgumentList&, CppVariant*); - void touchStart(const CppArgumentList&, CppVariant*); - void updateTouchPoint(const CppArgumentList&, CppVariant*); - - void gestureFlingCancel(const CppArgumentList&, CppVariant*); - void gestureFlingStart(const CppArgumentList&, CppVariant*); - void gestureScrollBegin(const CppArgumentList&, CppVariant*); - void gestureScrollEnd(const CppArgumentList&, CppVariant*); - void gestureScrollFirstPoint(const CppArgumentList&, CppVariant*); - void gestureScrollUpdate(const CppArgumentList&, CppVariant*); - void gestureScrollUpdateWithoutPropagation(const CppArgumentList&, CppVariant*); - void gestureTap(const CppArgumentList&, CppVariant*); - void gestureTapDown(const CppArgumentList&, CppVariant*); - void gestureShowPress(const CppArgumentList&, CppVariant*); - void gestureTapCancel(const CppArgumentList&, CppVariant*); - void gestureLongPress(const CppArgumentList&, CppVariant*); - void gestureLongTap(const CppArgumentList&, CppVariant*); - void gestureTwoFingerTap(const CppArgumentList&, CppVariant*); - void gestureEvent(blink::WebInputEvent::Type, const CppArgumentList&); - - // Setting this to false makes EventSender not force layout() calls. - // This makes it possible to test the standard WebCore event dispatch. - CppVariant forceLayoutOnEvents; - - // Unimplemented stubs - void enableDOMUIEventLogging(const CppArgumentList&, CppVariant*); - void fireKeyboardEventsToElement(const CppArgumentList&, CppVariant*); - void clearKillRing(const CppArgumentList&, CppVariant*); - - // Properties used in layout tests. -#if defined(OS_WIN) - CppVariant wmKeyDown; - CppVariant wmKeyUp; - CppVariant wmChar; - CppVariant wmDeadChar; - CppVariant wmSysKeyDown; - CppVariant wmSysKeyUp; - CppVariant wmSysChar; - CppVariant wmSysDeadChar; -#endif - - WebTaskList* taskList() { return &m_taskList; } - -private: - blink::WebView* webview() { return m_webView; } - - // Returns true if dragMode is true. - bool isDragMode() { return dragMode.isBool() && dragMode.toBoolean(); } - - bool shouldForceLayoutOnEvents() const { return forceLayoutOnEvents.isBool() && forceLayoutOnEvents.toBoolean(); } - - // Sometimes we queue up mouse move and mouse up events for drag drop - // handling purposes. These methods dispatch the event. - void doMouseMove(const blink::WebMouseEvent&); - void doMouseUp(const blink::WebMouseEvent&); - static void doLeapForward(int milliseconds); - void replaySavedEvents(); - - // Helper to return the button type given a button code - static blink::WebMouseEvent::Button getButtonTypeFromButtonNumber(int); - - // Helper to extract the button number from the optional argument in - // mouseDown and mouseUp - static int getButtonNumberFromSingleArg(const CppArgumentList&); - - // Returns true if the specified key code passed in needs a shift key - // modifier to be passed into the generated event. - bool needsShiftModifier(int); - - void finishDragAndDrop(const blink::WebMouseEvent&, blink::WebDragOperation); - void updateClickCountForButton(blink::WebMouseEvent::Button); - - // Compose a touch event from the current touch points and send it. - void sendCurrentTouchEvent(const blink::WebInputEvent::Type); - - // Init a mouse wheel event from the given args. - void initMouseWheelEvent(const CppArgumentList&, CppVariant*, bool continuous, blink::WebMouseWheelEvent*); - - WebTaskList m_taskList; - - TestInterfaces* m_testInterfaces; - WebTestDelegate* m_delegate; - blink::WebView* m_webView; - - scoped_ptr<blink::WebContextMenuData> m_lastContextMenuData; - - // Location of the touch point that initiated a gesture. - blink::WebPoint m_currentGestureLocation; - - // Location of last mouseMoveTo event. - static blink::WebPoint lastMousePos; - - // Currently pressed mouse button (Left/Right/Middle or None) - static blink::WebMouseEvent::Button pressedButton; - - // The last button number passed to mouseDown and mouseUp. - // Used to determine whether the click count continues to - // increment or not. - static blink::WebMouseEvent::Button lastButtonType; -}; - -} - -#endif // CONTENT_SHELL_RENDERER_TEST_RUNNER_EVENTSENDER_H_ diff --git a/content/shell/renderer/test_runner/TestInterfaces.cpp b/content/shell/renderer/test_runner/TestInterfaces.cpp index 5e08ac3..c7c4d2d 100644 --- a/content/shell/renderer/test_runner/TestInterfaces.cpp +++ b/content/shell/renderer/test_runner/TestInterfaces.cpp @@ -7,9 +7,9 @@ #include <string> #include "base/strings/stringprintf.h" -#include "content/shell/renderer/test_runner/EventSender.h" #include "content/shell/renderer/test_runner/WebTestProxy.h" #include "content/shell/renderer/test_runner/accessibility_controller.h" +#include "content/shell/renderer/test_runner/event_sender.h" #include "content/shell/renderer/test_runner/gamepad_controller.h" #include "content/shell/renderer/test_runner/text_input_controller.h" #include "content/shell/renderer/test_runner/test_runner.h" @@ -27,7 +27,7 @@ namespace WebTestRunner { TestInterfaces::TestInterfaces() : m_accessibilityController(new content::AccessibilityController()) - , m_eventSender(new EventSender(this)) + , m_eventSender(new content::EventSender(this)) , m_gamepadController(new content::GamepadController()) , m_textInputController(new content::TextInputController()) , m_testRunner(new content::TestRunner(this)) @@ -44,13 +44,13 @@ TestInterfaces::TestInterfaces() TestInterfaces::~TestInterfaces() { m_accessibilityController->SetWebView(0); - m_eventSender->setWebView(0); + m_eventSender->SetWebView(0); // m_gamepadController doesn't depend on WebView. m_textInputController->SetWebView(NULL); m_testRunner->SetWebView(0, 0); m_accessibilityController->SetDelegate(0); - m_eventSender->setDelegate(0); + m_eventSender->SetDelegate(0); m_gamepadController->SetDelegate(0); // m_textInputController doesn't depend on WebTestDelegate. m_testRunner->SetDelegate(0); @@ -60,7 +60,7 @@ void TestInterfaces::setWebView(WebView* webView, WebTestProxyBase* proxy) { m_proxy = proxy; m_accessibilityController->SetWebView(webView); - m_eventSender->setWebView(webView); + m_eventSender->SetWebView(webView); // m_gamepadController doesn't depend on WebView. m_textInputController->SetWebView(webView); m_testRunner->SetWebView(webView, proxy); @@ -69,7 +69,7 @@ void TestInterfaces::setWebView(WebView* webView, WebTestProxyBase* proxy) void TestInterfaces::setDelegate(WebTestDelegate* delegate) { m_accessibilityController->SetDelegate(delegate); - m_eventSender->setDelegate(delegate); + m_eventSender->SetDelegate(delegate); m_gamepadController->SetDelegate(delegate); // m_textInputController doesn't depend on WebTestDelegate. m_testRunner->SetDelegate(delegate); @@ -79,7 +79,7 @@ void TestInterfaces::setDelegate(WebTestDelegate* delegate) void TestInterfaces::bindTo(WebFrame* frame) { m_accessibilityController->Install(frame); - m_eventSender->bindToJavascript(frame, WebString::fromUTF8("eventSender")); + m_eventSender->Install(frame); m_gamepadController->Install(frame); m_textInputController->Install(frame); m_testRunner->Install(frame); @@ -88,7 +88,7 @@ void TestInterfaces::bindTo(WebFrame* frame) void TestInterfaces::resetTestHelperControllers() { m_accessibilityController->Reset(); - m_eventSender->reset(); + m_eventSender->Reset(); m_gamepadController->Reset(); // m_textInputController doesn't have any state to reset. WebCache::clear(); @@ -157,7 +157,7 @@ content::AccessibilityController* TestInterfaces::accessibilityController() return m_accessibilityController.get(); } -EventSender* TestInterfaces::eventSender() +content::EventSender* TestInterfaces::eventSender() { return m_eventSender.get(); } diff --git a/content/shell/renderer/test_runner/TestInterfaces.h b/content/shell/renderer/test_runner/TestInterfaces.h index 5e6ba1f..4bc50d9 100644 --- a/content/shell/renderer/test_runner/TestInterfaces.h +++ b/content/shell/renderer/test_runner/TestInterfaces.h @@ -26,6 +26,7 @@ class WebView; namespace content { class AccessibilityController; +class EventSender; class GamepadController; class TestRunner; class TextInputController; @@ -33,7 +34,6 @@ class TextInputController; namespace WebTestRunner { -class EventSender; class WebTestDelegate; class WebTestProxyBase; @@ -54,7 +54,7 @@ public: void windowClosed(WebTestProxyBase*); content::AccessibilityController* accessibilityController(); - EventSender* eventSender(); + content::EventSender* eventSender(); content::TestRunner* testRunner(); WebTestDelegate* delegate(); WebTestProxyBase* proxy(); @@ -63,7 +63,7 @@ public: private: scoped_ptr<content::AccessibilityController> m_accessibilityController; - scoped_ptr<EventSender> m_eventSender; + scoped_ptr<content::EventSender> m_eventSender; scoped_ptr<content::GamepadController> m_gamepadController; scoped_ptr<content::TextInputController> m_textInputController; scoped_ptr<content::TestRunner> m_testRunner; diff --git a/content/shell/renderer/test_runner/WebTestProxy.cpp b/content/shell/renderer/test_runner/WebTestProxy.cpp index 0b8ddd5..9d454a2 100644 --- a/content/shell/renderer/test_runner/WebTestProxy.cpp +++ b/content/shell/renderer/test_runner/WebTestProxy.cpp @@ -6,7 +6,7 @@ #include <cctype> -#include "content/shell/renderer/test_runner/EventSender.h" +#include "content/shell/renderer/test_runner/event_sender.h" #include "content/shell/renderer/test_runner/MockColorChooser.h" #include "content/shell/renderer/test_runner/MockWebSpeechInputController.h" #include "content/shell/renderer/test_runner/MockWebSpeechRecognizer.h" @@ -875,7 +875,7 @@ void WebTestProxyBase::startDragging(WebFrame*, const WebDragData& data, WebDrag { // When running a test, we need to fake a drag drop operation otherwise // Windows waits for real mouse events to know when the drag is over. - m_testInterfaces->eventSender()->doDragDrop(data, mask); + m_testInterfaces->eventSender()->DoDragDrop(data, mask); } // The output from these methods in layout test mode should match that @@ -924,7 +924,7 @@ void WebTestProxyBase::didStopLoading() void WebTestProxyBase::showContextMenu(WebFrame*, const WebContextMenuData& contextMenuData) { - m_testInterfaces->eventSender()->setContextMenuData(contextMenuData); + m_testInterfaces->eventSender()->SetContextMenuData(contextMenuData); } WebUserMediaClient* WebTestProxyBase::userMediaClient() diff --git a/content/shell/renderer/test_runner/event_sender.cc b/content/shell/renderer/test_runner/event_sender.cc new file mode 100644 index 0000000..12063af --- /dev/null +++ b/content/shell/renderer/test_runner/event_sender.cc @@ -0,0 +1,2085 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/shell/renderer/test_runner/event_sender.h" + +#include "base/basictypes.h" +#include "base/logging.h" +#include "base/strings/stringprintf.h" +#include "content/shell/renderer/test_runner/KeyCodeMapping.h" +#include "content/shell/renderer/test_runner/MockSpellCheck.h" +#include "content/shell/renderer/test_runner/TestInterfaces.h" +#include "content/shell/renderer/test_runner/WebTestDelegate.h" +#include "content/shell/renderer/test_runner/WebTestProxy.h" +#include "gin/handle.h" +#include "gin/object_template_builder.h" +#include "gin/wrappable.h" +#include "third_party/WebKit/public/platform/WebString.h" +#include "third_party/WebKit/public/platform/WebVector.h" +#include "third_party/WebKit/public/web/WebContextMenuData.h" +#include "third_party/WebKit/public/web/WebFrame.h" +#include "third_party/WebKit/public/web/WebKit.h" +#include "third_party/WebKit/public/web/WebView.h" +#include "v8/include/v8.h" + +#if defined(OS_WIN) +#include "third_party/WebKit/public/web/win/WebInputEventFactory.h" +#elif defined(OS_MACOSX) +#include "third_party/WebKit/public/web/mac/WebInputEventFactory.h" +#elif defined(OS_ANDROID) +#include "third_party/WebKit/public/web/android/WebInputEventFactory.h" +#elif defined(TOOLKIT_GTK) +#include "third_party/WebKit/public/web/gtk/WebInputEventFactory.h" +#endif + +using blink::WebContextMenuData; +using blink::WebDragData; +using blink::WebDragOperationsMask; +using blink::WebFloatPoint; +using blink::WebFrame; +using blink::WebGestureEvent; +using blink::WebInputEvent; +using blink::WebKeyboardEvent; +using blink::WebMouseEvent; +using blink::WebMouseWheelEvent; +using blink::WebPoint; +using blink::WebString; +using blink::WebTouchEvent; +using blink::WebTouchPoint; +using blink::WebVector; +using blink::WebView; + +#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_ANDROID) || \ + defined(TOOLKIT_GTK) +using blink::WebInputEventFactory; +#endif + +namespace content { + +namespace { + +void InitMouseEvent(WebInputEvent::Type t, + WebMouseEvent::Button b, + const WebPoint& pos, + double time_stamp, + int click_count, + int modifiers, + WebMouseEvent* e) { + e->type = t; + e->button = b; + e->modifiers = modifiers; + e->x = pos.x; + e->y = pos.y; + e->globalX = pos.x; + e->globalY = pos.y; + e->timeStampSeconds = time_stamp; + e->clickCount = click_count; +} + +int GetKeyModifier(const std::string& modifier_name) { + const char* characters = modifier_name.c_str(); + if (!strcmp(characters, "ctrlKey") +#ifndef __APPLE__ + || !strcmp(characters, "addSelectionKey") +#endif + ) { + return WebInputEvent::ControlKey; + } else if (!strcmp(characters, "shiftKey") || + !strcmp(characters, "rangeSelectionKey")) { + return WebInputEvent::ShiftKey; + } else if (!strcmp(characters, "altKey")) { + return WebInputEvent::AltKey; +#ifdef __APPLE__ + } else if (!strcmp(characters, "metaKey") || + !strcmp(characters, "addSelectionKey")) { + return WebInputEvent::MetaKey; +#else + } else if (!strcmp(characters, "metaKey")) { + return WebInputEvent::MetaKey; +#endif + } else if (!strcmp(characters, "autoRepeat")) { + return WebInputEvent::IsAutoRepeat; + } else if (!strcmp(characters, "copyKey")) { +#ifdef __APPLE__ + return WebInputEvent::AltKey; +#else + return WebInputEvent::ControlKey; +#endif + } + + return 0; +} + +int GetKeyModifiers(const std::vector<std::string>& modifier_names) { + int modifiers = 0; + for (std::vector<std::string>::const_iterator it = modifier_names.begin(); + it != modifier_names.end(); ++it) { + modifiers |= GetKeyModifier(*it); + } + return modifiers; +} + +int GetKeyModifiersFromV8(v8::Handle<v8::Value> value) { + std::vector<std::string> modifier_names; + if (value->IsString()) { + modifier_names.push_back(gin::V8ToString(value)); + } else if (value->IsArray()) { + gin::Converter<std::vector<std::string> >::FromV8( + NULL, value, &modifier_names); + } + return GetKeyModifiers(modifier_names); +} + +// Maximum distance (in space and time) for a mouse click to register as a +// double or triple click. +const double kMultipleClickTimeSec = 1; +const int kMultipleClickRadiusPixels = 5; + +bool OutsideMultiClickRadius(const WebPoint& a, const WebPoint& b) { + return ((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)) > + kMultipleClickRadiusPixels * kMultipleClickRadiusPixels; +} + +// Because actual context menu is implemented by the browser side, +// this function does only what LayoutTests are expecting: +// - Many test checks the count of items. So returning non-zero value makes +// sense. +// - Some test compares the count before and after some action. So changing the +// count based on flags also makes sense. This function is doing such for some +// flags. +// - Some test even checks actual string content. So providing it would be also +// helpful. +std::vector<std::string> MakeMenuItemStringsFor( + WebContextMenuData* context_menu, + WebTestRunner::WebTestDelegate* delegate) { + // These constants are based on Safari's context menu because tests are made + // for it. + static const char* kNonEditableMenuStrings[] = { + "Back", + "Reload Page", + "Open in Dashbaord", + "<separator>", + "View Source", + "Save Page As", + "Print Page", + "Inspect Element", + 0 + }; + static const char* kEditableMenuStrings[] = { + "Cut", + "Copy", + "<separator>", + "Paste", + "Spelling and Grammar", + "Substitutions, Transformations", + "Font", + "Speech", + "Paragraph Direction", + "<separator>", + 0 + }; + + // This is possible because mouse events are cancelleable. + if (!context_menu) + return std::vector<std::string>(); + + std::vector<std::string> strings; + + if (context_menu->isEditable) { + for (const char** item = kEditableMenuStrings; *item; ++item) { + strings.push_back(*item); + } + WebVector<WebString> suggestions; + WebTestRunner::MockSpellCheck::fillSuggestionList( + context_menu->misspelledWord, &suggestions); + for (size_t i = 0; i < suggestions.size(); ++i) { + strings.push_back(suggestions[i].utf8()); + } + } else { + for (const char** item = kNonEditableMenuStrings; *item; ++item) { + strings.push_back(*item); + } + } + + return strings; +} + +// How much we should scroll per event - the value here is chosen to match the +// WebKit impl and layout test results. +const float kScrollbarPixelsPerTick = 40.0f; + +WebMouseEvent::Button GetButtonTypeFromButtonNumber(int button_code) { + if (!button_code) + return WebMouseEvent::ButtonLeft; + if (button_code == 2) + return WebMouseEvent::ButtonRight; + return WebMouseEvent::ButtonMiddle; +} + +class MouseDownTask : public WebTestRunner::WebMethodTask<EventSender> { + public: + MouseDownTask(EventSender* obj, int button_number, int modifiers) + : WebMethodTask<EventSender>(obj), + button_number_(button_number), + modifiers_(modifiers) {} + + virtual void runIfValid() OVERRIDE { + m_object->MouseDown(button_number_, modifiers_); + } + + private: + int button_number_; + int modifiers_; +}; + +class MouseUpTask : public WebTestRunner::WebMethodTask<EventSender> { + public: + MouseUpTask(EventSender* obj, int button_number, int modifiers) + : WebMethodTask<EventSender>(obj), + button_number_(button_number), + modifiers_(modifiers) {} + + virtual void runIfValid() OVERRIDE { + m_object->MouseUp(button_number_, modifiers_); + } + + private: + int button_number_; + int modifiers_; +}; + +class KeyDownTask : public WebTestRunner::WebMethodTask<EventSender> { + public: + KeyDownTask(EventSender* obj, + const std::string code_str, + int modifiers, + KeyLocationCode location) + : WebMethodTask<EventSender>(obj), + modifiers_(modifiers), + location_(location) {} + + virtual void runIfValid() OVERRIDE { + m_object->KeyDown(code_str_, modifiers_, location_); + } + + private: + std::string code_str_; + int modifiers_; + KeyLocationCode location_; +}; + +bool NeedsShiftModifier(int keyCode) { + // If code is an uppercase letter, assign a SHIFT key to eventDown.modifier. + return (keyCode & 0xFF) >= 'A' && (keyCode & 0xFF) <= 'Z'; +} + +// Get the edit command corresponding to a keyboard event. +// Returns true if the specified event corresponds to an edit command, the name +// of the edit command will be stored in |*name|. +bool GetEditCommand(const WebKeyboardEvent& event, std::string* name) { +#if defined(OS_MACOSX) +// We only cares about Left,Right,Up,Down keys with Command or Command+Shift +// modifiers. These key events correspond to some special movement and +// selection editor commands. These keys will be marked as system key, which +// prevents them from being handled. Thus they must be handled specially. + if ((event.modifiers & ~WebKeyboardEvent::ShiftKey) != + WebKeyboardEvent::MetaKey) + return false; + + switch (event.windowsKeyCode) { + case WebTestRunner::VKEY_LEFT: + *name = "MoveToBeginningOfLine"; + break; + case WebTestRunner::VKEY_RIGHT: + *name = "MoveToEndOfLine"; + break; + case WebTestRunner::VKEY_UP: + *name = "MoveToBeginningOfDocument"; + break; + case WebTestRunner::VKEY_DOWN: + *name = "MoveToEndOfDocument"; + break; + default: + return false; + } + + if (event.modifiers & WebKeyboardEvent::ShiftKey) + name->append("AndModifySelection"); + + return true; +#else + return false; +#endif +} + +} // namespace + +class EventSenderBindings : public gin::Wrappable<EventSenderBindings> { + public: + static gin::WrapperInfo kWrapperInfo; + + static void Install(base::WeakPtr<EventSender> sender, + blink::WebFrame* frame); + + private: + explicit EventSenderBindings(base::WeakPtr<EventSender> sender); + virtual ~EventSenderBindings(); + + // gin::Wrappable: + virtual gin::ObjectTemplateBuilder GetObjectTemplateBuilder( + v8::Isolate* isolate) OVERRIDE; + + // Bound methods: + void EnableDOMUIEventLogging(); + void FireKeyboardEventsToElement(); + void ClearKillRing(); + std::vector<std::string> ContextClick(); + void TextZoomIn(); + void TextZoomOut(); + void ZoomPageIn(); + void ZoomPageOut(); + void SetPageScaleFactor(float scale_factor, int x, int y); + void ClearTouchPoints(); + void ReleaseTouchPoint(unsigned index); + void UpdateTouchPoint(unsigned index, int x, int y); + void CancelTouchPoint(unsigned index); + void SetTouchModifier(const std::string& key_name, bool set_mask); + void DumpFilenameBeingDragged(); + void GestureFlingCancel(); + void GestureFlingStart(float x, float y, float velocity_x, float velocity_y); + void GestureScrollFirstPoint(int x, int y); + void TouchStart(); + void TouchMove(); + void TouchCancel(); + void TouchEnd(); + void LeapForward(int milliseconds); + void BeginDragWithFiles(const std::vector<std::string>& files); + void AddTouchPoint(gin::Arguments* args); + void MouseDragBegin(); + void MouseDragEnd(); + void MouseMomentumBegin(); + void GestureScrollBegin(gin::Arguments* args); + void GestureScrollEnd(gin::Arguments* args); + void GestureScrollUpdate(gin::Arguments* args); + void GestureScrollUpdateWithoutPropagation(gin::Arguments* args); + void GestureTap(gin::Arguments* args); + void GestureTapDown(gin::Arguments* args); + void GestureShowPress(gin::Arguments* args); + void GestureTapCancel(gin::Arguments* args); + void GestureLongPress(gin::Arguments* args); + void GestureLongTap(gin::Arguments* args); + void GestureTwoFingerTap(gin::Arguments* args); + void ContinuousMouseScrollBy(gin::Arguments* args); + void DispatchMessage(int msg, int wparam, int lparam); + void MouseMoveTo(gin::Arguments* args); + void MouseScrollBy(gin::Arguments* args); + void MouseMomentumScrollBy(gin::Arguments* args); + void MouseMomentumEnd(); + void ScheduleAsynchronousClick(gin::Arguments* args); + void ScheduleAsynchronousKeyDown(gin::Arguments* args); + void MouseDown(gin::Arguments* args); + void MouseUp(gin::Arguments* args); + void KeyDown(gin::Arguments* args); + + // Binding properties: + bool ForceLayoutOnEvents() const; + void SetForceLayoutOnEvents(bool force); + bool IsDragMode() const; + void SetIsDragMode(bool drag_mode); + +#if defined(OS_WIN) + int WmKeyDown() const; + void SetWmKeyDown(int key_down); + + int WmKeyUp() const; + void SetWmKeyUp(int key_up); + + int WmChar() const; + void SetWmChar(int wm_char); + + int WmDeadChar() const; + void SetWmDeadChar(int dead_char); + + int WmSysKeyDown() const; + void SetWmSysKeyDown(int key_down); + + int WmSysKeyUp() const; + void SetWmSysKeyUp(int key_up); + + int WmSysChar() const; + void SetWmSysChar(int sys_char); + + int WmSysDeadChar() const; + void SetWmSysDeadChar(int sys_dead_char); +#endif + + base::WeakPtr<EventSender> sender_; + + DISALLOW_COPY_AND_ASSIGN(EventSenderBindings); +}; + +gin::WrapperInfo EventSenderBindings::kWrapperInfo = {gin::kEmbedderNativeGin}; + +EventSenderBindings::EventSenderBindings(base::WeakPtr<EventSender> sender) + : sender_(sender) { +} + +EventSenderBindings::~EventSenderBindings() {} + +// static +void EventSenderBindings::Install(base::WeakPtr<EventSender> sender, + WebFrame* frame) { + v8::Isolate* isolate = blink::mainThreadIsolate(); + v8::HandleScope handle_scope(isolate); + v8::Handle<v8::Context> context = frame->mainWorldScriptContext(); + if (context.IsEmpty()) + return; + + v8::Context::Scope context_scope(context); + + gin::Handle<EventSenderBindings> bindings = + gin::CreateHandle(isolate, new EventSenderBindings(sender)); + v8::Handle<v8::Object> global = context->Global(); + global->Set(gin::StringToV8(isolate, "eventSender"), bindings.ToV8()); +} + +gin::ObjectTemplateBuilder +EventSenderBindings::GetObjectTemplateBuilder(v8::Isolate* isolate) { + return gin::Wrappable<EventSenderBindings>::GetObjectTemplateBuilder(isolate) + .SetMethod("enableDOMUIEventLogging", + &EventSenderBindings::EnableDOMUIEventLogging) + .SetMethod("fireKeyboardEventsToElement", + &EventSenderBindings::FireKeyboardEventsToElement) + .SetMethod("clearKillRing", &EventSenderBindings::ClearKillRing) + .SetMethod("contextClick", &EventSenderBindings::ContextClick) + .SetMethod("textZoomIn", &EventSenderBindings::TextZoomIn) + .SetMethod("textZoomOut", &EventSenderBindings::TextZoomOut) + .SetMethod("zoomPageIn", &EventSenderBindings::ZoomPageIn) + .SetMethod("zoomPageOut", &EventSenderBindings::ZoomPageOut) + .SetMethod("setPageScaleFactor", &EventSenderBindings::SetPageScaleFactor) + .SetMethod("clearTouchPoints", &EventSenderBindings::ClearTouchPoints) + .SetMethod("releaseTouchPoint", &EventSenderBindings::ReleaseTouchPoint) + .SetMethod("updateTouchPoint", &EventSenderBindings::UpdateTouchPoint) + .SetMethod("cancelTouchPoint", &EventSenderBindings::CancelTouchPoint) + .SetMethod("setTouchModifier", &EventSenderBindings::SetTouchModifier) + .SetMethod("dumpFilenameBeingDragged", + &EventSenderBindings::DumpFilenameBeingDragged) + .SetMethod("gestureFlingCancel", &EventSenderBindings::GestureFlingCancel) + .SetMethod("gestureFlingStart", &EventSenderBindings::GestureFlingStart) + .SetMethod("gestureScrollFirstPoint", + &EventSenderBindings::GestureScrollFirstPoint) + .SetMethod("touchStart", &EventSenderBindings::TouchStart) + .SetMethod("touchMove", &EventSenderBindings::TouchMove) + .SetMethod("touchCancel", &EventSenderBindings::TouchCancel) + .SetMethod("touchEnd", &EventSenderBindings::TouchEnd) + .SetMethod("leapForward", &EventSenderBindings::LeapForward) + .SetMethod("beginDragWithFiles", &EventSenderBindings::BeginDragWithFiles) + .SetMethod("addTouchPoint", &EventSenderBindings::AddTouchPoint) + .SetMethod("mouseDragBegin", &EventSenderBindings::MouseDragBegin) + .SetMethod("mouseDragEnd", &EventSenderBindings::MouseDragEnd) + .SetMethod("mouseMomentumBegin", &EventSenderBindings::MouseMomentumBegin) + .SetMethod("gestureScrollBegin", &EventSenderBindings::GestureScrollBegin) + .SetMethod("gestureScrollEnd", &EventSenderBindings::GestureScrollEnd) + .SetMethod("gestureScrollUpdate", + &EventSenderBindings::GestureScrollUpdate) + .SetMethod("gestureScrollUpdateWithoutPropagation", + &EventSenderBindings::GestureScrollUpdateWithoutPropagation) + .SetMethod("gestureTap", &EventSenderBindings::GestureTap) + .SetMethod("gestureTapDown", &EventSenderBindings::GestureTapDown) + .SetMethod("gestureShowPress", &EventSenderBindings::GestureShowPress) + .SetMethod("gestureTapCancel", &EventSenderBindings::GestureTapCancel) + .SetMethod("gestureLongPress", &EventSenderBindings::GestureLongPress) + .SetMethod("gestureLongTap", &EventSenderBindings::GestureLongTap) + .SetMethod("gestureTwoFingerTap", + &EventSenderBindings::GestureTwoFingerTap) + .SetMethod("continuousMouseScrollBy", + &EventSenderBindings::ContinuousMouseScrollBy) + .SetMethod("dispatchMessage", &EventSenderBindings::DispatchMessage) + .SetMethod("keyDown", &EventSenderBindings::KeyDown) + .SetMethod("mouseDown", &EventSenderBindings::MouseDown) + .SetMethod("mouseMoveTo", &EventSenderBindings::MouseMoveTo) + .SetMethod("mouseScrollBy", &EventSenderBindings::MouseScrollBy) + .SetMethod("mouseUp", &EventSenderBindings::MouseUp) + .SetMethod("mouseMomentumScrollBy", + &EventSenderBindings::MouseMomentumScrollBy) + .SetMethod("mouseMomentumEnd", &EventSenderBindings::MouseMomentumEnd) + .SetMethod("scheduleAsynchronousClick", + &EventSenderBindings::ScheduleAsynchronousClick) + .SetMethod("scheduleAsynchronousKeyDown", + &EventSenderBindings::ScheduleAsynchronousKeyDown) + .SetProperty("forceLayoutOnEvents", + &EventSenderBindings::ForceLayoutOnEvents, + &EventSenderBindings::SetForceLayoutOnEvents) + .SetProperty("dragMode", + &EventSenderBindings::IsDragMode, + &EventSenderBindings::SetIsDragMode) +#if defined(OS_WIN) + .SetProperty("WM_KEYDOWN", + &EventSenderBindings::WmKeyDown, + &EventSenderBindings::SetWmKeyDown) + .SetProperty("WM_KEYUP", + &EventSenderBindings::WmKeyUp, + &EventSenderBindings::SetWmKeyUp) + .SetProperty("WM_CHAR", + &EventSenderBindings::WmChar, + &EventSenderBindings::SetWmChar) + .SetProperty("WM_DEADCHAR", + &EventSenderBindings::WmDeadChar, + &EventSenderBindings::SetWmDeadChar) + .SetProperty("WM_SYSKEYDOWN", + &EventSenderBindings::WmSysKeyDown, + &EventSenderBindings::SetWmSysKeyDown) + .SetProperty("WM_SYSKEYUP", + &EventSenderBindings::WmSysKeyUp, + &EventSenderBindings::SetWmSysKeyUp) + .SetProperty("WM_SYSCHAR", + &EventSenderBindings::WmSysChar, + &EventSenderBindings::SetWmSysChar) + .SetProperty("WM_SYSDEADCHAR", + &EventSenderBindings::WmSysDeadChar, + &EventSenderBindings::SetWmSysDeadChar); +#else + ; +#endif +} + +void EventSenderBindings::EnableDOMUIEventLogging() { + if (sender_) + sender_->EnableDOMUIEventLogging(); +} + +void EventSenderBindings::FireKeyboardEventsToElement() { + if (sender_) + sender_->FireKeyboardEventsToElement(); +} + +void EventSenderBindings::ClearKillRing() { + if (sender_) + sender_->ClearKillRing(); +} + +std::vector<std::string> EventSenderBindings::ContextClick() { + if (sender_) + return sender_->ContextClick(); + return std::vector<std::string>(); +} + +void EventSenderBindings::TextZoomIn() { + if (sender_) + sender_->TextZoomIn(); +} +void EventSenderBindings::TextZoomOut() { + if (sender_) + sender_->TextZoomOut(); +} +void EventSenderBindings::ZoomPageIn() { + if (sender_) + sender_->ZoomPageIn(); +} +void EventSenderBindings::ZoomPageOut() { + if (sender_) + sender_->ZoomPageOut(); +} +void EventSenderBindings::SetPageScaleFactor(float scale_factor, int x, int y) { + if (sender_) + sender_->SetPageScaleFactor(scale_factor, x, y); +} +void EventSenderBindings::ClearTouchPoints() { + if (sender_) + sender_->ClearTouchPoints(); +} +void EventSenderBindings::ReleaseTouchPoint(unsigned index) { + if (sender_) + sender_->ReleaseTouchPoint(index); +} +void EventSenderBindings::UpdateTouchPoint(unsigned index, int x, int y) { + if (sender_) + sender_->UpdateTouchPoint(index, x, y); +} +void EventSenderBindings::CancelTouchPoint(unsigned index) { + if (sender_) + sender_->CancelTouchPoint(index); +} +void EventSenderBindings::SetTouchModifier(const std::string& key_name, + bool set_mask) { + if (sender_) + sender_->SetTouchModifier(key_name, set_mask); +} +void EventSenderBindings::DumpFilenameBeingDragged() { + if (sender_) + sender_->DumpFilenameBeingDragged(); +} +void EventSenderBindings::GestureFlingCancel() { + if (sender_) + sender_->GestureFlingCancel(); +} +void EventSenderBindings::GestureFlingStart(float x, + float y, + float velocity_x, + float velocity_y) { + if (sender_) + sender_->GestureFlingStart(x, y, velocity_x, velocity_y); +} +void EventSenderBindings::GestureScrollFirstPoint(int x, int y) { + if (sender_) + sender_->GestureScrollFirstPoint(x, y); +} +void EventSenderBindings::TouchStart() { + if (sender_) + sender_->TouchStart(); +} +void EventSenderBindings::TouchMove() { + if (sender_) + sender_->TouchMove(); +} +void EventSenderBindings::TouchCancel() { + if (sender_) + sender_->TouchCancel(); +} +void EventSenderBindings::TouchEnd() { + if (sender_) + sender_->TouchEnd(); +} +void EventSenderBindings::LeapForward(int milliseconds) { + if (sender_) + sender_->LeapForward(milliseconds); +} +void EventSenderBindings::BeginDragWithFiles( + const std::vector<std::string>& files) { + if (sender_) + sender_->BeginDragWithFiles(files); +} +void EventSenderBindings::AddTouchPoint(gin::Arguments* args) { + if (sender_) + sender_->AddTouchPoint(args); +} +void EventSenderBindings::MouseDragBegin() { + if (sender_) + sender_->MouseDragBegin(); +} +void EventSenderBindings::MouseDragEnd() { + if (sender_) + sender_->MouseDragEnd(); +} +void EventSenderBindings::MouseMomentumBegin() { + if (sender_) + sender_->MouseMomentumBegin(); +} +void EventSenderBindings::GestureScrollBegin(gin::Arguments* args) { + if (sender_) + sender_->GestureScrollBegin(args); +} +void EventSenderBindings::GestureScrollEnd(gin::Arguments* args) { + if (sender_) + sender_->GestureScrollEnd(args); +} +void EventSenderBindings::GestureScrollUpdate(gin::Arguments* args) { + if (sender_) + sender_->GestureScrollUpdate(args); +} +void EventSenderBindings::GestureScrollUpdateWithoutPropagation( + gin::Arguments* args) { + if (sender_) + sender_->GestureScrollUpdateWithoutPropagation(args); +} +void EventSenderBindings::GestureTap(gin::Arguments* args) { + if (sender_) + sender_->GestureTap(args); +} +void EventSenderBindings::GestureTapDown(gin::Arguments* args) { + if (sender_) + sender_->GestureTapDown(args); +} +void EventSenderBindings::GestureShowPress(gin::Arguments* args) { + if (sender_) + sender_->GestureShowPress(args); +} +void EventSenderBindings::GestureTapCancel(gin::Arguments* args) { + if (sender_) + sender_->GestureTapCancel(args); +} +void EventSenderBindings::GestureLongPress(gin::Arguments* args) { + if (sender_) + sender_->GestureLongPress(args); +} +void EventSenderBindings::GestureLongTap(gin::Arguments* args) { + if (sender_) + sender_->GestureLongTap(args); +} +void EventSenderBindings::GestureTwoFingerTap(gin::Arguments* args) { + if (sender_) + sender_->GestureTwoFingerTap(args); +} +void EventSenderBindings::ContinuousMouseScrollBy(gin::Arguments* args) { + if (sender_) + sender_->ContinuousMouseScrollBy(args); +} +void EventSenderBindings::DispatchMessage(int msg, int wparam, int lparam) { + if (sender_) + sender_->DispatchMessage(msg, wparam, lparam); +} +void EventSenderBindings::MouseMoveTo(gin::Arguments* args) { + if (sender_) + sender_->MouseMoveTo(args); +} +void EventSenderBindings::MouseScrollBy(gin::Arguments* args) { + if (sender_) + sender_->MouseScrollBy(args); +} +void EventSenderBindings::MouseMomentumScrollBy(gin::Arguments* args) { + if (sender_) + sender_->MouseMomentumScrollBy(args); +} +void EventSenderBindings::MouseMomentumEnd() { + if (sender_) + sender_->MouseMomentumEnd(); +} +void EventSenderBindings::ScheduleAsynchronousClick(gin::Arguments* args) { + if (!sender_) + return; + + int button_number = 0; + int modifiers = 0; + if (!args->PeekNext().IsEmpty()) { + args->GetNext(&button_number); + if (!args->PeekNext().IsEmpty()) + modifiers = GetKeyModifiersFromV8(args->PeekNext()); + } + sender_->ScheduleAsynchronousClick(button_number, modifiers); +} +void EventSenderBindings::ScheduleAsynchronousKeyDown(gin::Arguments* args) { + if (!sender_) + return; + + std::string code_str; + int modifiers = 0; + int location = DOMKeyLocationStandard; + args->GetNext(&code_str); + if (!args->PeekNext().IsEmpty()) { + v8::Handle<v8::Value> value; + args->GetNext(&value); + modifiers = GetKeyModifiersFromV8(value); + if (!args->PeekNext().IsEmpty()) + args->GetNext(&location); + } + sender_->ScheduleAsynchronousKeyDown(code_str, modifiers, + static_cast<KeyLocationCode>(location)); +} +void EventSenderBindings::MouseDown(gin::Arguments* args) { + if (!sender_) + return; + + int button_number = 0; + int modifiers = 0; + if (!args->PeekNext().IsEmpty()) { + args->GetNext(&button_number); + if (!args->PeekNext().IsEmpty()) + modifiers = GetKeyModifiersFromV8(args->PeekNext()); + } + sender_->MouseDown(button_number, modifiers); +} +void EventSenderBindings::MouseUp(gin::Arguments* args) { + if (!sender_) + return; + + int button_number = 0; + int modifiers = 0; + if (!args->PeekNext().IsEmpty()) { + args->GetNext(&button_number); + if (!args->PeekNext().IsEmpty()) + modifiers = GetKeyModifiersFromV8(args->PeekNext()); + } + sender_->MouseUp(button_number, modifiers); +} +void EventSenderBindings::KeyDown(gin::Arguments* args) { + if (!sender_) + return; + + std::string code_str; + int modifiers = 0; + int location = DOMKeyLocationStandard; + args->GetNext(&code_str); + if (!args->PeekNext().IsEmpty()) { + v8::Handle<v8::Value> value; + args->GetNext(&value); + modifiers = GetKeyModifiersFromV8(value); + if (!args->PeekNext().IsEmpty()) + args->GetNext(&location); + } + sender_->KeyDown(code_str, modifiers, static_cast<KeyLocationCode>(location)); +} +bool EventSenderBindings::ForceLayoutOnEvents() const { + if (sender_) + return sender_->force_layout_on_events(); + return false; +} +void EventSenderBindings::SetForceLayoutOnEvents(bool force) { + if (sender_) + sender_->set_force_layout_on_events(force); +} +bool EventSenderBindings::IsDragMode() const { + if (sender_) + return sender_->is_drag_mode(); + return false; +} +void EventSenderBindings::SetIsDragMode(bool drag_mode) { + if (sender_) + sender_->set_is_drag_mode(drag_mode); +} + +#if defined(OS_WIN) +int EventSenderBindings::WmKeyDown() const { + if (sender_) + return sender_->wm_key_down(); + return 0; +} +void EventSenderBindings::SetWmKeyDown(int key_down) { + if (sender_) + sender_->set_wm_key_down(key_down); +} + +int EventSenderBindings::WmKeyUp() const { + if (sender_) + return sender_->wm_key_up(); + return 0; +} +void EventSenderBindings::SetWmKeyUp(int key_up) { + if (sender_) + sender_->set_wm_key_up(key_up); +} + +int EventSenderBindings::WmChar() const { + if (sender_) + return sender_->wm_char(); + return 0; +} +void EventSenderBindings::SetWmChar(int wm_char) { + if (sender_) + sender_->set_wm_char(wm_char); +} + +int EventSenderBindings::WmDeadChar() const { + if (sender_) + return sender_->wm_dead_char(); + return 0; +} +void EventSenderBindings::SetWmDeadChar(int dead_char) { + if (sender_) + sender_->set_wm_dead_char(dead_char); +} + +int EventSenderBindings::WmSysKeyDown() const { + if (sender_) + return sender_->wm_sys_key_down(); + return 0; +} +void EventSenderBindings::SetWmSysKeyDown(int key_down) { + if (sender_) + sender_->set_wm_sys_key_down(key_down); +} + +int EventSenderBindings::WmSysKeyUp() const { + if (sender_) + return sender_->wm_sys_key_up(); + return 0; +} +void EventSenderBindings::SetWmSysKeyUp(int key_up) { + if (sender_) + sender_->set_wm_sys_key_up(key_up); +} + +int EventSenderBindings::WmSysChar() const { + if (sender_) + return sender_->wm_sys_char(); + return 0; +} +void EventSenderBindings::SetWmSysChar(int sys_char) { + if (sender_) + sender_->set_wm_sys_char(sys_char); +} + +int EventSenderBindings::WmSysDeadChar() const { + if (sender_) + return sender_->wm_sys_dead_char(); + return 0; +} +void EventSenderBindings::SetWmSysDeadChar(int sys_dead_char) { + if (sender_) + sender_->set_wm_sys_dead_char(sys_dead_char); +} +#endif + +// EventSender ----------------------------------------------------------------- + +WebMouseEvent::Button EventSender::pressed_button_ = WebMouseEvent::ButtonNone; + +WebPoint EventSender::last_mouse_pos_; + +WebMouseEvent::Button EventSender::last_button_type_ = + WebMouseEvent::ButtonNone; + +EventSender::SavedEvent::SavedEvent() + : type(TYPE_UNSPECIFIED), + button_type(WebMouseEvent::ButtonNone), + milliseconds(0), + modifiers(0) {} + +EventSender::EventSender(WebTestRunner::TestInterfaces* interfaces) + : interfaces_(interfaces), + delegate_(NULL), + view_(NULL), + force_layout_on_events_(false), + is_drag_mode_(true), + touch_modifiers_(0), + replaying_saved_events_(false), + current_drag_effects_allowed_(blink::WebDragOperationNone), + last_click_time_sec_(0), + current_drag_effect_(blink::WebDragOperationNone), + time_offset_ms_(0), + click_count_(0), +#if defined(OS_WIN) + wm_key_down_(0), + wm_key_up_(0), + wm_char_(0), + wm_dead_char_(0), + wm_sys_key_down_(0), + wm_sys_key_up_(0), + wm_sys_char_(0), + wm_sys_dead_char_(0), +#endif + weak_factory_(this) {} + +EventSender::~EventSender() {} + +void EventSender::Reset() { + DCHECK(current_drag_data_.isNull()); + current_drag_data_.reset(); + current_drag_effect_ = blink::WebDragOperationNone; + current_drag_effects_allowed_ = blink::WebDragOperationNone; + if (view_ && pressed_button_ != WebMouseEvent::ButtonNone) + view_->mouseCaptureLost(); + pressed_button_ = WebMouseEvent::ButtonNone; + is_drag_mode_ = true; + force_layout_on_events_ = true; + +#if defined(OS_WIN) + wm_key_down_ = WM_KEYDOWN; + wm_key_up_ = WM_KEYUP; + wm_char_ = WM_CHAR; + wm_dead_char_ = WM_DEADCHAR; + wm_sys_key_down_ = WM_SYSKEYDOWN; + wm_sys_key_up_ = WM_SYSKEYUP; + wm_sys_char_ = WM_SYSCHAR; + wm_sys_dead_char_ = WM_SYSDEADCHAR; +#endif + + last_mouse_pos_ = WebPoint(0, 0); + last_click_time_sec_ = 0; + last_click_pos_ = WebPoint(0, 0); + last_button_type_ = WebMouseEvent::ButtonNone; + touch_points_.clear(); + task_list_.revokeAll(); + current_gesture_location_ = WebPoint(0, 0); + mouse_event_queue_.clear(); + + time_offset_ms_ = 0; + click_count_ = 0; +} + +void EventSender::Install(WebFrame* frame) { + EventSenderBindings::Install(weak_factory_.GetWeakPtr(), frame); +} + +void EventSender::SetDelegate(WebTestRunner::WebTestDelegate* delegate) { + delegate_ = delegate; +} + +void EventSender::SetWebView(WebView* view) { + view_ = view; +} + +void EventSender::SetContextMenuData(const WebContextMenuData& data) { + last_context_menu_data_.reset(new WebContextMenuData(data)); +} + +void EventSender::DoDragDrop(const WebDragData& drag_data, + WebDragOperationsMask mask) { + WebMouseEvent event; + InitMouseEvent(WebInputEvent::MouseDown, + pressed_button_, + last_mouse_pos_, + GetCurrentEventTimeSec(), + click_count_, + 0, + &event); + WebPoint client_point(event.x, event.y); + WebPoint screen_point(event.globalX, event.globalY); + current_drag_data_ = drag_data; + current_drag_effects_allowed_ = mask; + current_drag_effect_ = view_->dragTargetDragEnter( + drag_data, client_point, screen_point, current_drag_effects_allowed_, 0); + + // Finish processing events. + ReplaySavedEvents(); +} + +void EventSender::MouseDown(int button_number, int modifiers) { + if (force_layout_on_events_) + view_->layout(); + + DCHECK_NE(-1, button_number); + + WebMouseEvent::Button button_type = + GetButtonTypeFromButtonNumber(button_number); + + UpdateClickCountForButton(button_type); + + pressed_button_ = button_type; + + WebMouseEvent event; + InitMouseEvent(WebInputEvent::MouseDown, + button_type, + last_mouse_pos_, + GetCurrentEventTimeSec(), + click_count_, + modifiers, + &event); + view_->handleInputEvent(event); +} + +void EventSender::MouseUp(int button_number, int modifiers) { + if (force_layout_on_events_) + view_->layout(); + + DCHECK_NE(-1, button_number); + + WebMouseEvent::Button button_type = + GetButtonTypeFromButtonNumber(button_number); + + if (is_drag_mode_ && !replaying_saved_events_) { + SavedEvent saved_event; + saved_event.type = SavedEvent::TYPE_MOUSE_UP; + saved_event.button_type = button_type; + saved_event.modifiers = modifiers; + mouse_event_queue_.push_back(saved_event); + ReplaySavedEvents(); + } else { + WebMouseEvent event; + InitMouseEvent(WebInputEvent::MouseUp, + button_type, + last_mouse_pos_, + GetCurrentEventTimeSec(), + click_count_, + modifiers, + &event); + DoMouseUp(event); + } +} + +void EventSender::KeyDown(const std::string& code_str, + int modifiers, + KeyLocationCode location) { + // FIXME: I'm not exactly sure how we should convert the string to a key + // event. This seems to work in the cases I tested. + // FIXME: Should we also generate a KEY_UP? + + bool generate_char = false; + + // Convert \n -> VK_RETURN. Some layout tests use \n to mean "Enter", when + // Windows uses \r for "Enter". + int code = 0; + int text = 0; + bool needs_shift_key_modifier = false; + + if ("\n" == code_str) { + generate_char = true; + text = code = WebTestRunner::VKEY_RETURN; + } else if ("rightArrow" == code_str) { + code = WebTestRunner::VKEY_RIGHT; + } else if ("downArrow" == code_str) { + code = WebTestRunner::VKEY_DOWN; + } else if ("leftArrow" == code_str) { + code = WebTestRunner::VKEY_LEFT; + } else if ("upArrow" == code_str) { + code = WebTestRunner::VKEY_UP; + } else if ("insert" == code_str) { + code = WebTestRunner::VKEY_INSERT; + } else if ("delete" == code_str) { + code = WebTestRunner::VKEY_DELETE; + } else if ("pageUp" == code_str) { + code = WebTestRunner::VKEY_PRIOR; + } else if ("pageDown" == code_str) { + code = WebTestRunner::VKEY_NEXT; + } else if ("home" == code_str) { + code = WebTestRunner::VKEY_HOME; + } else if ("end" == code_str) { + code = WebTestRunner::VKEY_END; + } else if ("printScreen" == code_str) { + code = WebTestRunner::VKEY_SNAPSHOT; + } else if ("menu" == code_str) { + code = WebTestRunner::VKEY_APPS; + } else if ("leftControl" == code_str) { + code = WebTestRunner::VKEY_LCONTROL; + } else if ("rightControl" == code_str) { + code = WebTestRunner::VKEY_RCONTROL; + } else if ("leftShift" == code_str) { + code = WebTestRunner::VKEY_LSHIFT; + } else if ("rightShift" == code_str) { + code = WebTestRunner::VKEY_RSHIFT; + } else if ("leftAlt" == code_str) { + code = WebTestRunner::VKEY_LMENU; + } else if ("rightAlt" == code_str) { + code = WebTestRunner::VKEY_RMENU; + } else if ("numLock" == code_str) { + code = WebTestRunner::VKEY_NUMLOCK; + } else { + // Compare the input string with the function-key names defined by the + // DOM spec (i.e. "F1",...,"F24"). If the input string is a function-key + // name, set its key code. + for (int i = 1; i <= 24; ++i) { + std::string function_key_name = base::StringPrintf("F%d", i); + if (function_key_name == code_str) { + code = WebTestRunner::VKEY_F1 + (i - 1); + break; + } + } + if (!code) { + WebString web_code_str = + WebString::fromUTF8(code_str.data(), code_str.size()); + DCHECK_EQ(1u, web_code_str.length()); + text = code = web_code_str.at(0); + needs_shift_key_modifier = NeedsShiftModifier(code); + if ((code & 0xFF) >= 'a' && (code & 0xFF) <= 'z') + code -= 'a' - 'A'; + generate_char = true; + } + + if ("(" == code_str) { + code = '9'; + needs_shift_key_modifier = true; + } + } + + // For one generated keyboard event, we need to generate a keyDown/keyUp + // pair; + // On Windows, we might also need to generate a char event to mimic the + // Windows event flow; on other platforms we create a merged event and test + // the event flow that that platform provides. + WebKeyboardEvent event_down; + event_down.type = WebInputEvent::RawKeyDown; + event_down.modifiers = modifiers; + event_down.windowsKeyCode = code; + +#if defined(OS_LINUX) && defined(TOOLKIT_GTK) + event_down.nativeKeyCode = NativeKeyCodeForWindowsKeyCode(code); +#endif + + if (generate_char) { + event_down.text[0] = text; + event_down.unmodifiedText[0] = text; + } + + event_down.setKeyIdentifierFromWindowsKeyCode(); + +#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_ANDROID) || \ + defined(TOOLKIT_GTK) + if (event_down.modifiers != 0) + event_down.isSystemKey = WebInputEventFactory::isSystemKeyEvent(event_down); +#endif + + if (needs_shift_key_modifier) + event_down.modifiers |= WebInputEvent::ShiftKey; + + // See if KeyLocation argument is given. + if (location == DOMKeyLocationNumpad) + event_down.modifiers |= WebInputEvent::IsKeyPad; + + WebKeyboardEvent event_up; + event_up = event_down; + event_up.type = WebInputEvent::KeyUp; + // EventSender.m forces a layout here, with at least one + // test (fast/forms/focus-control-to-page.html) relying on this. + if (force_layout_on_events_) + view_->layout(); + + // In the browser, if a keyboard event corresponds to an editor command, + // the command will be dispatched to the renderer just before dispatching + // the keyboard event, and then it will be executed in the + // RenderView::handleCurrentKeyboardEvent() method. + // We just simulate the same behavior here. + std::string edit_command; + if (GetEditCommand(event_down, &edit_command)) + delegate_->setEditCommand(edit_command, ""); + + view_->handleInputEvent(event_down); + + if (code == WebTestRunner::VKEY_ESCAPE && !current_drag_data_.isNull()) { + WebMouseEvent event; + InitMouseEvent(WebInputEvent::MouseDown, + pressed_button_, + last_mouse_pos_, + GetCurrentEventTimeSec(), + click_count_, + 0, + &event); + FinishDragAndDrop(event, blink::WebDragOperationNone); + } + + delegate_->clearEditCommand(); + + if (generate_char) { + WebKeyboardEvent event_char = event_up; + event_char.type = WebInputEvent::Char; + event_char.keyIdentifier[0] = '\0'; + view_->handleInputEvent(event_char); + } + + view_->handleInputEvent(event_up); +} + +void EventSender::EnableDOMUIEventLogging() {} + +void EventSender::FireKeyboardEventsToElement() {} + +void EventSender::ClearKillRing() {} + +std::vector<std::string> EventSender::ContextClick() { + if (force_layout_on_events_) { + view_->layout(); + } + + UpdateClickCountForButton(WebMouseEvent::ButtonRight); + + // Clears last context menu data because we need to know if the context menu + // be requested after following mouse events. + last_context_menu_data_.reset(); + + // Generate right mouse down and up. + WebMouseEvent event; + // This is a hack to work around only allowing a single pressed button since + // we want to test the case where both the left and right mouse buttons are + // pressed. + if (pressed_button_ == WebMouseEvent::ButtonNone) { + pressed_button_ = WebMouseEvent::ButtonRight; + } + InitMouseEvent(WebInputEvent::MouseDown, + WebMouseEvent::ButtonRight, + last_mouse_pos_, + GetCurrentEventTimeSec(), + click_count_, + 0, + &event); + view_->handleInputEvent(event); + +#if defined(OS_WIN) + InitMouseEvent(WebInputEvent::MouseUp, + WebMouseEvent::ButtonRight, + last_mouse_pos_, + GetCurrentEventTimeSec(), + click_count_, + 0, + &event); + view_->handleInputEvent(event); + + pressed_button_= WebMouseEvent::ButtonNone; +#endif + + return MakeMenuItemStringsFor(last_context_menu_data_.release(), delegate_); +} + +void EventSender::TextZoomIn() { + view_->setTextZoomFactor(view_->textZoomFactor() * 1.2f); +} + +void EventSender::TextZoomOut() { + view_->setTextZoomFactor(view_->textZoomFactor() / 1.2f); +} + +void EventSender::ZoomPageIn() { + const std::vector<WebTestRunner::WebTestProxyBase*>& window_list = + interfaces_->windowList(); + + for (size_t i = 0; i < window_list.size(); ++i) { + window_list.at(i)->webView()->setZoomLevel( + window_list.at(i)->webView()->zoomLevel() + 1); + } +} + +void EventSender::ZoomPageOut() { + const std::vector<WebTestRunner::WebTestProxyBase*>& window_list = + interfaces_->windowList(); + + for (size_t i = 0; i < window_list.size(); ++i) { + window_list.at(i)->webView()->setZoomLevel( + window_list.at(i)->webView()->zoomLevel() - 1); + } +} + +void EventSender::SetPageScaleFactor(float scale_factor, int x, int y) { + view_->setPageScaleFactorLimits(scale_factor, scale_factor); + view_->setPageScaleFactor(scale_factor, WebPoint(x, y)); +} + +void EventSender::ClearTouchPoints() { + touch_points_.clear(); +} + +void EventSender::ReleaseTouchPoint(unsigned index) { + DCHECK_LT(index, touch_points_.size()); + + WebTouchPoint* touch_point = &touch_points_[index]; + touch_point->state = WebTouchPoint::StateReleased; +} + +void EventSender::UpdateTouchPoint(unsigned index, int x, int y) { + DCHECK_LT(index, touch_points_.size()); + + WebTouchPoint* touch_point = &touch_points_[index]; + touch_point->state = WebTouchPoint::StateMoved; + touch_point->position = WebFloatPoint(x, y); + touch_point->screenPosition = touch_point->position; +} + +void EventSender::CancelTouchPoint(unsigned index) { + DCHECK_LT(index, touch_points_.size()); + + WebTouchPoint* touch_point = &touch_points_[index]; + touch_point->state = WebTouchPoint::StateCancelled; +} + +void EventSender::SetTouchModifier(const std::string& key_name, + bool set_mask) { + int mask = 0; + if (key_name == "shift") + mask = WebInputEvent::ShiftKey; + else if (key_name == "alt") + mask = WebInputEvent::AltKey; + else if (key_name == "ctrl") + mask = WebInputEvent::ControlKey; + else if (key_name == "meta") + mask = WebInputEvent::MetaKey; + + if (set_mask) + touch_modifiers_ |= mask; + else + touch_modifiers_ &= ~mask; +} + +void EventSender::DumpFilenameBeingDragged() { + WebString filename; + WebVector<WebDragData::Item> items = current_drag_data_.items(); + for (size_t i = 0; i < items.size(); ++i) { + if (items[i].storageType == WebDragData::Item::StorageTypeBinaryData) { + filename = items[i].title; + break; + } + } + delegate_->printMessage(std::string("Filename being dragged: ") + + filename.utf8().data() + "\n"); +} + +void EventSender::GestureFlingCancel() { + WebGestureEvent event; + event.type = WebInputEvent::GestureFlingCancel; + event.timeStampSeconds = GetCurrentEventTimeSec(); + + if (force_layout_on_events_) + view_->layout(); + + view_->handleInputEvent(event); +} + +void EventSender::GestureFlingStart(float x, + float y, + float velocity_x, + float velocity_y) { + WebGestureEvent event; + event.type = WebInputEvent::GestureFlingStart; + + event.x = x; + event.y = y; + event.globalX = event.x; + event.globalY = event.y; + + event.data.flingStart.velocityX = velocity_x; + event.data.flingStart.velocityY = velocity_y; + event.timeStampSeconds = GetCurrentEventTimeSec(); + + if (force_layout_on_events_) + view_->layout(); + + view_->handleInputEvent(event); +} + +void EventSender::GestureScrollFirstPoint(int x, int y) { + current_gesture_location_ = WebPoint(x, y); +} + +void EventSender::TouchStart() { + SendCurrentTouchEvent(WebInputEvent::TouchStart); +} + +void EventSender::TouchMove() { + SendCurrentTouchEvent(WebInputEvent::TouchMove); +} + +void EventSender::TouchCancel() { + SendCurrentTouchEvent(WebInputEvent::TouchCancel); +} + +void EventSender::TouchEnd() { + SendCurrentTouchEvent(WebInputEvent::TouchEnd); +} + +void EventSender::LeapForward(int milliseconds) { + if (is_drag_mode_ && pressed_button_ == WebMouseEvent::ButtonLeft && + !replaying_saved_events_) { + SavedEvent saved_event; + saved_event.type = SavedEvent::TYPE_LEAP_FORWARD; + saved_event.milliseconds = milliseconds; + mouse_event_queue_.push_back(saved_event); + } else { + DoLeapForward(milliseconds); + } +} + +void EventSender::BeginDragWithFiles(const std::vector<std::string>& files) { + current_drag_data_.initialize(); + WebVector<WebString> absolute_filenames(files.size()); + for (size_t i = 0; i < files.size(); ++i) { + WebDragData::Item item; + item.storageType = WebDragData::Item::StorageTypeFilename; + item.filenameData = delegate_->getAbsoluteWebStringFromUTF8Path(files[i]); + current_drag_data_.addItem(item); + absolute_filenames[i] = item.filenameData; + } + current_drag_data_.setFilesystemId( + delegate_->registerIsolatedFileSystem(absolute_filenames)); + current_drag_effects_allowed_ = blink::WebDragOperationCopy; + + // Provide a drag source. + view_->dragTargetDragEnter(current_drag_data_, + last_mouse_pos_, + last_mouse_pos_, + current_drag_effects_allowed_, + 0); + // |is_drag_mode_| saves events and then replays them later. We don't + // need/want that. + is_drag_mode_ = false; + + // Make the rest of eventSender think a drag is in progress. + pressed_button_ = WebMouseEvent::ButtonLeft; +} + +void EventSender::AddTouchPoint(gin::Arguments* args) { + int x; + int y; + args->GetNext(&x); + args->GetNext(&y); + + WebTouchPoint touch_point; + touch_point.state = WebTouchPoint::StatePressed; + touch_point.position = WebFloatPoint(x, y); + touch_point.screenPosition = touch_point.position; + + if (!args->PeekNext().IsEmpty()) { + int radius_x; + if (!args->GetNext(&radius_x)) { + args->ThrowError(); + return; + } + + int radius_y = radius_x; + if (!args->PeekNext().IsEmpty()) { + if (!args->GetNext(&radius_y)) { + args->ThrowError(); + return; + } + } + + touch_point.radiusX = radius_x; + touch_point.radiusY = radius_y; + } + + int lowest_id = 0; + for (size_t i = 0; i < touch_points_.size(); i++) { + if (touch_points_[i].id == lowest_id) + lowest_id++; + } + touch_point.id = lowest_id; + touch_points_.push_back(touch_point); +} + +void EventSender::MouseDragBegin() { + WebMouseWheelEvent event; + InitMouseEvent(WebInputEvent::MouseWheel, + WebMouseEvent::ButtonNone, + last_mouse_pos_, + GetCurrentEventTimeSec(), + click_count_, + 0, + &event); + event.phase = WebMouseWheelEvent::PhaseBegan; + event.hasPreciseScrollingDeltas = true; + view_->handleInputEvent(event); +} + +void EventSender::MouseDragEnd() { + WebMouseWheelEvent event; + InitMouseEvent(WebInputEvent::MouseWheel, + WebMouseEvent::ButtonNone, + last_mouse_pos_, + GetCurrentEventTimeSec(), + click_count_, + 0, + &event); + event.phase = WebMouseWheelEvent::PhaseEnded; + event.hasPreciseScrollingDeltas = true; + view_->handleInputEvent(event); +} + +void EventSender::MouseMomentumBegin() { + WebMouseWheelEvent event; + InitMouseEvent(WebInputEvent::MouseWheel, + WebMouseEvent::ButtonNone, + last_mouse_pos_, + GetCurrentEventTimeSec(), + click_count_, + 0, + &event); + event.momentumPhase = WebMouseWheelEvent::PhaseBegan; + event.hasPreciseScrollingDeltas = true; + view_->handleInputEvent(event); +} + +void EventSender::GestureScrollBegin(gin::Arguments* args) { + GestureEvent(WebInputEvent::GestureScrollBegin, args); +} + +void EventSender::GestureScrollEnd(gin::Arguments* args) { + GestureEvent(WebInputEvent::GestureScrollEnd, args); +} + +void EventSender::GestureScrollUpdate(gin::Arguments* args) { + GestureEvent(WebInputEvent::GestureScrollUpdate, args); +} + +void EventSender::GestureScrollUpdateWithoutPropagation(gin::Arguments* args) { + GestureEvent(WebInputEvent::GestureScrollUpdateWithoutPropagation, args); +} + +void EventSender::GestureTap(gin::Arguments* args) { + GestureEvent(WebInputEvent::GestureTap, args); +} + +void EventSender::GestureTapDown(gin::Arguments* args) { + GestureEvent(WebInputEvent::GestureTapDown, args); +} + +void EventSender::GestureShowPress(gin::Arguments* args) { + GestureEvent(WebInputEvent::GestureShowPress, args); +} + +void EventSender::GestureTapCancel(gin::Arguments* args) { + GestureEvent(WebInputEvent::GestureTapCancel, args); +} + +void EventSender::GestureLongPress(gin::Arguments* args) { + GestureEvent(WebInputEvent::GestureLongPress, args); +} + +void EventSender::GestureLongTap(gin::Arguments* args) { + GestureEvent(WebInputEvent::GestureLongTap, args); +} + +void EventSender::GestureTwoFingerTap(gin::Arguments* args) { + GestureEvent(WebInputEvent::GestureTwoFingerTap, args); +} + +void EventSender::ContinuousMouseScrollBy(gin::Arguments* args) { + WebMouseWheelEvent event; + InitMouseWheelEvent(args, true, &event); + view_->handleInputEvent(event); +} + +void EventSender::DispatchMessage(int msg, int wparam, int lparam) { +#if defined(OS_WIN) + // WebKit's version of this function stuffs a MSG struct and uses + // TranslateMessage and DispatchMessage. We use a WebKeyboardEvent, which + // doesn't need to receive the DeadChar and SysDeadChar messages. + if (msg == WM_DEADCHAR || msg == WM_SYSDEADCHAR) + return; + + if (force_layout_on_events_) + view_->layout(); + + view_->handleInputEvent( + WebInputEventFactory::keyboardEvent(0, msg, wparam, lparam)); +#endif +} + +void EventSender::MouseMoveTo(gin::Arguments* args) { + if (force_layout_on_events_) + view_->layout(); + + int x; + int y; + args->GetNext(&x); + args->GetNext(&y); + WebPoint mouse_pos(x, y); + + int modifiers = 0; + if (!args->PeekNext().IsEmpty()) + modifiers = GetKeyModifiersFromV8(args->PeekNext()); + + if (is_drag_mode_ && pressed_button_ == WebMouseEvent::ButtonLeft && + !replaying_saved_events_) { + SavedEvent saved_event; + saved_event.type = SavedEvent::TYPE_MOUSE_MOVE; + saved_event.pos = mouse_pos; + saved_event.modifiers = modifiers; + mouse_event_queue_.push_back(saved_event); + } else { + WebMouseEvent event; + InitMouseEvent(WebInputEvent::MouseMove, + pressed_button_, + mouse_pos, + GetCurrentEventTimeSec(), + click_count_, + modifiers, + &event); + DoMouseMove(event); + } +} + +void EventSender::MouseScrollBy(gin::Arguments* args) { + WebMouseWheelEvent event; + InitMouseWheelEvent(args, false, &event); + view_->handleInputEvent(event); +} + +void EventSender::MouseMomentumScrollBy(gin::Arguments* args) { + WebMouseWheelEvent event; + InitMouseWheelEvent(args, true, &event); + event.momentumPhase = WebMouseWheelEvent::PhaseChanged; + event.hasPreciseScrollingDeltas = true; + view_->handleInputEvent(event); +} + +void EventSender::MouseMomentumEnd() { + WebMouseWheelEvent event; + InitMouseEvent(WebInputEvent::MouseWheel, + WebMouseEvent::ButtonNone, + last_mouse_pos_, + GetCurrentEventTimeSec(), + click_count_, + 0, + &event); + event.momentumPhase = WebMouseWheelEvent::PhaseEnded; + event.hasPreciseScrollingDeltas = true; + view_->handleInputEvent(event); +} + +void EventSender::ScheduleAsynchronousClick(int button_number, int modifiers) { + delegate_->postTask(new MouseDownTask(this, button_number, modifiers)); + delegate_->postTask(new MouseUpTask(this, button_number, modifiers)); +} + +void EventSender::ScheduleAsynchronousKeyDown(const std::string& code_str, + int modifiers, + KeyLocationCode location) { + delegate_->postTask(new KeyDownTask(this, code_str, modifiers, location)); +} + +double EventSender::GetCurrentEventTimeSec() { + return (delegate_->getCurrentTimeInMillisecond() + time_offset_ms_) / 1000.0; +} + +void EventSender::DoLeapForward(int milliseconds) { + time_offset_ms_ += milliseconds; +} + +void EventSender::SendCurrentTouchEvent(WebInputEvent::Type type) { + DCHECK_GT(static_cast<unsigned>(WebTouchEvent::touchesLengthCap), + touch_points_.size()); + if (force_layout_on_events_) + view_->layout(); + + WebTouchEvent touch_event; + touch_event.type = type; + touch_event.modifiers = touch_modifiers_; + touch_event.timeStampSeconds = GetCurrentEventTimeSec(); + touch_event.touchesLength = touch_points_.size(); + for (size_t i = 0; i < touch_points_.size(); ++i) + touch_event.touches[i] = touch_points_[i]; + view_->handleInputEvent(touch_event); + + for (size_t i = 0; i < touch_points_.size(); ++i) { + WebTouchPoint* touch_point = &touch_points_[i]; + if (touch_point->state == WebTouchPoint::StateReleased) { + touch_points_.erase(touch_points_.begin() + i); + --i; + } else + touch_point->state = WebTouchPoint::StateStationary; + } +} + +void EventSender::GestureEvent(WebInputEvent::Type type, + gin::Arguments* args) { + double x; + double y; + args->GetNext(&x); + args->GetNext(&y); + WebPoint point(x, y); + + WebGestureEvent event; + event.type = type; + + switch (type) { + case WebInputEvent::GestureScrollUpdate: + case WebInputEvent::GestureScrollUpdateWithoutPropagation: + event.data.scrollUpdate.deltaX = static_cast<float>(x); + event.data.scrollUpdate.deltaY = static_cast<float>(y); + event.x = current_gesture_location_.x; + event.y = current_gesture_location_.y; + current_gesture_location_.x = + current_gesture_location_.x + event.data.scrollUpdate.deltaX; + current_gesture_location_.y = + current_gesture_location_.y + event.data.scrollUpdate.deltaY; + break; + case WebInputEvent::GestureScrollBegin: + current_gesture_location_ = WebPoint(point.x, point.y); + event.x = current_gesture_location_.x; + event.y = current_gesture_location_.y; + break; + case WebInputEvent::GestureScrollEnd: + case WebInputEvent::GestureFlingStart: + event.x = current_gesture_location_.x; + event.y = current_gesture_location_.y; + break; + case WebInputEvent::GestureTap: + if (!args->PeekNext().IsEmpty()) { + float tap_count; + if (!args->GetNext(&tap_count)) { + args->ThrowError(); + return; + } + event.data.tap.tapCount = tap_count; + } else { + event.data.tap.tapCount = 1; + } + + event.x = point.x; + event.y = point.y; + break; + case WebInputEvent::GestureTapUnconfirmed: + if (!args->PeekNext().IsEmpty()) { + float tap_count; + if (!args->GetNext(&tap_count)) { + args->ThrowError(); + return; + } + event.data.tap.tapCount = tap_count; + } else { + event.data.tap.tapCount = 1; + } + event.x = point.x; + event.y = point.y; + break; + case WebInputEvent::GestureTapDown: + event.x = point.x; + event.y = point.y; + if (!args->PeekNext().IsEmpty()) { + float width; + if (!args->GetNext(&width)) { + args->ThrowError(); + return; + } + event.data.tapDown.width = width; + } + if (!args->PeekNext().IsEmpty()) { + float height; + if (!args->GetNext(&height)) { + args->ThrowError(); + return; + } + event.data.tapDown.height = height; + } + break; + case WebInputEvent::GestureShowPress: + event.x = point.x; + event.y = point.y; + if (!args->PeekNext().IsEmpty()) { + float width; + if (!args->GetNext(&width)) { + args->ThrowError(); + return; + } + event.data.showPress.width = width; + if (!args->PeekNext().IsEmpty()) { + float height; + if (!args->GetNext(&height)) { + args->ThrowError(); + return; + } + event.data.showPress.height = height; + } + } + break; + case WebInputEvent::GestureTapCancel: + event.x = point.x; + event.y = point.y; + break; + case WebInputEvent::GestureLongPress: + event.x = point.x; + event.y = point.y; + if (!args->PeekNext().IsEmpty()) { + float width; + if (!args->GetNext(&width)) { + args->ThrowError(); + return; + } + event.data.longPress.width = width; + if (!args->PeekNext().IsEmpty()) { + float height; + if (!args->GetNext(&height)) { + args->ThrowError(); + return; + } + event.data.longPress.height = height; + } + } + break; + case WebInputEvent::GestureLongTap: + event.x = point.x; + event.y = point.y; + if (!args->PeekNext().IsEmpty()) { + float width; + if (!args->GetNext(&width)) { + args->ThrowError(); + return; + } + event.data.longPress.width = width; + if (!args->PeekNext().IsEmpty()) { + float height; + if (!args->GetNext(&height)) { + args->ThrowError(); + return; + } + event.data.longPress.height = height; + } + } + break; + case WebInputEvent::GestureTwoFingerTap: + event.x = point.x; + event.y = point.y; + if (!args->PeekNext().IsEmpty()) { + float first_finger_width; + if (!args->GetNext(&first_finger_width)) { + args->ThrowError(); + return; + } + event.data.twoFingerTap.firstFingerWidth = first_finger_width; + if (!args->PeekNext().IsEmpty()) { + float first_finger_height; + if (!args->GetNext(&first_finger_height)) { + args->ThrowError(); + return; + } + event.data.twoFingerTap.firstFingerHeight = first_finger_height; + } + } + break; + default: + NOTREACHED(); + } + + event.globalX = event.x; + event.globalY = event.y; + event.timeStampSeconds = GetCurrentEventTimeSec(); + + if (force_layout_on_events_) + view_->layout(); + + view_->handleInputEvent(event); + + // Long press might start a drag drop session. Complete it if so. + if (type == WebInputEvent::GestureLongPress && !current_drag_data_.isNull()) { + WebMouseEvent mouse_event; + InitMouseEvent(WebInputEvent::MouseDown, + pressed_button_, + point, + GetCurrentEventTimeSec(), + click_count_, + 0, + &mouse_event); + + FinishDragAndDrop(mouse_event, blink::WebDragOperationNone); + } +} + +void EventSender::UpdateClickCountForButton( + WebMouseEvent::Button button_type) { + if ((GetCurrentEventTimeSec() - last_click_time_sec_ < + kMultipleClickTimeSec) && + (!OutsideMultiClickRadius(last_mouse_pos_, last_click_pos_)) && + (button_type == last_button_type_)) { + ++click_count_; + } else { + click_count_ = 1; + last_button_type_ = button_type; + } +} + +void EventSender::InitMouseWheelEvent(gin::Arguments* args, + bool continuous, + WebMouseWheelEvent* event) { + // Force a layout here just to make sure every position has been + // determined before we send events (as well as all the other methods + // that send an event do). + if (force_layout_on_events_) + view_->layout(); + + double horizontal; + if (!args->GetNext(&horizontal)) { + args->ThrowError(); + return; + } + double vertical; + if (!args->GetNext(&vertical)) { + args->ThrowError(); + return; + } + + bool paged = false; + bool has_precise_scrolling_deltas = false; + int modifiers = 0; + if (!args->PeekNext().IsEmpty()) { + args->GetNext(&paged); + if (!args->PeekNext().IsEmpty()) { + args->GetNext(&has_precise_scrolling_deltas); + if (!args->PeekNext().IsEmpty()) + modifiers = GetKeyModifiersFromV8(args->PeekNext()); + } + } + + InitMouseEvent(WebInputEvent::MouseWheel, + pressed_button_, + last_mouse_pos_, + GetCurrentEventTimeSec(), + click_count_, + modifiers, + event); + event->wheelTicksX = static_cast<float>(horizontal); + event->wheelTicksY = static_cast<float>(vertical); + event->deltaX = event->wheelTicksX; + event->deltaY = event->wheelTicksY; + event->scrollByPage = paged; + event->hasPreciseScrollingDeltas = has_precise_scrolling_deltas; + + if (continuous) { + event->wheelTicksX /= kScrollbarPixelsPerTick; + event->wheelTicksY /= kScrollbarPixelsPerTick; + } else { + event->deltaX *= kScrollbarPixelsPerTick; + event->deltaY *= kScrollbarPixelsPerTick; + } +} + +void EventSender::FinishDragAndDrop(const WebMouseEvent& e, + blink::WebDragOperation drag_effect) { + WebPoint client_point(e.x, e.y); + WebPoint screen_point(e.globalX, e.globalY); + current_drag_effect_ = drag_effect; + if (current_drag_effect_) { + // Specifically pass any keyboard modifiers to the drop method. This allows + // tests to control the drop type (i.e. copy or move). + view_->dragTargetDrop(client_point, screen_point, e.modifiers); + } else { + view_->dragTargetDragLeave(); + } + view_->dragSourceEndedAt(client_point, screen_point, current_drag_effect_); + view_->dragSourceSystemDragEnded(); + + current_drag_data_.reset(); +} + +void EventSender::DoMouseUp(const WebMouseEvent& e) { + view_->handleInputEvent(e); + + pressed_button_ = WebMouseEvent::ButtonNone; + last_click_time_sec_ = e.timeStampSeconds; + last_click_pos_ = last_mouse_pos_; + + // If we're in a drag operation, complete it. + if (current_drag_data_.isNull()) + return; + + WebPoint client_point(e.x, e.y); + WebPoint screen_point(e.globalX, e.globalY); + FinishDragAndDrop( + e, + view_->dragTargetDragOver( + client_point, screen_point, current_drag_effects_allowed_, 0)); +} + +void EventSender::DoMouseMove(const WebMouseEvent& e) { + last_mouse_pos_ = WebPoint(e.x, e.y); + + view_->handleInputEvent(e); + + if (pressed_button_ == WebMouseEvent::ButtonNone || + current_drag_data_.isNull()) { + return; + } + + WebPoint client_point(e.x, e.y); + WebPoint screen_point(e.globalX, e.globalY); + current_drag_effect_ = view_->dragTargetDragOver( + client_point, screen_point, current_drag_effects_allowed_, 0); +} + +void EventSender::ReplaySavedEvents() { + replaying_saved_events_ = true; + while (!mouse_event_queue_.empty()) { + SavedEvent e = mouse_event_queue_.front(); + mouse_event_queue_.pop_front(); + + switch (e.type) { + case SavedEvent::TYPE_MOUSE_MOVE: { + WebMouseEvent event; + InitMouseEvent(WebInputEvent::MouseMove, + pressed_button_, + e.pos, + GetCurrentEventTimeSec(), + click_count_, + e.modifiers, + &event); + DoMouseMove(event); + break; + } + case SavedEvent::TYPE_LEAP_FORWARD: + DoLeapForward(e.milliseconds); + break; + case SavedEvent::TYPE_MOUSE_UP: { + WebMouseEvent event; + InitMouseEvent(WebInputEvent::MouseUp, + e.button_type, + last_mouse_pos_, + GetCurrentEventTimeSec(), + click_count_, + e.modifiers, + &event); + DoMouseUp(event); + break; + } + default: + NOTREACHED(); + } + } + + replaying_saved_events_ = false; +} + +} // namespace content diff --git a/content/shell/renderer/test_runner/event_sender.h b/content/shell/renderer/test_runner/event_sender.h new file mode 100644 index 0000000..e1423a5 --- /dev/null +++ b/content/shell/renderer/test_runner/event_sender.h @@ -0,0 +1,276 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_SHELL_RENDERER_TEST_RUNNER_EVENT_SENDER_H_ +#define CONTENT_SHELL_RENDERER_TEST_RUNNER_EVENT_SENDER_H_ + +#include <queue> +#include <string> +#include <vector> + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "build/build_config.h" +#include "content/shell/renderer/test_runner/WebTask.h" +#include "third_party/WebKit/public/platform/WebDragData.h" +#include "third_party/WebKit/public/platform/WebPoint.h" +#include "third_party/WebKit/public/web/WebDragOperation.h" +#include "third_party/WebKit/public/web/WebInputEvent.h" +#include "third_party/WebKit/public/web/WebTouchPoint.h" + +namespace blink { +class WebFrame; +class WebView; +struct WebContextMenuData; +} + +namespace gin { +class Arguments; +} + +namespace WebTestRunner { +class TestInterfaces; +class WebTestDelegate; +} + +namespace content { + +// Key event location code introduced in DOM Level 3. +// See also: http://www.w3.org/TR/DOM-Level-3-Events/#events-keyboardevents +enum KeyLocationCode { + DOMKeyLocationStandard = 0x00, + DOMKeyLocationLeft = 0x01, + DOMKeyLocationRight = 0x02, + DOMKeyLocationNumpad = 0x03 +}; + +class EventSender : public base::SupportsWeakPtr<EventSender> { + public: + explicit EventSender(WebTestRunner::TestInterfaces*); + virtual ~EventSender(); + + void Reset(); + void Install(blink::WebFrame*); + void SetDelegate(WebTestRunner::WebTestDelegate*); + void SetWebView(blink::WebView*); + + void SetContextMenuData(const blink::WebContextMenuData&); + + void DoDragDrop(const blink::WebDragData&, blink::WebDragOperationsMask); + + void MouseDown(int button_number, int modifiers); + void MouseUp(int button_number, int modifiers); + void KeyDown(const std::string& code_str, + int modifiers, + KeyLocationCode location); + + WebTestRunner::WebTaskList* taskList() { return &task_list_; } + + private: + friend class EventSenderBindings; + + struct SavedEvent { + enum SavedEventType { + TYPE_UNSPECIFIED, + TYPE_MOUSE_UP, + TYPE_MOUSE_MOVE, + TYPE_LEAP_FORWARD + }; + + SavedEvent(); + + SavedEventType type; + blink::WebMouseEvent::Button button_type; // For MouseUp. + blink::WebPoint pos; // For MouseMove. + int milliseconds; // For LeapForward. + int modifiers; + }; + + void EnableDOMUIEventLogging(); + void FireKeyboardEventsToElement(); + void ClearKillRing(); + + std::vector<std::string> ContextClick(); + + void TextZoomIn(); + void TextZoomOut(); + + void ZoomPageIn(); + void ZoomPageOut(); + + void SetPageScaleFactor(float scale_factor, int x, int y); + + void ClearTouchPoints(); + void ReleaseTouchPoint(unsigned index); + void UpdateTouchPoint(unsigned index, int x, int y); + void CancelTouchPoint(unsigned index); + void SetTouchModifier(const std::string& key_name, bool set_mask); + + void DumpFilenameBeingDragged(); + + void GestureFlingCancel(); + void GestureFlingStart(float x, float y, float velocity_x, float velocity_y); + void GestureScrollFirstPoint(int x, int y); + + void TouchStart(); + void TouchMove(); + void TouchCancel(); + void TouchEnd(); + + void LeapForward(int milliseconds); + + void BeginDragWithFiles(const std::vector<std::string>& files); + + void AddTouchPoint(gin::Arguments* args); + + void MouseDragBegin(); + void MouseDragEnd(); + void MouseMomentumBegin(); + + void GestureScrollBegin(gin::Arguments* args); + void GestureScrollEnd(gin::Arguments* args); + void GestureScrollUpdate(gin::Arguments* args); + void GestureScrollUpdateWithoutPropagation(gin::Arguments* args); + void GestureTap(gin::Arguments* args); + void GestureTapDown(gin::Arguments* args); + void GestureShowPress(gin::Arguments* args); + void GestureTapCancel(gin::Arguments* args); + void GestureLongPress(gin::Arguments* args); + void GestureLongTap(gin::Arguments* args); + void GestureTwoFingerTap(gin::Arguments* args); + + void ContinuousMouseScrollBy(gin::Arguments* args); + void DispatchMessage(int msg, int wparam, int lparam); + void MouseMoveTo(gin::Arguments* args); + void MouseScrollBy(gin::Arguments* args); + void MouseMomentumScrollBy(gin::Arguments* args); + void MouseMomentumEnd(); + void ScheduleAsynchronousClick(int button_number, int modifiers); + void ScheduleAsynchronousKeyDown(const std::string& code_str, + int modifiers, + KeyLocationCode location); + + double GetCurrentEventTimeSec(); + + void DoLeapForward(int milliseconds); + + void SendCurrentTouchEvent(blink::WebInputEvent::Type); + + void GestureEvent(blink::WebInputEvent::Type, gin::Arguments*); + + void UpdateClickCountForButton(blink::WebMouseEvent::Button); + + void InitMouseWheelEvent(gin::Arguments* args, + bool continuous, + blink::WebMouseWheelEvent* event); + + void FinishDragAndDrop(const blink::WebMouseEvent&, blink::WebDragOperation); + + void DoMouseUp(const blink::WebMouseEvent&); + void DoMouseMove(const blink::WebMouseEvent&); + void ReplaySavedEvents(); + + bool force_layout_on_events() const { return force_layout_on_events_; } + void set_force_layout_on_events(bool force) { + force_layout_on_events_ = force; + } + + bool is_drag_mode() const { return is_drag_mode_; } + void set_is_drag_mode(bool drag_mode) { is_drag_mode_ = drag_mode; } + +#if defined(OS_WIN) + int wm_key_down() const { return wm_key_down_; } + void set_wm_key_down(int key_down) { wm_key_down_ = key_down; } + + int wm_key_up() const { return wm_key_up_; } + void set_wm_key_up(int key_up) { wm_key_up_ = key_up; } + + int wm_char() const { return wm_char_; } + void set_wm_char(int wm_char) { wm_char_ = wm_char; } + + int wm_dead_char() const { return wm_dead_char_; } + void set_wm_dead_char(int dead_char) { + wm_dead_char_ = dead_char; + } + + int wm_sys_key_down() const { return wm_sys_key_down_; } + void set_wm_sys_key_down(int key_down) { wm_sys_key_down_ = key_down; } + + int wm_sys_key_up() const { return wm_sys_key_up_; } + void set_wm_sys_key_up(int key_up) { wm_sys_key_up_ = key_up; } + + int wm_sys_char() const { return wm_sys_char_; } + void set_wm_sys_char(int sys_char) { wm_sys_char_ = sys_char; } + + int wm_sys_dead_char() const { return wm_sys_dead_char_; } + void set_wm_sys_dead_char(int sys_dead_char) { + wm_sys_dead_char_ = sys_dead_char; + } + + int wm_key_down_; + int wm_key_up_; + int wm_char_; + int wm_dead_char_; + int wm_sys_key_down_; + int wm_sys_key_up_; + int wm_sys_char_; + int wm_sys_dead_char_; +#endif + + WebTestRunner::WebTaskList task_list_; + + WebTestRunner::TestInterfaces* interfaces_; + WebTestRunner::WebTestDelegate* delegate_; + blink::WebView* view_; + + bool force_layout_on_events_; + + // When set to true (the default value), we batch mouse move and mouse up + // events so we can simulate drag & drop. + bool is_drag_mode_; + + int touch_modifiers_; + std::vector<blink::WebTouchPoint> touch_points_; + + scoped_ptr<blink::WebContextMenuData> last_context_menu_data_; + + blink::WebDragData current_drag_data_; + + // Location of the touch point that initiated a gesture. + blink::WebPoint current_gesture_location_; + + // Currently pressed mouse button (Left/Right/Middle or None). + static blink::WebMouseEvent::Button pressed_button_; + + bool replaying_saved_events_; + + std::deque<SavedEvent> mouse_event_queue_; + + blink::WebDragOperationsMask current_drag_effects_allowed_; + + // Location of last mouseMoveTo event. + static blink::WebPoint last_mouse_pos_; + + // Time and place of the last mouse up event. + double last_click_time_sec_; + blink::WebPoint last_click_pos_; + + // The last button number passed to mouseDown and mouseUp. + // Used to determine whether the click count continues to increment or not. + static blink::WebMouseEvent::Button last_button_type_; + + blink::WebDragOperation current_drag_effect_; + + uint32 time_offset_ms_; + int click_count_; + + base::WeakPtrFactory<EventSender> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(EventSender); +}; + +} // namespace content + +#endif // CONTENT_SHELL_RENDERER_TEST_RUNNER_EVENT_SENDER_H_ |