summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjochen@chromium.org <jochen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-20 13:27:38 +0000
committerjochen@chromium.org <jochen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-20 13:27:38 +0000
commit3de922f39b244a05cf5ed58699256158048a1b89 (patch)
tree80f5fd65f420f54afa2daef7d217670812614bb6
parenta3e41cd4f1ed6879b25a3dcc8730db868df69fd4 (diff)
downloadchromium_src-3de922f39b244a05cf5ed58699256158048a1b89.zip
chromium_src-3de922f39b244a05cf5ed58699256158048a1b89.tar.gz
chromium_src-3de922f39b244a05cf5ed58699256158048a1b89.tar.bz2
Import TestRunner library into chromium.
The reasons for the move are: - it's actually a blink embedder, so it can't use blink/wtf types - it can't use base either - we want to replace CppBoundClass with gin::Wrappable, not possible in blink In the first step, this is mostly a 1:1 copy (except for include paths). Follow-up CLs will move the test plugin and layout tests helpers and clean up the coding style BUG=324658 R=abarth@chromium.org, maruel@chromium.org, torne@chromium.org, jam@chromium.org TBR=torne@chromium.org Review URL: https://codereview.chromium.org/110533009 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@242095 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--PRESUBMIT.py10
-rwxr-xr-xandroid_webview/tools/webview_licenses.py2
-rw-r--r--content/content_shell.gypi86
-rw-r--r--content/content_tests.gypi5
-rw-r--r--content/shell/DEPS3
-rw-r--r--content/shell/common/test_runner/OWNERS1
-rw-r--r--content/shell/common/test_runner/WebPreferences.cpp51
-rw-r--r--content/shell/common/test_runner/WebPreferences.h54
-rw-r--r--content/shell/common/webkit_test_helpers.cc2
-rw-r--r--content/shell/renderer/shell_content_renderer_client.cc6
-rw-r--r--content/shell/renderer/shell_render_frame_observer.cc4
-rw-r--r--content/shell/renderer/shell_render_process_observer.cc2
-rw-r--r--content/shell/renderer/test_runner/AccessibilityController.cpp180
-rw-r--r--content/shell/renderer/test_runner/AccessibilityController.h70
-rw-r--r--content/shell/renderer/test_runner/CppBoundClass.cpp362
-rw-r--r--content/shell/renderer/test_runner/CppBoundClass.h251
-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.cpp1439
-rw-r--r--content/shell/renderer/test_runner/EventSender.h188
-rw-r--r--content/shell/renderer/test_runner/GamepadController.cpp173
-rw-r--r--content/shell/renderer/test_runner/GamepadController.h46
-rw-r--r--content/shell/renderer/test_runner/KeyCodeMapping.cpp222
-rw-r--r--content/shell/renderer/test_runner/KeyCodeMapping.h41
-rw-r--r--content/shell/renderer/test_runner/MockColorChooser.cpp58
-rw-r--r--content/shell/renderer/test_runner/MockColorChooser.h38
-rw-r--r--content/shell/renderer/test_runner/MockConstraints.cpp59
-rw-r--r--content/shell/renderer/test_runner/MockConstraints.h22
-rw-r--r--content/shell/renderer/test_runner/MockGrammarCheck.cpp58
-rw-r--r--content/shell/renderer/test_runner/MockGrammarCheck.h31
-rw-r--r--content/shell/renderer/test_runner/MockSpellCheck.cpp184
-rw-r--r--content/shell/renderer/test_runner/MockSpellCheck.h67
-rw-r--r--content/shell/renderer/test_runner/MockWebAudioDevice.cpp33
-rw-r--r--content/shell/renderer/test_runner/MockWebAudioDevice.h29
-rw-r--r--content/shell/renderer/test_runner/MockWebMIDIAccessor.cpp58
-rw-r--r--content/shell/renderer/test_runner/MockWebMIDIAccessor.h45
-rw-r--r--content/shell/renderer/test_runner/MockWebMediaStreamCenter.cpp93
-rw-r--r--content/shell/renderer/test_runner/MockWebMediaStreamCenter.h37
-rw-r--r--content/shell/renderer/test_runner/MockWebRTCDTMFSenderHandler.cpp73
-rw-r--r--content/shell/renderer/test_runner/MockWebRTCDTMFSenderHandler.h46
-rw-r--r--content/shell/renderer/test_runner/MockWebRTCDataChannelHandler.cpp108
-rw-r--r--content/shell/renderer/test_runner/MockWebRTCDataChannelHandler.h53
-rw-r--r--content/shell/renderer/test_runner/MockWebRTCPeerConnectionHandler.cpp281
-rw-r--r--content/shell/renderer/test_runner/MockWebRTCPeerConnectionHandler.h63
-rw-r--r--content/shell/renderer/test_runner/MockWebSpeechInputController.cpp186
-rw-r--r--content/shell/renderer/test_runner/MockWebSpeechInputController.h77
-rw-r--r--content/shell/renderer/test_runner/MockWebSpeechRecognizer.cpp226
-rw-r--r--content/shell/renderer/test_runner/MockWebSpeechRecognizer.h84
-rw-r--r--content/shell/renderer/test_runner/NotificationPresenter.cpp141
-rw-r--r--content/shell/renderer/test_runner/NotificationPresenter.h61
-rw-r--r--content/shell/renderer/test_runner/OWNERS1
-rw-r--r--content/shell/renderer/test_runner/SpellCheckClient.cpp143
-rw-r--r--content/shell/renderer/test_runner/SpellCheckClient.h55
-rw-r--r--content/shell/renderer/test_runner/TestCommon.cpp37
-rw-r--r--content/shell/renderer/test_runner/TestCommon.h28
-rw-r--r--content/shell/renderer/test_runner/TestInterfaces.cpp191
-rw-r--r--content/shell/renderer/test_runner/TestInterfaces.h83
-rw-r--r--content/shell/renderer/test_runner/TestPlugin.cpp560
-rw-r--r--content/shell/renderer/test_runner/TestPlugin.h137
-rw-r--r--content/shell/renderer/test_runner/TestRunner.cpp2132
-rw-r--r--content/shell/renderer/test_runner/TestRunner.h737
-rw-r--r--content/shell/renderer/test_runner/TextInputController.cpp193
-rw-r--r--content/shell/renderer/test_runner/TextInputController.h42
-rw-r--r--content/shell/renderer/test_runner/WebAXObjectProxy.cpp1161
-rw-r--r--content/shell/renderer/test_runner/WebAXObjectProxy.h145
-rw-r--r--content/shell/renderer/test_runner/WebFrameTestProxy.h154
-rw-r--r--content/shell/renderer/test_runner/WebPermissions.cpp113
-rw-r--r--content/shell/renderer/test_runner/WebPermissions.h56
-rw-r--r--content/shell/renderer/test_runner/WebScopedPtr.h123
-rw-r--r--content/shell/renderer/test_runner/WebTask.cpp53
-rw-r--r--content/shell/renderer/test_runner/WebTask.h77
-rw-r--r--content/shell/renderer/test_runner/WebTestDelegate.h142
-rw-r--r--content/shell/renderer/test_runner/WebTestInterfaces.cpp92
-rw-r--r--content/shell/renderer/test_runner/WebTestInterfaces.h61
-rw-r--r--content/shell/renderer/test_runner/WebTestProxy.cpp1367
-rw-r--r--content/shell/renderer/test_runner/WebTestProxy.h539
-rw-r--r--content/shell/renderer/test_runner/WebTestRunner.h41
-rw-r--r--content/shell/renderer/test_runner/WebTestThemeControlWin.cpp465
-rw-r--r--content/shell/renderer/test_runner/WebTestThemeControlWin.h175
-rw-r--r--content/shell/renderer/test_runner/WebTestThemeEngineMac.h45
-rw-r--r--content/shell/renderer/test_runner/WebTestThemeEngineMac.mm173
-rw-r--r--content/shell/renderer/test_runner/WebTestThemeEngineMock.cpp601
-rw-r--r--content/shell/renderer/test_runner/WebTestThemeEngineMock.h32
-rw-r--r--content/shell/renderer/test_runner/WebTestThemeEngineWin.cpp716
-rw-r--r--content/shell/renderer/test_runner/WebTestThemeEngineWin.h78
-rw-r--r--content/shell/renderer/test_runner/WebUserMediaClientMock.cpp141
-rw-r--r--content/shell/renderer/test_runner/WebUserMediaClientMock.h38
-rw-r--r--content/shell/renderer/webkit_test_runner.cc8
-rw-r--r--content/shell/renderer/webkit_test_runner.h4
-rw-r--r--content/test/DEPS1
-rw-r--r--content/test/layouttest_support.cc4
91 files changed, 16744 insertions, 24 deletions
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index e33fa80..9bb1471 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -28,6 +28,13 @@ _EXCLUDED_PATHS = (
r"^gpu[\\\/]config[\\\/].*_list_json\.cc$",
)
+# TestRunner library is temporarily excluded from pan-project checks until
+# it's transitioned to chromium coding style.
+_TESTRUNNER_PATHS = (
+ r"^content[\\\/]shell[\\\/]renderer[\\\/]test_runner[\\\/].*",
+ r"^content[\\\/]shell[\\\/]common[\\\/]test_runner[\\\/].*",
+)
+
# Fragment of a regular expression that matches C++ and Objective-C++
# implementation files.
_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
@@ -999,7 +1006,8 @@ def _CommonChecks(input_api, output_api):
"""Checks common to both upload and commit."""
results = []
results.extend(input_api.canned_checks.PanProjectChecks(
- input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
+ input_api, output_api,
+ excluded_paths=_EXCLUDED_PATHS + _TESTRUNNER_PATHS))
results.extend(_CheckAuthorizedAuthor(input_api, output_api))
results.extend(
_CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
diff --git a/android_webview/tools/webview_licenses.py b/android_webview/tools/webview_licenses.py
index 9702465..3a1911b 100755
--- a/android_webview/tools/webview_licenses.py
+++ b/android_webview/tools/webview_licenses.py
@@ -103,6 +103,8 @@ def _CheckLicenseHeaders(excluded_dirs_list, whitelisted_files):
excluded_dirs_list.append('chrome/app/resources')
# This is a test output directory
excluded_dirs_list.append('chrome/tools/test/reference_build')
+ # blink style copy right headers.
+ excluded_dirs_list.append('content/shell/renderer/test_runner')
# This is tests directory, doesn't exist in the snapshot
excluded_dirs_list.append('content/test/data')
# This is a tests directory that doesn't exist in the shipped product.
diff --git a/content/content_shell.gypi b/content/content_shell.gypi
index 0031964..9d5ded0 100644
--- a/content/content_shell.gypi
+++ b/content/content_shell.gypi
@@ -46,7 +46,9 @@
'../net/net.gyp:net',
'../net/net.gyp:net_resources',
'../skia/skia.gyp:skia',
- '../third_party/WebKit/public/blink_test_runner.gyp:blink_test_runner',
+ '../third_party/WebKit/public/blink.gyp:blink',
+ '../third_party/WebKit/public/blink_test_runner.gyp:blink_test_runner_resources',
+ '../third_party/WebKit/public/blink_test_runner.gyp:blink_test_support',
'../ui/events/events.gyp:events_base',
'../ui/gfx/gfx.gyp:gfx',
'../ui/gfx/gfx.gyp:gfx_geometry',
@@ -63,6 +65,7 @@
'..',
],
'sources': [
+ 'public/test/layouttest_support.h',
'shell/android/shell_jni_registrar.cc',
'shell/android/shell_jni_registrar.h',
'shell/android/shell_manager.cc',
@@ -151,6 +154,8 @@
'shell/common/shell_switches.h',
'shell/common/shell_test_configuration.cc',
'shell/common/shell_test_configuration.h',
+ 'shell/common/test_runner/WebPreferences.cpp',
+ 'shell/common/test_runner/WebPreferences.h',
'shell/common/webkit_test_helpers.cc',
'shell/common/webkit_test_helpers.h',
'shell/geolocation/shell_access_token_store.cc',
@@ -165,8 +170,83 @@
'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/AccessibilityController.cpp',
+ 'shell/renderer/test_runner/AccessibilityController.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/GamepadController.cpp',
+ 'shell/renderer/test_runner/GamepadController.h',
+ 'shell/renderer/test_runner/KeyCodeMapping.cpp',
+ 'shell/renderer/test_runner/KeyCodeMapping.h',
+ 'shell/renderer/test_runner/MockColorChooser.cpp',
+ 'shell/renderer/test_runner/MockColorChooser.h',
+ 'shell/renderer/test_runner/MockConstraints.cpp',
+ 'shell/renderer/test_runner/MockConstraints.h',
+ 'shell/renderer/test_runner/MockGrammarCheck.cpp',
+ 'shell/renderer/test_runner/MockGrammarCheck.h',
+ 'shell/renderer/test_runner/MockSpellCheck.cpp',
+ 'shell/renderer/test_runner/MockSpellCheck.h',
+ 'shell/renderer/test_runner/MockWebAudioDevice.cpp',
+ 'shell/renderer/test_runner/MockWebAudioDevice.h',
+ 'shell/renderer/test_runner/MockWebMediaStreamCenter.cpp',
+ 'shell/renderer/test_runner/MockWebMediaStreamCenter.h',
+ 'shell/renderer/test_runner/MockWebMIDIAccessor.cpp',
+ 'shell/renderer/test_runner/MockWebMIDIAccessor.h',
+ 'shell/renderer/test_runner/MockWebRTCDataChannelHandler.cpp',
+ 'shell/renderer/test_runner/MockWebRTCDataChannelHandler.h',
+ 'shell/renderer/test_runner/MockWebRTCDTMFSenderHandler.cpp',
+ 'shell/renderer/test_runner/MockWebRTCDTMFSenderHandler.h',
+ 'shell/renderer/test_runner/MockWebRTCPeerConnectionHandler.cpp',
+ 'shell/renderer/test_runner/MockWebRTCPeerConnectionHandler.h',
+ 'shell/renderer/test_runner/MockWebSpeechInputController.cpp',
+ 'shell/renderer/test_runner/MockWebSpeechInputController.h',
+ 'shell/renderer/test_runner/MockWebSpeechRecognizer.cpp',
+ 'shell/renderer/test_runner/MockWebSpeechRecognizer.h',
+ 'shell/renderer/test_runner/NotificationPresenter.cpp',
+ 'shell/renderer/test_runner/NotificationPresenter.h',
+ 'shell/renderer/test_runner/SpellCheckClient.cpp',
+ 'shell/renderer/test_runner/SpellCheckClient.h',
+ 'shell/renderer/test_runner/TestCommon.cpp',
+ 'shell/renderer/test_runner/TestCommon.h',
+ 'shell/renderer/test_runner/TestInterfaces.cpp',
+ 'shell/renderer/test_runner/TestInterfaces.h',
+ 'shell/renderer/test_runner/TestPlugin.cpp',
+ 'shell/renderer/test_runner/TestPlugin.h',
+ 'shell/renderer/test_runner/TestRunner.cpp',
+ 'shell/renderer/test_runner/TestRunner.h',
+ 'shell/renderer/test_runner/TextInputController.cpp',
+ 'shell/renderer/test_runner/TextInputController.h',
+ 'shell/renderer/test_runner/WebAXObjectProxy.cpp',
+ 'shell/renderer/test_runner/WebAXObjectProxy.h',
+ 'shell/renderer/test_runner/WebFrameTestProxy.h',
+ 'shell/renderer/test_runner/WebPermissions.cpp',
+ 'shell/renderer/test_runner/WebPermissions.h',
+ 'shell/renderer/test_runner/WebScopedPtr.h',
+ 'shell/renderer/test_runner/WebTask.cpp',
+ 'shell/renderer/test_runner/WebTask.h',
+ 'shell/renderer/test_runner/WebTestDelegate.h',
+ 'shell/renderer/test_runner/WebTestInterfaces.cpp',
+ 'shell/renderer/test_runner/WebTestInterfaces.h',
+ 'shell/renderer/test_runner/WebTestProxy.cpp',
+ 'shell/renderer/test_runner/WebTestProxy.h',
+ 'shell/renderer/test_runner/WebTestRunner.h',
+ 'shell/renderer/test_runner/WebTestThemeControlWin.cpp',
+ 'shell/renderer/test_runner/WebTestThemeControlWin.h',
+ 'shell/renderer/test_runner/WebTestThemeEngineMac.h',
+ 'shell/renderer/test_runner/WebTestThemeEngineMac.mm',
+ 'shell/renderer/test_runner/WebTestThemeEngineMock.cpp',
+ 'shell/renderer/test_runner/WebTestThemeEngineMock.h',
+ 'shell/renderer/test_runner/WebTestThemeEngineWin.cpp',
+ 'shell/renderer/test_runner/WebTestThemeEngineWin.h',
+ 'shell/renderer/test_runner/WebUserMediaClientMock.cpp',
+ 'shell/renderer/test_runner/WebUserMediaClientMock.h',
'shell/renderer/webkit_test_runner.cc',
'shell/renderer/webkit_test_runner.h',
+ 'test/layouttest_support.cc',
],
'msvs_settings': {
'VCLinkerTool': {
@@ -197,6 +277,10 @@
},
# TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
'msvs_disabled_warnings': [ 4267, ],
+ }, { # OS!="win"
+ 'sources/': [
+ ['exclude', 'Win\\.cpp$'],
+ ],
}], # OS=="win"
['OS=="linux"', {
'dependencies': [
diff --git a/content/content_tests.gypi b/content/content_tests.gypi
index ffd2ec1..ec1edb39 100644
--- a/content/content_tests.gypi
+++ b/content/content_tests.gypi
@@ -40,7 +40,6 @@
'public/test/download_test_observer.h',
'public/test/fake_speech_recognition_manager.cc',
'public/test/fake_speech_recognition_manager.h',
- 'public/test/layouttest_support.h',
'public/test/mock_download_item.cc',
'public/test/mock_download_item.h',
'public/test/mock_download_manager.cc',
@@ -113,7 +112,6 @@
'gpu/gpu_idirect3d9_mock_win.h',
'test/content_test_suite.cc',
'test/content_test_suite.h',
- 'test/layouttest_support.cc',
'test/mock_google_streaming_server.cc',
'test/mock_google_streaming_server.h',
'test/mock_keyboard.cc',
@@ -226,7 +224,6 @@
'../ppapi/ppapi_internal.gyp:ppapi_shared',
'../ppapi/ppapi_internal.gyp:ppapi_unittest_shared',
'../third_party/WebKit/public/blink.gyp:blink',
- '../third_party/WebKit/public/blink_test_runner.gyp:blink_test_runner',
'../ui/surface/surface.gyp:surface',
'../webkit/child/webkit_child.gyp:webkit_child',
'../webkit/common/gpu/webkit_gpu.gyp:webkit_gpu',
@@ -1214,6 +1211,8 @@
'type': 'static_library',
'dependencies': [
'test_support_content',
+ # TODO(jochen): remove this.
+ '../third_party/WebKit/public/blink_test_runner.gyp:blink_test_support',
],
'include_dirs': [
'..',
diff --git a/content/shell/DEPS b/content/shell/DEPS
index 3cc264e..1d7524c 100644
--- a/content/shell/DEPS
+++ b/content/shell/DEPS
@@ -20,9 +20,6 @@ include_rules = [
"+ui/aura",
"+ui/views",
- # For WebTestRunner library
- "+third_party/WebKit/public/testing",
-
"+components/breakpad",
]
diff --git a/content/shell/common/test_runner/OWNERS b/content/shell/common/test_runner/OWNERS
new file mode 100644
index 0000000..cf00f71
--- /dev/null
+++ b/content/shell/common/test_runner/OWNERS
@@ -0,0 +1 @@
+abarth@chromium.org
diff --git a/content/shell/common/test_runner/WebPreferences.cpp b/content/shell/common/test_runner/WebPreferences.cpp
new file mode 100644
index 0000000..a8952e3
--- /dev/null
+++ b/content/shell/common/test_runner/WebPreferences.cpp
@@ -0,0 +1,51 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/shell/common/test_runner/WebPreferences.h"
+
+using namespace blink;
+
+namespace WebTestRunner {
+
+void WebPreferences::reset()
+{
+ defaultFontSize = 16;
+ minimumFontSize = 0;
+ DOMPasteAllowed = true;
+ XSSAuditorEnabled = false;
+ allowDisplayOfInsecureContent = true;
+ allowFileAccessFromFileURLs = true;
+ allowRunningOfInsecureContent = true;
+ defaultTextEncodingName = WebString::fromUTF8("ISO-8859-1");
+ experimentalWebGLEnabled = false;
+ experimentalCSSRegionsEnabled = true;
+ experimentalCSSGridLayoutEnabled = true;
+ javaEnabled = false;
+ javaScriptCanAccessClipboard = true;
+ javaScriptCanOpenWindowsAutomatically = true;
+ supportsMultipleWindows = true;
+ javaScriptEnabled = true;
+ loadsImagesAutomatically = true;
+ offlineWebApplicationCacheEnabled = true;
+ pluginsEnabled = true;
+ caretBrowsingEnabled = false;
+
+ // Allow those layout tests running as local files, i.e. under
+ // LayoutTests/http/tests/local, to access http server.
+ allowUniversalAccessFromFileURLs = true;
+
+#ifdef __APPLE__
+ editingBehavior = WebSettings::EditingBehaviorMac;
+#else
+ editingBehavior = WebSettings::EditingBehaviorWin;
+#endif
+
+ tabsToLinks = false;
+ hyperlinkAuditingEnabled = false;
+ cssCustomFilterEnabled = false;
+ shouldRespectImageOrientation = false;
+ asynchronousSpellCheckingEnabled = false;
+}
+
+}
diff --git a/content/shell/common/test_runner/WebPreferences.h b/content/shell/common/test_runner/WebPreferences.h
new file mode 100644
index 0000000..dbcc923
--- /dev/null
+++ b/content/shell/common/test_runner/WebPreferences.h
@@ -0,0 +1,54 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WebPreferences_h
+#define WebPreferences_h
+
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/platform/WebURL.h"
+#include "third_party/WebKit/public/web/WebSettings.h"
+
+namespace blink {
+class WebView;
+}
+
+namespace WebTestRunner {
+
+struct WebPreferences {
+ int defaultFontSize;
+ int minimumFontSize;
+ bool DOMPasteAllowed;
+ bool XSSAuditorEnabled;
+ bool allowDisplayOfInsecureContent;
+ bool allowFileAccessFromFileURLs;
+ bool allowRunningOfInsecureContent;
+ bool authorAndUserStylesEnabled;
+ blink::WebString defaultTextEncodingName;
+ bool experimentalWebGLEnabled;
+ bool experimentalCSSRegionsEnabled;
+ bool experimentalCSSGridLayoutEnabled;
+ bool javaEnabled;
+ bool javaScriptCanAccessClipboard;
+ bool javaScriptCanOpenWindowsAutomatically;
+ bool supportsMultipleWindows;
+ bool javaScriptEnabled;
+ bool loadsImagesAutomatically;
+ bool offlineWebApplicationCacheEnabled;
+ bool pluginsEnabled;
+ bool allowUniversalAccessFromFileURLs;
+ blink::WebSettings::EditingBehavior editingBehavior;
+ bool tabsToLinks;
+ bool hyperlinkAuditingEnabled;
+ bool caretBrowsingEnabled;
+ bool cssCustomFilterEnabled;
+ bool shouldRespectImageOrientation;
+ bool asynchronousSpellCheckingEnabled;
+
+ WebPreferences() { reset(); }
+ void reset();
+};
+
+}
+
+#endif // WebPreferences_h
diff --git a/content/shell/common/webkit_test_helpers.cc b/content/shell/common/webkit_test_helpers.cc
index 3d3212e..131b453 100644
--- a/content/shell/common/webkit_test_helpers.cc
+++ b/content/shell/common/webkit_test_helpers.cc
@@ -10,7 +10,7 @@
#include "base/strings/utf_string_conversions.h"
#include "content/public/common/content_switches.h"
#include "content/shell/common/shell_switches.h"
-#include "third_party/WebKit/public/testing/WebPreferences.h"
+#include "content/shell/common/test_runner/WebPreferences.h"
#include "webkit/common/webpreferences.h"
namespace content {
diff --git a/content/shell/renderer/shell_content_renderer_client.cc b/content/shell/renderer/shell_content_renderer_client.cc
index 58f0222..e7046ba 100644
--- a/content/shell/renderer/shell_content_renderer_client.cc
+++ b/content/shell/renderer/shell_content_renderer_client.cc
@@ -15,12 +15,12 @@
#include "content/shell/renderer/shell_render_frame_observer.h"
#include "content/shell/renderer/shell_render_process_observer.h"
#include "content/shell/renderer/shell_render_view_observer.h"
+#include "content/shell/renderer/test_runner/WebTestInterfaces.h"
+#include "content/shell/renderer/test_runner/WebTestProxy.h"
+#include "content/shell/renderer/test_runner/WebTestRunner.h"
#include "content/shell/renderer/webkit_test_runner.h"
#include "content/test/mock_webclipboard_impl.h"
#include "third_party/WebKit/public/platform/WebMediaStreamCenter.h"
-#include "third_party/WebKit/public/testing/WebTestInterfaces.h"
-#include "third_party/WebKit/public/testing/WebTestProxy.h"
-#include "third_party/WebKit/public/testing/WebTestRunner.h"
#include "third_party/WebKit/public/web/WebPluginParams.h"
#include "third_party/WebKit/public/web/WebView.h"
#include "v8/include/v8.h"
diff --git a/content/shell/renderer/shell_render_frame_observer.cc b/content/shell/renderer/shell_render_frame_observer.cc
index a7c367d..9d6c251 100644
--- a/content/shell/renderer/shell_render_frame_observer.cc
+++ b/content/shell/renderer/shell_render_frame_observer.cc
@@ -7,8 +7,8 @@
#include "base/command_line.h"
#include "content/shell/common/shell_switches.h"
#include "content/shell/renderer/shell_render_process_observer.h"
-#include "third_party/WebKit/public/testing/WebTestInterfaces.h"
-#include "third_party/WebKit/public/testing/WebTestRunner.h"
+#include "content/shell/renderer/test_runner/WebTestInterfaces.h"
+#include "content/shell/renderer/test_runner/WebTestRunner.h"
#include "third_party/WebKit/public/web/WebFrame.h"
namespace content {
diff --git a/content/shell/renderer/shell_render_process_observer.cc b/content/shell/renderer/shell_render_process_observer.cc
index c4fc640..457ccc4 100644
--- a/content/shell/renderer/shell_render_process_observer.cc
+++ b/content/shell/renderer/shell_render_process_observer.cc
@@ -13,8 +13,8 @@
#include "content/shell/common/shell_switches.h"
#include "content/shell/renderer/gc_extension.h"
#include "content/shell/renderer/shell_content_renderer_client.h"
+#include "content/shell/renderer/test_runner/WebTestInterfaces.h"
#include "content/shell/renderer/webkit_test_runner.h"
-#include "third_party/WebKit/public/testing/WebTestInterfaces.h"
#include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
#include "third_party/WebKit/public/web/WebView.h"
#include "webkit/glue/webkit_glue.h"
diff --git a/content/shell/renderer/test_runner/AccessibilityController.cpp b/content/shell/renderer/test_runner/AccessibilityController.cpp
new file mode 100644
index 0000000..9225ede
--- /dev/null
+++ b/content/shell/renderer/test_runner/AccessibilityController.cpp
@@ -0,0 +1,180 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/shell/renderer/test_runner/AccessibilityController.h"
+
+#include "content/shell/renderer/test_runner/WebTestDelegate.h"
+#include "third_party/WebKit/public/platform/WebCString.h"
+#include "third_party/WebKit/public/web/WebAXObject.h"
+#include "third_party/WebKit/public/web/WebElement.h"
+#include "third_party/WebKit/public/web/WebFrame.h"
+#include "third_party/WebKit/public/web/WebNode.h"
+#include "third_party/WebKit/public/web/WebView.h"
+
+using namespace blink;
+
+namespace WebTestRunner {
+
+AccessibilityController::AccessibilityController()
+ : m_logAccessibilityEvents(false)
+{
+
+ bindMethod("logAccessibilityEvents", &AccessibilityController::logAccessibilityEventsCallback);
+ bindMethod("addNotificationListener", &AccessibilityController::addNotificationListenerCallback);
+ bindMethod("removeNotificationListener", &AccessibilityController::removeNotificationListenerCallback);
+
+ bindProperty("focusedElement", &AccessibilityController::focusedElementGetterCallback);
+ bindProperty("rootElement", &AccessibilityController::rootElementGetterCallback);
+
+ bindMethod("accessibleElementById", &AccessibilityController::accessibleElementByIdGetterCallback);
+
+ bindFallbackMethod(&AccessibilityController::fallbackCallback);
+}
+
+void AccessibilityController::bindToJavascript(WebFrame* frame, const WebString& classname)
+{
+ WebAXObject::enableAccessibility();
+ WebAXObject::enableInlineTextBoxAccessibility();
+ CppBoundClass::bindToJavascript(frame, classname);
+}
+
+void AccessibilityController::reset()
+{
+ m_rootElement = WebAXObject();
+ m_focusedElement = WebAXObject();
+ m_elements.clear();
+ m_notificationCallbacks.clear();
+
+ m_logAccessibilityEvents = false;
+}
+
+void AccessibilityController::setFocusedElement(const WebAXObject& focusedElement)
+{
+ m_focusedElement = focusedElement;
+}
+
+WebAXObjectProxy* AccessibilityController::getFocusedElement()
+{
+ if (m_focusedElement.isNull())
+ m_focusedElement = m_webView->accessibilityObject();
+ return m_elements.getOrCreate(m_focusedElement);
+}
+
+WebAXObjectProxy* AccessibilityController::getRootElement()
+{
+ if (m_rootElement.isNull())
+ m_rootElement = m_webView->accessibilityObject();
+ return m_elements.createRoot(m_rootElement);
+}
+
+WebAXObjectProxy* AccessibilityController::findAccessibleElementByIdRecursive(const WebAXObject& obj, const WebString& id)
+{
+ if (obj.isNull() || obj.isDetached())
+ return 0;
+
+ WebNode node = obj.node();
+ if (!node.isNull() && node.isElementNode()) {
+ WebElement element = node.to<WebElement>();
+ element.getAttribute("id");
+ if (element.getAttribute("id") == id)
+ return m_elements.getOrCreate(obj);
+ }
+
+ unsigned childCount = obj.childCount();
+ for (unsigned i = 0; i < childCount; i++) {
+ if (WebAXObjectProxy* result = findAccessibleElementByIdRecursive(obj.childAt(i), id))
+ return result;
+ }
+
+ return 0;
+}
+
+WebAXObjectProxy* AccessibilityController::getAccessibleElementById(const std::string& id)
+{
+ if (m_rootElement.isNull())
+ m_rootElement = m_webView->accessibilityObject();
+
+ if (!m_rootElement.updateBackingStoreAndCheckValidity())
+ return 0;
+
+ return findAccessibleElementByIdRecursive(m_rootElement, WebString::fromUTF8(id.c_str()));
+}
+
+bool AccessibilityController::shouldLogAccessibilityEvents()
+{
+ return m_logAccessibilityEvents;
+}
+
+void AccessibilityController::notificationReceived(const blink::WebAXObject& target, const char* notificationName)
+{
+ // Call notification listeners on the element.
+ WebAXObjectProxy* element = m_elements.getOrCreate(target);
+ element->notificationReceived(notificationName);
+
+ // Call global notification listeners.
+ size_t callbackCount = m_notificationCallbacks.size();
+ for (size_t i = 0; i < callbackCount; i++) {
+ CppVariant arguments[2];
+ arguments[0].set(*element->getAsCppVariant());
+ arguments[1].set(notificationName);
+ CppVariant invokeResult;
+ m_notificationCallbacks[i].invokeDefault(arguments, 2, invokeResult);
+ }
+}
+
+void AccessibilityController::logAccessibilityEventsCallback(const CppArgumentList&, CppVariant* result)
+{
+ m_logAccessibilityEvents = true;
+ result->setNull();
+}
+
+void AccessibilityController::addNotificationListenerCallback(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() < 1 || !arguments[0].isObject()) {
+ result->setNull();
+ return;
+ }
+
+ m_notificationCallbacks.push_back(arguments[0]);
+ result->setNull();
+}
+
+void AccessibilityController::removeNotificationListenerCallback(const CppArgumentList&, CppVariant* result)
+{
+ // FIXME: Implement this.
+ result->setNull();
+}
+
+void AccessibilityController::focusedElementGetterCallback(CppVariant* result)
+{
+ result->set(*(getFocusedElement()->getAsCppVariant()));
+}
+
+void AccessibilityController::rootElementGetterCallback(CppVariant* result)
+{
+ result->set(*(getRootElement()->getAsCppVariant()));
+}
+
+void AccessibilityController::accessibleElementByIdGetterCallback(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ if (arguments.size() < 1 || !arguments[0].isString())
+ return;
+
+ std::string id = arguments[0].toString();
+ WebAXObjectProxy* foundElement = getAccessibleElementById(id);
+ if (!foundElement)
+ return;
+
+ result->set(*(foundElement->getAsCppVariant()));
+}
+
+void AccessibilityController::fallbackCallback(const CppArgumentList&, CppVariant* result)
+{
+ m_delegate->printMessage("CONSOLE MESSAGE: JavaScript ERROR: unknown method called on AccessibilityController\n");
+ result->setNull();
+}
+
+}
diff --git a/content/shell/renderer/test_runner/AccessibilityController.h b/content/shell/renderer/test_runner/AccessibilityController.h
new file mode 100644
index 0000000..42f7403
--- /dev/null
+++ b/content/shell/renderer/test_runner/AccessibilityController.h
@@ -0,0 +1,70 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef AccessibilityController_h
+#define AccessibilityController_h
+
+#include "content/shell/renderer/test_runner/CppBoundClass.h"
+#include "content/shell/renderer/test_runner/WebAXObjectProxy.h"
+
+namespace blink {
+class WebAXObject;
+class WebFrame;
+class WebView;
+}
+
+namespace WebTestRunner {
+
+class WebTestDelegate;
+
+class AccessibilityController : public CppBoundClass {
+public:
+ AccessibilityController();
+
+ // Shadow to include accessibility initialization.
+ void bindToJavascript(blink::WebFrame*, const blink::WebString& classname);
+ void reset();
+
+ void setFocusedElement(const blink::WebAXObject&);
+ WebAXObjectProxy* getFocusedElement();
+ WebAXObjectProxy* getRootElement();
+ WebAXObjectProxy* getAccessibleElementById(const std::string& id);
+
+ bool shouldLogAccessibilityEvents();
+
+ void notificationReceived(const blink::WebAXObject& target, const char* notificationName);
+
+ void setDelegate(WebTestDelegate* delegate) { m_delegate = delegate; }
+ void setWebView(blink::WebView* webView) { m_webView = webView; }
+
+private:
+ // If true, will log all accessibility notifications.
+ bool m_logAccessibilityEvents;
+
+ // Bound methods and properties
+ void logAccessibilityEventsCallback(const CppArgumentList&, CppVariant*);
+ void fallbackCallback(const CppArgumentList&, CppVariant*);
+ void addNotificationListenerCallback(const CppArgumentList&, CppVariant*);
+ void removeNotificationListenerCallback(const CppArgumentList&, CppVariant*);
+
+ void focusedElementGetterCallback(CppVariant*);
+ void rootElementGetterCallback(CppVariant*);
+ void accessibleElementByIdGetterCallback(const CppArgumentList&, CppVariant*);
+
+ WebAXObjectProxy* findAccessibleElementByIdRecursive(const blink::WebAXObject&, const blink::WebString& id);
+
+ blink::WebAXObject m_focusedElement;
+ blink::WebAXObject m_rootElement;
+
+ WebAXObjectProxyList m_elements;
+
+ std::vector<CppVariant> m_notificationCallbacks;
+
+ WebTestDelegate* m_delegate;
+ blink::WebView* m_webView;
+};
+
+}
+
+#endif // AccessibilityController_h
diff --git a/content/shell/renderer/test_runner/CppBoundClass.cpp b/content/shell/renderer/test_runner/CppBoundClass.cpp
new file mode 100644
index 0000000..e8d603f
--- /dev/null
+++ b/content/shell/renderer/test_runner/CppBoundClass.cpp
@@ -0,0 +1,362 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/*
+ * 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)
+ {
+ value->set(*m_value);
+ return true;
+ }
+
+ virtual bool setValue(const CppVariant& value)
+ {
+ m_value->set(value);
+ return true;
+ }
+
+private:
+ CppVariant* m_value;
+};
+
+class GetterPropertyCallback : public CppBoundClass::PropertyCallback {
+public:
+ GetterPropertyCallback(WebScopedPtr<CppBoundClass::GetterCallback> callback)
+ : m_callback(callback)
+ {
+ }
+
+ virtual bool getValue(CppVariant* value)
+ {
+ m_callback->run(value);
+ return true;
+ }
+
+ virtual bool setValue(const CppVariant& value) { return false; }
+
+private:
+ WebScopedPtr<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()
+{
+ 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, WebScopedPtr<GetterCallback> callback)
+{
+ PropertyCallback* propertyCallback = callback.get() ? new GetterPropertyCallback(callback) : 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..f3870fd
--- /dev/null
+++ b/content/shell/renderer/test_runner/CppBoundClass.h
@@ -0,0 +1,251 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/*
+ * 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 CppBoundClass_h
+#define CppBoundClass_h
+
+#include <map>
+#include <vector>
+
+#include "content/shell/renderer/test_runner/CppVariant.h"
+#include "content/shell/renderer/test_runner/WebScopedPtr.h"
+#include "third_party/WebKit/public/platform/WebNonCopyable.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 blink::WebNonCopyable {
+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() : m_boundToFrame(false) { }
+ 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&, WebScopedPtr<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*))
+ {
+ WebScopedPtr<GetterCallback> callback(new MemberGetterCallback<T>(static_cast<T*>(this), method));
+ bindGetterCallback(name, callback);
+ }
+
+ // 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(WebScopedPtr<Callback> fallbackCallback)
+ {
+ m_fallbackCallback = fallbackCallback;
+ }
+
+ // 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(WebScopedPtr<Callback>(new MemberCallback<T>(static_cast<T*>(this), method)));
+ else
+ bindFallbackCallback(WebScopedPtr<Callback>());
+ }
+
+ // 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.
+ WebScopedPtr<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;
+};
+
+}
+
+#endif // 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..47936df
--- /dev/null
+++ b/content/shell/renderer/test_runner/CppVariant.cpp
@@ -0,0 +1,296 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#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..1aa6c6d
--- /dev/null
+++ b/content/shell/renderer/test_runner/CppVariant.h
@@ -0,0 +1,119 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/*
+ This file contains the 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 CppVariant_h
+#define 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 // 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..5d7eec8
--- /dev/null
+++ b/content/shell/renderer/test_runner/EventSender.cpp
@@ -0,0 +1,1439 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains the definition for EventSender.
+//
+// Some notes about drag and drop handling:
+// Windows drag and drop goes through a system call to doDragDrop. At that
+// point, program control is given to Windows which then periodically makes
+// callbacks into the webview. This won't work for layout tests, so instead,
+// we queue up all the mouse move and mouse up events. When the test tries to
+// start a drag (by calling EvenSendingController::doDragDrop), we take the
+// events in the queue and replay them.
+// The behavior of queuing events and replaying them can be disabled by a
+// layout test by setting eventSender.dragMode to false.
+
+#include "content/shell/renderer/test_runner/EventSender.h"
+
+#include <deque>
+
+#include "content/shell/renderer/test_runner/KeyCodeMapping.h"
+#include "content/shell/renderer/test_runner/MockSpellCheck.h"
+#include "content/shell/renderer/test_runner/TestCommon.h"
+#include "content/shell/renderer/test_runner/TestInterfaces.h"
+#include "content/shell/renderer/test_runner/WebTestDelegate.h"
+#include "content/shell/renderer/test_runner/WebTestProxy.h"
+#include "third_party/WebKit/public/platform/WebDragData.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/platform/WebVector.h"
+#include "third_party/WebKit/public/web/WebContextMenuData.h"
+#include "third_party/WebKit/public/web/WebTouchPoint.h"
+#include "third_party/WebKit/public/web/WebView.h"
+
+#ifdef WIN32
+#include "third_party/WebKit/public/web/win/WebInputEventFactory.h"
+#elif __APPLE__
+#include "third_party/WebKit/public/web/mac/WebInputEventFactory.h"
+#elif defined(ANDROID)
+#include "third_party/WebKit/public/web/android/WebInputEventFactory.h"
+#elif defined(TOOLKIT_GTK)
+#include "third_party/WebKit/public/web/gtk/WebInputEventFactory.h"
+#endif
+
+// FIXME: layout before each event?
+
+using namespace std;
+using namespace blink;
+
+namespace WebTestRunner {
+
+WebPoint EventSender::lastMousePos;
+WebMouseEvent::Button EventSender::pressedButton = WebMouseEvent::ButtonNone;
+WebMouseEvent::Button EventSender::lastButtonType = WebMouseEvent::ButtonNone;
+
+namespace {
+
+struct SavedEvent {
+ enum SavedEventType {
+ Unspecified,
+ MouseUp,
+ MouseMove,
+ LeapForward
+ };
+
+ SavedEventType type;
+ WebMouseEvent::Button buttonType; // For MouseUp.
+ WebPoint pos; // For MouseMove.
+ int milliseconds; // For LeapForward.
+
+ SavedEvent()
+ : type(Unspecified)
+ , buttonType(WebMouseEvent::ButtonNone)
+ , milliseconds(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)
+{
+ e->type = t;
+ e->button = b;
+ e->modifiers = 0;
+ e->x = pos.x;
+ e->y = pos.y;
+ e->globalX = pos.x;
+ e->globalY = pos.y;
+ e->timeStampSeconds = ts;
+ e->clickCount = clickCount;
+}
+
+void applyKeyModifier(const string& modifierName, WebInputEvent* event)
+{
+ const char* characters = modifierName.c_str();
+ if (!strcmp(characters, "ctrlKey")
+#ifndef __APPLE__
+ || !strcmp(characters, "addSelectionKey")
+#endif
+ ) {
+ event->modifiers |= WebInputEvent::ControlKey;
+ } else if (!strcmp(characters, "shiftKey") || !strcmp(characters, "rangeSelectionKey"))
+ event->modifiers |= WebInputEvent::ShiftKey;
+ else if (!strcmp(characters, "altKey")) {
+ event->modifiers |= WebInputEvent::AltKey;
+#ifdef __APPLE__
+ } else if (!strcmp(characters, "metaKey") || !strcmp(characters, "addSelectionKey")) {
+ event->modifiers |= WebInputEvent::MetaKey;
+#else
+ } else if (!strcmp(characters, "metaKey")) {
+ event->modifiers |= WebInputEvent::MetaKey;
+#endif
+ } else if (!strcmp(characters, "autoRepeat")) {
+ event->modifiers |= WebInputEvent::IsAutoRepeat;
+ }
+}
+
+void applyKeyModifiers(const CppVariant* argument, WebInputEvent* event)
+{
+ if (argument->isObject()) {
+ vector<string> modifiers = argument->toStringVector();
+ for (vector<string>::const_iterator i = modifiers.begin(); i != modifiers.end(); ++i)
+ applyKeyModifier(*i, event);
+ } else if (argument->isString()) {
+ applyKeyModifier(argument->toString(), event);
+ }
+}
+
+// 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 = WebScopedPtr<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));
+ 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;
+ initMouseEvent(WebInputEvent::MouseDown, buttonType, lastMousePos, &event, getCurrentEventTimeSec(m_delegate));
+ if (arguments.size() >= 2 && (arguments[1].isObject() || arguments[1].isString()))
+ applyKeyModifiers(&(arguments[1]), &event);
+ 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);
+
+ if (isDragMode() && !replayingSavedEvents) {
+ SavedEvent savedEvent;
+ savedEvent.type = SavedEvent::MouseUp;
+ savedEvent.buttonType = buttonType;
+ mouseEventQueue.push_back(savedEvent);
+ replaySavedEvents();
+ } else {
+ WebMouseEvent event;
+ initMouseEvent(WebInputEvent::MouseUp, buttonType, lastMousePos, &event, getCurrentEventTimeSec(m_delegate));
+ if (arguments.size() >= 2 && (arguments[1].isObject() || arguments[1].isString()))
+ applyKeyModifiers(&(arguments[1]), &event);
+ 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)
+ webview()->dragTargetDrop(clientPoint, screenPoint, 0);
+ 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());
+
+ if (isDragMode() && pressedButton == WebMouseEvent::ButtonLeft && !replayingSavedEvents) {
+ SavedEvent savedEvent;
+ savedEvent.type = SavedEvent::MouseMove;
+ savedEvent.pos = mousePos;
+ mouseEventQueue.push_back(savedEvent);
+ } else {
+ WebMouseEvent event;
+ initMouseEvent(WebInputEvent::MouseMove, pressedButton, mousePos, &event, getCurrentEventTimeSec(m_delegate));
+ if (arguments.size() >= 3 && (arguments[2].isObject() || arguments[2].isString()))
+ applyKeyModifiers(&(arguments[2]), &event);
+ 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())) {
+ applyKeyModifiers(&(arguments[1]), &eventDown);
+#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));
+ 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));
+ 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));
+ 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));
+ webview()->handleInputEvent(event);
+
+#ifdef WIN32
+ initMouseEvent(WebInputEvent::MouseUp, WebMouseEvent::ButtonRight, lastMousePos, &event, getCurrentEventTimeSec(m_delegate));
+ 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() { 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() { 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() { 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 = WebPoint(arguments[0].toInt32(), arguments[1].toInt32());
+ touchPoint.screenPosition = touchPoint.position;
+
+ if (arguments.size() > 2) {
+ int radiusX = arguments[2].toInt32();
+ int radiusY = radiusX;
+ if (arguments.size() > 3)
+ radiusY = arguments[3].toInt32();
+
+ touchPoint.radiusX = radiusX;
+ touchPoint.radiusY = radiusY;
+ }
+
+ int lowestId = 0;
+ for (size_t i = 0; i < touchPoints.size(); i++) {
+ if (touchPoints[i].id == lowestId)
+ lowestId++;
+ }
+ touchPoint.id = lowestId;
+ touchPoints.push_back(touchPoint);
+}
+
+void EventSender::clearTouchPoints(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+ touchPoints.clear();
+}
+
+void EventSender::releaseTouchPoint(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ const unsigned index = arguments[0].toInt32();
+ BLINK_ASSERT(index < touchPoints.size());
+
+ WebTouchPoint* touchPoint = &touchPoints[index];
+ touchPoint->state = WebTouchPoint::StateReleased;
+}
+
+void EventSender::setTouchModifier(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ int mask = 0;
+ const string keyName = arguments[0].toString();
+ if (keyName == "shift")
+ mask = WebInputEvent::ShiftKey;
+ else if (keyName == "alt")
+ mask = WebInputEvent::AltKey;
+ else if (keyName == "ctrl")
+ mask = WebInputEvent::ControlKey;
+ else if (keyName == "meta")
+ mask = WebInputEvent::MetaKey;
+
+ if (arguments[1].toBoolean())
+ touchModifiers |= mask;
+ else
+ touchModifiers &= ~mask;
+}
+
+void EventSender::updateTouchPoint(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ const unsigned index = arguments[0].toInt32();
+ BLINK_ASSERT(index < touchPoints.size());
+
+ WebPoint position(arguments[1].toInt32(), arguments[2].toInt32());
+ WebTouchPoint* touchPoint = &touchPoints[index];
+ touchPoint->state = WebTouchPoint::StateMoved;
+ touchPoint->position = position;
+ touchPoint->screenPosition = 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));
+ 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));
+ 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));
+ 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));
+ 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;
+
+ if (arguments.size() > 2 && arguments[2].isBool())
+ paged = arguments[2].toBoolean();
+
+ if (arguments.size() > 3 && arguments[3].isBool())
+ hasPreciseScrollingDeltas = arguments[3].toBoolean();
+
+ initMouseEvent(WebInputEvent::MouseWheel, pressedButton, lastMousePos, event, getCurrentEventTimeSec(m_delegate));
+ 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));
+ 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..03edb81
--- /dev/null
+++ b/content/shell/renderer/test_runner/EventSender.h
@@ -0,0 +1,188 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/*
+ EventSender class:
+ Bound to a JavaScript window.eventSender object using
+ CppBoundClass::bindToJavascript(), this allows layout tests to fire DOM events.
+*/
+
+#ifndef EventSender_h
+#define EventSender_h
+
+#include "content/shell/renderer/test_runner/CppBoundClass.h"
+#include "content/shell/renderer/test_runner/WebScopedPtr.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*);
+ ~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;
+
+ WebScopedPtr<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 // EventSender_h
diff --git a/content/shell/renderer/test_runner/GamepadController.cpp b/content/shell/renderer/test_runner/GamepadController.cpp
new file mode 100644
index 0000000..559585b
--- /dev/null
+++ b/content/shell/renderer/test_runner/GamepadController.cpp
@@ -0,0 +1,173 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/shell/renderer/test_runner/GamepadController.h"
+
+#include "content/shell/renderer/test_runner/WebTestDelegate.h"
+
+using namespace blink;
+
+namespace WebTestRunner {
+
+GamepadController::GamepadController()
+{
+ bindMethod("connect", &GamepadController::connect);
+ bindMethod("disconnect", &GamepadController::disconnect);
+ bindMethod("setId", &GamepadController::setId);
+ bindMethod("setButtonCount", &GamepadController::setButtonCount);
+ bindMethod("setButtonData", &GamepadController::setButtonData);
+ bindMethod("setAxisCount", &GamepadController::setAxisCount);
+ bindMethod("setAxisData", &GamepadController::setAxisData);
+
+ bindFallbackMethod(&GamepadController::fallbackCallback);
+
+ reset();
+}
+
+void GamepadController::bindToJavascript(WebFrame* frame, const WebString& classname)
+{
+ CppBoundClass::bindToJavascript(frame, classname);
+}
+
+void GamepadController::setDelegate(WebTestDelegate* delegate)
+{
+ m_delegate = delegate;
+}
+
+void GamepadController::reset()
+{
+ memset(&m_gamepads, 0, sizeof(m_gamepads));
+}
+
+void GamepadController::connect(const CppArgumentList& args, CppVariant* result)
+{
+ if (args.size() < 1) {
+ m_delegate->printMessage("Invalid args");
+ return;
+ }
+ int index = args[0].toInt32();
+ if (index < 0 || index >= static_cast<int>(blink::WebGamepads::itemsLengthCap))
+ return;
+ m_gamepads.items[index].connected = true;
+ m_gamepads.length = 0;
+ for (unsigned i = 0; i < blink::WebGamepads::itemsLengthCap; ++i)
+ if (m_gamepads.items[i].connected)
+ m_gamepads.length = i + 1;
+ m_delegate->setGamepadData(m_gamepads);
+ result->setNull();
+}
+
+void GamepadController::disconnect(const CppArgumentList& args, CppVariant* result)
+{
+ if (args.size() < 1) {
+ m_delegate->printMessage("Invalid args");
+ return;
+ }
+ int index = args[0].toInt32();
+ if (index < 0 || index >= static_cast<int>(blink::WebGamepads::itemsLengthCap))
+ return;
+ m_gamepads.items[index].connected = false;
+ m_gamepads.length = 0;
+ for (unsigned i = 0; i < blink::WebGamepads::itemsLengthCap; ++i)
+ if (m_gamepads.items[i].connected)
+ m_gamepads.length = i + 1;
+ m_delegate->setGamepadData(m_gamepads);
+ result->setNull();
+}
+
+void GamepadController::setId(const CppArgumentList& args, CppVariant* result)
+{
+ if (args.size() < 2) {
+ m_delegate->printMessage("Invalid args");
+ return;
+ }
+ int index = args[0].toInt32();
+ if (index < 0 || index >= static_cast<int>(blink::WebGamepads::itemsLengthCap))
+ return;
+ std::string src = args[1].toString();
+ const char* p = src.c_str();
+ memset(m_gamepads.items[index].id, 0, sizeof(m_gamepads.items[index].id));
+ for (unsigned i = 0; *p && i < blink::WebGamepad::idLengthCap - 1; ++i)
+ m_gamepads.items[index].id[i] = *p++;
+ m_delegate->setGamepadData(m_gamepads);
+ result->setNull();
+}
+
+void GamepadController::setButtonCount(const CppArgumentList& args, CppVariant* result)
+{
+ if (args.size() < 2) {
+ m_delegate->printMessage("Invalid args");
+ return;
+ }
+ int index = args[0].toInt32();
+ if (index < 0 || index >= static_cast<int>(blink::WebGamepads::itemsLengthCap))
+ return;
+ int buttons = args[1].toInt32();
+ if (buttons < 0 || buttons >= static_cast<int>(blink::WebGamepad::buttonsLengthCap))
+ return;
+ m_gamepads.items[index].buttonsLength = buttons;
+ m_delegate->setGamepadData(m_gamepads);
+ result->setNull();
+}
+
+void GamepadController::setButtonData(const CppArgumentList& args, CppVariant* result)
+{
+ if (args.size() < 3) {
+ m_delegate->printMessage("Invalid args");
+ return;
+ }
+ int index = args[0].toInt32();
+ if (index < 0 || index >= static_cast<int>(blink::WebGamepads::itemsLengthCap))
+ return;
+ int button = args[1].toInt32();
+ if (button < 0 || button >= static_cast<int>(blink::WebGamepad::buttonsLengthCap))
+ return;
+ double data = args[2].toDouble();
+ m_gamepads.items[index].buttons[button] = data;
+ m_delegate->setGamepadData(m_gamepads);
+ result->setNull();
+}
+
+void GamepadController::setAxisCount(const CppArgumentList& args, CppVariant* result)
+{
+ if (args.size() < 2) {
+ m_delegate->printMessage("Invalid args");
+ return;
+ }
+ int index = args[0].toInt32();
+ if (index < 0 || index >= static_cast<int>(blink::WebGamepads::itemsLengthCap))
+ return;
+ int axes = args[1].toInt32();
+ if (axes < 0 || axes >= static_cast<int>(blink::WebGamepad::axesLengthCap))
+ return;
+ m_gamepads.items[index].axesLength = axes;
+ m_delegate->setGamepadData(m_gamepads);
+ result->setNull();
+}
+
+void GamepadController::setAxisData(const CppArgumentList& args, CppVariant* result)
+{
+ if (args.size() < 3) {
+ m_delegate->printMessage("Invalid args");
+ return;
+ }
+ int index = args[0].toInt32();
+ if (index < 0 || index >= static_cast<int>(blink::WebGamepads::itemsLengthCap))
+ return;
+ int axis = args[1].toInt32();
+ if (axis < 0 || axis >= static_cast<int>(blink::WebGamepad::axesLengthCap))
+ return;
+ double data = args[2].toDouble();
+ m_gamepads.items[index].axes[axis] = data;
+ m_delegate->setGamepadData(m_gamepads);
+ result->setNull();
+}
+
+void GamepadController::fallbackCallback(const CppArgumentList&, CppVariant* result)
+{
+ m_delegate->printMessage("CONSOLE MESSAGE: JavaScript ERROR: unknown method called on GamepadController\n");
+ result->setNull();
+}
+
+}
diff --git a/content/shell/renderer/test_runner/GamepadController.h b/content/shell/renderer/test_runner/GamepadController.h
new file mode 100644
index 0000000..68ec793
--- /dev/null
+++ b/content/shell/renderer/test_runner/GamepadController.h
@@ -0,0 +1,46 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GamepadController_h
+#define GamepadController_h
+
+#include "content/shell/renderer/test_runner/CppBoundClass.h"
+#include "third_party/WebKit/public/platform/WebGamepads.h"
+
+namespace blink {
+class WebGamepads;
+class WebFrame;
+}
+
+namespace WebTestRunner {
+
+class WebTestDelegate;
+
+class GamepadController : public CppBoundClass {
+public:
+ GamepadController();
+
+ void bindToJavascript(blink::WebFrame*, const blink::WebString& classname);
+ void setDelegate(WebTestDelegate*);
+ void reset();
+
+private:
+ // Bound methods and properties
+ void connect(const CppArgumentList&, CppVariant*);
+ void disconnect(const CppArgumentList&, CppVariant*);
+ void setId(const CppArgumentList&, CppVariant*);
+ void setButtonCount(const CppArgumentList&, CppVariant*);
+ void setButtonData(const CppArgumentList&, CppVariant*);
+ void setAxisCount(const CppArgumentList&, CppVariant*);
+ void setAxisData(const CppArgumentList&, CppVariant*);
+ void fallbackCallback(const CppArgumentList&, CppVariant*);
+
+ blink::WebGamepads m_gamepads;
+
+ WebTestDelegate* m_delegate;
+};
+
+}
+
+#endif // GamepadController_h
diff --git a/content/shell/renderer/test_runner/KeyCodeMapping.cpp b/content/shell/renderer/test_runner/KeyCodeMapping.cpp
new file mode 100644
index 0000000..e5ec961
--- /dev/null
+++ b/content/shell/renderer/test_runner/KeyCodeMapping.cpp
@@ -0,0 +1,222 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/shell/renderer/test_runner/KeyCodeMapping.h"
+
+#include "content/shell/renderer/test_runner/TestCommon.h"
+
+namespace WebTestRunner {
+
+int NativeKeyCodeForWindowsKeyCode(int keysym)
+{
+#if defined(__linux__) && defined(TOOLKIT_GTK)
+ // See /usr/share/X11/xkb/keycodes/*
+ static const int asciiToKeyCode[] = {
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22,
+ 23,
+ 0,
+ 0,
+ 0,
+ 36,
+ 0,
+ 0,
+ 50,
+ 37,
+ 64,
+ 127,
+ 66,
+ 0,
+ 0,
+ 0,
+ 0,
+ 131,
+ 0,
+ 9,
+ 100,
+ 102,
+ 0,
+ 0,
+ 65, // ' '
+ 112, // '!'
+ 117, // '"'
+ 115, // '#'
+ 110, // '$'
+ 113, // '%'
+ 111, // '&'
+ 114, // '''
+ 116, // '('
+ 0, // ')'
+ 107, // '*'
+ 0, // '+'
+ 0, // ','
+ 118, // '-'
+ 119, // '.'
+ 146, // '/'
+ 19, // '0'
+ 10, // '1'
+ 11, // '2'
+ 12, // '3'
+ 13, // '4'
+ 14, // '5'
+ 15, // '6'
+ 16, // '7'
+ 17, // '8'
+ 18, // '9'
+ 0, // ':'
+ 0, // ';'
+ 0, // '<'
+ 0, // '='
+ 0, // '>'
+ 0, // '?'
+ 0, // '@'
+ 38, // 'A'
+ 56, // 'B'
+ 54, // 'C'
+ 40, // 'D'
+ 26, // 'E'
+ 41, // 'F'
+ 42, // 'G'
+ 43, // 'H'
+ 31, // 'I'
+ 44, // 'J'
+ 45, // 'K'
+ 46, // 'L'
+ 58, // 'M'
+ 57, // 'N'
+ 32, // 'O'
+ 33, // 'P'
+ 24, // 'Q'
+ 27, // 'R'
+ 39, // 'S'
+ 28, // 'T'
+ 30, // 'U'
+ 55, // 'V'
+ 25, // 'W'
+ 53, // 'X'
+ 29, // 'Y'
+ 52, // 'Z'
+ 133, // '['
+ 134, // '\'
+ 135, // ']'
+ 0, // '^'
+ 0, // '_'
+ 90, // '`'
+ 38, // 'a'
+ 56, // 'b'
+ 54, // 'c'
+ 40, // 'd'
+ 26, // 'e'
+ 41, // 'f'
+ 42, // 'g'
+ 43, // 'h'
+ 31, // 'i'
+ 44, // 'j'
+ 45, // 'k'
+ 46, // 'l'
+ 58, // 'm'
+ 57, // 'n'
+ 32, // 'o'
+ 33, // 'p'
+ 24, // 'q'
+ 27, // 'r'
+ 39, // 's'
+ 28, // 't'
+ 30, // 'u'
+ 55, // 'v'
+ 25, // 'w'
+ 53, // 'x'
+ 29, // 'y'
+ 52, // 'z'
+ 96, // '{'
+ 0, // '|'
+ 0, // '}'
+ 0, // '~'
+ 0, // DEL
+ };
+
+ if (keysym <= 127)
+ return asciiToKeyCode[keysym];
+
+ switch (keysym) {
+ case VKEY_PRIOR:
+ return 112;
+ case VKEY_NEXT:
+ return 117;
+ case VKEY_END:
+ return 115;
+ case VKEY_HOME:
+ return 110;
+ case VKEY_LEFT:
+ return 113;
+ case VKEY_UP:
+ return 111;
+ case VKEY_RIGHT:
+ return 114;
+ case VKEY_DOWN:
+ return 116;
+ case VKEY_SNAPSHOT:
+ return 107;
+ case VKEY_INSERT:
+ return 118;
+ case VKEY_DELETE:
+ return 119;
+ case VKEY_APPS:
+ return 135;
+ case VKEY_F1:
+ case VKEY_F1 + 1:
+ case VKEY_F1 + 2:
+ case VKEY_F1 + 3:
+ case VKEY_F1 + 4:
+ case VKEY_F1 + 5:
+ case VKEY_F1 + 6:
+ case VKEY_F1 + 7:
+ case VKEY_F1 + 8:
+ case VKEY_F1 + 9:
+ case VKEY_F1 + 10:
+ case VKEY_F1 + 11:
+ case VKEY_F1 + 12:
+ case VKEY_F1 + 13:
+ case VKEY_F1 + 14:
+ case VKEY_F1 + 15:
+ case VKEY_F1 + 16:
+ case VKEY_F1 + 17:
+ case VKEY_F1 + 18:
+ case VKEY_F1 + 19:
+ case VKEY_F1 + 20:
+ case VKEY_F1 + 21:
+ case VKEY_F1 + 22:
+ case VKEY_F1 + 23:
+ return 67 + (keysym - VKEY_F1);
+ case VKEY_LSHIFT:
+ return 50;
+ case VKEY_RSHIFT:
+ return 62;
+ case VKEY_LCONTROL:
+ return 37;
+ case VKEY_RCONTROL:
+ return 105;
+ case VKEY_LMENU:
+ return 64;
+ case VKEY_RMENU:
+ return 108;
+ case VKEY_NUMLOCK:
+ return 77;
+
+ default:
+ return 0;
+ }
+#else
+ return keysym - keysym;
+#endif
+}
+
+}
diff --git a/content/shell/renderer/test_runner/KeyCodeMapping.h b/content/shell/renderer/test_runner/KeyCodeMapping.h
new file mode 100644
index 0000000..75325e1
--- /dev/null
+++ b/content/shell/renderer/test_runner/KeyCodeMapping.h
@@ -0,0 +1,41 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef KeyCodeMapping_h
+#define KeyCodeMapping_h
+
+namespace WebTestRunner {
+
+// The keycodes match the values of the virtual keycodes found here http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
+enum {
+ VKEY_RETURN = 0x0D,
+ VKEY_ESCAPE = 0x1B,
+ VKEY_PRIOR = 0x21,
+ VKEY_NEXT = 0x22,
+ VKEY_END = 0x23,
+ VKEY_HOME = 0x24,
+ VKEY_LEFT = 0x25,
+ VKEY_UP = 0x26,
+ VKEY_RIGHT = 0x27,
+ VKEY_DOWN = 0x28,
+ VKEY_SNAPSHOT = 0x2C,
+ VKEY_INSERT = 0x2D,
+ VKEY_DELETE = 0x2E,
+ VKEY_APPS = 0x5D,
+ VKEY_F1 = 0x70,
+ VKEY_NUMLOCK = 0x90,
+ VKEY_LSHIFT = 0xA0,
+ VKEY_RSHIFT = 0xA1,
+ VKEY_LCONTROL = 0xA2,
+ VKEY_RCONTROL = 0xA3,
+ VKEY_LMENU = 0xA4,
+ VKEY_RMENU = 0xA5,
+};
+
+// Map a windows keycode to a native keycode on defined(__linux__) && defined(TOOLKIT_GTK).
+int NativeKeyCodeForWindowsKeyCode(int keysym);
+
+}
+
+#endif // KeyCodeMapping_h
diff --git a/content/shell/renderer/test_runner/MockColorChooser.cpp b/content/shell/renderer/test_runner/MockColorChooser.cpp
new file mode 100644
index 0000000..7b88a5a
--- /dev/null
+++ b/content/shell/renderer/test_runner/MockColorChooser.cpp
@@ -0,0 +1,58 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/shell/renderer/test_runner/MockColorChooser.h"
+
+#include "content/shell/renderer/test_runner/WebTestDelegate.h"
+#include "content/shell/renderer/test_runner/WebTestProxy.h"
+
+using namespace blink;
+using namespace std;
+
+namespace WebTestRunner {
+
+namespace {
+class HostMethodTask : public WebMethodTask<MockColorChooser> {
+public:
+ typedef void (MockColorChooser::*CallbackMethodType)();
+ HostMethodTask(MockColorChooser* object, CallbackMethodType callback)
+ : WebMethodTask<MockColorChooser>(object)
+ , m_callback(callback)
+ { }
+
+ virtual void runIfValid() { (m_object->*m_callback)(); }
+
+private:
+ CallbackMethodType m_callback;
+};
+}
+
+MockColorChooser::MockColorChooser(blink::WebColorChooserClient* client, WebTestDelegate* delegate, WebTestProxyBase* proxy)
+ : m_client(client)
+ , m_delegate(delegate)
+ , m_proxy(proxy)
+{
+ m_proxy->didOpenChooser();
+}
+
+MockColorChooser::~MockColorChooser()
+{
+ m_proxy->didCloseChooser();
+}
+
+void MockColorChooser::setSelectedColor(const blink::WebColor)
+{
+}
+
+void MockColorChooser::endChooser()
+{
+ m_delegate->postDelayedTask(new HostMethodTask(this, &MockColorChooser::invokeDidEndChooser), 0);
+}
+
+void MockColorChooser::invokeDidEndChooser()
+{
+ m_client->didEndChooser();
+}
+
+}
diff --git a/content/shell/renderer/test_runner/MockColorChooser.h b/content/shell/renderer/test_runner/MockColorChooser.h
new file mode 100644
index 0000000..5641114
--- /dev/null
+++ b/content/shell/renderer/test_runner/MockColorChooser.h
@@ -0,0 +1,38 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MockColorChooser_h
+#define MockColorChooser_h
+
+#include "content/shell/renderer/test_runner/TestCommon.h"
+#include "content/shell/renderer/test_runner/WebTask.h"
+#include "third_party/WebKit/public/platform/WebNonCopyable.h"
+#include "third_party/WebKit/public/web/WebColorChooser.h"
+#include "third_party/WebKit/public/web/WebColorChooserClient.h"
+
+namespace WebTestRunner {
+
+class WebTestDelegate;
+class WebTestProxyBase;
+class MockColorChooser : public blink::WebColorChooser, public blink::WebNonCopyable {
+public:
+ MockColorChooser(blink::WebColorChooserClient*, WebTestDelegate*, WebTestProxyBase*);
+ virtual ~MockColorChooser();
+
+ // blink::WebColorChooser implementation.
+ virtual void setSelectedColor(const blink::WebColor) OVERRIDE;
+ virtual void endChooser() OVERRIDE;
+
+ void invokeDidEndChooser();
+ WebTaskList* taskList() { return &m_taskList; }
+private:
+ blink::WebColorChooserClient* m_client;
+ WebTestDelegate* m_delegate;
+ WebTestProxyBase* m_proxy;
+ WebTaskList m_taskList;
+};
+
+}
+
+#endif // MockColorChooser_h
diff --git a/content/shell/renderer/test_runner/MockConstraints.cpp b/content/shell/renderer/test_runner/MockConstraints.cpp
new file mode 100644
index 0000000..2fdb9fe
--- /dev/null
+++ b/content/shell/renderer/test_runner/MockConstraints.cpp
@@ -0,0 +1,59 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/shell/renderer/test_runner/MockConstraints.h"
+
+#include "third_party/WebKit/public/platform/WebMediaConstraints.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+
+using namespace blink;
+
+namespace WebTestRunner {
+
+namespace {
+
+bool isSupported(const WebString& constraint)
+{
+ return constraint == "valid_and_supported_1" || constraint == "valid_and_supported_2";
+}
+
+bool isValid(const WebString& constraint)
+{
+ return isSupported(constraint) || constraint == "valid_but_unsupported_1" || constraint == "valid_but_unsupported_2";
+}
+
+}
+
+bool MockConstraints::verifyConstraints(const WebMediaConstraints& constraints, WebString* failedConstraint)
+{
+ WebVector<WebMediaConstraint> mandatoryConstraints;
+ constraints.getMandatoryConstraints(mandatoryConstraints);
+ if (mandatoryConstraints.size()) {
+ for (size_t i = 0; i < mandatoryConstraints.size(); ++i) {
+ const WebMediaConstraint& curr = mandatoryConstraints[i];
+ if (!isSupported(curr.m_name) || curr.m_value != "1") {
+ if (failedConstraint)
+ *failedConstraint = curr.m_name;
+ return false;
+ }
+ }
+ }
+
+ WebVector<WebMediaConstraint> optionalConstraints;
+ constraints.getOptionalConstraints(optionalConstraints);
+ if (optionalConstraints.size()) {
+ for (size_t i = 0; i < optionalConstraints.size(); ++i) {
+ const WebMediaConstraint& curr = optionalConstraints[i];
+ if (!isValid(curr.m_name) || curr.m_value != "0") {
+ if (failedConstraint)
+ *failedConstraint = curr.m_name;
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+}
diff --git a/content/shell/renderer/test_runner/MockConstraints.h b/content/shell/renderer/test_runner/MockConstraints.h
new file mode 100644
index 0000000..1ed1c73
--- /dev/null
+++ b/content/shell/renderer/test_runner/MockConstraints.h
@@ -0,0 +1,22 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MockConstraints_h
+#define MockConstraints_h
+
+namespace blink {
+class WebMediaConstraints;
+class WebString;
+}
+
+namespace WebTestRunner {
+
+class MockConstraints {
+public:
+ static bool verifyConstraints(const blink::WebMediaConstraints&, blink::WebString* failedConstraint = 0);
+};
+
+}
+
+#endif // MockConstraints_h
diff --git a/content/shell/renderer/test_runner/MockGrammarCheck.cpp b/content/shell/renderer/test_runner/MockGrammarCheck.cpp
new file mode 100644
index 0000000..9a27c5e
--- /dev/null
+++ b/content/shell/renderer/test_runner/MockGrammarCheck.cpp
@@ -0,0 +1,58 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/shell/renderer/test_runner/MockGrammarCheck.h"
+
+#include <algorithm>
+
+#include "content/shell/renderer/test_runner/TestCommon.h"
+#include "third_party/WebKit/public/platform/WebCString.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/web/WebTextCheckingResult.h"
+
+using namespace blink;
+using namespace std;
+
+namespace WebTestRunner {
+
+bool MockGrammarCheck::checkGrammarOfString(const WebString& text, vector<WebTextCheckingResult>* results)
+{
+ BLINK_ASSERT(results);
+ string16 stringText = text;
+ if (find_if(stringText.begin(), stringText.end(), isASCIIAlpha) == stringText.end())
+ return true;
+
+ // Find matching grammatical errors from known ones. This function has to
+ // check all errors because the given text may consist of two or more
+ // sentences that have grammatical errors.
+ static const struct {
+ const char* text;
+ int location;
+ int length;
+ } grammarErrors[] = {
+ {"I have a issue.", 7, 1},
+ {"I have an grape.", 7, 2},
+ {"I have an kiwi.", 7, 2},
+ {"I have an muscat.", 7, 2},
+ {"You has the right.", 4, 3},
+ {"apple orange zz.", 0, 16},
+ {"apple zz orange.", 0, 16},
+ {"apple,zz,orange.", 0, 16},
+ {"orange,zz,apple.", 0, 16},
+ {"the the adlj adaasj sdklj. there there", 4, 3},
+ {"the the adlj adaasj sdklj. there there", 33, 5},
+ {"zz apple orange.", 0, 16},
+ };
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(grammarErrors); ++i) {
+ size_t offset = 0;
+ string16 error(grammarErrors[i].text, grammarErrors[i].text + strlen(grammarErrors[i].text));
+ while ((offset = stringText.find(error, offset)) != string16::npos) {
+ results->push_back(WebTextCheckingResult(WebTextDecorationTypeGrammar, offset + grammarErrors[i].location, grammarErrors[i].length));
+ offset += grammarErrors[i].length;
+ }
+ }
+ return false;
+}
+
+}
diff --git a/content/shell/renderer/test_runner/MockGrammarCheck.h b/content/shell/renderer/test_runner/MockGrammarCheck.h
new file mode 100644
index 0000000..348c97a
--- /dev/null
+++ b/content/shell/renderer/test_runner/MockGrammarCheck.h
@@ -0,0 +1,31 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MockGrammarCheck_h
+#define MockGrammarCheck_h
+
+#include <vector>
+
+namespace blink {
+
+class WebString;
+struct WebTextCheckingResult;
+
+}
+
+namespace WebTestRunner {
+
+// A mock implementation of a grammar-checker used for WebKit tests. This class
+// only implements the minimal functionarities required by WebKit tests, i.e.
+// this class just compares the given string with known grammar mistakes in
+// webkit tests and adds grammar markers on them. Even though this is sufficent
+// for webkit tests, this class is not suitable for any other usages.
+class MockGrammarCheck {
+public:
+ static bool checkGrammarOfString(const blink::WebString&, std::vector<blink::WebTextCheckingResult>*);
+};
+
+}
+
+#endif // MockSpellCheck_h
diff --git a/content/shell/renderer/test_runner/MockSpellCheck.cpp b/content/shell/renderer/test_runner/MockSpellCheck.cpp
new file mode 100644
index 0000000..2268ebe
--- /dev/null
+++ b/content/shell/renderer/test_runner/MockSpellCheck.cpp
@@ -0,0 +1,184 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/shell/renderer/test_runner/MockSpellCheck.h"
+
+#include "content/shell/renderer/test_runner/TestCommon.h"
+#include "third_party/WebKit/public/platform/WebCString.h"
+
+using namespace blink;
+using namespace std;
+
+namespace WebTestRunner {
+
+namespace {
+
+void append(WebVector<WebString>* data, const WebString& item)
+{
+ WebVector<WebString> result(data->size() + 1);
+ for (size_t i = 0; i < data->size(); ++i)
+ result[i] = (*data)[i];
+ result[data->size()] = item;
+ data->swap(result);
+}
+
+}
+
+MockSpellCheck::MockSpellCheck()
+ : m_initialized(false) { }
+
+MockSpellCheck::~MockSpellCheck() { }
+
+bool MockSpellCheck::spellCheckWord(const WebString& text, int* misspelledOffset, int* misspelledLength)
+{
+ BLINK_ASSERT(misspelledOffset);
+ BLINK_ASSERT(misspelledLength);
+
+ // Initialize this spellchecker.
+ initializeIfNeeded();
+
+ // Reset the result values as our spellchecker does.
+ *misspelledOffset = 0;
+ *misspelledLength = 0;
+
+ // Convert to a string16 because we store string16 instances in
+ // m_misspelledWords and WebString has no find().
+ string16 stringText = text;
+ int skippedLength = 0;
+
+ while (!stringText.empty()) {
+ // Extract the first possible English word from the given string.
+ // The given string may include non-ASCII characters or numbers. So, we
+ // should filter out such characters before start looking up our
+ // misspelled-word table.
+ // (This is a simple version of our SpellCheckWordIterator class.)
+ // If the given string doesn't include any ASCII characters, we can treat the
+ // string as valid one.
+ string16::iterator firstChar = find_if(stringText.begin(), stringText.end(), isASCIIAlpha);
+ if (firstChar == stringText.end())
+ return true;
+ int wordOffset = distance(stringText.begin(), firstChar);
+ int maxWordLength = static_cast<int>(stringText.length()) - wordOffset;
+ int wordLength;
+ string16 word;
+
+ // Look up our misspelled-word table to check if the extracted word is a
+ // known misspelled word, and return the offset and the length of the
+ // extracted word if this word is a known misspelled word.
+ // (See the comment in MockSpellCheck::initializeIfNeeded() why we use a
+ // misspelled-word table.)
+ for (size_t i = 0; i < m_misspelledWords.size(); ++i) {
+ wordLength = static_cast<int>(m_misspelledWords.at(i).length()) > maxWordLength ? maxWordLength : static_cast<int>(m_misspelledWords.at(i).length());
+ word = stringText.substr(wordOffset, wordLength);
+ if (word == m_misspelledWords.at(i) && (static_cast<int>(stringText.length()) == wordOffset + wordLength || isNotASCIIAlpha(stringText[wordOffset + wordLength]))) {
+ *misspelledOffset = wordOffset + skippedLength;
+ *misspelledLength = wordLength;
+ break;
+ }
+ }
+
+ if (*misspelledLength > 0)
+ break;
+
+ string16::iterator lastChar = find_if(stringText.begin() + wordOffset, stringText.end(), isNotASCIIAlpha);
+ if (lastChar == stringText.end())
+ wordLength = static_cast<int>(stringText.length()) - wordOffset;
+ else
+ wordLength = distance(firstChar, lastChar);
+
+ BLINK_ASSERT(0 < wordOffset + wordLength);
+ stringText = stringText.substr(wordOffset + wordLength);
+ skippedLength += wordOffset + wordLength;
+ }
+
+ return false;
+}
+
+bool MockSpellCheck::hasInCache(const WebString& word)
+{
+ return word == WebString::fromUTF8("Spell wellcome. Is it broken?") || word == WebString::fromUTF8("Spell wellcome.\x007F");
+}
+
+bool MockSpellCheck::isMultiWordMisspelling(const WebString& text, vector<WebTextCheckingResult>* results)
+{
+ if (text == WebString::fromUTF8("Helllo wordl.")) {
+ results->push_back(WebTextCheckingResult(WebTextDecorationTypeSpelling, 0, 6, WebString("Hello")));
+ results->push_back(WebTextCheckingResult(WebTextDecorationTypeSpelling, 7, 5, WebString("world")));
+ return true;
+ }
+ return false;
+}
+
+void MockSpellCheck::fillSuggestionList(const WebString& word, WebVector<WebString>* suggestions)
+{
+ if (word == WebString::fromUTF8("wellcome"))
+ append(suggestions, WebString::fromUTF8("welcome"));
+ else if (word == WebString::fromUTF8("upper case"))
+ append(suggestions, WebString::fromUTF8("uppercase"));
+ else if (word == WebString::fromUTF8("Helllo"))
+ append(suggestions, WebString::fromUTF8("Hello"));
+ else if (word == WebString::fromUTF8("wordl"))
+ append(suggestions, WebString::fromUTF8("world"));
+}
+
+bool MockSpellCheck::initializeIfNeeded()
+{
+ // Exit if we have already initialized this object.
+ if (m_initialized)
+ return false;
+
+ // Create a table that consists of misspelled words used in WebKit layout
+ // tests.
+ // Since WebKit layout tests don't have so many misspelled words as
+ // well-spelled words, it is easier to compare the given word with misspelled
+ // ones than to compare with well-spelled ones.
+ static const char* misspelledWords[] = {
+ // These words are known misspelled words in webkit tests.
+ // If there are other misspelled words in webkit tests, please add them in
+ // this array.
+ "foo",
+ "Foo",
+ "baz",
+ "fo",
+ "LibertyF",
+ "chello",
+ "xxxtestxxx",
+ "XXxxx",
+ "Textx",
+ "blockquoted",
+ "asd",
+ "Lorem",
+ "Nunc",
+ "Curabitur",
+ "eu",
+ "adlj",
+ "adaasj",
+ "sdklj",
+ "jlkds",
+ "jsaada",
+ "jlda",
+ "zz",
+ "contentEditable",
+ // The following words are used by unit tests.
+ "ifmmp",
+ "qwertyuiopasd",
+ "qwertyuiopasdf",
+ "upper case",
+ "wellcome"
+ };
+
+ m_misspelledWords.clear();
+ for (size_t i = 0; i < arraysize(misspelledWords); ++i)
+ m_misspelledWords.push_back(string16(misspelledWords[i], misspelledWords[i] + strlen(misspelledWords[i])));
+
+ // Mark as initialized to prevent this object from being initialized twice
+ // or more.
+ m_initialized = true;
+
+ // Since this MockSpellCheck class doesn't download dictionaries, this
+ // function always returns false.
+ return false;
+}
+
+}
diff --git a/content/shell/renderer/test_runner/MockSpellCheck.h b/content/shell/renderer/test_runner/MockSpellCheck.h
new file mode 100644
index 0000000..5123c03
--- /dev/null
+++ b/content/shell/renderer/test_runner/MockSpellCheck.h
@@ -0,0 +1,67 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MockSpellCheck_h
+#define MockSpellCheck_h
+
+#include <vector>
+
+#include "third_party/WebKit/public/platform/WebNonCopyable.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/platform/WebVector.h"
+#include "third_party/WebKit/public/web/WebTextCheckingResult.h"
+
+namespace WebTestRunner {
+
+// A mock implementation of a spell-checker used for WebKit tests.
+// This class only implements the minimal functionarities required by WebKit
+// tests, i.e. this class just compares the given string with known misspelled
+// words in webkit tests and mark them as missspelled.
+// Even though this is sufficent for webkit tests, this class is not suitable
+// for any other usages.
+class MockSpellCheck : public blink::WebNonCopyable {
+public:
+ static void fillSuggestionList(const blink::WebString& word, blink::WebVector<blink::WebString>* suggestions);
+
+ MockSpellCheck();
+ ~MockSpellCheck();
+
+ // Checks the spellings of the specified text.
+ // This function returns true if the text consists of valid words, and
+ // returns false if it includes invalid words.
+ // When the given text includes invalid words, this function sets the
+ // position of the first invalid word to misspelledOffset, and the length of
+ // the first invalid word to misspelledLength, respectively.
+ // For example, when the given text is " zz zz", this function sets 3 to
+ // misspelledOffset and 2 to misspelledLength, respectively.
+ bool spellCheckWord(const blink::WebString& text, int* misspelledOffset, int* misspelledLength);
+
+ // Checks whether the specified text can be spell checked immediately using
+ // the spell checker cache.
+ bool hasInCache(const blink::WebString& text);
+
+ // Checks whether the specified text is a misspelling comprised of more
+ // than one word. If it is, append multiple results to the results vector.
+ bool isMultiWordMisspelling(const blink::WebString& text, std::vector<blink::WebTextCheckingResult>* results);
+
+private:
+ // Initialize the internal resources if we need to initialize it.
+ // Initializing this object may take long time. To prevent from hurting
+ // the performance of test_shell, we initialize this object when
+ // SpellCheckWord() is called for the first time.
+ // To be compliant with SpellCheck:InitializeIfNeeded(), this function
+ // returns true if this object is downloading a dictionary, otherwise
+ // it returns false.
+ bool initializeIfNeeded();
+
+ // A table that consists of misspelled words.
+ std::vector<string16> m_misspelledWords;
+
+ // A flag representing whether or not this object is initialized.
+ bool m_initialized;
+};
+
+}
+
+#endif // MockSpellCheck_h
diff --git a/content/shell/renderer/test_runner/MockWebAudioDevice.cpp b/content/shell/renderer/test_runner/MockWebAudioDevice.cpp
new file mode 100644
index 0000000..b3bc688
--- /dev/null
+++ b/content/shell/renderer/test_runner/MockWebAudioDevice.cpp
@@ -0,0 +1,33 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/shell/renderer/test_runner/MockWebAudioDevice.h"
+
+using namespace blink;
+
+namespace WebTestRunner {
+
+MockWebAudioDevice::MockWebAudioDevice(double sampleRate)
+ : m_sampleRate(sampleRate)
+{
+}
+
+MockWebAudioDevice::~MockWebAudioDevice()
+{
+}
+
+void MockWebAudioDevice::start()
+{
+}
+
+void MockWebAudioDevice::stop()
+{
+}
+
+double MockWebAudioDevice::sampleRate()
+{
+ return m_sampleRate;
+}
+
+} // namespace WebTestRunner
diff --git a/content/shell/renderer/test_runner/MockWebAudioDevice.h b/content/shell/renderer/test_runner/MockWebAudioDevice.h
new file mode 100644
index 0000000..3888f06
--- /dev/null
+++ b/content/shell/renderer/test_runner/MockWebAudioDevice.h
@@ -0,0 +1,29 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MockWebAudioDevice_h
+#define MockWebAudioDevice_h
+
+#include "content/shell/renderer/test_runner/TestCommon.h"
+#include "third_party/WebKit/public/platform/WebAudioDevice.h"
+#include "third_party/WebKit/public/platform/WebNonCopyable.h"
+
+namespace WebTestRunner {
+
+class MockWebAudioDevice : public blink::WebAudioDevice, public blink::WebNonCopyable {
+public:
+ explicit MockWebAudioDevice(double sampleRate);
+ virtual ~MockWebAudioDevice();
+
+ virtual void start();
+ virtual void stop();
+ virtual double sampleRate();
+
+private:
+ double m_sampleRate;
+};
+
+} // namespace WebTestRunner
+
+#endif // MockWebAudioDevice_h
diff --git a/content/shell/renderer/test_runner/MockWebMIDIAccessor.cpp b/content/shell/renderer/test_runner/MockWebMIDIAccessor.cpp
new file mode 100644
index 0000000..21a4501
--- /dev/null
+++ b/content/shell/renderer/test_runner/MockWebMIDIAccessor.cpp
@@ -0,0 +1,58 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/shell/renderer/test_runner/MockWebMIDIAccessor.h"
+
+#include "content/shell/renderer/test_runner/TestInterfaces.h"
+#include "content/shell/renderer/test_runner/TestRunner.h"
+#include "content/shell/renderer/test_runner/WebTestDelegate.h"
+#include "content/shell/renderer/test_runner/WebTestRunner.h"
+#include "third_party/WebKit/public/platform/WebMIDIAccessorClient.h"
+
+using namespace blink;
+
+namespace {
+
+class DidStartSessionTask : public WebTestRunner::WebMethodTask<WebTestRunner::MockWebMIDIAccessor> {
+public:
+ DidStartSessionTask(WebTestRunner::MockWebMIDIAccessor* object, blink::WebMIDIAccessorClient* client, bool result)
+ : WebMethodTask<WebTestRunner::MockWebMIDIAccessor>(object)
+ , m_client(client)
+ , m_result(result)
+ {
+ }
+
+ virtual void runIfValid() OVERRIDE
+ {
+ m_client->didStartSession(m_result);
+ }
+
+private:
+ blink::WebMIDIAccessorClient* m_client;
+ bool m_result;
+};
+
+} // namespace
+
+namespace WebTestRunner {
+
+MockWebMIDIAccessor::MockWebMIDIAccessor(blink::WebMIDIAccessorClient* client, TestInterfaces* interfaces)
+ : m_client(client)
+ , m_interfaces(interfaces)
+{
+}
+
+MockWebMIDIAccessor::~MockWebMIDIAccessor()
+{
+}
+
+void MockWebMIDIAccessor::startSession()
+{
+ // Add a mock input and output port.
+ m_client->didAddInputPort("MockInputID", "MockInputManufacturer", "MockInputName", "MockInputVersion");
+ m_client->didAddOutputPort("MockOutputID", "MockOutputManufacturer", "MockOutputName", "MockOutputVersion");
+ m_interfaces->delegate()->postTask(new DidStartSessionTask(this, m_client, m_interfaces->testRunner()->midiAccessorResult()));
+}
+
+} // namespace WebTestRunner
diff --git a/content/shell/renderer/test_runner/MockWebMIDIAccessor.h b/content/shell/renderer/test_runner/MockWebMIDIAccessor.h
new file mode 100644
index 0000000..2953a5f
--- /dev/null
+++ b/content/shell/renderer/test_runner/MockWebMIDIAccessor.h
@@ -0,0 +1,45 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MockWebMIDIAccessor_h
+#define MockWebMIDIAccessor_h
+
+#include "content/shell/renderer/test_runner/TestCommon.h"
+#include "content/shell/renderer/test_runner/WebTask.h"
+#include "third_party/WebKit/public/platform/WebMIDIAccessor.h"
+#include "third_party/WebKit/public/platform/WebNonCopyable.h"
+
+namespace blink {
+class WebMIDIAccessorClient;
+}
+
+namespace WebTestRunner {
+
+class TestInterfaces;
+
+class MockWebMIDIAccessor : public blink::WebMIDIAccessor, public blink::WebNonCopyable {
+public:
+ explicit MockWebMIDIAccessor(blink::WebMIDIAccessorClient*, TestInterfaces*);
+ virtual ~MockWebMIDIAccessor();
+
+ // blink::WebMIDIAccessor implementation.
+ virtual void startSession() OVERRIDE;
+ virtual void sendMIDIData(
+ unsigned portIndex,
+ const unsigned char* data,
+ size_t length,
+ double timestamp) OVERRIDE { }
+
+ // WebTask related methods
+ WebTaskList* taskList() { return &m_taskList; }
+
+private:
+ blink::WebMIDIAccessorClient* m_client;
+ WebTaskList m_taskList;
+ TestInterfaces* m_interfaces;
+};
+
+} // namespace WebTestRunner
+
+#endif // MockWebMIDIAccessor_h
diff --git a/content/shell/renderer/test_runner/MockWebMediaStreamCenter.cpp b/content/shell/renderer/test_runner/MockWebMediaStreamCenter.cpp
new file mode 100644
index 0000000..613e649
--- /dev/null
+++ b/content/shell/renderer/test_runner/MockWebMediaStreamCenter.cpp
@@ -0,0 +1,93 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/shell/renderer/test_runner/MockWebMediaStreamCenter.h"
+
+#include "third_party/WebKit/public/platform/WebAudioDestinationConsumer.h"
+#include "third_party/WebKit/public/platform/WebMediaStream.h"
+#include "third_party/WebKit/public/platform/WebMediaStreamCenterClient.h"
+#include "third_party/WebKit/public/platform/WebMediaStreamSource.h"
+#include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
+#include "third_party/WebKit/public/platform/WebMediaStreamTrackSourcesRequest.h"
+#include "third_party/WebKit/public/platform/WebSourceInfo.h"
+#include "third_party/WebKit/public/platform/WebVector.h"
+
+using namespace blink;
+
+namespace WebTestRunner {
+
+MockWebMediaStreamCenter::MockWebMediaStreamCenter(WebMediaStreamCenterClient* client)
+{
+}
+
+bool MockWebMediaStreamCenter::getMediaStreamTrackSources(const WebMediaStreamTrackSourcesRequest& request)
+{
+ size_t size = 2;
+ WebVector<WebSourceInfo> results(size);
+ results[0].initialize("MockAudioDevice#1", WebSourceInfo::SourceKindAudio, "Mock audio device", WebSourceInfo::VideoFacingModeNone);
+ results[1].initialize("MockVideoDevice#1", WebSourceInfo::SourceKindVideo, "Mock video device", WebSourceInfo::VideoFacingModeEnvironment);
+ request.requestSucceeded(results);
+ return true;
+}
+
+void MockWebMediaStreamCenter::didEnableMediaStreamTrack(const WebMediaStream&, const WebMediaStreamTrack& track)
+{
+ track.source().setReadyState(WebMediaStreamSource::ReadyStateLive);
+}
+
+void MockWebMediaStreamCenter::didDisableMediaStreamTrack(const WebMediaStream&, const WebMediaStreamTrack& track)
+{
+ track.source().setReadyState(WebMediaStreamSource::ReadyStateMuted);
+}
+
+bool MockWebMediaStreamCenter::didAddMediaStreamTrack(const WebMediaStream&, const WebMediaStreamTrack&)
+{
+ return true;
+}
+
+bool MockWebMediaStreamCenter::didRemoveMediaStreamTrack(const WebMediaStream&, const WebMediaStreamTrack&)
+{
+ return true;
+}
+
+void MockWebMediaStreamCenter::didStopLocalMediaStream(const WebMediaStream& stream)
+{
+ WebVector<WebMediaStreamTrack> tracks;
+ stream.audioTracks(tracks);
+ for (size_t i = 0; i < tracks.size(); ++i)
+ tracks[i].source().setReadyState(WebMediaStreamSource::ReadyStateEnded);
+ stream.videoTracks(tracks);
+ for (size_t i = 0; i < tracks.size(); ++i)
+ tracks[i].source().setReadyState(WebMediaStreamSource::ReadyStateEnded);
+}
+
+bool MockWebMediaStreamCenter::didStopMediaStreamTrack(const blink::WebMediaStreamTrack& track)
+{
+ track.source().setReadyState(WebMediaStreamSource::ReadyStateEnded);
+ return true;
+}
+
+class MockWebAudioDestinationConsumer : public WebAudioDestinationConsumer {
+public:
+ virtual ~MockWebAudioDestinationConsumer() { }
+ virtual void setFormat(size_t numberOfChannels, float sampleRate) OVERRIDE { }
+ virtual void consumeAudio(const WebVector<const float*>&, size_t number_of_frames) OVERRIDE { }
+};
+
+void MockWebMediaStreamCenter::didCreateMediaStream(WebMediaStream& stream)
+{
+ WebVector<WebMediaStreamTrack> audioTracks;
+ stream.audioTracks(audioTracks);
+ for (size_t i = 0; i < audioTracks.size(); ++i) {
+ WebMediaStreamSource source = audioTracks[i].source();
+ if (source.requiresAudioConsumer()) {
+ MockWebAudioDestinationConsumer* consumer = new MockWebAudioDestinationConsumer();
+ source.addAudioConsumer(consumer);
+ source.removeAudioConsumer(consumer);
+ delete consumer;
+ }
+ }
+}
+
+}
diff --git a/content/shell/renderer/test_runner/MockWebMediaStreamCenter.h b/content/shell/renderer/test_runner/MockWebMediaStreamCenter.h
new file mode 100644
index 0000000..178746d
--- /dev/null
+++ b/content/shell/renderer/test_runner/MockWebMediaStreamCenter.h
@@ -0,0 +1,37 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MockWebMediaStreamCenter_h
+#define MockWebMediaStreamCenter_h
+
+#include "content/shell/renderer/test_runner/TestCommon.h"
+#include "third_party/WebKit/public/platform/WebMediaStreamCenter.h"
+#include "third_party/WebKit/public/platform/WebNonCopyable.h"
+
+namespace blink {
+class WebMediaStreamCenterClient;
+};
+
+namespace WebTestRunner {
+
+class MockWebMediaStreamCenter : public blink::WebMediaStreamCenter, public blink::WebNonCopyable {
+public:
+ explicit MockWebMediaStreamCenter(blink::WebMediaStreamCenterClient*);
+
+ virtual bool getMediaStreamTrackSources(const blink::WebMediaStreamTrackSourcesRequest&) OVERRIDE;
+ virtual void didEnableMediaStreamTrack(const blink::WebMediaStream&, const blink::WebMediaStreamTrack&) OVERRIDE;
+ virtual void didDisableMediaStreamTrack(const blink::WebMediaStream&, const blink::WebMediaStreamTrack&) OVERRIDE;
+ virtual bool didAddMediaStreamTrack(const blink::WebMediaStream&, const blink::WebMediaStreamTrack&) OVERRIDE;
+ virtual bool didRemoveMediaStreamTrack(const blink::WebMediaStream&, const blink::WebMediaStreamTrack&) OVERRIDE;
+ virtual void didStopLocalMediaStream(const blink::WebMediaStream&) OVERRIDE;
+ virtual bool didStopMediaStreamTrack(const blink::WebMediaStreamTrack&) OVERRIDE;
+ virtual void didCreateMediaStream(blink::WebMediaStream&) OVERRIDE;
+
+private:
+ MockWebMediaStreamCenter() { }
+};
+
+}
+
+#endif // MockWebMediaStreamCenter_h
diff --git a/content/shell/renderer/test_runner/MockWebRTCDTMFSenderHandler.cpp b/content/shell/renderer/test_runner/MockWebRTCDTMFSenderHandler.cpp
new file mode 100644
index 0000000..223c16d
--- /dev/null
+++ b/content/shell/renderer/test_runner/MockWebRTCDTMFSenderHandler.cpp
@@ -0,0 +1,73 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/shell/renderer/test_runner/MockWebRTCDTMFSenderHandler.h"
+
+#include <assert.h>
+
+#include "content/shell/renderer/test_runner/WebTestDelegate.h"
+#include "third_party/WebKit/public/platform/WebMediaStreamSource.h"
+#include "third_party/WebKit/public/platform/WebRTCDTMFSenderHandlerClient.h"
+
+using namespace blink;
+
+namespace WebTestRunner {
+
+class DTMFSenderToneTask : public WebMethodTask<MockWebRTCDTMFSenderHandler> {
+public:
+ DTMFSenderToneTask(MockWebRTCDTMFSenderHandler* object, WebRTCDTMFSenderHandlerClient* client)
+ : WebMethodTask<MockWebRTCDTMFSenderHandler>(object)
+ , m_client(client)
+ {
+ }
+
+ virtual void runIfValid() OVERRIDE
+ {
+ WebString tones = m_object->currentToneBuffer();
+ m_object->clearToneBuffer();
+ m_client->didPlayTone(tones);
+ }
+
+private:
+ WebRTCDTMFSenderHandlerClient* m_client;
+};
+
+/////////////////////
+
+MockWebRTCDTMFSenderHandler::MockWebRTCDTMFSenderHandler(const WebMediaStreamTrack& track, WebTestDelegate* delegate)
+ : m_client(0)
+ , m_track(track)
+ , m_delegate(delegate)
+{
+}
+
+void MockWebRTCDTMFSenderHandler::setClient(WebRTCDTMFSenderHandlerClient* client)
+{
+ m_client = client;
+}
+
+WebString MockWebRTCDTMFSenderHandler::currentToneBuffer()
+{
+ return m_toneBuffer;
+}
+
+bool MockWebRTCDTMFSenderHandler::canInsertDTMF()
+{
+ assert(m_client && !m_track.isNull());
+ return m_track.source().type() == WebMediaStreamSource::TypeAudio && m_track.isEnabled() && m_track.source().readyState() == WebMediaStreamSource::ReadyStateLive;
+}
+
+bool MockWebRTCDTMFSenderHandler::insertDTMF(const WebString& tones, long duration, long interToneGap)
+{
+ assert(m_client);
+ if (!canInsertDTMF())
+ return false;
+
+ m_toneBuffer = tones;
+ m_delegate->postTask(new DTMFSenderToneTask(this, m_client));
+ m_delegate->postTask(new DTMFSenderToneTask(this, m_client));
+ return true;
+}
+
+}
diff --git a/content/shell/renderer/test_runner/MockWebRTCDTMFSenderHandler.h b/content/shell/renderer/test_runner/MockWebRTCDTMFSenderHandler.h
new file mode 100644
index 0000000..dd4a757
--- /dev/null
+++ b/content/shell/renderer/test_runner/MockWebRTCDTMFSenderHandler.h
@@ -0,0 +1,46 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MockWebRTCDTMFSenderHandler_h
+#define MockWebRTCDTMFSenderHandler_h
+
+#include "content/shell/renderer/test_runner/TestCommon.h"
+#include "content/shell/renderer/test_runner/WebTask.h"
+#include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
+#include "third_party/WebKit/public/platform/WebNonCopyable.h"
+#include "third_party/WebKit/public/platform/WebRTCDTMFSenderHandler.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+
+namespace WebTestRunner {
+
+class WebTestDelegate;
+
+class MockWebRTCDTMFSenderHandler : public blink::WebRTCDTMFSenderHandler, public blink::WebNonCopyable {
+public:
+ MockWebRTCDTMFSenderHandler(const blink::WebMediaStreamTrack&, WebTestDelegate*);
+
+ virtual void setClient(blink::WebRTCDTMFSenderHandlerClient*) OVERRIDE;
+
+ virtual blink::WebString currentToneBuffer() OVERRIDE;
+
+ virtual bool canInsertDTMF() OVERRIDE;
+ virtual bool insertDTMF(const blink::WebString& tones, long duration, long interToneGap) OVERRIDE;
+
+ // WebTask related methods
+ WebTaskList* taskList() { return &m_taskList; }
+ void clearToneBuffer() { m_toneBuffer.reset(); }
+
+private:
+ MockWebRTCDTMFSenderHandler();
+
+ blink::WebRTCDTMFSenderHandlerClient* m_client;
+ blink::WebMediaStreamTrack m_track;
+ blink::WebString m_toneBuffer;
+ WebTaskList m_taskList;
+ WebTestDelegate* m_delegate;
+};
+
+}
+
+#endif // MockWebRTCDTMFSenderHandler_h
diff --git a/content/shell/renderer/test_runner/MockWebRTCDataChannelHandler.cpp b/content/shell/renderer/test_runner/MockWebRTCDataChannelHandler.cpp
new file mode 100644
index 0000000..e57696b
--- /dev/null
+++ b/content/shell/renderer/test_runner/MockWebRTCDataChannelHandler.cpp
@@ -0,0 +1,108 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/shell/renderer/test_runner/MockWebRTCDataChannelHandler.h"
+
+#include <assert.h>
+
+#include "content/shell/renderer/test_runner/WebTestDelegate.h"
+#include "third_party/WebKit/public/platform/WebRTCDataChannelHandlerClient.h"
+
+using namespace blink;
+
+namespace WebTestRunner {
+
+class DataChannelReadyStateTask : public WebMethodTask<MockWebRTCDataChannelHandler> {
+public:
+ DataChannelReadyStateTask(MockWebRTCDataChannelHandler* object, WebRTCDataChannelHandlerClient* dataChannelClient, WebRTCDataChannelHandlerClient::ReadyState state)
+ : WebMethodTask<MockWebRTCDataChannelHandler>(object)
+ , m_dataChannelClient(dataChannelClient)
+ , m_state(state)
+ {
+ }
+
+ virtual void runIfValid() OVERRIDE
+ {
+ m_dataChannelClient->didChangeReadyState(m_state);
+ }
+
+private:
+ WebRTCDataChannelHandlerClient* m_dataChannelClient;
+ WebRTCDataChannelHandlerClient::ReadyState m_state;
+};
+
+/////////////////////
+
+MockWebRTCDataChannelHandler::MockWebRTCDataChannelHandler(WebString label, const WebRTCDataChannelInit& init, WebTestDelegate* delegate)
+ : m_client(0)
+ , m_label(label)
+ , m_init(init)
+ , m_delegate(delegate)
+{
+ m_reliable = (init.ordered && init.maxRetransmits == -1 && init.maxRetransmitTime == -1);
+}
+
+void MockWebRTCDataChannelHandler::setClient(WebRTCDataChannelHandlerClient* client)
+{
+ m_client = client;
+ if (m_client)
+ m_delegate->postTask(new DataChannelReadyStateTask(this, m_client, WebRTCDataChannelHandlerClient::ReadyStateOpen));
+}
+
+bool MockWebRTCDataChannelHandler::ordered() const
+{
+ return m_init.ordered;
+}
+
+unsigned short MockWebRTCDataChannelHandler::maxRetransmitTime() const
+{
+ return m_init.maxRetransmitTime;
+}
+
+unsigned short MockWebRTCDataChannelHandler::maxRetransmits() const
+{
+ return m_init.maxRetransmits;
+}
+
+WebString MockWebRTCDataChannelHandler::protocol() const
+{
+ return m_init.protocol;
+}
+
+bool MockWebRTCDataChannelHandler::negotiated() const
+{
+ return m_init.negotiated;
+}
+
+unsigned short MockWebRTCDataChannelHandler::id() const
+{
+ return m_init.id;
+}
+
+unsigned long MockWebRTCDataChannelHandler::bufferedAmount()
+{
+ return 0;
+}
+
+bool MockWebRTCDataChannelHandler::sendStringData(const WebString& data)
+{
+ assert(m_client);
+ m_client->didReceiveStringData(data);
+ return true;
+}
+
+bool MockWebRTCDataChannelHandler::sendRawData(const char* data, size_t size)
+{
+ assert(m_client);
+ m_client->didReceiveRawData(data, size);
+ return true;
+}
+
+void MockWebRTCDataChannelHandler::close()
+{
+ assert(m_client);
+ m_delegate->postTask(new DataChannelReadyStateTask(this, m_client, WebRTCDataChannelHandlerClient::ReadyStateClosed));
+}
+
+}
diff --git a/content/shell/renderer/test_runner/MockWebRTCDataChannelHandler.h b/content/shell/renderer/test_runner/MockWebRTCDataChannelHandler.h
new file mode 100644
index 0000000..ce99ff8
--- /dev/null
+++ b/content/shell/renderer/test_runner/MockWebRTCDataChannelHandler.h
@@ -0,0 +1,53 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MockWebRTCDataChannelHandler_h
+#define MockWebRTCDataChannelHandler_h
+
+#include "content/shell/renderer/test_runner/TestCommon.h"
+#include "content/shell/renderer/test_runner/WebTask.h"
+#include "third_party/WebKit/public/platform/WebNonCopyable.h"
+#include "third_party/WebKit/public/platform/WebRTCDataChannelHandler.h"
+#include "third_party/WebKit/public/platform/WebRTCDataChannelInit.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+
+namespace WebTestRunner {
+
+class WebTestDelegate;
+
+class MockWebRTCDataChannelHandler : public blink::WebRTCDataChannelHandler, public blink::WebNonCopyable {
+public:
+ MockWebRTCDataChannelHandler(blink::WebString label, const blink::WebRTCDataChannelInit&, WebTestDelegate*);
+
+ virtual void setClient(blink::WebRTCDataChannelHandlerClient*) OVERRIDE;
+ virtual blink::WebString label() OVERRIDE { return m_label; }
+ virtual bool isReliable() OVERRIDE { return m_reliable; }
+ virtual bool ordered() const OVERRIDE;
+ virtual unsigned short maxRetransmitTime() const OVERRIDE;
+ virtual unsigned short maxRetransmits() const OVERRIDE;
+ virtual blink::WebString protocol() const OVERRIDE;
+ virtual bool negotiated() const OVERRIDE;
+ virtual unsigned short id() const OVERRIDE;
+ virtual unsigned long bufferedAmount() OVERRIDE;
+ virtual bool sendStringData(const blink::WebString&) OVERRIDE;
+ virtual bool sendRawData(const char*, size_t) OVERRIDE;
+ virtual void close() OVERRIDE;
+
+ // WebTask related methods
+ WebTaskList* taskList() { return &m_taskList; }
+
+private:
+ MockWebRTCDataChannelHandler();
+
+ blink::WebRTCDataChannelHandlerClient* m_client;
+ blink::WebString m_label;
+ blink::WebRTCDataChannelInit m_init;
+ bool m_reliable;
+ WebTaskList m_taskList;
+ WebTestDelegate* m_delegate;
+};
+
+}
+
+#endif // MockWebRTCDataChannelHandler_h
diff --git a/content/shell/renderer/test_runner/MockWebRTCPeerConnectionHandler.cpp b/content/shell/renderer/test_runner/MockWebRTCPeerConnectionHandler.cpp
new file mode 100644
index 0000000..6b46ff7
--- /dev/null
+++ b/content/shell/renderer/test_runner/MockWebRTCPeerConnectionHandler.cpp
@@ -0,0 +1,281 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/shell/renderer/test_runner/MockWebRTCPeerConnectionHandler.h"
+
+#include "content/shell/renderer/test_runner/MockConstraints.h"
+#include "content/shell/renderer/test_runner/MockWebRTCDTMFSenderHandler.h"
+#include "content/shell/renderer/test_runner/MockWebRTCDataChannelHandler.h"
+#include "content/shell/renderer/test_runner/TestInterfaces.h"
+#include "content/shell/renderer/test_runner/WebTestDelegate.h"
+#include "third_party/WebKit/public/platform/WebMediaConstraints.h"
+#include "third_party/WebKit/public/platform/WebMediaStream.h"
+#include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
+#include "third_party/WebKit/public/platform/WebRTCDataChannelInit.h"
+#include "third_party/WebKit/public/platform/WebRTCPeerConnectionHandlerClient.h"
+#include "third_party/WebKit/public/platform/WebRTCStatsResponse.h"
+#include "third_party/WebKit/public/platform/WebRTCVoidRequest.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/platform/WebVector.h"
+
+using namespace blink;
+
+namespace WebTestRunner {
+
+class RTCSessionDescriptionRequestSuccededTask : public WebMethodTask<MockWebRTCPeerConnectionHandler> {
+public:
+ RTCSessionDescriptionRequestSuccededTask(MockWebRTCPeerConnectionHandler* object, const WebRTCSessionDescriptionRequest& request, const WebRTCSessionDescription& result)
+ : WebMethodTask<MockWebRTCPeerConnectionHandler>(object)
+ , m_request(request)
+ , m_result(result)
+ {
+ }
+
+ virtual void runIfValid() OVERRIDE
+ {
+ m_request.requestSucceeded(m_result);
+ }
+
+private:
+ WebRTCSessionDescriptionRequest m_request;
+ WebRTCSessionDescription m_result;
+};
+
+class RTCSessionDescriptionRequestFailedTask : public WebMethodTask<MockWebRTCPeerConnectionHandler> {
+public:
+ RTCSessionDescriptionRequestFailedTask(MockWebRTCPeerConnectionHandler* object, const WebRTCSessionDescriptionRequest& request)
+ : WebMethodTask<MockWebRTCPeerConnectionHandler>(object)
+ , m_request(request)
+ {
+ }
+
+ virtual void runIfValid() OVERRIDE
+ {
+ m_request.requestFailed("TEST_ERROR");
+ }
+
+private:
+ WebRTCSessionDescriptionRequest m_request;
+};
+
+class RTCStatsRequestSucceededTask : public WebMethodTask<MockWebRTCPeerConnectionHandler> {
+public:
+ RTCStatsRequestSucceededTask(MockWebRTCPeerConnectionHandler* object, const blink::WebRTCStatsRequest& request, const blink::WebRTCStatsResponse& response)
+ : WebMethodTask<MockWebRTCPeerConnectionHandler>(object)
+ , m_request(request)
+ , m_response(response)
+ {
+ }
+
+ virtual void runIfValid() OVERRIDE
+ {
+ m_request.requestSucceeded(m_response);
+ }
+
+private:
+ blink::WebRTCStatsRequest m_request;
+ blink::WebRTCStatsResponse m_response;
+};
+
+class RTCVoidRequestTask : public WebMethodTask<MockWebRTCPeerConnectionHandler> {
+public:
+ RTCVoidRequestTask(MockWebRTCPeerConnectionHandler* object, const WebRTCVoidRequest& request, bool succeeded)
+ : WebMethodTask<MockWebRTCPeerConnectionHandler>(object)
+ , m_request(request)
+ , m_succeeded(succeeded)
+ {
+ }
+
+ virtual void runIfValid() OVERRIDE
+ {
+ if (m_succeeded)
+ m_request.requestSucceeded();
+ else
+ m_request.requestFailed("TEST_ERROR");
+ }
+
+private:
+ WebRTCVoidRequest m_request;
+ bool m_succeeded;
+};
+
+class RTCPeerConnectionStateTask : public WebMethodTask<MockWebRTCPeerConnectionHandler> {
+public:
+ RTCPeerConnectionStateTask(MockWebRTCPeerConnectionHandler* object, WebRTCPeerConnectionHandlerClient* client, WebRTCPeerConnectionHandlerClient::ICEConnectionState connectionState, WebRTCPeerConnectionHandlerClient::ICEGatheringState gatheringState)
+ : WebMethodTask<MockWebRTCPeerConnectionHandler>(object)
+ , m_client(client)
+ , m_connectionState(connectionState)
+ , m_gatheringState(gatheringState)
+ {
+ }
+
+ virtual void runIfValid() OVERRIDE
+ {
+ m_client->didChangeICEGatheringState(m_gatheringState);
+ m_client->didChangeICEConnectionState(m_connectionState);
+ }
+
+private:
+ WebRTCPeerConnectionHandlerClient* m_client;
+ WebRTCPeerConnectionHandlerClient::ICEConnectionState m_connectionState;
+ WebRTCPeerConnectionHandlerClient::ICEGatheringState m_gatheringState;
+};
+
+class RemoteDataChannelTask : public WebMethodTask<MockWebRTCPeerConnectionHandler> {
+public:
+ RemoteDataChannelTask(MockWebRTCPeerConnectionHandler* object, WebRTCPeerConnectionHandlerClient* client, WebTestDelegate* delegate)
+ : WebMethodTask<MockWebRTCPeerConnectionHandler>(object)
+ , m_client(client)
+ , m_delegate(delegate)
+ {
+ }
+
+ virtual void runIfValid() OVERRIDE
+ {
+ WebRTCDataChannelInit init;
+ WebRTCDataChannelHandler* remoteDataChannel = new MockWebRTCDataChannelHandler("MockRemoteDataChannel", init, m_delegate);
+ m_client->didAddRemoteDataChannel(remoteDataChannel);
+ }
+
+private:
+ WebRTCPeerConnectionHandlerClient* m_client;
+ WebTestDelegate* m_delegate;
+};
+
+/////////////////////
+
+MockWebRTCPeerConnectionHandler::MockWebRTCPeerConnectionHandler(WebRTCPeerConnectionHandlerClient* client, TestInterfaces* interfaces)
+ : m_client(client)
+ , m_stopped(false)
+ , m_streamCount(0)
+ , m_interfaces(interfaces)
+{
+}
+
+bool MockWebRTCPeerConnectionHandler::initialize(const WebRTCConfiguration&, const WebMediaConstraints& constraints)
+{
+ if (MockConstraints::verifyConstraints(constraints)) {
+ m_interfaces->delegate()->postTask(new RTCPeerConnectionStateTask(this, m_client, WebRTCPeerConnectionHandlerClient::ICEConnectionStateCompleted, WebRTCPeerConnectionHandlerClient::ICEGatheringStateComplete));
+ return true;
+ }
+
+ return false;
+}
+
+void MockWebRTCPeerConnectionHandler::createOffer(const WebRTCSessionDescriptionRequest& request, const WebMediaConstraints& constraints)
+{
+ WebString shouldSucceed;
+ if (constraints.getMandatoryConstraintValue("succeed", shouldSucceed) && shouldSucceed == "true") {
+ WebRTCSessionDescription sessionDescription;
+ sessionDescription.initialize("offer", "local");
+ m_interfaces->delegate()->postTask(new RTCSessionDescriptionRequestSuccededTask(this, request, sessionDescription));
+ } else
+ m_interfaces->delegate()->postTask(new RTCSessionDescriptionRequestFailedTask(this, request));
+}
+
+void MockWebRTCPeerConnectionHandler::createAnswer(const WebRTCSessionDescriptionRequest& request, const WebMediaConstraints&)
+{
+ if (!m_remoteDescription.isNull()) {
+ WebRTCSessionDescription sessionDescription;
+ sessionDescription.initialize("answer", "local");
+ m_interfaces->delegate()->postTask(new RTCSessionDescriptionRequestSuccededTask(this, request, sessionDescription));
+ } else
+ m_interfaces->delegate()->postTask(new RTCSessionDescriptionRequestFailedTask(this, request));
+}
+
+void MockWebRTCPeerConnectionHandler::setLocalDescription(const WebRTCVoidRequest& request, const WebRTCSessionDescription& localDescription)
+{
+ if (!localDescription.isNull() && localDescription.sdp() == "local") {
+ m_localDescription = localDescription;
+ m_interfaces->delegate()->postTask(new RTCVoidRequestTask(this, request, true));
+ } else
+ m_interfaces->delegate()->postTask(new RTCVoidRequestTask(this, request, false));
+}
+
+void MockWebRTCPeerConnectionHandler::setRemoteDescription(const WebRTCVoidRequest& request, const WebRTCSessionDescription& remoteDescription)
+{
+ if (!remoteDescription.isNull() && remoteDescription.sdp() == "remote") {
+ m_remoteDescription = remoteDescription;
+ m_interfaces->delegate()->postTask(new RTCVoidRequestTask(this, request, true));
+ } else
+ m_interfaces->delegate()->postTask(new RTCVoidRequestTask(this, request, false));
+}
+
+WebRTCSessionDescription MockWebRTCPeerConnectionHandler::localDescription()
+{
+ return m_localDescription;
+}
+
+WebRTCSessionDescription MockWebRTCPeerConnectionHandler::remoteDescription()
+{
+ return m_remoteDescription;
+}
+
+bool MockWebRTCPeerConnectionHandler::updateICE(const WebRTCConfiguration&, const WebMediaConstraints&)
+{
+ return true;
+}
+
+bool MockWebRTCPeerConnectionHandler::addICECandidate(const WebRTCICECandidate& iceCandidate)
+{
+ m_client->didGenerateICECandidate(iceCandidate);
+ return true;
+}
+
+bool MockWebRTCPeerConnectionHandler::addICECandidate(const WebRTCVoidRequest& request, const WebRTCICECandidate& iceCandidate)
+{
+ m_interfaces->delegate()->postTask(new RTCVoidRequestTask(this, request, true));
+ return true;
+}
+
+bool MockWebRTCPeerConnectionHandler::addStream(const WebMediaStream& stream, const WebMediaConstraints&)
+{
+ ++m_streamCount;
+ m_client->negotiationNeeded();
+ return true;
+}
+
+void MockWebRTCPeerConnectionHandler::removeStream(const WebMediaStream& stream)
+{
+ --m_streamCount;
+ m_client->negotiationNeeded();
+}
+
+void MockWebRTCPeerConnectionHandler::getStats(const WebRTCStatsRequest& request)
+{
+ WebRTCStatsResponse response = request.createResponse();
+ double currentDate = m_interfaces->delegate()->getCurrentTimeInMillisecond();
+ if (request.hasSelector()) {
+ // FIXME: There is no check that the fetched values are valid.
+ size_t reportIndex = response.addReport("Mock video", "ssrc", currentDate);
+ response.addStatistic(reportIndex, "type", "video");
+ } else {
+ for (int i = 0; i < m_streamCount; ++i) {
+ size_t reportIndex = response.addReport("Mock audio", "ssrc", currentDate);
+ response.addStatistic(reportIndex, "type", "audio");
+ reportIndex = response.addReport("Mock video", "ssrc", currentDate);
+ response.addStatistic(reportIndex, "type", "video");
+ }
+ }
+ m_interfaces->delegate()->postTask(new RTCStatsRequestSucceededTask(this, request, response));
+}
+
+WebRTCDataChannelHandler* MockWebRTCPeerConnectionHandler::createDataChannel(const WebString& label, const blink::WebRTCDataChannelInit& init)
+{
+ m_interfaces->delegate()->postTask(new RemoteDataChannelTask(this, m_client, m_interfaces->delegate()));
+
+ return new MockWebRTCDataChannelHandler(label, init, m_interfaces->delegate());
+}
+
+WebRTCDTMFSenderHandler* MockWebRTCPeerConnectionHandler::createDTMFSender(const WebMediaStreamTrack& track)
+{
+ return new MockWebRTCDTMFSenderHandler(track, m_interfaces->delegate());
+}
+
+void MockWebRTCPeerConnectionHandler::stop()
+{
+ m_stopped = true;
+}
+
+}
diff --git a/content/shell/renderer/test_runner/MockWebRTCPeerConnectionHandler.h b/content/shell/renderer/test_runner/MockWebRTCPeerConnectionHandler.h
new file mode 100644
index 0000000..f44360e
--- /dev/null
+++ b/content/shell/renderer/test_runner/MockWebRTCPeerConnectionHandler.h
@@ -0,0 +1,63 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MockWebRTCPeerConnectionHandler_h
+#define MockWebRTCPeerConnectionHandler_h
+
+#include "content/shell/renderer/test_runner/TestCommon.h"
+#include "content/shell/renderer/test_runner/WebTask.h"
+#include "third_party/WebKit/public/platform/WebNonCopyable.h"
+#include "third_party/WebKit/public/platform/WebRTCPeerConnectionHandler.h"
+#include "third_party/WebKit/public/platform/WebRTCSessionDescription.h"
+#include "third_party/WebKit/public/platform/WebRTCSessionDescriptionRequest.h"
+#include "third_party/WebKit/public/platform/WebRTCStatsRequest.h"
+
+namespace blink {
+class WebRTCPeerConnectionHandlerClient;
+};
+
+namespace WebTestRunner {
+
+class TestInterfaces;
+
+class MockWebRTCPeerConnectionHandler : public blink::WebRTCPeerConnectionHandler, public blink::WebNonCopyable {
+public:
+ MockWebRTCPeerConnectionHandler(blink::WebRTCPeerConnectionHandlerClient*, TestInterfaces*);
+
+ virtual bool initialize(const blink::WebRTCConfiguration&, const blink::WebMediaConstraints&) OVERRIDE;
+
+ virtual void createOffer(const blink::WebRTCSessionDescriptionRequest&, const blink::WebMediaConstraints&) OVERRIDE;
+ virtual void createAnswer(const blink::WebRTCSessionDescriptionRequest&, const blink::WebMediaConstraints&) OVERRIDE;
+ virtual void setLocalDescription(const blink::WebRTCVoidRequest&, const blink::WebRTCSessionDescription&) OVERRIDE;
+ virtual void setRemoteDescription(const blink::WebRTCVoidRequest&, const blink::WebRTCSessionDescription&) OVERRIDE;
+ virtual blink::WebRTCSessionDescription localDescription() OVERRIDE;
+ virtual blink::WebRTCSessionDescription remoteDescription() OVERRIDE;
+ virtual bool updateICE(const blink::WebRTCConfiguration&, const blink::WebMediaConstraints&) OVERRIDE;
+ virtual bool addICECandidate(const blink::WebRTCICECandidate&) OVERRIDE;
+ virtual bool addICECandidate(const blink::WebRTCVoidRequest&, const blink::WebRTCICECandidate&) OVERRIDE;
+ virtual bool addStream(const blink::WebMediaStream&, const blink::WebMediaConstraints&) OVERRIDE;
+ virtual void removeStream(const blink::WebMediaStream&) OVERRIDE;
+ virtual void getStats(const blink::WebRTCStatsRequest&) OVERRIDE;
+ virtual blink::WebRTCDataChannelHandler* createDataChannel(const blink::WebString& label, const blink::WebRTCDataChannelInit&) OVERRIDE;
+ virtual blink::WebRTCDTMFSenderHandler* createDTMFSender(const blink::WebMediaStreamTrack&) OVERRIDE;
+ virtual void stop() OVERRIDE;
+
+ // WebTask related methods
+ WebTaskList* taskList() { return &m_taskList; }
+
+private:
+ MockWebRTCPeerConnectionHandler() { }
+
+ blink::WebRTCPeerConnectionHandlerClient* m_client;
+ bool m_stopped;
+ WebTaskList m_taskList;
+ blink::WebRTCSessionDescription m_localDescription;
+ blink::WebRTCSessionDescription m_remoteDescription;
+ int m_streamCount;
+ TestInterfaces* m_interfaces;
+};
+
+}
+
+#endif // MockWebRTCPeerConnectionHandler_h
diff --git a/content/shell/renderer/test_runner/MockWebSpeechInputController.cpp b/content/shell/renderer/test_runner/MockWebSpeechInputController.cpp
new file mode 100644
index 0000000..f6263c7
--- /dev/null
+++ b/content/shell/renderer/test_runner/MockWebSpeechInputController.cpp
@@ -0,0 +1,186 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/shell/renderer/test_runner/MockWebSpeechInputController.h"
+
+#include "content/shell/renderer/test_runner/WebTestDelegate.h"
+#include "third_party/WebKit/public/platform/WebCString.h"
+#include "third_party/WebKit/public/platform/WebVector.h"
+#include "third_party/WebKit/public/web/WebSpeechInputListener.h"
+
+#if ENABLE_INPUT_SPEECH
+
+using namespace blink;
+using namespace std;
+
+namespace WebTestRunner {
+
+namespace {
+
+WebSpeechInputResultArray makeRectResult(const WebRect& rect)
+{
+ char buffer[100];
+ snprintf(buffer, sizeof(buffer), "%d,%d,%d,%d", rect.x, rect.y, rect.width, rect.height);
+
+ WebSpeechInputResult res;
+ res.assign(WebString::fromUTF8(static_cast<const char*>(buffer)), 1.0);
+
+ WebSpeechInputResultArray results;
+ results.assign(&res, 1);
+ return results;
+}
+
+}
+
+MockWebSpeechInputController::MockWebSpeechInputController(WebSpeechInputListener* listener)
+ : m_listener(listener)
+ , m_speechTask(0)
+ , m_recording(false)
+ , m_requestId(-1)
+ , m_dumpRect(false)
+ , m_delegate(0)
+{
+}
+
+MockWebSpeechInputController::~MockWebSpeechInputController()
+{
+}
+
+void MockWebSpeechInputController::setDelegate(WebTestDelegate* delegate)
+{
+ m_delegate = delegate;
+}
+
+void MockWebSpeechInputController::addMockRecognitionResult(const WebString& result, double confidence, const WebString& language)
+{
+ WebSpeechInputResult res;
+ res.assign(result, confidence);
+
+ if (language.isEmpty())
+ m_resultsForEmptyLanguage.push_back(res);
+ else {
+ string langString = language.utf8();
+ if (m_recognitionResults.find(langString) == m_recognitionResults.end())
+ m_recognitionResults[langString] = vector<WebSpeechInputResult>();
+ m_recognitionResults[langString].push_back(res);
+ }
+}
+
+void MockWebSpeechInputController::setDumpRect(bool dumpRect)
+{
+ m_dumpRect = dumpRect;
+}
+
+void MockWebSpeechInputController::clearResults()
+{
+ m_resultsForEmptyLanguage.clear();
+ m_recognitionResults.clear();
+ m_dumpRect = false;
+}
+
+bool MockWebSpeechInputController::startRecognition(int requestId, const WebRect& elementRect, const WebString& language, const WebString& grammar, const WebSecurityOrigin& origin)
+{
+ if (m_speechTask)
+ return false;
+
+ m_requestId = requestId;
+ m_requestRect = elementRect;
+ m_recording = true;
+ m_language = language.utf8();
+
+ m_speechTask = new SpeechTask(this);
+ m_delegate->postTask(m_speechTask);
+
+ return true;
+}
+
+void MockWebSpeechInputController::cancelRecognition(int requestId)
+{
+ if (m_speechTask) {
+ BLINK_ASSERT(requestId == m_requestId);
+
+ m_speechTask->stop();
+ m_recording = false;
+ m_listener->didCompleteRecognition(m_requestId);
+ m_requestId = 0;
+ }
+}
+
+void MockWebSpeechInputController::stopRecording(int requestId)
+{
+ BLINK_ASSERT(requestId == m_requestId);
+ if (m_speechTask && m_recording) {
+ m_speechTask->stop();
+ speechTaskFired();
+ }
+}
+
+void MockWebSpeechInputController::speechTaskFired()
+{
+ if (m_recording) {
+ m_recording = false;
+ m_listener->didCompleteRecording(m_requestId);
+
+ m_speechTask = new SpeechTask(this);
+ m_delegate->postTask(m_speechTask);
+ } else {
+ bool noResultsFound = false;
+ // We take a copy of the requestId here so that if scripts destroyed the input element
+ // inside one of the callbacks below, we'll still know what this session's requestId was.
+ int requestId = m_requestId;
+ m_requestId = 0;
+
+ if (m_dumpRect) {
+ m_listener->setRecognitionResult(requestId, makeRectResult(m_requestRect));
+ } else if (m_language.empty()) {
+ // Empty language case must be handled separately to avoid problems with HashMap and empty keys.
+ if (!m_resultsForEmptyLanguage.empty())
+ m_listener->setRecognitionResult(requestId, m_resultsForEmptyLanguage);
+ else
+ noResultsFound = true;
+ } else {
+ if (m_recognitionResults.find(m_language) != m_recognitionResults.end())
+ m_listener->setRecognitionResult(requestId, m_recognitionResults[m_language]);
+ else
+ noResultsFound = true;
+ }
+
+ if (noResultsFound) {
+ // Can't avoid setting a result even if no result was set for the given language.
+ // This would avoid generating the events used to check the results and the test would timeout.
+ string error("error: no result found for language '");
+ error.append(m_language);
+ error.append("'");
+
+ WebSpeechInputResult res;
+ res.assign(WebString::fromUTF8(error), 1.0);
+
+ vector<WebSpeechInputResult> results;
+ results.push_back(res);
+
+ m_listener->setRecognitionResult(requestId, results);
+ }
+ }
+}
+
+MockWebSpeechInputController::SpeechTask::SpeechTask(MockWebSpeechInputController* mock)
+ : WebMethodTask<MockWebSpeechInputController>::WebMethodTask(mock)
+{
+}
+
+void MockWebSpeechInputController::SpeechTask::stop()
+{
+ m_object->m_speechTask = 0;
+ cancel();
+}
+
+void MockWebSpeechInputController::SpeechTask::runIfValid()
+{
+ m_object->m_speechTask = 0;
+ m_object->speechTaskFired();
+}
+
+}
+
+#endif
diff --git a/content/shell/renderer/test_runner/MockWebSpeechInputController.h b/content/shell/renderer/test_runner/MockWebSpeechInputController.h
new file mode 100644
index 0000000..af493ce
--- /dev/null
+++ b/content/shell/renderer/test_runner/MockWebSpeechInputController.h
@@ -0,0 +1,77 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MockWebSpeechInputController_h
+#define MockWebSpeechInputController_h
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "content/shell/renderer/test_runner/TestCommon.h"
+#include "content/shell/renderer/test_runner/WebTask.h"
+#include "third_party/WebKit/public/platform/WebNonCopyable.h"
+#include "third_party/WebKit/public/platform/WebRect.h"
+#include "third_party/WebKit/public/web/WebSpeechInputController.h"
+#include "third_party/WebKit/public/web/WebSpeechInputResult.h"
+
+namespace blink {
+class WebSecurityOrigin;
+class WebSpeechInputListener;
+class WebString;
+}
+
+namespace WebTestRunner {
+
+class WebTestDelegate;
+
+class MockWebSpeechInputController : public blink::WebSpeechInputController, public blink::WebNonCopyable {
+public:
+ explicit MockWebSpeechInputController(blink::WebSpeechInputListener*);
+ ~MockWebSpeechInputController();
+
+ void addMockRecognitionResult(const blink::WebString& result, double confidence, const blink::WebString& language);
+ void setDumpRect(bool);
+ void clearResults();
+ void setDelegate(WebTestDelegate*);
+
+ // WebSpeechInputController implementation:
+ virtual bool startRecognition(int requestId, const blink::WebRect& elementRect, const blink::WebString& language, const blink::WebString& grammar, const blink::WebSecurityOrigin&) OVERRIDE;
+ virtual void cancelRecognition(int requestId) OVERRIDE;
+ virtual void stopRecording(int requestId) OVERRIDE;
+
+ WebTaskList* taskList() { return &m_taskList; }
+
+private:
+ void speechTaskFired();
+
+ class SpeechTask : public WebMethodTask<MockWebSpeechInputController> {
+ public:
+ SpeechTask(MockWebSpeechInputController*);
+ void stop();
+
+ private:
+ virtual void runIfValid() OVERRIDE;
+ };
+
+ blink::WebSpeechInputListener* m_listener;
+
+ WebTaskList m_taskList;
+ SpeechTask* m_speechTask;
+
+ bool m_recording;
+ int m_requestId;
+ blink::WebRect m_requestRect;
+ std::string m_language;
+
+ std::map<std::string, std::vector<blink::WebSpeechInputResult> > m_recognitionResults;
+ std::vector<blink::WebSpeechInputResult> m_resultsForEmptyLanguage;
+ bool m_dumpRect;
+
+ WebTestDelegate* m_delegate;
+};
+
+}
+
+#endif // MockWebSpeechInputController_h
diff --git a/content/shell/renderer/test_runner/MockWebSpeechRecognizer.cpp b/content/shell/renderer/test_runner/MockWebSpeechRecognizer.cpp
new file mode 100644
index 0000000..2854a03
--- /dev/null
+++ b/content/shell/renderer/test_runner/MockWebSpeechRecognizer.cpp
@@ -0,0 +1,226 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/shell/renderer/test_runner/MockWebSpeechRecognizer.h"
+
+#include "content/shell/renderer/test_runner/WebTestDelegate.h"
+#include "third_party/WebKit/public/web/WebSpeechRecognitionResult.h"
+#include "third_party/WebKit/public/web/WebSpeechRecognizerClient.h"
+
+using namespace blink;
+using namespace std;
+
+namespace WebTestRunner {
+
+namespace {
+
+// Task class for calling a client function that does not take any parameters.
+typedef void (WebSpeechRecognizerClient::*ClientFunctionPointer)(const WebSpeechRecognitionHandle&);
+class ClientCallTask : public MockWebSpeechRecognizer::Task {
+public:
+ ClientCallTask(MockWebSpeechRecognizer* mock, ClientFunctionPointer function)
+ : MockWebSpeechRecognizer::Task(mock)
+ , m_function(function)
+ {
+ }
+
+ virtual void run() OVERRIDE { (m_recognizer->client()->*m_function)(m_recognizer->handle()); }
+
+private:
+ ClientFunctionPointer m_function;
+};
+
+// Task for delivering a result event.
+class ResultTask : public MockWebSpeechRecognizer::Task {
+public:
+ ResultTask(MockWebSpeechRecognizer* mock, const WebString transcript, float confidence)
+ : MockWebSpeechRecognizer::Task(mock)
+ , m_transcript(transcript)
+ , m_confidence(confidence)
+ {
+ }
+
+ virtual void run() OVERRIDE
+ {
+ WebVector<WebString> transcripts(static_cast<size_t>(1));
+ WebVector<float> confidences(static_cast<size_t>(1));
+ transcripts[0] = m_transcript;
+ confidences[0] = m_confidence;
+ WebVector<WebSpeechRecognitionResult> finalResults(static_cast<size_t>(1));
+ WebVector<WebSpeechRecognitionResult> interimResults;
+ finalResults[0].assign(transcripts, confidences, true);
+
+ m_recognizer->client()->didReceiveResults(m_recognizer->handle(), finalResults, interimResults);
+ }
+
+private:
+ WebString m_transcript;
+ float m_confidence;
+};
+
+// Task for delivering a nomatch event.
+class NoMatchTask : public MockWebSpeechRecognizer::Task {
+public:
+ NoMatchTask(MockWebSpeechRecognizer* mock) : MockWebSpeechRecognizer::Task(mock) { }
+ virtual void run() OVERRIDE { m_recognizer->client()->didReceiveNoMatch(m_recognizer->handle(), WebSpeechRecognitionResult()); }
+};
+
+// Task for delivering an error event.
+class ErrorTask : public MockWebSpeechRecognizer::Task {
+public:
+ ErrorTask(MockWebSpeechRecognizer* mock, WebSpeechRecognizerClient::ErrorCode code, const WebString& message)
+ : MockWebSpeechRecognizer::Task(mock)
+ , m_code(code)
+ , m_message(message)
+ {
+ }
+
+ virtual void run() OVERRIDE { m_recognizer->client()->didReceiveError(m_recognizer->handle(), m_message, m_code); }
+
+private:
+ WebSpeechRecognizerClient::ErrorCode m_code;
+ WebString m_message;
+};
+
+} // namespace
+
+MockWebSpeechRecognizer::MockWebSpeechRecognizer()
+ : m_wasAborted(false)
+ , m_taskQueueRunning(false)
+ , m_delegate(0)
+{
+}
+
+MockWebSpeechRecognizer::~MockWebSpeechRecognizer()
+{
+ clearTaskQueue();
+}
+
+void MockWebSpeechRecognizer::setDelegate(WebTestDelegate* delegate)
+{
+ m_delegate = delegate;
+}
+
+void MockWebSpeechRecognizer::start(const WebSpeechRecognitionHandle& handle, const WebSpeechRecognitionParams& params, WebSpeechRecognizerClient* client)
+{
+ m_wasAborted = false;
+ m_handle = handle;
+ m_client = client;
+
+ m_taskQueue.push_back(new ClientCallTask(this, &WebSpeechRecognizerClient::didStart));
+ m_taskQueue.push_back(new ClientCallTask(this, &WebSpeechRecognizerClient::didStartAudio));
+ m_taskQueue.push_back(new ClientCallTask(this, &WebSpeechRecognizerClient::didStartSound));
+
+ if (!m_mockTranscripts.empty()) {
+ BLINK_ASSERT(m_mockTranscripts.size() == m_mockConfidences.size());
+
+ for (size_t i = 0; i < m_mockTranscripts.size(); ++i)
+ m_taskQueue.push_back(new ResultTask(this, m_mockTranscripts[i], m_mockConfidences[i]));
+
+ m_mockTranscripts.clear();
+ m_mockConfidences.clear();
+ } else
+ m_taskQueue.push_back(new NoMatchTask(this));
+
+ m_taskQueue.push_back(new ClientCallTask(this, &WebSpeechRecognizerClient::didEndSound));
+ m_taskQueue.push_back(new ClientCallTask(this, &WebSpeechRecognizerClient::didEndAudio));
+ m_taskQueue.push_back(new ClientCallTask(this, &WebSpeechRecognizerClient::didEnd));
+
+ startTaskQueue();
+}
+
+void MockWebSpeechRecognizer::stop(const WebSpeechRecognitionHandle& handle, WebSpeechRecognizerClient* client)
+{
+ m_handle = handle;
+ m_client = client;
+
+ // FIXME: Implement.
+ BLINK_ASSERT_NOT_REACHED();
+}
+
+void MockWebSpeechRecognizer::abort(const WebSpeechRecognitionHandle& handle, WebSpeechRecognizerClient* client)
+{
+ m_handle = handle;
+ m_client = client;
+
+ clearTaskQueue();
+ m_wasAborted = true;
+ m_taskQueue.push_back(new ClientCallTask(this, &WebSpeechRecognizerClient::didEnd));
+ startTaskQueue();
+}
+
+void MockWebSpeechRecognizer::addMockResult(const WebString& transcript, float confidence)
+{
+ m_mockTranscripts.push_back(transcript);
+ m_mockConfidences.push_back(confidence);
+}
+
+void MockWebSpeechRecognizer::setError(const WebString& error, const WebString& message)
+{
+ WebSpeechRecognizerClient::ErrorCode code;
+ if (error == "OtherError")
+ code = WebSpeechRecognizerClient::OtherError;
+ else if (error == "NoSpeechError")
+ code = WebSpeechRecognizerClient::NoSpeechError;
+ else if (error == "AbortedError")
+ code = WebSpeechRecognizerClient::AbortedError;
+ else if (error == "AudioCaptureError")
+ code = WebSpeechRecognizerClient::AudioCaptureError;
+ else if (error == "NetworkError")
+ code = WebSpeechRecognizerClient::NetworkError;
+ else if (error == "NotAllowedError")
+ code = WebSpeechRecognizerClient::NotAllowedError;
+ else if (error == "ServiceNotAllowedError")
+ code = WebSpeechRecognizerClient::ServiceNotAllowedError;
+ else if (error == "BadGrammarError")
+ code = WebSpeechRecognizerClient::BadGrammarError;
+ else if (error == "LanguageNotSupportedError")
+ code = WebSpeechRecognizerClient::LanguageNotSupportedError;
+ else
+ return;
+
+ clearTaskQueue();
+ m_taskQueue.push_back(new ErrorTask(this, code, message));
+ m_taskQueue.push_back(new ClientCallTask(this, &WebSpeechRecognizerClient::didEnd));
+ startTaskQueue();
+}
+
+void MockWebSpeechRecognizer::startTaskQueue()
+{
+ if (m_taskQueueRunning)
+ return;
+ m_delegate->postTask(new StepTask(this));
+ m_taskQueueRunning = true;
+}
+
+void MockWebSpeechRecognizer::clearTaskQueue()
+{
+ while (!m_taskQueue.empty()) {
+ delete m_taskQueue.front();
+ m_taskQueue.pop_front();
+ }
+ m_taskQueueRunning = false;
+}
+
+void MockWebSpeechRecognizer::StepTask::runIfValid()
+{
+ if (m_object->m_taskQueue.empty()) {
+ m_object->m_taskQueueRunning = false;
+ return;
+ }
+
+ Task* task = m_object->m_taskQueue.front();
+ m_object->m_taskQueue.pop_front();
+ task->run();
+ delete task;
+
+ if (m_object->m_taskQueue.empty()) {
+ m_object->m_taskQueueRunning = false;
+ return;
+ }
+
+ m_object->m_delegate->postTask(new StepTask(m_object));
+}
+
+}
diff --git a/content/shell/renderer/test_runner/MockWebSpeechRecognizer.h b/content/shell/renderer/test_runner/MockWebSpeechRecognizer.h
new file mode 100644
index 0000000..d249641
--- /dev/null
+++ b/content/shell/renderer/test_runner/MockWebSpeechRecognizer.h
@@ -0,0 +1,84 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MockWebSpeechRecognizer_h
+#define MockWebSpeechRecognizer_h
+
+#include <deque>
+#include <vector>
+
+#include "content/shell/renderer/test_runner/TestCommon.h"
+#include "content/shell/renderer/test_runner/WebTask.h"
+#include "third_party/WebKit/public/platform/WebNonCopyable.h"
+#include "third_party/WebKit/public/web/WebSpeechRecognizer.h"
+
+namespace blink {
+class WebSpeechRecognitionHandle;
+class WebSpeechRecognitionParams;
+class WebSpeechRecognizerClient;
+}
+
+namespace WebTestRunner {
+
+class WebTestDelegate;
+
+class MockWebSpeechRecognizer : public blink::WebSpeechRecognizer, public blink::WebNonCopyable {
+public:
+ MockWebSpeechRecognizer();
+ ~MockWebSpeechRecognizer();
+
+ void setDelegate(WebTestDelegate*);
+
+ // WebSpeechRecognizer implementation:
+ virtual void start(const blink::WebSpeechRecognitionHandle&, const blink::WebSpeechRecognitionParams&, blink::WebSpeechRecognizerClient*) OVERRIDE;
+ virtual void stop(const blink::WebSpeechRecognitionHandle&, blink::WebSpeechRecognizerClient*) OVERRIDE;
+ virtual void abort(const blink::WebSpeechRecognitionHandle&, blink::WebSpeechRecognizerClient*) OVERRIDE;
+
+ // Methods accessed by layout tests:
+ void addMockResult(const blink::WebString& transcript, float confidence);
+ void setError(const blink::WebString& error, const blink::WebString& message);
+ bool wasAborted() const { return m_wasAborted; }
+
+ // Methods accessed from Task objects:
+ blink::WebSpeechRecognizerClient* client() { return m_client; }
+ blink::WebSpeechRecognitionHandle& handle() { return m_handle; }
+ WebTaskList* taskList() { return &m_taskList; }
+
+ class Task {
+ public:
+ Task(MockWebSpeechRecognizer* recognizer) : m_recognizer(recognizer) { }
+ virtual ~Task() { }
+ virtual void run() = 0;
+ protected:
+ MockWebSpeechRecognizer* m_recognizer;
+ };
+
+private:
+ void startTaskQueue();
+ void clearTaskQueue();
+
+ WebTaskList m_taskList;
+ blink::WebSpeechRecognitionHandle m_handle;
+ blink::WebSpeechRecognizerClient* m_client;
+ std::vector<blink::WebString> m_mockTranscripts;
+ std::vector<float> m_mockConfidences;
+ bool m_wasAborted;
+
+ // Queue of tasks to be run.
+ std::deque<Task*> m_taskQueue;
+ bool m_taskQueueRunning;
+
+ WebTestDelegate* m_delegate;
+
+ // Task for stepping the queue.
+ class StepTask : public WebMethodTask<MockWebSpeechRecognizer> {
+ public:
+ StepTask(MockWebSpeechRecognizer* object) : WebMethodTask<MockWebSpeechRecognizer>(object) { }
+ virtual void runIfValid() OVERRIDE;
+ };
+};
+
+}
+
+#endif // MockWebSpeechRecognizer_h
diff --git a/content/shell/renderer/test_runner/NotificationPresenter.cpp b/content/shell/renderer/test_runner/NotificationPresenter.cpp
new file mode 100644
index 0000000..b3c9963
--- /dev/null
+++ b/content/shell/renderer/test_runner/NotificationPresenter.cpp
@@ -0,0 +1,141 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/shell/renderer/test_runner/NotificationPresenter.h"
+
+#include "content/shell/renderer/test_runner/WebTestDelegate.h"
+#include "third_party/WebKit/public/platform/Platform.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/platform/WebURL.h"
+#include "third_party/WebKit/public/web/WebKit.h"
+#include "third_party/WebKit/public/web/WebNotificationPermissionCallback.h"
+#include "third_party/WebKit/public/web/WebSecurityOrigin.h"
+#include "url/gurl.h"
+
+using namespace blink;
+using namespace std;
+
+namespace WebTestRunner {
+
+namespace {
+
+WebString identifierForNotification(const WebNotification& notification)
+{
+ if (notification.isHTML())
+ return notification.url().spec().utf16();
+ return notification.title();
+}
+
+void deferredDisplayDispatch(void* context)
+{
+ WebNotification* notification = static_cast<WebNotification*>(context);
+ notification->dispatchDisplayEvent();
+ delete notification;
+}
+
+}
+
+NotificationPresenter::NotificationPresenter()
+ : m_delegate(0)
+{
+}
+
+NotificationPresenter::~NotificationPresenter()
+{
+}
+
+void NotificationPresenter::grantPermission(const WebString& origin)
+{
+ m_allowedOrigins.insert(origin.utf8());
+}
+
+bool NotificationPresenter::simulateClick(const WebString& title)
+{
+ string id(title.utf8());
+ if (m_activeNotifications.find(id) == m_activeNotifications.end())
+ return false;
+
+ const WebNotification& notification = m_activeNotifications.find(id)->second;
+ WebNotification eventTarget(notification);
+ eventTarget.dispatchClickEvent();
+ return true;
+}
+
+void NotificationPresenter::cancelAllActiveNotifications()
+{
+ while (!m_activeNotifications.empty()) {
+ const WebNotification& notification = m_activeNotifications.begin()->second;
+ cancel(notification);
+ }
+}
+
+// The output from all these methods matches what DumpRenderTree produces.
+bool NotificationPresenter::show(const WebNotification& notification)
+{
+ WebString identifier = identifierForNotification(notification);
+ if (!notification.replaceId().isEmpty()) {
+ string replaceId(notification.replaceId().utf8());
+ if (m_replacements.find(replaceId) != m_replacements.end())
+ m_delegate->printMessage(string("REPLACING NOTIFICATION ") + m_replacements.find(replaceId)->second + "\n");
+
+ m_replacements[replaceId] = identifier.utf8();
+ }
+
+ if (notification.isHTML())
+ m_delegate->printMessage(string("DESKTOP NOTIFICATION: contents at ") + string(notification.url().spec()) + "\n");
+ else {
+ m_delegate->printMessage("DESKTOP NOTIFICATION:");
+ m_delegate->printMessage(notification.direction() == WebTextDirectionRightToLeft ? "(RTL)" : "");
+ m_delegate->printMessage(" icon ");
+ m_delegate->printMessage(notification.iconURL().isEmpty() ? "" : notification.iconURL().spec().data());
+ m_delegate->printMessage(", title ");
+ m_delegate->printMessage(notification.title().isEmpty() ? "" : notification.title().utf8().data());
+ m_delegate->printMessage(", text ");
+ m_delegate->printMessage(notification.body().isEmpty() ? "" : notification.body().utf8().data());
+ m_delegate->printMessage("\n");
+ }
+
+ string id(identifier.utf8());
+ m_activeNotifications[id] = notification;
+
+ Platform::current()->callOnMainThread(deferredDisplayDispatch, new WebNotification(notification));
+ return true;
+}
+
+void NotificationPresenter::cancel(const WebNotification& notification)
+{
+ WebString identifier = identifierForNotification(notification);
+ m_delegate->printMessage(string("DESKTOP NOTIFICATION CLOSED: ") + string(identifier.utf8()) + "\n");
+ WebNotification eventTarget(notification);
+ eventTarget.dispatchCloseEvent(false);
+
+ string id(identifier.utf8());
+ m_activeNotifications.erase(id);
+}
+
+void NotificationPresenter::objectDestroyed(const blink::WebNotification& notification)
+{
+ WebString identifier = identifierForNotification(notification);
+ string id(identifier.utf8());
+ m_activeNotifications.erase(id);
+}
+
+WebNotificationPresenter::Permission NotificationPresenter::checkPermission(const WebSecurityOrigin& origin)
+{
+ // Check with the layout test controller
+ WebString originString = origin.toString();
+ bool allowed = m_allowedOrigins.find(string(originString.utf8())) != m_allowedOrigins.end();
+ return allowed ? WebNotificationPresenter::PermissionAllowed
+ : WebNotificationPresenter::PermissionDenied;
+}
+
+void NotificationPresenter::requestPermission(
+ const WebSecurityOrigin& origin,
+ WebNotificationPermissionCallback* callback)
+{
+ m_delegate->printMessage("DESKTOP NOTIFICATION PERMISSION REQUESTED: " + string(origin.toString().utf8()) + "\n");
+ callback->permissionRequestComplete();
+}
+
+}
diff --git a/content/shell/renderer/test_runner/NotificationPresenter.h b/content/shell/renderer/test_runner/NotificationPresenter.h
new file mode 100644
index 0000000..a680a3a
--- /dev/null
+++ b/content/shell/renderer/test_runner/NotificationPresenter.h
@@ -0,0 +1,61 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NotificationPresenter_h
+#define NotificationPresenter_h
+
+#include <map>
+#include <set>
+#include <string>
+
+#include "third_party/WebKit/public/platform/WebNonCopyable.h"
+#include "third_party/WebKit/public/web/WebNotification.h"
+#include "third_party/WebKit/public/web/WebNotificationPresenter.h"
+
+namespace WebTestRunner {
+
+class WebTestDelegate;
+
+// A class that implements WebNotificationPresenter for the TestRunner library.
+class NotificationPresenter : public blink::WebNotificationPresenter, public blink::WebNonCopyable {
+public:
+ NotificationPresenter();
+ virtual ~NotificationPresenter();
+
+ void setDelegate(WebTestDelegate* delegate) { m_delegate = delegate; }
+
+ // Called by the TestRunner to simulate a user granting permission.
+ void grantPermission(const blink::WebString& origin);
+
+ // Called by the TestRunner to simulate a user clicking on a notification.
+ bool simulateClick(const blink::WebString& notificationIdentifier);
+
+ // Called by the TestRunner to cancel all active notications.
+ void cancelAllActiveNotifications();
+
+ // blink::WebNotificationPresenter interface
+ virtual bool show(const blink::WebNotification&);
+ virtual void cancel(const blink::WebNotification&);
+ virtual void objectDestroyed(const blink::WebNotification&);
+ virtual Permission checkPermission(const blink::WebSecurityOrigin&);
+ virtual void requestPermission(const blink::WebSecurityOrigin&, blink::WebNotificationPermissionCallback*);
+
+ void reset() { m_allowedOrigins.clear(); }
+
+private:
+ WebTestDelegate* m_delegate;
+
+ // Set of allowed origins.
+ std::set<std::string> m_allowedOrigins;
+
+ // Map of active notifications.
+ std::map<std::string, blink::WebNotification> m_activeNotifications;
+
+ // Map of active replacement IDs to the titles of those notifications
+ std::map<std::string, std::string> m_replacements;
+};
+
+}
+
+#endif // NotificationPresenter_h
diff --git a/content/shell/renderer/test_runner/OWNERS b/content/shell/renderer/test_runner/OWNERS
new file mode 100644
index 0000000..cf00f71
--- /dev/null
+++ b/content/shell/renderer/test_runner/OWNERS
@@ -0,0 +1 @@
+abarth@chromium.org
diff --git a/content/shell/renderer/test_runner/SpellCheckClient.cpp b/content/shell/renderer/test_runner/SpellCheckClient.cpp
new file mode 100644
index 0000000..3ae2f32
--- /dev/null
+++ b/content/shell/renderer/test_runner/SpellCheckClient.cpp
@@ -0,0 +1,143 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/shell/renderer/test_runner/SpellCheckClient.h"
+
+#include "content/shell/renderer/test_runner/MockGrammarCheck.h"
+#include "content/shell/renderer/test_runner/WebTestDelegate.h"
+#include "content/shell/renderer/test_runner/WebTestProxy.h"
+#include "third_party/WebKit/public/web/WebTextCheckingCompletion.h"
+#include "third_party/WebKit/public/web/WebTextCheckingResult.h"
+
+using namespace blink;
+using namespace std;
+
+namespace WebTestRunner {
+
+namespace {
+
+class HostMethodTask : public WebMethodTask<SpellCheckClient> {
+public:
+ typedef void (SpellCheckClient::*CallbackMethodType)();
+ HostMethodTask(SpellCheckClient* object, CallbackMethodType callback)
+ : WebMethodTask<SpellCheckClient>(object)
+ , m_callback(callback)
+ { }
+
+ virtual void runIfValid() { (m_object->*m_callback)(); }
+
+private:
+ CallbackMethodType m_callback;
+};
+
+}
+
+SpellCheckClient::SpellCheckClient(WebTestProxyBase* webTestProxy)
+ : m_lastRequestedTextCheckingCompletion(0)
+ , m_webTestProxy(webTestProxy)
+{
+}
+
+SpellCheckClient::~SpellCheckClient()
+{
+}
+
+void SpellCheckClient::setDelegate(WebTestDelegate* delegate)
+{
+ m_delegate = delegate;
+}
+
+// blink::WebSpellCheckClient
+void SpellCheckClient::spellCheck(const WebString& text, int& misspelledOffset, int& misspelledLength, WebVector<WebString>* optionalSuggestions)
+{
+ // Check the spelling of the given text.
+ m_spellcheck.spellCheckWord(text, &misspelledOffset, &misspelledLength);
+}
+
+void SpellCheckClient::checkTextOfParagraph(const WebString& text, WebTextCheckingTypeMask mask, WebVector<WebTextCheckingResult>* webResults)
+{
+ vector<WebTextCheckingResult> results;
+ if (mask & WebTextCheckingTypeSpelling) {
+ size_t offset = 0;
+ string16 data = text;
+ while (offset < data.length()) {
+ int misspelledPosition = 0;
+ int misspelledLength = 0;
+ m_spellcheck.spellCheckWord(data.substr(offset), &misspelledPosition, &misspelledLength);
+ if (!misspelledLength)
+ break;
+ WebTextCheckingResult result;
+ result.decoration = WebTextDecorationTypeSpelling;
+ result.location = offset + misspelledPosition;
+ result.length = misspelledLength;
+ results.push_back(result);
+ offset += misspelledPosition + misspelledLength;
+ }
+ }
+ if (mask & WebTextCheckingTypeGrammar)
+ MockGrammarCheck::checkGrammarOfString(text, &results);
+ webResults->assign(results);
+}
+
+void SpellCheckClient::requestCheckingOfText(
+ const WebString& text,
+ const WebVector<uint32_t>& markers,
+ const WebVector<unsigned>& markerOffsets,
+ WebTextCheckingCompletion* completion)
+{
+ if (text.isEmpty()) {
+ if (completion)
+ completion->didCancelCheckingText();
+ return;
+ }
+
+ if (m_lastRequestedTextCheckingCompletion)
+ m_lastRequestedTextCheckingCompletion->didCancelCheckingText();
+
+ m_lastRequestedTextCheckingCompletion = completion;
+ m_lastRequestedTextCheckString = text;
+ if (m_spellcheck.hasInCache(text))
+ finishLastTextCheck();
+ else
+ m_delegate->postDelayedTask(new HostMethodTask(this, &SpellCheckClient::finishLastTextCheck), 0);
+}
+
+void SpellCheckClient::finishLastTextCheck()
+{
+ if (!m_lastRequestedTextCheckingCompletion)
+ return;
+ vector<WebTextCheckingResult> results;
+ int offset = 0;
+ string16 text = m_lastRequestedTextCheckString;
+ if (!m_spellcheck.isMultiWordMisspelling(WebString(text), &results)) {
+ while (text.length()) {
+ int misspelledPosition = 0;
+ int misspelledLength = 0;
+ m_spellcheck.spellCheckWord(WebString(text), &misspelledPosition, &misspelledLength);
+ if (!misspelledLength)
+ break;
+ WebVector<WebString> suggestions;
+ m_spellcheck.fillSuggestionList(WebString(text.substr(misspelledPosition, misspelledLength)), &suggestions);
+ results.push_back(WebTextCheckingResult(WebTextDecorationTypeSpelling, offset + misspelledPosition, misspelledLength, suggestions.isEmpty() ? WebString() : suggestions[0]));
+ text = text.substr(misspelledPosition + misspelledLength);
+ offset += misspelledPosition + misspelledLength;
+ }
+ MockGrammarCheck::checkGrammarOfString(m_lastRequestedTextCheckString, &results);
+ }
+ m_lastRequestedTextCheckingCompletion->didFinishCheckingText(results);
+ m_lastRequestedTextCheckingCompletion = 0;
+
+ m_webTestProxy->postSpellCheckEvent(WebString("finishLastTextCheck"));
+}
+
+WebString SpellCheckClient::autoCorrectWord(const WebString&)
+{
+ // Returns an empty string as Mac WebKit ('WebKitSupport/WebEditorClient.mm')
+ // does. (If this function returns a non-empty string, WebKit replaces the
+ // given misspelled string with the result one. This process executes some
+ // editor commands and causes layout-test failures.)
+ return WebString();
+}
+
+}
diff --git a/content/shell/renderer/test_runner/SpellCheckClient.h b/content/shell/renderer/test_runner/SpellCheckClient.h
new file mode 100644
index 0000000..bc8ad9d
--- /dev/null
+++ b/content/shell/renderer/test_runner/SpellCheckClient.h
@@ -0,0 +1,55 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SpellCheckClient_h
+#define SpellCheckClient_h
+
+#include "content/shell/renderer/test_runner/MockSpellCheck.h"
+#include "content/shell/renderer/test_runner/WebTask.h"
+#include "third_party/WebKit/public/platform/WebNonCopyable.h"
+#include "third_party/WebKit/public/web/WebSpellCheckClient.h"
+
+namespace WebTestRunner {
+
+class WebTestDelegate;
+class WebTestProxyBase;
+
+class SpellCheckClient : public blink::WebSpellCheckClient, public blink::WebNonCopyable {
+public:
+ explicit SpellCheckClient(WebTestProxyBase*);
+ virtual ~SpellCheckClient();
+
+ void setDelegate(WebTestDelegate*);
+
+ WebTaskList* taskList() { return &m_taskList; }
+ MockSpellCheck* mockSpellCheck() { return &m_spellcheck; }
+
+ // blink::WebSpellCheckClient implementation.
+ virtual void spellCheck(const blink::WebString&, int& offset, int& length, blink::WebVector<blink::WebString>* optionalSuggestions);
+ virtual void checkTextOfParagraph(const blink::WebString&, blink::WebTextCheckingTypeMask, blink::WebVector<blink::WebTextCheckingResult>*);
+ virtual void requestCheckingOfText(const blink::WebString&,
+ const blink::WebVector<uint32_t>&,
+ const blink::WebVector<unsigned>&,
+ blink::WebTextCheckingCompletion*);
+ virtual blink::WebString autoCorrectWord(const blink::WebString&);
+
+private:
+ void finishLastTextCheck();
+
+ // The mock spellchecker used in spellCheck().
+ MockSpellCheck m_spellcheck;
+
+ blink::WebString m_lastRequestedTextCheckString;
+ blink::WebTextCheckingCompletion* m_lastRequestedTextCheckingCompletion;
+
+ WebTaskList m_taskList;
+
+ WebTestDelegate* m_delegate;
+
+ WebTestProxyBase* m_webTestProxy;
+};
+
+}
+
+#endif // SpellCheckClient_h
diff --git a/content/shell/renderer/test_runner/TestCommon.cpp b/content/shell/renderer/test_runner/TestCommon.cpp
new file mode 100644
index 0000000..691ecdd
--- /dev/null
+++ b/content/shell/renderer/test_runner/TestCommon.cpp
@@ -0,0 +1,37 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/shell/renderer/test_runner/TestCommon.h"
+
+using namespace std;
+
+namespace WebTestRunner {
+
+namespace {
+
+const char layoutTestsPattern[] = "/LayoutTests/";
+const string::size_type layoutTestsPatternSize = sizeof(layoutTestsPattern) - 1;
+const char fileUrlPattern[] = "file:/";
+const char fileTestPrefix[] = "(file test):";
+const char dataUrlPattern[] = "data:";
+const string::size_type dataUrlPatternSize = sizeof(dataUrlPattern) - 1;
+
+}
+
+string normalizeLayoutTestURL(const string& url)
+{
+ string result = url;
+ size_t pos;
+ if (!url.find(fileUrlPattern) && ((pos = url.find(layoutTestsPattern)) != string::npos)) {
+ // adjust file URLs to match upstream results.
+ result.replace(0, pos + layoutTestsPatternSize, fileTestPrefix);
+ } else if (!url.find(dataUrlPattern)) {
+ // URL-escape data URLs to match results upstream.
+ string path = url.substr(dataUrlPatternSize);
+ result.replace(dataUrlPatternSize, url.length(), path);
+ }
+ return result;
+}
+
+}
diff --git a/content/shell/renderer/test_runner/TestCommon.h b/content/shell/renderer/test_runner/TestCommon.h
new file mode 100644
index 0000000..5e83c47
--- /dev/null
+++ b/content/shell/renderer/test_runner/TestCommon.h
@@ -0,0 +1,28 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TestCommon_h
+#define TestCommon_h
+
+#include <stdio.h>
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "third_party/WebKit/public/platform/WebCommon.h"
+
+#if defined(WIN32)
+#define snprintf(str, size, ...) _snprintf_s(str, size, size, __VA_ARGS__)
+#endif
+
+namespace WebTestRunner {
+
+inline bool isASCIIAlpha(char ch) { return (ch | 0x20) >= 'a' && (ch | 0x20) <= 'z'; }
+
+inline bool isNotASCIIAlpha(char ch) { return !isASCIIAlpha(ch); }
+
+std::string normalizeLayoutTestURL(const std::string& url);
+
+}
+
+#endif // TestCommon_h
diff --git a/content/shell/renderer/test_runner/TestInterfaces.cpp b/content/shell/renderer/test_runner/TestInterfaces.cpp
new file mode 100644
index 0000000..6f1fc4d
--- /dev/null
+++ b/content/shell/renderer/test_runner/TestInterfaces.cpp
@@ -0,0 +1,191 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/shell/renderer/test_runner/TestInterfaces.h"
+
+#include <string>
+
+#include "content/shell/renderer/test_runner/AccessibilityController.h"
+#include "content/shell/renderer/test_runner/EventSender.h"
+#include "content/shell/renderer/test_runner/GamepadController.h"
+#include "content/shell/renderer/test_runner/TestRunner.h"
+#include "content/shell/renderer/test_runner/TextInputController.h"
+#include "content/shell/renderer/test_runner/WebTestProxy.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/platform/WebURL.h"
+#include "third_party/WebKit/public/web/WebCache.h"
+#include "third_party/WebKit/public/web/WebKit.h"
+#include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
+#include "third_party/WebKit/public/web/WebView.h"
+
+using namespace blink;
+using namespace std;
+
+namespace WebTestRunner {
+
+TestInterfaces::TestInterfaces()
+ : m_accessibilityController(new AccessibilityController())
+ , m_eventSender(new EventSender(this))
+ , m_gamepadController(new GamepadController())
+ , m_textInputController(new TextInputController())
+ , m_testRunner(new TestRunner(this))
+ , m_delegate(0)
+{
+ blink::setLayoutTestMode(true);
+
+ // NOTE: please don't put feature specific enable flags here,
+ // instead add them to RuntimeEnabledFeatures.in
+
+ resetAll();
+}
+
+TestInterfaces::~TestInterfaces()
+{
+ m_accessibilityController->setWebView(0);
+ m_eventSender->setWebView(0);
+ // m_gamepadController doesn't depend on WebView.
+ m_textInputController->setWebView(0);
+ m_testRunner->setWebView(0, 0);
+
+ m_accessibilityController->setDelegate(0);
+ m_eventSender->setDelegate(0);
+ m_gamepadController->setDelegate(0);
+ // m_textInputController doesn't depend on WebTestDelegate.
+ m_testRunner->setDelegate(0);
+}
+
+void TestInterfaces::setWebView(WebView* webView, WebTestProxyBase* proxy)
+{
+ m_proxy = proxy;
+ m_accessibilityController->setWebView(webView);
+ m_eventSender->setWebView(webView);
+ // m_gamepadController doesn't depend on WebView.
+ m_textInputController->setWebView(webView);
+ m_testRunner->setWebView(webView, proxy);
+}
+
+void TestInterfaces::setDelegate(WebTestDelegate* delegate)
+{
+ m_accessibilityController->setDelegate(delegate);
+ m_eventSender->setDelegate(delegate);
+ m_gamepadController->setDelegate(delegate);
+ // m_textInputController doesn't depend on WebTestDelegate.
+ m_testRunner->setDelegate(delegate);
+ m_delegate = delegate;
+}
+
+void TestInterfaces::bindTo(WebFrame* frame)
+{
+ m_accessibilityController->bindToJavascript(frame, WebString::fromUTF8("accessibilityController"));
+ m_eventSender->bindToJavascript(frame, WebString::fromUTF8("eventSender"));
+ m_gamepadController->bindToJavascript(frame, WebString::fromUTF8("gamepadController"));
+ m_textInputController->bindToJavascript(frame, WebString::fromUTF8("textInputController"));
+ m_testRunner->bindToJavascript(frame, WebString::fromUTF8("testRunner"));
+ m_testRunner->bindToJavascript(frame, WebString::fromUTF8("layoutTestController"));
+}
+
+void TestInterfaces::resetTestHelperControllers()
+{
+ m_accessibilityController->reset();
+ m_eventSender->reset();
+ m_gamepadController->reset();
+ // m_textInputController doesn't have any state to reset.
+ WebCache::clear();
+}
+
+void TestInterfaces::resetAll()
+{
+ resetTestHelperControllers();
+ m_testRunner->reset();
+}
+
+void TestInterfaces::setTestIsRunning(bool running)
+{
+ m_testRunner->setTestIsRunning(running);
+}
+
+void TestInterfaces::configureForTestWithURL(const WebURL& testURL, bool generatePixels)
+{
+ string spec = GURL(testURL).spec();
+ m_testRunner->setShouldGeneratePixelResults(generatePixels);
+ if (spec.find("loading/") != string::npos)
+ m_testRunner->setShouldDumpFrameLoadCallbacks(true);
+ if (spec.find("/dumpAsText/") != string::npos) {
+ m_testRunner->setShouldDumpAsText(true);
+ m_testRunner->setShouldGeneratePixelResults(false);
+ }
+ if (spec.find("/inspector/") != string::npos)
+ m_testRunner->showDevTools();
+ if (spec.find("/viewsource/") != string::npos) {
+ m_testRunner->setShouldEnableViewSource(true);
+ m_testRunner->setShouldGeneratePixelResults(false);
+ m_testRunner->setShouldDumpAsMarkup(true);
+ }
+}
+
+void TestInterfaces::windowOpened(WebTestProxyBase* proxy)
+{
+ m_windowList.push_back(proxy);
+}
+
+void TestInterfaces::windowClosed(WebTestProxyBase* proxy)
+{
+ vector<WebTestProxyBase*>::iterator pos = find(m_windowList.begin(), m_windowList.end(), proxy);
+ if (pos == m_windowList.end()) {
+ BLINK_ASSERT_NOT_REACHED();
+ return;
+ }
+ m_windowList.erase(pos);
+}
+
+AccessibilityController* TestInterfaces::accessibilityController()
+{
+ return m_accessibilityController.get();
+}
+
+EventSender* TestInterfaces::eventSender()
+{
+ return m_eventSender.get();
+}
+
+TestRunner* TestInterfaces::testRunner()
+{
+ return m_testRunner.get();
+}
+
+WebTestDelegate* TestInterfaces::delegate()
+{
+ return m_delegate;
+}
+
+WebTestProxyBase* TestInterfaces::proxy()
+{
+ return m_proxy;
+}
+
+const vector<WebTestProxyBase*>& TestInterfaces::windowList()
+{
+ return m_windowList;
+}
+
+WebThemeEngine* TestInterfaces::themeEngine()
+{
+#if defined(USE_DEFAULT_RENDER_THEME) || !(defined(WIN32) || defined(__APPLE__) || defined(ANDROID))
+ if (!m_themeEngine.get())
+ m_themeEngine.reset(new WebTestThemeEngineMock());
+ return m_themeEngine.get();
+#elif defined(WIN32)
+ if (!m_themeEngine.get())
+ m_themeEngine.reset(new WebTestThemeEngineWin());
+ return m_themeEngine.get();
+#elif defined(__APPLE__)
+ if (!m_themeEngine.get())
+ m_themeEngine.reset(new WebTestThemeEngineMac());
+ return m_themeEngine.get();
+#else
+ return 0;
+#endif
+}
+
+}
diff --git a/content/shell/renderer/test_runner/TestInterfaces.h b/content/shell/renderer/test_runner/TestInterfaces.h
new file mode 100644
index 0000000..fccdc1c
--- /dev/null
+++ b/content/shell/renderer/test_runner/TestInterfaces.h
@@ -0,0 +1,83 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TestInterfaces_h
+#define TestInterfaces_h
+
+#include <vector>
+
+#include "content/shell/renderer/test_runner/WebScopedPtr.h"
+#include "third_party/WebKit/public/platform/WebNonCopyable.h"
+
+#if defined(USE_DEFAULT_RENDER_THEME)
+#include "content/shell/renderer/test_runner/WebTestThemeEngineMock.h"
+#elif defined(WIN32)
+#include "content/shell/renderer/test_runner/WebTestThemeEngineWin.h"
+#elif defined(__APPLE__)
+#include "content/shell/renderer/test_runner/WebTestThemeEngineMac.h"
+#endif
+
+namespace blink {
+class WebFrame;
+class WebThemeEngine;
+class WebURL;
+class WebView;
+}
+
+namespace WebTestRunner {
+
+class AccessibilityController;
+class EventSender;
+class GamepadController;
+class TestRunner;
+class TextInputController;
+class WebTestDelegate;
+class WebTestProxyBase;
+
+class TestInterfaces : public blink::WebNonCopyable {
+public:
+ TestInterfaces();
+ ~TestInterfaces();
+
+ void setWebView(blink::WebView*, WebTestProxyBase*);
+ void setDelegate(WebTestDelegate*);
+ void bindTo(blink::WebFrame*);
+ void resetTestHelperControllers();
+ void resetAll();
+ void setTestIsRunning(bool);
+ void configureForTestWithURL(const blink::WebURL&, bool generatePixels);
+
+ void windowOpened(WebTestProxyBase*);
+ void windowClosed(WebTestProxyBase*);
+
+ AccessibilityController* accessibilityController();
+ EventSender* eventSender();
+ TestRunner* testRunner();
+ WebTestDelegate* delegate();
+ WebTestProxyBase* proxy();
+ const std::vector<WebTestProxyBase*>& windowList();
+ blink::WebThemeEngine* themeEngine();
+
+private:
+ WebScopedPtr<AccessibilityController> m_accessibilityController;
+ WebScopedPtr<EventSender> m_eventSender;
+ WebScopedPtr<GamepadController> m_gamepadController;
+ WebScopedPtr<TextInputController> m_textInputController;
+ WebScopedPtr<TestRunner> m_testRunner;
+ WebTestDelegate* m_delegate;
+ WebTestProxyBase* m_proxy;
+
+ std::vector<WebTestProxyBase*> m_windowList;
+#if defined(USE_DEFAULT_RENDER_THEME)
+ WebScopedPtr<WebTestThemeEngineMock> m_themeEngine;
+#elif defined(WIN32)
+ WebScopedPtr<WebTestThemeEngineWin> m_themeEngine;
+#elif defined(__APPLE__)
+ WebScopedPtr<WebTestThemeEngineMac> m_themeEngine;
+#endif
+};
+
+}
+
+#endif // TestInterfaces_h
diff --git a/content/shell/renderer/test_runner/TestPlugin.cpp b/content/shell/renderer/test_runner/TestPlugin.cpp
new file mode 100644
index 0000000..eada1dc
--- /dev/null
+++ b/content/shell/renderer/test_runner/TestPlugin.cpp
@@ -0,0 +1,560 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/shell/renderer/test_runner/TestPlugin.h"
+
+#include "content/shell/renderer/test_runner/TestCommon.h"
+#include "content/shell/renderer/test_runner/WebTestDelegate.h"
+#include "third_party/WebKit/public/platform/Platform.h"
+#include "third_party/WebKit/public/platform/WebCompositorSupport.h"
+#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
+#include "third_party/WebKit/public/web/WebFrame.h"
+#include "third_party/WebKit/public/web/WebInputEvent.h"
+#include "third_party/WebKit/public/web/WebKit.h"
+#include "third_party/WebKit/public/web/WebPluginParams.h"
+#include "third_party/WebKit/public/web/WebTouchPoint.h"
+#include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
+
+using namespace blink;
+using namespace std;
+
+namespace WebTestRunner {
+
+namespace {
+
+// GLenum values copied from gl2.h.
+#define GL_FALSE 0
+#define GL_TRUE 1
+#define GL_ONE 1
+#define GL_TRIANGLES 0x0004
+#define GL_ONE_MINUS_SRC_ALPHA 0x0303
+#define GL_DEPTH_TEST 0x0B71
+#define GL_BLEND 0x0BE2
+#define GL_SCISSOR_TEST 0x0B90
+#define GL_TEXTURE_2D 0x0DE1
+#define GL_FLOAT 0x1406
+#define GL_RGBA 0x1908
+#define GL_UNSIGNED_BYTE 0x1401
+#define GL_TEXTURE_MAG_FILTER 0x2800
+#define GL_TEXTURE_MIN_FILTER 0x2801
+#define GL_TEXTURE_WRAP_S 0x2802
+#define GL_TEXTURE_WRAP_T 0x2803
+#define GL_NEAREST 0x2600
+#define GL_COLOR_BUFFER_BIT 0x4000
+#define GL_CLAMP_TO_EDGE 0x812F
+#define GL_ARRAY_BUFFER 0x8892
+#define GL_STATIC_DRAW 0x88E4
+#define GL_FRAGMENT_SHADER 0x8B30
+#define GL_VERTEX_SHADER 0x8B31
+#define GL_COMPILE_STATUS 0x8B81
+#define GL_LINK_STATUS 0x8B82
+#define GL_COLOR_ATTACHMENT0 0x8CE0
+#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
+#define GL_FRAMEBUFFER 0x8D40
+
+void premultiplyAlpha(const unsigned colorIn[3], float alpha, float colorOut[4])
+{
+ for (int i = 0; i < 3; ++i)
+ colorOut[i] = (colorIn[i] / 255.0f) * alpha;
+
+ colorOut[3] = alpha;
+}
+
+const char* pointState(WebTouchPoint::State state)
+{
+ switch (state) {
+ case WebTouchPoint::StateReleased:
+ return "Released";
+ case WebTouchPoint::StatePressed:
+ return "Pressed";
+ case WebTouchPoint::StateMoved:
+ return "Moved";
+ case WebTouchPoint::StateCancelled:
+ return "Cancelled";
+ default:
+ return "Unknown";
+ }
+
+ BLINK_ASSERT_NOT_REACHED();
+ return 0;
+}
+
+void printTouchList(WebTestDelegate* delegate, const WebTouchPoint* points, int length)
+{
+ for (int i = 0; i < length; ++i) {
+ char buffer[100];
+ snprintf(buffer, sizeof(buffer), "* %d, %d: %s\n", points[i].position.x, points[i].position.y, pointState(points[i].state));
+ delegate->printMessage(buffer);
+ }
+}
+
+void printEventDetails(WebTestDelegate* delegate, const WebInputEvent& event)
+{
+ if (WebInputEvent::isTouchEventType(event.type)) {
+ const WebTouchEvent& touch = static_cast<const WebTouchEvent&>(event);
+ printTouchList(delegate, touch.touches, touch.touchesLength);
+ printTouchList(delegate, touch.changedTouches, touch.changedTouchesLength);
+ printTouchList(delegate, touch.targetTouches, touch.targetTouchesLength);
+ } else if (WebInputEvent::isMouseEventType(event.type) || event.type == WebInputEvent::MouseWheel) {
+ const WebMouseEvent& mouse = static_cast<const WebMouseEvent&>(event);
+ char buffer[100];
+ snprintf(buffer, sizeof(buffer), "* %d, %d\n", mouse.x, mouse.y);
+ delegate->printMessage(buffer);
+ } else if (WebInputEvent::isGestureEventType(event.type)) {
+ const WebGestureEvent& gesture = static_cast<const WebGestureEvent&>(event);
+ char buffer[100];
+ snprintf(buffer, sizeof(buffer), "* %d, %d\n", gesture.x, gesture.y);
+ delegate->printMessage(buffer);
+ }
+}
+
+WebPluginContainer::TouchEventRequestType parseTouchEventRequestType(const WebString& string)
+{
+ if (string == WebString::fromUTF8("raw"))
+ return WebPluginContainer::TouchEventRequestTypeRaw;
+ if (string == WebString::fromUTF8("synthetic"))
+ return WebPluginContainer::TouchEventRequestTypeSynthesizedMouse;
+ return WebPluginContainer::TouchEventRequestTypeNone;
+}
+
+void deferredDelete(void* context)
+{
+ TestPlugin* plugin = static_cast<TestPlugin*>(context);
+ delete plugin;
+}
+
+}
+
+
+TestPlugin::TestPlugin(WebFrame* frame, const WebPluginParams& params, WebTestDelegate* delegate)
+ : m_frame(frame)
+ , m_delegate(delegate)
+ , m_container(0)
+ , m_context(0)
+ , m_colorTexture(0)
+ , m_mailboxChanged(false)
+ , m_framebuffer(0)
+ , m_touchEventRequest(WebPluginContainer::TouchEventRequestTypeNone)
+ , m_reRequestTouchEvents(false)
+ , m_printEventDetails(false)
+ , m_printUserGestureStatus(false)
+ , m_canProcessDrag(false)
+{
+ static const WebString kAttributePrimitive = WebString::fromUTF8("primitive");
+ static const WebString kAttributeBackgroundColor = WebString::fromUTF8("background-color");
+ static const WebString kAttributePrimitiveColor = WebString::fromUTF8("primitive-color");
+ static const WebString kAttributeOpacity = WebString::fromUTF8("opacity");
+ static const WebString kAttributeAcceptsTouch = WebString::fromUTF8("accepts-touch");
+ static const WebString kAttributeReRequestTouchEvents = WebString::fromUTF8("re-request-touch");
+ static const WebString kAttributePrintEventDetails = WebString::fromUTF8("print-event-details");
+ static const WebString kAttributeCanProcessDrag = WebString::fromUTF8("can-process-drag");
+ static const WebString kAttributePrintUserGestureStatus = WebString::fromUTF8("print-user-gesture-status");
+
+ BLINK_ASSERT(params.attributeNames.size() == params.attributeValues.size());
+ size_t size = params.attributeNames.size();
+ for (size_t i = 0; i < size; ++i) {
+ const WebString& attributeName = params.attributeNames[i];
+ const WebString& attributeValue = params.attributeValues[i];
+
+ if (attributeName == kAttributePrimitive)
+ m_scene.primitive = parsePrimitive(attributeValue);
+ else if (attributeName == kAttributeBackgroundColor)
+ parseColor(attributeValue, m_scene.backgroundColor);
+ else if (attributeName == kAttributePrimitiveColor)
+ parseColor(attributeValue, m_scene.primitiveColor);
+ else if (attributeName == kAttributeOpacity)
+ m_scene.opacity = parseOpacity(attributeValue);
+ else if (attributeName == kAttributeAcceptsTouch)
+ m_touchEventRequest = parseTouchEventRequestType(attributeValue);
+ else if (attributeName == kAttributeReRequestTouchEvents)
+ m_reRequestTouchEvents = parseBoolean(attributeValue);
+ else if (attributeName == kAttributePrintEventDetails)
+ m_printEventDetails = parseBoolean(attributeValue);
+ else if (attributeName == kAttributeCanProcessDrag)
+ m_canProcessDrag = parseBoolean(attributeValue);
+ else if (attributeName == kAttributePrintUserGestureStatus)
+ m_printUserGestureStatus = parseBoolean(attributeValue);
+ }
+}
+
+TestPlugin::~TestPlugin()
+{
+}
+
+bool TestPlugin::initialize(WebPluginContainer* container)
+{
+ WebGraphicsContext3D::Attributes attrs;
+ m_context = Platform::current()->createOffscreenGraphicsContext3D(attrs);
+ if (!m_context)
+ return false;
+
+ if (!m_context->makeContextCurrent())
+ return false;
+
+ if (!initScene())
+ return false;
+
+ m_layer = WebScopedPtr<WebExternalTextureLayer>(Platform::current()->compositorSupport()->createExternalTextureLayer(this));
+ m_container = container;
+ m_container->setWebLayer(m_layer->layer());
+ if (m_reRequestTouchEvents) {
+ m_container->requestTouchEventType(WebPluginContainer::TouchEventRequestTypeSynthesizedMouse);
+ m_container->requestTouchEventType(WebPluginContainer::TouchEventRequestTypeRaw);
+ }
+ m_container->requestTouchEventType(m_touchEventRequest);
+ m_container->setWantsWheelEvents(true);
+ return true;
+}
+
+void TestPlugin::destroy()
+{
+ if (m_layer.get())
+ m_layer->clearTexture();
+ if (m_container)
+ m_container->setWebLayer(0);
+ m_layer.reset();
+ destroyScene();
+
+ delete m_context;
+ m_context = 0;
+
+ m_container = 0;
+ m_frame = 0;
+
+ Platform::current()->callOnMainThread(deferredDelete, this);
+}
+
+void TestPlugin::updateGeometry(const WebRect& frameRect, const WebRect& clipRect, const WebVector<WebRect>& cutOutsRects, bool isVisible)
+{
+ if (clipRect == m_rect)
+ return;
+ m_rect = clipRect;
+ if (m_rect.isEmpty())
+ return;
+
+ m_context->reshapeWithScaleFactor(m_rect.width, m_rect.height, 1.f);
+ m_context->viewport(0, 0, m_rect.width, m_rect.height);
+
+ m_context->bindTexture(GL_TEXTURE_2D, m_colorTexture);
+ m_context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ m_context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ m_context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ m_context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ m_context->texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_rect.width, m_rect.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
+ m_context->bindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
+ m_context->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorTexture, 0);
+
+ drawScene();
+
+ m_context->genMailboxCHROMIUM(m_mailbox.name);
+ m_context->produceTextureCHROMIUM(GL_TEXTURE_2D, m_mailbox.name);
+
+ m_context->flush();
+ m_layer->layer()->invalidate();
+ m_mailboxChanged = true;
+}
+
+bool TestPlugin::prepareMailbox(blink::WebExternalTextureMailbox* mailbox, blink::WebExternalBitmap*)
+{
+ if (!m_mailboxChanged)
+ return false;
+ *mailbox = m_mailbox;
+ m_mailboxChanged = false;
+ return true;
+}
+
+void TestPlugin::mailboxReleased(const blink::WebExternalTextureMailbox&)
+{
+}
+
+TestPlugin::Primitive TestPlugin::parsePrimitive(const WebString& string)
+{
+ static const WebString kPrimitiveNone = WebString::fromUTF8("none");
+ static const WebString kPrimitiveTriangle = WebString::fromUTF8("triangle");
+
+ Primitive primitive = PrimitiveNone;
+ if (string == kPrimitiveNone)
+ primitive = PrimitiveNone;
+ else if (string == kPrimitiveTriangle)
+ primitive = PrimitiveTriangle;
+ else
+ BLINK_ASSERT_NOT_REACHED();
+ return primitive;
+}
+
+// FIXME: This method should already exist. Use it.
+// For now just parse primary colors.
+void TestPlugin::parseColor(const WebString& string, unsigned color[3])
+{
+ color[0] = color[1] = color[2] = 0;
+ if (string == "black")
+ return;
+
+ if (string == "red")
+ color[0] = 255;
+ else if (string == "green")
+ color[1] = 255;
+ else if (string == "blue")
+ color[2] = 255;
+ else
+ BLINK_ASSERT_NOT_REACHED();
+}
+
+float TestPlugin::parseOpacity(const WebString& string)
+{
+ return static_cast<float>(atof(string.utf8().data()));
+}
+
+bool TestPlugin::parseBoolean(const WebString& string)
+{
+ static const WebString kPrimitiveTrue = WebString::fromUTF8("true");
+ return string == kPrimitiveTrue;
+}
+
+bool TestPlugin::initScene()
+{
+ float color[4];
+ premultiplyAlpha(m_scene.backgroundColor, m_scene.opacity, color);
+
+ m_colorTexture = m_context->createTexture();
+ m_framebuffer = m_context->createFramebuffer();
+
+ m_context->viewport(0, 0, m_rect.width, m_rect.height);
+ m_context->disable(GL_DEPTH_TEST);
+ m_context->disable(GL_SCISSOR_TEST);
+
+ m_context->clearColor(color[0], color[1], color[2], color[3]);
+
+ m_context->enable(GL_BLEND);
+ m_context->blendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+
+ return m_scene.primitive != PrimitiveNone ? initProgram() && initPrimitive() : true;
+}
+
+void TestPlugin::drawScene()
+{
+ m_context->viewport(0, 0, m_rect.width, m_rect.height);
+ m_context->clear(GL_COLOR_BUFFER_BIT);
+
+ if (m_scene.primitive != PrimitiveNone)
+ drawPrimitive();
+}
+
+void TestPlugin::destroyScene()
+{
+ if (m_scene.program) {
+ m_context->deleteProgram(m_scene.program);
+ m_scene.program = 0;
+ }
+ if (m_scene.vbo) {
+ m_context->deleteBuffer(m_scene.vbo);
+ m_scene.vbo = 0;
+ }
+
+ if (m_framebuffer) {
+ m_context->deleteFramebuffer(m_framebuffer);
+ m_framebuffer = 0;
+ }
+
+ if (m_colorTexture) {
+ m_context->deleteTexture(m_colorTexture);
+ m_colorTexture = 0;
+ }
+}
+
+bool TestPlugin::initProgram()
+{
+ const string vertexSource(
+ "attribute vec4 position; \n"
+ "void main() { \n"
+ " gl_Position = position; \n"
+ "} \n"
+ );
+
+ const string fragmentSource(
+ "precision mediump float; \n"
+ "uniform vec4 color; \n"
+ "void main() { \n"
+ " gl_FragColor = color; \n"
+ "} \n"
+ );
+
+ m_scene.program = loadProgram(vertexSource, fragmentSource);
+ if (!m_scene.program)
+ return false;
+
+ m_scene.colorLocation = m_context->getUniformLocation(m_scene.program, "color");
+ m_scene.positionLocation = m_context->getAttribLocation(m_scene.program, "position");
+ return true;
+}
+
+bool TestPlugin::initPrimitive()
+{
+ BLINK_ASSERT(m_scene.primitive == PrimitiveTriangle);
+
+ m_scene.vbo = m_context->createBuffer();
+ if (!m_scene.vbo)
+ return false;
+
+ const float vertices[] = {
+ 0.0f, 0.8f, 0.0f,
+ -0.8f, -0.8f, 0.0f,
+ 0.8f, -0.8f, 0.0f };
+ m_context->bindBuffer(GL_ARRAY_BUFFER, m_scene.vbo);
+ m_context->bufferData(GL_ARRAY_BUFFER, sizeof(vertices), 0, GL_STATIC_DRAW);
+ m_context->bufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
+ return true;
+}
+
+void TestPlugin::drawPrimitive()
+{
+ BLINK_ASSERT(m_scene.primitive == PrimitiveTriangle);
+ BLINK_ASSERT(m_scene.vbo);
+ BLINK_ASSERT(m_scene.program);
+
+ m_context->useProgram(m_scene.program);
+
+ // Bind primitive color.
+ float color[4];
+ premultiplyAlpha(m_scene.primitiveColor, m_scene.opacity, color);
+ m_context->uniform4f(m_scene.colorLocation, color[0], color[1], color[2], color[3]);
+
+ // Bind primitive vertices.
+ m_context->bindBuffer(GL_ARRAY_BUFFER, m_scene.vbo);
+ m_context->enableVertexAttribArray(m_scene.positionLocation);
+ m_context->vertexAttribPointer(m_scene.positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
+ m_context->drawArrays(GL_TRIANGLES, 0, 3);
+}
+
+unsigned TestPlugin::loadShader(unsigned type, const string& source)
+{
+ unsigned shader = m_context->createShader(type);
+ if (shader) {
+ m_context->shaderSource(shader, source.data());
+ m_context->compileShader(shader);
+
+ int compiled = 0;
+ m_context->getShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+ if (!compiled) {
+ m_context->deleteShader(shader);
+ shader = 0;
+ }
+ }
+ return shader;
+}
+
+unsigned TestPlugin::loadProgram(const string& vertexSource, const string& fragmentSource)
+{
+ unsigned vertexShader = loadShader(GL_VERTEX_SHADER, vertexSource);
+ unsigned fragmentShader = loadShader(GL_FRAGMENT_SHADER, fragmentSource);
+ unsigned program = m_context->createProgram();
+ if (vertexShader && fragmentShader && program) {
+ m_context->attachShader(program, vertexShader);
+ m_context->attachShader(program, fragmentShader);
+ m_context->linkProgram(program);
+
+ int linked = 0;
+ m_context->getProgramiv(program, GL_LINK_STATUS, &linked);
+ if (!linked) {
+ m_context->deleteProgram(program);
+ program = 0;
+ }
+ }
+ if (vertexShader)
+ m_context->deleteShader(vertexShader);
+ if (fragmentShader)
+ m_context->deleteShader(fragmentShader);
+
+ return program;
+}
+
+bool TestPlugin::handleInputEvent(const WebInputEvent& event, WebCursorInfo& info)
+{
+ const char* eventName = 0;
+ switch (event.type) {
+ case WebInputEvent::Undefined: eventName = "unknown"; break;
+
+ case WebInputEvent::MouseDown: eventName = "MouseDown"; break;
+ case WebInputEvent::MouseUp: eventName = "MouseUp"; break;
+ case WebInputEvent::MouseMove: eventName = "MouseMove"; break;
+ case WebInputEvent::MouseEnter: eventName = "MouseEnter"; break;
+ case WebInputEvent::MouseLeave: eventName = "MouseLeave"; break;
+ case WebInputEvent::ContextMenu: eventName = "ContextMenu"; break;
+
+ case WebInputEvent::MouseWheel: eventName = "MouseWheel"; break;
+
+ case WebInputEvent::RawKeyDown: eventName = "RawKeyDown"; break;
+ case WebInputEvent::KeyDown: eventName = "KeyDown"; break;
+ case WebInputEvent::KeyUp: eventName = "KeyUp"; break;
+ case WebInputEvent::Char: eventName = "Char"; break;
+
+ case WebInputEvent::GestureScrollBegin: eventName = "GestureScrollBegin"; break;
+ case WebInputEvent::GestureScrollEnd: eventName = "GestureScrollEnd"; break;
+ case WebInputEvent::GestureScrollUpdateWithoutPropagation:
+ case WebInputEvent::GestureScrollUpdate: eventName = "GestureScrollUpdate"; break;
+ case WebInputEvent::GestureFlingStart: eventName = "GestureFlingStart"; break;
+ case WebInputEvent::GestureFlingCancel: eventName = "GestureFlingCancel"; break;
+ case WebInputEvent::GestureTap: eventName = "GestureTap"; break;
+ case WebInputEvent::GestureTapUnconfirmed:
+ eventName = "GestureTapUnconfirmed"; break;
+ case WebInputEvent::GestureTapDown: eventName = "GestureTapDown"; break;
+ case WebInputEvent::GestureShowPress: eventName = "GestureShowPress"; break;
+ case WebInputEvent::GestureTapCancel: eventName = "GestureTapCancel"; break;
+ case WebInputEvent::GestureDoubleTap: eventName = "GestureDoubleTap"; break;
+ case WebInputEvent::GestureTwoFingerTap: eventName = "GestureTwoFingerTap"; break;
+ case WebInputEvent::GestureLongPress: eventName = "GestureLongPress"; break;
+ case WebInputEvent::GestureLongTap: eventName = "GestureLongTap"; break;
+ case WebInputEvent::GesturePinchBegin: eventName = "GesturePinchBegin"; break;
+ case WebInputEvent::GesturePinchEnd: eventName = "GesturePinchEnd"; break;
+ case WebInputEvent::GesturePinchUpdate: eventName = "GesturePinchUpdate"; break;
+
+ case WebInputEvent::TouchStart: eventName = "TouchStart"; break;
+ case WebInputEvent::TouchMove: eventName = "TouchMove"; break;
+ case WebInputEvent::TouchEnd: eventName = "TouchEnd"; break;
+ case WebInputEvent::TouchCancel: eventName = "TouchCancel"; break;
+ }
+
+ m_delegate->printMessage(std::string("Plugin received event: ") + (eventName ? eventName : "unknown") + "\n");
+ if (m_printEventDetails)
+ printEventDetails(m_delegate, event);
+ if (m_printUserGestureStatus)
+ m_delegate->printMessage(std::string("* ") + (WebUserGestureIndicator::isProcessingUserGesture() ? "" : "not ") + "handling user gesture\n");
+ return false;
+}
+
+bool TestPlugin::handleDragStatusUpdate(WebDragStatus dragStatus, const WebDragData&, WebDragOperationsMask, const WebPoint& position, const WebPoint& screenPosition)
+{
+ const char* dragStatusName = 0;
+ switch (dragStatus) {
+ case WebDragStatusEnter:
+ dragStatusName = "DragEnter";
+ break;
+ case WebDragStatusOver:
+ dragStatusName = "DragOver";
+ break;
+ case WebDragStatusLeave:
+ dragStatusName = "DragLeave";
+ break;
+ case WebDragStatusDrop:
+ dragStatusName = "DragDrop";
+ break;
+ case WebDragStatusUnknown:
+ BLINK_ASSERT_NOT_REACHED();
+ }
+ m_delegate->printMessage(std::string("Plugin received event: ") + dragStatusName + "\n");
+ return false;
+}
+
+TestPlugin* TestPlugin::create(WebFrame* frame, const WebPluginParams& params, WebTestDelegate* delegate)
+{
+ return new TestPlugin(frame, params, delegate);
+}
+
+const WebString& TestPlugin::mimeType()
+{
+ static const WebString kMimeType = WebString::fromUTF8("application/x-webkit-test-webplugin");
+ return kMimeType;
+}
+
+}
diff --git a/content/shell/renderer/test_runner/TestPlugin.h b/content/shell/renderer/test_runner/TestPlugin.h
new file mode 100644
index 0000000..73666fd
--- /dev/null
+++ b/content/shell/renderer/test_runner/TestPlugin.h
@@ -0,0 +1,137 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TestPlugin_h
+#define TestPlugin_h
+
+#include <string>
+
+#include "content/shell/renderer/test_runner/WebScopedPtr.h"
+#include "third_party/WebKit/public/platform/WebExternalTextureLayer.h"
+#include "third_party/WebKit/public/platform/WebExternalTextureLayerClient.h"
+#include "third_party/WebKit/public/platform/WebExternalTextureMailbox.h"
+#include "third_party/WebKit/public/platform/WebNonCopyable.h"
+#include "third_party/WebKit/public/web/WebPlugin.h"
+#include "third_party/WebKit/public/web/WebPluginContainer.h"
+
+namespace WebTestRunner {
+
+class WebTestDelegate;
+
+// A fake implemention of blink::WebPlugin for testing purposes.
+//
+// It uses WebGraphicsContext3D to paint a scene consisiting of a primitive
+// over a background. The primitive and background can be customized using
+// the following plugin parameters:
+// primitive: none (default), triangle.
+// background-color: black (default), red, green, blue.
+// primitive-color: black (default), red, green, blue.
+// opacity: [0.0 - 1.0]. Default is 1.0.
+//
+// Whether the plugin accepts touch events or not can be customized using the
+// 'accepts-touch' plugin parameter (defaults to false).
+class TestPlugin : public blink::WebPlugin, public blink::WebExternalTextureLayerClient, public blink::WebNonCopyable {
+public:
+ static TestPlugin* create(blink::WebFrame*, const blink::WebPluginParams&, WebTestDelegate*);
+ virtual ~TestPlugin();
+
+ static const blink::WebString& mimeType();
+
+ // WebPlugin methods:
+ virtual bool initialize(blink::WebPluginContainer*);
+ virtual void destroy();
+ virtual NPObject* scriptableObject() { return 0; }
+ virtual bool canProcessDrag() const { return m_canProcessDrag; }
+ virtual void paint(blink::WebCanvas*, const blink::WebRect&) { }
+ virtual void updateGeometry(const blink::WebRect& frameRect, const blink::WebRect& clipRect, const blink::WebVector<blink::WebRect>& cutOutsRects, bool isVisible);
+ virtual void updateFocus(bool) { }
+ virtual void updateVisibility(bool) { }
+ virtual bool acceptsInputEvents() { return true; }
+ virtual bool handleInputEvent(const blink::WebInputEvent&, blink::WebCursorInfo&);
+ virtual bool handleDragStatusUpdate(blink::WebDragStatus, const blink::WebDragData&, blink::WebDragOperationsMask, const blink::WebPoint& position, const blink::WebPoint& screenPosition);
+ virtual void didReceiveResponse(const blink::WebURLResponse&) { }
+ virtual void didReceiveData(const char* data, int dataLength) { }
+ virtual void didFinishLoading() { }
+ virtual void didFailLoading(const blink::WebURLError&) { }
+ virtual void didFinishLoadingFrameRequest(const blink::WebURL&, void* notifyData) { }
+ virtual void didFailLoadingFrameRequest(const blink::WebURL&, void* notifyData, const blink::WebURLError&) { }
+ virtual bool isPlaceholder() { return false; }
+
+ // WebExternalTextureLayerClient methods:
+ virtual blink::WebGraphicsContext3D* context() { return 0; }
+ virtual bool prepareMailbox(blink::WebExternalTextureMailbox*, blink::WebExternalBitmap*);
+ virtual void mailboxReleased(const blink::WebExternalTextureMailbox&);
+
+private:
+ TestPlugin(blink::WebFrame*, const blink::WebPluginParams&, WebTestDelegate*);
+
+ enum Primitive {
+ PrimitiveNone,
+ PrimitiveTriangle
+ };
+
+ struct Scene {
+ Primitive primitive;
+ unsigned backgroundColor[3];
+ unsigned primitiveColor[3];
+ float opacity;
+
+ unsigned vbo;
+ unsigned program;
+ int colorLocation;
+ int positionLocation;
+
+ Scene()
+ : primitive(PrimitiveNone)
+ , opacity(1.0f) // Fully opaque.
+ , vbo(0)
+ , program(0)
+ , colorLocation(-1)
+ , positionLocation(-1)
+ {
+ backgroundColor[0] = backgroundColor[1] = backgroundColor[2] = 0;
+ primitiveColor[0] = primitiveColor[1] = primitiveColor[2] = 0;
+ }
+ };
+
+ // Functions for parsing plugin parameters.
+ Primitive parsePrimitive(const blink::WebString&);
+ void parseColor(const blink::WebString&, unsigned color[3]);
+ float parseOpacity(const blink::WebString&);
+ bool parseBoolean(const blink::WebString&);
+
+ // Functions for loading and drawing scene.
+ bool initScene();
+ void drawScene();
+ void destroyScene();
+ bool initProgram();
+ bool initPrimitive();
+ void drawPrimitive();
+ unsigned loadShader(unsigned type, const std::string& source);
+ unsigned loadProgram(const std::string& vertexSource, const std::string& fragmentSource);
+
+ blink::WebFrame* m_frame;
+ WebTestDelegate* m_delegate;
+ blink::WebPluginContainer* m_container;
+
+ blink::WebRect m_rect;
+ blink::WebGraphicsContext3D* m_context;
+ unsigned m_colorTexture;
+ blink::WebExternalTextureMailbox m_mailbox;
+ bool m_mailboxChanged;
+ unsigned m_framebuffer;
+ Scene m_scene;
+ WebScopedPtr<blink::WebExternalTextureLayer> m_layer;
+
+ blink::WebPluginContainer::TouchEventRequestType m_touchEventRequest;
+ // Requests touch events from the WebPluginContainerImpl multiple times to tickle webkit.org/b/108381
+ bool m_reRequestTouchEvents;
+ bool m_printEventDetails;
+ bool m_printUserGestureStatus;
+ bool m_canProcessDrag;
+};
+
+}
+
+#endif // TestPlugin_h
diff --git a/content/shell/renderer/test_runner/TestRunner.cpp b/content/shell/renderer/test_runner/TestRunner.cpp
new file mode 100644
index 0000000..030abf5
--- /dev/null
+++ b/content/shell/renderer/test_runner/TestRunner.cpp
@@ -0,0 +1,2132 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2010 Pawel Hajdan (phajdan.jr@chromium.org)
+ * Copyright (C) 2012 Apple Inc. All Rights Reserved.
+ *
+ * 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.
+ */
+
+#include "content/shell/renderer/test_runner/TestRunner.h"
+
+#include <limits>
+
+#include "content/shell/common/test_runner/WebPreferences.h"
+#include "content/shell/renderer/test_runner/MockWebSpeechInputController.h"
+#include "content/shell/renderer/test_runner/MockWebSpeechRecognizer.h"
+#include "content/shell/renderer/test_runner/NotificationPresenter.h"
+#include "content/shell/renderer/test_runner/TestInterfaces.h"
+#include "content/shell/renderer/test_runner/WebPermissions.h"
+#include "content/shell/renderer/test_runner/WebTestDelegate.h"
+#include "content/shell/renderer/test_runner/WebTestProxy.h"
+#include "third_party/WebKit/public/platform/WebData.h"
+#include "third_party/WebKit/public/platform/WebDeviceMotionData.h"
+#include "third_party/WebKit/public/platform/WebDeviceOrientationData.h"
+#include "third_party/WebKit/public/platform/WebPoint.h"
+#include "third_party/WebKit/public/platform/WebURLResponse.h"
+#include "third_party/WebKit/public/web/WebBindings.h"
+#include "third_party/WebKit/public/web/WebDataSource.h"
+#include "third_party/WebKit/public/web/WebDocument.h"
+#include "third_party/WebKit/public/web/WebElement.h"
+#include "third_party/WebKit/public/web/WebFindOptions.h"
+#include "third_party/WebKit/public/web/WebFrame.h"
+#include "third_party/WebKit/public/web/WebGeolocationClientMock.h"
+#include "third_party/WebKit/public/web/WebInputElement.h"
+#include "third_party/WebKit/public/web/WebMIDIClientMock.h"
+#include "third_party/WebKit/public/web/WebScriptSource.h"
+#include "third_party/WebKit/public/web/WebSecurityPolicy.h"
+#include "third_party/WebKit/public/web/WebSerializedScriptValue.h"
+#include "third_party/WebKit/public/web/WebSettings.h"
+#include "third_party/WebKit/public/web/WebSurroundingText.h"
+#include "third_party/WebKit/public/web/WebView.h"
+#include "v8/include/v8.h"
+
+#if defined(__linux__) || defined(ANDROID)
+#include "third_party/WebKit/public/web/linux/WebFontRendering.h"
+#endif
+
+using namespace blink;
+using namespace std;
+
+namespace WebTestRunner {
+
+namespace {
+
+class InvokeCallbackTask : public WebMethodTask<TestRunner> {
+public:
+ InvokeCallbackTask(TestRunner* object, WebScopedPtr<CppVariant> callbackArguments)
+ : WebMethodTask<TestRunner>(object)
+ , m_callbackArguments(callbackArguments)
+ {
+ }
+
+ virtual void runIfValid()
+ {
+ CppVariant invokeResult;
+ m_callbackArguments->invokeDefault(m_callbackArguments.get(), 1, invokeResult);
+ }
+
+private:
+ WebScopedPtr<CppVariant> m_callbackArguments;
+};
+
+}
+
+TestRunner::WorkQueue::~WorkQueue()
+{
+ reset();
+}
+
+void TestRunner::WorkQueue::processWorkSoon()
+{
+ if (m_controller->topLoadingFrame())
+ return;
+
+ if (!m_queue.empty()) {
+ // We delay processing queued work to avoid recursion problems.
+ m_controller->m_delegate->postTask(new WorkQueueTask(this));
+ } else if (!m_controller->m_waitUntilDone)
+ m_controller->m_delegate->testFinished();
+}
+
+void TestRunner::WorkQueue::processWork()
+{
+ // Quit doing work once a load is in progress.
+ while (!m_queue.empty()) {
+ bool startedLoad = m_queue.front()->run(m_controller->m_delegate, m_controller->m_webView);
+ delete m_queue.front();
+ m_queue.pop_front();
+ if (startedLoad)
+ return;
+ }
+
+ if (!m_controller->m_waitUntilDone && !m_controller->topLoadingFrame())
+ m_controller->m_delegate->testFinished();
+}
+
+void TestRunner::WorkQueue::reset()
+{
+ m_frozen = false;
+ while (!m_queue.empty()) {
+ delete m_queue.front();
+ m_queue.pop_front();
+ }
+}
+
+void TestRunner::WorkQueue::addWork(WorkItem* work)
+{
+ if (m_frozen) {
+ delete work;
+ return;
+ }
+ m_queue.push_back(work);
+}
+
+
+TestRunner::TestRunner(TestInterfaces* interfaces)
+ : m_testIsRunning(false)
+ , m_closeRemainingWindows(false)
+ , m_workQueue(this)
+ , m_testInterfaces(interfaces)
+ , m_delegate(0)
+ , m_webView(0)
+ , m_pageOverlay(0)
+ , m_webPermissions(new WebPermissions)
+ , m_notificationPresenter(new NotificationPresenter)
+{
+ // 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 TestRunner).
+
+ // Methods controlling test execution.
+ bindMethod("notifyDone", &TestRunner::notifyDone);
+ bindMethod("queueBackNavigation", &TestRunner::queueBackNavigation);
+ bindMethod("queueForwardNavigation", &TestRunner::queueForwardNavigation);
+ bindMethod("queueLoadingScript", &TestRunner::queueLoadingScript);
+ bindMethod("queueLoad", &TestRunner::queueLoad);
+ bindMethod("queueLoadHTMLString", &TestRunner::queueLoadHTMLString);
+ bindMethod("queueNonLoadingScript", &TestRunner::queueNonLoadingScript);
+ bindMethod("queueReload", &TestRunner::queueReload);
+ bindMethod("setCloseRemainingWindowsWhenComplete", &TestRunner::setCloseRemainingWindowsWhenComplete);
+ bindMethod("resetTestHelperControllers", &TestRunner::resetTestHelperControllers);
+ bindMethod("setCustomPolicyDelegate", &TestRunner::setCustomPolicyDelegate);
+ bindMethod("waitForPolicyDelegate", &TestRunner::waitForPolicyDelegate);
+ bindMethod("waitUntilDone", &TestRunner::waitUntilDone);
+ bindMethod("windowCount", &TestRunner::windowCount);
+ // Methods implemented in terms of chromium's public WebKit API.
+ bindMethod("setTabKeyCyclesThroughElements", &TestRunner::setTabKeyCyclesThroughElements);
+ bindMethod("execCommand", &TestRunner::execCommand);
+ bindMethod("isCommandEnabled", &TestRunner::isCommandEnabled);
+ bindMethod("callShouldCloseOnWebView", &TestRunner::callShouldCloseOnWebView);
+ bindMethod("setDomainRelaxationForbiddenForURLScheme", &TestRunner::setDomainRelaxationForbiddenForURLScheme);
+ bindMethod("evaluateScriptInIsolatedWorldAndReturnValue", &TestRunner::evaluateScriptInIsolatedWorldAndReturnValue);
+ bindMethod("evaluateScriptInIsolatedWorld", &TestRunner::evaluateScriptInIsolatedWorld);
+ bindMethod("setIsolatedWorldSecurityOrigin", &TestRunner::setIsolatedWorldSecurityOrigin);
+ bindMethod("setIsolatedWorldContentSecurityPolicy", &TestRunner::setIsolatedWorldContentSecurityPolicy);
+ bindMethod("addOriginAccessWhitelistEntry", &TestRunner::addOriginAccessWhitelistEntry);
+ bindMethod("removeOriginAccessWhitelistEntry", &TestRunner::removeOriginAccessWhitelistEntry);
+ bindMethod("hasCustomPageSizeStyle", &TestRunner::hasCustomPageSizeStyle);
+ bindMethod("forceRedSelectionColors", &TestRunner::forceRedSelectionColors);
+ bindMethod("injectStyleSheet", &TestRunner::injectStyleSheet);
+ bindMethod("startSpeechInput", &TestRunner::startSpeechInput);
+ bindMethod("findString", &TestRunner::findString);
+ bindMethod("setValueForUser", &TestRunner::setValueForUser);
+ bindMethod("selectionAsMarkup", &TestRunner::selectionAsMarkup);
+ bindMethod("setTextSubpixelPositioning", &TestRunner::setTextSubpixelPositioning);
+ bindMethod("setPageVisibility", &TestRunner::setPageVisibility);
+ bindMethod("setTextDirection", &TestRunner::setTextDirection);
+ bindMethod("textSurroundingNode", &TestRunner::textSurroundingNode);
+ bindMethod("useUnfortunateSynchronousResizeMode", &TestRunner::useUnfortunateSynchronousResizeMode);
+ bindMethod("disableAutoResizeMode", &TestRunner::disableAutoResizeMode);
+ bindMethod("enableAutoResizeMode", &TestRunner::enableAutoResizeMode);
+ bindMethod("setMockDeviceMotion", &TestRunner::setMockDeviceMotion);
+ bindMethod("setMockDeviceOrientation", &TestRunner::setMockDeviceOrientation);
+ bindMethod("didAcquirePointerLock", &TestRunner::didAcquirePointerLock);
+ bindMethod("didLosePointerLock", &TestRunner::didLosePointerLock);
+ bindMethod("didNotAcquirePointerLock", &TestRunner::didNotAcquirePointerLock);
+ bindMethod("setPointerLockWillRespondAsynchronously", &TestRunner::setPointerLockWillRespondAsynchronously);
+ bindMethod("setPointerLockWillFailSynchronously", &TestRunner::setPointerLockWillFailSynchronously);
+
+ // The following modify WebPreferences.
+ bindMethod("setPopupBlockingEnabled", &TestRunner::setPopupBlockingEnabled);
+ bindMethod("setJavaScriptCanAccessClipboard", &TestRunner::setJavaScriptCanAccessClipboard);
+ bindMethod("setXSSAuditorEnabled", &TestRunner::setXSSAuditorEnabled);
+ bindMethod("setAllowUniversalAccessFromFileURLs", &TestRunner::setAllowUniversalAccessFromFileURLs);
+ bindMethod("setAllowFileAccessFromFileURLs", &TestRunner::setAllowFileAccessFromFileURLs);
+ bindMethod("overridePreference", &TestRunner::overridePreference);
+ bindMethod("setPluginsEnabled", &TestRunner::setPluginsEnabled);
+
+ // The following modify the state of the TestRunner.
+ bindMethod("dumpEditingCallbacks", &TestRunner::dumpEditingCallbacks);
+ bindMethod("dumpAsText", &TestRunner::dumpAsText);
+ bindMethod("dumpAsTextWithPixelResults", &TestRunner::dumpAsTextWithPixelResults);
+ bindMethod("dumpChildFramesAsText", &TestRunner::dumpChildFramesAsText);
+ bindMethod("dumpChildFrameScrollPositions", &TestRunner::dumpChildFrameScrollPositions);
+ bindMethod("dumpIconChanges", &TestRunner::dumpIconChanges);
+ bindMethod("setAudioData", &TestRunner::setAudioData);
+ bindMethod("dumpFrameLoadCallbacks", &TestRunner::dumpFrameLoadCallbacks);
+ bindMethod("dumpPingLoaderCallbacks", &TestRunner::dumpPingLoaderCallbacks);
+ bindMethod("dumpUserGestureInFrameLoadCallbacks", &TestRunner::dumpUserGestureInFrameLoadCallbacks);
+ bindMethod("dumpTitleChanges", &TestRunner::dumpTitleChanges);
+ bindMethod("dumpCreateView", &TestRunner::dumpCreateView);
+ bindMethod("setCanOpenWindows", &TestRunner::setCanOpenWindows);
+ bindMethod("dumpResourceLoadCallbacks", &TestRunner::dumpResourceLoadCallbacks);
+ bindMethod("dumpResourceRequestCallbacks", &TestRunner::dumpResourceRequestCallbacks);
+ bindMethod("dumpResourceResponseMIMETypes", &TestRunner::dumpResourceResponseMIMETypes);
+ bindMethod("dumpPermissionClientCallbacks", &TestRunner::dumpPermissionClientCallbacks);
+ bindMethod("setImagesAllowed", &TestRunner::setImagesAllowed);
+ bindMethod("setScriptsAllowed", &TestRunner::setScriptsAllowed);
+ bindMethod("setStorageAllowed", &TestRunner::setStorageAllowed);
+ bindMethod("setPluginsAllowed", &TestRunner::setPluginsAllowed);
+ bindMethod("setAllowDisplayOfInsecureContent", &TestRunner::setAllowDisplayOfInsecureContent);
+ bindMethod("setAllowRunningOfInsecureContent", &TestRunner::setAllowRunningOfInsecureContent);
+ bindMethod("dumpStatusCallbacks", &TestRunner::dumpWindowStatusChanges);
+ bindMethod("dumpProgressFinishedCallback", &TestRunner::dumpProgressFinishedCallback);
+ bindMethod("dumpSpellCheckCallbacks", &TestRunner::dumpSpellCheckCallbacks);
+ bindMethod("dumpBackForwardList", &TestRunner::dumpBackForwardList);
+ bindMethod("dumpSelectionRect", &TestRunner::dumpSelectionRect);
+ bindMethod("testRepaint", &TestRunner::testRepaint);
+ bindMethod("repaintSweepHorizontally", &TestRunner::repaintSweepHorizontally);
+ bindMethod("setPrinting", &TestRunner::setPrinting);
+ bindMethod("setShouldStayOnPageAfterHandlingBeforeUnload", &TestRunner::setShouldStayOnPageAfterHandlingBeforeUnload);
+ bindMethod("setWillSendRequestClearHeader", &TestRunner::setWillSendRequestClearHeader);
+ bindMethod("dumpResourceRequestPriorities", &TestRunner::dumpResourceRequestPriorities);
+
+ // The following methods interact with the WebTestProxy.
+ // The following methods interact with the WebTestDelegate.
+ bindMethod("showWebInspector", &TestRunner::showWebInspector);
+ bindMethod("closeWebInspector", &TestRunner::closeWebInspector);
+ bindMethod("evaluateInWebInspector", &TestRunner::evaluateInWebInspector);
+ bindMethod("clearAllDatabases", &TestRunner::clearAllDatabases);
+ bindMethod("setDatabaseQuota", &TestRunner::setDatabaseQuota);
+ bindMethod("setAlwaysAcceptCookies", &TestRunner::setAlwaysAcceptCookies);
+ bindMethod("setWindowIsKey", &TestRunner::setWindowIsKey);
+ bindMethod("pathToLocalResource", &TestRunner::pathToLocalResource);
+ bindMethod("setBackingScaleFactor", &TestRunner::setBackingScaleFactor);
+ bindMethod("setPOSIXLocale", &TestRunner::setPOSIXLocale);
+ bindMethod("numberOfPendingGeolocationPermissionRequests", &TestRunner:: numberOfPendingGeolocationPermissionRequests);
+ bindMethod("setGeolocationPermission", &TestRunner::setGeolocationPermission);
+ bindMethod("setMockGeolocationPositionUnavailableError", &TestRunner::setMockGeolocationPositionUnavailableError);
+ bindMethod("setMockGeolocationPosition", &TestRunner::setMockGeolocationPosition);
+ bindMethod("setMIDIAccessorResult", &TestRunner::setMIDIAccessorResult);
+ bindMethod("setMIDISysExPermission", &TestRunner::setMIDISysExPermission);
+ bindMethod("grantWebNotificationPermission", &TestRunner::grantWebNotificationPermission);
+ bindMethod("simulateLegacyWebNotificationClick", &TestRunner::simulateLegacyWebNotificationClick);
+ bindMethod("cancelAllActiveNotifications", &TestRunner::cancelAllActiveNotifications);
+ bindMethod("addMockSpeechInputResult", &TestRunner::addMockSpeechInputResult);
+ bindMethod("setMockSpeechInputDumpRect", &TestRunner::setMockSpeechInputDumpRect);
+ bindMethod("addMockSpeechRecognitionResult", &TestRunner::addMockSpeechRecognitionResult);
+ bindMethod("setMockSpeechRecognitionError", &TestRunner::setMockSpeechRecognitionError);
+ bindMethod("wasMockSpeechRecognitionAborted", &TestRunner::wasMockSpeechRecognitionAborted);
+ bindMethod("display", &TestRunner::display);
+ bindMethod("displayInvalidatedRegion", &TestRunner::displayInvalidatedRegion);
+ bindMethod("isChooserShown", &TestRunner::isChooserShown);
+
+ // The following modify WebPageOverlays.
+ bindMethod("addWebPageOverlay", &TestRunner::addWebPageOverlay);
+ bindMethod("removeWebPageOverlay", &TestRunner::removeWebPageOverlay);
+
+ // Properties.
+ bindProperty("globalFlag", &m_globalFlag);
+ bindProperty("platformName", &m_platformName);
+ bindProperty("tooltipText", &m_tooltipText);
+ bindProperty("disableNotifyDone", &m_disableNotifyDone);
+
+ // webHistoryItemCount is used by tests in LayoutTests\http\tests\history
+ bindProperty("webHistoryItemCount", &m_webHistoryItemCount);
+ bindProperty("interceptPostMessage", &m_interceptPostMessage);
+
+ // The following are stubs.
+ bindMethod("dumpDatabaseCallbacks", &TestRunner::notImplemented);
+ bindMethod("denyWebNotificationPermission", &TestRunner::notImplemented);
+ bindMethod("removeAllWebNotificationPermissions", &TestRunner::notImplemented);
+ bindMethod("simulateWebNotificationClick", &TestRunner::notImplemented);
+ bindMethod("setIconDatabaseEnabled", &TestRunner::notImplemented);
+ bindMethod("setScrollbarPolicy", &TestRunner::notImplemented);
+ bindMethod("clearAllApplicationCaches", &TestRunner::notImplemented);
+ bindMethod("clearApplicationCacheForOrigin", &TestRunner::notImplemented);
+ bindMethod("clearBackForwardList", &TestRunner::notImplemented);
+ bindMethod("keepWebHistory", &TestRunner::notImplemented);
+ bindMethod("setApplicationCacheOriginQuota", &TestRunner::notImplemented);
+ bindMethod("setCallCloseOnWebViews", &TestRunner::notImplemented);
+ bindMethod("setMainFrameIsFirstResponder", &TestRunner::notImplemented);
+ bindMethod("setUseDashboardCompatibilityMode", &TestRunner::notImplemented);
+ bindMethod("deleteAllLocalStorage", &TestRunner::notImplemented);
+ bindMethod("localStorageDiskUsageForOrigin", &TestRunner::notImplemented);
+ bindMethod("originsWithLocalStorage", &TestRunner::notImplemented);
+ bindMethod("deleteLocalStorageForOrigin", &TestRunner::notImplemented);
+ bindMethod("observeStorageTrackerNotifications", &TestRunner::notImplemented);
+ bindMethod("syncLocalStorage", &TestRunner::notImplemented);
+ bindMethod("addDisallowedURL", &TestRunner::notImplemented);
+ bindMethod("applicationCacheDiskUsageForOrigin", &TestRunner::notImplemented);
+ bindMethod("abortModal", &TestRunner::notImplemented);
+
+ // The fallback method is called when an unknown method is invoked.
+ bindFallbackMethod(&TestRunner::fallbackMethod);
+}
+
+TestRunner::~TestRunner()
+{
+}
+
+void TestRunner::setDelegate(WebTestDelegate* delegate)
+{
+ m_delegate = delegate;
+ m_webPermissions->setDelegate(delegate);
+ m_notificationPresenter->setDelegate(delegate);
+}
+
+void TestRunner::setWebView(WebView* webView, WebTestProxyBase* proxy)
+{
+ m_webView = webView;
+ m_proxy = proxy;
+}
+
+void TestRunner::reset()
+{
+ if (m_webView) {
+ m_webView->setZoomLevel(0);
+ m_webView->setTextZoomFactor(1);
+ m_webView->setTabKeyCyclesThroughElements(true);
+#if !defined(__APPLE__) && !defined(WIN32) // Actually, TOOLKIT_GTK
+ // (Constants copied because we can't depend on the header that defined
+ // them from this file.)
+ m_webView->setSelectionColors(0xff1e90ff, 0xff000000, 0xffc8c8c8, 0xff323232);
+#endif
+ m_webView->removeInjectedStyleSheets();
+ m_webView->setVisibilityState(WebPageVisibilityStateVisible, true);
+ m_webView->mainFrame()->enableViewSourceMode(false);
+
+ if (m_pageOverlay) {
+ m_webView->removePageOverlay(m_pageOverlay);
+ delete m_pageOverlay;
+ m_pageOverlay = 0;
+ }
+ }
+
+ m_topLoadingFrame = 0;
+ m_waitUntilDone = false;
+ m_policyDelegateEnabled = false;
+ m_policyDelegateIsPermissive = false;
+ m_policyDelegateShouldNotifyDone = false;
+
+ WebSecurityPolicy::resetOriginAccessWhitelists();
+#if defined(__linux__) || defined(ANDROID)
+ WebFontRendering::setSubpixelPositioning(false);
+#endif
+
+ if (m_delegate) {
+ // Reset the default quota for each origin to 5MB
+ m_delegate->setDatabaseQuota(5 * 1024 * 1024);
+ m_delegate->setDeviceScaleFactor(1);
+ m_delegate->setAcceptAllCookies(false);
+ m_delegate->setLocale("");
+ m_delegate->useUnfortunateSynchronousResizeMode(false);
+ m_delegate->disableAutoResizeMode(WebSize());
+ m_delegate->deleteAllCookies();
+ }
+
+ m_dumpEditingCallbacks = false;
+ m_dumpAsText = false;
+ m_dumpAsMarkup = false;
+ m_generatePixelResults = true;
+ m_dumpChildFrameScrollPositions = false;
+ m_dumpChildFramesAsText = false;
+ m_dumpIconChanges = false;
+ m_dumpAsAudio = false;
+ m_dumpFrameLoadCallbacks = false;
+ m_dumpPingLoaderCallbacks = false;
+ m_dumpUserGestureInFrameLoadCallbacks = false;
+ m_dumpTitleChanges = false;
+ m_dumpCreateView = false;
+ m_canOpenWindows = false;
+ m_dumpResourceLoadCallbacks = false;
+ m_dumpResourceRequestCallbacks = false;
+ m_dumpResourceResponseMIMETypes = false;
+ m_dumpWindowStatusChanges = false;
+ m_dumpProgressFinishedCallback = false;
+ m_dumpSpellCheckCallbacks = false;
+ m_dumpBackForwardList = false;
+ m_dumpSelectionRect = false;
+ m_testRepaint = false;
+ m_sweepHorizontally = false;
+ m_isPrinting = false;
+ m_midiAccessorResult = true;
+ m_shouldStayOnPageAfterHandlingBeforeUnload = false;
+ m_shouldDumpResourcePriorities = false;
+
+ m_httpHeadersToClear.clear();
+
+ m_globalFlag.set(false);
+ m_webHistoryItemCount.set(0);
+ m_interceptPostMessage.set(false);
+ m_platformName.set("chromium");
+ m_tooltipText.set("");
+ m_disableNotifyDone.set(false);
+
+ m_webPermissions->reset();
+
+ m_notificationPresenter->reset();
+
+ m_pointerLocked = false;
+ m_pointerLockPlannedResult = PointerLockWillSucceed;
+
+ m_taskList.revokeAll();
+ m_workQueue.reset();
+
+ if (m_closeRemainingWindows && m_delegate)
+ m_delegate->closeRemainingWindows();
+ else
+ m_closeRemainingWindows = true;
+}
+
+
+void TestRunner::setTestIsRunning(bool running)
+{
+ m_testIsRunning = running;
+}
+
+bool TestRunner::shouldDumpEditingCallbacks() const
+{
+ return m_dumpEditingCallbacks;
+}
+
+void TestRunner::checkResponseMimeType()
+{
+ // Text output: the test page can request different types of output
+ // which we handle here.
+ if (!m_dumpAsText) {
+ string mimeType = m_webView->mainFrame()->dataSource()->response().mimeType().utf8();
+ if (mimeType == "text/plain") {
+ m_dumpAsText = true;
+ m_generatePixelResults = false;
+ }
+ }
+}
+
+bool TestRunner::shouldDumpAsText()
+{
+ checkResponseMimeType();
+ return m_dumpAsText;
+}
+
+void TestRunner::setShouldDumpAsText(bool value)
+{
+ m_dumpAsText = value;
+}
+
+bool TestRunner::shouldDumpAsMarkup()
+{
+ return m_dumpAsMarkup;
+}
+
+void TestRunner::setShouldDumpAsMarkup(bool value)
+{
+ m_dumpAsMarkup = value;
+}
+
+bool TestRunner::shouldGeneratePixelResults()
+{
+ checkResponseMimeType();
+ return m_generatePixelResults;
+}
+
+void TestRunner::setShouldGeneratePixelResults(bool value)
+{
+ m_generatePixelResults = value;
+}
+
+bool TestRunner::shouldDumpChildFrameScrollPositions() const
+{
+ return m_dumpChildFrameScrollPositions;
+}
+
+bool TestRunner::shouldDumpChildFramesAsText() const
+{
+ return m_dumpChildFramesAsText;
+}
+
+bool TestRunner::shouldDumpAsAudio() const
+{
+ return m_dumpAsAudio;
+}
+
+const WebArrayBufferView* TestRunner::audioData() const
+{
+ return &m_audioData;
+}
+
+bool TestRunner::shouldDumpFrameLoadCallbacks() const
+{
+ return m_testIsRunning && m_dumpFrameLoadCallbacks;
+}
+
+void TestRunner::setShouldDumpFrameLoadCallbacks(bool value)
+{
+ m_dumpFrameLoadCallbacks = value;
+}
+
+bool TestRunner::shouldDumpPingLoaderCallbacks() const
+{
+ return m_testIsRunning && m_dumpPingLoaderCallbacks;
+}
+
+void TestRunner::setShouldDumpPingLoaderCallbacks(bool value)
+{
+ m_dumpPingLoaderCallbacks = value;
+}
+
+void TestRunner::setShouldEnableViewSource(bool value)
+{
+ m_webView->mainFrame()->enableViewSourceMode(value);
+}
+
+bool TestRunner::shouldDumpUserGestureInFrameLoadCallbacks() const
+{
+ return m_testIsRunning && m_dumpUserGestureInFrameLoadCallbacks;
+}
+
+bool TestRunner::shouldDumpTitleChanges() const
+{
+ return m_dumpTitleChanges;
+}
+
+bool TestRunner::shouldDumpIconChanges() const
+{
+ return m_dumpIconChanges;
+}
+
+bool TestRunner::shouldDumpCreateView() const
+{
+ return m_dumpCreateView;
+}
+
+bool TestRunner::canOpenWindows() const
+{
+ return m_canOpenWindows;
+}
+
+bool TestRunner::shouldDumpResourceLoadCallbacks() const
+{
+ return m_testIsRunning && m_dumpResourceLoadCallbacks;
+}
+
+bool TestRunner::shouldDumpResourceRequestCallbacks() const
+{
+ return m_testIsRunning && m_dumpResourceRequestCallbacks;
+}
+
+bool TestRunner::shouldDumpResourceResponseMIMETypes() const
+{
+ return m_testIsRunning && m_dumpResourceResponseMIMETypes;
+}
+
+WebPermissionClient* TestRunner::webPermissions() const
+{
+ return m_webPermissions.get();
+}
+
+bool TestRunner::shouldDumpStatusCallbacks() const
+{
+ return m_dumpWindowStatusChanges;
+}
+
+bool TestRunner::shouldDumpProgressFinishedCallback() const
+{
+ return m_dumpProgressFinishedCallback;
+}
+
+bool TestRunner::shouldDumpSpellCheckCallbacks() const
+{
+ return m_dumpSpellCheckCallbacks;
+}
+
+bool TestRunner::shouldDumpBackForwardList() const
+{
+ return m_dumpBackForwardList;
+}
+
+bool TestRunner::shouldDumpSelectionRect() const
+{
+ return m_dumpSelectionRect;
+}
+
+bool TestRunner::testRepaint() const
+{
+ return m_testRepaint;
+}
+
+bool TestRunner::sweepHorizontally() const
+{
+ return m_sweepHorizontally;
+}
+
+bool TestRunner::isPrinting() const
+{
+ return m_isPrinting;
+}
+
+bool TestRunner::shouldStayOnPageAfterHandlingBeforeUnload() const
+{
+ return m_shouldStayOnPageAfterHandlingBeforeUnload;
+}
+
+const std::set<std::string>* TestRunner::httpHeadersToClear() const
+{
+ return &m_httpHeadersToClear;
+}
+
+void TestRunner::setTopLoadingFrame(WebFrame* frame, bool clear)
+{
+ if (frame->top()->view() != m_webView)
+ return;
+ if (!m_testIsRunning)
+ return;
+ if (clear) {
+ m_topLoadingFrame = 0;
+ locationChangeDone();
+ } else if (!m_topLoadingFrame)
+ m_topLoadingFrame = frame;
+}
+
+WebFrame* TestRunner::topLoadingFrame() const
+{
+ return m_topLoadingFrame;
+}
+
+void TestRunner::policyDelegateDone()
+{
+ BLINK_ASSERT(m_waitUntilDone);
+ m_delegate->testFinished();
+ m_waitUntilDone = false;
+}
+
+bool TestRunner::policyDelegateEnabled() const
+{
+ return m_policyDelegateEnabled;
+}
+
+bool TestRunner::policyDelegateIsPermissive() const
+{
+ return m_policyDelegateIsPermissive;
+}
+
+bool TestRunner::policyDelegateShouldNotifyDone() const
+{
+ return m_policyDelegateShouldNotifyDone;
+}
+
+bool TestRunner::shouldInterceptPostMessage() const
+{
+ return m_interceptPostMessage.isBool() && m_interceptPostMessage.toBoolean();
+}
+
+bool TestRunner::shouldDumpResourcePriorities() const
+{
+ return m_shouldDumpResourcePriorities;
+}
+
+WebNotificationPresenter* TestRunner::notificationPresenter() const
+{
+ return m_notificationPresenter.get();
+}
+
+bool TestRunner::requestPointerLock()
+{
+ switch (m_pointerLockPlannedResult) {
+ case PointerLockWillSucceed:
+ m_delegate->postDelayedTask(new HostMethodTask(this, &TestRunner::didAcquirePointerLockInternal), 0);
+ return true;
+ case PointerLockWillRespondAsync:
+ BLINK_ASSERT(!m_pointerLocked);
+ return true;
+ case PointerLockWillFailSync:
+ BLINK_ASSERT(!m_pointerLocked);
+ return false;
+ default:
+ BLINK_ASSERT_NOT_REACHED();
+ return false;
+ }
+}
+
+void TestRunner::requestPointerUnlock()
+{
+ m_delegate->postDelayedTask(new HostMethodTask(this, &TestRunner::didLosePointerLockInternal), 0);
+}
+
+bool TestRunner::isPointerLocked()
+{
+ return m_pointerLocked;
+}
+
+void TestRunner::setToolTipText(const blink::WebString& text)
+{
+ m_tooltipText.set(text.utf8());
+}
+
+bool TestRunner::midiAccessorResult()
+{
+ return m_midiAccessorResult;
+}
+
+TestRunner::TestPageOverlay::TestPageOverlay(blink::WebView* webView) : m_webView(webView)
+{
+}
+
+TestRunner::TestPageOverlay::~TestPageOverlay()
+{
+}
+
+void TestRunner::TestPageOverlay::paintPageOverlay(blink::WebCanvas* canvas)
+{
+ SkRect rect = SkRect::MakeWH(m_webView->size().width, m_webView->size().height);
+ SkPaint paint;
+ paint.setColor(SK_ColorCYAN);
+ paint.setStyle(SkPaint::kFill_Style);
+ canvas->drawRect(rect, paint);
+}
+
+void TestRunner::didAcquirePointerLockInternal()
+{
+ m_pointerLocked = true;
+ m_webView->didAcquirePointerLock();
+
+ // Reset planned result to default.
+ m_pointerLockPlannedResult = PointerLockWillSucceed;
+}
+
+void TestRunner::didNotAcquirePointerLockInternal()
+{
+ BLINK_ASSERT(!m_pointerLocked);
+ m_pointerLocked = false;
+ m_webView->didNotAcquirePointerLock();
+
+ // Reset planned result to default.
+ m_pointerLockPlannedResult = PointerLockWillSucceed;
+}
+
+void TestRunner::didLosePointerLockInternal()
+{
+ bool wasLocked = m_pointerLocked;
+ m_pointerLocked = false;
+ if (wasLocked)
+ m_webView->didLosePointerLock();
+}
+
+void TestRunner::showDevTools()
+{
+ m_delegate->showDevTools();
+}
+
+void TestRunner::waitUntilDone(const CppArgumentList&, CppVariant* result)
+{
+ m_waitUntilDone = true;
+ result->setNull();
+}
+
+void TestRunner::notifyDone(const CppArgumentList&, CppVariant* result)
+{
+ if (m_disableNotifyDone.toBoolean())
+ return;
+
+ // Test didn't timeout. Kill the timeout timer.
+ taskList()->revokeAll();
+
+ completeNotifyDone();
+ result->setNull();
+}
+
+void TestRunner::completeNotifyDone()
+{
+ if (m_waitUntilDone && !topLoadingFrame() && m_workQueue.isEmpty())
+ m_delegate->testFinished();
+ m_waitUntilDone = false;
+}
+
+class WorkItemBackForward : public TestRunner::WorkItem {
+public:
+ WorkItemBackForward(int distance) : m_distance(distance) { }
+ bool run(WebTestDelegate* delegate, WebView*)
+ {
+ delegate->goToOffset(m_distance);
+ return true; // FIXME: Did it really start a navigation?
+ }
+
+private:
+ int m_distance;
+};
+
+void TestRunner::queueBackNavigation(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isNumber())
+ m_workQueue.addWork(new WorkItemBackForward(-arguments[0].toInt32()));
+ result->setNull();
+}
+
+void TestRunner::queueForwardNavigation(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isNumber())
+ m_workQueue.addWork(new WorkItemBackForward(arguments[0].toInt32()));
+ result->setNull();
+}
+
+class WorkItemReload : public TestRunner::WorkItem {
+public:
+ bool run(WebTestDelegate* delegate, WebView*)
+ {
+ delegate->reload();
+ return true;
+ }
+};
+
+void TestRunner::queueReload(const CppArgumentList&, CppVariant* result)
+{
+ m_workQueue.addWork(new WorkItemReload);
+ result->setNull();
+}
+
+class WorkItemLoadingScript : public TestRunner::WorkItem {
+public:
+ WorkItemLoadingScript(const string& script) : m_script(script) { }
+ bool run(WebTestDelegate*, WebView* webView)
+ {
+ webView->mainFrame()->executeScript(WebScriptSource(WebString::fromUTF8(m_script)));
+ return true; // FIXME: Did it really start a navigation?
+ }
+
+private:
+ string m_script;
+};
+
+class WorkItemNonLoadingScript : public TestRunner::WorkItem {
+public:
+ WorkItemNonLoadingScript(const string& script) : m_script(script) { }
+ bool run(WebTestDelegate*, WebView* webView)
+ {
+ webView->mainFrame()->executeScript(WebScriptSource(WebString::fromUTF8(m_script)));
+ return false;
+ }
+
+private:
+ string m_script;
+};
+
+void TestRunner::queueLoadingScript(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isString())
+ m_workQueue.addWork(new WorkItemLoadingScript(arguments[0].toString()));
+ result->setNull();
+}
+
+void TestRunner::queueNonLoadingScript(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isString())
+ m_workQueue.addWork(new WorkItemNonLoadingScript(arguments[0].toString()));
+ result->setNull();
+}
+
+class WorkItemLoad : public TestRunner::WorkItem {
+public:
+ WorkItemLoad(const WebURL& url, const string& target)
+ : m_url(url)
+ , m_target(target) { }
+ bool run(WebTestDelegate* delegate, WebView*)
+ {
+ delegate->loadURLForFrame(m_url, m_target);
+ return true; // FIXME: Did it really start a navigation?
+ }
+
+private:
+ WebURL m_url;
+ string m_target;
+};
+
+void TestRunner::queueLoad(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isString()) {
+ // FIXME: Implement WebURL::resolve() and avoid GURL.
+ GURL currentURL = m_webView->mainFrame()->document().url();
+ GURL fullURL = currentURL.Resolve(arguments[0].toString());
+
+ string target = "";
+ if (arguments.size() > 1 && arguments[1].isString())
+ target = arguments[1].toString();
+
+ m_workQueue.addWork(new WorkItemLoad(fullURL, target));
+ }
+ result->setNull();
+}
+
+class WorkItemLoadHTMLString : public TestRunner::WorkItem {
+public:
+ WorkItemLoadHTMLString(const std::string& html, const WebURL& baseURL)
+ : m_html(html)
+ , m_baseURL(baseURL) { }
+ WorkItemLoadHTMLString(const std::string& html, const WebURL& baseURL, const WebURL& unreachableURL)
+ : m_html(html)
+ , m_baseURL(baseURL)
+ , m_unreachableURL(unreachableURL) { }
+ bool run(WebTestDelegate*, WebView* webView)
+ {
+ webView->mainFrame()->loadHTMLString(
+ blink::WebData(m_html.data(), m_html.length()), m_baseURL, m_unreachableURL);
+ return true;
+ }
+
+private:
+ std::string m_html;
+ WebURL m_baseURL;
+ WebURL m_unreachableURL;
+};
+
+void TestRunner::queueLoadHTMLString(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isString()) {
+ string html = arguments[0].toString();
+ WebURL baseURL(GURL(""));
+ if (arguments.size() > 1 && arguments[1].isString())
+ baseURL = WebURL(GURL(arguments[1].toString()));
+ if (arguments.size() > 2 && arguments[2].isString())
+ m_workQueue.addWork(new WorkItemLoadHTMLString(html, baseURL, WebURL(GURL(arguments[2].toString()))));
+ else
+ m_workQueue.addWork(new WorkItemLoadHTMLString(html, baseURL));
+ }
+ result->setNull();
+}
+
+void TestRunner::locationChangeDone()
+{
+ m_webHistoryItemCount.set(m_delegate->navigationEntryCount());
+
+ // No more new work after the first complete load.
+ m_workQueue.setFrozen(true);
+
+ if (!m_waitUntilDone)
+ m_workQueue.processWorkSoon();
+}
+
+void TestRunner::windowCount(const CppArgumentList&, CppVariant* result)
+{
+ result->set(static_cast<int>(m_testInterfaces->windowList().size()));
+}
+
+void TestRunner::setCloseRemainingWindowsWhenComplete(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_closeRemainingWindows = arguments[0].value.boolValue;
+ result->setNull();
+}
+
+void TestRunner::resetTestHelperControllers(const CppArgumentList& arguments, CppVariant* result)
+{
+ m_testInterfaces->resetTestHelperControllers();
+
+ result->setNull();
+}
+
+void TestRunner::setCustomPolicyDelegate(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool()) {
+ m_policyDelegateEnabled = arguments[0].value.boolValue;
+ m_policyDelegateIsPermissive = false;
+ if (arguments.size() > 1 && arguments[1].isBool())
+ m_policyDelegateIsPermissive = arguments[1].value.boolValue;
+ }
+ result->setNull();
+}
+
+void TestRunner::waitForPolicyDelegate(const CppArgumentList&, CppVariant* result)
+{
+ m_policyDelegateEnabled = true;
+ m_policyDelegateShouldNotifyDone = true;
+ m_waitUntilDone = true;
+ result->setNull();
+}
+
+void TestRunner::dumpPermissionClientCallbacks(const CppArgumentList&, CppVariant* result)
+{
+ m_webPermissions->setDumpCallbacks(true);
+ result->setNull();
+}
+
+void TestRunner::setImagesAllowed(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_webPermissions->setImagesAllowed(arguments[0].toBoolean());
+ result->setNull();
+}
+
+void TestRunner::setScriptsAllowed(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_webPermissions->setScriptsAllowed(arguments[0].toBoolean());
+ result->setNull();
+}
+
+void TestRunner::setStorageAllowed(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_webPermissions->setStorageAllowed(arguments[0].toBoolean());
+ result->setNull();
+}
+
+void TestRunner::setPluginsAllowed(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_webPermissions->setPluginsAllowed(arguments[0].toBoolean());
+ result->setNull();
+}
+
+void TestRunner::setAllowDisplayOfInsecureContent(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_webPermissions->setDisplayingInsecureContentAllowed(arguments[0].toBoolean());
+
+ result->setNull();
+}
+
+void TestRunner::setAllowRunningOfInsecureContent(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_webPermissions->setRunningInsecureContentAllowed(arguments[0].value.boolValue);
+
+ result->setNull();
+}
+
+void TestRunner::dumpWindowStatusChanges(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpWindowStatusChanges = true;
+ result->setNull();
+}
+
+void TestRunner::dumpProgressFinishedCallback(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpProgressFinishedCallback = true;
+ result->setNull();
+}
+
+void TestRunner::dumpSpellCheckCallbacks(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpSpellCheckCallbacks = true;
+ result->setNull();
+}
+
+void TestRunner::dumpBackForwardList(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpBackForwardList = true;
+ result->setNull();
+}
+
+void TestRunner::dumpSelectionRect(const CppArgumentList& arguments, CppVariant* result)
+{
+ m_dumpSelectionRect = true;
+ result->setNull();
+}
+
+void TestRunner::testRepaint(const CppArgumentList&, CppVariant* result)
+{
+ m_testRepaint = true;
+ result->setNull();
+}
+
+void TestRunner::repaintSweepHorizontally(const CppArgumentList&, CppVariant* result)
+{
+ m_sweepHorizontally = true;
+ result->setNull();
+}
+
+void TestRunner::setPrinting(const CppArgumentList& arguments, CppVariant* result)
+{
+ m_isPrinting = true;
+ result->setNull();
+}
+
+void TestRunner::setShouldStayOnPageAfterHandlingBeforeUnload(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() == 1 && arguments[0].isBool())
+ m_shouldStayOnPageAfterHandlingBeforeUnload = arguments[0].toBoolean();
+
+ result->setNull();
+}
+
+void TestRunner::setWillSendRequestClearHeader(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isString()) {
+ string header = arguments[0].toString();
+ if (!header.empty())
+ m_httpHeadersToClear.insert(header);
+ }
+ result->setNull();
+}
+
+void TestRunner::setTabKeyCyclesThroughElements(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_webView->setTabKeyCyclesThroughElements(arguments[0].toBoolean());
+ result->setNull();
+}
+
+void TestRunner::execCommand(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() <= 0 || !arguments[0].isString())
+ return;
+
+ std::string command = arguments[0].toString();
+ std::string value("");
+ // Ignore the second parameter (which is userInterface)
+ // since this command emulates a manual action.
+ if (arguments.size() >= 3 && arguments[2].isString())
+ value = arguments[2].toString();
+
+ // Note: webkit's version does not return the boolean, so neither do we.
+ m_webView->focusedFrame()->executeCommand(WebString::fromUTF8(command), WebString::fromUTF8(value));
+}
+
+void TestRunner::isCommandEnabled(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() <= 0 || !arguments[0].isString()) {
+ result->setNull();
+ return;
+ }
+
+ std::string command = arguments[0].toString();
+ bool rv = m_webView->focusedFrame()->isCommandEnabled(WebString::fromUTF8(command));
+ result->set(rv);
+}
+
+void TestRunner::callShouldCloseOnWebView(const CppArgumentList&, CppVariant* result)
+{
+ result->set(m_webView->dispatchBeforeUnloadEvent());
+}
+
+void TestRunner::setDomainRelaxationForbiddenForURLScheme(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() != 2 || !arguments[0].isBool() || !arguments[1].isString())
+ return;
+ m_webView->setDomainRelaxationForbidden(cppVariantToBool(arguments[0]), cppVariantToWebString(arguments[1]));
+}
+
+void TestRunner::evaluateScriptInIsolatedWorldAndReturnValue(const CppArgumentList& arguments, CppVariant* result)
+{
+ v8::HandleScope scope(v8::Isolate::GetCurrent());
+ WebVector<v8::Local<v8::Value> > values;
+ if (arguments.size() >= 2 && arguments[0].isNumber() && arguments[1].isString()) {
+ WebScriptSource source(cppVariantToWebString(arguments[1]));
+ // This relies on the iframe focusing itself when it loads. This is a bit
+ // sketchy, but it seems to be what other tests do.
+ m_webView->focusedFrame()->executeScriptInIsolatedWorld(arguments[0].toInt32(), &source, 1, 1, &values);
+ }
+ result->setNull();
+ // Since only one script was added, only one result is expected
+ if (values.size() == 1 && !values[0].IsEmpty()) {
+ v8::Local<v8::Value> scriptValue = values[0];
+ // FIXME: There are many more types that can be handled.
+ if (scriptValue->IsString()) {
+ v8::String::Utf8Value utf8V8(scriptValue);
+ result->set(std::string(*utf8V8));
+ } else if (scriptValue->IsBoolean())
+ result->set(scriptValue->ToBoolean()->Value());
+ else if (scriptValue->IsNumber()) {
+ if (scriptValue->IsInt32())
+ result->set(scriptValue->ToInt32()->Value());
+ else
+ result->set(scriptValue->ToNumber()->Value());
+ } else if (scriptValue->IsNull())
+ result->setNull();
+ }
+}
+
+void TestRunner::evaluateScriptInIsolatedWorld(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() >= 2 && arguments[0].isNumber() && arguments[1].isString()) {
+ WebScriptSource source(cppVariantToWebString(arguments[1]));
+ // This relies on the iframe focusing itself when it loads. This is a bit
+ // sketchy, but it seems to be what other tests do.
+ m_webView->focusedFrame()->executeScriptInIsolatedWorld(arguments[0].toInt32(), &source, 1, 1);
+ }
+ result->setNull();
+}
+
+void TestRunner::setIsolatedWorldSecurityOrigin(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ if (arguments.size() != 2 || !arguments[0].isNumber() || !(arguments[1].isString() || arguments[1].isNull()))
+ return;
+
+ WebSecurityOrigin origin;
+ if (arguments[1].isString())
+ origin = WebSecurityOrigin::createFromString(cppVariantToWebString(arguments[1]));
+ m_webView->focusedFrame()->setIsolatedWorldSecurityOrigin(arguments[0].toInt32(), origin);
+}
+
+void TestRunner::setIsolatedWorldContentSecurityPolicy(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ if (arguments.size() != 2 || !arguments[0].isNumber() || !arguments[1].isString())
+ return;
+
+ m_webView->focusedFrame()->setIsolatedWorldContentSecurityPolicy(arguments[0].toInt32(), cppVariantToWebString(arguments[1]));
+}
+
+void TestRunner::addOriginAccessWhitelistEntry(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ if (arguments.size() != 4 || !arguments[0].isString() || !arguments[1].isString()
+ || !arguments[2].isString() || !arguments[3].isBool())
+ return;
+
+ blink::WebURL url(GURL(arguments[0].toString()));
+ if (!url.isValid())
+ return;
+
+ WebSecurityPolicy::addOriginAccessWhitelistEntry(
+ url,
+ cppVariantToWebString(arguments[1]),
+ cppVariantToWebString(arguments[2]),
+ arguments[3].toBoolean());
+}
+
+void TestRunner::removeOriginAccessWhitelistEntry(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ if (arguments.size() != 4 || !arguments[0].isString() || !arguments[1].isString()
+ || !arguments[2].isString() || !arguments[3].isBool())
+ return;
+
+ blink::WebURL url(GURL(arguments[0].toString()));
+ if (!url.isValid())
+ return;
+
+ WebSecurityPolicy::removeOriginAccessWhitelistEntry(
+ url,
+ cppVariantToWebString(arguments[1]),
+ cppVariantToWebString(arguments[2]),
+ arguments[3].toBoolean());
+}
+
+void TestRunner::hasCustomPageSizeStyle(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->set(false);
+ int pageIndex = 0;
+ if (arguments.size() > 1)
+ return;
+ if (arguments.size() == 1)
+ pageIndex = cppVariantToInt32(arguments[0]);
+ WebFrame* frame = m_webView->mainFrame();
+ if (!frame)
+ return;
+ result->set(frame->hasCustomPageSizeStyle(pageIndex));
+}
+
+void TestRunner::forceRedSelectionColors(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ m_webView->setSelectionColors(0xffee0000, 0xff00ee00, 0xff000000, 0xffc0c0c0);
+}
+
+void TestRunner::injectStyleSheet(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 2 || !arguments[0].isString() || !arguments[1].isBool())
+ return;
+ WebView::injectStyleSheet(
+ cppVariantToWebString(arguments[0]), WebVector<WebString>(),
+ arguments[1].toBoolean() ? WebView::InjectStyleInAllFrames : WebView::InjectStyleInTopFrameOnly);
+}
+
+void TestRunner::startSpeechInput(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() != 1)
+ return;
+
+ WebElement element;
+ if (!WebBindings::getElement(arguments[0].value.objectValue, &element))
+ return;
+
+ WebInputElement* input = toWebInputElement(&element);
+ if (!input)
+ return;
+
+ if (!input->isSpeechInputEnabled())
+ return;
+
+ input->startSpeechInput();
+}
+
+void TestRunner::findString(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() < 1 || !arguments[0].isString())
+ return;
+
+ WebFindOptions findOptions;
+ bool wrapAround = false;
+ if (arguments.size() >= 2) {
+ vector<string> optionsArray = arguments[1].toStringVector();
+ findOptions.matchCase = true;
+ findOptions.findNext = true;
+
+ for (size_t i = 0; i < optionsArray.size(); ++i) {
+ const std::string& option = optionsArray[i];
+ if (option == "CaseInsensitive")
+ findOptions.matchCase = false;
+ else if (option == "Backwards")
+ findOptions.forward = false;
+ else if (option == "StartInSelection")
+ findOptions.findNext = false;
+ else if (option == "AtWordStarts")
+ findOptions.wordStart = true;
+ else if (option == "TreatMedialCapitalAsWordStart")
+ findOptions.medialCapitalAsWordStart = true;
+ else if (option == "WrapAround")
+ wrapAround = true;
+ }
+ }
+
+ WebFrame* frame = m_webView->mainFrame();
+ const bool findResult = frame->find(0, cppVariantToWebString(arguments[0]), findOptions, wrapAround, 0);
+ frame->stopFinding(false);
+ result->set(findResult);
+}
+
+void TestRunner::setValueForUser(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() != 2)
+ return;
+
+ WebElement element;
+ if (!WebBindings::getElement(arguments[0].value.objectValue, &element))
+ return;
+
+ WebInputElement* input = toWebInputElement(&element);
+ if (!input)
+ return;
+
+ input->setValue(cppVariantToWebString(arguments[1]), true);
+}
+
+void TestRunner::selectionAsMarkup(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->set(m_webView->mainFrame()->selectionAsMarkup().utf8());
+}
+
+void TestRunner::setTextSubpixelPositioning(const CppArgumentList& arguments, CppVariant* result)
+{
+#if defined(__linux__) || defined(ANDROID)
+ // Since FontConfig doesn't provide a variable to control subpixel positioning, we'll fall back
+ // to setting it globally for all fonts.
+ if (arguments.size() > 0 && arguments[0].isBool())
+ WebFontRendering::setSubpixelPositioning(arguments[0].value.boolValue);
+#endif
+ result->setNull();
+}
+
+void TestRunner::setPageVisibility(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isString()) {
+ string newVisibility = arguments[0].toString();
+ if (newVisibility == "visible")
+ m_webView->setVisibilityState(WebPageVisibilityStateVisible, false);
+ else if (newVisibility == "hidden")
+ m_webView->setVisibilityState(WebPageVisibilityStateHidden, false);
+ else if (newVisibility == "prerender")
+ m_webView->setVisibilityState(WebPageVisibilityStatePrerender, false);
+ }
+}
+
+void TestRunner::setTextDirection(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() != 1 || !arguments[0].isString())
+ return;
+
+ // Map a direction name to a WebTextDirection value.
+ std::string directionName = arguments[0].toString();
+ blink::WebTextDirection direction;
+ if (directionName == "auto")
+ direction = blink::WebTextDirectionDefault;
+ else if (directionName == "rtl")
+ direction = blink::WebTextDirectionRightToLeft;
+ else if (directionName == "ltr")
+ direction = blink::WebTextDirectionLeftToRight;
+ else
+ return;
+
+ m_webView->setTextDirection(direction);
+}
+
+void TestRunner::textSurroundingNode(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 4 || !arguments[0].isObject() || !arguments[1].isNumber() || !arguments[2].isNumber() || !arguments[3].isNumber())
+ return;
+
+ WebNode node;
+ if (!WebBindings::getNode(arguments[0].value.objectValue, &node))
+ return;
+
+ if (node.isNull() || !node.isTextNode())
+ return;
+
+ WebPoint point(arguments[1].toInt32(), arguments[2].toInt32());
+ unsigned maxLength = arguments[3].toInt32();
+
+ WebSurroundingText surroundingText;
+ surroundingText.initialize(node, point, maxLength);
+ if (surroundingText.isNull())
+ return;
+
+ result->set(surroundingText.textContent().utf8());
+}
+
+void TestRunner::dumpResourceRequestPriorities(const CppArgumentList& arguments, CppVariant* result)
+{
+ m_shouldDumpResourcePriorities = true;
+ result->setNull();
+}
+
+void TestRunner::useUnfortunateSynchronousResizeMode(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ m_delegate->useUnfortunateSynchronousResizeMode(true);
+}
+
+void TestRunner::enableAutoResizeMode(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() != 4) {
+ result->set(false);
+ return;
+ }
+ int minWidth = cppVariantToInt32(arguments[0]);
+ int minHeight = cppVariantToInt32(arguments[1]);
+ blink::WebSize minSize(minWidth, minHeight);
+
+ int maxWidth = cppVariantToInt32(arguments[2]);
+ int maxHeight = cppVariantToInt32(arguments[3]);
+ blink::WebSize maxSize(maxWidth, maxHeight);
+
+ m_delegate->enableAutoResizeMode(minSize, maxSize);
+ result->set(true);
+}
+
+void TestRunner::disableAutoResizeMode(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() !=2) {
+ result->set(false);
+ return;
+ }
+ int newWidth = cppVariantToInt32(arguments[0]);
+ int newHeight = cppVariantToInt32(arguments[1]);
+ blink::WebSize newSize(newWidth, newHeight);
+
+ m_delegate->disableAutoResizeMode(newSize);
+ result->set(true);
+}
+
+void TestRunner::setMockDeviceMotion(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 19
+ || !arguments[0].isBool() || !arguments[1].isNumber() // acceleration.x
+ || !arguments[2].isBool() || !arguments[3].isNumber() // acceleration.y
+ || !arguments[4].isBool() || !arguments[5].isNumber() // acceleration.z
+ || !arguments[6].isBool() || !arguments[7].isNumber() // accelerationIncludingGravity.x
+ || !arguments[8].isBool() || !arguments[9].isNumber() // accelerationIncludingGravity.y
+ || !arguments[10].isBool() || !arguments[11].isNumber() // accelerationIncludingGravity.z
+ || !arguments[12].isBool() || !arguments[13].isNumber() // rotationRate.alpha
+ || !arguments[14].isBool() || !arguments[15].isNumber() // rotationRate.beta
+ || !arguments[16].isBool() || !arguments[17].isNumber() // rotationRate.gamma
+ || !arguments[18].isNumber()) // interval
+ return;
+
+ WebDeviceMotionData motion;
+
+ // acceleration
+ motion.hasAccelerationX = arguments[0].toBoolean();
+ motion.accelerationX = arguments[1].toDouble();
+ motion.hasAccelerationY = arguments[2].toBoolean();
+ motion.accelerationY = arguments[3].toDouble();
+ motion.hasAccelerationZ = arguments[4].toBoolean();
+ motion.accelerationZ = arguments[5].toDouble();
+
+ // accelerationIncludingGravity
+ motion.hasAccelerationIncludingGravityX = arguments[6].toBoolean();
+ motion.accelerationIncludingGravityX = arguments[7].toDouble();
+ motion.hasAccelerationIncludingGravityY = arguments[8].toBoolean();
+ motion.accelerationIncludingGravityY = arguments[9].toDouble();
+ motion.hasAccelerationIncludingGravityZ = arguments[10].toBoolean();
+ motion.accelerationIncludingGravityZ = arguments[11].toDouble();
+
+ // rotationRate
+ motion.hasRotationRateAlpha = arguments[12].toBoolean();
+ motion.rotationRateAlpha = arguments[13].toDouble();
+ motion.hasRotationRateBeta = arguments[14].toBoolean();
+ motion.rotationRateBeta = arguments[15].toDouble();
+ motion.hasRotationRateGamma = arguments[16].toBoolean();
+ motion.rotationRateGamma = arguments[17].toDouble();
+
+ // interval
+ motion.interval = arguments[18].toDouble();
+
+ m_delegate->setDeviceMotionData(motion);
+}
+
+void TestRunner::setMockDeviceOrientation(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 8
+ || !arguments[0].isBool() || !arguments[1].isNumber() // alpha
+ || !arguments[2].isBool() || !arguments[3].isNumber() // beta
+ || !arguments[4].isBool() || !arguments[5].isNumber() // gamma
+ || !arguments[6].isBool() || !arguments[7].isBool()) // absolute
+ return;
+
+ WebDeviceOrientationData orientation;
+
+ // alpha
+ orientation.hasAlpha = arguments[0].toBoolean();
+ orientation.alpha = arguments[1].toDouble();
+
+ // beta
+ orientation.hasBeta = arguments[2].toBoolean();
+ orientation.beta = arguments[3].toDouble();
+
+ // gamma
+ orientation.hasGamma = arguments[4].toBoolean();
+ orientation.gamma = arguments[5].toDouble();
+
+ // absolute
+ orientation.hasAbsolute = arguments[6].toBoolean();
+ orientation.absolute = arguments[7].toBoolean();
+
+ m_delegate->setDeviceOrientationData(orientation);
+}
+
+void TestRunner::setPopupBlockingEnabled(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool()) {
+ bool blockPopups = arguments[0].toBoolean();
+ m_delegate->preferences()->javaScriptCanOpenWindowsAutomatically = !blockPopups;
+ m_delegate->applyPreferences();
+ }
+ result->setNull();
+}
+
+void TestRunner::setJavaScriptCanAccessClipboard(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool()) {
+ m_delegate->preferences()->javaScriptCanAccessClipboard = arguments[0].value.boolValue;
+ m_delegate->applyPreferences();
+ }
+ result->setNull();
+}
+
+void TestRunner::setXSSAuditorEnabled(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool()) {
+ m_delegate->preferences()->XSSAuditorEnabled = arguments[0].value.boolValue;
+ m_delegate->applyPreferences();
+ }
+ result->setNull();
+}
+
+void TestRunner::setAllowUniversalAccessFromFileURLs(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool()) {
+ m_delegate->preferences()->allowUniversalAccessFromFileURLs = arguments[0].value.boolValue;
+ m_delegate->applyPreferences();
+ }
+ result->setNull();
+}
+
+void TestRunner::setAllowFileAccessFromFileURLs(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool()) {
+ m_delegate->preferences()->allowFileAccessFromFileURLs = arguments[0].value.boolValue;
+ m_delegate->applyPreferences();
+ }
+ result->setNull();
+}
+
+void TestRunner::overridePreference(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() != 2 || !arguments[0].isString())
+ return;
+
+ string key = arguments[0].toString();
+ CppVariant value = arguments[1];
+ WebPreferences* prefs = m_delegate->preferences();
+ if (key == "WebKitDefaultFontSize")
+ prefs->defaultFontSize = cppVariantToInt32(value);
+ else if (key == "WebKitMinimumFontSize")
+ prefs->minimumFontSize = cppVariantToInt32(value);
+ else if (key == "WebKitDefaultTextEncodingName")
+ prefs->defaultTextEncodingName = cppVariantToWebString(value);
+ else if (key == "WebKitJavaScriptEnabled")
+ prefs->javaScriptEnabled = cppVariantToBool(value);
+ else if (key == "WebKitSupportsMultipleWindows")
+ prefs->supportsMultipleWindows = cppVariantToBool(value);
+ else if (key == "WebKitDisplayImagesKey")
+ prefs->loadsImagesAutomatically = cppVariantToBool(value);
+ else if (key == "WebKitPluginsEnabled")
+ prefs->pluginsEnabled = cppVariantToBool(value);
+ else if (key == "WebKitJavaEnabled")
+ prefs->javaEnabled = cppVariantToBool(value);
+ else if (key == "WebKitOfflineWebApplicationCacheEnabled")
+ prefs->offlineWebApplicationCacheEnabled = cppVariantToBool(value);
+ else if (key == "WebKitTabToLinksPreferenceKey")
+ prefs->tabsToLinks = cppVariantToBool(value);
+ else if (key == "WebKitWebGLEnabled")
+ prefs->experimentalWebGLEnabled = cppVariantToBool(value);
+ else if (key == "WebKitCSSRegionsEnabled")
+ prefs->experimentalCSSRegionsEnabled = cppVariantToBool(value);
+ else if (key == "WebKitCSSGridLayoutEnabled")
+ prefs->experimentalCSSGridLayoutEnabled = cppVariantToBool(value);
+ else if (key == "WebKitHyperlinkAuditingEnabled")
+ prefs->hyperlinkAuditingEnabled = cppVariantToBool(value);
+ else if (key == "WebKitEnableCaretBrowsing")
+ prefs->caretBrowsingEnabled = cppVariantToBool(value);
+ else if (key == "WebKitAllowDisplayingInsecureContent")
+ prefs->allowDisplayOfInsecureContent = cppVariantToBool(value);
+ else if (key == "WebKitAllowRunningInsecureContent")
+ prefs->allowRunningOfInsecureContent = cppVariantToBool(value);
+ else if (key == "WebKitCSSCustomFilterEnabled")
+ prefs->cssCustomFilterEnabled = cppVariantToBool(value);
+ else if (key == "WebKitShouldRespectImageOrientation")
+ prefs->shouldRespectImageOrientation = cppVariantToBool(value);
+ else if (key == "WebKitWebAudioEnabled")
+ BLINK_ASSERT(cppVariantToBool(value));
+ else {
+ string message("Invalid name for preference: ");
+ message.append(key);
+ printErrorMessage(message);
+ }
+ m_delegate->applyPreferences();
+}
+
+void TestRunner::setPluginsEnabled(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool()) {
+ m_delegate->preferences()->pluginsEnabled = arguments[0].toBoolean();
+ m_delegate->applyPreferences();
+ }
+ result->setNull();
+}
+
+void TestRunner::showWebInspector(const CppArgumentList&, CppVariant* result)
+{
+ showDevTools();
+ result->setNull();
+}
+
+void TestRunner::closeWebInspector(const CppArgumentList& args, CppVariant* result)
+{
+ m_delegate->closeDevTools();
+ result->setNull();
+}
+
+void TestRunner::isChooserShown(const CppArgumentList&, CppVariant* result)
+{
+ result->set(m_proxy->isChooserShown());
+}
+
+void TestRunner::evaluateInWebInspector(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isString())
+ return;
+ m_delegate->evaluateInWebInspector(arguments[0].toInt32(), arguments[1].toString());
+}
+
+void TestRunner::clearAllDatabases(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ m_delegate->clearAllDatabases();
+}
+
+void TestRunner::setDatabaseQuota(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if ((arguments.size() >= 1) && arguments[0].isNumber())
+ m_delegate->setDatabaseQuota(arguments[0].toInt32());
+}
+
+void TestRunner::setAlwaysAcceptCookies(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0)
+ m_delegate->setAcceptAllCookies(cppVariantToBool(arguments[0]));
+ result->setNull();
+}
+
+void TestRunner::setWindowIsKey(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_delegate->setFocus(m_proxy, arguments[0].value.boolValue);
+ result->setNull();
+}
+
+void TestRunner::pathToLocalResource(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() <= 0 || !arguments[0].isString())
+ return;
+
+ result->set(m_delegate->pathToLocalResource(arguments[0].toString()));
+}
+
+void TestRunner::setBackingScaleFactor(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isObject())
+ return;
+
+ float value = arguments[0].value.doubleValue;
+ m_delegate->setDeviceScaleFactor(value);
+ m_proxy->discardBackingStore();
+
+ WebScopedPtr<CppVariant> callbackArguments(new CppVariant());
+ callbackArguments->set(arguments[1]);
+ result->setNull();
+ m_delegate->postTask(new InvokeCallbackTask(this, callbackArguments));
+}
+
+void TestRunner::setPOSIXLocale(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() == 1 && arguments[0].isString())
+ m_delegate->setLocale(arguments[0].toString());
+}
+
+void TestRunner::numberOfPendingGeolocationPermissionRequests(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->set(m_proxy->geolocationClientMock()->numberOfPendingPermissionRequests());
+}
+
+// FIXME: For greater test flexibility, we should be able to set each page's geolocation mock individually.
+// https://bugs.webkit.org/show_bug.cgi?id=52368
+void TestRunner::setGeolocationPermission(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 1 || !arguments[0].isBool())
+ return;
+ const vector<WebTestProxyBase*>& windowList = m_testInterfaces->windowList();
+ for (unsigned i = 0; i < windowList.size(); ++i)
+ windowList.at(i)->geolocationClientMock()->setPermission(arguments[0].toBoolean());
+}
+
+void TestRunner::setMockGeolocationPosition(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 3 || !arguments[0].isNumber() || !arguments[1].isNumber() || !arguments[2].isNumber())
+ return;
+ const vector<WebTestProxyBase*>& windowList = m_testInterfaces->windowList();
+ for (unsigned i = 0; i < windowList.size(); ++i)
+ windowList.at(i)->geolocationClientMock()->setPosition(arguments[0].toDouble(), arguments[1].toDouble(), arguments[2].toDouble());
+}
+
+void TestRunner::setMockGeolocationPositionUnavailableError(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() != 1 || !arguments[0].isString())
+ return;
+ const vector<WebTestProxyBase*>& windowList = m_testInterfaces->windowList();
+ for (unsigned i = 0; i < windowList.size(); ++i)
+ windowList.at(i)->geolocationClientMock()->setPositionUnavailableError(WebString::fromUTF8(arguments[0].toString()));
+}
+
+void TestRunner::setMIDIAccessorResult(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 1 || !arguments[0].isBool())
+ return;
+ m_midiAccessorResult = arguments[0].toBoolean();
+}
+
+void TestRunner::setMIDISysExPermission(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 1 || !arguments[0].isBool())
+ return;
+ const vector<WebTestProxyBase*>& windowList = m_testInterfaces->windowList();
+ for (unsigned i = 0; i < windowList.size(); ++i)
+ windowList.at(i)->midiClientMock()->setSysExPermission(arguments[0].toBoolean());
+}
+
+void TestRunner::grantWebNotificationPermission(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() != 1 || !arguments[0].isString()) {
+ result->set(false);
+ return;
+ }
+ m_notificationPresenter->grantPermission(WebString::fromUTF8(arguments[0].toString()));
+ result->set(true);
+}
+
+void TestRunner::simulateLegacyWebNotificationClick(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() != 1 || !arguments[0].isString()) {
+ result->set(false);
+ return;
+ }
+ result->set(m_notificationPresenter->simulateClick(WebString::fromUTF8(arguments[0].toString())));
+}
+
+void TestRunner::cancelAllActiveNotifications(const CppArgumentList& arguments, CppVariant* result)
+{
+ m_notificationPresenter->cancelAllActiveNotifications();
+ result->set(true);
+}
+
+void TestRunner::addMockSpeechInputResult(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 3 || !arguments[0].isString() || !arguments[1].isNumber() || !arguments[2].isString())
+ return;
+
+#if ENABLE_INPUT_SPEECH
+ m_proxy->speechInputControllerMock()->addMockRecognitionResult(WebString::fromUTF8(arguments[0].toString()), arguments[1].toDouble(), WebString::fromUTF8(arguments[2].toString()));
+#endif
+}
+
+void TestRunner::setMockSpeechInputDumpRect(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 1 || !arguments[0].isBool())
+ return;
+
+#if ENABLE_INPUT_SPEECH
+ m_proxy->speechInputControllerMock()->setDumpRect(arguments[0].toBoolean());
+#endif
+}
+
+void TestRunner::addMockSpeechRecognitionResult(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 2 || !arguments[0].isString() || !arguments[1].isNumber())
+ return;
+
+ m_proxy->speechRecognizerMock()->addMockResult(WebString::fromUTF8(arguments[0].toString()), arguments[1].toDouble());
+}
+
+void TestRunner::setMockSpeechRecognitionError(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() != 2 || !arguments[0].isString() || !arguments[1].isString())
+ return;
+
+ m_proxy->speechRecognizerMock()->setError(WebString::fromUTF8(arguments[0].toString()), WebString::fromUTF8(arguments[1].toString()));
+}
+
+void TestRunner::wasMockSpeechRecognitionAborted(const CppArgumentList&, CppVariant* result)
+{
+ result->set(m_proxy->speechRecognizerMock()->wasAborted());
+}
+
+void TestRunner::addWebPageOverlay(const CppArgumentList&, CppVariant* result)
+{
+ if (m_webView && !m_pageOverlay) {
+ m_pageOverlay = new TestPageOverlay(m_webView);
+ m_webView->addPageOverlay(m_pageOverlay, 0);
+ }
+ result->setNull();
+}
+
+void TestRunner::removeWebPageOverlay(const CppArgumentList&, CppVariant* result)
+{
+ if (m_webView && m_pageOverlay) {
+ m_webView->removePageOverlay(m_pageOverlay);
+ delete m_pageOverlay;
+ m_pageOverlay = 0;
+ }
+
+ result->setNull();
+}
+
+void TestRunner::display(const CppArgumentList& arguments, CppVariant* result)
+{
+ m_proxy->display();
+ result->setNull();
+}
+
+void TestRunner::displayInvalidatedRegion(const CppArgumentList& arguments, CppVariant* result)
+{
+ m_proxy->displayInvalidatedRegion();
+ result->setNull();
+}
+
+void TestRunner::dumpEditingCallbacks(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpEditingCallbacks = true;
+ result->setNull();
+}
+
+void TestRunner::dumpAsText(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpAsText = true;
+ m_generatePixelResults = false;
+
+ result->setNull();
+}
+
+void TestRunner::dumpAsTextWithPixelResults(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpAsText = true;
+ m_generatePixelResults = true;
+
+ result->setNull();
+}
+
+void TestRunner::dumpChildFrameScrollPositions(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpChildFrameScrollPositions = true;
+ result->setNull();
+}
+
+void TestRunner::dumpChildFramesAsText(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpChildFramesAsText = true;
+ result->setNull();
+}
+
+void TestRunner::dumpIconChanges(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpIconChanges = true;
+ result->setNull();
+}
+
+void TestRunner::setAudioData(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ if (arguments.size() < 1 || !arguments[0].isObject())
+ return;
+
+ // Check that passed-in object is, in fact, an ArrayBufferView.
+ NPObject* npobject = NPVARIANT_TO_OBJECT(arguments[0]);
+ if (!npobject)
+ return;
+ if (!WebBindings::getArrayBufferView(npobject, &m_audioData))
+ return;
+
+ m_dumpAsAudio = true;
+}
+
+void TestRunner::dumpFrameLoadCallbacks(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpFrameLoadCallbacks = true;
+ result->setNull();
+}
+
+void TestRunner::dumpPingLoaderCallbacks(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpPingLoaderCallbacks = true;
+ result->setNull();
+}
+
+void TestRunner::dumpUserGestureInFrameLoadCallbacks(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpUserGestureInFrameLoadCallbacks = true;
+ result->setNull();
+}
+
+void TestRunner::dumpTitleChanges(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpTitleChanges = true;
+ result->setNull();
+}
+
+void TestRunner::dumpCreateView(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpCreateView = true;
+ result->setNull();
+}
+
+void TestRunner::setCanOpenWindows(const CppArgumentList&, CppVariant* result)
+{
+ m_canOpenWindows = true;
+ result->setNull();
+}
+
+void TestRunner::dumpResourceLoadCallbacks(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpResourceLoadCallbacks = true;
+ result->setNull();
+}
+
+void TestRunner::dumpResourceRequestCallbacks(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpResourceRequestCallbacks = true;
+ result->setNull();
+}
+
+void TestRunner::dumpResourceResponseMIMETypes(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpResourceResponseMIMETypes = true;
+ result->setNull();
+}
+
+// Need these conversions because the format of the value for booleans
+// may vary - for example, on mac "1" and "0" are used for boolean.
+bool TestRunner::cppVariantToBool(const CppVariant& value)
+{
+ if (value.isBool())
+ return value.toBoolean();
+ if (value.isNumber())
+ return value.toInt32() != 0;
+ if (value.isString()) {
+ string valueString = value.toString();
+ if (valueString == "true" || valueString == "1")
+ return true;
+ if (valueString == "false" || valueString == "0")
+ return false;
+ }
+ printErrorMessage("Invalid value. Expected boolean value.");
+ return false;
+}
+
+int32_t TestRunner::cppVariantToInt32(const CppVariant& value)
+{
+ if (value.isNumber())
+ return value.toInt32();
+ if (value.isString()) {
+ string stringSource = value.toString();
+ const char* source = stringSource.data();
+ char* end;
+ long number = strtol(source, &end, 10);
+ if (end == source + stringSource.length() && number >= numeric_limits<int32_t>::min() && number <= numeric_limits<int32_t>::max())
+ return static_cast<int32_t>(number);
+ }
+ printErrorMessage("Invalid value for preference. Expected integer value.");
+ return 0;
+}
+
+WebString TestRunner::cppVariantToWebString(const CppVariant& value)
+{
+ if (!value.isString()) {
+ printErrorMessage("Invalid value for preference. Expected string value.");
+ return WebString();
+ }
+ return WebString::fromUTF8(value.toString());
+}
+
+void TestRunner::printErrorMessage(const string& text)
+{
+ m_delegate->printMessage(string("CONSOLE MESSAGE: ") + text + "\n");
+}
+
+void TestRunner::fallbackMethod(const CppArgumentList&, CppVariant* result)
+{
+ printErrorMessage("JavaScript ERROR: unknown method called on TestRunner");
+ result->setNull();
+}
+
+void TestRunner::notImplemented(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void TestRunner::didAcquirePointerLock(const CppArgumentList&, CppVariant* result)
+{
+ didAcquirePointerLockInternal();
+ result->setNull();
+}
+
+void TestRunner::didNotAcquirePointerLock(const CppArgumentList&, CppVariant* result)
+{
+ didNotAcquirePointerLockInternal();
+ result->setNull();
+}
+
+void TestRunner::didLosePointerLock(const CppArgumentList&, CppVariant* result)
+{
+ didLosePointerLockInternal();
+ result->setNull();
+}
+
+void TestRunner::setPointerLockWillRespondAsynchronously(const CppArgumentList&, CppVariant* result)
+{
+ m_pointerLockPlannedResult = PointerLockWillRespondAsync;
+ result->setNull();
+}
+
+void TestRunner::setPointerLockWillFailSynchronously(const CppArgumentList&, CppVariant* result)
+{
+ m_pointerLockPlannedResult = PointerLockWillFailSync;
+ result->setNull();
+}
+
+}
diff --git a/content/shell/renderer/test_runner/TestRunner.h b/content/shell/renderer/test_runner/TestRunner.h
new file mode 100644
index 0000000..34c1cbf
--- /dev/null
+++ b/content/shell/renderer/test_runner/TestRunner.h
@@ -0,0 +1,737 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2010 Pawel Hajdan (phajdan.jr@chromium.org)
+ * Copyright (C) 2012 Apple Inc. All Rights Reserved.
+ *
+ * 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.
+ */
+
+#ifndef TestRunner_h
+#define TestRunner_h
+
+#include <deque>
+#include <set>
+#include <string>
+
+#include "content/shell/renderer/test_runner/CppBoundClass.h"
+#include "content/shell/renderer/test_runner/TestCommon.h"
+#include "content/shell/renderer/test_runner/WebScopedPtr.h"
+#include "content/shell/renderer/test_runner/WebTask.h"
+#include "content/shell/renderer/test_runner/WebTestRunner.h"
+#include "third_party/WebKit/public/platform/WebCanvas.h"
+#include "third_party/WebKit/public/platform/WebURL.h"
+#include "third_party/WebKit/public/web/WebArrayBufferView.h"
+#include "third_party/WebKit/public/web/WebPageOverlay.h"
+#include "third_party/WebKit/public/web/WebTextDirection.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+
+namespace blink {
+class WebArrayBufferView;
+class WebNotificationPresenter;
+class WebPageOverlay;
+class WebPermissionClient;
+class WebView;
+}
+
+namespace WebTestRunner {
+
+class NotificationPresenter;
+class TestInterfaces;
+class WebPermissions;
+class WebTestDelegate;
+class WebTestProxyBase;
+
+class TestRunner : public WebTestRunner, public CppBoundClass {
+public:
+ explicit TestRunner(TestInterfaces*);
+ virtual ~TestRunner();
+
+ void setDelegate(WebTestDelegate*);
+ void setWebView(blink::WebView*, WebTestProxyBase*);
+
+ void reset();
+
+ WebTaskList* taskList() { return &m_taskList; }
+
+ void setTestIsRunning(bool);
+ bool testIsRunning() const { return m_testIsRunning; }
+
+ // WebTestRunner implementation.
+ virtual bool shouldGeneratePixelResults() OVERRIDE;
+ virtual bool shouldDumpAsAudio() const OVERRIDE;
+ virtual const blink::WebArrayBufferView* audioData() const OVERRIDE;
+ virtual bool shouldDumpBackForwardList() const OVERRIDE;
+ virtual blink::WebPermissionClient* webPermissions() const OVERRIDE;
+
+ // Methods used by WebTestProxyBase.
+ bool shouldDumpSelectionRect() const;
+ bool testRepaint() const;
+ bool sweepHorizontally() const;
+ bool isPrinting() const;
+ bool shouldDumpAsText();
+ bool shouldDumpAsTextWithPixelResults();
+ bool shouldDumpAsMarkup();
+ bool shouldDumpChildFrameScrollPositions() const;
+ bool shouldDumpChildFramesAsText() const;
+ void showDevTools();
+ void setShouldDumpAsText(bool);
+ void setShouldDumpAsMarkup(bool);
+ void setShouldGeneratePixelResults(bool);
+ void setShouldDumpFrameLoadCallbacks(bool);
+ void setShouldDumpPingLoaderCallbacks(bool);
+ void setShouldEnableViewSource(bool);
+ bool shouldDumpEditingCallbacks() const;
+ bool shouldDumpFrameLoadCallbacks() const;
+ bool shouldDumpPingLoaderCallbacks() const;
+ bool shouldDumpUserGestureInFrameLoadCallbacks() const;
+ bool shouldDumpTitleChanges() const;
+ bool shouldDumpIconChanges() const;
+ bool shouldDumpCreateView() const;
+ bool canOpenWindows() const;
+ bool shouldDumpResourceLoadCallbacks() const;
+ bool shouldDumpResourceRequestCallbacks() const;
+ bool shouldDumpResourceResponseMIMETypes() const;
+ bool shouldDumpStatusCallbacks() const;
+ bool shouldDumpProgressFinishedCallback() const;
+ bool shouldDumpSpellCheckCallbacks() const;
+ bool shouldStayOnPageAfterHandlingBeforeUnload() const;
+ const std::set<std::string>* httpHeadersToClear() const;
+ void setTopLoadingFrame(blink::WebFrame*, bool);
+ blink::WebFrame* topLoadingFrame() const;
+ void policyDelegateDone();
+ bool policyDelegateEnabled() const;
+ bool policyDelegateIsPermissive() const;
+ bool policyDelegateShouldNotifyDone() const;
+ bool shouldInterceptPostMessage() const;
+ bool shouldDumpResourcePriorities() const;
+ blink::WebNotificationPresenter* notificationPresenter() const;
+ bool requestPointerLock();
+ void requestPointerUnlock();
+ bool isPointerLocked();
+ void setToolTipText(const blink::WebString&);
+
+ bool midiAccessorResult();
+
+ // A single item in the work queue.
+ class WorkItem {
+ public:
+ virtual ~WorkItem() { }
+
+ // Returns true if this started a load.
+ virtual bool run(WebTestDelegate*, blink::WebView*) = 0;
+ };
+
+private:
+ friend class WorkQueue;
+
+ // Helper class for managing events queued by methods like queueLoad or
+ // queueScript.
+ class WorkQueue {
+ public:
+ WorkQueue(TestRunner* controller) : m_frozen(false), m_controller(controller) { }
+ virtual ~WorkQueue();
+ void processWorkSoon();
+
+ // Reset the state of the class between tests.
+ void reset();
+
+ void addWork(WorkItem*);
+
+ void setFrozen(bool frozen) { m_frozen = frozen; }
+ bool isEmpty() { return m_queue.empty(); }
+ WebTaskList* taskList() { return &m_taskList; }
+
+ private:
+ void processWork();
+ class WorkQueueTask: public WebMethodTask<WorkQueue> {
+ public:
+ WorkQueueTask(WorkQueue* object): WebMethodTask<WorkQueue>(object) { }
+ virtual void runIfValid() { m_object->processWork(); }
+ };
+
+ WebTaskList m_taskList;
+ std::deque<WorkItem*> m_queue;
+ bool m_frozen;
+ TestRunner* m_controller;
+ };
+ ///////////////////////////////////////////////////////////////////////////
+ // Methods dealing with the test logic
+
+ // By default, tests end when page load is complete. These methods are used
+ // to delay the completion of the test until notifyDone is called.
+ void waitUntilDone(const CppArgumentList&, CppVariant*);
+ void notifyDone(const CppArgumentList&, CppVariant*);
+
+ // Methods for adding actions to the work queue. Used in conjunction with
+ // waitUntilDone/notifyDone above.
+ void queueBackNavigation(const CppArgumentList&, CppVariant*);
+ void queueForwardNavigation(const CppArgumentList&, CppVariant*);
+ void queueReload(const CppArgumentList&, CppVariant*);
+ void queueLoadingScript(const CppArgumentList&, CppVariant*);
+ void queueNonLoadingScript(const CppArgumentList&, CppVariant*);
+ void queueLoad(const CppArgumentList&, CppVariant*);
+ void queueLoadHTMLString(const CppArgumentList&, CppVariant*);
+
+
+ // Causes navigation actions just printout the intended navigation instead
+ // of taking you to the page. This is used for cases like mailto, where you
+ // don't actually want to open the mail program.
+ void setCustomPolicyDelegate(const CppArgumentList&, CppVariant*);
+
+ // Delays completion of the test until the policy delegate runs.
+ void waitForPolicyDelegate(const CppArgumentList&, CppVariant*);
+
+ // Functions for dealing with windows. By default we block all new windows.
+ void windowCount(const CppArgumentList&, CppVariant*);
+ void setCloseRemainingWindowsWhenComplete(const CppArgumentList&, CppVariant*);
+
+ void resetTestHelperControllers(const CppArgumentList&, CppVariant*);
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Methods implemented entirely in terms of chromium's public WebKit API
+
+ // Method that controls whether pressing Tab key cycles through page elements
+ // or inserts a '\t' char in text area
+ void setTabKeyCyclesThroughElements(const CppArgumentList&, CppVariant*);
+
+ // Executes an internal command (superset of document.execCommand() commands).
+ void execCommand(const CppArgumentList&, CppVariant*);
+
+ // Checks if an internal command is currently available.
+ void isCommandEnabled(const CppArgumentList&, CppVariant*);
+
+ void callShouldCloseOnWebView(const CppArgumentList&, CppVariant*);
+ void setDomainRelaxationForbiddenForURLScheme(const CppArgumentList&, CppVariant*);
+ void evaluateScriptInIsolatedWorldAndReturnValue(const CppArgumentList&, CppVariant*);
+ void evaluateScriptInIsolatedWorld(const CppArgumentList&, CppVariant*);
+ void setIsolatedWorldSecurityOrigin(const CppArgumentList&, CppVariant*);
+ void setIsolatedWorldContentSecurityPolicy(const CppArgumentList&, CppVariant*);
+
+ // Allows layout tests to manage origins' whitelisting.
+ void addOriginAccessWhitelistEntry(const CppArgumentList&, CppVariant*);
+ void removeOriginAccessWhitelistEntry(const CppArgumentList&, CppVariant*);
+
+ // Returns true if the current page box has custom page size style for
+ // printing.
+ void hasCustomPageSizeStyle(const CppArgumentList&, CppVariant*);
+
+ // Forces the selection colors for testing under Linux.
+ void forceRedSelectionColors(const CppArgumentList&, CppVariant*);
+
+ // Adds a style sheet to be injected into new documents.
+ void injectStyleSheet(const CppArgumentList&, CppVariant*);
+
+ void startSpeechInput(const CppArgumentList&, CppVariant*);
+
+ void findString(const CppArgumentList&, CppVariant*);
+
+ // Expects the first argument to be an input element and the second argument to be a string value.
+ // Forwards the setValueForUser() call to the element.
+ void setValueForUser(const CppArgumentList&, CppVariant*);
+
+ void selectionAsMarkup(const CppArgumentList&, CppVariant*);
+
+ // Enables or disables subpixel positioning (i.e. fractional X positions for
+ // glyphs) in text rendering on Linux. Since this method changes global
+ // settings, tests that call it must use their own custom font family for
+ // all text that they render. If not, an already-cached style will be used,
+ // resulting in the changed setting being ignored.
+ void setTextSubpixelPositioning(const CppArgumentList&, CppVariant*);
+
+ // Switch the visibility of the page.
+ void setPageVisibility(const CppArgumentList&, CppVariant*);
+
+ // Changes the direction of the focused element.
+ void setTextDirection(const CppArgumentList&, CppVariant*);
+
+ // Retrieves the text surrounding a position in a text node.
+ // Expects the first argument to be a text node, the second and third to be
+ // point coordinates relative to the node and the fourth the maximum text
+ // length to retrieve.
+ void textSurroundingNode(const CppArgumentList&, CppVariant*);
+
+ // After this function is called, all window-sizing machinery is
+ // short-circuited inside the renderer. This mode is necessary for
+ // some tests that were written before browsers had multi-process architecture
+ // and rely on window resizes to happen synchronously.
+ // The function has "unfortunate" it its name because we must strive to remove all tests
+ // that rely on this... well, unfortunate behavior. See http://crbug.com/309760 for the plan.
+ void useUnfortunateSynchronousResizeMode(const CppArgumentList&, CppVariant*);
+
+ void enableAutoResizeMode(const CppArgumentList&, CppVariant*);
+ void disableAutoResizeMode(const CppArgumentList&, CppVariant*);
+
+ // Device Motion / Device Orientation related functions
+ void setMockDeviceMotion(const CppArgumentList&, CppVariant*);
+ void setMockDeviceOrientation(const CppArgumentList&, CppVariant*);
+
+ void didAcquirePointerLock(const CppArgumentList&, CppVariant*);
+ void didNotAcquirePointerLock(const CppArgumentList&, CppVariant*);
+ void didLosePointerLock(const CppArgumentList&, CppVariant*);
+ void setPointerLockWillFailSynchronously(const CppArgumentList&, CppVariant*);
+ void setPointerLockWillRespondAsynchronously(const CppArgumentList&, CppVariant*);
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Methods modifying WebPreferences.
+
+ // Set the WebPreference that controls webkit's popup blocking.
+ void setPopupBlockingEnabled(const CppArgumentList&, CppVariant*);
+
+ void setJavaScriptCanAccessClipboard(const CppArgumentList&, CppVariant*);
+ void setXSSAuditorEnabled(const CppArgumentList&, CppVariant*);
+ void setAllowUniversalAccessFromFileURLs(const CppArgumentList&, CppVariant*);
+ void setAllowFileAccessFromFileURLs(const CppArgumentList&, CppVariant*);
+ void overridePreference(const CppArgumentList&, CppVariant*);
+
+ // Enable or disable plugins.
+ void setPluginsEnabled(const CppArgumentList&, CppVariant*);
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Methods that modify the state of TestRunner
+
+ // This function sets a flag that tells the test_shell to print a line of
+ // descriptive text for each editing command. It takes no arguments, and
+ // ignores any that may be present.
+ void dumpEditingCallbacks(const CppArgumentList&, CppVariant*);
+
+ // This function sets a flag that tells the test_shell to dump pages as
+ // plain text, rather than as a text representation of the renderer's state.
+ // The pixel results will not be generated for this test.
+ void dumpAsText(const CppArgumentList&, CppVariant*);
+
+ // This function sets a flag that tells the test_shell to dump pages as
+ // plain text, rather than as a text representation of the renderer's state.
+ // It will also generate a pixel dump for the test.
+ void dumpAsTextWithPixelResults(const CppArgumentList&, CppVariant*);
+
+ // This function sets a flag that tells the test_shell to print out the
+ // scroll offsets of the child frames. It ignores all.
+ void dumpChildFrameScrollPositions(const CppArgumentList&, CppVariant*);
+
+ // This function sets a flag that tells the test_shell to recursively
+ // dump all frames as plain text if the dumpAsText flag is set.
+ // It takes no arguments, and ignores any that may be present.
+ void dumpChildFramesAsText(const CppArgumentList&, CppVariant*);
+
+ // This function sets a flag that tells the test_shell to print out the
+ // information about icon changes notifications from WebKit.
+ void dumpIconChanges(const CppArgumentList&, CppVariant*);
+
+ // Deals with Web Audio WAV file data.
+ void setAudioData(const CppArgumentList&, CppVariant*);
+
+ // This function sets a flag that tells the test_shell to print a line of
+ // descriptive text for each frame load callback. It takes no arguments, and
+ // ignores any that may be present.
+ void dumpFrameLoadCallbacks(const CppArgumentList&, CppVariant*);
+
+ // This function sets a flag that tells the test_shell to print a line of
+ // descriptive text for each PingLoader dispatch. It takes no arguments, and
+ // ignores any that may be present.
+ void dumpPingLoaderCallbacks(const CppArgumentList&, CppVariant*);
+
+ // This function sets a flag that tells the test_shell to print a line of
+ // user gesture status text for some frame load callbacks. It takes no
+ // arguments, and ignores any that may be present.
+ void dumpUserGestureInFrameLoadCallbacks(const CppArgumentList&, CppVariant*);
+
+ void dumpTitleChanges(const CppArgumentList&, CppVariant*);
+
+ // This function sets a flag that tells the test_shell to dump all calls to
+ // WebViewClient::createView().
+ // It takes no arguments, and ignores any that may be present.
+ void dumpCreateView(const CppArgumentList&, CppVariant*);
+
+ void setCanOpenWindows(const CppArgumentList&, CppVariant*);
+
+ // This function sets a flag that tells the test_shell to dump a descriptive
+ // line for each resource load callback. It takes no arguments, and ignores
+ // any that may be present.
+ void dumpResourceLoadCallbacks(const CppArgumentList&, CppVariant*);
+
+ // This function sets a flag that tells the test_shell to print a line of
+ // descriptive text for each element that requested a resource. It takes no
+ // arguments, and ignores any that may be present.
+ void dumpResourceRequestCallbacks(const CppArgumentList&, CppVariant*);
+
+ // This function sets a flag that tells the test_shell to dump the MIME type
+ // for each resource that was loaded. It takes no arguments, and ignores any
+ // that may be present.
+ void dumpResourceResponseMIMETypes(const CppArgumentList&, CppVariant*);
+
+ // WebPermissionClient related.
+ void setImagesAllowed(const CppArgumentList&, CppVariant*);
+ void setScriptsAllowed(const CppArgumentList&, CppVariant*);
+ void setStorageAllowed(const CppArgumentList&, CppVariant*);
+ void setPluginsAllowed(const CppArgumentList&, CppVariant*);
+ void setAllowDisplayOfInsecureContent(const CppArgumentList&, CppVariant*);
+ void setAllowRunningOfInsecureContent(const CppArgumentList&, CppVariant*);
+ void dumpPermissionClientCallbacks(const CppArgumentList&, CppVariant*);
+
+ // This function sets a flag that tells the test_shell to dump all calls
+ // to window.status().
+ // It takes no arguments, and ignores any that may be present.
+ void dumpWindowStatusChanges(const CppArgumentList&, CppVariant*);
+
+ // This function sets a flag that tells the test_shell to print a line of
+ // descriptive text for the progress finished callback. It takes no
+ // arguments, and ignores any that may be present.
+ void dumpProgressFinishedCallback(const CppArgumentList&, CppVariant*);
+
+ // This function sets a flag that tells the test_shell to dump all
+ // the lines of descriptive text about spellcheck execution.
+ void dumpSpellCheckCallbacks(const CppArgumentList&, CppVariant*);
+
+ // This function sets a flag that tells the test_shell to print out a text
+ // representation of the back/forward list. It ignores all arguments.
+ void dumpBackForwardList(const CppArgumentList&, CppVariant*);
+
+ void dumpSelectionRect(const CppArgumentList&, CppVariant*);
+ void testRepaint(const CppArgumentList&, CppVariant*);
+ void repaintSweepHorizontally(const CppArgumentList&, CppVariant*);
+
+ // Causes layout to happen as if targetted to printed pages.
+ void setPrinting(const CppArgumentList&, CppVariant*);
+
+ void setShouldStayOnPageAfterHandlingBeforeUnload(const CppArgumentList&, CppVariant*);
+
+ // Causes WillSendRequest to clear certain headers.
+ void setWillSendRequestClearHeader(const CppArgumentList&, CppVariant*);
+
+ // This function sets a flag that tells the test_shell to dump a descriptive
+ // line for each resource load's priority and any time that priority
+ // changes. It takes no arguments, and ignores any that may be present.
+ void dumpResourceRequestPriorities(const CppArgumentList&, CppVariant*);
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Methods interacting with the WebTestProxy
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Methods forwarding to the WebTestDelegate
+
+ // Shows DevTools window.
+ void showWebInspector(const CppArgumentList&, CppVariant*);
+ void closeWebInspector(const CppArgumentList&, CppVariant*);
+
+ // Inspect chooser state
+ void isChooserShown(const CppArgumentList&, CppVariant*);
+
+ // Allows layout tests to exec scripts at WebInspector side.
+ void evaluateInWebInspector(const CppArgumentList&, CppVariant*);
+
+ // Clears all databases.
+ void clearAllDatabases(const CppArgumentList&, CppVariant*);
+ // Sets the default quota for all origins
+ void setDatabaseQuota(const CppArgumentList&, CppVariant*);
+
+ // Changes the cookie policy from the default to allow all cookies.
+ void setAlwaysAcceptCookies(const CppArgumentList&, CppVariant*);
+
+ // Gives focus to the window.
+ void setWindowIsKey(const CppArgumentList&, CppVariant*);
+
+ // Converts a URL starting with file:///tmp/ to the local mapping.
+ void pathToLocalResource(const CppArgumentList&, CppVariant*);
+
+ // Used to set the device scale factor.
+ void setBackingScaleFactor(const CppArgumentList&, CppVariant*);
+
+ // Calls setlocale(LC_ALL, ...) for a specified locale.
+ // Resets between tests.
+ void setPOSIXLocale(const CppArgumentList&, CppVariant*);
+
+ // Gets the number of geolocation permissions requests pending.
+ void numberOfPendingGeolocationPermissionRequests(const CppArgumentList&, CppVariant*);
+
+ // Geolocation related functions.
+ void setGeolocationPermission(const CppArgumentList&, CppVariant*);
+ void setMockGeolocationPosition(const CppArgumentList&, CppVariant*);
+ void setMockGeolocationPositionUnavailableError(const CppArgumentList&, CppVariant*);
+
+ // MIDI function to control permission handling.
+ void setMIDIAccessorResult(const CppArgumentList&, CppVariant*);
+ void setMIDISysExPermission(const CppArgumentList&, CppVariant*);
+
+ // Grants permission for desktop notifications to an origin
+ void grantWebNotificationPermission(const CppArgumentList&, CppVariant*);
+ // Simulates a click on a desktop notification.
+ void simulateLegacyWebNotificationClick(const CppArgumentList&, CppVariant*);
+ // Cancel all active desktop notifications.
+ void cancelAllActiveNotifications(const CppArgumentList& arguments, CppVariant* result);
+
+ // Speech input related functions.
+ void addMockSpeechInputResult(const CppArgumentList&, CppVariant*);
+ void setMockSpeechInputDumpRect(const CppArgumentList&, CppVariant*);
+ void addMockSpeechRecognitionResult(const CppArgumentList&, CppVariant*);
+ void setMockSpeechRecognitionError(const CppArgumentList&, CppVariant*);
+ void wasMockSpeechRecognitionAborted(const CppArgumentList&, CppVariant*);
+
+ // WebPageOverlay related functions. Permits the adding and removing of only
+ // one opaque overlay.
+ void addWebPageOverlay(const CppArgumentList&, CppVariant*);
+ void removeWebPageOverlay(const CppArgumentList&, CppVariant*);
+
+ void display(const CppArgumentList&, CppVariant*);
+ void displayInvalidatedRegion(const CppArgumentList&, CppVariant*);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Fallback and stub methods
+
+ // The fallback method is called when a nonexistent method is called on
+ // the layout test controller object.
+ // It is usefull to catch typos in the JavaScript code (a few layout tests
+ // do have typos in them) and it allows the script to continue running in
+ // that case (as the Mac does).
+ void fallbackMethod(const CppArgumentList&, CppVariant*);
+
+ // Stub for not implemented methods.
+ void notImplemented(const CppArgumentList&, CppVariant*);
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Internal helpers
+ void checkResponseMimeType();
+ void completeNotifyDone();
+ class HostMethodTask : public WebMethodTask<TestRunner> {
+ public:
+ typedef void (TestRunner::*CallbackMethodType)();
+ HostMethodTask(TestRunner* object, CallbackMethodType callback)
+ : WebMethodTask<TestRunner>(object)
+ , m_callback(callback)
+ { }
+
+ virtual void runIfValid() { (m_object->*m_callback)(); }
+
+ private:
+ CallbackMethodType m_callback;
+ };
+ class TestPageOverlay : public blink::WebPageOverlay {
+ public:
+ explicit TestPageOverlay(blink::WebView*);
+ virtual void paintPageOverlay(blink::WebCanvas*) OVERRIDE;
+ virtual ~TestPageOverlay();
+ private:
+ blink::WebView* m_webView;
+ };
+ void didAcquirePointerLockInternal();
+ void didNotAcquirePointerLockInternal();
+ void didLosePointerLockInternal();
+
+ bool cppVariantToBool(const CppVariant&);
+ int32_t cppVariantToInt32(const CppVariant&);
+ blink::WebString cppVariantToWebString(const CppVariant&);
+
+ void printErrorMessage(const std::string&);
+
+ // In the Mac code, this is called to trigger the end of a test after the
+ // page has finished loading. From here, we can generate the dump for the
+ // test.
+ void locationChangeDone();
+
+ bool m_testIsRunning;
+
+ // When reset is called, go through and close all but the main test shell
+ // window. By default, set to true but toggled to false using
+ // setCloseRemainingWindowsWhenComplete().
+ bool m_closeRemainingWindows;
+
+ // If true, don't dump output until notifyDone is called.
+ bool m_waitUntilDone;
+
+ // Causes navigation actions just printout the intended navigation instead
+ // of taking you to the page. This is used for cases like mailto, where you
+ // don't actually want to open the mail program.
+ bool m_policyDelegateEnabled;
+
+ // Toggles the behavior of the policy delegate. If true, then navigations
+ // will be allowed. Otherwise, they will be ignored (dropped).
+ bool m_policyDelegateIsPermissive;
+
+ // If true, the policy delegate will signal layout test completion.
+ bool m_policyDelegateShouldNotifyDone;
+
+ WorkQueue m_workQueue;
+
+ // globalFlag is used by a number of layout tests in http/tests/security/dataURL.
+ CppVariant m_globalFlag;
+
+ // Bound variable to return the name of this platform (chromium).
+ CppVariant m_platformName;
+
+ // Bound variable counting the number of top URLs visited.
+ CppVariant m_webHistoryItemCount;
+
+ // Bound variable to set whether postMessages should be intercepted or not
+ CppVariant m_interceptPostMessage;
+
+ // Bound variable to store the last tooltip text
+ CppVariant m_tooltipText;
+
+ // Bound variable to disable notifyDone calls. This is used in GC leak
+ // tests, where existing LayoutTests are loaded within an iframe. The GC
+ // test harness will set this flag to ignore the notifyDone calls from the
+ // target LayoutTest.
+ CppVariant m_disableNotifyDone;
+
+ // If true, the test_shell will write a descriptive line for each editing
+ // command.
+ bool m_dumpEditingCallbacks;
+
+ // If true, the test_shell will generate pixel results in dumpAsText mode
+ bool m_generatePixelResults;
+
+ // If true, the test_shell will produce a plain text dump rather than a
+ // text representation of the renderer.
+ bool m_dumpAsText;
+
+ // If true and if dump_as_text_ is true, the test_shell will recursively
+ // dump all frames as plain text.
+ bool m_dumpChildFramesAsText;
+
+ // If true, the test_shell will produce a dump of the DOM rather than a text
+ // representation of the renderer.
+ bool m_dumpAsMarkup;
+
+ // If true, the test_shell will print out the child frame scroll offsets as
+ // well.
+ bool m_dumpChildFrameScrollPositions;
+
+ // If true, the test_shell will print out the icon change notifications.
+ bool m_dumpIconChanges;
+
+ // If true, the test_shell will output a base64 encoded WAVE file.
+ bool m_dumpAsAudio;
+
+ // If true, the test_shell will output a descriptive line for each frame
+ // load callback.
+ bool m_dumpFrameLoadCallbacks;
+
+ // If true, the test_shell will output a descriptive line for each
+ // PingLoader dispatched.
+ bool m_dumpPingLoaderCallbacks;
+
+ // If true, the test_shell will output a line of the user gesture status
+ // text for some frame load callbacks.
+ bool m_dumpUserGestureInFrameLoadCallbacks;
+
+ // If true, output a message when the page title is changed.
+ bool m_dumpTitleChanges;
+
+ // If true, output a descriptive line each time WebViewClient::createView
+ // is invoked.
+ bool m_dumpCreateView;
+
+ // If true, new windows can be opened via javascript or by plugins. By
+ // default, set to false and can be toggled to true using
+ // setCanOpenWindows().
+ bool m_canOpenWindows;
+
+ // If true, the test_shell will output a descriptive line for each resource
+ // load callback.
+ bool m_dumpResourceLoadCallbacks;
+
+ // If true, the test_shell will output a descriptive line for each resource
+ // request callback.
+ bool m_dumpResourceRequestCallbacks;
+
+ // If true, the test_shell will output the MIME type for each resource that
+ // was loaded.
+ bool m_dumpResourceResponseMIMETypes;
+
+ // If true, the test_shell will dump all changes to window.status.
+ bool m_dumpWindowStatusChanges;
+
+ // If true, the test_shell will output a descriptive line for the progress
+ // finished callback.
+ bool m_dumpProgressFinishedCallback;
+
+ // If true, the test_shell will output descriptive test for spellcheck
+ // execution.
+ bool m_dumpSpellCheckCallbacks;
+
+ // If true, the test_shell will produce a dump of the back forward list as
+ // well.
+ bool m_dumpBackForwardList;
+
+ // If true, the test_shell will draw the bounds of the current selection rect
+ // taking possible transforms of the selection rect into account.
+ bool m_dumpSelectionRect;
+
+ // If true, pixel dump will be produced as a series of 1px-tall, view-wide
+ // individual paints over the height of the view.
+ bool m_testRepaint;
+
+ // If true and test_repaint_ is true as well, pixel dump will be produced as
+ // a series of 1px-wide, view-tall paints across the width of the view.
+ bool m_sweepHorizontally;
+
+ // If true, layout is to target printed pages.
+ bool m_isPrinting;
+
+ // If false, MockWebMIDIAccessor fails on startSession() for testing.
+ bool m_midiAccessorResult;
+
+ bool m_shouldStayOnPageAfterHandlingBeforeUnload;
+
+ bool m_shouldDumpResourcePriorities;
+
+ std::set<std::string> m_httpHeadersToClear;
+
+ // WAV audio data is stored here.
+ blink::WebArrayBufferView m_audioData;
+
+ // Used for test timeouts.
+ WebTaskList m_taskList;
+
+ TestInterfaces* m_testInterfaces;
+ WebTestDelegate* m_delegate;
+ blink::WebView* m_webView;
+ TestPageOverlay* m_pageOverlay;
+ WebTestProxyBase* m_proxy;
+
+ // This is non-0 IFF a load is in progress.
+ blink::WebFrame* m_topLoadingFrame;
+
+ // WebPermissionClient mock object.
+ WebScopedPtr<WebPermissions> m_webPermissions;
+
+ WebScopedPtr<NotificationPresenter> m_notificationPresenter;
+
+ bool m_pointerLocked;
+ enum {
+ PointerLockWillSucceed,
+ PointerLockWillRespondAsync,
+ PointerLockWillFailSync,
+ } m_pointerLockPlannedResult;
+};
+
+}
+
+#endif // TestRunner_h
diff --git a/content/shell/renderer/test_runner/TextInputController.cpp b/content/shell/renderer/test_runner/TextInputController.cpp
new file mode 100644
index 0000000..e2811a0
--- /dev/null
+++ b/content/shell/renderer/test_runner/TextInputController.cpp
@@ -0,0 +1,193 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/shell/renderer/test_runner/TextInputController.h"
+
+#include <string>
+#include "content/shell/renderer/test_runner/TestCommon.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/platform/WebVector.h"
+#include "third_party/WebKit/public/web/WebBindings.h"
+#include "third_party/WebKit/public/web/WebCompositionUnderline.h"
+#include "third_party/WebKit/public/web/WebFrame.h"
+#include "third_party/WebKit/public/web/WebInputEvent.h"
+#include "third_party/WebKit/public/web/WebRange.h"
+#include "third_party/WebKit/public/web/WebView.h"
+
+using namespace blink;
+using namespace std;
+
+namespace WebTestRunner {
+
+TextInputController::TextInputController()
+{
+ bindMethod("doCommand", &TextInputController::doCommand);
+ bindMethod("firstRectForCharacterRange", &TextInputController::firstRectForCharacterRange);
+ bindMethod("hasMarkedText", &TextInputController::hasMarkedText);
+ bindMethod("insertText", &TextInputController::insertText);
+ bindMethod("markedRange", &TextInputController::markedRange);
+ bindMethod("selectedRange", &TextInputController::selectedRange);
+ bindMethod("setMarkedText", &TextInputController::setMarkedText);
+ bindMethod("unmarkText", &TextInputController::unmarkText);
+ bindMethod("setComposition", &TextInputController::setComposition);
+}
+
+void TextInputController::insertText(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ if (arguments.size() < 1 || !arguments[0].isString())
+ return;
+
+ m_webView->confirmComposition(WebString::fromUTF8(arguments[0].toString()));
+}
+
+void TextInputController::doCommand(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ WebFrame* mainFrame = m_webView->mainFrame();
+ if (!mainFrame)
+ return;
+
+ if (arguments.size() >= 1 && arguments[0].isString())
+ mainFrame->executeCommand(WebString::fromUTF8(arguments[0].toString()));
+}
+
+void TextInputController::setMarkedText(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ if (arguments.size() < 3 || !arguments[0].isString()
+ || !arguments[1].isNumber() || !arguments[2].isNumber())
+ return;
+
+ WebString text(WebString::fromUTF8(arguments[0].toString()));
+ int start = arguments[1].toInt32();
+ int length = arguments[2].toInt32();
+
+ // Split underline into up to 3 elements (before, selection, and after).
+ vector<WebCompositionUnderline> underlines;
+ WebCompositionUnderline underline;
+ if (!start) {
+ underline.endOffset = length;
+ } else {
+ underline.endOffset = start;
+ underlines.push_back(underline);
+ underline.startOffset = start;
+ underline.endOffset = start + length;
+ }
+ underline.thick = true;
+ underlines.push_back(underline);
+ if (start + length < static_cast<int>(text.length())) {
+ underline.startOffset = underline.endOffset;
+ underline.endOffset = text.length();
+ underline.thick = false;
+ underlines.push_back(underline);
+ }
+
+ m_webView->setComposition(text, underlines, start, start + length);
+}
+
+void TextInputController::unmarkText(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+
+ m_webView->confirmComposition();
+}
+
+void TextInputController::hasMarkedText(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+
+ WebFrame* mainFrame = m_webView->mainFrame();
+ if (!mainFrame)
+ return;
+
+ result->set(mainFrame->hasMarkedText());
+}
+
+void TextInputController::markedRange(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+
+ WebFrame* mainFrame = m_webView->mainFrame();
+ if (!mainFrame)
+ return;
+
+ WebRange range = mainFrame->markedRange();
+ vector<int> intArray(2);
+ intArray[0] = range.startOffset();
+ intArray[1] = range.endOffset();
+
+ NPObject* resultArray = WebBindings::makeIntArray(intArray);
+ result->set(resultArray);
+ WebBindings::releaseObject(resultArray);
+}
+
+void TextInputController::selectedRange(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+
+ WebFrame* mainFrame = m_webView->mainFrame();
+ if (!mainFrame)
+ return;
+
+ WebRange range = mainFrame->selectionRange();
+ vector<int> intArray(2);
+ intArray[0] = range.startOffset();
+ intArray[1] = range.endOffset();
+
+ NPObject* resultArray = WebBindings::makeIntArray(intArray);
+ result->set(resultArray);
+ WebBindings::releaseObject(resultArray);
+}
+
+void TextInputController::firstRectForCharacterRange(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ WebFrame* frame = m_webView->focusedFrame();
+ if (!frame)
+ return;
+
+ if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isNumber())
+ return;
+
+ WebRect rect;
+ if (!frame->firstRectForCharacterRange(arguments[0].toInt32(), arguments[1].toInt32(), rect))
+ return;
+
+ vector<int> intArray(4);
+ intArray[0] = rect.x;
+ intArray[1] = rect.y;
+ intArray[2] = rect.width;
+ intArray[3] = rect.height;
+
+ NPObject* resultArray = WebBindings::makeIntArray(intArray);
+ result->set(resultArray);
+ WebBindings::releaseObject(resultArray);
+}
+
+void TextInputController::setComposition(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ if (arguments.size() < 1)
+ return;
+
+ // Sends a keydown event with key code = 0xE5 to emulate input method behavior.
+ WebKeyboardEvent keyDown;
+ keyDown.type = WebInputEvent::RawKeyDown;
+ keyDown.modifiers = 0;
+ keyDown.windowsKeyCode = 0xE5; // VKEY_PROCESSKEY
+ keyDown.setKeyIdentifierFromWindowsKeyCode();
+ m_webView->handleInputEvent(keyDown);
+
+ WebVector<WebCompositionUnderline> underlines;
+ WebString text(WebString::fromUTF8(arguments[0].toString()));
+ m_webView->setComposition(text, underlines, 0, text.length());
+}
+
+}
diff --git a/content/shell/renderer/test_runner/TextInputController.h b/content/shell/renderer/test_runner/TextInputController.h
new file mode 100644
index 0000000..2277f01
--- /dev/null
+++ b/content/shell/renderer/test_runner/TextInputController.h
@@ -0,0 +1,42 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// TextInputController is bound to window.textInputController in Javascript
+// when DRT is running. Layout tests use it to exercise various corners of
+// text input.
+
+#ifndef TextInputController_h
+#define TextInputController_h
+
+#include "content/shell/renderer/test_runner/CppBoundClass.h"
+
+namespace blink {
+class WebView;
+}
+
+namespace WebTestRunner {
+
+class TextInputController : public CppBoundClass {
+public:
+ TextInputController();
+
+ void setWebView(blink::WebView* webView) { m_webView = webView; }
+
+ void insertText(const CppArgumentList&, CppVariant*);
+ void doCommand(const CppArgumentList&, CppVariant*);
+ void setMarkedText(const CppArgumentList&, CppVariant*);
+ void unmarkText(const CppArgumentList&, CppVariant*);
+ void hasMarkedText(const CppArgumentList&, CppVariant*);
+ void markedRange(const CppArgumentList&, CppVariant*);
+ void selectedRange(const CppArgumentList&, CppVariant*);
+ void firstRectForCharacterRange(const CppArgumentList&, CppVariant*);
+ void setComposition(const CppArgumentList&, CppVariant*);
+
+private:
+ blink::WebView* m_webView;
+};
+
+}
+
+#endif // TextInputController_h
diff --git a/content/shell/renderer/test_runner/WebAXObjectProxy.cpp b/content/shell/renderer/test_runner/WebAXObjectProxy.cpp
new file mode 100644
index 0000000..993af65
--- /dev/null
+++ b/content/shell/renderer/test_runner/WebAXObjectProxy.cpp
@@ -0,0 +1,1161 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/shell/renderer/test_runner/WebAXObjectProxy.h"
+
+#include "content/shell/renderer/test_runner/TestCommon.h"
+#include "third_party/WebKit/public/platform/WebCString.h"
+#include "third_party/WebKit/public/platform/WebPoint.h"
+#include "third_party/WebKit/public/platform/WebRect.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+
+using namespace blink;
+using namespace std;
+
+namespace WebTestRunner {
+
+namespace {
+
+// Map role value to string, matching Safari/Mac platform implementation to
+// avoid rebaselining layout tests.
+string roleToString(WebAXRole role)
+{
+ string result = "AXRole: AX";
+ switch (role) {
+ case WebAXRoleAlertDialog:
+ return result.append("AlertDialog");
+ case WebAXRoleAlert:
+ return result.append("Alert");
+ case WebAXRoleAnnotation:
+ return result.append("Annotation");
+ case WebAXRoleApplication:
+ return result.append("Application");
+ case WebAXRoleArticle:
+ return result.append("Article");
+ case WebAXRoleBanner:
+ return result.append("Banner");
+ case WebAXRoleBrowser:
+ return result.append("Browser");
+ case WebAXRoleBusyIndicator:
+ return result.append("BusyIndicator");
+ case WebAXRoleButton:
+ return result.append("Button");
+ case WebAXRoleCanvas:
+ return result.append("Canvas");
+ case WebAXRoleCell:
+ return result.append("Cell");
+ case WebAXRoleCheckBox:
+ return result.append("CheckBox");
+ case WebAXRoleColorWell:
+ return result.append("ColorWell");
+ case WebAXRoleColumnHeader:
+ return result.append("ColumnHeader");
+ case WebAXRoleColumn:
+ return result.append("Column");
+ case WebAXRoleComboBox:
+ return result.append("ComboBox");
+ case WebAXRoleComplementary:
+ return result.append("Complementary");
+ case WebAXRoleContentInfo:
+ return result.append("ContentInfo");
+ case WebAXRoleDefinition:
+ return result.append("Definition");
+ case WebAXRoleDescriptionListDetail:
+ return result.append("DescriptionListDetail");
+ case WebAXRoleDescriptionListTerm:
+ return result.append("DescriptionListTerm");
+ case WebAXRoleDialog:
+ return result.append("Dialog");
+ case WebAXRoleDirectory:
+ return result.append("Directory");
+ case WebAXRoleDisclosureTriangle:
+ return result.append("DisclosureTriangle");
+ case WebAXRoleDiv:
+ return result.append("Div");
+ case WebAXRoleDocument:
+ return result.append("Document");
+ case WebAXRoleDrawer:
+ return result.append("Drawer");
+ case WebAXRoleEditableText:
+ return result.append("EditableText");
+ case WebAXRoleFooter:
+ return result.append("Footer");
+ case WebAXRoleForm:
+ return result.append("Form");
+ case WebAXRoleGrid:
+ return result.append("Grid");
+ case WebAXRoleGroup:
+ return result.append("Group");
+ case WebAXRoleGrowArea:
+ return result.append("GrowArea");
+ case WebAXRoleHeading:
+ return result.append("Heading");
+ case WebAXRoleHelpTag:
+ return result.append("HelpTag");
+ case WebAXRoleHorizontalRule:
+ return result.append("HorizontalRule");
+ case WebAXRoleIgnored:
+ return result.append("Ignored");
+ case WebAXRoleImageMapLink:
+ return result.append("ImageMapLink");
+ case WebAXRoleImageMap:
+ return result.append("ImageMap");
+ case WebAXRoleImage:
+ return result.append("Image");
+ case WebAXRoleIncrementor:
+ return result.append("Incrementor");
+ case WebAXRoleInlineTextBox:
+ return result.append("InlineTextBox");
+ case WebAXRoleLabel:
+ return result.append("Label");
+ case WebAXRoleLegend:
+ return result.append("Legend");
+ case WebAXRoleLink:
+ return result.append("Link");
+ case WebAXRoleListBoxOption:
+ return result.append("ListBoxOption");
+ case WebAXRoleListBox:
+ return result.append("ListBox");
+ case WebAXRoleListItem:
+ return result.append("ListItem");
+ case WebAXRoleListMarker:
+ return result.append("ListMarker");
+ case WebAXRoleList:
+ return result.append("List");
+ case WebAXRoleLog:
+ return result.append("Log");
+ case WebAXRoleMain:
+ return result.append("Main");
+ case WebAXRoleMarquee:
+ return result.append("Marquee");
+ case WebAXRoleMathElement:
+ return result.append("MathElement");
+ case WebAXRoleMath:
+ return result.append("Math");
+ case WebAXRoleMatte:
+ return result.append("Matte");
+ case WebAXRoleMenuBar:
+ return result.append("MenuBar");
+ case WebAXRoleMenuButton:
+ return result.append("MenuButton");
+ case WebAXRoleMenuItem:
+ return result.append("MenuItem");
+ case WebAXRoleMenuListOption:
+ return result.append("MenuListOption");
+ case WebAXRoleMenuListPopup:
+ return result.append("MenuListPopup");
+ case WebAXRoleMenu:
+ return result.append("Menu");
+ case WebAXRoleNavigation:
+ return result.append("Navigation");
+ case WebAXRoleNote:
+ return result.append("Note");
+ case WebAXRoleOutline:
+ return result.append("Outline");
+ case WebAXRoleParagraph:
+ return result.append("Paragraph");
+ case WebAXRolePopUpButton:
+ return result.append("PopUpButton");
+ case WebAXRolePresentational:
+ return result.append("Presentational");
+ case WebAXRoleProgressIndicator:
+ return result.append("ProgressIndicator");
+ case WebAXRoleRadioButton:
+ return result.append("RadioButton");
+ case WebAXRoleRadioGroup:
+ return result.append("RadioGroup");
+ case WebAXRoleRegion:
+ return result.append("Region");
+ case WebAXRoleRootWebArea:
+ return result.append("RootWebArea");
+ case WebAXRoleRowHeader:
+ return result.append("RowHeader");
+ case WebAXRoleRow:
+ return result.append("Row");
+ case WebAXRoleRulerMarker:
+ return result.append("RulerMarker");
+ case WebAXRoleRuler:
+ return result.append("Ruler");
+ case WebAXRoleSVGRoot:
+ return result.append("SVGRoot");
+ case WebAXRoleScrollArea:
+ return result.append("ScrollArea");
+ case WebAXRoleScrollBar:
+ return result.append("ScrollBar");
+ case WebAXRoleSeamlessWebArea:
+ return result.append("SeamlessWebArea");
+ case WebAXRoleSearch:
+ return result.append("Search");
+ case WebAXRoleSheet:
+ return result.append("Sheet");
+ case WebAXRoleSlider:
+ return result.append("Slider");
+ case WebAXRoleSliderThumb:
+ return result.append("SliderThumb");
+ case WebAXRoleSpinButtonPart:
+ return result.append("SpinButtonPart");
+ case WebAXRoleSpinButton:
+ return result.append("SpinButton");
+ case WebAXRoleSplitGroup:
+ return result.append("SplitGroup");
+ case WebAXRoleSplitter:
+ return result.append("Splitter");
+ case WebAXRoleStaticText:
+ return result.append("StaticText");
+ case WebAXRoleStatus:
+ return result.append("Status");
+ case WebAXRoleSystemWide:
+ return result.append("SystemWide");
+ case WebAXRoleTabGroup:
+ return result.append("TabGroup");
+ case WebAXRoleTabList:
+ return result.append("TabList");
+ case WebAXRoleTabPanel:
+ return result.append("TabPanel");
+ case WebAXRoleTab:
+ return result.append("Tab");
+ case WebAXRoleTableHeaderContainer:
+ return result.append("TableHeaderContainer");
+ case WebAXRoleTable:
+ return result.append("Table");
+ case WebAXRoleTextArea:
+ return result.append("TextArea");
+ case WebAXRoleTextField:
+ return result.append("TextField");
+ case WebAXRoleTimer:
+ return result.append("Timer");
+ case WebAXRoleToggleButton:
+ return result.append("ToggleButton");
+ case WebAXRoleToolbar:
+ return result.append("Toolbar");
+ case WebAXRoleTreeGrid:
+ return result.append("TreeGrid");
+ case WebAXRoleTreeItem:
+ return result.append("TreeItem");
+ case WebAXRoleTree:
+ return result.append("Tree");
+ case WebAXRoleUnknown:
+ return result.append("Unknown");
+ case WebAXRoleUserInterfaceTooltip:
+ return result.append("UserInterfaceTooltip");
+ case WebAXRoleValueIndicator:
+ return result.append("ValueIndicator");
+ case WebAXRoleWebArea:
+ return result.append("WebArea");
+ case WebAXRoleWindow:
+ return result.append("Window");
+ default:
+ return result.append("Unknown");
+ }
+}
+
+string getDescription(const WebAXObject& object)
+{
+ string description = object.accessibilityDescription().utf8();
+ return description.insert(0, "AXDescription: ");
+}
+
+string getHelpText(const WebAXObject& object)
+{
+ string helpText = object.helpText().utf8();
+ return helpText.insert(0, "AXHelp: ");
+}
+
+string getStringValue(const WebAXObject& object)
+{
+ string value;
+ if (object.role() == WebAXRoleColorWell) {
+ int r, g, b;
+ char buffer[100];
+ object.colorValue(r, g, b);
+ snprintf(buffer, sizeof(buffer), "rgb %7.5f %7.5f %7.5f 1", r / 255., g / 255., b / 255.);
+ value = buffer;
+ } else {
+ value = object.stringValue().utf8();
+ }
+ return value.insert(0, "AXValue: ");
+}
+
+string getRole(const WebAXObject& object)
+{
+ string roleString = roleToString(object.role());
+
+ // Special-case canvas with fallback content because Chromium wants to
+ // treat this as essentially a separate role that it can map differently depending
+ // on the platform.
+ if (object.role() == WebAXRoleCanvas && object.canvasHasFallbackContent())
+ roleString += "WithFallbackContent";
+
+ return roleString;
+}
+
+string getTitle(const WebAXObject& object)
+{
+ string title = object.title().utf8();
+ return title.insert(0, "AXTitle: ");
+}
+
+string getOrientation(const WebAXObject& object)
+{
+ if (object.isVertical())
+ return "AXOrientation: AXVerticalOrientation";
+
+ return "AXOrientation: AXHorizontalOrientation";
+}
+
+string getValueDescription(const WebAXObject& object)
+{
+ string valueDescription = object.valueDescription().utf8();
+ return valueDescription.insert(0, "AXValueDescription: ");
+}
+
+string getAttributes(const WebAXObject& object)
+{
+ // FIXME: Concatenate all attributes of the AXObject.
+ string attributes(getTitle(object));
+ attributes.append("\n");
+ attributes.append(getRole(object));
+ attributes.append("\n");
+ attributes.append(getDescription(object));
+ return attributes;
+}
+
+WebRect boundsForCharacter(const WebAXObject& object, int characterIndex)
+{
+ BLINK_ASSERT(object.role() == WebAXRoleStaticText);
+ int end = 0;
+ for (unsigned i = 0; i < object.childCount(); i++) {
+ WebAXObject inlineTextBox = object.childAt(i);
+ BLINK_ASSERT(inlineTextBox.role() == WebAXRoleInlineTextBox);
+ int start = end;
+ end += inlineTextBox.stringValue().length();
+ if (end <= characterIndex)
+ continue;
+ WebRect inlineTextBoxRect = inlineTextBox.boundingBoxRect();
+ int localIndex = characterIndex - start;
+ WebVector<int> characterOffsets;
+ inlineTextBox.characterOffsets(characterOffsets);
+ BLINK_ASSERT(characterOffsets.size() > 0 && characterOffsets.size() == inlineTextBox.stringValue().length());
+ switch (inlineTextBox.textDirection()) {
+ case WebAXTextDirectionLR: {
+ if (localIndex) {
+ int left = inlineTextBoxRect.x + characterOffsets[localIndex - 1];
+ int width = characterOffsets[localIndex] - characterOffsets[localIndex - 1];
+ return WebRect(left, inlineTextBoxRect.y, width, inlineTextBoxRect.height);
+ }
+ return WebRect(inlineTextBoxRect.x, inlineTextBoxRect.y, characterOffsets[0], inlineTextBoxRect.height);
+ }
+ case WebAXTextDirectionRL: {
+ int right = inlineTextBoxRect.x + inlineTextBoxRect.width;
+
+ if (localIndex) {
+ int left = right - characterOffsets[localIndex];
+ int width = characterOffsets[localIndex] - characterOffsets[localIndex - 1];
+ return WebRect(left, inlineTextBoxRect.y, width, inlineTextBoxRect.height);
+ }
+ int left = right - characterOffsets[0];
+ return WebRect(left, inlineTextBoxRect.y, characterOffsets[0], inlineTextBoxRect.height);
+ }
+ case WebAXTextDirectionTB: {
+ if (localIndex) {
+ int top = inlineTextBoxRect.y + characterOffsets[localIndex - 1];
+ int height = characterOffsets[localIndex] - characterOffsets[localIndex - 1];
+ return WebRect(inlineTextBoxRect.x, top, inlineTextBoxRect.width, height);
+ }
+ return WebRect(inlineTextBoxRect.x, inlineTextBoxRect.y, inlineTextBoxRect.width, characterOffsets[0]);
+ }
+ case WebAXTextDirectionBT: {
+ int bottom = inlineTextBoxRect.y + inlineTextBoxRect.height;
+
+ if (localIndex) {
+ int top = bottom - characterOffsets[localIndex];
+ int height = characterOffsets[localIndex] - characterOffsets[localIndex - 1];
+ return WebRect(inlineTextBoxRect.x, top, inlineTextBoxRect.width, height);
+ }
+ int top = bottom - characterOffsets[0];
+ return WebRect(inlineTextBoxRect.x, top, inlineTextBoxRect.width, characterOffsets[0]);
+ }
+ }
+ }
+
+ BLINK_ASSERT(false);
+ return WebRect();
+}
+
+void getBoundariesForOneWord(const WebAXObject& object, int characterIndex, int& wordStart, int& wordEnd)
+{
+ int end = 0;
+ for (unsigned i = 0; i < object.childCount(); i++) {
+ WebAXObject inlineTextBox = object.childAt(i);
+ BLINK_ASSERT(inlineTextBox.role() == WebAXRoleInlineTextBox);
+ int start = end;
+ end += inlineTextBox.stringValue().length();
+ if (end <= characterIndex)
+ continue;
+ int localIndex = characterIndex - start;
+
+ WebVector<int> starts;
+ WebVector<int> ends;
+ inlineTextBox.wordBoundaries(starts, ends);
+ size_t wordCount = starts.size();
+ BLINK_ASSERT(ends.size() == wordCount);
+
+ // If there are no words, use the InlineTextBox boundaries.
+ if (!wordCount) {
+ wordStart = start;
+ wordEnd = end;
+ return;
+ }
+
+ // Look for a character within any word other than the last.
+ for (size_t j = 0; j < wordCount - 1; j++) {
+ if (localIndex <= ends[j]) {
+ wordStart = start + starts[j];
+ wordEnd = start + ends[j];
+ return;
+ }
+ }
+
+ // Return the last word by default.
+ wordStart = start + starts[wordCount - 1];
+ wordEnd = start + ends[wordCount - 1];
+ return;
+ }
+}
+
+// Collects attributes into a string, delimited by dashes. Used by all methods
+// that output lists of attributes: attributesOfLinkedUIElementsCallback,
+// AttributesOfChildrenCallback, etc.
+class AttributesCollector {
+public:
+ void collectAttributes(const WebAXObject& object)
+ {
+ m_attributes.append("\n------------\n");
+ m_attributes.append(getAttributes(object));
+ }
+
+ string attributes() const { return m_attributes; }
+
+private:
+ string m_attributes;
+};
+
+}
+
+WebAXObjectProxy::WebAXObjectProxy(const WebAXObject& object, Factory* factory)
+ : m_accessibilityObject(object)
+ , m_factory(factory)
+{
+
+ BLINK_ASSERT(factory);
+
+ //
+ // Properties
+ //
+
+ bindProperty("role", &WebAXObjectProxy::roleGetterCallback);
+ bindProperty("title", &WebAXObjectProxy::titleGetterCallback);
+ bindProperty("description", &WebAXObjectProxy::descriptionGetterCallback);
+ bindProperty("helpText", &WebAXObjectProxy::helpTextGetterCallback);
+ bindProperty("stringValue", &WebAXObjectProxy::stringValueGetterCallback);
+ bindProperty("x", &WebAXObjectProxy::xGetterCallback);
+ bindProperty("y", &WebAXObjectProxy::yGetterCallback);
+ bindProperty("width", &WebAXObjectProxy::widthGetterCallback);
+ bindProperty("height", &WebAXObjectProxy::heightGetterCallback);
+ bindProperty("intValue", &WebAXObjectProxy::intValueGetterCallback);
+ bindProperty("minValue", &WebAXObjectProxy::minValueGetterCallback);
+ bindProperty("maxValue", &WebAXObjectProxy::maxValueGetterCallback);
+ bindProperty("valueDescription", &WebAXObjectProxy::valueDescriptionGetterCallback);
+ bindProperty("childrenCount", &WebAXObjectProxy::childrenCountGetterCallback);
+ bindProperty("insertionPointLineNumber", &WebAXObjectProxy::insertionPointLineNumberGetterCallback);
+ bindProperty("selectedTextRange", &WebAXObjectProxy::selectedTextRangeGetterCallback);
+ bindProperty("isEnabled", &WebAXObjectProxy::isEnabledGetterCallback);
+ bindProperty("isRequired", &WebAXObjectProxy::isRequiredGetterCallback);
+ bindProperty("isFocused", &WebAXObjectProxy::isFocusedGetterCallback);
+ bindProperty("isFocusable", &WebAXObjectProxy::isFocusableGetterCallback);
+ bindProperty("isSelected", &WebAXObjectProxy::isSelectedGetterCallback);
+ bindProperty("isSelectable", &WebAXObjectProxy::isSelectableGetterCallback);
+ bindProperty("isMultiSelectable", &WebAXObjectProxy::isMultiSelectableGetterCallback);
+ bindProperty("isSelectedOptionActive", &WebAXObjectProxy::isSelectedOptionActiveGetterCallback);
+ bindProperty("isExpanded", &WebAXObjectProxy::isExpandedGetterCallback);
+ bindProperty("isChecked", &WebAXObjectProxy::isCheckedGetterCallback);
+ bindProperty("isVisible", &WebAXObjectProxy::isVisibleGetterCallback);
+ bindProperty("isOffScreen", &WebAXObjectProxy::isOffScreenGetterCallback);
+ bindProperty("isCollapsed", &WebAXObjectProxy::isCollapsedGetterCallback);
+ bindProperty("hasPopup", &WebAXObjectProxy::hasPopupGetterCallback);
+ bindProperty("isValid", &WebAXObjectProxy::isValidGetterCallback);
+ bindProperty("isReadOnly", &WebAXObjectProxy::isReadOnlyGetterCallback);
+ bindProperty("orientation", &WebAXObjectProxy::orientationGetterCallback);
+ bindProperty("clickPointX", &WebAXObjectProxy::clickPointXGetterCallback);
+ bindProperty("clickPointY", &WebAXObjectProxy::clickPointYGetterCallback);
+ bindProperty("rowCount", &WebAXObjectProxy::rowCountGetterCallback);
+ bindProperty("columnCount", &WebAXObjectProxy::columnCountGetterCallback);
+ bindProperty("isClickable", &WebAXObjectProxy::isClickableGetterCallback);
+
+ //
+ // Methods
+ //
+
+ bindMethod("allAttributes", &WebAXObjectProxy::allAttributesCallback);
+ bindMethod("attributesOfChildren", &WebAXObjectProxy::attributesOfChildrenCallback);
+ bindMethod("lineForIndex", &WebAXObjectProxy::lineForIndexCallback);
+ bindMethod("boundsForRange", &WebAXObjectProxy::boundsForRangeCallback);
+ bindMethod("childAtIndex", &WebAXObjectProxy::childAtIndexCallback);
+ bindMethod("elementAtPoint", &WebAXObjectProxy::elementAtPointCallback);
+ bindMethod("tableHeader", &WebAXObjectProxy::tableHeaderCallback);
+ bindMethod("rowIndexRange", &WebAXObjectProxy::rowIndexRangeCallback);
+ bindMethod("columnIndexRange", &WebAXObjectProxy::columnIndexRangeCallback);
+ bindMethod("cellForColumnAndRow", &WebAXObjectProxy::cellForColumnAndRowCallback);
+ bindMethod("titleUIElement", &WebAXObjectProxy::titleUIElementCallback);
+ bindMethod("setSelectedTextRange", &WebAXObjectProxy::setSelectedTextRangeCallback);
+ bindMethod("isAttributeSettable", &WebAXObjectProxy::isAttributeSettableCallback);
+ bindMethod("isPressActionSupported", &WebAXObjectProxy::isPressActionSupportedCallback);
+ bindMethod("isIncrementActionSupported", &WebAXObjectProxy::isIncrementActionSupportedCallback);
+ bindMethod("isDecrementActionSupported", &WebAXObjectProxy::isDecrementActionSupportedCallback);
+ bindMethod("parentElement", &WebAXObjectProxy::parentElementCallback);
+ bindMethod("increment", &WebAXObjectProxy::incrementCallback);
+ bindMethod("decrement", &WebAXObjectProxy::decrementCallback);
+ bindMethod("showMenu", &WebAXObjectProxy::showMenuCallback);
+ bindMethod("press", &WebAXObjectProxy::pressCallback);
+ bindMethod("isEqual", &WebAXObjectProxy::isEqualCallback);
+ bindMethod("addNotificationListener", &WebAXObjectProxy::addNotificationListenerCallback);
+ bindMethod("removeNotificationListener", &WebAXObjectProxy::removeNotificationListenerCallback);
+ bindMethod("takeFocus", &WebAXObjectProxy::takeFocusCallback);
+ bindMethod("scrollToMakeVisible", &WebAXObjectProxy::scrollToMakeVisibleCallback);
+ bindMethod("scrollToMakeVisibleWithSubFocus", &WebAXObjectProxy::scrollToMakeVisibleWithSubFocusCallback);
+ bindMethod("scrollToGlobalPoint", &WebAXObjectProxy::scrollToGlobalPointCallback);
+ bindMethod("wordStart", &WebAXObjectProxy::wordStartCallback);
+ bindMethod("wordEnd", &WebAXObjectProxy::wordEndCallback);
+
+ bindFallbackMethod(&WebAXObjectProxy::fallbackCallback);
+}
+
+WebAXObjectProxy* WebAXObjectProxy::getChildAtIndex(unsigned index)
+{
+ return m_factory->getOrCreate(accessibilityObject().childAt(index));
+}
+
+bool WebAXObjectProxy::isEqual(const blink::WebAXObject& other)
+{
+ return accessibilityObject().equals(other);
+}
+
+void WebAXObjectProxy::notificationReceived(const char* notificationName)
+{
+ size_t callbackCount = m_notificationCallbacks.size();
+ for (size_t i = 0; i < callbackCount; i++) {
+ CppVariant notificationNameArgument;
+ notificationNameArgument.set(notificationName);
+ CppVariant invokeResult;
+ m_notificationCallbacks[i].invokeDefault(&notificationNameArgument, 1, invokeResult);
+ }
+}
+
+//
+// Properties
+//
+
+void WebAXObjectProxy::roleGetterCallback(CppVariant* result)
+{
+ result->set(getRole(accessibilityObject()));
+}
+
+void WebAXObjectProxy::titleGetterCallback(CppVariant* result)
+{
+ result->set(getTitle(accessibilityObject()));
+}
+
+void WebAXObjectProxy::descriptionGetterCallback(CppVariant* result)
+{
+ result->set(getDescription(accessibilityObject()));
+}
+
+void WebAXObjectProxy::helpTextGetterCallback(CppVariant* result)
+{
+ result->set(getHelpText(accessibilityObject()));
+}
+
+void WebAXObjectProxy::stringValueGetterCallback(CppVariant* result)
+{
+ result->set(getStringValue(accessibilityObject()));
+}
+
+void WebAXObjectProxy::xGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().boundingBoxRect().x);
+}
+
+void WebAXObjectProxy::yGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().boundingBoxRect().y);
+}
+
+void WebAXObjectProxy::widthGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().boundingBoxRect().width);
+}
+
+void WebAXObjectProxy::heightGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().boundingBoxRect().height);
+}
+
+void WebAXObjectProxy::intValueGetterCallback(CppVariant* result)
+{
+ if (accessibilityObject().supportsRangeValue())
+ result->set(accessibilityObject().valueForRange());
+ else if (accessibilityObject().role() == WebAXRoleHeading)
+ result->set(accessibilityObject().headingLevel());
+ else
+ result->set(atoi(accessibilityObject().stringValue().utf8().data()));
+}
+
+void WebAXObjectProxy::minValueGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().minValueForRange());
+}
+
+void WebAXObjectProxy::maxValueGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().maxValueForRange());
+}
+
+void WebAXObjectProxy::valueDescriptionGetterCallback(CppVariant* result)
+{
+ result->set(getValueDescription(accessibilityObject()));
+}
+
+void WebAXObjectProxy::childrenCountGetterCallback(CppVariant* result)
+{
+ int count = 1; // Root object always has only one child, the WebView.
+ if (!isRoot())
+ count = accessibilityObject().childCount();
+ result->set(count);
+}
+
+void WebAXObjectProxy::insertionPointLineNumberGetterCallback(CppVariant* result)
+{
+ if (!accessibilityObject().isFocused()) {
+ result->set(-1);
+ return;
+ }
+
+ int lineNumber = accessibilityObject().selectionEndLineNumber();
+ result->set(lineNumber);
+}
+
+void WebAXObjectProxy::selectedTextRangeGetterCallback(CppVariant* result)
+{
+ unsigned selectionStart = accessibilityObject().selectionStart();
+ unsigned selectionEnd = accessibilityObject().selectionEnd();
+ char buffer[100];
+ snprintf(buffer, sizeof(buffer), "{%d, %d}", selectionStart, selectionEnd - selectionStart);
+
+ result->set(std::string(buffer));
+}
+
+void WebAXObjectProxy::isEnabledGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().isEnabled());
+}
+
+void WebAXObjectProxy::isRequiredGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().isRequired());
+}
+
+void WebAXObjectProxy::isFocusedGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().isFocused());
+}
+
+void WebAXObjectProxy::isFocusableGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().canSetFocusAttribute());
+}
+
+void WebAXObjectProxy::isSelectedGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().isSelected());
+}
+
+void WebAXObjectProxy::isSelectableGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().canSetSelectedAttribute());
+}
+
+void WebAXObjectProxy::isMultiSelectableGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().isMultiSelectable());
+}
+
+void WebAXObjectProxy::isSelectedOptionActiveGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().isSelectedOptionActive());
+}
+
+void WebAXObjectProxy::isExpandedGetterCallback(CppVariant* result)
+{
+ result->set(!accessibilityObject().isCollapsed());
+}
+
+void WebAXObjectProxy::isCheckedGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().isChecked());
+}
+
+void WebAXObjectProxy::isVisibleGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().isVisible());
+}
+
+void WebAXObjectProxy::isOffScreenGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().isOffScreen());
+}
+
+void WebAXObjectProxy::isCollapsedGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().isCollapsed());
+}
+
+void WebAXObjectProxy::hasPopupGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().ariaHasPopup());
+}
+
+void WebAXObjectProxy::isValidGetterCallback(CppVariant* result)
+{
+ result->set(!accessibilityObject().isDetached());
+}
+
+void WebAXObjectProxy::isReadOnlyGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().isReadOnly());
+}
+
+void WebAXObjectProxy::orientationGetterCallback(CppVariant* result)
+{
+ result->set(getOrientation(accessibilityObject()));
+}
+
+void WebAXObjectProxy::clickPointXGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().clickPoint().x);
+}
+
+void WebAXObjectProxy::clickPointYGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().clickPoint().y);
+}
+
+void WebAXObjectProxy::rowCountGetterCallback(CppVariant* result)
+{
+ result->set(static_cast<int32_t>(accessibilityObject().rowCount()));
+}
+
+void WebAXObjectProxy::columnCountGetterCallback(CppVariant* result)
+{
+ result->set(static_cast<int32_t>(accessibilityObject().columnCount()));
+}
+
+void WebAXObjectProxy::isClickableGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().isClickable());
+}
+
+//
+// Methods
+//
+
+void WebAXObjectProxy::allAttributesCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->set(getAttributes(accessibilityObject()));
+}
+
+void WebAXObjectProxy::attributesOfChildrenCallback(const CppArgumentList& arguments, CppVariant* result)
+{
+ AttributesCollector collector;
+ unsigned size = accessibilityObject().childCount();
+ for (unsigned i = 0; i < size; ++i)
+ collector.collectAttributes(accessibilityObject().childAt(i));
+ result->set(collector.attributes());
+}
+
+void WebAXObjectProxy::lineForIndexCallback(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (!arguments.size() || !arguments[0].isNumber()) {
+ result->setNull();
+ return;
+ }
+
+ int index = arguments[0].toInt32();
+
+ WebVector<int> lineBreaks;
+ accessibilityObject().lineBreaks(lineBreaks);
+ int line = 0;
+ int vectorSize = static_cast<int>(lineBreaks.size());
+ while (line < vectorSize && lineBreaks[line] <= index)
+ line++;
+ result->set(line);
+}
+
+void WebAXObjectProxy::boundsForRangeCallback(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ if (arguments.size() != 2 || !arguments[0].isNumber() || !arguments[1].isNumber())
+ return;
+
+ if (accessibilityObject().role() != WebAXRoleStaticText)
+ return;
+
+ int start = arguments[0].toInt32();
+ int end = arguments[1].toInt32();
+ int len = end - start;
+
+ // Get the bounds for each character and union them into one large rectangle.
+ // This is just for testing so it doesn't need to be efficient.
+ WebRect bounds = boundsForCharacter(accessibilityObject(), start);
+ for (int i = 1; i < len; i++) {
+ WebRect next = boundsForCharacter(accessibilityObject(), start + i);
+ int right = std::max(bounds.x + bounds.width, next.x + next.width);
+ int bottom = std::max(bounds.y + bounds.height, next.y + next.height);
+ bounds.x = std::min(bounds.x, next.x);
+ bounds.y = std::min(bounds.y, next.y);
+ bounds.width = right - bounds.x;
+ bounds.height = bottom - bounds.y;
+ }
+
+ char buffer[100];
+ snprintf(buffer, sizeof(buffer), "{x: %d, y: %d, width: %d, height: %d}", bounds.x, bounds.y, bounds.width, bounds.height);
+ result->set(string(buffer));
+}
+
+void WebAXObjectProxy::childAtIndexCallback(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (!arguments.size() || !arguments[0].isNumber()) {
+ result->setNull();
+ return;
+ }
+
+ WebAXObjectProxy* child = getChildAtIndex(arguments[0].toInt32());
+ if (!child) {
+ result->setNull();
+ return;
+ }
+
+ result->set(*(child->getAsCppVariant()));
+}
+
+void WebAXObjectProxy::elementAtPointCallback(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ if (arguments.size() != 2 || !arguments[0].isNumber() || !arguments[1].isNumber())
+ return;
+
+ int x = arguments[0].toInt32();
+ int y = arguments[1].toInt32();
+ WebPoint point(x, y);
+ WebAXObject obj = accessibilityObject().hitTest(point);
+ if (obj.isNull())
+ return;
+
+ result->set(*(m_factory->getOrCreate(obj)->getAsCppVariant()));
+}
+
+void WebAXObjectProxy::tableHeaderCallback(const CppArgumentList&, CppVariant* result)
+{
+ WebAXObject obj = accessibilityObject().headerContainerObject();
+ if (obj.isNull()) {
+ result->setNull();
+ return;
+ }
+
+ result->set(*(m_factory->getOrCreate(obj)->getAsCppVariant()));
+}
+
+void WebAXObjectProxy::rowIndexRangeCallback(const CppArgumentList&, CppVariant* result)
+{
+ unsigned rowIndex = accessibilityObject().cellRowIndex();
+ unsigned rowSpan = accessibilityObject().cellRowSpan();
+ char buffer[100];
+ snprintf(buffer, sizeof(buffer), "{%d, %d}", rowIndex, rowSpan);
+ string value = buffer;
+ result->set(std::string(buffer));
+}
+
+void WebAXObjectProxy::columnIndexRangeCallback(const CppArgumentList&, CppVariant* result)
+{
+ unsigned columnIndex = accessibilityObject().cellColumnIndex();
+ unsigned columnSpan = accessibilityObject().cellColumnSpan();
+ char buffer[100];
+ snprintf(buffer, sizeof(buffer), "{%d, %d}", columnIndex, columnSpan);
+ result->set(std::string(buffer));
+}
+
+void WebAXObjectProxy::cellForColumnAndRowCallback(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() != 2 || !arguments[0].isNumber() || !arguments[1].isNumber())
+ return;
+
+ int column = arguments[0].toInt32();
+ int row = arguments[1].toInt32();
+ WebAXObject obj = accessibilityObject().cellForColumnAndRow(column, row);
+ if (obj.isNull()) {
+ result->setNull();
+ return;
+ }
+
+ result->set(*(m_factory->getOrCreate(obj)->getAsCppVariant()));
+}
+
+void WebAXObjectProxy::titleUIElementCallback(const CppArgumentList&, CppVariant* result)
+{
+ WebAXObject obj = accessibilityObject().titleUIElement();
+ if (obj.isNull()) {
+ result->setNull();
+ return;
+ }
+
+ result->set(*(m_factory->getOrCreate(obj)->getAsCppVariant()));
+}
+
+void WebAXObjectProxy::setSelectedTextRangeCallback(const CppArgumentList&arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() != 2 || !arguments[0].isNumber() || !arguments[1].isNumber())
+ return;
+
+ int selectionStart = arguments[0].toInt32();
+ int selectionEnd = selectionStart + arguments[1].toInt32();
+ accessibilityObject().setSelectedTextRange(selectionStart, selectionEnd);
+}
+
+void WebAXObjectProxy::isAttributeSettableCallback(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() < 1 && !arguments[0].isString()) {
+ result->setNull();
+ return;
+ }
+
+ string attribute = arguments[0].toString();
+ bool settable = false;
+ if (attribute == "AXValue")
+ settable = accessibilityObject().canSetValueAttribute();
+ result->set(settable);
+}
+
+void WebAXObjectProxy::isPressActionSupportedCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->set(accessibilityObject().canPress());
+}
+
+void WebAXObjectProxy::isIncrementActionSupportedCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->set(accessibilityObject().canIncrement());
+}
+
+void WebAXObjectProxy::isDecrementActionSupportedCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->set(accessibilityObject().canDecrement());
+}
+
+void WebAXObjectProxy::parentElementCallback(const CppArgumentList&, CppVariant* result)
+{
+ WebAXObject parentObject = accessibilityObject().parentObject();
+ while (parentObject.accessibilityIsIgnored())
+ parentObject = parentObject.parentObject();
+ WebAXObjectProxy* parent = m_factory->getOrCreate(parentObject);
+ if (!parent) {
+ result->setNull();
+ return;
+ }
+
+ result->set(*(parent->getAsCppVariant()));
+}
+
+void WebAXObjectProxy::incrementCallback(const CppArgumentList&, CppVariant* result)
+{
+ accessibilityObject().increment();
+ result->setNull();
+}
+
+void WebAXObjectProxy::decrementCallback(const CppArgumentList&, CppVariant* result)
+{
+ accessibilityObject().decrement();
+ result->setNull();
+}
+
+void WebAXObjectProxy::showMenuCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void WebAXObjectProxy::pressCallback(const CppArgumentList&, CppVariant* result)
+{
+ accessibilityObject().press();
+ result->setNull();
+}
+
+void WebAXObjectProxy::isEqualCallback(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() < 1 || !arguments[0].isObject()) {
+ result->setNull();
+ return;
+ }
+
+ result->set(arguments[0].isEqual(*getAsCppVariant()));
+}
+
+void WebAXObjectProxy::addNotificationListenerCallback(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() < 1 || !arguments[0].isObject()) {
+ result->setNull();
+ return;
+ }
+
+ m_notificationCallbacks.push_back(arguments[0]);
+ result->setNull();
+}
+
+void WebAXObjectProxy::removeNotificationListenerCallback(const CppArgumentList&, CppVariant* result)
+{
+ // FIXME: Implement this.
+ result->setNull();
+}
+
+void WebAXObjectProxy::takeFocusCallback(const CppArgumentList&, CppVariant* result)
+{
+ accessibilityObject().setFocused(true);
+ result->setNull();
+}
+
+void WebAXObjectProxy::scrollToMakeVisibleCallback(const CppArgumentList&, CppVariant* result)
+{
+ accessibilityObject().scrollToMakeVisible();
+ result->setNull();
+}
+
+void WebAXObjectProxy::scrollToMakeVisibleWithSubFocusCallback(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ if (arguments.size() != 4
+ || !arguments[0].isNumber()
+ || !arguments[1].isNumber()
+ || !arguments[2].isNumber()
+ || !arguments[3].isNumber())
+ return;
+
+ int x = arguments[0].toInt32();
+ int y = arguments[1].toInt32();
+ int width = arguments[2].toInt32();
+ int height = arguments[3].toInt32();
+ accessibilityObject().scrollToMakeVisibleWithSubFocus(WebRect(x, y, width, height));
+ result->setNull();
+}
+
+void WebAXObjectProxy::scrollToGlobalPointCallback(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ if (arguments.size() != 2
+ || !arguments[0].isNumber()
+ || !arguments[1].isNumber())
+ return;
+
+ int x = arguments[0].toInt32();
+ int y = arguments[1].toInt32();
+
+ accessibilityObject().scrollToGlobalPoint(WebPoint(x, y));
+ result->setNull();
+}
+
+void WebAXObjectProxy::wordStartCallback(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ if (arguments.size() != 1 || !arguments[0].isNumber())
+ return;
+
+ if (accessibilityObject().role() != WebAXRoleStaticText)
+ return;
+
+ int characterIndex = arguments[0].toInt32();
+ int wordStart, wordEnd;
+ getBoundariesForOneWord(accessibilityObject(), characterIndex, wordStart, wordEnd);
+ result->set(wordStart);
+}
+
+void WebAXObjectProxy::wordEndCallback(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ if (arguments.size() != 1 || !arguments[0].isNumber())
+ return;
+
+ if (accessibilityObject().role() != WebAXRoleStaticText)
+ return;
+
+ int characterIndex = arguments[0].toInt32();
+ int wordStart, wordEnd;
+ getBoundariesForOneWord(accessibilityObject(), characterIndex, wordStart, wordEnd);
+ result->set(wordEnd);
+}
+
+void WebAXObjectProxy::fallbackCallback(const CppArgumentList &, CppVariant* result)
+{
+ result->setNull();
+}
+
+RootWebAXObjectProxy::RootWebAXObjectProxy(const WebAXObject &object, Factory *factory)
+ : WebAXObjectProxy(object, factory) { }
+
+WebAXObjectProxy* RootWebAXObjectProxy::getChildAtIndex(unsigned index)
+{
+ if (index)
+ return 0;
+
+ return factory()->getOrCreate(accessibilityObject());
+}
+
+
+WebAXObjectProxyList ::~WebAXObjectProxyList()
+{
+ clear();
+}
+
+void WebAXObjectProxyList::clear()
+{
+ for (ElementList::iterator i = m_elements.begin(); i != m_elements.end(); ++i)
+ delete (*i);
+ m_elements.clear();
+}
+
+WebAXObjectProxy* WebAXObjectProxyList::getOrCreate(const WebAXObject& object)
+{
+ if (object.isNull())
+ return 0;
+
+ size_t elementCount = m_elements.size();
+ for (size_t i = 0; i < elementCount; i++) {
+ if (m_elements[i]->isEqual(object))
+ return m_elements[i];
+ }
+
+ WebAXObjectProxy* element = new WebAXObjectProxy(object, this);
+ m_elements.push_back(element);
+ return element;
+}
+
+WebAXObjectProxy* WebAXObjectProxyList::createRoot(const WebAXObject& object)
+{
+ WebAXObjectProxy* element = new RootWebAXObjectProxy(object, this);
+ m_elements.push_back(element);
+ return element;
+}
+
+}
diff --git a/content/shell/renderer/test_runner/WebAXObjectProxy.h b/content/shell/renderer/test_runner/WebAXObjectProxy.h
new file mode 100644
index 0000000..a90273f
--- /dev/null
+++ b/content/shell/renderer/test_runner/WebAXObjectProxy.h
@@ -0,0 +1,145 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WebAXObjectProxy_h
+#define WebAXObjectProxy_h
+
+#include <vector>
+
+#include "content/shell/renderer/test_runner/CppBoundClass.h"
+#include "third_party/WebKit/public/web/WebAXObject.h"
+
+namespace WebTestRunner {
+
+class WebAXObjectProxy : public CppBoundClass {
+public:
+ class Factory {
+ public:
+ virtual ~Factory() { }
+ virtual WebAXObjectProxy* getOrCreate(const blink::WebAXObject&) = 0;
+ };
+
+ WebAXObjectProxy(const blink::WebAXObject&, Factory*);
+
+ virtual WebAXObjectProxy* getChildAtIndex(unsigned);
+ virtual bool isRoot() const { return false; }
+ virtual bool isEqual(const blink::WebAXObject&);
+
+ virtual void notificationReceived(const char *notificationName);
+
+protected:
+ const blink::WebAXObject& accessibilityObject() const { return m_accessibilityObject; }
+
+ Factory* factory() const { return m_factory; }
+
+private:
+ // Bound properties.
+ void roleGetterCallback(CppVariant*);
+ void titleGetterCallback(CppVariant*);
+ void descriptionGetterCallback(CppVariant*);
+ void helpTextGetterCallback(CppVariant*);
+ void stringValueGetterCallback(CppVariant*);
+ void xGetterCallback(CppVariant*);
+ void yGetterCallback(CppVariant*);
+ void widthGetterCallback(CppVariant*);
+ void heightGetterCallback(CppVariant*);
+ void intValueGetterCallback(CppVariant*);
+ void minValueGetterCallback(CppVariant*);
+ void maxValueGetterCallback(CppVariant*);
+ void valueDescriptionGetterCallback(CppVariant*);
+ void childrenCountGetterCallback(CppVariant*);
+ void insertionPointLineNumberGetterCallback(CppVariant*);
+ void selectedTextRangeGetterCallback(CppVariant*);
+ void isEnabledGetterCallback(CppVariant*);
+ void isRequiredGetterCallback(CppVariant*);
+ void isFocusedGetterCallback(CppVariant*);
+ void isFocusableGetterCallback(CppVariant*);
+ void isSelectedGetterCallback(CppVariant*);
+ void isSelectableGetterCallback(CppVariant*);
+ void isMultiSelectableGetterCallback(CppVariant*);
+ void isSelectedOptionActiveGetterCallback(CppVariant*);
+ void isExpandedGetterCallback(CppVariant*);
+ void isCheckedGetterCallback(CppVariant*);
+ void isVisibleGetterCallback(CppVariant*);
+ void isOffScreenGetterCallback(CppVariant*);
+ void isCollapsedGetterCallback(CppVariant*);
+ void hasPopupGetterCallback(CppVariant*);
+ void isValidGetterCallback(CppVariant*);
+ void isReadOnlyGetterCallback(CppVariant*);
+ void orientationGetterCallback(CppVariant*);
+ void clickPointXGetterCallback(CppVariant*);
+ void clickPointYGetterCallback(CppVariant*);
+ void rowCountGetterCallback(CppVariant*);
+ void columnCountGetterCallback(CppVariant*);
+ void isClickableGetterCallback(CppVariant*);
+
+ // Bound methods.
+ void allAttributesCallback(const CppArgumentList&, CppVariant*);
+ void attributesOfChildrenCallback(const CppArgumentList&, CppVariant*);
+ void lineForIndexCallback(const CppArgumentList&, CppVariant*);
+ void boundsForRangeCallback(const CppArgumentList&, CppVariant*);
+ void childAtIndexCallback(const CppArgumentList&, CppVariant*);
+ void elementAtPointCallback(const CppArgumentList&, CppVariant*);
+ void tableHeaderCallback(const CppArgumentList&, CppVariant*);
+ void rowIndexRangeCallback(const CppArgumentList&, CppVariant*);
+ void columnIndexRangeCallback(const CppArgumentList&, CppVariant*);
+ void cellForColumnAndRowCallback(const CppArgumentList&, CppVariant*);
+ void titleUIElementCallback(const CppArgumentList&, CppVariant*);
+ void setSelectedTextRangeCallback(const CppArgumentList&, CppVariant*);
+ void isAttributeSettableCallback(const CppArgumentList&, CppVariant*);
+ void isPressActionSupportedCallback(const CppArgumentList&, CppVariant*);
+ void isIncrementActionSupportedCallback(const CppArgumentList&, CppVariant*);
+ void isDecrementActionSupportedCallback(const CppArgumentList&, CppVariant*);
+ void parentElementCallback(const CppArgumentList&, CppVariant*);
+ void incrementCallback(const CppArgumentList&, CppVariant*);
+ void decrementCallback(const CppArgumentList&, CppVariant*);
+ void showMenuCallback(const CppArgumentList&, CppVariant*);
+ void pressCallback(const CppArgumentList&, CppVariant*);
+ void isEqualCallback(const CppArgumentList&, CppVariant*);
+ void addNotificationListenerCallback(const CppArgumentList&, CppVariant*);
+ void removeNotificationListenerCallback(const CppArgumentList&, CppVariant*);
+ void takeFocusCallback(const CppArgumentList&, CppVariant*);
+ void scrollToMakeVisibleCallback(const CppArgumentList&, CppVariant*);
+ void scrollToMakeVisibleWithSubFocusCallback(const CppArgumentList&, CppVariant*);
+ void scrollToGlobalPointCallback(const CppArgumentList&, CppVariant*);
+ void wordStartCallback(const CppArgumentList&, CppVariant*);
+ void wordEndCallback(const CppArgumentList&, CppVariant*);
+
+ void fallbackCallback(const CppArgumentList&, CppVariant*);
+
+ blink::WebAXObject m_accessibilityObject;
+ Factory* m_factory;
+ std::vector<CppVariant> m_notificationCallbacks;
+};
+
+
+class RootWebAXObjectProxy : public WebAXObjectProxy {
+public:
+ RootWebAXObjectProxy(const blink::WebAXObject&, Factory*);
+
+ virtual WebAXObjectProxy* getChildAtIndex(unsigned);
+ virtual bool isRoot() const { return true; }
+};
+
+
+// Provides simple lifetime management of the WebAXObjectProxy instances:
+// all WebAXObjectProxys ever created from the controller are stored in
+// a list and cleared explicitly.
+class WebAXObjectProxyList : public WebAXObjectProxy::Factory {
+public:
+ WebAXObjectProxyList() { }
+ virtual ~WebAXObjectProxyList();
+
+ void clear();
+ virtual WebAXObjectProxy* getOrCreate(const blink::WebAXObject&);
+ WebAXObjectProxy* createRoot(const blink::WebAXObject&);
+
+private:
+ typedef std::vector<WebAXObjectProxy*> ElementList;
+ ElementList m_elements;
+};
+
+}
+
+#endif // WebAXObjectProxy_h
diff --git a/content/shell/renderer/test_runner/WebFrameTestProxy.h b/content/shell/renderer/test_runner/WebFrameTestProxy.h
new file mode 100644
index 0000000..400d2bb
--- /dev/null
+++ b/content/shell/renderer/test_runner/WebFrameTestProxy.h
@@ -0,0 +1,154 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WebFrameTestProxy_h
+#define WebFrameTestProxy_h
+
+#include "content/shell/renderer/test_runner/WebTestProxy.h"
+#include "third_party/WebKit/public/platform/WebNonCopyable.h"
+
+namespace WebTestRunner {
+
+// Templetized wrapper around RenderFrameImpl objects, which implement
+// the WebFrameClient interface.
+template<class Base, typename P, typename R>
+class WebFrameTestProxy : public Base, public blink::WebNonCopyable {
+public:
+ WebFrameTestProxy(P p, R r)
+ : Base(p, r)
+ , m_baseProxy(0)
+ , m_version(0) { }
+
+ virtual ~WebFrameTestProxy() { }
+
+ void setBaseProxy(WebTestProxyBase* proxy)
+ {
+ m_baseProxy = proxy;
+ }
+
+ void setVersion(int version)
+ {
+ m_version = version;
+ }
+
+ blink::WebPlugin* createPlugin(blink::WebFrame* frame, const blink::WebPluginParams& params)
+ {
+ blink::WebPlugin* plugin = m_baseProxy->createPlugin(frame, params);
+ if (plugin)
+ return plugin;
+ return Base::createPlugin(frame, params);
+ }
+
+ // WebFrameClient implementation.
+ virtual void didStartProvisionalLoad(blink::WebFrame* frame)
+ {
+ if (m_version > 2)
+ m_baseProxy->didStartProvisionalLoad(frame);
+ Base::didStartProvisionalLoad(frame);
+ }
+ virtual void didReceiveServerRedirectForProvisionalLoad(blink::WebFrame* frame)
+ {
+ Base::didReceiveServerRedirectForProvisionalLoad(frame);
+ }
+ virtual void didFailProvisionalLoad(blink::WebFrame* frame, const blink::WebURLError& error)
+ {
+ Base::didFailProvisionalLoad(frame, error);
+ }
+ virtual void didCommitProvisionalLoad(blink::WebFrame* frame, bool isNewNavigation)
+ {
+ Base::didCommitProvisionalLoad(frame, isNewNavigation);
+ }
+ virtual void didReceiveTitle(blink::WebFrame* frame, const blink::WebString& title, blink::WebTextDirection direction)
+ {
+ Base::didReceiveTitle(frame, title, direction);
+ }
+ virtual void didChangeIcon(blink::WebFrame* frame, blink::WebIconURL::Type iconType)
+ {
+ Base::didChangeIcon(frame, iconType);
+ }
+ virtual void didFinishDocumentLoad(blink::WebFrame* frame)
+ {
+ Base::didFinishDocumentLoad(frame);
+ }
+ virtual void didHandleOnloadEvents(blink::WebFrame* frame)
+ {
+ Base::didHandleOnloadEvents(frame);
+ }
+ virtual void didFailLoad(blink::WebFrame* frame, const blink::WebURLError& error)
+ {
+ Base::didFailLoad(frame, error);
+ }
+ virtual void didFinishLoad(blink::WebFrame* frame)
+ {
+ Base::didFinishLoad(frame);
+ }
+ virtual void didDetectXSS(blink::WebFrame* frame, const blink::WebURL& insecureURL, bool didBlockEntirePage)
+ {
+ // This is not implemented in RenderFrameImpl, so need to explicitly call
+ // into the base proxy.
+ m_baseProxy->didDetectXSS(frame, insecureURL, didBlockEntirePage);
+ Base::didDetectXSS(frame, insecureURL, didBlockEntirePage);
+ }
+ virtual void didDispatchPingLoader(blink::WebFrame* frame, const blink::WebURL& url)
+ {
+ // This is not implemented in RenderFrameImpl, so need to explicitly call
+ // into the base proxy.
+ m_baseProxy->didDispatchPingLoader(frame, url);
+ Base::didDispatchPingLoader(frame, url);
+ }
+ virtual void willRequestResource(blink::WebFrame* frame, const blink::WebCachedURLRequest& request)
+ {
+ // This is not implemented in RenderFrameImpl, so need to explicitly call
+ // into the base proxy.
+ m_baseProxy->willRequestResource(frame, request);
+ Base::willRequestResource(frame, request);
+ }
+ virtual void didCreateDataSource(blink::WebFrame* frame, blink::WebDataSource* ds)
+ {
+ Base::didCreateDataSource(frame, ds);
+ }
+ virtual void willSendRequest(blink::WebFrame* frame, unsigned identifier, blink::WebURLRequest& request, const blink::WebURLResponse& redirectResponse)
+ {
+ m_baseProxy->willSendRequest(frame, identifier, request, redirectResponse);
+ Base::willSendRequest(frame, identifier, request, redirectResponse);
+ }
+ virtual void didReceiveResponse(blink::WebFrame* frame, unsigned identifier, const blink::WebURLResponse& response)
+ {
+ m_baseProxy->didReceiveResponse(frame, identifier, response);
+ Base::didReceiveResponse(frame, identifier, response);
+ }
+ virtual void didChangeResourcePriority(blink::WebFrame* frame, unsigned identifier, const blink::WebURLRequest::Priority& priority)
+ {
+ // This is not implemented in RenderFrameImpl, so need to explicitly call
+ // into the base proxy.
+ m_baseProxy->didChangeResourcePriority(frame, identifier, priority);
+ Base::didChangeResourcePriority(frame, identifier, priority);
+ }
+ virtual void didFinishResourceLoad(blink::WebFrame* frame, unsigned identifier)
+ {
+ Base::didFinishResourceLoad(frame, identifier);
+ }
+ virtual blink::WebNavigationPolicy decidePolicyForNavigation(blink::WebFrame* frame, blink::WebDataSource::ExtraData* extraData, const blink::WebURLRequest& request, blink::WebNavigationType type, blink::WebNavigationPolicy defaultPolicy, bool isRedirect)
+ {
+ return Base::decidePolicyForNavigation(frame, extraData, request, type, defaultPolicy, isRedirect);
+ }
+ virtual bool willCheckAndDispatchMessageEvent(blink::WebFrame* sourceFrame, blink::WebFrame* targetFrame, blink::WebSecurityOrigin target, blink::WebDOMMessageEvent event)
+ {
+ if (m_baseProxy->willCheckAndDispatchMessageEvent(sourceFrame, targetFrame, target, event))
+ return true;
+ return Base::willCheckAndDispatchMessageEvent(sourceFrame, targetFrame, target, event);
+ }
+
+private:
+ WebTestProxyBase* m_baseProxy;
+
+ // This is used to incrementally change code between Blink and Chromium.
+ // It is used instead of a #define and is set by layouttest_support when
+ // creating this object.
+ int m_version;
+};
+
+}
+
+#endif // WebTestProxy_h
diff --git a/content/shell/renderer/test_runner/WebPermissions.cpp b/content/shell/renderer/test_runner/WebPermissions.cpp
new file mode 100644
index 0000000..6837172
--- /dev/null
+++ b/content/shell/renderer/test_runner/WebPermissions.cpp
@@ -0,0 +1,113 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/shell/renderer/test_runner/WebPermissions.h"
+
+#include "content/shell/renderer/test_runner/TestCommon.h"
+#include "content/shell/renderer/test_runner/WebTestDelegate.h"
+#include "third_party/WebKit/public/platform/WebCString.h"
+#include "third_party/WebKit/public/platform/WebURL.h"
+
+using namespace std;
+
+namespace WebTestRunner {
+
+WebPermissions::WebPermissions()
+ : m_delegate(0)
+{
+ reset();
+}
+
+WebPermissions::~WebPermissions()
+{
+}
+
+bool WebPermissions::allowImage(blink::WebFrame*, bool enabledPerSettings, const blink::WebURL& imageURL)
+{
+ bool allowed = enabledPerSettings && m_imagesAllowed;
+ if (m_dumpCallbacks && m_delegate)
+ m_delegate->printMessage(std::string("PERMISSION CLIENT: allowImage(") + normalizeLayoutTestURL(imageURL.spec()) + "): " + (allowed ? "true" : "false") + "\n");
+ return allowed;
+}
+
+bool WebPermissions::allowScriptFromSource(blink::WebFrame*, bool enabledPerSettings, const blink::WebURL& scriptURL)
+{
+ bool allowed = enabledPerSettings && m_scriptsAllowed;
+ if (m_dumpCallbacks && m_delegate)
+ m_delegate->printMessage(std::string("PERMISSION CLIENT: allowScriptFromSource(") + normalizeLayoutTestURL(scriptURL.spec()) + "): " + (allowed ? "true" : "false") + "\n");
+ return allowed;
+}
+
+bool WebPermissions::allowStorage(blink::WebFrame*, bool)
+{
+ return m_storageAllowed;
+}
+
+bool WebPermissions::allowPlugins(blink::WebFrame*, bool enabledPerSettings)
+{
+ return enabledPerSettings && m_pluginsAllowed;
+}
+
+bool WebPermissions::allowDisplayingInsecureContent(blink::WebFrame*, bool enabledPerSettings, const blink::WebSecurityOrigin&, const blink::WebURL&)
+{
+ return enabledPerSettings || m_displayingInsecureContentAllowed;
+}
+
+bool WebPermissions::allowRunningInsecureContent(blink::WebFrame*, bool enabledPerSettings, const blink::WebSecurityOrigin&, const blink::WebURL&)
+{
+ return enabledPerSettings || m_runningInsecureContentAllowed;
+}
+
+void WebPermissions::setImagesAllowed(bool imagesAllowed)
+{
+ m_imagesAllowed = imagesAllowed;
+}
+
+void WebPermissions::setScriptsAllowed(bool scriptsAllowed)
+{
+ m_scriptsAllowed = scriptsAllowed;
+}
+
+void WebPermissions::setStorageAllowed(bool storageAllowed)
+{
+ m_storageAllowed = storageAllowed;
+}
+
+void WebPermissions::setPluginsAllowed(bool pluginsAllowed)
+{
+ m_pluginsAllowed = pluginsAllowed;
+}
+
+void WebPermissions::setDisplayingInsecureContentAllowed(bool allowed)
+{
+ m_displayingInsecureContentAllowed = allowed;
+}
+
+void WebPermissions::setRunningInsecureContentAllowed(bool allowed)
+{
+ m_runningInsecureContentAllowed = allowed;
+}
+
+void WebPermissions::setDelegate(WebTestDelegate* delegate)
+{
+ m_delegate = delegate;
+}
+
+void WebPermissions::setDumpCallbacks(bool dumpCallbacks)
+{
+ m_dumpCallbacks = dumpCallbacks;
+}
+
+void WebPermissions::reset()
+{
+ m_dumpCallbacks = false;
+ m_imagesAllowed = true;
+ m_scriptsAllowed = true;
+ m_storageAllowed = true;
+ m_pluginsAllowed = true;
+ m_displayingInsecureContentAllowed = false;
+ m_runningInsecureContentAllowed = false;
+}
+
+}
diff --git a/content/shell/renderer/test_runner/WebPermissions.h b/content/shell/renderer/test_runner/WebPermissions.h
new file mode 100644
index 0000000..f9294cd
--- /dev/null
+++ b/content/shell/renderer/test_runner/WebPermissions.h
@@ -0,0 +1,56 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WebPermissions_h
+#define WebPermissions_h
+
+#include "third_party/WebKit/public/platform/WebNonCopyable.h"
+#include "third_party/WebKit/public/web/WebPermissionClient.h"
+
+namespace WebTestRunner {
+
+class WebTestDelegate;
+
+class WebPermissions : public blink::WebPermissionClient, public blink::WebNonCopyable {
+public:
+ WebPermissions();
+ virtual ~WebPermissions();
+
+ // Override WebPermissionClient methods.
+ virtual bool allowImage(blink::WebFrame*, bool enabledPerSettings, const blink::WebURL& imageURL);
+ virtual bool allowScriptFromSource(blink::WebFrame*, bool enabledPerSettings, const blink::WebURL& scriptURL);
+ virtual bool allowStorage(blink::WebFrame*, bool local);
+ virtual bool allowPlugins(blink::WebFrame*, bool enabledPerSettings);
+ virtual bool allowDisplayingInsecureContent(blink::WebFrame*, bool enabledPerSettings, const blink::WebSecurityOrigin&, const blink::WebURL&);
+ virtual bool allowRunningInsecureContent(blink::WebFrame*, bool enabledPerSettings, const blink::WebSecurityOrigin&, const blink::WebURL&);
+
+ // Hooks to set the different policies.
+ void setImagesAllowed(bool);
+ void setScriptsAllowed(bool);
+ void setStorageAllowed(bool);
+ void setPluginsAllowed(bool);
+ void setDisplayingInsecureContentAllowed(bool);
+ void setRunningInsecureContentAllowed(bool);
+
+ // Resets the policy to allow everything, except for running insecure content.
+ void reset();
+
+ void setDelegate(WebTestDelegate*);
+ void setDumpCallbacks(bool);
+
+private:
+ WebTestDelegate* m_delegate;
+ bool m_dumpCallbacks;
+
+ bool m_imagesAllowed;
+ bool m_scriptsAllowed;
+ bool m_storageAllowed;
+ bool m_pluginsAllowed;
+ bool m_displayingInsecureContentAllowed;
+ bool m_runningInsecureContentAllowed;
+};
+
+}
+
+#endif
diff --git a/content/shell/renderer/test_runner/WebScopedPtr.h b/content/shell/renderer/test_runner/WebScopedPtr.h
new file mode 100644
index 0000000..94af5b60
--- /dev/null
+++ b/content/shell/renderer/test_runner/WebScopedPtr.h
@@ -0,0 +1,123 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WebScopedPtr_h
+#define WebScopedPtr_h
+
+#include <stddef.h>
+
+namespace WebTestRunner {
+
+template<typename Deallocator, typename T>
+class WebScopedPtrBase {
+public:
+ // Default constructor. Constructs an empty scoped pointer.
+ inline WebScopedPtrBase() : m_ptr(0) { }
+
+ // Constructs a scoped pointer from a plain one.
+ explicit inline WebScopedPtrBase(T* ptr) : m_ptr(ptr) { }
+
+ // Copy constructor removes the pointer from the original to avoid double
+ // freeing.
+ inline WebScopedPtrBase(const WebScopedPtrBase<Deallocator, T>& rhs)
+ : m_ptr(rhs.m_ptr)
+ {
+ const_cast<WebScopedPtrBase<Deallocator, T>&>(rhs).m_ptr = 0;
+ }
+
+ // When the destructor of the scoped pointer is executed the plain pointer
+ // is deleted using DeleteArray. This implies that you must allocate with
+ // NewArray.
+ inline ~WebScopedPtrBase()
+ {
+ if (m_ptr)
+ Deallocator::Delete(m_ptr);
+ }
+
+ inline T* operator->() const { return m_ptr; }
+
+ // You can get the underlying pointer out with the * operator.
+ inline T* operator*() { return m_ptr; }
+
+ // You can use [n] to index as if it was a plain pointer.
+ inline T& operator[](size_t i)
+ {
+ return m_ptr[i];
+ }
+
+ // You can use [n] to index as if it was a plain pointer.
+ const inline T& operator[](size_t i) const
+ {
+ return m_ptr[i];
+ }
+
+ // We don't have implicit conversion to a T* since that hinders migration:
+ // You would not be able to change a method from returning a T* to
+ // returning an WebScopedArrayPtr<T> and then get errors wherever it is used.
+ inline T* get() const { return m_ptr; }
+
+ inline void reset(T* newValue = 0)
+ {
+ if (m_ptr)
+ Deallocator::Delete(m_ptr);
+ m_ptr = newValue;
+ }
+
+ // Assignment requires an empty (0) WebScopedArrayPtr as the receiver. Like
+ // the copy constructor it removes the pointer in the original to avoid
+ // double freeing.
+ inline WebScopedPtrBase<Deallocator, T>& operator=(const WebScopedPtrBase<Deallocator, T>& rhs)
+ {
+ reset(rhs.m_ptr);
+ const_cast<WebScopedPtrBase<Deallocator, T>&>(rhs).m_ptr = 0;
+ return *this;
+ }
+
+ inline bool isEmpty() { return !m_ptr; }
+
+private:
+ T* m_ptr;
+};
+
+// A 'scoped array pointer' that calls DeleteArray on its pointer when the
+// destructor is called.
+template<typename T>
+struct ArrayDeallocator {
+ static void Delete(T* array)
+ {
+ DeleteArray(array);
+ }
+};
+
+template<typename T>
+class WebScopedArrayPtr: public WebScopedPtrBase<ArrayDeallocator<T>, T> {
+public:
+ inline WebScopedArrayPtr() { }
+ explicit inline WebScopedArrayPtr(T* ptr)
+ : WebScopedPtrBase<ArrayDeallocator<T>, T>(ptr) { }
+ inline WebScopedArrayPtr(const WebScopedArrayPtr<T>& rhs)
+ : WebScopedPtrBase<ArrayDeallocator<T>, T>(rhs) { }
+};
+
+template<typename T>
+struct ObjectDeallocator {
+ static void Delete(T* object)
+ {
+ delete object;
+ }
+};
+
+template<typename T>
+class WebScopedPtr: public WebScopedPtrBase<ObjectDeallocator<T>, T> {
+public:
+ inline WebScopedPtr() { }
+ explicit inline WebScopedPtr(T* ptr)
+ : WebScopedPtrBase<ObjectDeallocator<T>, T>(ptr) { }
+ inline WebScopedPtr(const WebScopedPtr<T>& rhs)
+ : WebScopedPtrBase<ObjectDeallocator<T>, T>(rhs) { }
+};
+
+} // namespace WebTestRunner
+
+#endif // WebScopedPtr_h
diff --git a/content/shell/renderer/test_runner/WebTask.cpp b/content/shell/renderer/test_runner/WebTask.cpp
new file mode 100644
index 0000000..0a21971
--- /dev/null
+++ b/content/shell/renderer/test_runner/WebTask.cpp
@@ -0,0 +1,53 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/shell/renderer/test_runner/WebTask.h"
+
+#include <algorithm>
+#include "third_party/WebKit/public/web/WebKit.h"
+
+using namespace std;
+
+namespace WebTestRunner {
+
+WebTask::WebTask(WebTaskList* list)
+ : m_taskList(list)
+{
+ m_taskList->registerTask(this);
+}
+
+WebTask::~WebTask()
+{
+ if (m_taskList)
+ m_taskList->unregisterTask(this);
+}
+
+WebTaskList::WebTaskList()
+{
+}
+
+WebTaskList::~WebTaskList()
+{
+ revokeAll();
+}
+
+void WebTaskList::registerTask(WebTask* task)
+{
+ m_tasks.push_back(task);
+}
+
+void WebTaskList::unregisterTask(WebTask* task)
+{
+ vector<WebTask*>::iterator iter = find(m_tasks.begin(), m_tasks.end(), task);
+ if (iter != m_tasks.end())
+ m_tasks.erase(iter);
+}
+
+void WebTaskList::revokeAll()
+{
+ while (!m_tasks.empty())
+ m_tasks[0]->cancel();
+}
+
+}
diff --git a/content/shell/renderer/test_runner/WebTask.h b/content/shell/renderer/test_runner/WebTask.h
new file mode 100644
index 0000000..3f8a234
--- /dev/null
+++ b/content/shell/renderer/test_runner/WebTask.h
@@ -0,0 +1,77 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WebTask_h
+#define WebTask_h
+
+#include <vector>
+
+namespace WebTestRunner {
+
+class WebTaskList;
+
+// WebTask represents a task which can run by WebTestDelegate::postTask() or
+// WebTestDelegate::postDelayedTask().
+class WebTask {
+public:
+ explicit WebTask(WebTaskList*);
+ virtual ~WebTask();
+
+ // The main code of this task.
+ // An implementation of run() should return immediately if cancel() was called.
+ virtual void run() = 0;
+ virtual void cancel() = 0;
+
+protected:
+ WebTaskList* m_taskList;
+};
+
+class WebTaskList {
+public:
+ WebTaskList();
+ ~WebTaskList();
+ void registerTask(WebTask*);
+ void unregisterTask(WebTask*);
+ void revokeAll();
+
+private:
+ std::vector<WebTask*> m_tasks;
+};
+
+// A task containing an object pointer of class T. Derived classes should
+// override runIfValid() which in turn can safely invoke methods on the
+// m_object. The Class T must have "WebTaskList* taskList()".
+template<class T>
+class WebMethodTask : public WebTask {
+public:
+ explicit WebMethodTask(T* object)
+ : WebTask(object->taskList())
+ , m_object(object)
+ {
+ }
+
+ virtual ~WebMethodTask() { }
+
+ virtual void run()
+ {
+ if (m_object)
+ runIfValid();
+ }
+
+ virtual void cancel()
+ {
+ m_object = 0;
+ m_taskList->unregisterTask(this);
+ m_taskList = 0;
+ }
+
+ virtual void runIfValid() = 0;
+
+protected:
+ T* m_object;
+};
+
+}
+
+#endif // WebTask_h
diff --git a/content/shell/renderer/test_runner/WebTestDelegate.h b/content/shell/renderer/test_runner/WebTestDelegate.h
new file mode 100644
index 0000000..75d7cd9
--- /dev/null
+++ b/content/shell/renderer/test_runner/WebTestDelegate.h
@@ -0,0 +1,142 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WebTestDelegate_h
+#define WebTestDelegate_h
+
+#include <string>
+
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/platform/WebURL.h"
+#include "third_party/WebKit/public/platform/WebVector.h"
+
+#define WEBTESTRUNNER_NEW_HISTORY_CAPTURE
+
+namespace blink {
+class WebDeviceMotionData;
+class WebDeviceOrientationData;
+class WebFrame;
+class WebGamepads;
+class WebHistoryItem;
+struct WebRect;
+struct WebSize;
+struct WebURLError;
+}
+
+namespace WebTestRunner {
+
+struct WebPreferences;
+class WebTask;
+class WebTestProxyBase;
+
+class WebTestDelegate {
+public:
+ // Set and clear the edit command to execute on the next call to
+ // WebViewClient::handleCurrentKeyboardEvent().
+ virtual void clearEditCommand() = 0;
+ virtual void setEditCommand(const std::string& name, const std::string& value) = 0;
+
+ // Set the gamepads to return from Platform::sampleGamepads().
+ virtual void setGamepadData(const blink::WebGamepads&) = 0;
+
+ // Set data to return when registering via Platform::setDeviceMotionListener().
+ virtual void setDeviceMotionData(const blink::WebDeviceMotionData&) = 0;
+ // Set data to return when registering via Platform::setDeviceOrientationListener().
+ virtual void setDeviceOrientationData(const blink::WebDeviceOrientationData&) = 0;
+
+ // Add a message to the text dump for the layout test.
+ virtual void printMessage(const std::string& message) = 0;
+
+ // The delegate takes ownership of the WebTask objects and is responsible
+ // for deleting them.
+ virtual void postTask(WebTask*) = 0;
+ virtual void postDelayedTask(WebTask*, long long ms) = 0;
+
+ // Register a new isolated filesystem with the given files, and return the
+ // new filesystem id.
+ virtual blink::WebString registerIsolatedFileSystem(const blink::WebVector<blink::WebString>& absoluteFilenames) = 0;
+
+ // Gets the current time in milliseconds since the UNIX epoch.
+ virtual long long getCurrentTimeInMillisecond() = 0;
+
+ // Convert the provided relative path into an absolute path.
+ virtual blink::WebString getAbsoluteWebStringFromUTF8Path(const std::string& path) = 0;
+
+ // Reads in the given file and returns its contents as data URL.
+ virtual blink::WebURL localFileToDataURL(const blink::WebURL&) = 0;
+
+ // Replaces file:///tmp/LayoutTests/ with the actual path to the
+ // LayoutTests directory.
+ virtual blink::WebURL rewriteLayoutTestsURL(const std::string& utf8URL) = 0;
+
+ // Manages the settings to used for layout tests.
+ virtual WebPreferences* preferences() = 0;
+ virtual void applyPreferences() = 0;
+
+ // Enables or disables synchronous resize mode. When enabled, all window-sizing machinery is
+ // short-circuited inside the renderer. This mode is necessary for some tests that were written
+ // before browsers had multi-process architecture and rely on window resizes to happen synchronously.
+ // The function has "unfortunate" it its name because we must strive to remove all tests
+ // that rely on this... well, unfortunate behavior. See http://crbug.com/309760 for the plan.
+ virtual void useUnfortunateSynchronousResizeMode(bool) = 0;
+
+ // Controls auto resize mode.
+ virtual void enableAutoResizeMode(const blink::WebSize& minSize, const blink::WebSize& maxSize) = 0;
+ virtual void disableAutoResizeMode(const blink::WebSize&) = 0;
+
+ // Opens and closes the inspector.
+ virtual void showDevTools() = 0;
+ virtual void closeDevTools() = 0;
+
+ // Evaluate the given script in the DevTools agent.
+ virtual void evaluateInWebInspector(long callID, const std::string& script) = 0;
+
+ // Controls WebSQL databases.
+ virtual void clearAllDatabases() = 0;
+ virtual void setDatabaseQuota(int) = 0;
+
+ // Controls the device scale factor of the main WebView for hidpi tests.
+ virtual void setDeviceScaleFactor(float) = 0;
+
+ // Controls which WebView should be focused.
+ virtual void setFocus(WebTestProxyBase*, bool) = 0;
+
+ // Controls whether all cookies should be accepted or writing cookies in a
+ // third-party context is blocked.
+ virtual void setAcceptAllCookies(bool) = 0;
+
+ // The same as rewriteLayoutTestsURL unless the resource is a path starting
+ // with /tmp/, then return a file URL to a temporary file.
+ virtual std::string pathToLocalResource(const std::string& resource) = 0;
+
+ // Sets the POSIX locale of the current process.
+ virtual void setLocale(const std::string&) = 0;
+
+ // Invoked when the test finished.
+ virtual void testFinished() = 0;
+
+ // Invoked when the embedder should close all but the main WebView.
+ virtual void closeRemainingWindows() = 0;
+
+ virtual void deleteAllCookies() = 0;
+
+ // Returns the length of the back/forward history of the main WebView.
+ virtual int navigationEntryCount() = 0;
+
+ // The following trigger navigations on the main WebViwe.
+ virtual void goToOffset(int offset) = 0;
+ virtual void reload() = 0;
+ virtual void loadURLForFrame(const blink::WebURL&, const std::string& frameName) = 0;
+
+ // Returns true if resource requests to external URLs should be permitted.
+ virtual bool allowExternalPages() = 0;
+
+ // Returns the back/forward history for the WebView associated with the
+ // given WebTestProxyBase as well as the index of the current entry.
+ virtual void captureHistoryForWindow(WebTestProxyBase*, blink::WebVector<blink::WebHistoryItem>*, size_t* currentEntryIndex) = 0;
+};
+
+}
+
+#endif // WebTestDelegate_h
diff --git a/content/shell/renderer/test_runner/WebTestInterfaces.cpp b/content/shell/renderer/test_runner/WebTestInterfaces.cpp
new file mode 100644
index 0000000..692c858
--- /dev/null
+++ b/content/shell/renderer/test_runner/WebTestInterfaces.cpp
@@ -0,0 +1,92 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/shell/renderer/test_runner/WebTestInterfaces.h"
+
+#include "content/shell/renderer/test_runner/MockWebAudioDevice.h"
+#include "content/shell/renderer/test_runner/MockWebMIDIAccessor.h"
+#include "content/shell/renderer/test_runner/MockWebMediaStreamCenter.h"
+#include "content/shell/renderer/test_runner/MockWebRTCPeerConnectionHandler.h"
+#include "content/shell/renderer/test_runner/TestInterfaces.h"
+#include "content/shell/renderer/test_runner/TestRunner.h"
+
+using namespace blink;
+
+namespace WebTestRunner {
+
+WebTestInterfaces::WebTestInterfaces()
+ : m_interfaces(new TestInterfaces())
+{
+}
+
+WebTestInterfaces::~WebTestInterfaces()
+{
+}
+
+void WebTestInterfaces::setWebView(WebView* webView, WebTestProxyBase* proxy)
+{
+ m_interfaces->setWebView(webView, proxy);
+}
+
+void WebTestInterfaces::setDelegate(WebTestDelegate* delegate)
+{
+ m_interfaces->setDelegate(delegate);
+}
+
+void WebTestInterfaces::bindTo(WebFrame* frame)
+{
+ m_interfaces->bindTo(frame);
+}
+
+void WebTestInterfaces::resetAll()
+{
+ m_interfaces->resetAll();
+}
+
+void WebTestInterfaces::setTestIsRunning(bool running)
+{
+ m_interfaces->setTestIsRunning(running);
+}
+
+void WebTestInterfaces::configureForTestWithURL(const WebURL& testURL, bool generatePixels)
+{
+ m_interfaces->configureForTestWithURL(testURL, generatePixels);
+}
+
+WebTestRunner* WebTestInterfaces::testRunner()
+{
+ return m_interfaces->testRunner();
+}
+
+WebThemeEngine* WebTestInterfaces::themeEngine()
+{
+ return m_interfaces->themeEngine();
+}
+
+TestInterfaces* WebTestInterfaces::testInterfaces()
+{
+ return m_interfaces.get();
+}
+
+WebMediaStreamCenter* WebTestInterfaces::createMediaStreamCenter(WebMediaStreamCenterClient* client)
+{
+ return new MockWebMediaStreamCenter(client);
+}
+
+WebRTCPeerConnectionHandler* WebTestInterfaces::createWebRTCPeerConnectionHandler(WebRTCPeerConnectionHandlerClient* client)
+{
+ return new MockWebRTCPeerConnectionHandler(client, m_interfaces.get());
+}
+
+WebMIDIAccessor* WebTestInterfaces::createMIDIAccessor(WebMIDIAccessorClient* client)
+{
+ return new MockWebMIDIAccessor(client, m_interfaces.get());
+}
+
+WebAudioDevice* WebTestInterfaces::createAudioDevice(double sampleRate)
+{
+ return new MockWebAudioDevice(sampleRate);
+}
+
+}
diff --git a/content/shell/renderer/test_runner/WebTestInterfaces.h b/content/shell/renderer/test_runner/WebTestInterfaces.h
new file mode 100644
index 0000000..cd59fd0
--- /dev/null
+++ b/content/shell/renderer/test_runner/WebTestInterfaces.h
@@ -0,0 +1,61 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WebTestInterfaces_h
+#define WebTestInterfaces_h
+
+#include "content/shell/renderer/test_runner/WebScopedPtr.h"
+
+namespace blink {
+class WebAudioDevice;
+class WebFrame;
+class WebMediaStreamCenter;
+class WebMediaStreamCenterClient;
+class WebMIDIAccessor;
+class WebMIDIAccessorClient;
+class WebRTCPeerConnectionHandler;
+class WebRTCPeerConnectionHandlerClient;
+class WebThemeEngine;
+class WebURL;
+class WebView;
+}
+
+namespace WebTestRunner {
+
+class TestInterfaces;
+class WebTestDelegate;
+class WebTestProxyBase;
+class WebTestRunner;
+
+class WebTestInterfaces {
+public:
+ WebTestInterfaces();
+ ~WebTestInterfaces();
+
+ void setWebView(blink::WebView*, WebTestProxyBase*);
+ void setDelegate(WebTestDelegate*);
+ void bindTo(blink::WebFrame*);
+ void resetAll();
+ void setTestIsRunning(bool);
+ void configureForTestWithURL(const blink::WebURL&, bool generatePixels);
+
+ WebTestRunner* testRunner();
+ blink::WebThemeEngine* themeEngine();
+
+ blink::WebMediaStreamCenter* createMediaStreamCenter(blink::WebMediaStreamCenterClient*);
+ blink::WebRTCPeerConnectionHandler* createWebRTCPeerConnectionHandler(blink::WebRTCPeerConnectionHandlerClient*);
+
+ blink::WebMIDIAccessor* createMIDIAccessor(blink::WebMIDIAccessorClient*);
+
+ blink::WebAudioDevice* createAudioDevice(double sampleRate);
+
+ TestInterfaces* testInterfaces();
+
+private:
+ WebScopedPtr<TestInterfaces> m_interfaces;
+};
+
+}
+
+#endif // WebTestInterfaces_h
diff --git a/content/shell/renderer/test_runner/WebTestProxy.cpp b/content/shell/renderer/test_runner/WebTestProxy.cpp
new file mode 100644
index 0000000..541ec74
--- /dev/null
+++ b/content/shell/renderer/test_runner/WebTestProxy.cpp
@@ -0,0 +1,1367 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/shell/renderer/test_runner/WebTestProxy.h"
+
+#include <cctype>
+
+#include "content/shell/renderer/test_runner/AccessibilityController.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"
+#include "content/shell/renderer/test_runner/SpellCheckClient.h"
+#include "content/shell/renderer/test_runner/TestCommon.h"
+#include "content/shell/renderer/test_runner/TestInterfaces.h"
+#include "content/shell/renderer/test_runner/TestPlugin.h"
+#include "content/shell/renderer/test_runner/TestRunner.h"
+#include "content/shell/renderer/test_runner/WebTestDelegate.h"
+#include "content/shell/renderer/test_runner/WebTestInterfaces.h"
+#include "content/shell/renderer/test_runner/WebTestRunner.h"
+#include "content/shell/renderer/test_runner/WebUserMediaClientMock.h"
+// FIXME: Including platform_canvas.h here is a layering violation.
+#include "skia/ext/platform_canvas.h"
+#include "third_party/WebKit/public/platform/WebCString.h"
+#include "third_party/WebKit/public/platform/WebURLError.h"
+#include "third_party/WebKit/public/platform/WebURLRequest.h"
+#include "third_party/WebKit/public/platform/WebURLResponse.h"
+#include "third_party/WebKit/public/web/WebAXEnums.h"
+#include "third_party/WebKit/public/web/WebAXObject.h"
+#include "third_party/WebKit/public/web/WebCachedURLRequest.h"
+#include "third_party/WebKit/public/web/WebConsoleMessage.h"
+#include "third_party/WebKit/public/web/WebDataSource.h"
+#include "third_party/WebKit/public/web/WebDocument.h"
+#include "third_party/WebKit/public/web/WebElement.h"
+#include "third_party/WebKit/public/web/WebFrame.h"
+#include "third_party/WebKit/public/web/WebGeolocationClientMock.h"
+#include "third_party/WebKit/public/web/WebHistoryItem.h"
+#include "third_party/WebKit/public/web/WebMIDIClientMock.h"
+#include "third_party/WebKit/public/web/WebNode.h"
+#include "third_party/WebKit/public/web/WebPluginParams.h"
+#include "third_party/WebKit/public/web/WebPrintParams.h"
+#include "third_party/WebKit/public/web/WebRange.h"
+#include "third_party/WebKit/public/web/WebScriptController.h"
+#include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
+#include "third_party/WebKit/public/web/WebView.h"
+
+using namespace blink;
+using namespace std;
+
+namespace WebTestRunner {
+
+namespace {
+
+class HostMethodTask : public WebMethodTask<WebTestProxyBase> {
+public:
+ typedef void (WebTestProxyBase::*CallbackMethodType)();
+ HostMethodTask(WebTestProxyBase* object, CallbackMethodType callback)
+ : WebMethodTask<WebTestProxyBase>(object)
+ , m_callback(callback)
+ { }
+
+ virtual void runIfValid() { (m_object->*m_callback)(); }
+
+private:
+ CallbackMethodType m_callback;
+};
+
+void printFrameDescription(WebTestDelegate* delegate, WebFrame* frame)
+{
+ string name8 = frame->uniqueName().utf8();
+ if (frame == frame->view()->mainFrame()) {
+ if (!name8.length()) {
+ delegate->printMessage("main frame");
+ return;
+ }
+ delegate->printMessage(string("main frame \"") + name8 + "\"");
+ return;
+ }
+ if (!name8.length()) {
+ delegate->printMessage("frame (anonymous)");
+ return;
+ }
+ delegate->printMessage(string("frame \"") + name8 + "\"");
+}
+
+void printFrameUserGestureStatus(WebTestDelegate* delegate, WebFrame* frame, const char* msg)
+{
+ bool isUserGesture = WebUserGestureIndicator::isProcessingUserGesture();
+ delegate->printMessage(string("Frame with user gesture \"") + (isUserGesture ? "true" : "false") + "\"" + msg);
+}
+
+// Used to write a platform neutral file:/// URL by taking the
+// filename and its directory. (e.g., converts
+// "file:///tmp/foo/bar.txt" to just "bar.txt").
+string descriptionSuitableForTestResult(const string& url)
+{
+ if (url.empty() || string::npos == url.find("file://"))
+ return url;
+
+ size_t pos = url.rfind('/');
+ if (pos == string::npos || !pos)
+ return "ERROR:" + url;
+ pos = url.rfind('/', pos - 1);
+ if (pos == string::npos)
+ return "ERROR:" + url;
+
+ return url.substr(pos + 1);
+}
+
+void printResponseDescription(WebTestDelegate* delegate, const WebURLResponse& response)
+{
+ if (response.isNull()) {
+ delegate->printMessage("(null)");
+ return;
+ }
+ string url = response.url().spec();
+ char data[100];
+ snprintf(data, sizeof(data), "%d", response. httpStatusCode());
+ delegate->printMessage(string("<NSURLResponse ") + descriptionSuitableForTestResult(url) + ", http status code " + data + ">");
+}
+
+string URLDescription(const GURL& url)
+{
+ if (url.SchemeIs("file"))
+ return url.ExtractFileName();
+ return url.possibly_invalid_spec();
+}
+
+string PriorityDescription(const WebURLRequest::Priority& priority)
+{
+ switch (priority) {
+ case WebURLRequest::PriorityVeryLow:
+ return "VeryLow";
+ case WebURLRequest::PriorityLow:
+ return "Low";
+ case WebURLRequest::PriorityMedium:
+ return "Medium";
+ case WebURLRequest::PriorityHigh:
+ return "High";
+ case WebURLRequest::PriorityVeryHigh:
+ return "VeryHigh";
+ case WebURLRequest::PriorityUnresolved:
+ default:
+ return "Unresolved";
+ }
+}
+
+void blockRequest(WebURLRequest& request)
+{
+ request.setURL(GURL("255.255.255.255"));
+}
+
+bool isLocalhost(const string& host)
+{
+ return host == "127.0.0.1" || host == "localhost";
+}
+
+bool hostIsUsedBySomeTestsToGenerateError(const string& host)
+{
+ return host == "255.255.255.255";
+}
+
+// Used to write a platform neutral file:/// URL by only taking the filename
+// (e.g., converts "file:///tmp/foo.txt" to just "foo.txt").
+string urlSuitableForTestResult(const string& url)
+{
+ if (url.empty() || string::npos == url.find("file://"))
+ return url;
+
+ size_t pos = url.rfind('/');
+ if (pos == string::npos) {
+#ifdef WIN32
+ pos = url.rfind('\\');
+ if (pos == string::npos)
+ pos = 0;
+#else
+ pos = 0;
+#endif
+ }
+ string filename = url.substr(pos + 1);
+ if (filename.empty())
+ return "file:"; // A WebKit test has this in its expected output.
+ return filename;
+}
+
+// WebNavigationType debugging strings taken from PolicyDelegate.mm.
+const char* linkClickedString = "link clicked";
+const char* formSubmittedString = "form submitted";
+const char* backForwardString = "back/forward";
+const char* reloadString = "reload";
+const char* formResubmittedString = "form resubmitted";
+const char* otherString = "other";
+const char* illegalString = "illegal value";
+
+// Get a debugging string from a WebNavigationType.
+const char* webNavigationTypeToString(WebNavigationType type)
+{
+ switch (type) {
+ case blink::WebNavigationTypeLinkClicked:
+ return linkClickedString;
+ case blink::WebNavigationTypeFormSubmitted:
+ return formSubmittedString;
+ case blink::WebNavigationTypeBackForward:
+ return backForwardString;
+ case blink::WebNavigationTypeReload:
+ return reloadString;
+ case blink::WebNavigationTypeFormResubmitted:
+ return formResubmittedString;
+ case blink::WebNavigationTypeOther:
+ return otherString;
+ }
+ return illegalString;
+}
+
+string dumpDocumentText(WebFrame* frame)
+{
+ // We use the document element's text instead of the body text here because
+ // not all documents have a body, such as XML documents.
+ WebElement documentElement = frame->document().documentElement();
+ if (documentElement.isNull())
+ return string();
+ return documentElement.innerText().utf8();
+}
+
+string dumpFramesAsText(WebFrame* frame, bool recursive)
+{
+ string result;
+
+ // Add header for all but the main frame. Skip empty frames.
+ if (frame->parent() && !frame->document().documentElement().isNull()) {
+ result.append("\n--------\nFrame: '");
+ result.append(frame->uniqueName().utf8().data());
+ result.append("'\n--------\n");
+ }
+
+ result.append(dumpDocumentText(frame));
+ result.append("\n");
+
+ if (recursive) {
+ for (WebFrame* child = frame->firstChild(); child; child = child->nextSibling())
+ result.append(dumpFramesAsText(child, recursive));
+ }
+
+ return result;
+}
+
+string dumpFramesAsPrintedText(WebFrame* frame, bool recursive)
+{
+ string result;
+
+ // Cannot do printed format for anything other than HTML
+ if (!frame->document().isHTMLDocument())
+ return string();
+
+ // Add header for all but the main frame. Skip empty frames.
+ if (frame->parent() && !frame->document().documentElement().isNull()) {
+ result.append("\n--------\nFrame: '");
+ result.append(frame->uniqueName().utf8().data());
+ result.append("'\n--------\n");
+ }
+
+ result.append(frame->renderTreeAsText(WebFrame::RenderAsTextPrinting).utf8());
+ result.append("\n");
+
+ if (recursive) {
+ for (WebFrame* child = frame->firstChild(); child; child = child->nextSibling())
+ result.append(dumpFramesAsPrintedText(child, recursive));
+ }
+
+ return result;
+}
+
+string dumpFrameScrollPosition(WebFrame* frame, bool recursive)
+{
+ string result;
+ WebSize offset = frame->scrollOffset();
+ if (offset.width > 0 || offset.height > 0) {
+ if (frame->parent())
+ result = string("frame '") + frame->uniqueName().utf8().data() + "' ";
+ char data[100];
+ snprintf(data, sizeof(data), "scrolled to %d,%d\n", offset.width, offset.height);
+ result += data;
+ }
+
+ if (!recursive)
+ return result;
+ for (WebFrame* child = frame->firstChild(); child; child = child->nextSibling())
+ result += dumpFrameScrollPosition(child, recursive);
+ return result;
+}
+
+struct ToLower {
+ char16 operator()(char16 c) { return tolower(c); }
+};
+
+// Returns True if item1 < item2.
+bool HistoryItemCompareLess(const WebHistoryItem& item1, const WebHistoryItem& item2)
+{
+ string16 target1 = item1.target();
+ string16 target2 = item2.target();
+ std::transform(target1.begin(), target1.end(), target1.begin(), ToLower());
+ std::transform(target2.begin(), target2.end(), target2.begin(), ToLower());
+ return target1 < target2;
+}
+
+string dumpHistoryItem(const WebHistoryItem& item, int indent, bool isCurrent)
+{
+ string result;
+
+ if (isCurrent) {
+ result.append("curr->");
+ result.append(indent - 6, ' '); // 6 == "curr->".length()
+ } else
+ result.append(indent, ' ');
+
+ string url = normalizeLayoutTestURL(item.urlString().utf8());
+ result.append(url);
+ if (!item.target().isEmpty()) {
+ result.append(" (in frame \"");
+ result.append(item.target().utf8());
+ result.append("\")");
+ }
+ result.append("\n");
+
+ const WebVector<WebHistoryItem>& children = item.children();
+ if (!children.isEmpty()) {
+ // Must sort to eliminate arbitrary result ordering which defeats
+ // reproducible testing.
+ // FIXME: WebVector should probably just be a std::vector!!
+ std::vector<WebHistoryItem> sortedChildren;
+ for (size_t i = 0; i < children.size(); ++i)
+ sortedChildren.push_back(children[i]);
+ std::sort(sortedChildren.begin(), sortedChildren.end(), HistoryItemCompareLess);
+ for (size_t i = 0; i < sortedChildren.size(); ++i)
+ result += dumpHistoryItem(sortedChildren[i], indent + 4, false);
+ }
+
+ return result;
+}
+
+void dumpBackForwardList(const WebVector<WebHistoryItem>& history, size_t currentEntryIndex, string& result)
+{
+ result.append("\n============== Back Forward List ==============\n");
+ for (size_t index = 0; index < history.size(); ++index)
+ result.append(dumpHistoryItem(history[index], 8, index == currentEntryIndex));
+ result.append("===============================================\n");
+}
+
+string dumpAllBackForwardLists(TestInterfaces* interfaces, WebTestDelegate* delegate)
+{
+ string result;
+ const vector<WebTestProxyBase*>& windowList = interfaces->windowList();
+ for (unsigned i = 0; i < windowList.size(); ++i) {
+ size_t currentEntryIndex = 0;
+ WebVector<WebHistoryItem> history;
+ delegate->captureHistoryForWindow(windowList.at(i), &history, &currentEntryIndex);
+ dumpBackForwardList(history, currentEntryIndex, result);
+ }
+ return result;
+}
+
+}
+
+WebTestProxyBase::WebTestProxyBase()
+ : m_testInterfaces(0)
+ , m_delegate(0)
+ , m_webWidget(0)
+ , m_spellcheck(new SpellCheckClient(this))
+ , m_chooserCount(0)
+{
+ reset();
+}
+
+WebTestProxyBase::~WebTestProxyBase()
+{
+ m_testInterfaces->windowClosed(this);
+}
+
+void WebTestProxyBase::setInterfaces(WebTestInterfaces* interfaces)
+{
+ m_testInterfaces = interfaces->testInterfaces();
+ m_testInterfaces->windowOpened(this);
+}
+
+void WebTestProxyBase::setDelegate(WebTestDelegate* delegate)
+{
+ m_delegate = delegate;
+ m_spellcheck->setDelegate(delegate);
+#if ENABLE_INPUT_SPEECH
+ if (m_speechInputController.get())
+ m_speechInputController->setDelegate(delegate);
+#endif
+ if (m_speechRecognizer.get())
+ m_speechRecognizer->setDelegate(delegate);
+}
+
+void WebTestProxyBase::setWidget(WebWidget* widget)
+{
+ m_webWidget = widget;
+}
+
+WebWidget* WebTestProxyBase::webWidget()
+{
+ return m_webWidget;
+}
+
+WebView* WebTestProxyBase::webView()
+{
+ BLINK_ASSERT(m_webWidget);
+ // TestRunner does not support popup widgets. So m_webWidget is always a WebView.
+ return static_cast<WebView*>(m_webWidget);
+}
+
+void WebTestProxyBase::didForceResize()
+{
+ invalidateAll();
+ discardBackingStore();
+}
+
+void WebTestProxyBase::reset()
+{
+ m_paintRect = WebRect();
+ m_canvas.reset();
+ m_isPainting = false;
+ m_animateScheduled = false;
+ m_resourceIdentifierMap.clear();
+ m_logConsoleOutput = true;
+ if (m_geolocationClient.get())
+ m_geolocationClient->resetMock();
+ if (m_midiClient.get())
+ m_midiClient->resetMock();
+#if ENABLE_INPUT_SPEECH
+ if (m_speechInputController.get())
+ m_speechInputController->clearResults();
+#endif
+}
+
+WebSpellCheckClient* WebTestProxyBase::spellCheckClient() const
+{
+ return m_spellcheck.get();
+}
+
+WebColorChooser* WebTestProxyBase::createColorChooser(WebColorChooserClient* client, const blink::WebColor& color)
+{
+ // This instance is deleted by WebCore::ColorInputType
+ return new MockColorChooser(client, m_delegate, this);
+}
+
+WebColorChooser* WebTestProxyBase::createColorChooser(WebColorChooserClient* client, const blink::WebColor& color, const blink::WebVector<blink::WebColorSuggestion>& suggestions)
+{
+ // This instance is deleted by WebCore::ColorInputType
+ return new MockColorChooser(client, m_delegate, this);
+}
+
+bool WebTestProxyBase::runFileChooser(const blink::WebFileChooserParams&, blink::WebFileChooserCompletion*)
+{
+ m_delegate->printMessage("Mock: Opening a file chooser.\n");
+ // FIXME: Add ability to set file names to a file upload control.
+ return false;
+}
+
+void WebTestProxyBase::showValidationMessage(const WebRect&, const WebString& message, const WebString& subMessage, WebTextDirection)
+{
+ m_delegate->printMessage(std::string("ValidationMessageClient: main-message=") + std::string(message.utf8()) + " sub-message=" + std::string(subMessage.utf8()) + "\n");
+}
+
+void WebTestProxyBase::hideValidationMessage()
+{
+}
+
+void WebTestProxyBase::moveValidationMessage(const WebRect&)
+{
+}
+
+string WebTestProxyBase::captureTree(bool debugRenderTree)
+{
+ WebScriptController::flushConsoleMessages();
+
+ bool shouldDumpAsText = m_testInterfaces->testRunner()->shouldDumpAsText();
+ bool shouldDumpAsMarkup = m_testInterfaces->testRunner()->shouldDumpAsMarkup();
+ bool shouldDumpAsPrinted = m_testInterfaces->testRunner()->isPrinting();
+ WebFrame* frame = webView()->mainFrame();
+ string dataUtf8;
+ if (shouldDumpAsText) {
+ bool recursive = m_testInterfaces->testRunner()->shouldDumpChildFramesAsText();
+ dataUtf8 = shouldDumpAsPrinted ? dumpFramesAsPrintedText(frame, recursive) : dumpFramesAsText(frame, recursive);
+ } else if (shouldDumpAsMarkup) {
+ // Append a newline for the test driver.
+ dataUtf8 = frame->contentAsMarkup().utf8() + "\n";
+ } else {
+ bool recursive = m_testInterfaces->testRunner()->shouldDumpChildFrameScrollPositions();
+ WebFrame::RenderAsTextControls renderTextBehavior = WebFrame::RenderAsTextNormal;
+ if (shouldDumpAsPrinted)
+ renderTextBehavior |= WebFrame::RenderAsTextPrinting;
+ if (debugRenderTree)
+ renderTextBehavior |= WebFrame::RenderAsTextDebug;
+ dataUtf8 = frame->renderTreeAsText(renderTextBehavior).utf8();
+ dataUtf8 += dumpFrameScrollPosition(frame, recursive);
+ }
+
+ if (m_testInterfaces->testRunner()->shouldDumpBackForwardList())
+ dataUtf8 += dumpAllBackForwardLists(m_testInterfaces, m_delegate);
+
+ return dataUtf8;
+}
+
+SkCanvas* WebTestProxyBase::capturePixels()
+{
+ webWidget()->layout();
+ if (m_testInterfaces->testRunner()->testRepaint()) {
+ WebSize viewSize = webWidget()->size();
+ int width = viewSize.width;
+ int height = viewSize.height;
+ if (m_testInterfaces->testRunner()->sweepHorizontally()) {
+ for (WebRect column(0, 0, 1, height); column.x < width; column.x++)
+ paintRect(column);
+ } else {
+ for (WebRect line(0, 0, width, 1); line.y < height; line.y++)
+ paintRect(line);
+ }
+ } else if (m_testInterfaces->testRunner()->isPrinting())
+ paintPagesWithBoundaries();
+ else
+ paintInvalidatedRegion();
+
+ // See if we need to draw the selection bounds rect. Selection bounds
+ // rect is the rect enclosing the (possibly transformed) selection.
+ // The rect should be drawn after everything is laid out and painted.
+ if (m_testInterfaces->testRunner()->shouldDumpSelectionRect()) {
+ // If there is a selection rect - draw a red 1px border enclosing rect
+ WebRect wr = webView()->mainFrame()->selectionBoundsRect();
+ if (!wr.isEmpty()) {
+ // Render a red rectangle bounding selection rect
+ SkPaint paint;
+ paint.setColor(0xFFFF0000); // Fully opaque red
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setFlags(SkPaint::kAntiAlias_Flag);
+ paint.setStrokeWidth(1.0f);
+ SkIRect rect; // Bounding rect
+ rect.set(wr.x, wr.y, wr.x + wr.width, wr.y + wr.height);
+ canvas()->drawIRect(rect, paint);
+ }
+ }
+
+ return canvas();
+}
+
+void WebTestProxyBase::setLogConsoleOutput(bool enabled)
+{
+ m_logConsoleOutput = enabled;
+}
+
+void WebTestProxyBase::paintRect(const WebRect& rect)
+{
+ BLINK_ASSERT(!m_isPainting);
+ BLINK_ASSERT(canvas());
+ m_isPainting = true;
+ float deviceScaleFactor = webView()->deviceScaleFactor();
+ int scaledX = static_cast<int>(static_cast<float>(rect.x) * deviceScaleFactor);
+ int scaledY = static_cast<int>(static_cast<float>(rect.y) * deviceScaleFactor);
+ int scaledWidth = static_cast<int>(ceil(static_cast<float>(rect.width) * deviceScaleFactor));
+ int scaledHeight = static_cast<int>(ceil(static_cast<float>(rect.height) * deviceScaleFactor));
+ WebRect deviceRect(scaledX, scaledY, scaledWidth, scaledHeight);
+ webWidget()->paint(canvas(), deviceRect);
+ m_isPainting = false;
+}
+
+void WebTestProxyBase::paintInvalidatedRegion()
+{
+ webWidget()->animate(0.0);
+ webWidget()->layout();
+ WebSize widgetSize = webWidget()->size();
+ WebRect clientRect(0, 0, widgetSize.width, widgetSize.height);
+
+ // Paint the canvas if necessary. Allow painting to generate extra rects
+ // for the first two calls. This is necessary because some WebCore rendering
+ // objects update their layout only when painted.
+ // Store the total area painted in total_paint. Then tell the gdk window
+ // to update that area after we're done painting it.
+ for (int i = 0; i < 3; ++i) {
+ // rect = intersect(m_paintRect , clientRect)
+ WebRect damageRect = m_paintRect;
+ int left = max(damageRect.x, clientRect.x);
+ int top = max(damageRect.y, clientRect.y);
+ int right = min(damageRect.x + damageRect.width, clientRect.x + clientRect.width);
+ int bottom = min(damageRect.y + damageRect.height, clientRect.y + clientRect.height);
+ WebRect rect;
+ if (left < right && top < bottom)
+ rect = WebRect(left, top, right - left, bottom - top);
+
+ m_paintRect = WebRect();
+ if (rect.isEmpty())
+ continue;
+ paintRect(rect);
+ }
+ BLINK_ASSERT(m_paintRect.isEmpty());
+}
+
+void WebTestProxyBase::paintPagesWithBoundaries()
+{
+ BLINK_ASSERT(!m_isPainting);
+ BLINK_ASSERT(canvas());
+ m_isPainting = true;
+
+ WebSize pageSizeInPixels = webWidget()->size();
+ WebFrame* webFrame = webView()->mainFrame();
+
+ int pageCount = webFrame->printBegin(pageSizeInPixels);
+ int totalHeight = pageCount * (pageSizeInPixels.height + 1) - 1;
+
+ SkCanvas* testCanvas = skia::TryCreateBitmapCanvas(pageSizeInPixels.width, totalHeight, true);
+ if (testCanvas) {
+ discardBackingStore();
+ m_canvas.reset(testCanvas);
+ } else {
+ webFrame->printEnd();
+ return;
+ }
+
+ webFrame->printPagesWithBoundaries(canvas(), pageSizeInPixels);
+ webFrame->printEnd();
+
+ m_isPainting = false;
+}
+
+SkCanvas* WebTestProxyBase::canvas()
+{
+ if (m_canvas.get())
+ return m_canvas.get();
+ WebSize widgetSize = webWidget()->size();
+ float deviceScaleFactor = webView()->deviceScaleFactor();
+ int scaledWidth = static_cast<int>(ceil(static_cast<float>(widgetSize.width) * deviceScaleFactor));
+ int scaledHeight = static_cast<int>(ceil(static_cast<float>(widgetSize.height) * deviceScaleFactor));
+ m_canvas.reset(skia::CreateBitmapCanvas(scaledWidth, scaledHeight, true));
+ return m_canvas.get();
+}
+
+// Paints the entire canvas a semi-transparent black (grayish). This is used
+// by the layout tests in fast/repaint. The alpha value matches upstream.
+void WebTestProxyBase::displayRepaintMask()
+{
+ canvas()->drawARGB(167, 0, 0, 0);
+}
+
+void WebTestProxyBase::display()
+{
+ const blink::WebSize& size = webWidget()->size();
+ WebRect rect(0, 0, size.width, size.height);
+ m_paintRect = rect;
+ paintInvalidatedRegion();
+ displayRepaintMask();
+}
+
+void WebTestProxyBase::displayInvalidatedRegion()
+{
+ paintInvalidatedRegion();
+ displayRepaintMask();
+}
+
+void WebTestProxyBase::discardBackingStore()
+{
+ m_canvas.reset();
+}
+
+WebGeolocationClientMock* WebTestProxyBase::geolocationClientMock()
+{
+ if (!m_geolocationClient.get())
+ m_geolocationClient.reset(WebGeolocationClientMock::create());
+ return m_geolocationClient.get();
+}
+
+WebMIDIClientMock* WebTestProxyBase::midiClientMock()
+{
+ if (!m_midiClient.get())
+ m_midiClient.reset(new WebMIDIClientMock);
+ return m_midiClient.get();
+}
+
+#if ENABLE_INPUT_SPEECH
+MockWebSpeechInputController* WebTestProxyBase::speechInputControllerMock()
+{
+ BLINK_ASSERT(m_speechInputController.get());
+ return m_speechInputController.get();
+}
+#endif
+
+MockWebSpeechRecognizer* WebTestProxyBase::speechRecognizerMock()
+{
+ if (!m_speechRecognizer.get()) {
+ m_speechRecognizer.reset(new MockWebSpeechRecognizer());
+ m_speechRecognizer->setDelegate(m_delegate);
+ }
+ return m_speechRecognizer.get();
+}
+
+void WebTestProxyBase::didInvalidateRect(const WebRect& rect)
+{
+ // m_paintRect = m_paintRect U rect
+ if (rect.isEmpty())
+ return;
+ if (m_paintRect.isEmpty()) {
+ m_paintRect = rect;
+ return;
+ }
+ int left = min(m_paintRect.x, rect.x);
+ int top = min(m_paintRect.y, rect.y);
+ int right = max(m_paintRect.x + m_paintRect.width, rect.x + rect.width);
+ int bottom = max(m_paintRect.y + m_paintRect.height, rect.y + rect.height);
+ m_paintRect = WebRect(left, top, right - left, bottom - top);
+}
+
+void WebTestProxyBase::didScrollRect(int, int, const WebRect& clipRect)
+{
+ didInvalidateRect(clipRect);
+}
+
+void WebTestProxyBase::invalidateAll()
+{
+ m_paintRect = WebRect(0, 0, INT_MAX, INT_MAX);
+}
+
+void WebTestProxyBase::scheduleComposite()
+{
+ invalidateAll();
+}
+
+void WebTestProxyBase::scheduleAnimation()
+{
+ if (!m_testInterfaces->testRunner()->testIsRunning())
+ return;
+
+ if (!m_animateScheduled) {
+ m_animateScheduled = true;
+ m_delegate->postDelayedTask(new HostMethodTask(this, &WebTestProxyBase::animateNow), 1);
+ }
+}
+
+void WebTestProxyBase::animateNow()
+{
+ if (m_animateScheduled) {
+ m_animateScheduled = false;
+ webWidget()->animate(0.0);
+ }
+}
+
+void WebTestProxyBase::show(WebNavigationPolicy)
+{
+ invalidateAll();
+}
+
+void WebTestProxyBase::setWindowRect(const WebRect& rect)
+{
+ invalidateAll();
+ discardBackingStore();
+}
+
+void WebTestProxyBase::didAutoResize(const WebSize&)
+{
+ invalidateAll();
+}
+
+void WebTestProxyBase::postAccessibilityEvent(const blink::WebAXObject& obj, blink::WebAXEvent event)
+{
+ if (event == blink::WebAXEventFocus)
+ m_testInterfaces->accessibilityController()->setFocusedElement(obj);
+
+ const char* eventName = 0;
+ switch (event) {
+ case blink::WebAXEventActiveDescendantChanged:
+ eventName = "ActiveDescendantChanged";
+ break;
+ case blink::WebAXEventAlert:
+ eventName = "Alert";
+ break;
+ case blink::WebAXEventAriaAttributeChanged:
+ eventName = "AriaAttributeChanged";
+ break;
+ case blink::WebAXEventAutocorrectionOccured:
+ eventName = "AutocorrectionOccured";
+ break;
+ case blink::WebAXEventBlur:
+ eventName = "Blur";
+ break;
+ case blink::WebAXEventCheckedStateChanged:
+ eventName = "CheckedStateChanged";
+ break;
+ case blink::WebAXEventChildrenChanged:
+ eventName = "ChildrenChanged";
+ break;
+ case blink::WebAXEventFocus:
+ eventName = "Focus";
+ break;
+ case blink::WebAXEventHide:
+ eventName = "Hide";
+ break;
+ case blink::WebAXEventInvalidStatusChanged:
+ eventName = "InvalidStatusChanged";
+ break;
+ case blink::WebAXEventLayoutComplete:
+ eventName = "LayoutComplete";
+ break;
+ case blink::WebAXEventLiveRegionChanged:
+ eventName = "LiveRegionChanged";
+ break;
+ case blink::WebAXEventLoadComplete:
+ eventName = "LoadComplete";
+ break;
+ case blink::WebAXEventLocationChanged:
+ eventName = "LocationChanged";
+ break;
+ case blink::WebAXEventMenuListItemSelected:
+ eventName = "MenuListItemSelected";
+ break;
+ case blink::WebAXEventMenuListValueChanged:
+ eventName = "MenuListValueChanged";
+ break;
+ case blink::WebAXEventRowCollapsed:
+ eventName = "RowCollapsed";
+ break;
+ case blink::WebAXEventRowCountChanged:
+ eventName = "RowCountChanged";
+ break;
+ case blink::WebAXEventRowExpanded:
+ eventName = "RowExpanded";
+ break;
+ case blink::WebAXEventScrolledToAnchor:
+ eventName = "ScrolledToAnchor";
+ break;
+ case blink::WebAXEventSelectedChildrenChanged:
+ eventName = "SelectedChildrenChanged";
+ break;
+ case blink::WebAXEventSelectedTextChanged:
+ eventName = "SelectedTextChanged";
+ break;
+ case blink::WebAXEventShow:
+ eventName = "Show";
+ break;
+ case blink::WebAXEventTextChanged:
+ eventName = "TextChanged";
+ break;
+ case blink::WebAXEventTextInserted:
+ eventName = "TextInserted";
+ break;
+ case blink::WebAXEventTextRemoved:
+ eventName = "TextRemoved";
+ break;
+ case blink::WebAXEventValueChanged:
+ eventName = "ValueChanged";
+ break;
+ }
+
+ m_testInterfaces->accessibilityController()->notificationReceived(obj, eventName);
+
+ if (m_testInterfaces->accessibilityController()->shouldLogAccessibilityEvents()) {
+ string message("AccessibilityNotification - ");
+ message += eventName;
+
+ blink::WebNode node = obj.node();
+ if (!node.isNull() && node.isElementNode()) {
+ blink::WebElement element = node.to<blink::WebElement>();
+ if (element.hasAttribute("id")) {
+ message += " - id:";
+ message += element.getAttribute("id").utf8().data();
+ }
+ }
+
+ m_delegate->printMessage(message + "\n");
+ }
+}
+
+void WebTestProxyBase::startDragging(WebFrame*, const WebDragData& data, WebDragOperationsMask mask, const WebImage&, const WebPoint&)
+{
+ // 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);
+}
+
+// The output from these methods in layout test mode should match that
+// expected by the layout tests. See EditingDelegate.m in DumpRenderTree.
+
+void WebTestProxyBase::didChangeSelection(bool isEmptySelection)
+{
+ if (m_testInterfaces->testRunner()->shouldDumpEditingCallbacks())
+ m_delegate->printMessage("EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification\n");
+}
+
+void WebTestProxyBase::didChangeContents()
+{
+ if (m_testInterfaces->testRunner()->shouldDumpEditingCallbacks())
+ m_delegate->printMessage("EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification\n");
+}
+
+bool WebTestProxyBase::createView(WebFrame*, const WebURLRequest& request, const WebWindowFeatures&, const WebString&, WebNavigationPolicy, bool)
+{
+ if (!m_testInterfaces->testRunner()->canOpenWindows())
+ return false;
+ if (m_testInterfaces->testRunner()->shouldDumpCreateView())
+ m_delegate->printMessage(string("createView(") + URLDescription(request.url()) + ")\n");
+ return true;
+}
+
+WebPlugin* WebTestProxyBase::createPlugin(WebFrame* frame, const WebPluginParams& params)
+{
+ if (params.mimeType == TestPlugin::mimeType())
+ return TestPlugin::create(frame, params, m_delegate);
+ return 0;
+}
+
+void WebTestProxyBase::setStatusText(const WebString& text)
+{
+ if (!m_testInterfaces->testRunner()->shouldDumpStatusCallbacks())
+ return;
+ m_delegate->printMessage(string("UI DELEGATE STATUS CALLBACK: setStatusText:") + text.utf8().data() + "\n");
+}
+
+void WebTestProxyBase::didStopLoading()
+{
+ if (m_testInterfaces->testRunner()->shouldDumpProgressFinishedCallback())
+ m_delegate->printMessage("postProgressFinishedNotification\n");
+}
+
+void WebTestProxyBase::showContextMenu(WebFrame*, const WebContextMenuData& contextMenuData)
+{
+ m_testInterfaces->eventSender()->setContextMenuData(contextMenuData);
+}
+
+WebUserMediaClient* WebTestProxyBase::userMediaClient()
+{
+ if (!m_userMediaClient.get())
+ m_userMediaClient.reset(new WebUserMediaClientMock(m_delegate));
+ return m_userMediaClient.get();
+}
+
+// Simulate a print by going into print mode and then exit straight away.
+void WebTestProxyBase::printPage(WebFrame* frame)
+{
+ WebSize pageSizeInPixels = webWidget()->size();
+ if (pageSizeInPixels.isEmpty())
+ return;
+ WebPrintParams printParams(pageSizeInPixels);
+ frame->printBegin(printParams);
+ frame->printEnd();
+}
+
+WebNotificationPresenter* WebTestProxyBase::notificationPresenter()
+{
+ return m_testInterfaces->testRunner()->notificationPresenter();
+}
+
+WebGeolocationClient* WebTestProxyBase::geolocationClient()
+{
+ return geolocationClientMock();
+}
+
+WebMIDIClient* WebTestProxyBase::webMIDIClient()
+{
+ return midiClientMock();
+}
+
+WebSpeechInputController* WebTestProxyBase::speechInputController(WebSpeechInputListener* listener)
+{
+#if ENABLE_INPUT_SPEECH
+ if (!m_speechInputController.get()) {
+ m_speechInputController.reset(new MockWebSpeechInputController(listener));
+ m_speechInputController->setDelegate(m_delegate);
+ }
+ return m_speechInputController.get();
+#else
+ BLINK_ASSERT(listener);
+ return 0;
+#endif
+}
+
+WebSpeechRecognizer* WebTestProxyBase::speechRecognizer()
+{
+ return speechRecognizerMock();
+}
+
+bool WebTestProxyBase::requestPointerLock()
+{
+ return m_testInterfaces->testRunner()->requestPointerLock();
+}
+
+void WebTestProxyBase::requestPointerUnlock()
+{
+ m_testInterfaces->testRunner()->requestPointerUnlock();
+}
+
+bool WebTestProxyBase::isPointerLocked()
+{
+ return m_testInterfaces->testRunner()->isPointerLocked();
+}
+
+void WebTestProxyBase::didFocus()
+{
+ m_delegate->setFocus(this, true);
+}
+
+void WebTestProxyBase::didBlur()
+{
+ m_delegate->setFocus(this, false);
+}
+
+void WebTestProxyBase::setToolTipText(const WebString& text, WebTextDirection)
+{
+ m_testInterfaces->testRunner()->setToolTipText(text);
+}
+
+void WebTestProxyBase::didOpenChooser()
+{
+ m_chooserCount++;
+}
+
+void WebTestProxyBase::didCloseChooser()
+{
+ m_chooserCount--;
+}
+
+bool WebTestProxyBase::isChooserShown()
+{
+ return 0 < m_chooserCount;
+}
+
+void WebTestProxyBase::didStartProvisionalLoad(WebFrame* frame)
+{
+ if (!m_testInterfaces->testRunner()->topLoadingFrame())
+ m_testInterfaces->testRunner()->setTopLoadingFrame(frame, false);
+
+ if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(m_delegate, frame);
+ m_delegate->printMessage(" - didStartProvisionalLoadForFrame\n");
+ }
+
+ if (m_testInterfaces->testRunner()->shouldDumpUserGestureInFrameLoadCallbacks())
+ printFrameUserGestureStatus(m_delegate, frame, " - in didStartProvisionalLoadForFrame\n");
+}
+
+void WebTestProxyBase::didReceiveServerRedirectForProvisionalLoad(WebFrame* frame)
+{
+ if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(m_delegate, frame);
+ m_delegate->printMessage(" - didReceiveServerRedirectForProvisionalLoadForFrame\n");
+ }
+}
+
+bool WebTestProxyBase::didFailProvisionalLoad(WebFrame* frame, const WebURLError&)
+{
+ if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(m_delegate, frame);
+ m_delegate->printMessage(" - didFailProvisionalLoadWithError\n");
+ }
+ locationChangeDone(frame);
+ return !frame->provisionalDataSource();
+}
+
+void WebTestProxyBase::didCommitProvisionalLoad(WebFrame* frame, bool)
+{
+ if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(m_delegate, frame);
+ m_delegate->printMessage(" - didCommitLoadForFrame\n");
+ }
+}
+
+void WebTestProxyBase::didReceiveTitle(WebFrame* frame, const WebString& title, WebTextDirection direction)
+{
+ WebCString title8 = title.utf8();
+
+ if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(m_delegate, frame);
+ m_delegate->printMessage(string(" - didReceiveTitle: ") + title8.data() + "\n");
+ }
+
+ if (m_testInterfaces->testRunner()->shouldDumpTitleChanges())
+ m_delegate->printMessage(string("TITLE CHANGED: '") + title8.data() + "'\n");
+}
+
+void WebTestProxyBase::didChangeIcon(WebFrame* frame, WebIconURL::Type)
+{
+ if (m_testInterfaces->testRunner()->shouldDumpIconChanges()) {
+ printFrameDescription(m_delegate, frame);
+ m_delegate->printMessage(string(" - didChangeIcons\n"));
+ }
+}
+
+void WebTestProxyBase::didFinishDocumentLoad(WebFrame* frame)
+{
+ if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(m_delegate, frame);
+ m_delegate->printMessage(" - didFinishDocumentLoadForFrame\n");
+ } else {
+ unsigned pendingUnloadEvents = frame->unloadListenerCount();
+ if (pendingUnloadEvents) {
+ printFrameDescription(m_delegate, frame);
+ char buffer[100];
+ snprintf(buffer, sizeof(buffer), " - has %u onunload handler(s)\n", pendingUnloadEvents);
+ m_delegate->printMessage(buffer);
+ }
+ }
+}
+
+void WebTestProxyBase::didHandleOnloadEvents(WebFrame* frame)
+{
+ if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(m_delegate, frame);
+ m_delegate->printMessage(" - didHandleOnloadEventsForFrame\n");
+ }
+}
+
+void WebTestProxyBase::didFailLoad(WebFrame* frame, const WebURLError&)
+{
+ if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(m_delegate, frame);
+ m_delegate->printMessage(" - didFailLoadWithError\n");
+ }
+ locationChangeDone(frame);
+}
+
+void WebTestProxyBase::didFinishLoad(WebFrame* frame)
+{
+ if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(m_delegate, frame);
+ m_delegate->printMessage(" - didFinishLoadForFrame\n");
+ }
+ locationChangeDone(frame);
+}
+
+void WebTestProxyBase::didDetectXSS(WebFrame*, const WebURL&, bool)
+{
+ if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks())
+ m_delegate->printMessage("didDetectXSS\n");
+}
+
+void WebTestProxyBase::didDispatchPingLoader(WebFrame*, const WebURL& url)
+{
+ if (m_testInterfaces->testRunner()->shouldDumpPingLoaderCallbacks())
+ m_delegate->printMessage(string("PingLoader dispatched to '") + URLDescription(url).c_str() + "'.\n");
+}
+
+void WebTestProxyBase::willRequestResource(WebFrame* frame, const blink::WebCachedURLRequest& request)
+{
+ if (m_testInterfaces->testRunner()->shouldDumpResourceRequestCallbacks()) {
+ printFrameDescription(m_delegate, frame);
+ m_delegate->printMessage(string(" - ") + request.initiatorName().utf8().data());
+ m_delegate->printMessage(string(" requested '") + URLDescription(request.urlRequest().url()).c_str() + "'\n");
+ }
+}
+
+void WebTestProxyBase::willSendRequest(WebFrame*, unsigned identifier, blink::WebURLRequest& request, const blink::WebURLResponse& redirectResponse)
+{
+ // Need to use GURL for host() and SchemeIs()
+ GURL url = request.url();
+ string requestURL = url.possibly_invalid_spec();
+
+ GURL mainDocumentURL = request.firstPartyForCookies();
+
+ if (redirectResponse.isNull() && (m_testInterfaces->testRunner()->shouldDumpResourceLoadCallbacks() || m_testInterfaces->testRunner()->shouldDumpResourcePriorities())) {
+ BLINK_ASSERT(m_resourceIdentifierMap.find(identifier) == m_resourceIdentifierMap.end());
+ m_resourceIdentifierMap[identifier] = descriptionSuitableForTestResult(requestURL);
+ }
+
+ if (m_testInterfaces->testRunner()->shouldDumpResourceLoadCallbacks()) {
+ if (m_resourceIdentifierMap.find(identifier) == m_resourceIdentifierMap.end())
+ m_delegate->printMessage("<unknown>");
+ else
+ m_delegate->printMessage(m_resourceIdentifierMap[identifier]);
+ m_delegate->printMessage(" - willSendRequest <NSURLRequest URL ");
+ m_delegate->printMessage(descriptionSuitableForTestResult(requestURL).c_str());
+ m_delegate->printMessage(", main document URL ");
+ m_delegate->printMessage(URLDescription(mainDocumentURL).c_str());
+ m_delegate->printMessage(", http method ");
+ m_delegate->printMessage(request.httpMethod().utf8().data());
+ m_delegate->printMessage("> redirectResponse ");
+ printResponseDescription(m_delegate, redirectResponse);
+ m_delegate->printMessage("\n");
+ }
+
+ if (m_testInterfaces->testRunner()->shouldDumpResourcePriorities()) {
+ m_delegate->printMessage(descriptionSuitableForTestResult(requestURL).c_str());
+ m_delegate->printMessage(" has priority ");
+ m_delegate->printMessage(PriorityDescription(request.priority()));
+ m_delegate->printMessage("\n");
+ }
+
+ if (m_testInterfaces->testRunner()->httpHeadersToClear()) {
+ const set<string> *clearHeaders = m_testInterfaces->testRunner()->httpHeadersToClear();
+ for (set<string>::const_iterator header = clearHeaders->begin(); header != clearHeaders->end(); ++header)
+ request.clearHTTPHeaderField(WebString::fromUTF8(*header));
+ }
+
+ string host = url.host();
+ if (!host.empty() && (url.SchemeIs("http") || url.SchemeIs("https"))) {
+ if (!isLocalhost(host) && !hostIsUsedBySomeTestsToGenerateError(host)
+ && ((!mainDocumentURL.SchemeIs("http") && !mainDocumentURL.SchemeIs("https")) || isLocalhost(mainDocumentURL.host()))
+ && !m_delegate->allowExternalPages()) {
+ m_delegate->printMessage(string("Blocked access to external URL ") + requestURL + "\n");
+ blockRequest(request);
+ return;
+ }
+ }
+
+ // Set the new substituted URL.
+ request.setURL(m_delegate->rewriteLayoutTestsURL(request.url().spec()));
+}
+
+void WebTestProxyBase::didReceiveResponse(WebFrame*, unsigned identifier, const blink::WebURLResponse& response)
+{
+ if (m_testInterfaces->testRunner()->shouldDumpResourceLoadCallbacks()) {
+ if (m_resourceIdentifierMap.find(identifier) == m_resourceIdentifierMap.end())
+ m_delegate->printMessage("<unknown>");
+ else
+ m_delegate->printMessage(m_resourceIdentifierMap[identifier]);
+ m_delegate->printMessage(" - didReceiveResponse ");
+ printResponseDescription(m_delegate, response);
+ m_delegate->printMessage("\n");
+ }
+ if (m_testInterfaces->testRunner()->shouldDumpResourceResponseMIMETypes()) {
+ GURL url = response.url();
+ WebString mimeType = response.mimeType();
+ m_delegate->printMessage(url.ExtractFileName());
+ m_delegate->printMessage(" has MIME type ");
+ // Simulate NSURLResponse's mapping of empty/unknown MIME types to application/octet-stream
+ m_delegate->printMessage(mimeType.isEmpty() ? "application/octet-stream" : mimeType.utf8().data());
+ m_delegate->printMessage("\n");
+ }
+}
+
+void WebTestProxyBase::didChangeResourcePriority(WebFrame*, unsigned identifier, const blink::WebURLRequest::Priority& priority)
+{
+ if (m_testInterfaces->testRunner()->shouldDumpResourcePriorities()) {
+ if (m_resourceIdentifierMap.find(identifier) == m_resourceIdentifierMap.end())
+ m_delegate->printMessage("<unknown>");
+ else
+ m_delegate->printMessage(m_resourceIdentifierMap[identifier]);
+ m_delegate->printMessage(" changed priority to ");
+ m_delegate->printMessage(PriorityDescription(priority));
+ m_delegate->printMessage("\n");
+ }
+}
+
+void WebTestProxyBase::didFinishResourceLoad(WebFrame*, unsigned identifier)
+{
+ if (m_testInterfaces->testRunner()->shouldDumpResourceLoadCallbacks()) {
+ if (m_resourceIdentifierMap.find(identifier) == m_resourceIdentifierMap.end())
+ m_delegate->printMessage("<unknown>");
+ else
+ m_delegate->printMessage(m_resourceIdentifierMap[identifier]);
+ m_delegate->printMessage(" - didFinishLoading\n");
+ }
+ m_resourceIdentifierMap.erase(identifier);
+}
+
+void WebTestProxyBase::didAddMessageToConsole(const WebConsoleMessage& message, const WebString& sourceName, unsigned sourceLine)
+{
+ // This matches win DumpRenderTree's UIDelegate.cpp.
+ if (!m_logConsoleOutput)
+ return;
+ string level;
+ switch (message.level) {
+ case WebConsoleMessage::LevelDebug:
+ level = "DEBUG";
+ break;
+ case WebConsoleMessage::LevelLog:
+ level = "MESSAGE";
+ break;
+ case WebConsoleMessage::LevelInfo:
+ level = "INFO";
+ break;
+ case WebConsoleMessage::LevelWarning:
+ level = "WARNING";
+ break;
+ case WebConsoleMessage::LevelError:
+ level = "ERROR";
+ break;
+ }
+ m_delegate->printMessage(string("CONSOLE ") + level + ": ");
+ if (sourceLine) {
+ char buffer[40];
+ snprintf(buffer, sizeof(buffer), "line %d: ", sourceLine);
+ m_delegate->printMessage(buffer);
+ }
+ if (!message.text.isEmpty()) {
+ string newMessage;
+ newMessage = message.text.utf8();
+ size_t fileProtocol = newMessage.find("file://");
+ if (fileProtocol != string::npos) {
+ newMessage = newMessage.substr(0, fileProtocol)
+ + urlSuitableForTestResult(newMessage.substr(fileProtocol));
+ }
+ m_delegate->printMessage(newMessage);
+ }
+ m_delegate->printMessage(string("\n"));
+}
+
+void WebTestProxyBase::runModalAlertDialog(WebFrame*, const WebString& message)
+{
+ m_delegate->printMessage(string("ALERT: ") + message.utf8().data() + "\n");
+}
+
+bool WebTestProxyBase::runModalConfirmDialog(WebFrame*, const WebString& message)
+{
+ m_delegate->printMessage(string("CONFIRM: ") + message.utf8().data() + "\n");
+ return true;
+}
+
+bool WebTestProxyBase::runModalPromptDialog(WebFrame* frame, const WebString& message, const WebString& defaultValue, WebString*)
+{
+ m_delegate->printMessage(string("PROMPT: ") + message.utf8().data() + ", default text: " + defaultValue.utf8().data() + "\n");
+ return true;
+}
+
+bool WebTestProxyBase::runModalBeforeUnloadDialog(WebFrame*, const WebString& message)
+{
+ m_delegate->printMessage(string("CONFIRM NAVIGATION: ") + message.utf8().data() + "\n");
+ return !m_testInterfaces->testRunner()->shouldStayOnPageAfterHandlingBeforeUnload();
+}
+
+void WebTestProxyBase::locationChangeDone(WebFrame* frame)
+{
+ if (frame != m_testInterfaces->testRunner()->topLoadingFrame())
+ return;
+ m_testInterfaces->testRunner()->setTopLoadingFrame(frame, true);
+}
+
+WebNavigationPolicy WebTestProxyBase::decidePolicyForNavigation(WebFrame*, WebDataSource::ExtraData*, const WebURLRequest& request, WebNavigationType type, WebNavigationPolicy defaultPolicy, bool isRedirect)
+{
+ WebNavigationPolicy result;
+ if (!m_testInterfaces->testRunner()->policyDelegateEnabled())
+ return defaultPolicy;
+
+ m_delegate->printMessage(string("Policy delegate: attempt to load ") + URLDescription(request.url()) + " with navigation type '" + webNavigationTypeToString(type) + "'\n");
+ if (m_testInterfaces->testRunner()->policyDelegateIsPermissive())
+ result = blink::WebNavigationPolicyCurrentTab;
+ else
+ result = blink::WebNavigationPolicyIgnore;
+
+ if (m_testInterfaces->testRunner()->policyDelegateShouldNotifyDone())
+ m_testInterfaces->testRunner()->policyDelegateDone();
+ return result;
+}
+
+bool WebTestProxyBase::willCheckAndDispatchMessageEvent(WebFrame*, WebFrame*, WebSecurityOrigin, WebDOMMessageEvent)
+{
+ if (m_testInterfaces->testRunner()->shouldInterceptPostMessage()) {
+ m_delegate->printMessage("intercepted postMessage\n");
+ return true;
+ }
+
+ return false;
+}
+
+void WebTestProxyBase::postSpellCheckEvent(const WebString& eventName)
+{
+ if (m_testInterfaces->testRunner()->shouldDumpSpellCheckCallbacks()) {
+ m_delegate->printMessage(string("SpellCheckEvent: ") + eventName.utf8().data() + "\n");
+ }
+}
+
+void WebTestProxyBase::resetInputMethod()
+{
+ // If a composition text exists, then we need to let the browser process
+ // to cancel the input method's ongoing composition session.
+ if (m_webWidget)
+ m_webWidget->confirmComposition();
+}
+
+}
diff --git a/content/shell/renderer/test_runner/WebTestProxy.h b/content/shell/renderer/test_runner/WebTestProxy.h
new file mode 100644
index 0000000..4f406fbd
--- /dev/null
+++ b/content/shell/renderer/test_runner/WebTestProxy.h
@@ -0,0 +1,539 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WebTestProxy_h
+#define WebTestProxy_h
+
+#include <map>
+#include <string>
+
+#include "content/shell/renderer/test_runner/WebScopedPtr.h"
+#include "content/shell/renderer/test_runner/WebTask.h"
+#include "third_party/WebKit/public/platform/WebNonCopyable.h"
+#include "third_party/WebKit/public/platform/WebRect.h"
+#include "third_party/WebKit/public/platform/WebURLError.h"
+#include "third_party/WebKit/public/platform/WebURLRequest.h"
+#include "third_party/WebKit/public/web/WebAXEnums.h"
+#include "third_party/WebKit/public/web/WebDOMMessageEvent.h"
+#include "third_party/WebKit/public/web/WebDataSource.h"
+#include "third_party/WebKit/public/web/WebDragOperation.h"
+#include "third_party/WebKit/public/web/WebIconURL.h"
+#include "third_party/WebKit/public/web/WebNavigationPolicy.h"
+#include "third_party/WebKit/public/web/WebNavigationType.h"
+#include "third_party/WebKit/public/web/WebSecurityOrigin.h"
+#include "third_party/WebKit/public/web/WebTextAffinity.h"
+#include "third_party/WebKit/public/web/WebTextDirection.h"
+
+namespace blink {
+class WebAXObject;
+class WebAudioDevice;
+class WebCachedURLRequest;
+class WebColorChooser;
+class WebColorChooserClient;
+class WebDataSource;
+class WebDragData;
+class WebFileChooserCompletion;
+class WebFrame;
+class WebGeolocationClient;
+class WebGeolocationClientMock;
+class WebImage;
+class WebMIDIAccessor;
+class WebMIDIAccessorClient;
+class WebMIDIClient;
+class WebMIDIClientMock;
+class WebNode;
+class WebNotificationPresenter;
+class WebPlugin;
+class WebRange;
+class WebSerializedScriptValue;
+class WebSpeechInputController;
+class WebSpeechInputListener;
+class WebSpeechRecognizer;
+class WebSpellCheckClient;
+class WebString;
+class WebURL;
+class WebURLResponse;
+class WebUserMediaClient;
+class WebView;
+class WebWidget;
+struct WebColorSuggestion;
+struct WebConsoleMessage;
+struct WebContextMenuData;
+struct WebFileChooserParams;
+struct WebPluginParams;
+struct WebPoint;
+struct WebSize;
+struct WebWindowFeatures;
+typedef unsigned WebColor;
+}
+
+class SkCanvas;
+
+namespace WebTestRunner {
+
+class MockWebSpeechInputController;
+class MockWebSpeechRecognizer;
+class SpellCheckClient;
+class TestInterfaces;
+class WebTestDelegate;
+class WebTestInterfaces;
+class WebTestRunner;
+class WebUserMediaClientMock;
+
+class WebTestProxyBase {
+public:
+ void setInterfaces(WebTestInterfaces*);
+ void setDelegate(WebTestDelegate*);
+ void setWidget(blink::WebWidget*);
+
+ void reset();
+
+ blink::WebSpellCheckClient *spellCheckClient() const;
+ blink::WebColorChooser* createColorChooser(blink::WebColorChooserClient*, const blink::WebColor&);
+ blink::WebColorChooser* createColorChooser(blink::WebColorChooserClient*, const blink::WebColor&, const blink::WebVector<blink::WebColorSuggestion>& suggestions);
+ bool runFileChooser(const blink::WebFileChooserParams&, blink::WebFileChooserCompletion*);
+ void showValidationMessage(const blink::WebRect& anchorInRootView, const blink::WebString& mainText, const blink::WebString& supplementalText, blink::WebTextDirection);
+ void hideValidationMessage();
+ void moveValidationMessage(const blink::WebRect& anchorInRootView);
+
+ std::string captureTree(bool debugRenderTree);
+ SkCanvas* capturePixels();
+
+ void setLogConsoleOutput(bool enabled);
+
+ // FIXME: Make this private again.
+ void scheduleComposite();
+
+ void didOpenChooser();
+ void didCloseChooser();
+ bool isChooserShown();
+
+ void display();
+ void displayInvalidatedRegion();
+ void discardBackingStore();
+
+ blink::WebGeolocationClientMock* geolocationClientMock();
+ blink::WebMIDIClientMock* midiClientMock();
+ MockWebSpeechInputController* speechInputControllerMock();
+ MockWebSpeechRecognizer* speechRecognizerMock();
+
+ WebTaskList* taskList() { return &m_taskList; }
+
+ blink::WebView* webView();
+
+ void didForceResize();
+
+ void postSpellCheckEvent(const blink::WebString& eventName);
+
+protected:
+ WebTestProxyBase();
+ ~WebTestProxyBase();
+
+ void didInvalidateRect(const blink::WebRect&);
+ void didScrollRect(int, int, const blink::WebRect&);
+ void scheduleAnimation();
+ // FIXME: Remove once we switch to use didForceResize.
+ void setWindowRect(const blink::WebRect&);
+ void show(blink::WebNavigationPolicy);
+ void didAutoResize(const blink::WebSize&);
+ void postAccessibilityEvent(const blink::WebAXObject&, blink::WebAXEvent);
+ void startDragging(blink::WebFrame*, const blink::WebDragData&, blink::WebDragOperationsMask, const blink::WebImage&, const blink::WebPoint&);
+ void didChangeSelection(bool isEmptySelection);
+ void didChangeContents();
+ void didEndEditing();
+ bool createView(blink::WebFrame* creator, const blink::WebURLRequest&, const blink::WebWindowFeatures&, const blink::WebString& frameName, blink::WebNavigationPolicy, bool suppressOpener);
+ blink::WebPlugin* createPlugin(blink::WebFrame*, const blink::WebPluginParams&);
+ void setStatusText(const blink::WebString&);
+ void didStopLoading();
+ void showContextMenu(blink::WebFrame*, const blink::WebContextMenuData&);
+ blink::WebUserMediaClient* userMediaClient();
+ void printPage(blink::WebFrame*);
+ blink::WebNotificationPresenter* notificationPresenter();
+ blink::WebGeolocationClient* geolocationClient();
+ blink::WebMIDIClient* webMIDIClient();
+ blink::WebSpeechInputController* speechInputController(blink::WebSpeechInputListener*);
+ blink::WebSpeechRecognizer* speechRecognizer();
+ bool requestPointerLock();
+ void requestPointerUnlock();
+ bool isPointerLocked();
+ void didFocus();
+ void didBlur();
+ void setToolTipText(const blink::WebString&, blink::WebTextDirection);
+ void didAddMessageToConsole(const blink::WebConsoleMessage&, const blink::WebString& sourceName, unsigned sourceLine);
+ void runModalAlertDialog(blink::WebFrame*, const blink::WebString&);
+ bool runModalConfirmDialog(blink::WebFrame*, const blink::WebString&);
+ bool runModalPromptDialog(blink::WebFrame*, const blink::WebString& message, const blink::WebString& defaultValue, blink::WebString* actualValue);
+ bool runModalBeforeUnloadDialog(blink::WebFrame*, const blink::WebString&);
+
+ void didStartProvisionalLoad(blink::WebFrame*);
+ void didReceiveServerRedirectForProvisionalLoad(blink::WebFrame*);
+ bool didFailProvisionalLoad(blink::WebFrame*, const blink::WebURLError&);
+ void didCommitProvisionalLoad(blink::WebFrame*, bool isNewNavigation);
+ void didReceiveTitle(blink::WebFrame*, const blink::WebString& title, blink::WebTextDirection);
+ void didChangeIcon(blink::WebFrame*, blink::WebIconURL::Type);
+ void didFinishDocumentLoad(blink::WebFrame*);
+ void didHandleOnloadEvents(blink::WebFrame*);
+ void didFailLoad(blink::WebFrame*, const blink::WebURLError&);
+ void didFinishLoad(blink::WebFrame*);
+ void didChangeLocationWithinPage(blink::WebFrame*);
+ void didDetectXSS(blink::WebFrame*, const blink::WebURL& insecureURL, bool didBlockEntirePage);
+ void didDispatchPingLoader(blink::WebFrame*, const blink::WebURL&);
+ void willRequestResource(blink::WebFrame*, const blink::WebCachedURLRequest&);
+ void willSendRequest(blink::WebFrame*, unsigned identifier, blink::WebURLRequest&, const blink::WebURLResponse& redirectResponse);
+ void didReceiveResponse(blink::WebFrame*, unsigned identifier, const blink::WebURLResponse&);
+ void didChangeResourcePriority(blink::WebFrame*, unsigned identifier, const blink::WebURLRequest::Priority&);
+ void didFinishResourceLoad(blink::WebFrame*, unsigned identifier);
+ blink::WebNavigationPolicy decidePolicyForNavigation(blink::WebFrame*, blink::WebDataSource::ExtraData*, const blink::WebURLRequest&, blink::WebNavigationType, blink::WebNavigationPolicy defaultPolicy, bool isRedirect);
+ bool willCheckAndDispatchMessageEvent(blink::WebFrame* sourceFrame, blink::WebFrame* targetFrame, blink::WebSecurityOrigin target, blink::WebDOMMessageEvent);
+ void resetInputMethod();
+
+private:
+ template<class, typename, typename> friend class WebFrameTestProxy;
+ void locationChangeDone(blink::WebFrame*);
+ void paintRect(const blink::WebRect&);
+ void paintInvalidatedRegion();
+ void paintPagesWithBoundaries();
+ SkCanvas* canvas();
+ void displayRepaintMask();
+ void invalidateAll();
+ void animateNow();
+
+ blink::WebWidget* webWidget();
+
+ TestInterfaces* m_testInterfaces;
+ WebTestDelegate* m_delegate;
+ blink::WebWidget* m_webWidget;
+
+ WebTaskList m_taskList;
+
+ WebScopedPtr<SpellCheckClient> m_spellcheck;
+ WebScopedPtr<WebUserMediaClientMock> m_userMediaClient;
+
+ // Painting.
+ WebScopedPtr<SkCanvas> m_canvas;
+ blink::WebRect m_paintRect;
+ bool m_isPainting;
+ bool m_animateScheduled;
+ std::map<unsigned, std::string> m_resourceIdentifierMap;
+ std::map<unsigned, blink::WebURLRequest> m_requestMap;
+
+ bool m_logConsoleOutput;
+ int m_chooserCount;
+
+ WebScopedPtr<blink::WebGeolocationClientMock> m_geolocationClient;
+ WebScopedPtr<blink::WebMIDIClientMock> m_midiClient;
+ WebScopedPtr<MockWebSpeechRecognizer> m_speechRecognizer;
+ WebScopedPtr<MockWebSpeechInputController> m_speechInputController;
+
+ // FIXME:: We want to move away from this pattern and mark classes
+ // as Noncopyable, but this class is marked as WEBTESTRUNNER_EXPORT
+ // while WebNonCopyable is not, so we cannot inherit from WebNonCopyable.
+ // To overcome the problem, for now not inheriting from WebNonCopyable
+ // but plan to fix it when we make the change of making WebNonCopyable
+ // a macro rather than class. We will have a single way to mark all classes
+ // as Noncopyable.
+ // Tracked under: http://code.google.com/p/chromium/issues/detail?id=229178
+private:
+ WebTestProxyBase(WebTestProxyBase&);
+ WebTestProxyBase& operator=(const WebTestProxyBase&);
+};
+
+// Use this template to inject methods into your WebViewClient/WebFrameClient
+// implementation required for the running layout tests.
+template<class Base, typename T>
+class WebTestProxy : public Base, public WebTestProxyBase, public blink::WebNonCopyable {
+public:
+ explicit WebTestProxy(T t)
+ : Base(t)
+ {
+ }
+
+ virtual ~WebTestProxy() { }
+
+ // WebViewClient implementation.
+ virtual void didInvalidateRect(const blink::WebRect& rect)
+ {
+ WebTestProxyBase::didInvalidateRect(rect);
+ }
+ virtual void didScrollRect(int dx, int dy, const blink::WebRect& clipRect)
+ {
+ WebTestProxyBase::didScrollRect(dx, dy, clipRect);
+ }
+ virtual void scheduleComposite()
+ {
+ WebTestProxyBase::scheduleComposite();
+ }
+ virtual void scheduleAnimation()
+ {
+ WebTestProxyBase::scheduleAnimation();
+ }
+ virtual void setWindowRect(const blink::WebRect& rect)
+ {
+ WebTestProxyBase::setWindowRect(rect);
+ Base::setWindowRect(rect);
+ }
+ virtual void show(blink::WebNavigationPolicy policy)
+ {
+ WebTestProxyBase::show(policy);
+ Base::show(policy);
+ }
+ virtual void didAutoResize(const blink::WebSize& newSize)
+ {
+ WebTestProxyBase::didAutoResize(newSize);
+ Base::didAutoResize(newSize);
+ }
+ virtual void postAccessibilityEvent(const blink::WebAXObject& object, blink::WebAXEvent event)
+ {
+ WebTestProxyBase::postAccessibilityEvent(object, event);
+ Base::postAccessibilityEvent(object, event);
+ }
+ virtual void startDragging(blink::WebFrame* frame, const blink::WebDragData& data, blink::WebDragOperationsMask mask, const blink::WebImage& image, const blink::WebPoint& point)
+ {
+ WebTestProxyBase::startDragging(frame, data, mask, image, point);
+ // Don't forward this call to Base because we don't want to do a real drag-and-drop.
+ }
+ virtual void didChangeSelection(bool isEmptySelection)
+ {
+ WebTestProxyBase::didChangeSelection(isEmptySelection);
+ Base::didChangeSelection(isEmptySelection);
+ }
+ virtual void didChangeContents()
+ {
+ WebTestProxyBase::didChangeContents();
+ Base::didChangeContents();
+ }
+ virtual blink::WebView* createView(blink::WebFrame* creator, const blink::WebURLRequest& request, const blink::WebWindowFeatures& features, const blink::WebString& frameName, blink::WebNavigationPolicy policy, bool suppressOpener)
+ {
+ if (!WebTestProxyBase::createView(creator, request, features, frameName, policy, suppressOpener))
+ return 0;
+ return Base::createView(creator, request, features, frameName, policy, suppressOpener);
+ }
+ virtual void setStatusText(const blink::WebString& text)
+ {
+ WebTestProxyBase::setStatusText(text);
+ Base::setStatusText(text);
+ }
+ virtual void didStopLoading()
+ {
+ WebTestProxyBase::didStopLoading();
+ Base::didStopLoading();
+ }
+ virtual void showContextMenu(blink::WebFrame* frame, const blink::WebContextMenuData& contextMenuData)
+ {
+ WebTestProxyBase::showContextMenu(frame, contextMenuData);
+ Base::showContextMenu(frame, contextMenuData);
+ }
+ virtual blink::WebUserMediaClient* userMediaClient()
+ {
+ return WebTestProxyBase::userMediaClient();
+ }
+ virtual void printPage(blink::WebFrame* frame)
+ {
+ WebTestProxyBase::printPage(frame);
+ }
+ virtual blink::WebNotificationPresenter* notificationPresenter()
+ {
+ return WebTestProxyBase::notificationPresenter();
+ }
+ virtual blink::WebGeolocationClient* geolocationClient()
+ {
+ return WebTestProxyBase::geolocationClient();
+ }
+ virtual blink::WebMIDIClient* webMIDIClient()
+ {
+ return WebTestProxyBase::webMIDIClient();
+ }
+ virtual blink::WebSpeechInputController* speechInputController(blink::WebSpeechInputListener* listener)
+ {
+ return WebTestProxyBase::speechInputController(listener);
+ }
+ virtual blink::WebSpeechRecognizer* speechRecognizer()
+ {
+ return WebTestProxyBase::speechRecognizer();
+ }
+ virtual bool requestPointerLock()
+ {
+ return WebTestProxyBase::requestPointerLock();
+ }
+ virtual void requestPointerUnlock()
+ {
+ WebTestProxyBase::requestPointerUnlock();
+ }
+ virtual bool isPointerLocked()
+ {
+ return WebTestProxyBase::isPointerLocked();
+ }
+ virtual void didFocus()
+ {
+ WebTestProxyBase::didFocus();
+ Base::didFocus();
+ }
+ virtual void didBlur()
+ {
+ WebTestProxyBase::didBlur();
+ Base::didBlur();
+ }
+ virtual void setToolTipText(const blink::WebString& text, blink::WebTextDirection hint)
+ {
+ WebTestProxyBase::setToolTipText(text, hint);
+ Base::setToolTipText(text, hint);
+ }
+ virtual void resetInputMethod()
+ {
+ WebTestProxyBase::resetInputMethod();
+ }
+
+ virtual void didStartProvisionalLoad(blink::WebFrame* frame)
+ {
+ WebTestProxyBase::didStartProvisionalLoad(frame);
+ Base::didStartProvisionalLoad(frame);
+ }
+ virtual void didReceiveServerRedirectForProvisionalLoad(blink::WebFrame* frame)
+ {
+ WebTestProxyBase::didReceiveServerRedirectForProvisionalLoad(frame);
+ Base::didReceiveServerRedirectForProvisionalLoad(frame);
+ }
+ virtual void didFailProvisionalLoad(blink::WebFrame* frame, const blink::WebURLError& error)
+ {
+ // If the test finished, don't notify the embedder of the failed load,
+ // as we already destroyed the document loader.
+ if (WebTestProxyBase::didFailProvisionalLoad(frame, error))
+ return;
+ Base::didFailProvisionalLoad(frame, error);
+ }
+ virtual void didCommitProvisionalLoad(blink::WebFrame* frame, bool isNewNavigation)
+ {
+ WebTestProxyBase::didCommitProvisionalLoad(frame, isNewNavigation);
+ Base::didCommitProvisionalLoad(frame, isNewNavigation);
+ }
+ virtual void didReceiveTitle(blink::WebFrame* frame, const blink::WebString& title, blink::WebTextDirection direction)
+ {
+ WebTestProxyBase::didReceiveTitle(frame, title, direction);
+ Base::didReceiveTitle(frame, title, direction);
+ }
+ virtual void didChangeIcon(blink::WebFrame* frame, blink::WebIconURL::Type iconType)
+ {
+ WebTestProxyBase::didChangeIcon(frame, iconType);
+ Base::didChangeIcon(frame, iconType);
+ }
+ virtual void didFinishDocumentLoad(blink::WebFrame* frame)
+ {
+ WebTestProxyBase::didFinishDocumentLoad(frame);
+ Base::didFinishDocumentLoad(frame);
+ }
+ virtual void didHandleOnloadEvents(blink::WebFrame* frame)
+ {
+ WebTestProxyBase::didHandleOnloadEvents(frame);
+ Base::didHandleOnloadEvents(frame);
+ }
+ virtual void didFailLoad(blink::WebFrame* frame, const blink::WebURLError& error)
+ {
+ WebTestProxyBase::didFailLoad(frame, error);
+ Base::didFailLoad(frame, error);
+ }
+ virtual void didFinishLoad(blink::WebFrame* frame)
+ {
+ WebTestProxyBase::didFinishLoad(frame);
+ Base::didFinishLoad(frame);
+ }
+ virtual void didDetectXSS(blink::WebFrame* frame, const blink::WebURL& insecureURL, bool didBlockEntirePage)
+ {
+ WebTestProxyBase::didDetectXSS(frame, insecureURL, didBlockEntirePage);
+ Base::didDetectXSS(frame, insecureURL, didBlockEntirePage);
+ }
+ virtual void willRequestResource(blink::WebFrame* frame, const blink::WebCachedURLRequest& request)
+ {
+ WebTestProxyBase::willRequestResource(frame, request);
+ Base::willRequestResource(frame, request);
+ }
+ virtual void willSendRequest(blink::WebFrame* frame, unsigned identifier, blink::WebURLRequest& request, const blink::WebURLResponse& redirectResponse)
+ {
+ WebTestProxyBase::willSendRequest(frame, identifier, request, redirectResponse);
+ Base::willSendRequest(frame, identifier, request, redirectResponse);
+ }
+ virtual void didReceiveResponse(blink::WebFrame* frame, unsigned identifier, const blink::WebURLResponse& response)
+ {
+ WebTestProxyBase::didReceiveResponse(frame, identifier, response);
+ Base::didReceiveResponse(frame, identifier, response);
+ }
+ virtual void didChangeResourcePriority(blink::WebFrame* frame, unsigned identifier, const blink::WebURLRequest::Priority& priority)
+ {
+ WebTestProxyBase::didChangeResourcePriority(frame, identifier, priority);
+ Base::didChangeResourcePriority(frame, identifier, priority);
+ }
+ virtual void didFinishResourceLoad(blink::WebFrame* frame, unsigned identifier)
+ {
+ WebTestProxyBase::didFinishResourceLoad(frame, identifier);
+ Base::didFinishResourceLoad(frame, identifier);
+ }
+ virtual void didAddMessageToConsole(const blink::WebConsoleMessage& message, const blink::WebString& sourceName, unsigned sourceLine, const blink::WebString& stackTrace)
+ {
+ WebTestProxyBase::didAddMessageToConsole(message, sourceName, sourceLine);
+ Base::didAddMessageToConsole(message, sourceName, sourceLine, stackTrace);
+ }
+ virtual void runModalAlertDialog(blink::WebFrame* frame, const blink::WebString& message)
+ {
+ WebTestProxyBase::runModalAlertDialog(frame, message);
+ Base::runModalAlertDialog(frame, message);
+ }
+ virtual bool runModalConfirmDialog(blink::WebFrame* frame, const blink::WebString& message)
+ {
+ WebTestProxyBase::runModalConfirmDialog(frame, message);
+ return Base::runModalConfirmDialog(frame, message);
+ }
+ virtual bool runModalPromptDialog(blink::WebFrame* frame, const blink::WebString& message, const blink::WebString& defaultValue, blink::WebString* actualValue)
+ {
+ WebTestProxyBase::runModalPromptDialog(frame, message, defaultValue, actualValue);
+ return Base::runModalPromptDialog(frame, message, defaultValue, actualValue);
+ }
+ virtual bool runModalBeforeUnloadDialog(blink::WebFrame* frame, const blink::WebString& message)
+ {
+ return WebTestProxyBase::runModalBeforeUnloadDialog(frame, message);
+ }
+ virtual blink::WebNavigationPolicy decidePolicyForNavigation(blink::WebFrame* frame, blink::WebDataSource::ExtraData* extraData, const blink::WebURLRequest& request, blink::WebNavigationType type, blink::WebNavigationPolicy defaultPolicy, bool isRedirect)
+ {
+ blink::WebNavigationPolicy policy = WebTestProxyBase::decidePolicyForNavigation(frame, extraData, request, type, defaultPolicy, isRedirect);
+ if (policy == blink::WebNavigationPolicyIgnore)
+ return policy;
+ return Base::decidePolicyForNavigation(frame, extraData, request, type, defaultPolicy, isRedirect);
+ }
+ virtual bool willCheckAndDispatchMessageEvent(blink::WebFrame* sourceFrame, blink::WebFrame* targetFrame, blink::WebSecurityOrigin target, blink::WebDOMMessageEvent event)
+ {
+ if (WebTestProxyBase::willCheckAndDispatchMessageEvent(sourceFrame, targetFrame, target, event))
+ return true;
+ return Base::willCheckAndDispatchMessageEvent(sourceFrame, targetFrame, target, event);
+ }
+ virtual blink::WebColorChooser* createColorChooser(blink::WebColorChooserClient* client, const blink::WebColor& color)
+ {
+ return WebTestProxyBase::createColorChooser(client, color);
+ }
+ virtual blink::WebColorChooser* createColorChooser(blink::WebColorChooserClient* client, const blink::WebColor& color, const blink::WebVector<blink::WebColorSuggestion>& suggestions)
+ {
+ return WebTestProxyBase::createColorChooser(client, color, suggestions);
+ }
+ virtual bool runFileChooser(const blink::WebFileChooserParams& params, blink::WebFileChooserCompletion* completion)
+ {
+ return WebTestProxyBase::runFileChooser(params, completion);
+ }
+ virtual void showValidationMessage(const blink::WebRect& anchorInRootView, const blink::WebString& mainText, const blink::WebString& supplementalText, blink::WebTextDirection hint)
+ {
+ WebTestProxyBase::showValidationMessage(anchorInRootView, mainText, supplementalText, hint);
+ }
+ virtual void hideValidationMessage()
+ {
+ WebTestProxyBase::hideValidationMessage();
+ }
+ virtual void moveValidationMessage(const blink::WebRect& anchorInRootView)
+ {
+ WebTestProxyBase::moveValidationMessage(anchorInRootView);
+ }
+ virtual void postSpellCheckEvent(const blink::WebString& eventName)
+ {
+ WebTestProxyBase::postSpellCheckEvent(eventName);
+ }
+};
+
+}
+
+#endif // WebTestProxy_h
diff --git a/content/shell/renderer/test_runner/WebTestRunner.h b/content/shell/renderer/test_runner/WebTestRunner.h
new file mode 100644
index 0000000..1ae5c30
--- /dev/null
+++ b/content/shell/renderer/test_runner/WebTestRunner.h
@@ -0,0 +1,41 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WebTestRunner_h
+#define WebTestRunner_h
+
+namespace blink {
+class WebArrayBufferView;
+class WebPermissionClient;
+}
+
+namespace WebTestRunner {
+
+class WebTestRunner {
+public:
+ // Returns a mock WebPermissionClient that is used for layout tests. An
+ // embedder should use this for all WebViews it creates.
+ virtual blink::WebPermissionClient* webPermissions() const = 0;
+
+ // After WebTestDelegate::testFinished was invoked, the following methods
+ // can be used to determine what kind of dump the main WebTestProxy can
+ // provide.
+
+ // If true, WebTestDelegate::audioData returns an audio dump and no text
+ // or pixel results are available.
+ virtual bool shouldDumpAsAudio() const = 0;
+ virtual const blink::WebArrayBufferView* audioData() const = 0;
+
+ // Returns true if the call to WebTestProxy::captureTree will invoke
+ // WebTestDelegate::captureHistoryForWindow.
+ virtual bool shouldDumpBackForwardList() const = 0;
+
+ // Returns true if WebTestProxy::capturePixels should be invoked after
+ // capturing text results.
+ virtual bool shouldGeneratePixelResults() = 0;
+};
+
+}
+
+#endif // WebTestRunner_h
diff --git a/content/shell/renderer/test_runner/WebTestThemeControlWin.cpp b/content/shell/renderer/test_runner/WebTestThemeControlWin.cpp
new file mode 100644
index 0000000..28f089a
--- /dev/null
+++ b/content/shell/renderer/test_runner/WebTestThemeControlWin.cpp
@@ -0,0 +1,465 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file implements a simple generic version of the WebThemeEngine,
+// which is used to draw all the native controls on a web page. We use this
+// file when running in layout test mode in order to remove any
+// platform-specific rendering differences due to themes, colors, etc.
+//
+
+#include "content/shell/renderer/test_runner/WebTestThemeControlWin.h"
+
+#include "content/shell/renderer/test_runner/TestCommon.h"
+#include "skia/ext/skia_utils_win.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkPaint.h"
+#include "third_party/skia/include/core/SkPath.h"
+
+#include <algorithm>
+
+using namespace blink;
+using namespace std;
+
+namespace WebTestRunner {
+
+namespace {
+
+const SkColor edgeColor = SK_ColorBLACK;
+const SkColor readOnlyColor = SkColorSetRGB(0xe9, 0xc2, 0xa6);
+const SkColor fgColor = SK_ColorBLACK;
+
+// These are indexed by WebTestThemeControlWin::State, *not* WebThemeEngine::State.
+const SkColor bgColors[] = {
+ SK_ColorBLACK, // Unknown (not used)
+ SkColorSetRGB(0xc9, 0xc9, 0xc9), // Disabled
+ SkColorSetRGB(0xf3, 0xe0, 0xd0), // Readonly
+ SkColorSetRGB(0x89, 0xc4, 0xff), // Normal
+ SkColorSetRGB(0x43, 0xf9, 0xff), // Hot
+ SkColorSetRGB(0x20, 0xf6, 0xcc), // Hover
+ SkColorSetRGB(0x00, 0xf3, 0xac), // Focused
+ SkColorSetRGB(0xa9, 0xff, 0x12), // Pressed
+ SkColorSetRGB(0xcc, 0xcc, 0xcc) // Indeterminate (not used)
+};
+
+SkIRect validate(const SkIRect& rect, WebTestThemeControlWin::Type ctype)
+{
+ switch (ctype) {
+ case WebTestThemeControlWin::UncheckedBoxType:
+ case WebTestThemeControlWin::CheckedBoxType:
+ case WebTestThemeControlWin::UncheckedRadioType:
+ case WebTestThemeControlWin::CheckedRadioType: {
+ SkIRect retval = rect;
+
+ // The maximum width and height is 13.
+ // Center the square in the passed rectangle.
+ const int maxControlSize = 13;
+ int controlSize = std::min(rect.width(), rect.height());
+ controlSize = std::min(controlSize, maxControlSize);
+
+ retval.fLeft = rect.fLeft + (rect.width() / 2) - (controlSize / 2);
+ retval.fRight = retval.fLeft + controlSize - 1;
+ retval.fTop = rect.fTop + (rect.height() / 2) - (controlSize / 2);
+ retval.fBottom = retval.fTop + controlSize - 1;
+
+ return retval;
+ }
+
+ default:
+ return rect;
+ }
+}
+
+}
+
+WebTestThemeControlWin::WebTestThemeControlWin(SkCanvas* canvas, const SkIRect& irect, Type ctype, State cstate)
+ : m_canvas(canvas)
+ , m_irect(validate(irect, ctype))
+ , m_type(ctype)
+ , m_state(cstate)
+ , m_left(m_irect.fLeft)
+ , m_right(m_irect.fRight)
+ , m_top(m_irect.fTop)
+ , m_bottom(m_irect.fBottom)
+ , m_height(m_irect.height())
+ , m_width(m_irect.width())
+ , m_edgeColor(edgeColor)
+ , m_bgColor(bgColors[cstate])
+ , m_fgColor(fgColor)
+{
+}
+
+WebTestThemeControlWin::~WebTestThemeControlWin()
+{
+}
+
+void WebTestThemeControlWin::box(const SkIRect& rect, SkColor fillColor)
+{
+ SkPaint paint;
+
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setColor(fillColor);
+ m_canvas->drawIRect(rect, paint);
+
+ paint.setColor(m_edgeColor);
+ paint.setStyle(SkPaint::kStroke_Style);
+ m_canvas->drawIRect(rect, paint);
+}
+
+void WebTestThemeControlWin::line(int x0, int y0, int x1, int y1, SkColor color)
+{
+ SkPaint paint;
+ paint.setColor(color);
+ m_canvas->drawLine(SkIntToScalar(x0), SkIntToScalar(y0), SkIntToScalar(x1), SkIntToScalar(y1), paint);
+}
+
+void WebTestThemeControlWin::triangle(int x0, int y0, int x1, int y1, int x2, int y2, SkColor color)
+{
+ SkPath path;
+ SkPaint paint;
+
+ paint.setColor(color);
+ paint.setStyle(SkPaint::kFill_Style);
+ path.incReserve(4);
+ path.moveTo(SkIntToScalar(x0), SkIntToScalar(y0));
+ path.lineTo(SkIntToScalar(x1), SkIntToScalar(y1));
+ path.lineTo(SkIntToScalar(x2), SkIntToScalar(y2));
+ path.close();
+ m_canvas->drawPath(path, paint);
+
+ paint.setColor(m_edgeColor);
+ paint.setStyle(SkPaint::kStroke_Style);
+ m_canvas->drawPath(path, paint);
+}
+
+void WebTestThemeControlWin::roundRect(SkColor color)
+{
+ SkRect rect;
+ SkScalar radius = SkIntToScalar(5);
+ SkPaint paint;
+
+ rect.set(m_irect);
+ paint.setColor(color);
+ paint.setStyle(SkPaint::kFill_Style);
+ m_canvas->drawRoundRect(rect, radius, radius, paint);
+
+ paint.setColor(m_edgeColor);
+ paint.setStyle(SkPaint::kStroke_Style);
+ m_canvas->drawRoundRect(rect, radius, radius, paint);
+}
+
+void WebTestThemeControlWin::oval(SkColor color)
+{
+ SkRect rect;
+ SkPaint paint;
+
+ rect.set(m_irect);
+ paint.setColor(color);
+ paint.setStyle(SkPaint::kFill_Style);
+ m_canvas->drawOval(rect, paint);
+
+ paint.setColor(m_edgeColor);
+ paint.setStyle(SkPaint::kStroke_Style);
+ m_canvas->drawOval(rect, paint);
+}
+
+void WebTestThemeControlWin::circle(SkScalar radius, SkColor color)
+{
+ SkScalar cy = SkIntToScalar(m_top + m_height / 2);
+ SkScalar cx = SkIntToScalar(m_left + m_width / 2);
+ SkPaint paint;
+
+ paint.setColor(color);
+ paint.setStyle(SkPaint::kFill_Style);
+ m_canvas->drawCircle(cx, cy, radius, paint);
+
+ paint.setColor(m_edgeColor);
+ paint.setStyle(SkPaint::kStroke_Style);
+ m_canvas->drawCircle(cx, cy, radius, paint);
+}
+
+void WebTestThemeControlWin::nestedBoxes(int indentLeft, int indentTop, int indentRight, int indentBottom, SkColor outerColor, SkColor innerColor)
+{
+ SkIRect lirect;
+ box(m_irect, outerColor);
+ lirect.set(m_irect.fLeft + indentLeft, m_irect.fTop + indentTop, m_irect.fRight - indentRight, m_irect.fBottom - indentBottom);
+ box(lirect, innerColor);
+}
+
+void WebTestThemeControlWin::markState()
+{
+ // The horizontal lines in a read only control are spaced by this amount.
+ const int readOnlyLineOffset = 5;
+
+ // The length of a triangle side for the corner marks.
+ const int triangleSize = 5;
+
+ switch (m_state) {
+ case UnknownState:
+ case DisabledState:
+ case NormalState:
+ case IndeterminateState:
+ // Don't visually mark these states (color is enough).
+ break;
+ case ReadOnlyState:
+ // Drawing lines across the control.
+ for (int i = m_top + readOnlyLineOffset; i < m_bottom; i += readOnlyLineOffset)
+ line(m_left + 1, i, m_right - 1, i, readOnlyColor);
+ break;
+
+ case HotState:
+ // Draw a triangle in the upper left corner of the control.
+ triangle(m_left, m_top, m_left + triangleSize, m_top, m_left, m_top + triangleSize, m_edgeColor);
+ break;
+
+ case HoverState:
+ // Draw a triangle in the upper right corner of the control.
+ triangle(m_right, m_top, m_right, m_top + triangleSize, m_right - triangleSize, m_top, m_edgeColor);
+ break;
+
+ case FocusedState:
+ // Draw a triangle in the bottom right corner of the control.
+ triangle(m_right, m_bottom, m_right - triangleSize, m_bottom, m_right, m_bottom - triangleSize, m_edgeColor);
+ break;
+
+ case PressedState:
+ // Draw a triangle in the bottom left corner of the control.
+ triangle(m_left, m_bottom, m_left, m_bottom - triangleSize, m_left + triangleSize, m_bottom, m_edgeColor);
+ break;
+
+ default:
+ BLINK_ASSERT_NOT_REACHED();
+ break;
+ }
+}
+
+void WebTestThemeControlWin::draw()
+{
+ int halfWidth = m_width / 2;
+ int halfHeight = m_height / 2;
+ int quarterWidth = m_width / 4;
+ int quarterHeight = m_height / 4;
+
+ // Indent amounts for the check in a checkbox or radio button.
+ const int checkIndent = 3;
+
+ // Indent amounts for short and long sides of the scrollbar notches.
+ const int notchLongOffset = 1;
+ const int notchShortOffset = 4;
+ const int noOffset = 0;
+
+ // Indent amounts for the short and long sides of a scroll thumb box.
+ const int thumbLongIndent = 0;
+ const int thumbShortIndent = 2;
+
+ // Indents for the crosshatch on a scroll grip.
+ const int gripLongIndent = 3;
+ const int gripShortIndent = 5;
+
+ // Indents for the the slider track.
+ const int sliderIndent = 2;
+
+ switch (m_type) {
+ case UnknownType:
+ BLINK_ASSERT_NOT_REACHED();
+ break;
+
+ case TextFieldType:
+ // We render this by hand outside of this function.
+ BLINK_ASSERT_NOT_REACHED();
+ break;
+
+ case PushButtonType:
+ // push buttons render as a rounded rectangle
+ roundRect(m_bgColor);
+ break;
+
+ case UncheckedBoxType:
+ // Unchecked boxes are simply plain boxes.
+ box(m_irect, m_bgColor);
+ break;
+
+ case CheckedBoxType:
+ nestedBoxes(checkIndent, checkIndent, checkIndent, checkIndent, m_bgColor, m_fgColor);
+ break;
+
+ case IndeterminateCheckboxType:
+ // Indeterminate checkbox is a box containing '-'.
+ nestedBoxes(checkIndent, halfHeight, checkIndent, halfHeight, m_bgColor, m_fgColor);
+ break;
+
+ case UncheckedRadioType:
+ circle(SkIntToScalar(halfHeight), m_bgColor);
+ break;
+
+ case CheckedRadioType:
+ circle(SkIntToScalar(halfHeight), m_bgColor);
+ circle(SkIntToScalar(halfHeight - checkIndent), m_fgColor);
+ break;
+
+ case HorizontalScrollTrackBackType: {
+ // Draw a box with a notch at the left.
+ int longOffset = halfHeight - notchLongOffset;
+ int shortOffset = m_width - notchShortOffset;
+ nestedBoxes(noOffset, longOffset, shortOffset, longOffset, m_bgColor, m_edgeColor);
+ break;
+ }
+
+ case HorizontalScrollTrackForwardType: {
+ // Draw a box with a notch at the right.
+ int longOffset = halfHeight - notchLongOffset;
+ int shortOffset = m_width - notchShortOffset;
+ nestedBoxes(shortOffset, longOffset, noOffset, longOffset, m_bgColor, m_fgColor);
+ break;
+ }
+
+ case VerticalScrollTrackBackType: {
+ // Draw a box with a notch at the top.
+ int longOffset = halfWidth - notchLongOffset;
+ int shortOffset = m_height - notchShortOffset;
+ nestedBoxes(longOffset, noOffset, longOffset, shortOffset, m_bgColor, m_fgColor);
+ break;
+ }
+
+ case VerticalScrollTrackForwardType: {
+ // Draw a box with a notch at the bottom.
+ int longOffset = halfWidth - notchLongOffset;
+ int shortOffset = m_height - notchShortOffset;
+ nestedBoxes(longOffset, shortOffset, longOffset, noOffset, m_bgColor, m_fgColor);
+ break;
+ }
+
+ case HorizontalScrollThumbType:
+ // Draw a narrower box on top of the outside box.
+ nestedBoxes(thumbLongIndent, thumbShortIndent, thumbLongIndent, thumbShortIndent, m_bgColor, m_bgColor);
+ break;
+
+ case VerticalScrollThumbType:
+ // Draw a shorter box on top of the outside box.
+ nestedBoxes(thumbShortIndent, thumbLongIndent, thumbShortIndent, thumbLongIndent, m_bgColor, m_bgColor);
+ break;
+
+ case HorizontalSliderThumbType:
+ case VerticalSliderThumbType:
+ // Slider thumbs are ovals.
+ oval(m_bgColor);
+ break;
+
+ case HorizontalScrollGripType: {
+ // Draw a horizontal crosshatch for the grip.
+ int longOffset = halfWidth - gripLongIndent;
+ line(m_left + gripLongIndent, m_top + halfHeight, m_right - gripLongIndent, m_top + halfHeight, m_fgColor);
+ line(m_left + longOffset, m_top + gripShortIndent, m_left + longOffset, m_bottom - gripShortIndent, m_fgColor);
+ line(m_right - longOffset, m_top + gripShortIndent, m_right - longOffset, m_bottom - gripShortIndent, m_fgColor);
+ break;
+ }
+
+ case VerticalScrollGripType: {
+ // Draw a vertical crosshatch for the grip.
+ int longOffset = halfHeight - gripLongIndent;
+ line(m_left + halfWidth, m_top + gripLongIndent, m_left + halfWidth, m_bottom - gripLongIndent, m_fgColor);
+ line(m_left + gripShortIndent, m_top + longOffset, m_right - gripShortIndent, m_top + longOffset, m_fgColor);
+ line(m_left + gripShortIndent, m_bottom - longOffset, m_right - gripShortIndent, m_bottom - longOffset, m_fgColor);
+ break;
+ }
+
+ case LeftArrowType:
+ // Draw a left arrow inside a box.
+ box(m_irect, m_bgColor);
+ triangle(m_right - quarterWidth, m_top + quarterHeight, m_right - quarterWidth, m_bottom - quarterHeight, m_left + quarterWidth, m_top + halfHeight, m_fgColor);
+ break;
+
+ case RightArrowType:
+ // Draw a left arrow inside a box.
+ box(m_irect, m_bgColor);
+ triangle(m_left + quarterWidth, m_top + quarterHeight, m_right - quarterWidth, m_top + halfHeight, m_left + quarterWidth, m_bottom - quarterHeight, m_fgColor);
+ break;
+
+ case UpArrowType:
+ // Draw an up arrow inside a box.
+ box(m_irect, m_bgColor);
+ triangle(m_left + quarterWidth, m_bottom - quarterHeight, m_left + halfWidth, m_top + quarterHeight, m_right - quarterWidth, m_bottom - quarterHeight, m_fgColor);
+ break;
+
+ case DownArrowType:
+ // Draw a down arrow inside a box.
+ box(m_irect, m_bgColor);
+ triangle(m_left + quarterWidth, m_top + quarterHeight, m_right - quarterWidth, m_top + quarterHeight, m_left + halfWidth, m_bottom - quarterHeight, m_fgColor);
+ break;
+
+ case HorizontalSliderTrackType: {
+ // Draw a narrow rect for the track plus box hatches on the ends.
+ SkIRect lirect;
+ lirect = m_irect;
+ lirect.inset(noOffset, halfHeight - sliderIndent);
+ box(lirect, m_bgColor);
+ line(m_left, m_top, m_left, m_bottom, m_edgeColor);
+ line(m_right, m_top, m_right, m_bottom, m_edgeColor);
+ break;
+ }
+
+ case VerticalSliderTrackType: {
+ // Draw a narrow rect for the track plus box hatches on the ends.
+ SkIRect lirect;
+ lirect = m_irect;
+ lirect.inset(halfWidth - sliderIndent, noOffset);
+ box(lirect, m_bgColor);
+ line(m_left, m_top, m_right, m_top, m_edgeColor);
+ line(m_left, m_bottom, m_right, m_bottom, m_edgeColor);
+ break;
+ }
+
+ case DropDownButtonType:
+ // Draw a box with a big down arrow on top.
+ box(m_irect, m_bgColor);
+ triangle(m_left + quarterWidth, m_top, m_right - quarterWidth, m_top, m_left + halfWidth, m_bottom, m_fgColor);
+ break;
+
+ default:
+ BLINK_ASSERT_NOT_REACHED();
+ break;
+ }
+
+ markState();
+}
+
+// Because rendering a text field is dependent on input
+// parameters the other controls don't have, we render it directly
+// rather than trying to overcomplicate draw() further.
+void WebTestThemeControlWin::drawTextField(bool drawEdges, bool fillContentArea, SkColor color)
+{
+ SkPaint paint;
+
+ if (fillContentArea) {
+ paint.setColor(color);
+ paint.setStyle(SkPaint::kFill_Style);
+ m_canvas->drawIRect(m_irect, paint);
+ }
+ if (drawEdges) {
+ paint.setColor(m_edgeColor);
+ paint.setStyle(SkPaint::kStroke_Style);
+ m_canvas->drawIRect(m_irect, paint);
+ }
+
+ markState();
+}
+
+void WebTestThemeControlWin::drawProgressBar(const SkIRect& fillRect)
+{
+ SkPaint paint;
+
+ paint.setColor(m_bgColor);
+ paint.setStyle(SkPaint::kFill_Style);
+ m_canvas->drawIRect(m_irect, paint);
+
+ // Emulate clipping
+ SkIRect tofill;
+ tofill.intersect(m_irect, fillRect);
+ paint.setColor(m_fgColor);
+ paint.setStyle(SkPaint::kFill_Style);
+ m_canvas->drawIRect(tofill, paint);
+
+ markState();
+}
+
+}
diff --git a/content/shell/renderer/test_runner/WebTestThemeControlWin.h b/content/shell/renderer/test_runner/WebTestThemeControlWin.h
new file mode 100644
index 0000000..66b5ae8
--- /dev/null
+++ b/content/shell/renderer/test_runner/WebTestThemeControlWin.h
@@ -0,0 +1,175 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// WebTestThemeControlWin implements the generic rendering of controls
+// needed by WebThemeEngineDRTWin. See the comments in that class
+// header file for why this class is needed and used.
+//
+// This class implements a generic set of widgets using Skia. The widgets
+// are optimized for testability, not a pleasing appearance.
+//
+
+#ifndef WebTestThemeControlWin_h
+#define WebTestThemeControlWin_h
+
+#include "third_party/WebKit/public/platform/WebNonCopyable.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "third_party/skia/include/core/SkRect.h"
+
+// Skia forward declarations
+class SkCanvas;
+
+namespace WebTestRunner {
+
+class WebTestThemeControlWin : public blink::WebNonCopyable {
+public:
+ // This list of states mostly mirrors the list in WebCore/platform/ThemeTypes.h
+ // but is maintained separately since that isn't public and also to minimize
+ // dependencies.
+ // Note that the WebKit ThemeTypes seem to imply that a control can be
+ // in multiple states simultaneously but WebThemeEngine only allows for
+ // a single state at a time.
+ //
+ // Some definitions for the various states:
+ // Disabled - indicates that a control can't be modified or selected
+ // (corresponds to HTML 'disabled' attribute)
+ // ReadOnly - indicates that a control can't be modified but can be
+ // selected
+ // Normal - the normal state of control on the page when it isn't
+ // focused or otherwise active
+ // Hot - when the mouse is hovering over a part of the control,
+ // all the other parts are considered "hot"
+ // Hover - when the mouse is directly over a control (the CSS
+ // :hover pseudo-class)
+ // Focused - when the control has the keyboard focus
+ // Pressed - when the control is being triggered (by a mousedown or
+ // a key event).
+ // Indeterminate - when set to indeterminate (only for progress bar)
+ enum State {
+ UnknownState = 0,
+ DisabledState,
+ ReadOnlyState,
+ NormalState,
+ HotState,
+ HoverState,
+ FocusedState,
+ PressedState,
+ IndeterminateState
+ };
+
+ // This list of types mostly mirrors the list in
+ // WebCore/platform/ThemeTypes.h but is maintained
+ // separately since that isn't public and also to minimize dependencies.
+ //
+ // Note that what the user might think of as a single control can be
+ // made up of multiple parts. For example, a single scroll bar contains
+ // six clickable parts - two arrows, the "thumb" indicating the current
+ // position on the bar, the other two parts of the bar (before and after
+ // the thumb) and the "gripper" on the thumb itself.
+ //
+ enum Type {
+ UnknownType = 0,
+ TextFieldType,
+ PushButtonType,
+ UncheckedBoxType,
+ CheckedBoxType,
+ IndeterminateCheckboxType,
+ UncheckedRadioType,
+ CheckedRadioType,
+ HorizontalScrollTrackBackType,
+ HorizontalScrollTrackForwardType,
+ HorizontalScrollThumbType,
+ HorizontalScrollGripType,
+ VerticalScrollTrackBackType,
+ VerticalScrollTrackForwardType,
+ VerticalScrollThumbType,
+ VerticalScrollGripType,
+ LeftArrowType,
+ RightArrowType,
+ UpArrowType,
+ DownArrowType,
+ HorizontalSliderTrackType,
+ HorizontalSliderThumbType,
+ VerticalSliderTrackType,
+ VerticalSliderThumbType,
+ DropDownButtonType,
+ ProgressBarType
+ };
+
+ // Constructs a control of the given size, type and state to draw
+ // on to the given canvas.
+ WebTestThemeControlWin(SkCanvas*, const SkIRect&, Type, State);
+ ~WebTestThemeControlWin();
+
+ // Draws the control.
+ void draw();
+
+ // Use this for TextField controls instead, because the logic
+ // for drawing them is dependent on what WebKit tells us to do.
+ // If drawEdges is true, draw an edge around the control. If
+ // fillContentArea is true, fill the content area with the given color.
+ void drawTextField(bool drawEdges, bool fillContentArea, SkColor);
+
+ // Use this for drawing ProgressBar controls instead, since we
+ // need to know the rect to fill inside the bar.
+ void drawProgressBar(const SkIRect& fillRect);
+
+private:
+ // Draws a box of size specified by irect, filled with the given color.
+ // The box will have a border drawn in the default edge color.
+ void box(const SkIRect& irect, SkColor);
+
+
+ // Draws a triangle of size specified by the three pairs of coordinates,
+ // filled with the given color. The box will have an edge drawn in the
+ // default edge color.
+ void triangle(int x0, int y0, int x1, int y1, int x2, int y2, SkColor);
+
+ // Draws a rectangle the size of the control with rounded corners, filled
+ // with the specified color (and with a border in the default edge color).
+ void roundRect(SkColor);
+
+ // Draws an oval the size of the control, filled with the specified color
+ // and with a border in the default edge color.
+ void oval(SkColor);
+
+ // Draws a circle centered in the control with the specified radius,
+ // filled with the specified color, and with a border draw in the
+ // default edge color.
+ void circle(SkScalar radius, SkColor);
+
+ // Draws a box the size of the control, filled with the outerColor and
+ // with a border in the default edge color, and then draws another box
+ // indented on all four sides by the specified amounts, filled with the
+ // inner color and with a border in the default edge color.
+ void nestedBoxes(int indentLeft, int indentTop, int indentRight, int indentBottom, SkColor outerColor, SkColor innerColor);
+
+ // Draws a line between the two points in the given color.
+ void line(int x0, int y0, int x1, int y1, SkColor);
+
+ // Draws a distinctive mark on the control for each state, so that the
+ // state of the control can be determined without needing to know which
+ // color is which.
+ void markState();
+
+ SkCanvas* m_canvas;
+ const SkIRect m_irect;
+ const Type m_type;
+ const State m_state;
+ const SkColor m_edgeColor;
+ const SkColor m_bgColor;
+ const SkColor m_fgColor;
+
+ // The following are convenience accessors for m_irect.
+ const int m_left;
+ const int m_right;
+ const int m_top;
+ const int m_bottom;
+ const int m_width;
+ const int m_height;
+};
+
+}
+
+#endif // WebTestThemeControlWin_h
diff --git a/content/shell/renderer/test_runner/WebTestThemeEngineMac.h b/content/shell/renderer/test_runner/WebTestThemeEngineMac.h
new file mode 100644
index 0000000..f51d128
--- /dev/null
+++ b/content/shell/renderer/test_runner/WebTestThemeEngineMac.h
@@ -0,0 +1,45 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This implements the WebThemeEngine API in such a way that we match the Mac
+// port rendering more than usual Chromium path, thus allowing us to share
+// more pixel baselines.
+
+#ifndef WebTestThemeEngineMac_h
+#define WebTestThemeEngineMac_h
+
+#include "third_party/WebKit/public/platform/WebNonCopyable.h"
+#include "third_party/WebKit/public/platform/mac/WebThemeEngine.h"
+
+namespace WebTestRunner {
+
+class WebTestThemeEngineMac : public blink::WebThemeEngine, public blink::WebNonCopyable {
+public:
+ virtual ~WebTestThemeEngineMac() { }
+
+ virtual void paintScrollbarThumb(
+ blink::WebCanvas*,
+ blink::WebThemeEngine::State,
+ blink::WebThemeEngine::Size,
+ const blink::WebRect&,
+ const blink::WebThemeEngine::ScrollbarInfo&);
+
+private:
+ virtual void paintHIThemeScrollbarThumb(
+ blink::WebCanvas*,
+ blink::WebThemeEngine::State,
+ blink::WebThemeEngine::Size,
+ const blink::WebRect&,
+ const blink::WebThemeEngine::ScrollbarInfo&);
+ virtual void paintNSScrollerScrollbarThumb(
+ blink::WebCanvas*,
+ blink::WebThemeEngine::State,
+ blink::WebThemeEngine::Size,
+ const blink::WebRect&,
+ const blink::WebThemeEngine::ScrollbarInfo&);
+};
+
+}
+
+#endif // WebTestThemeEngineMac_h
diff --git a/content/shell/renderer/test_runner/WebTestThemeEngineMac.mm b/content/shell/renderer/test_runner/WebTestThemeEngineMac.mm
new file mode 100644
index 0000000..8a26302
--- /dev/null
+++ b/content/shell/renderer/test_runner/WebTestThemeEngineMac.mm
@@ -0,0 +1,173 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/shell/renderer/test_runner/WebTestThemeEngineMac.h"
+
+#import <AppKit/NSAffineTransform.h>
+#import <AppKit/NSGraphicsContext.h>
+#import <AppKit/NSScroller.h>
+#import <AppKit/NSWindow.h>
+#include <Carbon/Carbon.h>
+#include "skia/ext/skia_utils_mac.h"
+#include "third_party/WebKit/public/platform/WebCanvas.h"
+#include "third_party/WebKit/public/platform/WebRect.h"
+
+using blink::WebCanvas;
+using blink::WebRect;
+using blink::WebThemeEngine;
+
+// We can't directly tell the NSScroller to draw itself as active or inactive,
+// instead we have to make it a child of an (in)active window. This class lets
+// us fake that parent window.
+@interface FakeActiveWindow : NSWindow {
+@private
+ BOOL hasActiveControls;
+}
++ (NSWindow*)alwaysActiveWindow;
++ (NSWindow*)alwaysInactiveWindow;
+- (id)initWithActiveControls:(BOOL)_hasActiveControls;
+- (BOOL)_hasActiveControls;
+@end
+
+@implementation FakeActiveWindow
+
+static NSWindow* alwaysActiveWindow = nil;
+static NSWindow* alwaysInactiveWindow = nil;
+
++ (NSWindow*)alwaysActiveWindow
+{
+ if (alwaysActiveWindow == nil)
+ alwaysActiveWindow = [[self alloc] initWithActiveControls:YES];
+ return alwaysActiveWindow;
+}
+
++ (NSWindow*)alwaysInactiveWindow
+{
+ if (alwaysInactiveWindow == nil)
+ alwaysInactiveWindow = [[self alloc] initWithActiveControls:NO];
+ return alwaysInactiveWindow;
+}
+
+- (id)initWithActiveControls:(BOOL)_hasActiveControls
+{
+ self = [super init];
+ hasActiveControls = _hasActiveControls;
+ return self;
+}
+
+- (BOOL)_hasActiveControls
+{
+ return hasActiveControls;
+}
+
+@end
+
+namespace WebTestRunner {
+
+namespace {
+
+ThemeTrackEnableState stateToHIEnableState(WebThemeEngine::State state)
+{
+ switch (state) {
+ case WebThemeEngine::StateDisabled:
+ return kThemeTrackDisabled;
+ case WebThemeEngine::StateInactive:
+ return kThemeTrackInactive;
+ default:
+ return kThemeTrackActive;
+ }
+}
+
+}
+
+void WebTestThemeEngineMac::paintScrollbarThumb(
+ WebCanvas* canvas,
+ WebThemeEngine::State state,
+ WebThemeEngine::Size size,
+ const WebRect& rect,
+ const WebThemeEngine::ScrollbarInfo& scrollbarInfo)
+{
+ // To match the Mac port, we still use HITheme for inner scrollbars.
+ if (scrollbarInfo.parent == WebThemeEngine::ScrollbarParentRenderLayer)
+ paintHIThemeScrollbarThumb(canvas, state, size, rect, scrollbarInfo);
+ else
+ paintNSScrollerScrollbarThumb(canvas, state, size, rect, scrollbarInfo);
+}
+
+// Duplicated from webkit/glue/webthemeengine_impl_mac.cc in the downstream
+// Chromium WebThemeEngine implementation.
+void WebTestThemeEngineMac::paintHIThemeScrollbarThumb(
+ WebCanvas* canvas,
+ WebThemeEngine::State state,
+ WebThemeEngine::Size size,
+ const WebRect& rect,
+ const WebThemeEngine::ScrollbarInfo& scrollbarInfo)
+{
+ HIThemeTrackDrawInfo trackInfo;
+ trackInfo.version = 0;
+ trackInfo.kind = size == WebThemeEngine::SizeRegular ? kThemeMediumScrollBar : kThemeSmallScrollBar;
+ trackInfo.bounds = CGRectMake(rect.x, rect.y, rect.width, rect.height);
+ trackInfo.min = 0;
+ trackInfo.max = scrollbarInfo.maxValue;
+ trackInfo.value = scrollbarInfo.currentValue;
+ trackInfo.trackInfo.scrollbar.viewsize = scrollbarInfo.visibleSize;
+ trackInfo.attributes = 0;
+ if (scrollbarInfo.orientation == WebThemeEngine::ScrollbarOrientationHorizontal)
+ trackInfo.attributes |= kThemeTrackHorizontal;
+
+ trackInfo.enableState = stateToHIEnableState(state);
+
+ trackInfo.trackInfo.scrollbar.pressState =
+ state == WebThemeEngine::StatePressed ? kThemeThumbPressed : 0;
+ trackInfo.attributes |= (kThemeTrackShowThumb | kThemeTrackHideTrack);
+ gfx::SkiaBitLocker bitLocker(canvas);
+ CGContextRef cgContext = bitLocker.cgContext();
+ HIThemeDrawTrack(&trackInfo, 0, cgContext, kHIThemeOrientationNormal);
+}
+
+void WebTestThemeEngineMac::paintNSScrollerScrollbarThumb(
+ WebCanvas* canvas,
+ WebThemeEngine::State state,
+ WebThemeEngine::Size size,
+ const WebRect& rect,
+ const WebThemeEngine::ScrollbarInfo& scrollbarInfo)
+{
+ [NSGraphicsContext saveGraphicsState];
+ NSScroller* scroller = [[NSScroller alloc] initWithFrame:NSMakeRect(rect.x, rect.y, rect.width, rect.height)];
+ [scroller setEnabled:state != WebThemeEngine::StateDisabled];
+ if (state == WebThemeEngine::StateInactive)
+ [[[FakeActiveWindow alwaysInactiveWindow] contentView] addSubview:scroller];
+ else
+ [[[FakeActiveWindow alwaysActiveWindow] contentView] addSubview:scroller];
+
+ [scroller setControlSize:size == WebThemeEngine::SizeRegular ? NSRegularControlSize : NSSmallControlSize];
+
+ double value = double(scrollbarInfo.currentValue) / double(scrollbarInfo.maxValue);
+ [scroller setDoubleValue: value];
+
+ float knobProportion = float(scrollbarInfo.visibleSize) / float(scrollbarInfo.totalSize);
+ [scroller setKnobProportion: knobProportion];
+
+ gfx::SkiaBitLocker bitLocker(canvas);
+ CGContextRef cgContext = bitLocker.cgContext();
+ NSGraphicsContext* nsGraphicsContext = [NSGraphicsContext graphicsContextWithGraphicsPort:cgContext flipped:YES];
+ [NSGraphicsContext setCurrentContext:nsGraphicsContext];
+
+ // Despite passing in frameRect() to the scroller, it always draws at (0, 0).
+ // Force it to draw in the right location by translating the whole graphics
+ // context.
+ CGContextSaveGState(cgContext);
+ NSAffineTransform *transform = [NSAffineTransform transform];
+ [transform translateXBy:rect.x yBy:rect.y];
+ [transform concat];
+
+ [scroller drawKnob];
+ CGContextRestoreGState(cgContext);
+
+ [scroller release];
+
+ [NSGraphicsContext restoreGraphicsState];
+}
+
+}
diff --git a/content/shell/renderer/test_runner/WebTestThemeEngineMock.cpp b/content/shell/renderer/test_runner/WebTestThemeEngineMock.cpp
new file mode 100644
index 0000000..125f134
--- /dev/null
+++ b/content/shell/renderer/test_runner/WebTestThemeEngineMock.cpp
@@ -0,0 +1,601 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// FIXME: This code is largely cloned from WebTestThemeEngineWin.cpp
+// and WebTestThemeControlWin.cpp. We should delete that code once the
+// cutover to Aura is final.
+
+#include "content/shell/renderer/test_runner/WebTestThemeEngineMock.h"
+
+#include "skia/ext/platform_canvas.h"
+#include "third_party/WebKit/public/platform/WebRect.h"
+#include "third_party/WebKit/public/platform/WebSize.h"
+#include "third_party/skia/include/core/SkRect.h"
+
+using blink::WebCanvas;
+using blink::WebColor;
+using blink::WebRect;
+using blink::WebThemeEngine;
+
+namespace WebTestRunner {
+
+static const SkColor edgeColor = SK_ColorBLACK;
+static const SkColor readOnlyColor = SkColorSetRGB(0xe9, 0xc2, 0xa6);
+static const SkColor bgColors[] = {
+ SkColorSetRGB(0xc9, 0xc9, 0xc9), // Disabled
+ SkColorSetRGB(0x43, 0xf9, 0xff), // Hover (Win's "Hot")
+ SkColorSetRGB(0x89, 0xc4, 0xff), // Normal
+ SkColorSetRGB(0xa9, 0xff, 0x12), // Pressed
+ SkColorSetRGB(0x00, 0xf3, 0xac), // Focused
+ SkColorSetRGB(0xf3, 0xe0, 0xd0), // Readonly
+};
+
+
+blink::WebSize WebTestThemeEngineMock::getSize(WebThemeEngine::Part part)
+{
+ // FIXME: We use this constant to indicate we are being asked for the size of
+ // a part that we don't expect to be asked about. We return a garbage value
+ // rather than just asserting because this code doesn't have access to either
+ // WTF or base to raise an assertion or do any logging :(.
+ const blink::WebSize invalidPartSize = blink::WebSize(100, 100);
+
+ switch (part) {
+ case WebThemeEngine::PartScrollbarLeftArrow:
+ return blink::WebSize(17, 15);
+ case WebThemeEngine::PartScrollbarRightArrow:
+ return invalidPartSize;
+ case WebThemeEngine::PartScrollbarUpArrow:
+ return blink::WebSize(15, 17);
+ case WebThemeEngine::PartScrollbarDownArrow:
+ return invalidPartSize;
+ case WebThemeEngine::PartScrollbarHorizontalThumb:
+ return blink::WebSize(15, 15);
+ case WebThemeEngine::PartScrollbarVerticalThumb:
+ return blink::WebSize(15, 15);
+ case WebThemeEngine::PartScrollbarHorizontalTrack:
+ return blink::WebSize(0, 15);
+ case WebThemeEngine::PartScrollbarVerticalTrack:
+ return blink::WebSize(15, 0);
+ case WebThemeEngine::PartCheckbox:
+ case WebThemeEngine::PartRadio:
+ return blink::WebSize(13, 13);
+ case WebThemeEngine::PartSliderThumb:
+ return blink::WebSize(11, 21);
+ case WebThemeEngine::PartInnerSpinButton:
+ return blink::WebSize(15, 8);
+ default:
+ return invalidPartSize;
+ }
+}
+
+static SkIRect webRectToSkIRect(const WebRect& webRect)
+{
+ SkIRect irect;
+ irect.set(webRect.x, webRect.y,
+ webRect.x + webRect.width - 1, webRect.y + webRect.height - 1);
+ return irect;
+}
+
+static SkIRect validate(const SkIRect& rect, WebThemeEngine::Part part)
+{
+ switch (part) {
+ case WebThemeEngine::PartCheckbox:
+ case WebThemeEngine::PartRadio: {
+ SkIRect retval = rect;
+
+ // The maximum width and height is 13.
+ // Center the square in the passed rectangle.
+ const int maxControlSize = 13;
+ int controlSize = std::min(rect.width(), rect.height());
+ controlSize = std::min(controlSize, maxControlSize);
+
+ retval.fLeft = rect.fLeft + (rect.width() / 2) - (controlSize / 2);
+ retval.fRight = retval.fLeft + controlSize - 1;
+ retval.fTop = rect.fTop + (rect.height() / 2) - (controlSize / 2);
+ retval.fBottom = retval.fTop + controlSize - 1;
+
+ return retval;
+ }
+ default:
+ return rect;
+ }
+}
+
+
+void box(SkCanvas *canvas, const SkIRect& rect, SkColor fillColor)
+{
+ SkPaint paint;
+
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setColor(fillColor);
+ canvas->drawIRect(rect, paint);
+
+ paint.setColor(edgeColor);
+ paint.setStyle(SkPaint::kStroke_Style);
+ canvas->drawIRect(rect, paint);
+}
+
+void line(SkCanvas *canvas, int x0, int y0, int x1, int y1, SkColor color)
+{
+ SkPaint paint;
+ paint.setColor(color);
+ canvas->drawLine(SkIntToScalar(x0), SkIntToScalar(y0),
+ SkIntToScalar(x1), SkIntToScalar(y1), paint);
+}
+
+void triangle(SkCanvas *canvas,
+ int x0, int y0,
+ int x1, int y1,
+ int x2, int y2,
+ SkColor color)
+{
+ SkPath path;
+ SkPaint paint;
+
+ paint.setColor(color);
+ paint.setStyle(SkPaint::kFill_Style);
+ path.incReserve(4);
+ path.moveTo(SkIntToScalar(x0), SkIntToScalar(y0));
+ path.lineTo(SkIntToScalar(x1), SkIntToScalar(y1));
+ path.lineTo(SkIntToScalar(x2), SkIntToScalar(y2));
+ path.close();
+ canvas->drawPath(path, paint);
+
+ paint.setColor(edgeColor);
+ paint.setStyle(SkPaint::kStroke_Style);
+ canvas->drawPath(path, paint);
+}
+
+void roundRect(SkCanvas *canvas, SkIRect irect, SkColor color)
+{
+ SkRect rect;
+ SkScalar radius = SkIntToScalar(5);
+ SkPaint paint;
+
+ rect.set(irect);
+ paint.setColor(color);
+ paint.setStyle(SkPaint::kFill_Style);
+ canvas->drawRoundRect(rect, radius, radius, paint);
+
+ paint.setColor(edgeColor);
+ paint.setStyle(SkPaint::kStroke_Style);
+ canvas->drawRoundRect(rect, radius, radius, paint);
+}
+
+void oval(SkCanvas* canvas, SkIRect irect, SkColor color)
+{
+ SkRect rect;
+ SkPaint paint;
+
+ rect.set(irect);
+ paint.setColor(color);
+ paint.setStyle(SkPaint::kFill_Style);
+ canvas->drawOval(rect, paint);
+
+ paint.setColor(edgeColor);
+ paint.setStyle(SkPaint::kStroke_Style);
+ canvas->drawOval(rect, paint);
+}
+
+void circle(SkCanvas *canvas, SkIRect irect, SkScalar radius, SkColor color)
+{
+ int left = irect.fLeft;
+ int width = irect.width();
+ int height = irect.height();
+ int top = irect.fTop;
+
+ SkScalar cy = SkIntToScalar(top + height / 2);
+ SkScalar cx = SkIntToScalar(left + width / 2);
+ SkPaint paint;
+
+ paint.setColor(color);
+ paint.setStyle(SkPaint::kFill_Style);
+ canvas->drawCircle(cx, cy, radius, paint);
+
+ paint.setColor(edgeColor);
+ paint.setStyle(SkPaint::kStroke_Style);
+ canvas->drawCircle(cx, cy, radius, paint);
+}
+
+void nestedBoxes(SkCanvas *canvas,
+ SkIRect irect,
+ int indentLeft,
+ int indentTop,
+ int indentRight,
+ int indentBottom,
+ SkColor outerColor,
+ SkColor innerColor)
+{
+ SkIRect lirect;
+ box(canvas, irect, outerColor);
+ lirect.set(irect.fLeft + indentLeft,
+ irect.fTop + indentTop,
+ irect.fRight - indentRight,
+ irect.fBottom - indentBottom);
+ box(canvas, lirect, innerColor);
+}
+
+void markState(SkCanvas *canvas, SkIRect irect, WebThemeEngine::State state)
+{
+ int left = irect.fLeft;
+ int right = irect.fRight;
+ int top = irect.fTop;
+ int bottom = irect.fBottom;
+
+ // The length of a triangle side for the corner marks.
+ const int triangleSize = 5;
+
+ switch (state) {
+ case WebThemeEngine::StateDisabled:
+ case WebThemeEngine::StateNormal:
+ // Don't visually mark these states (color is enough).
+ break;
+
+ case WebThemeEngine::StateReadonly: {
+ // The horizontal lines in a read only control are spaced by this amount.
+ const int readOnlyLineOffset = 5;
+
+ // Drawing lines across the control.
+ for (int i = top + readOnlyLineOffset; i < bottom; i += readOnlyLineOffset)
+ line(canvas, left + 1, i, right - 1, i, readOnlyColor);
+ break;
+ }
+ case WebThemeEngine::StateHover:
+ // Draw a triangle in the upper left corner of the control. (Win's "hot")
+ triangle(canvas,
+ left, top,
+ left + triangleSize, top,
+ left, top + triangleSize,
+ edgeColor);
+ break;
+
+ case WebThemeEngine::StateFocused:
+ // Draw a triangle in the bottom right corner of the control.
+ triangle(canvas,
+ right, bottom,
+ right - triangleSize, bottom,
+ right, bottom - triangleSize,
+ edgeColor);
+ break;
+
+ case WebThemeEngine::StatePressed:
+ // Draw a triangle in the bottom left corner of the control.
+ triangle(canvas,
+ left, bottom,
+ left, bottom - triangleSize,
+ left + triangleSize, bottom,
+ edgeColor);
+ break;
+
+ default:
+ // FIXME: Should we do something here to indicate that we got an invalid state?
+ // Unfortunately, we can't assert because we don't have access to WTF or base.
+ break;
+ }
+}
+
+void WebTestThemeEngineMock::paint(
+ blink::WebCanvas* canvas,
+ WebThemeEngine::Part part,
+ WebThemeEngine::State state,
+ const blink::WebRect& rect,
+ const WebThemeEngine::ExtraParams* extraParams)
+{
+ SkIRect irect = webRectToSkIRect(rect);
+ SkPaint paint;
+
+ // Indent amounts for the check in a checkbox or radio button.
+ const int checkIndent = 3;
+
+ // Indent amounts for short and long sides of the scrollbar notches.
+ const int notchLongOffset = 1;
+ const int notchShortOffset = 4;
+ const int noOffset = 0;
+
+ // Indent amounts for the short and long sides of a scroll thumb box.
+ const int thumbLongIndent = 0;
+ const int thumbShortIndent = 2;
+
+ // Indents for the crosshatch on a scroll grip.
+ const int gripLongIndent = 3;
+ const int gripShortIndent = 5;
+
+ // Indents for the the slider track.
+ const int sliderIndent = 2;
+
+ int halfHeight = irect.height() / 2;
+ int halfWidth = irect.width() / 2;
+ int quarterHeight = irect.height() / 4;
+ int quarterWidth = irect.width() / 4;
+ int left = irect.fLeft;
+ int right = irect.fRight;
+ int top = irect.fTop;
+ int bottom = irect.fBottom;
+
+ switch (part) {
+ case WebThemeEngine::PartScrollbarDownArrow:
+ box(canvas, irect, bgColors[state]);
+ triangle(canvas,
+ left + quarterWidth, top + quarterHeight,
+ right - quarterWidth, top + quarterHeight,
+ left + halfWidth, bottom - quarterHeight,
+ edgeColor);
+ markState(canvas, irect, state);
+ break;
+
+ case WebThemeEngine::PartScrollbarLeftArrow:
+ box(canvas, irect, bgColors[state]);
+ triangle(canvas,
+ right - quarterWidth, top + quarterHeight,
+ right - quarterWidth, bottom - quarterHeight,
+ left + quarterWidth, top + halfHeight,
+ edgeColor);
+ break;
+
+ case WebThemeEngine::PartScrollbarRightArrow:
+ box(canvas, irect, bgColors[state]);
+ triangle(canvas,
+ left + quarterWidth, top + quarterHeight,
+ right - quarterWidth, top + halfHeight,
+ left + quarterWidth, bottom - quarterHeight,
+ edgeColor);
+ break;
+
+ case WebThemeEngine::PartScrollbarUpArrow:
+ box(canvas, irect, bgColors[state]);
+ triangle(canvas,
+ left + quarterWidth, bottom - quarterHeight,
+ left + halfWidth, top + quarterHeight,
+ right - quarterWidth, bottom - quarterHeight,
+ edgeColor);
+ markState(canvas, irect, state);
+ break;
+
+ case WebThemeEngine::PartScrollbarHorizontalThumb: {
+ // Draw a narrower box on top of the outside box.
+ nestedBoxes(canvas, irect, thumbLongIndent, thumbShortIndent,
+ thumbLongIndent, thumbShortIndent,
+ bgColors[state], bgColors[state]);
+ // Draw a horizontal crosshatch for the grip.
+ int longOffset = halfWidth - gripLongIndent;
+ line(canvas,
+ left + gripLongIndent, top + halfHeight,
+ right - gripLongIndent, top + halfHeight,
+ edgeColor);
+ line(canvas,
+ left + longOffset, top + gripShortIndent,
+ left + longOffset, bottom - gripShortIndent,
+ edgeColor);
+ line(canvas,
+ right - longOffset, top + gripShortIndent,
+ right - longOffset, bottom - gripShortIndent,
+ edgeColor);
+ markState(canvas, irect, state);
+ break;
+ }
+
+ case WebThemeEngine::PartScrollbarVerticalThumb: {
+ // Draw a shorter box on top of the outside box.
+ nestedBoxes(canvas, irect, thumbShortIndent, thumbLongIndent,
+ thumbShortIndent, thumbLongIndent,
+ bgColors[state], bgColors[state]);
+ // Draw a vertical crosshatch for the grip.
+ int longOffset = halfHeight - gripLongIndent;
+ line(canvas,
+ left + halfWidth, top + gripLongIndent,
+ left + halfWidth, bottom - gripLongIndent,
+ edgeColor);
+ line(canvas,
+ left + gripShortIndent, top + longOffset,
+ right - gripShortIndent, top + longOffset,
+ edgeColor);
+ line(canvas,
+ left + gripShortIndent, bottom - longOffset,
+ right - gripShortIndent, bottom - longOffset,
+ edgeColor);
+ markState(canvas, irect, state);
+ break;
+ }
+
+ case WebThemeEngine::PartScrollbarHorizontalTrack: {
+ int longOffset = halfHeight - notchLongOffset;
+ int shortOffset = irect.width() - notchShortOffset;
+ if (extraParams->scrollbarTrack.isBack) {
+ // back, notch on left
+ nestedBoxes(canvas, irect, noOffset, longOffset, shortOffset,
+ longOffset, bgColors[state], edgeColor);
+ } else {
+ // forward, notch on right
+ nestedBoxes(canvas, irect, shortOffset, longOffset, noOffset,
+ longOffset, bgColors[state], edgeColor);
+ }
+
+ markState(canvas, irect, state);
+ break;
+ }
+
+ case WebThemeEngine::PartScrollbarVerticalTrack: {
+ int longOffset = halfWidth - notchLongOffset;
+ int shortOffset = irect.height() - notchShortOffset;
+ if (extraParams->scrollbarTrack.isBack) {
+ // back, notch at top
+ nestedBoxes(canvas, irect, longOffset, noOffset, longOffset,
+ shortOffset, bgColors[state], edgeColor);
+ } else {
+ // forward, notch at bottom
+ nestedBoxes(canvas, irect, longOffset, shortOffset, longOffset,
+ noOffset, bgColors[state], edgeColor);
+ }
+
+ markState(canvas, irect, state);
+ break;
+ }
+
+ case WebThemeEngine::PartCheckbox:
+ if (extraParams->button.indeterminate) {
+ nestedBoxes(canvas, irect,
+ checkIndent, halfHeight,
+ checkIndent, halfHeight,
+ bgColors[state], edgeColor);
+ } else if (extraParams->button.checked) {
+ irect = validate(irect, part);
+ nestedBoxes(canvas, irect,
+ checkIndent, checkIndent,
+ checkIndent, checkIndent,
+ bgColors[state], edgeColor);
+ } else {
+ irect = validate(irect, part);
+ box(canvas, irect, bgColors[state]);
+ }
+ break;
+
+ case WebThemeEngine::PartRadio:
+ irect = validate(irect, part);
+ halfHeight = irect.height() / 2;
+ if (extraParams->button.checked) {
+ circle(canvas, irect, SkIntToScalar(halfHeight), bgColors[state]);
+ circle(canvas, irect, SkIntToScalar(halfHeight - checkIndent), edgeColor);
+ } else {
+ circle(canvas, irect, SkIntToScalar(halfHeight), bgColors[state]);
+ }
+ break;
+
+ case WebThemeEngine::PartButton:
+ roundRect(canvas, irect, bgColors[state]);
+ markState(canvas, irect, state);
+ break;
+
+ case WebThemeEngine::PartTextField:
+ paint.setColor(extraParams->textField.backgroundColor);
+ paint.setStyle(SkPaint::kFill_Style);
+ canvas->drawIRect(irect, paint);
+
+ paint.setColor(edgeColor);
+ paint.setStyle(SkPaint::kStroke_Style);
+ canvas->drawIRect(irect, paint);
+
+ markState(canvas, irect, state);
+ break;
+
+ case WebThemeEngine::PartMenuList:
+ if (extraParams->menuList.fillContentArea) {
+ box(canvas, irect, extraParams->menuList.backgroundColor);
+ } else {
+ SkPaint paint;
+ paint.setColor(edgeColor);
+ paint.setStyle(SkPaint::kStroke_Style);
+ canvas->drawIRect(irect, paint);
+ }
+
+ // clip the drop-down arrow to be inside the select box
+ if (extraParams->menuList.arrowX - 4 > irect.fLeft)
+ irect.fLeft = extraParams->menuList.arrowX - 4;
+ if (extraParams->menuList.arrowX + 12 < irect.fRight)
+ irect.fRight = extraParams->menuList.arrowX + 12;
+
+ irect.fTop = extraParams->menuList.arrowY - (extraParams->menuList.arrowHeight) / 2;
+ irect.fBottom = extraParams->menuList.arrowY + (extraParams->menuList.arrowHeight - 1) / 2;
+ halfWidth = irect.width() / 2;
+ quarterWidth = irect.width() / 4;
+
+ if (state == WebThemeEngine::StateFocused) // FIXME: draw differenty?
+ state = WebThemeEngine::StateNormal;
+ box(canvas, irect, bgColors[state]);
+ triangle(canvas,
+ irect.fLeft + quarterWidth, irect.fTop,
+ irect.fRight - quarterWidth, irect.fTop,
+ irect.fLeft + halfWidth, irect.fBottom,
+ edgeColor);
+
+ break;
+
+ case WebThemeEngine::PartSliderTrack: {
+ SkIRect lirect = irect;
+
+ // Draw a narrow rect for the track plus box hatches on the ends.
+ if (state == WebThemeEngine::StateFocused) // FIXME: draw differently?
+ state = WebThemeEngine::StateNormal;
+ if (extraParams->slider.vertical) {
+ lirect.inset(halfWidth - sliderIndent, noOffset);
+ box(canvas, lirect, bgColors[state]);
+ line(canvas, left, top, right, top, edgeColor);
+ line(canvas, left, bottom, right, bottom, edgeColor);
+ } else {
+ lirect.inset(noOffset, halfHeight - sliderIndent);
+ box(canvas, lirect, bgColors[state]);
+ line(canvas, left, top, left, bottom, edgeColor);
+ line(canvas, right, top, right, bottom, edgeColor);
+ }
+ break;
+ }
+
+ case WebThemeEngine::PartSliderThumb:
+ if (state == WebThemeEngine::StateFocused) // FIXME: draw differently?
+ state = WebThemeEngine::StateNormal;
+ oval(canvas, irect, bgColors[state]);
+ break;
+
+ case WebThemeEngine::PartInnerSpinButton: {
+ // stack half-height up and down arrows on top of each other
+ SkIRect lirect;
+ int halfHeight = rect.height / 2;
+ if (extraParams->innerSpin.readOnly)
+ state = blink::WebThemeEngine::StateDisabled;
+
+ lirect.set(rect.x, rect.y, rect.x + rect.width - 1, rect.y + halfHeight - 1);
+ box(canvas, lirect, bgColors[state]);
+ bottom = lirect.fBottom;
+ quarterHeight = lirect.height() / 4;
+ triangle(canvas,
+ left + quarterWidth, bottom - quarterHeight,
+ right - quarterWidth, bottom - quarterHeight,
+ left + halfWidth, top + quarterHeight,
+ edgeColor);
+
+ lirect.set(rect.x, rect.y + halfHeight, rect.x + rect.width - 1,
+ rect.y + 2 * halfHeight - 1);
+ top = lirect.fTop;
+ bottom = lirect.fBottom;
+ quarterHeight = lirect.height() / 4;
+ box(canvas, lirect, bgColors[state]);
+ triangle(canvas,
+ left + quarterWidth, top + quarterHeight,
+ right - quarterWidth, top + quarterHeight,
+ left + halfWidth, bottom - quarterHeight,
+ edgeColor);
+ markState(canvas, irect, state);
+ break;
+ }
+ case WebThemeEngine::PartProgressBar: {
+ paint.setColor(bgColors[state]);
+ paint.setStyle(SkPaint::kFill_Style);
+ canvas->drawIRect(irect, paint);
+
+ // Emulate clipping
+ SkIRect tofill = irect;
+ if (extraParams->progressBar.determinate) {
+ tofill.set(extraParams->progressBar.valueRectX,
+ extraParams->progressBar.valueRectY,
+ extraParams->progressBar.valueRectX +
+ extraParams->progressBar.valueRectWidth - 1,
+ extraParams->progressBar.valueRectY +
+ extraParams->progressBar.valueRectHeight);
+ }
+
+ tofill.intersect(irect, tofill);
+ paint.setColor(edgeColor);
+ paint.setStyle(SkPaint::kFill_Style);
+ canvas->drawIRect(tofill, paint);
+
+ markState(canvas, irect, state);
+ break;
+ }
+ default:
+ // FIXME: Should we do something here to indicate that we got an invalid part?
+ // Unfortunately, we can't assert because we don't have access to WTF or base.
+ break;
+ }
+}
+
+} // namespace WebTestRunner
diff --git a/content/shell/renderer/test_runner/WebTestThemeEngineMock.h b/content/shell/renderer/test_runner/WebTestThemeEngineMock.h
new file mode 100644
index 0000000..88ac8e1
--- /dev/null
+++ b/content/shell/renderer/test_runner/WebTestThemeEngineMock.h
@@ -0,0 +1,32 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WebTestThemeEngineMock_h
+#define WebTestThemeEngineMock_h
+
+#include "third_party/WebKit/public/platform/WebRect.h"
+#include "third_party/WebKit/public/platform/default/WebThemeEngine.h"
+
+using blink::WebRect;
+using blink::WebThemeEngine;
+
+namespace WebTestRunner {
+
+class WebTestThemeEngineMock : public blink::WebThemeEngine {
+public:
+ virtual ~WebTestThemeEngineMock() { }
+
+ // WebThemeEngine methods:
+ virtual blink::WebSize getSize(WebThemeEngine::Part);
+
+ virtual void paint(blink::WebCanvas*,
+ WebThemeEngine::Part,
+ WebThemeEngine::State,
+ const blink::WebRect&,
+ const WebThemeEngine::ExtraParams*);
+};
+
+} // namespace WebTestRunner
+
+#endif // WebTestThemeEngineMock_h
diff --git a/content/shell/renderer/test_runner/WebTestThemeEngineWin.cpp b/content/shell/renderer/test_runner/WebTestThemeEngineWin.cpp
new file mode 100644
index 0000000..9a191fd
--- /dev/null
+++ b/content/shell/renderer/test_runner/WebTestThemeEngineWin.cpp
@@ -0,0 +1,716 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/shell/renderer/test_runner/WebTestThemeEngineWin.h"
+
+#include "content/shell/renderer/test_runner/TestCommon.h"
+#include "content/shell/renderer/test_runner/WebTestThemeControlWin.h"
+#include "third_party/WebKit/public/platform/WebRect.h"
+#include "third_party/skia/include/core/SkRect.h"
+
+// Although all this code is generic, we include these headers
+// to pull in the Windows #defines for the parts and states of
+// the controls.
+#include <windows.h>
+#include <vsstyle.h>
+
+using namespace blink;
+
+namespace WebTestRunner {
+
+namespace {
+
+// We define this for clarity, although there really should be a DFCS_NORMAL in winuser.h.
+const int dfcsNormal = 0x0000;
+
+SkIRect webRectToSkIRect(const WebRect& webRect)
+{
+ SkIRect irect;
+ irect.set(webRect.x, webRect.y, webRect.x + webRect.width - 1, webRect.y + webRect.height - 1);
+ return irect;
+}
+
+void drawControl(WebCanvas* canvas, const WebRect& rect, WebTestThemeControlWin::Type ctype, WebTestThemeControlWin::State cstate)
+{
+ WebTestThemeControlWin control(canvas, webRectToSkIRect(rect), ctype, cstate);
+ control.draw();
+}
+
+void drawTextField(WebCanvas* canvas, const WebRect& rect, WebTestThemeControlWin::Type ctype, WebTestThemeControlWin::State cstate, bool drawEdges, bool fillContentArea, WebColor color)
+{
+ WebTestThemeControlWin control(canvas, webRectToSkIRect(rect), ctype, cstate);
+ control.drawTextField(drawEdges, fillContentArea, color);
+}
+
+void drawProgressBar(WebCanvas* canvas, WebTestThemeControlWin::Type ctype, WebTestThemeControlWin::State cstate, const WebRect& barRect, const WebRect& fillRect)
+{
+ WebTestThemeControlWin control(canvas, webRectToSkIRect(barRect), ctype, cstate);
+ control.drawProgressBar(webRectToSkIRect(fillRect));
+}
+
+}
+
+void WebTestThemeEngineWin::paintButton(WebCanvas* canvas, int part, int state, int classicState, const WebRect& rect)
+{
+ WebTestThemeControlWin::Type ctype = WebTestThemeControlWin::UnknownType;
+ WebTestThemeControlWin::State cstate = WebTestThemeControlWin::UnknownState;
+
+ if (part == BP_CHECKBOX) {
+ switch (state) {
+ case CBS_UNCHECKEDNORMAL:
+ BLINK_ASSERT(classicState == dfcsNormal);
+ ctype = WebTestThemeControlWin::UncheckedBoxType;
+ cstate = WebTestThemeControlWin::NormalState;
+ break;
+
+ case CBS_UNCHECKEDHOT:
+ BLINK_ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_HOT));
+ ctype = WebTestThemeControlWin::UncheckedBoxType;
+ cstate = WebTestThemeControlWin::HotState;
+ break;
+
+ case CBS_UNCHECKEDPRESSED:
+ BLINK_ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_PUSHED));
+ ctype = WebTestThemeControlWin::UncheckedBoxType;
+ cstate = WebTestThemeControlWin::PressedState;
+ break;
+
+ case CBS_UNCHECKEDDISABLED:
+ BLINK_ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_INACTIVE));
+ ctype = WebTestThemeControlWin::UncheckedBoxType;
+ cstate = WebTestThemeControlWin::DisabledState;
+ break;
+
+ case CBS_CHECKEDNORMAL:
+ BLINK_ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_CHECKED));
+ ctype = WebTestThemeControlWin::CheckedBoxType;
+ cstate = WebTestThemeControlWin::NormalState;
+ break;
+
+ case CBS_CHECKEDHOT:
+ BLINK_ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_CHECKED | DFCS_HOT));
+ ctype = WebTestThemeControlWin::CheckedBoxType;
+ cstate = WebTestThemeControlWin::HotState;
+ break;
+
+ case CBS_CHECKEDPRESSED:
+ BLINK_ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_CHECKED | DFCS_PUSHED));
+ ctype = WebTestThemeControlWin::CheckedBoxType;
+ cstate = WebTestThemeControlWin::PressedState;
+ break;
+
+ case CBS_CHECKEDDISABLED:
+ BLINK_ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_CHECKED | DFCS_INACTIVE));
+ ctype = WebTestThemeControlWin::CheckedBoxType;
+ cstate = WebTestThemeControlWin::DisabledState;
+ break;
+
+ case CBS_MIXEDNORMAL:
+ // Classic theme can't represent mixed state checkbox. We assume
+ // it's equivalent to unchecked.
+ BLINK_ASSERT(classicState == DFCS_BUTTONCHECK);
+ ctype = WebTestThemeControlWin::IndeterminateCheckboxType;
+ cstate = WebTestThemeControlWin::NormalState;
+ break;
+
+ case CBS_MIXEDHOT:
+ BLINK_ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_HOT));
+ ctype = WebTestThemeControlWin::IndeterminateCheckboxType;
+ cstate = WebTestThemeControlWin::HotState;
+ break;
+
+ case CBS_MIXEDPRESSED:
+ BLINK_ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_PUSHED));
+ ctype = WebTestThemeControlWin::IndeterminateCheckboxType;
+ cstate = WebTestThemeControlWin::PressedState;
+ break;
+
+ case CBS_MIXEDDISABLED:
+ BLINK_ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_INACTIVE));
+ ctype = WebTestThemeControlWin::IndeterminateCheckboxType;
+ cstate = WebTestThemeControlWin::DisabledState;
+ break;
+
+ default:
+ BLINK_ASSERT_NOT_REACHED();
+ break;
+ }
+ } else if (BP_RADIOBUTTON == part) {
+ switch (state) {
+ case RBS_UNCHECKEDNORMAL:
+ BLINK_ASSERT(classicState == DFCS_BUTTONRADIO);
+ ctype = WebTestThemeControlWin::UncheckedRadioType;
+ cstate = WebTestThemeControlWin::NormalState;
+ break;
+
+ case RBS_UNCHECKEDHOT:
+ BLINK_ASSERT(classicState == (DFCS_BUTTONRADIO | DFCS_HOT));
+ ctype = WebTestThemeControlWin::UncheckedRadioType;
+ cstate = WebTestThemeControlWin::HotState;
+ break;
+
+ case RBS_UNCHECKEDPRESSED:
+ BLINK_ASSERT(classicState == (DFCS_BUTTONRADIO | DFCS_PUSHED));
+ ctype = WebTestThemeControlWin::UncheckedRadioType;
+ cstate = WebTestThemeControlWin::PressedState;
+ break;
+
+ case RBS_UNCHECKEDDISABLED:
+ BLINK_ASSERT(classicState == (DFCS_BUTTONRADIO | DFCS_INACTIVE));
+ ctype = WebTestThemeControlWin::UncheckedRadioType;
+ cstate = WebTestThemeControlWin::DisabledState;
+ break;
+
+ case RBS_CHECKEDNORMAL:
+ BLINK_ASSERT(classicState == (DFCS_BUTTONRADIO | DFCS_CHECKED));
+ ctype = WebTestThemeControlWin::CheckedRadioType;
+ cstate = WebTestThemeControlWin::NormalState;
+ break;
+
+ case RBS_CHECKEDHOT:
+ BLINK_ASSERT(classicState == (DFCS_BUTTONRADIO | DFCS_CHECKED | DFCS_HOT));
+ ctype = WebTestThemeControlWin::CheckedRadioType;
+ cstate = WebTestThemeControlWin::HotState;
+ break;
+
+ case RBS_CHECKEDPRESSED:
+ BLINK_ASSERT(classicState == (DFCS_BUTTONRADIO | DFCS_CHECKED | DFCS_PUSHED));
+ ctype = WebTestThemeControlWin::CheckedRadioType;
+ cstate = WebTestThemeControlWin::PressedState;
+ break;
+
+ case RBS_CHECKEDDISABLED:
+ BLINK_ASSERT(classicState == (DFCS_BUTTONRADIO | DFCS_CHECKED | DFCS_INACTIVE));
+ ctype = WebTestThemeControlWin::CheckedRadioType;
+ cstate = WebTestThemeControlWin::DisabledState;
+ break;
+
+ default:
+ BLINK_ASSERT_NOT_REACHED();
+ break;
+ }
+ } else if (BP_PUSHBUTTON == part) {
+ switch (state) {
+ case PBS_NORMAL:
+ BLINK_ASSERT(classicState == DFCS_BUTTONPUSH);
+ ctype = WebTestThemeControlWin::PushButtonType;
+ cstate = WebTestThemeControlWin::NormalState;
+ break;
+
+ case PBS_HOT:
+ BLINK_ASSERT(classicState == (DFCS_BUTTONPUSH | DFCS_HOT));
+ ctype = WebTestThemeControlWin::PushButtonType;
+ cstate = WebTestThemeControlWin::HotState;
+ break;
+
+ case PBS_PRESSED:
+ BLINK_ASSERT(classicState == (DFCS_BUTTONPUSH | DFCS_PUSHED));
+ ctype = WebTestThemeControlWin::PushButtonType;
+ cstate = WebTestThemeControlWin::PressedState;
+ break;
+
+ case PBS_DISABLED:
+ BLINK_ASSERT(classicState == (DFCS_BUTTONPUSH | DFCS_INACTIVE));
+ ctype = WebTestThemeControlWin::PushButtonType;
+ cstate = WebTestThemeControlWin::DisabledState;
+ break;
+
+ case PBS_DEFAULTED:
+ BLINK_ASSERT(classicState == DFCS_BUTTONPUSH);
+ ctype = WebTestThemeControlWin::PushButtonType;
+ cstate = WebTestThemeControlWin::FocusedState;
+ break;
+
+ default:
+ BLINK_ASSERT_NOT_REACHED();
+ break;
+ }
+ } else
+ BLINK_ASSERT_NOT_REACHED();
+
+ drawControl(canvas, rect, ctype, cstate);
+}
+
+void WebTestThemeEngineWin::paintMenuList(WebCanvas* canvas, int part, int state, int classicState, const WebRect& rect)
+{
+ WebTestThemeControlWin::Type ctype = WebTestThemeControlWin::UnknownType;
+ WebTestThemeControlWin::State cstate = WebTestThemeControlWin::UnknownState;
+
+ if (CP_DROPDOWNBUTTON == part) {
+ ctype = WebTestThemeControlWin::DropDownButtonType;
+ switch (state) {
+ case CBXS_NORMAL:
+ BLINK_ASSERT(classicState == DFCS_MENUARROW);
+ cstate = WebTestThemeControlWin::NormalState;
+ break;
+
+ case CBXS_HOT:
+ BLINK_ASSERT(classicState == (DFCS_MENUARROW | DFCS_HOT));
+ cstate = WebTestThemeControlWin::HoverState;
+ break;
+
+ case CBXS_PRESSED:
+ BLINK_ASSERT(classicState == (DFCS_MENUARROW | DFCS_PUSHED));
+ cstate = WebTestThemeControlWin::PressedState;
+ break;
+
+ case CBXS_DISABLED:
+ BLINK_ASSERT(classicState == (DFCS_MENUARROW | DFCS_INACTIVE));
+ cstate = WebTestThemeControlWin::DisabledState;
+ break;
+
+ default:
+ BLINK_ASSERT_NOT_REACHED();
+ break;
+ }
+ } else
+ BLINK_ASSERT_NOT_REACHED();
+
+ drawControl(canvas, rect, ctype, cstate);
+}
+
+void WebTestThemeEngineWin::paintScrollbarArrow(WebCanvas* canvas, int state, int classicState, const WebRect& rect)
+{
+ WebTestThemeControlWin::Type ctype = WebTestThemeControlWin::UnknownType;
+ WebTestThemeControlWin::State cstate = WebTestThemeControlWin::UnknownState;
+
+ switch (state) {
+ case ABS_UPNORMAL:
+ BLINK_ASSERT(classicState == DFCS_SCROLLUP);
+ ctype = WebTestThemeControlWin::UpArrowType;
+ cstate = WebTestThemeControlWin::NormalState;
+ break;
+
+ case ABS_DOWNNORMAL:
+ BLINK_ASSERT(classicState == DFCS_SCROLLDOWN);
+ ctype = WebTestThemeControlWin::DownArrowType;
+ cstate = WebTestThemeControlWin::NormalState;
+ break;
+
+ case ABS_LEFTNORMAL:
+ BLINK_ASSERT(classicState == DFCS_SCROLLLEFT);
+ ctype = WebTestThemeControlWin::LeftArrowType;
+ cstate = WebTestThemeControlWin::NormalState;
+ break;
+
+ case ABS_RIGHTNORMAL:
+ BLINK_ASSERT(classicState == DFCS_SCROLLRIGHT);
+ ctype = WebTestThemeControlWin::RightArrowType;
+ cstate = WebTestThemeControlWin::NormalState;
+ break;
+
+ case ABS_UPHOT:
+ BLINK_ASSERT(classicState == (DFCS_SCROLLUP | DFCS_HOT));
+ ctype = WebTestThemeControlWin::UpArrowType;
+ cstate = WebTestThemeControlWin::HotState;
+ break;
+
+ case ABS_DOWNHOT:
+ BLINK_ASSERT(classicState == (DFCS_SCROLLDOWN | DFCS_HOT));
+ ctype = WebTestThemeControlWin::DownArrowType;
+ cstate = WebTestThemeControlWin::HotState;
+ break;
+
+ case ABS_LEFTHOT:
+ BLINK_ASSERT(classicState == (DFCS_SCROLLLEFT | DFCS_HOT));
+ ctype = WebTestThemeControlWin::LeftArrowType;
+ cstate = WebTestThemeControlWin::HotState;
+ break;
+
+ case ABS_RIGHTHOT:
+ BLINK_ASSERT(classicState == (DFCS_SCROLLRIGHT | DFCS_HOT));
+ ctype = WebTestThemeControlWin::RightArrowType;
+ cstate = WebTestThemeControlWin::HotState;
+ break;
+
+ case ABS_UPHOVER:
+ BLINK_ASSERT(classicState == DFCS_SCROLLUP);
+ ctype = WebTestThemeControlWin::UpArrowType;
+ cstate = WebTestThemeControlWin::HoverState;
+ break;
+
+ case ABS_DOWNHOVER:
+ BLINK_ASSERT(classicState == DFCS_SCROLLDOWN);
+ ctype = WebTestThemeControlWin::DownArrowType;
+ cstate = WebTestThemeControlWin::HoverState;
+ break;
+
+ case ABS_LEFTHOVER:
+ BLINK_ASSERT(classicState == DFCS_SCROLLLEFT);
+ ctype = WebTestThemeControlWin::LeftArrowType;
+ cstate = WebTestThemeControlWin::HoverState;
+ break;
+
+ case ABS_RIGHTHOVER:
+ BLINK_ASSERT(classicState == DFCS_SCROLLRIGHT);
+ ctype = WebTestThemeControlWin::RightArrowType;
+ cstate = WebTestThemeControlWin::HoverState;
+ break;
+
+ case ABS_UPPRESSED:
+ BLINK_ASSERT(classicState == (DFCS_SCROLLUP | DFCS_PUSHED | DFCS_FLAT));
+ ctype = WebTestThemeControlWin::UpArrowType;
+ cstate = WebTestThemeControlWin::PressedState;
+ break;
+
+ case ABS_DOWNPRESSED:
+ BLINK_ASSERT(classicState == (DFCS_SCROLLDOWN | DFCS_PUSHED | DFCS_FLAT));
+ ctype = WebTestThemeControlWin::DownArrowType;
+ cstate = WebTestThemeControlWin::PressedState;
+ break;
+
+ case ABS_LEFTPRESSED:
+ BLINK_ASSERT(classicState == (DFCS_SCROLLLEFT | DFCS_PUSHED | DFCS_FLAT));
+ ctype = WebTestThemeControlWin::LeftArrowType;
+ cstate = WebTestThemeControlWin::PressedState;
+ break;
+
+ case ABS_RIGHTPRESSED:
+ BLINK_ASSERT(classicState == (DFCS_SCROLLRIGHT | DFCS_PUSHED | DFCS_FLAT));
+ ctype = WebTestThemeControlWin::RightArrowType;
+ cstate = WebTestThemeControlWin::PressedState;
+ break;
+
+ case ABS_UPDISABLED:
+ BLINK_ASSERT(classicState == (DFCS_SCROLLUP | DFCS_INACTIVE));
+ ctype = WebTestThemeControlWin::UpArrowType;
+ cstate = WebTestThemeControlWin::DisabledState;
+ break;
+
+ case ABS_DOWNDISABLED:
+ BLINK_ASSERT(classicState == (DFCS_SCROLLDOWN | DFCS_INACTIVE));
+ ctype = WebTestThemeControlWin::DownArrowType;
+ cstate = WebTestThemeControlWin::DisabledState;
+ break;
+
+ case ABS_LEFTDISABLED:
+ BLINK_ASSERT(classicState == (DFCS_SCROLLLEFT | DFCS_INACTIVE));
+ ctype = WebTestThemeControlWin::LeftArrowType;
+ cstate = WebTestThemeControlWin::DisabledState;
+ break;
+
+ case ABS_RIGHTDISABLED:
+ BLINK_ASSERT(classicState == (DFCS_SCROLLRIGHT | DFCS_INACTIVE));
+ ctype = WebTestThemeControlWin::RightArrowType;
+ cstate = WebTestThemeControlWin::DisabledState;
+ break;
+
+ default:
+ BLINK_ASSERT_NOT_REACHED();
+ break;
+ }
+
+ drawControl(canvas, rect, ctype, cstate);
+}
+
+void WebTestThemeEngineWin::paintScrollbarThumb(WebCanvas* canvas, int part, int state, int classicState, const WebRect& rect)
+{
+ WebTestThemeControlWin::Type ctype = WebTestThemeControlWin::UnknownType;
+ WebTestThemeControlWin::State cstate = WebTestThemeControlWin::UnknownState;
+
+ switch (part) {
+ case SBP_THUMBBTNHORZ:
+ ctype = WebTestThemeControlWin::HorizontalScrollThumbType;
+ break;
+
+ case SBP_THUMBBTNVERT:
+ ctype = WebTestThemeControlWin::VerticalScrollThumbType;
+ break;
+
+ case SBP_GRIPPERHORZ:
+ ctype = WebTestThemeControlWin::HorizontalScrollGripType;
+ break;
+
+ case SBP_GRIPPERVERT:
+ ctype = WebTestThemeControlWin::VerticalScrollGripType;
+ break;
+
+ default:
+ BLINK_ASSERT_NOT_REACHED();
+ break;
+ }
+
+ switch (state) {
+ case SCRBS_NORMAL:
+ BLINK_ASSERT(classicState == dfcsNormal);
+ cstate = WebTestThemeControlWin::NormalState;
+ break;
+
+ case SCRBS_HOT:
+ BLINK_ASSERT(classicState == DFCS_HOT);
+ cstate = WebTestThemeControlWin::HotState;
+ break;
+
+ case SCRBS_HOVER:
+ BLINK_ASSERT(classicState == dfcsNormal);
+ cstate = WebTestThemeControlWin::HoverState;
+ break;
+
+ case SCRBS_PRESSED:
+ BLINK_ASSERT(classicState == dfcsNormal);
+ cstate = WebTestThemeControlWin::PressedState;
+ break;
+
+ case SCRBS_DISABLED:
+ BLINK_ASSERT_NOT_REACHED(); // This should never happen in practice.
+ break;
+
+ default:
+ BLINK_ASSERT_NOT_REACHED();
+ break;
+ }
+
+ drawControl(canvas, rect, ctype, cstate);
+}
+
+void WebTestThemeEngineWin::paintScrollbarTrack(WebCanvas* canvas, int part, int state, int classicState, const WebRect& rect, const WebRect& alignRect)
+{
+ WebTestThemeControlWin::Type ctype = WebTestThemeControlWin::UnknownType;
+ WebTestThemeControlWin::State cstate = WebTestThemeControlWin::UnknownState;
+
+ switch (part) {
+ case SBP_UPPERTRACKHORZ:
+ ctype = WebTestThemeControlWin::HorizontalScrollTrackBackType;
+ break;
+
+ case SBP_LOWERTRACKHORZ:
+ ctype = WebTestThemeControlWin::HorizontalScrollTrackForwardType;
+ break;
+
+ case SBP_UPPERTRACKVERT:
+ ctype = WebTestThemeControlWin::VerticalScrollTrackBackType;
+ break;
+
+ case SBP_LOWERTRACKVERT:
+ ctype = WebTestThemeControlWin::VerticalScrollTrackForwardType;
+ break;
+
+ default:
+ BLINK_ASSERT_NOT_REACHED();
+ break;
+ }
+
+ switch (state) {
+ case SCRBS_NORMAL:
+ BLINK_ASSERT(classicState == dfcsNormal);
+ cstate = WebTestThemeControlWin::NormalState;
+ break;
+
+ case SCRBS_HOT:
+ BLINK_ASSERT_NOT_REACHED(); // This should never happen in practice.
+ break;
+
+ case SCRBS_HOVER:
+ BLINK_ASSERT(classicState == dfcsNormal);
+ cstate = WebTestThemeControlWin::HoverState;
+ break;
+
+ case SCRBS_PRESSED:
+ BLINK_ASSERT_NOT_REACHED(); // This should never happen in practice.
+ break;
+
+ case SCRBS_DISABLED:
+ BLINK_ASSERT(classicState == DFCS_INACTIVE);
+ cstate = WebTestThemeControlWin::DisabledState;
+ break;
+
+ default:
+ BLINK_ASSERT_NOT_REACHED();
+ break;
+ }
+
+ drawControl(canvas, rect, ctype, cstate);
+}
+
+void WebTestThemeEngineWin::paintSpinButton(WebCanvas* canvas, int part, int state, int classicState, const WebRect& rect)
+{
+ WebTestThemeControlWin::Type ctype = WebTestThemeControlWin::UnknownType;
+ WebTestThemeControlWin::State cstate = WebTestThemeControlWin::UnknownState;
+
+ if (part == SPNP_UP) {
+ ctype = WebTestThemeControlWin::UpArrowType;
+ switch (state) {
+ case UPS_NORMAL:
+ BLINK_ASSERT(classicState == DFCS_SCROLLUP);
+ cstate = WebTestThemeControlWin::NormalState;
+ break;
+ case UPS_DISABLED:
+ BLINK_ASSERT(classicState == (DFCS_SCROLLUP | DFCS_INACTIVE));
+ cstate = WebTestThemeControlWin::DisabledState;
+ break;
+ case UPS_PRESSED:
+ BLINK_ASSERT(classicState == (DFCS_SCROLLUP | DFCS_PUSHED));
+ cstate = WebTestThemeControlWin::PressedState;
+ break;
+ case UPS_HOT:
+ BLINK_ASSERT(classicState == (DFCS_SCROLLUP | DFCS_HOT));
+ cstate = WebTestThemeControlWin::HoverState;
+ break;
+ default:
+ BLINK_ASSERT_NOT_REACHED();
+ }
+ } else if (part == SPNP_DOWN) {
+ ctype = WebTestThemeControlWin::DownArrowType;
+ switch (state) {
+ case DNS_NORMAL:
+ BLINK_ASSERT(classicState == DFCS_SCROLLDOWN);
+ cstate = WebTestThemeControlWin::NormalState;
+ break;
+ case DNS_DISABLED:
+ BLINK_ASSERT(classicState == (DFCS_SCROLLDOWN | DFCS_INACTIVE));
+ cstate = WebTestThemeControlWin::DisabledState;
+ break;
+ case DNS_PRESSED:
+ BLINK_ASSERT(classicState == (DFCS_SCROLLDOWN | DFCS_PUSHED));
+ cstate = WebTestThemeControlWin::PressedState;
+ break;
+ case DNS_HOT:
+ BLINK_ASSERT(classicState == (DFCS_SCROLLDOWN | DFCS_HOT));
+ cstate = WebTestThemeControlWin::HoverState;
+ break;
+ default:
+ BLINK_ASSERT_NOT_REACHED();
+ }
+ } else
+ BLINK_ASSERT_NOT_REACHED();
+ drawControl(canvas, rect, ctype, cstate);
+}
+
+void WebTestThemeEngineWin::paintTextField(WebCanvas* canvas, int part, int state, int classicState, const WebRect& rect, WebColor color, bool fillContentArea, bool drawEdges)
+{
+ WebTestThemeControlWin::Type ctype = WebTestThemeControlWin::UnknownType;
+ WebTestThemeControlWin::State cstate = WebTestThemeControlWin::UnknownState;
+
+ BLINK_ASSERT(EP_EDITTEXT == part);
+ ctype = WebTestThemeControlWin::TextFieldType;
+
+ switch (state) {
+ case ETS_NORMAL:
+ BLINK_ASSERT(classicState == dfcsNormal);
+ cstate = WebTestThemeControlWin::NormalState;
+ break;
+
+ case ETS_HOT:
+ BLINK_ASSERT(classicState == DFCS_HOT);
+ cstate = WebTestThemeControlWin::HotState;
+ break;
+
+ case ETS_DISABLED:
+ BLINK_ASSERT(classicState == DFCS_INACTIVE);
+ cstate = WebTestThemeControlWin::DisabledState;
+ break;
+
+ case ETS_SELECTED:
+ BLINK_ASSERT(classicState == DFCS_PUSHED);
+ cstate = WebTestThemeControlWin::PressedState;
+ break;
+
+ case ETS_FOCUSED:
+ BLINK_ASSERT(classicState == dfcsNormal);
+ cstate = WebTestThemeControlWin::FocusedState;
+ break;
+
+ case ETS_READONLY:
+ BLINK_ASSERT(classicState == dfcsNormal);
+ cstate = WebTestThemeControlWin::ReadOnlyState;
+ break;
+
+ default:
+ BLINK_ASSERT_NOT_REACHED();
+ break;
+ }
+
+ drawTextField(canvas, rect, ctype, cstate, drawEdges, fillContentArea, color);
+}
+
+void WebTestThemeEngineWin::paintTrackbar(WebCanvas* canvas, int part, int state, int classicState, const WebRect& rect)
+{
+ WebTestThemeControlWin::Type ctype = WebTestThemeControlWin::UnknownType;
+ WebTestThemeControlWin::State cstate = WebTestThemeControlWin::UnknownState;
+
+ if (TKP_THUMBBOTTOM == part) {
+ ctype = WebTestThemeControlWin::HorizontalSliderThumbType;
+ switch (state) {
+ case TUS_NORMAL:
+ BLINK_ASSERT(classicState == dfcsNormal);
+ cstate = WebTestThemeControlWin::NormalState;
+ break;
+
+ case TUS_HOT:
+ BLINK_ASSERT(classicState == DFCS_HOT);
+ cstate = WebTestThemeControlWin::HotState;
+ break;
+
+ case TUS_DISABLED:
+ BLINK_ASSERT(classicState == DFCS_INACTIVE);
+ cstate = WebTestThemeControlWin::DisabledState;
+ break;
+
+ case TUS_PRESSED:
+ BLINK_ASSERT(classicState == DFCS_PUSHED);
+ cstate = WebTestThemeControlWin::PressedState;
+ break;
+
+ default:
+ BLINK_ASSERT_NOT_REACHED();
+ break;
+ }
+ } else if (TKP_THUMBVERT == part) {
+ ctype = WebTestThemeControlWin::VerticalSliderThumbType;
+ switch (state) {
+ case TUS_NORMAL:
+ BLINK_ASSERT(classicState == dfcsNormal);
+ cstate = WebTestThemeControlWin::NormalState;
+ break;
+
+ case TUS_HOT:
+ BLINK_ASSERT(classicState == DFCS_HOT);
+ cstate = WebTestThemeControlWin::HotState;
+ break;
+
+ case TUS_DISABLED:
+ BLINK_ASSERT(classicState == DFCS_INACTIVE);
+ cstate = WebTestThemeControlWin::DisabledState;
+ break;
+
+ case TUS_PRESSED:
+ BLINK_ASSERT(classicState == DFCS_PUSHED);
+ cstate = WebTestThemeControlWin::PressedState;
+ break;
+
+ default:
+ BLINK_ASSERT_NOT_REACHED();
+ break;
+ }
+ } else if (TKP_TRACK == part) {
+ ctype = WebTestThemeControlWin::HorizontalSliderTrackType;
+ BLINK_ASSERT(state == TRS_NORMAL);
+ BLINK_ASSERT(classicState == dfcsNormal);
+ cstate = WebTestThemeControlWin::NormalState;
+ } else if (TKP_TRACKVERT == part) {
+ ctype = WebTestThemeControlWin::VerticalSliderTrackType;
+ BLINK_ASSERT(state == TRVS_NORMAL);
+ BLINK_ASSERT(classicState == dfcsNormal);
+ cstate = WebTestThemeControlWin::NormalState;
+ } else
+ BLINK_ASSERT_NOT_REACHED();
+
+ drawControl(canvas, rect, ctype, cstate);
+}
+
+
+void WebTestThemeEngineWin::paintProgressBar(blink::WebCanvas* canvas, const blink::WebRect& barRect, const blink::WebRect& valueRect, bool determinate, double)
+{
+ WebTestThemeControlWin::Type ctype = WebTestThemeControlWin::ProgressBarType;
+ WebTestThemeControlWin::State cstate = determinate ? WebTestThemeControlWin::NormalState : WebTestThemeControlWin::IndeterminateState;
+ drawProgressBar(canvas, ctype, cstate, barRect, valueRect);
+}
+
+
+blink::WebSize WebTestThemeEngineWin::getSize(int part)
+{
+ return blink::WebSize();
+}
+
+}
diff --git a/content/shell/renderer/test_runner/WebTestThemeEngineWin.h b/content/shell/renderer/test_runner/WebTestThemeEngineWin.h
new file mode 100644
index 0000000..808af68
--- /dev/null
+++ b/content/shell/renderer/test_runner/WebTestThemeEngineWin.h
@@ -0,0 +1,78 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This implements the WebThemeEngine API used by the Windows version of
+// Chromium to render native form controls like checkboxes, radio buttons,
+// and scroll bars.
+// The normal implementation (native_theme) renders the controls using either
+// the UXTheme theming engine present in XP, Vista, and Win 7, or the "classic"
+// theme used if that theme is selected in the Desktop settings.
+// Unfortunately, both of these themes render controls differently on the
+// different versions of Windows.
+//
+// In order to ensure maximum consistency of baselines across the different
+// Windows versions, we provide a simple implementation for DRT here
+// instead. These controls are actually platform-independent (they're rendered
+// using Skia) and could be used on Linux and the Mac as well, should we
+// choose to do so at some point.
+//
+
+#ifndef WebTestThemeEngineWin_h
+#define WebTestThemeEngineWin_h
+
+#include "third_party/WebKit/public/platform/WebNonCopyable.h"
+#include "third_party/WebKit/public/platform/win/WebThemeEngine.h"
+
+namespace WebTestRunner {
+
+class WebTestThemeEngineWin : public blink::WebThemeEngine, public blink::WebNonCopyable {
+public:
+ WebTestThemeEngineWin() { }
+ virtual ~WebTestThemeEngineWin() { }
+
+ // WebThemeEngine methods:
+ virtual void paintButton(
+ blink::WebCanvas*, int part, int state, int classicState,
+ const blink::WebRect&);
+
+ virtual void paintMenuList(
+ blink::WebCanvas*, int part, int state, int classicState,
+ const blink::WebRect&);
+
+ virtual void paintScrollbarArrow(
+ blink::WebCanvas*, int state, int classicState,
+ const blink::WebRect&);
+
+ virtual void paintScrollbarThumb(
+ blink::WebCanvas*, int part, int state, int classicState,
+ const blink::WebRect&);
+
+ virtual void paintScrollbarTrack(
+ blink::WebCanvas*, int part, int state, int classicState,
+ const blink::WebRect&, const blink::WebRect& alignRect);
+
+ virtual void paintSpinButton(
+ blink::WebCanvas*, int part, int state, int classicState,
+ const blink::WebRect&);
+
+ virtual void paintTextField(
+ blink::WebCanvas*, int part, int state, int classicState,
+ const blink::WebRect&, blink::WebColor, bool fillContentArea,
+ bool drawEdges);
+
+ virtual void paintTrackbar(
+ blink::WebCanvas*, int part, int state, int classicState,
+ const blink::WebRect&);
+
+ virtual void paintProgressBar(
+ blink::WebCanvas*, const blink::WebRect& barRect,
+ const blink::WebRect& valueRect,
+ bool determinate, double time);
+
+ virtual blink::WebSize getSize(int part);
+};
+
+}
+
+#endif // WebTestThemeEngineWin_h
diff --git a/content/shell/renderer/test_runner/WebUserMediaClientMock.cpp b/content/shell/renderer/test_runner/WebUserMediaClientMock.cpp
new file mode 100644
index 0000000..36950a0
--- /dev/null
+++ b/content/shell/renderer/test_runner/WebUserMediaClientMock.cpp
@@ -0,0 +1,141 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/shell/renderer/test_runner/WebUserMediaClientMock.h"
+
+#include "content/shell/renderer/test_runner/MockConstraints.h"
+#include "content/shell/renderer/test_runner/WebTestDelegate.h"
+#include "third_party/WebKit/public/platform/WebMediaConstraints.h"
+#include "third_party/WebKit/public/platform/WebMediaStream.h"
+#include "third_party/WebKit/public/platform/WebMediaStreamSource.h"
+#include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
+#include "third_party/WebKit/public/platform/WebVector.h"
+#include "third_party/WebKit/public/web/WebDocument.h"
+#include "third_party/WebKit/public/web/WebMediaStreamRegistry.h"
+#include "third_party/WebKit/public/web/WebUserMediaRequest.h"
+
+using namespace blink;
+
+namespace WebTestRunner {
+
+class UserMediaRequestTask : public WebMethodTask<WebUserMediaClientMock> {
+public:
+ UserMediaRequestTask(WebUserMediaClientMock* object, const WebUserMediaRequest& request, const WebMediaStream result)
+ : WebMethodTask<WebUserMediaClientMock>(object)
+ , m_request(request)
+ , m_result(result)
+ {
+ BLINK_ASSERT(!m_result.isNull());
+ }
+
+ virtual void runIfValid() OVERRIDE
+ {
+ m_request.requestSucceeded(m_result);
+ }
+
+private:
+ WebUserMediaRequest m_request;
+ WebMediaStream m_result;
+};
+
+class UserMediaRequestConstraintFailedTask : public WebMethodTask<WebUserMediaClientMock> {
+public:
+ UserMediaRequestConstraintFailedTask(WebUserMediaClientMock* object, const WebUserMediaRequest& request, const WebString& constraint)
+ : WebMethodTask<WebUserMediaClientMock>(object)
+ , m_request(request)
+ , m_constraint(constraint)
+ {
+ }
+
+ virtual void runIfValid() OVERRIDE
+ {
+ m_request.requestFailedConstraint(m_constraint);
+ }
+
+private:
+ WebUserMediaRequest m_request;
+ WebString m_constraint;
+};
+
+class UserMediaRequestPermissionDeniedTask : public WebMethodTask<WebUserMediaClientMock> {
+public:
+ UserMediaRequestPermissionDeniedTask(WebUserMediaClientMock* object, const WebUserMediaRequest& request)
+ : WebMethodTask<WebUserMediaClientMock>(object)
+ , m_request(request)
+ {
+ }
+
+ virtual void runIfValid() OVERRIDE
+ {
+ m_request.requestFailed();
+ }
+
+private:
+ WebUserMediaRequest m_request;
+};
+
+////////////////////////////////
+
+class MockExtraData : public WebMediaStream::ExtraData {
+public:
+ int foo;
+};
+
+WebUserMediaClientMock::WebUserMediaClientMock(WebTestDelegate* delegate)
+ : m_delegate(delegate)
+{
+}
+
+void WebUserMediaClientMock::requestUserMedia(const WebUserMediaRequest& streamRequest)
+{
+ BLINK_ASSERT(!streamRequest.isNull());
+ WebUserMediaRequest request = streamRequest;
+
+ if (request.ownerDocument().isNull() || !request.ownerDocument().frame()) {
+ m_delegate->postTask(new UserMediaRequestPermissionDeniedTask(this, request));
+ return;
+ }
+
+ WebMediaConstraints constraints = request.audioConstraints();
+ WebString failedConstraint;
+ if (!constraints.isNull() && !MockConstraints::verifyConstraints(constraints, &failedConstraint)) {
+ m_delegate->postTask(new UserMediaRequestConstraintFailedTask(this, request, failedConstraint));
+ return;
+ }
+ constraints = request.videoConstraints();
+ if (!constraints.isNull() && !MockConstraints::verifyConstraints(constraints, &failedConstraint)) {
+ m_delegate->postTask(new UserMediaRequestConstraintFailedTask(this, request, failedConstraint));
+ return;
+ }
+
+ const size_t zero = 0;
+ const size_t one = 1;
+ WebVector<WebMediaStreamTrack> audioTracks(request.audio() ? one : zero);
+ WebVector<WebMediaStreamTrack> videoTracks(request.video() ? one : zero);
+
+ if (request.audio()) {
+ WebMediaStreamSource source;
+ source.initialize("MockAudioDevice#1", WebMediaStreamSource::TypeAudio, "Mock audio device");
+ audioTracks[0].initialize(source);
+ }
+
+ if (request.video()) {
+ WebMediaStreamSource source;
+ source.initialize("MockVideoDevice#1", WebMediaStreamSource::TypeVideo, "Mock video device");
+ videoTracks[0].initialize(source);
+ }
+
+ WebMediaStream stream;
+ stream.initialize(audioTracks, videoTracks);
+
+ stream.setExtraData(new MockExtraData());
+
+ m_delegate->postTask(new UserMediaRequestTask(this, request, stream));
+}
+
+void WebUserMediaClientMock::cancelUserMediaRequest(const WebUserMediaRequest&)
+{
+}
+
+}
diff --git a/content/shell/renderer/test_runner/WebUserMediaClientMock.h b/content/shell/renderer/test_runner/WebUserMediaClientMock.h
new file mode 100644
index 0000000..37a4bd9
--- /dev/null
+++ b/content/shell/renderer/test_runner/WebUserMediaClientMock.h
@@ -0,0 +1,38 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WebUserMediaClientMock_h
+#define WebUserMediaClientMock_h
+
+#include "content/shell/renderer/test_runner/TestCommon.h"
+#include "content/shell/renderer/test_runner/WebTask.h"
+#include "third_party/WebKit/public/platform/WebCommon.h"
+#include "third_party/WebKit/public/platform/WebNonCopyable.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/platform/WebURL.h"
+#include "third_party/WebKit/public/web/WebUserMediaClient.h"
+
+namespace WebTestRunner {
+
+class WebTestDelegate;
+
+class WebUserMediaClientMock : public blink::WebUserMediaClient, public blink::WebNonCopyable {
+public:
+ explicit WebUserMediaClientMock(WebTestDelegate*);
+ ~WebUserMediaClientMock() { }
+
+ virtual void requestUserMedia(const blink::WebUserMediaRequest&) OVERRIDE;
+ virtual void cancelUserMediaRequest(const blink::WebUserMediaRequest&) OVERRIDE;
+
+ // Task related methods
+ WebTaskList* taskList() { return &m_taskList; }
+
+private:
+ WebTaskList m_taskList;
+ WebTestDelegate* m_delegate;
+};
+
+}
+
+#endif // WebUserMediaClientMock_h
diff --git a/content/shell/renderer/webkit_test_runner.cc b/content/shell/renderer/webkit_test_runner.cc
index e9b96ae..666cd53 100644
--- a/content/shell/renderer/webkit_test_runner.cc
+++ b/content/shell/renderer/webkit_test_runner.cc
@@ -29,6 +29,10 @@
#include "content/shell/common/shell_messages.h"
#include "content/shell/common/webkit_test_helpers.h"
#include "content/shell/renderer/shell_render_process_observer.h"
+#include "content/shell/renderer/test_runner/WebTask.h"
+#include "content/shell/renderer/test_runner/WebTestInterfaces.h"
+#include "content/shell/renderer/test_runner/WebTestProxy.h"
+#include "content/shell/renderer/test_runner/WebTestRunner.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
#include "skia/ext/platform_canvas.h"
@@ -42,10 +46,6 @@
#include "third_party/WebKit/public/platform/WebURLError.h"
#include "third_party/WebKit/public/platform/WebURLRequest.h"
#include "third_party/WebKit/public/platform/WebURLResponse.h"
-#include "third_party/WebKit/public/testing/WebTask.h"
-#include "third_party/WebKit/public/testing/WebTestInterfaces.h"
-#include "third_party/WebKit/public/testing/WebTestProxy.h"
-#include "third_party/WebKit/public/testing/WebTestRunner.h"
#include "third_party/WebKit/public/web/WebArrayBufferView.h"
#include "third_party/WebKit/public/web/WebContextMenuData.h"
#include "third_party/WebKit/public/web/WebDataSource.h"
diff --git a/content/shell/renderer/webkit_test_runner.h b/content/shell/renderer/webkit_test_runner.h
index 4b12643..4b419ee 100644
--- a/content/shell/renderer/webkit_test_runner.h
+++ b/content/shell/renderer/webkit_test_runner.h
@@ -13,8 +13,8 @@
#include "content/public/renderer/render_view_observer.h"
#include "content/public/renderer/render_view_observer_tracker.h"
#include "content/shell/common/shell_test_configuration.h"
-#include "third_party/WebKit/public/testing/WebPreferences.h"
-#include "third_party/WebKit/public/testing/WebTestDelegate.h"
+#include "content/shell/common/test_runner/WebPreferences.h"
+#include "content/shell/renderer/test_runner/WebTestDelegate.h"
#include "v8/include/v8.h"
class SkCanvas;
diff --git a/content/test/DEPS b/content/test/DEPS
index 6e063e8..fb2a8f8 100644
--- a/content/test/DEPS
+++ b/content/test/DEPS
@@ -3,7 +3,6 @@ include_rules = [
"+content",
"+media/audio", # For AudioParameters in WebRTC tests.
"+media/base", # For ChannelLayout in WebRTC tests.
- "+third_party/WebKit/public/testing",
"+ui/base/resource/data_pack.h",
"+ui/base/resource/resource_bundle.h",
"!v8/include/v8.h",
diff --git a/content/test/layouttest_support.cc b/content/test/layouttest_support.cc
index 97eb7c4..125d2a2 100644
--- a/content/test/layouttest_support.cc
+++ b/content/test/layouttest_support.cc
@@ -11,12 +11,12 @@
#include "content/renderer/render_thread_impl.h"
#include "content/renderer/render_view_impl.h"
#include "content/renderer/renderer_webkitplatformsupport_impl.h"
+#include "content/shell/renderer/test_runner/WebFrameTestProxy.h"
+#include "content/shell/renderer/test_runner/WebTestProxy.h"
#include "content/test/test_media_stream_client.h"
#include "third_party/WebKit/public/platform/WebDeviceMotionData.h"
#include "third_party/WebKit/public/platform/WebDeviceOrientationData.h"
#include "third_party/WebKit/public/platform/WebGamepads.h"
-#include "third_party/WebKit/public/testing/WebFrameTestProxy.h"
-#include "third_party/WebKit/public/testing/WebTestProxy.h"
#if defined(OS_WIN) && !defined(USE_AURA)
#include "content/browser/web_contents/web_contents_drag_win.h"