summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorenne@chromium.org <enne@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-03-25 22:53:46 +0000
committerenne@chromium.org <enne@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-03-25 22:53:46 +0000
commitf4009be83d39141213e67db11c185b6b4ea79890 (patch)
tree73d3dc56a3d845d8040b456e5004fb80146254fc
parenteb9342fb26b9b957f46d88d783ad9ef9432dca0a (diff)
downloadchromium_src-f4009be83d39141213e67db11c185b6b4ea79890.zip
chromium_src-f4009be83d39141213e67db11c185b6b4ea79890.tar.gz
chromium_src-f4009be83d39141213e67db11c185b6b4ea79890.tar.bz2
Revert of Reland "Move EventSender from CppBoundClass to gin::Wrappable." (https://codereview.chromium.org/210833003/)
Reason for revert: Causes fast/dom/Window/property* tests to fail flakily. http://test-results.appspot.com/dashboards/flakiness_dashboard.html#group=%40ToT%20Blink&showExpectations=true&tests=fast%2Fdom%2FWindow%2Fproperty-access-on-cached-properties-after-frame-removed-and-gced.html%2Cfast%2Fdom%2FWindow%2Fproperty-access-on-cached-properties-after-frame-navigated.html%2Cfast%2Fdom%2FWindow%2Fproperty-access-on-cached-window-after-frame-navigated.html%2Cfast%2Fdom%2FWindow%2Fproperty-access-on-cached-window-after-frame-removed.html%2Cfast%2Fdom%2FWindow%2Fproperty-access-on-cached-window-after-frame-removed-and-gced.html%2Cfast%2Fdom%2FWindow%2Fproperty-access-on-cached-properties-after-frame-removed.html These tests now all fail with additional lines like: FAIL window.cached_eventSender.dragMode should be false. Was true. FAIL window.cached_eventSender.forceLayoutOnEvents should be false. Was true. Original issue's description: > Reland "Move EventSender from CppBoundClass to gin::Wrappable." > > (patch from issue 199793025 by tfarina@chromium.org) > > including the fix https://codereview.chromium.org/210773002/ > > BUG=297480, 331301 > COLLABORATOR=tfarina@chromium.org > R=jochen@chromium.org > TBR=jochen > > Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=259226 TBR=jochen@chromium.org,tfarina@chromium.org,hajimehoshi@chromium.org NOTREECHECKS=true NOTRY=true BUG=297480, 331301 Review URL: https://codereview.chromium.org/211863002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@259377 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--content/content_shell.gypi8
-rw-r--r--content/renderer/pepper/event_conversion.cc4
-rw-r--r--content/shell/renderer/test_runner/CppBoundClass.cpp367
-rw-r--r--content/shell/renderer/test_runner/CppBoundClass.h253
-rw-r--r--content/shell/renderer/test_runner/CppVariant.cpp296
-rw-r--r--content/shell/renderer/test_runner/CppVariant.h119
-rw-r--r--content/shell/renderer/test_runner/EventSender.cpp1467
-rw-r--r--content/shell/renderer/test_runner/EventSender.h188
-rw-r--r--content/shell/renderer/test_runner/TestInterfaces.cpp18
-rw-r--r--content/shell/renderer/test_runner/TestInterfaces.h6
-rw-r--r--content/shell/renderer/test_runner/WebTestProxy.cpp6
-rw-r--r--content/shell/renderer/test_runner/event_sender.cc2100
-rw-r--r--content/shell/renderer/test_runner/event_sender.h276
13 files changed, 2713 insertions, 2395 deletions
diff --git a/content/content_shell.gypi b/content/content_shell.gypi
index a665471..9290d49 100644
--- a/content/content_shell.gypi
+++ b/content/content_shell.gypi
@@ -173,6 +173,12 @@
'shell/renderer/shell_render_process_observer.h',
'shell/renderer/shell_render_view_observer.cc',
'shell/renderer/shell_render_view_observer.h',
+ 'shell/renderer/test_runner/CppBoundClass.cpp',
+ 'shell/renderer/test_runner/CppBoundClass.h',
+ 'shell/renderer/test_runner/CppVariant.cpp',
+ 'shell/renderer/test_runner/CppVariant.h',
+ 'shell/renderer/test_runner/EventSender.cpp',
+ 'shell/renderer/test_runner/EventSender.h',
'shell/renderer/test_runner/KeyCodeMapping.cpp',
'shell/renderer/test_runner/KeyCodeMapping.h',
'shell/renderer/test_runner/MockColorChooser.cpp',
@@ -226,8 +232,6 @@
'shell/renderer/test_runner/WebUserMediaClientMock.h',
'shell/renderer/test_runner/accessibility_controller.cc',
'shell/renderer/test_runner/accessibility_controller.h',
- 'shell/renderer/test_runner/event_sender.cc',
- 'shell/renderer/test_runner/event_sender.h',
'shell/renderer/test_runner/gamepad_controller.cc',
'shell/renderer/test_runner/gamepad_controller.h',
'shell/renderer/test_runner/notification_presenter.cc',
diff --git a/content/renderer/pepper/event_conversion.cc b/content/renderer/pepper/event_conversion.cc
index 0243434..52d382a 100644
--- a/content/renderer/pepper/event_conversion.cc
+++ b/content/renderer/pepper/event_conversion.cc
@@ -459,7 +459,7 @@ WebMouseWheelEvent* BuildMouseWheelEvent(const InputEventData& event) {
#endif
// Convert a character string to a Windows virtual key code. Adapted from
-// src/content/shell/renderer/test_runner/event_sender.cc. This
+// src/third_party/WebKit/Tools/DumpRenderTree/chromium/EventSender.cpp. This
// is used by CreateSimulatedWebInputEvents to convert keyboard events.
void GetKeyCode(const std::string& char_text,
WebUChar* code,
@@ -606,7 +606,7 @@ WebInputEvent* CreateWebInputEvent(const InputEventData& event) {
}
// Generate a coherent sequence of input events to simulate a user event.
-// From src/content/shell/renderer/test_runner/event_sender.cc.
+// From src/third_party/WebKit/Tools/DumpRenderTree/chromium/EventSender.cpp.
std::vector<linked_ptr<WebInputEvent> > CreateSimulatedWebInputEvents(
const ppapi::InputEventData& event,
int plugin_x,
diff --git a/content/shell/renderer/test_runner/CppBoundClass.cpp b/content/shell/renderer/test_runner/CppBoundClass.cpp
new file mode 100644
index 0000000..943dd92
--- /dev/null
+++ b/content/shell/renderer/test_runner/CppBoundClass.cpp
@@ -0,0 +1,367 @@
+// 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.
+
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2009 Pawel Hajdan (phajdan.jr@chromium.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// This file contains definitions for CppBoundClass
+
+// Here's the control flow of a JS method getting forwarded to a class.
+// - Something calls our NPObject with a function like "Invoke".
+// - CppNPObject's static invoke() function forwards it to its attached
+// CppBoundClass's invoke() method.
+// - CppBoundClass has then overridden invoke() to look up the function
+// name in its internal map of methods, and then calls the appropriate
+// method.
+
+#include "content/shell/renderer/test_runner/CppBoundClass.h"
+
+#include "content/shell/renderer/test_runner/TestCommon.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/web/WebBindings.h"
+#include "third_party/WebKit/public/web/WebFrame.h"
+
+using namespace blink;
+using namespace std;
+
+namespace WebTestRunner {
+
+namespace {
+
+class CppVariantPropertyCallback : public CppBoundClass::PropertyCallback {
+public:
+ CppVariantPropertyCallback(CppVariant* value) : m_value(value) { }
+
+ virtual bool getValue(CppVariant* value) OVERRIDE
+ {
+ value->set(*m_value);
+ return true;
+ }
+
+ virtual bool setValue(const CppVariant& value) OVERRIDE
+ {
+ m_value->set(value);
+ return true;
+ }
+
+private:
+ CppVariant* m_value;
+};
+
+class GetterPropertyCallback : public CppBoundClass::PropertyCallback {
+public:
+ GetterPropertyCallback(scoped_ptr<CppBoundClass::GetterCallback> callback)
+ : m_callback(callback.Pass())
+ {
+ }
+
+ virtual bool getValue(CppVariant* value) OVERRIDE
+ {
+ m_callback->run(value);
+ return true;
+ }
+
+ virtual bool setValue(const CppVariant& value) OVERRIDE { return false; }
+
+private:
+ scoped_ptr<CppBoundClass::GetterCallback> m_callback;
+};
+
+}
+
+// Our special NPObject type. We extend an NPObject with a pointer to a
+// CppBoundClass, which is just a C++ interface that we forward all NPObject
+// callbacks to.
+struct CppNPObject {
+ NPObject parent; // This must be the first field in the struct.
+ CppBoundClass* boundClass;
+
+ //
+ // All following objects and functions are static, and just used to interface
+ // with NPObject/NPClass.
+ //
+
+ // An NPClass associates static functions of CppNPObject with the
+ // function pointers used by the JS runtime.
+ static NPClass npClass;
+
+ // Allocate a new NPObject with the specified class.
+ static NPObject* allocate(NPP, NPClass*);
+
+ // Free an object.
+ static void deallocate(NPObject*);
+
+ // Returns true if the C++ class associated with this NPObject exposes the
+ // given property. Called by the JS runtime.
+ static bool hasProperty(NPObject*, NPIdentifier);
+
+ // Returns true if the C++ class associated with this NPObject exposes the
+ // given method. Called by the JS runtime.
+ static bool hasMethod(NPObject*, NPIdentifier);
+
+ // If the given method is exposed by the C++ class associated with this
+ // NPObject, invokes it with the given arguments and returns a result. Otherwise,
+ // returns "undefined" (in the JavaScript sense). Called by the JS runtime.
+ static bool invoke(NPObject*, NPIdentifier,
+ const NPVariant* arguments, uint32_t argumentCount,
+ NPVariant* result);
+
+ // If the given property is exposed by the C++ class associated with this
+ // NPObject, returns its value. Otherwise, returns "undefined" (in the
+ // JavaScript sense). Called by the JS runtime.
+ static bool getProperty(NPObject*, NPIdentifier, NPVariant* result);
+
+ // If the given property is exposed by the C++ class associated with this
+ // NPObject, sets its value. Otherwise, does nothing. Called by the JS
+ // runtime.
+ static bool setProperty(NPObject*, NPIdentifier, const NPVariant* value);
+};
+
+// Build CppNPObject's static function pointers into an NPClass, for use
+// in constructing NPObjects for the C++ classes.
+NPClass CppNPObject::npClass = {
+ NP_CLASS_STRUCT_VERSION,
+ CppNPObject::allocate,
+ CppNPObject::deallocate,
+ /* NPInvalidateFunctionPtr */ 0,
+ CppNPObject::hasMethod,
+ CppNPObject::invoke,
+ /* NPInvokeDefaultFunctionPtr */ 0,
+ CppNPObject::hasProperty,
+ CppNPObject::getProperty,
+ CppNPObject::setProperty,
+ /* NPRemovePropertyFunctionPtr */ 0
+};
+
+NPObject* CppNPObject::allocate(NPP npp, NPClass* aClass)
+{
+ CppNPObject* obj = new CppNPObject;
+ // obj->parent will be initialized by the NPObject code calling this.
+ obj->boundClass = 0;
+ return &obj->parent;
+}
+
+void CppNPObject::deallocate(NPObject* npObj)
+{
+ CppNPObject* obj = reinterpret_cast<CppNPObject*>(npObj);
+ delete obj;
+}
+
+bool CppNPObject::hasMethod(NPObject* npObj, NPIdentifier ident)
+{
+ CppNPObject* obj = reinterpret_cast<CppNPObject*>(npObj);
+ return obj->boundClass->hasMethod(ident);
+}
+
+bool CppNPObject::hasProperty(NPObject* npObj, NPIdentifier ident)
+{
+ CppNPObject* obj = reinterpret_cast<CppNPObject*>(npObj);
+ return obj->boundClass->hasProperty(ident);
+}
+
+bool CppNPObject::invoke(NPObject* npObj, NPIdentifier ident,
+ const NPVariant* arguments, uint32_t argumentCount,
+ NPVariant* result)
+{
+ CppNPObject* obj = reinterpret_cast<CppNPObject*>(npObj);
+ return obj->boundClass->invoke(ident, arguments, argumentCount, result);
+}
+
+bool CppNPObject::getProperty(NPObject* npObj, NPIdentifier ident, NPVariant* result)
+{
+ CppNPObject* obj = reinterpret_cast<CppNPObject*>(npObj);
+ return obj->boundClass->getProperty(ident, result);
+}
+
+bool CppNPObject::setProperty(NPObject* npObj, NPIdentifier ident, const NPVariant* value)
+{
+ CppNPObject* obj = reinterpret_cast<CppNPObject*>(npObj);
+ return obj->boundClass->setProperty(ident, value);
+}
+
+CppBoundClass::CppBoundClass()
+ : m_boundToFrame(false)
+{
+}
+
+CppBoundClass::~CppBoundClass()
+{
+ for (MethodList::iterator i = m_methods.begin(); i != m_methods.end(); ++i)
+ delete i->second;
+
+ for (PropertyList::iterator i = m_properties.begin(); i != m_properties.end(); ++i)
+ delete i->second;
+
+ // Unregister ourselves if we were bound to a frame.
+ if (m_boundToFrame)
+ WebBindings::unregisterObject(NPVARIANT_TO_OBJECT(m_selfVariant));
+}
+
+bool CppBoundClass::hasMethod(NPIdentifier ident) const
+{
+ return m_methods.find(ident) != m_methods.end();
+}
+
+bool CppBoundClass::hasProperty(NPIdentifier ident) const
+{
+ return m_properties.find(ident) != m_properties.end();
+}
+
+bool CppBoundClass::invoke(NPIdentifier ident,
+ const NPVariant* arguments,
+ size_t argumentCount,
+ NPVariant* result) {
+ MethodList::const_iterator end = m_methods.end();
+ MethodList::const_iterator method = m_methods.find(ident);
+ Callback* callback;
+ if (method == end) {
+ if (!m_fallbackCallback.get()) {
+ VOID_TO_NPVARIANT(*result);
+ return false;
+ }
+ callback = m_fallbackCallback.get();
+ } else
+ callback = (*method).second;
+
+ // Build a CppArgumentList argument vector from the NPVariants coming in.
+ CppArgumentList cppArguments(argumentCount);
+ for (size_t i = 0; i < argumentCount; i++)
+ cppArguments[i].set(arguments[i]);
+
+ CppVariant cppResult;
+ callback->run(cppArguments, &cppResult);
+
+ cppResult.copyToNPVariant(result);
+ return true;
+}
+
+bool CppBoundClass::getProperty(NPIdentifier ident, NPVariant* result) const
+{
+ PropertyList::const_iterator callback = m_properties.find(ident);
+ if (callback == m_properties.end()) {
+ VOID_TO_NPVARIANT(*result);
+ return false;
+ }
+
+ CppVariant cppValue;
+ if (!callback->second->getValue(&cppValue))
+ return false;
+ cppValue.copyToNPVariant(result);
+ return true;
+}
+
+bool CppBoundClass::setProperty(NPIdentifier ident, const NPVariant* value)
+{
+ PropertyList::iterator callback = m_properties.find(ident);
+ if (callback == m_properties.end())
+ return false;
+
+ CppVariant cppValue;
+ cppValue.set(*value);
+ return (*callback).second->setValue(cppValue);
+}
+
+void CppBoundClass::bindCallback(const string& name, Callback* callback)
+{
+ NPIdentifier ident = WebBindings::getStringIdentifier(name.c_str());
+ MethodList::iterator oldCallback = m_methods.find(ident);
+ if (oldCallback != m_methods.end()) {
+ delete oldCallback->second;
+ if (!callback) {
+ m_methods.erase(oldCallback);
+ return;
+ }
+ }
+
+ m_methods[ident] = callback;
+}
+
+void CppBoundClass::bindGetterCallback(const string& name, scoped_ptr<GetterCallback> callback)
+{
+ PropertyCallback* propertyCallback = callback.get() ? new GetterPropertyCallback(callback.Pass()) : 0;
+ bindProperty(name, propertyCallback);
+}
+
+void CppBoundClass::bindProperty(const string& name, CppVariant* prop)
+{
+ PropertyCallback* propertyCallback = prop ? new CppVariantPropertyCallback(prop) : 0;
+ bindProperty(name, propertyCallback);
+}
+
+void CppBoundClass::bindProperty(const string& name, PropertyCallback* callback)
+{
+ NPIdentifier ident = WebBindings::getStringIdentifier(name.c_str());
+ PropertyList::iterator oldCallback = m_properties.find(ident);
+ if (oldCallback != m_properties.end()) {
+ delete oldCallback->second;
+ if (!callback) {
+ m_properties.erase(oldCallback);
+ return;
+ }
+ }
+
+ m_properties[ident] = callback;
+}
+
+bool CppBoundClass::isMethodRegistered(const string& name) const
+{
+ NPIdentifier ident = WebBindings::getStringIdentifier(name.c_str());
+ MethodList::const_iterator callback = m_methods.find(ident);
+ return callback != m_methods.end();
+}
+
+CppVariant* CppBoundClass::getAsCppVariant()
+{
+ if (!m_selfVariant.isObject()) {
+ // Create an NPObject using our static NPClass. The first argument (a
+ // plugin's instance handle) is passed through to the allocate function
+ // directly, and we don't use it, so it's ok to be 0.
+ NPObject* npObj = WebBindings::createObject(0, &CppNPObject::npClass);
+ CppNPObject* obj = reinterpret_cast<CppNPObject*>(npObj);
+ obj->boundClass = this;
+ m_selfVariant.set(npObj);
+ WebBindings::releaseObject(npObj); // CppVariant takes the reference.
+ }
+ BLINK_ASSERT(m_selfVariant.isObject());
+ return &m_selfVariant;
+}
+
+void CppBoundClass::bindToJavascript(WebFrame* frame, const WebString& classname)
+{
+ // BindToWindowObject will take its own reference to the NPObject, and clean
+ // up after itself. It will also (indirectly) register the object with V8,
+ // so we must remember this so we can unregister it when we're destroyed.
+ frame->bindToWindowObject(classname, NPVARIANT_TO_OBJECT(*getAsCppVariant()), 0);
+ m_boundToFrame = true;
+}
+
+}
diff --git a/content/shell/renderer/test_runner/CppBoundClass.h b/content/shell/renderer/test_runner/CppBoundClass.h
new file mode 100644
index 0000000..23109f4
--- /dev/null
+++ b/content/shell/renderer/test_runner/CppBoundClass.h
@@ -0,0 +1,253 @@
+// 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.
+
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2009 Pawel Hajdan (phajdan.jr@chromium.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ CppBoundClass class:
+ This base class serves as a parent for C++ classes designed to be bound to
+ JavaScript objects.
+
+ Subclasses should define the constructor to build the property and method
+ lists needed to bind this class to a JS object. They should also declare
+ and define member variables and methods to be exposed to JS through
+ that object.
+*/
+
+#ifndef CONTENT_SHELL_RENDERER_TEST_RUNNER_CPPBOUNDCLASS_H_
+#define CONTENT_SHELL_RENDERER_TEST_RUNNER_CPPBOUNDCLASS_H_
+
+#include <map>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/shell/renderer/test_runner/CppVariant.h"
+
+namespace blink {
+class WebFrame;
+class WebString;
+}
+
+namespace WebTestRunner {
+
+typedef std::vector<CppVariant> CppArgumentList;
+
+// CppBoundClass lets you map Javascript method calls and property accesses
+// directly to C++ method calls and CppVariant* variable access.
+class CppBoundClass {
+public:
+ class PropertyCallback {
+ public:
+ virtual ~PropertyCallback() { }
+
+ // Sets |value| to the value of the property. Returns false in case of
+ // failure. |value| is always non-0.
+ virtual bool getValue(CppVariant* result) = 0;
+
+ // sets the property value to |value|. Returns false in case of failure.
+ virtual bool setValue(const CppVariant&) = 0;
+ };
+
+ // Callback class for "void function(CppVariant*)"
+ class GetterCallback {
+ public:
+ virtual ~GetterCallback() { }
+ virtual void run(CppVariant*) = 0;
+ };
+
+ // The constructor should call BindMethod, BindProperty, and
+ // SetFallbackMethod as needed to set up the methods, properties, and
+ // fallback method.
+ CppBoundClass();
+ virtual ~CppBoundClass();
+
+ // Return a CppVariant representing this class, for use with BindProperty().
+ // The variant type is guaranteed to be NPVariantType_Object.
+ CppVariant* getAsCppVariant();
+
+ // Given a WebFrame, BindToJavascript builds the NPObject that will represent
+ // the class and binds it to the frame's window under the given name. This
+ // should generally be called from the WebView delegate's
+ // WindowObjectCleared(). A class so bound will be accessible to JavaScript
+ // as window.<classname>. The owner of the CppBoundObject is responsible for
+ // keeping the object around while the frame is alive, and for destroying it
+ // afterwards.
+ void bindToJavascript(blink::WebFrame*, const blink::WebString& classname);
+
+ // Used by a test. Returns true if a method with the specified name exists,
+ // regardless of whether a fallback is registered.
+ bool isMethodRegistered(const std::string&) const;
+
+protected:
+ // Callback for "void function(const CppArguemntList&, CppVariant*)"
+ class Callback {
+ public:
+ virtual ~Callback() { }
+ virtual void run(const CppArgumentList&, CppVariant*) = 0;
+ };
+
+ // Callback for "void T::method(const CppArguemntList&, CppVariant*)"
+ template <class T> class MemberCallback : public Callback {
+ public:
+ typedef void (T::*MethodType)(const CppArgumentList&, CppVariant*);
+ MemberCallback(T* object, MethodType method)
+ : m_object(object)
+ , m_method(method) { }
+ virtual ~MemberCallback() { }
+
+ virtual void run(const CppArgumentList& arguments, CppVariant* result)
+ {
+ (m_object->*m_method)(arguments, result);
+ }
+
+ private:
+ T* m_object;
+ MethodType m_method;
+ };
+
+ // Callback class for "void T::method(CppVariant*)"
+ template <class T> class MemberGetterCallback : public GetterCallback {
+ public:
+ typedef void (T::*MethodType)(CppVariant*);
+ MemberGetterCallback(T* object, MethodType method)
+ : m_object(object)
+ , m_method(method) { }
+ virtual ~MemberGetterCallback() { }
+
+ virtual void run(CppVariant* result) { (m_object->*m_method)(result); }
+
+ private:
+ T* m_object;
+ MethodType m_method;
+ };
+
+ // Bind the Javascript method called the string parameter to the C++ method.
+ void bindCallback(const std::string&, Callback*);
+
+ // A wrapper for bindCallback, to simplify the common case of binding a
+ // method on the current object. Though not verified here, the method parameter
+ // must be a method of this CppBoundClass subclass.
+ template<class T>
+ void bindMethod(const std::string& name, void (T::*method)(const CppArgumentList&, CppVariant*))
+ {
+ Callback* callback = new MemberCallback<T>(static_cast<T*>(this), method);
+ bindCallback(name, callback);
+ }
+
+ // Bind Javascript property |name| to the C++ getter callback |callback|.
+ // This can be used to create read-only properties.
+ void bindGetterCallback(const std::string&, scoped_ptr<GetterCallback>);
+
+ // A wrapper for BindGetterCallback, to simplify the common case of binding a
+ // property on the current object. Though not verified here, the method parameter
+ // must be a method of this CppBoundClass subclass.
+ template<class T>
+ void bindProperty(const std::string& name, void (T::*method)(CppVariant*))
+ {
+ scoped_ptr<GetterCallback> callback(new MemberGetterCallback<T>(static_cast<T*>(this), method));
+ bindGetterCallback(name, callback.Pass());
+ }
+
+ // Bind the Javascript property called |name| to a CppVariant.
+ void bindProperty(const std::string&, CppVariant*);
+
+ // Bind Javascript property called |name| to a PropertyCallback.
+ // CppBoundClass assumes control over the life time of the callback.
+ void bindProperty(const std::string&, PropertyCallback*);
+
+ // Set the fallback callback, which is called when when a callback is
+ // invoked that isn't bound.
+ // If it is 0 (its default value), a JavaScript exception is thrown in
+ // that case (as normally expected). If non 0, the fallback method is
+ // invoked and the script continues its execution.
+ // Passing 0 clears out any existing binding.
+ // It is used for tests and should probably only be used in such cases
+ // as it may cause unexpected behaviors (a JavaScript object with a
+ // fallback always returns true when checked for a method's
+ // existence).
+ void bindFallbackCallback(scoped_ptr<Callback> fallbackCallback)
+ {
+ m_fallbackCallback = fallbackCallback.Pass();
+ }
+
+ // A wrapper for BindFallbackCallback, to simplify the common case of
+ // binding a method on the current object. Though not verified here,
+ // |method| must be a method of this CppBoundClass subclass.
+ // Passing 0 for |method| clears out any existing binding.
+ template<class T>
+ void bindFallbackMethod(void (T::*method)(const CppArgumentList&, CppVariant*))
+ {
+ if (method)
+ bindFallbackCallback(scoped_ptr<Callback>(new MemberCallback<T>(static_cast<T*>(this), method)).Pass());
+ else
+ bindFallbackCallback(scoped_ptr<Callback>().Pass());
+ }
+
+ // Some fields are protected because some tests depend on accessing them,
+ // but otherwise they should be considered private.
+
+ typedef std::map<NPIdentifier, PropertyCallback*> PropertyList;
+ typedef std::map<NPIdentifier, Callback*> MethodList;
+ // These maps associate names with property and method pointers to be
+ // exposed to JavaScript.
+ PropertyList m_properties;
+ MethodList m_methods;
+
+ // The callback gets invoked when a call is made to an nonexistent method.
+ scoped_ptr<Callback> m_fallbackCallback;
+
+private:
+ // NPObject callbacks.
+ friend struct CppNPObject;
+ bool hasMethod(NPIdentifier) const;
+ bool invoke(NPIdentifier, const NPVariant* args, size_t argCount,
+ NPVariant* result);
+ bool hasProperty(NPIdentifier) const;
+ bool getProperty(NPIdentifier, NPVariant* result) const;
+ bool setProperty(NPIdentifier, const NPVariant*);
+
+ // A lazily-initialized CppVariant representing this class. We retain 1
+ // reference to this object, and it is released on deletion.
+ CppVariant m_selfVariant;
+
+ // True if our np_object has been bound to a WebFrame, in which case it must
+ // be unregistered with V8 when we delete it.
+ bool m_boundToFrame;
+
+ DISALLOW_COPY_AND_ASSIGN(CppBoundClass);
+};
+
+}
+
+#endif // CONTENT_SHELL_RENDERER_TEST_RUNNER_CPPBOUNDCLASS_H_
diff --git a/content/shell/renderer/test_runner/CppVariant.cpp b/content/shell/renderer/test_runner/CppVariant.cpp
new file mode 100644
index 0000000..2b08e1e
--- /dev/null
+++ b/content/shell/renderer/test_runner/CppVariant.cpp
@@ -0,0 +1,296 @@
+// 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/CppVariant.h"
+
+#include <limits>
+#include "content/shell/renderer/test_runner/TestCommon.h"
+
+using namespace blink;
+using namespace std;
+
+namespace WebTestRunner {
+
+CppVariant::CppVariant()
+{
+ type = NPVariantType_Null;
+}
+
+// Note that Set() performs a deep copy, which is necessary to safely
+// call FreeData() on the value in the destructor.
+CppVariant::CppVariant(const CppVariant& original)
+{
+ type = NPVariantType_Null;
+ set(original);
+}
+
+// See comment for copy constructor, above.
+CppVariant& CppVariant::operator=(const CppVariant& original)
+{
+ if (&original != this)
+ set(original);
+ return *this;
+}
+
+CppVariant::~CppVariant()
+{
+ freeData();
+}
+
+void CppVariant::freeData()
+{
+ WebBindings::releaseVariantValue(this);
+}
+
+bool CppVariant::isEqual(const CppVariant& other) const
+{
+ if (type != other.type)
+ return false;
+
+ switch (type) {
+ case NPVariantType_Bool:
+ return (value.boolValue == other.value.boolValue);
+ case NPVariantType_Int32:
+ return (value.intValue == other.value.intValue);
+ case NPVariantType_Double:
+ return (value.doubleValue == other.value.doubleValue);
+ case NPVariantType_String: {
+ const NPString *this_value = &value.stringValue;
+ const NPString *other_value = &other.value.stringValue;
+ uint32_t len = this_value->UTF8Length;
+ return len == other_value->UTF8Length
+ && !strncmp(this_value->UTF8Characters,
+ other_value->UTF8Characters, len);
+ }
+ case NPVariantType_Null:
+ case NPVariantType_Void:
+ return true;
+ case NPVariantType_Object: {
+ NPObject* thisValue = value.objectValue;
+ NPObject* otherValue = other.value.objectValue;
+ return thisValue->_class == otherValue->_class
+ && thisValue->referenceCount == otherValue->referenceCount;
+ }
+ }
+ return false;
+}
+
+void CppVariant::copyToNPVariant(NPVariant* result) const
+{
+ result->type = type;
+ switch (type) {
+ case NPVariantType_Bool:
+ result->value.boolValue = value.boolValue;
+ break;
+ case NPVariantType_Int32:
+ result->value.intValue = value.intValue;
+ break;
+ case NPVariantType_Double:
+ result->value.doubleValue = value.doubleValue;
+ break;
+ case NPVariantType_String:
+ WebBindings::initializeVariantWithStringCopy(result, &value.stringValue);
+ break;
+ case NPVariantType_Null:
+ case NPVariantType_Void:
+ // Nothing to set.
+ break;
+ case NPVariantType_Object:
+ result->type = NPVariantType_Object;
+ result->value.objectValue = WebBindings::retainObject(value.objectValue);
+ break;
+ }
+}
+
+void CppVariant::set(const NPVariant& newValue)
+{
+ freeData();
+ switch (newValue.type) {
+ case NPVariantType_Bool:
+ set(newValue.value.boolValue);
+ break;
+ case NPVariantType_Int32:
+ set(newValue.value.intValue);
+ break;
+ case NPVariantType_Double:
+ set(newValue.value.doubleValue);
+ break;
+ case NPVariantType_String:
+ set(newValue.value.stringValue);
+ break;
+ case NPVariantType_Null:
+ case NPVariantType_Void:
+ type = newValue.type;
+ break;
+ case NPVariantType_Object:
+ set(newValue.value.objectValue);
+ break;
+ }
+}
+
+void CppVariant::setNull()
+{
+ freeData();
+ type = NPVariantType_Null;
+}
+
+void CppVariant::set(bool newValue)
+{
+ freeData();
+ type = NPVariantType_Bool;
+ value.boolValue = newValue;
+}
+
+void CppVariant::set(int32_t newValue)
+{
+ freeData();
+ type = NPVariantType_Int32;
+ value.intValue = newValue;
+}
+
+void CppVariant::set(double newValue)
+{
+ freeData();
+ type = NPVariantType_Double;
+ value.doubleValue = newValue;
+}
+
+// The newValue must be a null-terminated string.
+void CppVariant::set(const char* newValue)
+{
+ freeData();
+ type = NPVariantType_String;
+ NPString newString = {newValue,
+ static_cast<uint32_t>(strlen(newValue))};
+ WebBindings::initializeVariantWithStringCopy(this, &newString);
+}
+
+void CppVariant::set(const string& newValue)
+{
+ freeData();
+ type = NPVariantType_String;
+ NPString newString = {newValue.data(),
+ static_cast<uint32_t>(newValue.size())};
+ WebBindings::initializeVariantWithStringCopy(this, &newString);
+}
+
+void CppVariant::set(const NPString& newValue)
+{
+ freeData();
+ type = NPVariantType_String;
+ WebBindings::initializeVariantWithStringCopy(this, &newValue);
+}
+
+void CppVariant::set(NPObject* newValue)
+{
+ freeData();
+ type = NPVariantType_Object;
+ value.objectValue = WebBindings::retainObject(newValue);
+}
+
+string CppVariant::toString() const
+{
+ BLINK_ASSERT(isString());
+ return string(value.stringValue.UTF8Characters,
+ value.stringValue.UTF8Length);
+}
+
+int32_t CppVariant::toInt32() const
+{
+ if (isInt32())
+ return value.intValue;
+ if (isDouble())
+ return static_cast<int32_t>(value.doubleValue);
+ BLINK_ASSERT_NOT_REACHED();
+ return 0;
+}
+
+double CppVariant::toDouble() const
+{
+ if (isInt32())
+ return static_cast<double>(value.intValue);
+ if (isDouble())
+ return value.doubleValue;
+ BLINK_ASSERT_NOT_REACHED();
+ return 0;
+}
+
+bool CppVariant::toBoolean() const
+{
+ BLINK_ASSERT(isBool());
+ return value.boolValue;
+}
+
+vector<string> CppVariant::toStringVector() const
+{
+
+ BLINK_ASSERT(isObject());
+ vector<string> stringVector;
+ NPObject* npValue = value.objectValue;
+ NPIdentifier lengthId = WebBindings::getStringIdentifier("length");
+
+ if (!WebBindings::hasProperty(0, npValue, lengthId))
+ return stringVector;
+
+ NPVariant lengthValue;
+ if (!WebBindings::getProperty(0, npValue, lengthId, &lengthValue))
+ return stringVector;
+
+ int length = 0;
+ // The length is a double in some cases.
+ if (NPVARIANT_IS_DOUBLE(lengthValue))
+ length = static_cast<int>(NPVARIANT_TO_DOUBLE(lengthValue));
+ else if (NPVARIANT_IS_INT32(lengthValue))
+ length = NPVARIANT_TO_INT32(lengthValue);
+ WebBindings::releaseVariantValue(&lengthValue);
+
+ // For sanity, only allow 100 items.
+ length = min(100, length);
+ for (int i = 0; i < length; ++i) {
+ // Get each of the items.
+ char indexInChar[20]; // Enough size to store 32-bit integer
+ snprintf(indexInChar, 20, "%d", i);
+ string index(indexInChar);
+ NPIdentifier indexId = WebBindings::getStringIdentifier(index.c_str());
+ if (!WebBindings::hasProperty(0, npValue, indexId))
+ continue;
+ NPVariant indexValue;
+ if (!WebBindings::getProperty(0, npValue, indexId, &indexValue))
+ continue;
+ if (NPVARIANT_IS_STRING(indexValue)) {
+ string item(NPVARIANT_TO_STRING(indexValue).UTF8Characters,
+ NPVARIANT_TO_STRING(indexValue).UTF8Length);
+ stringVector.push_back(item);
+ }
+ WebBindings::releaseVariantValue(&indexValue);
+ }
+ return stringVector;
+}
+
+bool CppVariant::invoke(const string& method, const CppVariant* arguments,
+ uint32_t argumentCount, CppVariant& result) const
+{
+ BLINK_ASSERT(isObject());
+ NPIdentifier methodName = WebBindings::getStringIdentifier(method.c_str());
+ NPObject* npObject = value.objectValue;
+ if (!WebBindings::hasMethod(0, npObject, methodName))
+ return false;
+ NPVariant r;
+ bool status = WebBindings::invoke(0, npObject, methodName, arguments, argumentCount, &r);
+ result.set(r);
+ return status;
+}
+
+bool CppVariant::invokeDefault(const CppVariant* arguments, uint32_t argumentCount,
+ CppVariant& result) const
+{
+ BLINK_ASSERT(isObject());
+ NPObject* npObject = value.objectValue;
+ NPVariant r;
+ bool status = WebBindings::invokeDefault(0, npObject, arguments, argumentCount, &r);
+ result.set(r);
+ return status;
+}
+
+}
diff --git a/content/shell/renderer/test_runner/CppVariant.h b/content/shell/renderer/test_runner/CppVariant.h
new file mode 100644
index 0000000..572c060
--- /dev/null
+++ b/content/shell/renderer/test_runner/CppVariant.h
@@ -0,0 +1,119 @@
+// 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.
+
+/*
+ This file contains the declaration for CppVariant, a type used by C++ classes
+ that are to be bound to JavaScript objects.
+
+ CppVariant exists primarily as an interface between C++ callers and the
+ corresponding NPVariant type. CppVariant also provides a number of
+ convenience constructors and accessors, so that the NPVariantType values
+ don't need to be exposed, and a destructor to free any memory allocated for
+ string values.
+*/
+
+#ifndef CONTENT_SHELL_RENDERER_TEST_RUNNER_CPPVARIANT_H_
+#define CONTENT_SHELL_RENDERER_TEST_RUNNER_CPPVARIANT_H_
+
+#include <string>
+#include <vector>
+
+#include "third_party/WebKit/public/web/WebBindings.h"
+
+namespace WebTestRunner {
+
+class CppVariant : public NPVariant {
+public:
+ CppVariant();
+ ~CppVariant();
+ void setNull();
+ void set(bool);
+ void set(int32_t);
+ void set(double);
+
+ // Note that setting a CppVariant to a string value involves copying the
+ // string data, which must be freed with a call to freeData() when the
+ // CppVariant is set to a different value or is no longer needed. Normally
+ // this is handled by the other set() methods and by the destructor.
+ void set(const char*); // Must be a null-terminated string.
+ void set(const std::string&);
+ void set(const NPString&);
+ void set(const NPVariant&);
+
+ // Note that setting a CppVariant to an NPObject involves ref-counting
+ // the actual object. freeData() should only be called if the CppVariant
+ // is no longer needed. The other set() methods handle this internally.
+ // Also, the object's NPClass is expected to be a static object: neither
+ // the NP runtime nor CppVariant will ever free it.
+ void set(NPObject*_value);
+
+ // These three methods all perform deep copies of any string data. This
+ // allows local CppVariants to be released by the destructor without
+ // corrupting their sources. In performance-critical code, or when strings
+ // are very long, avoid creating new CppVariants.
+ // In case of NPObject as the data, the copying involves ref-counting
+ // as opposed to deep-copying. The ref-counting ensures that sources don't
+ // get corrupted when the copies get destroyed.
+ void copyToNPVariant(NPVariant* result) const;
+ CppVariant& operator=(const CppVariant& original);
+ CppVariant(const CppVariant& original);
+
+ // Calls NPN_ReleaseVariantValue, which frees any string data
+ // held by the object and sets its type to null.
+ // In case of NPObject, the NPN_ReleaseVariantValue decrements
+ // the ref-count (releases when ref-count becomes 0)
+ void freeData();
+
+ // Compares this CppVariant's type and value to another's. They must be
+ // identical in both type and value to be considered equal. For string and
+ // object types, a deep comparison is performed; that is, the contents of the
+ // strings, or the classes and refcounts of the objects, must be the same,
+ // but they need not be the same pointers.
+ bool isEqual(const CppVariant&) const;
+
+ // The value of a CppVariant may be read directly from its NPVariant (but
+ // should only be set using one of the set() methods above). Although the
+ // type of a CppVariant is likewise public, it can be accessed through these
+ // functions rather than directly if a caller wishes to avoid dependence on
+ // the NPVariantType values.
+ bool isBool() const { return (type == NPVariantType_Bool); }
+ bool isInt32() const { return (type == NPVariantType_Int32); }
+ bool isDouble() const { return (type == NPVariantType_Double); }
+ bool isNumber() const { return (isInt32() || isDouble()); }
+ bool isString() const { return (type == NPVariantType_String); }
+ bool isVoid() const { return (type == NPVariantType_Void); }
+ bool isNull() const { return (type == NPVariantType_Null); }
+ bool isEmpty() const { return (isVoid() || isNull()); }
+ bool isObject() const { return (type == NPVariantType_Object); }
+
+ // Converters. The CppVariant must be of a type convertible to these values.
+ // For example, toInt32() works only if isNumber() is true.
+ std::string toString() const;
+ int32_t toInt32() const;
+ double toDouble() const;
+ bool toBoolean() const;
+ // Returns a vector of strings for the specified argument. This is useful
+ // for converting a JavaScript array of strings into a vector of strings.
+ std::vector<std::string> toStringVector() const;
+
+ // Invoke method of the given name on an object with the supplied arguments.
+ // The first argument should be the object on which the method is to be
+ // invoked. Returns whether the method was successfully invoked. If the
+ // method was invoked successfully, any return value is stored in the
+ // CppVariant specified by result.
+ bool invoke(const std::string&, const CppVariant* arguments,
+ uint32_t argumentCount, CppVariant& result) const;
+
+ // Invoke an object's default method with the supplied arguments.
+ // The first argument should be the object on which the method is to be
+ // invoked. Returns whether the method was successfully invoked. If the
+ // method was invoked successfully, any return value is stored in the
+ // CppVariant specified by result.
+ bool invokeDefault(const CppVariant* arguments,
+ uint32_t argumentCount, CppVariant& result) const;
+};
+
+}
+
+#endif // CONTENT_SHELL_RENDERER_TEST_RUNNER_CPPVARIANT_H_
diff --git a/content/shell/renderer/test_runner/EventSender.cpp b/content/shell/renderer/test_runner/EventSender.cpp
new file mode 100644
index 0000000..369f31f
--- /dev/null
+++ b/content/shell/renderer/test_runner/EventSender.cpp
@@ -0,0 +1,1467 @@
+// 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.
+
+// 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.x = arguments[0].toInt32();
+ touchPoint.position.y = 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.x = arguments[1].toInt32();
+ touchPoint->position.y = 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
new file mode 100644
index 0000000..75fad30
--- /dev/null
+++ b/content/shell/renderer/test_runner/EventSender.h
@@ -0,0 +1,188 @@
+// 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.
+
+/*
+ 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 c7c4d2d..5e08ac3 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 content::EventSender(this))
+ , m_eventSender(new 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->Install(frame);
+ m_eventSender->bindToJavascript(frame, WebString::fromUTF8("eventSender"));
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();
}
-content::EventSender* TestInterfaces::eventSender()
+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 4bc50d9..5e6ba1f 100644
--- a/content/shell/renderer/test_runner/TestInterfaces.h
+++ b/content/shell/renderer/test_runner/TestInterfaces.h
@@ -26,7 +26,6 @@ class WebView;
namespace content {
class AccessibilityController;
-class EventSender;
class GamepadController;
class TestRunner;
class TextInputController;
@@ -34,6 +33,7 @@ class TextInputController;
namespace WebTestRunner {
+class EventSender;
class WebTestDelegate;
class WebTestProxyBase;
@@ -54,7 +54,7 @@ public:
void windowClosed(WebTestProxyBase*);
content::AccessibilityController* accessibilityController();
- content::EventSender* eventSender();
+ EventSender* eventSender();
content::TestRunner* testRunner();
WebTestDelegate* delegate();
WebTestProxyBase* proxy();
@@ -63,7 +63,7 @@ public:
private:
scoped_ptr<content::AccessibilityController> m_accessibilityController;
- scoped_ptr<content::EventSender> m_eventSender;
+ scoped_ptr<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 9d454a2..0b8ddd5 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/event_sender.h"
+#include "content/shell/renderer/test_runner/EventSender.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
deleted file mode 100644
index 2964cd4..0000000
--- a/content/shell/renderer/test_runner/event_sender.cc
+++ /dev/null
@@ -1,2100 +0,0 @@
-// 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),
- code_str_(code_str),
- 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(gin::Arguments* args);
- 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(gin::Arguments* args) {
- if (!sender_)
- return;
- float scale_factor;
- int x;
- int y;
- if (args->PeekNext().IsEmpty())
- return;
- args->GetNext(&scale_factor);
- if (args->PeekNext().IsEmpty())
- return;
- args->GetNext(&x);
- if (args->PeekNext().IsEmpty())
- return;
- args->GetNext(&y);
- 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 =
- WebTestRunner::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
deleted file mode 100644
index e1423a5..0000000
--- a/content/shell/renderer/test_runner/event_sender.h
+++ /dev/null
@@ -1,276 +0,0 @@
-// 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_