summaryrefslogtreecommitdiffstats
path: root/WebKitTools/DumpRenderTree
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2010-04-27 16:31:00 +0100
committerSteve Block <steveblock@google.com>2010-05-11 14:42:12 +0100
commitdcc8cf2e65d1aa555cce12431a16547e66b469ee (patch)
tree92a8d65cd5383bca9749f5327fb5e440563926e6 /WebKitTools/DumpRenderTree
parentccac38a6b48843126402088a309597e682f40fe6 (diff)
downloadexternal_webkit-dcc8cf2e65d1aa555cce12431a16547e66b469ee.zip
external_webkit-dcc8cf2e65d1aa555cce12431a16547e66b469ee.tar.gz
external_webkit-dcc8cf2e65d1aa555cce12431a16547e66b469ee.tar.bz2
Merge webkit.org at r58033 : Initial merge by git
Change-Id: If006c38561af287c50cd578d251629b51e4d8cd1
Diffstat (limited to 'WebKitTools/DumpRenderTree')
-rw-r--r--WebKitTools/DumpRenderTree/AccessibilityController.cpp14
-rw-r--r--WebKitTools/DumpRenderTree/AccessibilityController.h1
-rw-r--r--WebKitTools/DumpRenderTree/AccessibilityUIElement.cpp33
-rw-r--r--WebKitTools/DumpRenderTree/AccessibilityUIElement.h21
-rw-r--r--WebKitTools/DumpRenderTree/DumpRenderTree.gyp/DumpRenderTree.gyp186
-rw-r--r--WebKitTools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj8
-rw-r--r--WebKitTools/DumpRenderTree/LayoutTestController.cpp166
-rw-r--r--WebKitTools/DumpRenderTree/LayoutTestController.h30
-rw-r--r--WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp144
-rw-r--r--WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.h4
-rw-r--r--WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/main.cpp38
-rw-r--r--WebKitTools/DumpRenderTree/chromium/AccessibilityController.cpp119
-rw-r--r--WebKitTools/DumpRenderTree/chromium/AccessibilityController.h73
-rw-r--r--WebKitTools/DumpRenderTree/chromium/AccessibilityUIElement.cpp585
-rw-r--r--WebKitTools/DumpRenderTree/chromium/AccessibilityUIElement.h142
-rw-r--r--WebKitTools/DumpRenderTree/chromium/CppBoundClass.cpp350
-rw-r--r--WebKitTools/DumpRenderTree/chromium/CppBoundClass.h241
-rw-r--r--WebKitTools/DumpRenderTree/chromium/CppVariant.cpp310
-rw-r--r--WebKitTools/DumpRenderTree/chromium/CppVariant.h133
-rw-r--r--WebKitTools/DumpRenderTree/chromium/DumpRenderTree.cpp119
-rw-r--r--WebKitTools/DumpRenderTree/chromium/EventSender.cpp807
-rw-r--r--WebKitTools/DumpRenderTree/chromium/EventSender.h145
-rw-r--r--WebKitTools/DumpRenderTree/chromium/ImageDiff.cpp407
-rw-r--r--WebKitTools/DumpRenderTree/chromium/LayoutTestController.cpp1179
-rw-r--r--WebKitTools/DumpRenderTree/chromium/LayoutTestController.h440
-rw-r--r--WebKitTools/DumpRenderTree/chromium/LayoutTestHelper.mm118
-rw-r--r--WebKitTools/DumpRenderTree/chromium/MockSpellCheck.cpp149
-rw-r--r--WebKitTools/DumpRenderTree/chromium/MockSpellCheck.h82
-rw-r--r--WebKitTools/DumpRenderTree/chromium/PlainTextController.cpp79
-rw-r--r--WebKitTools/DumpRenderTree/chromium/PlainTextController.h52
-rw-r--r--WebKitTools/DumpRenderTree/chromium/TestNavigationController.cpp269
-rw-r--r--WebKitTools/DumpRenderTree/chromium/TestNavigationController.h204
-rw-r--r--WebKitTools/DumpRenderTree/chromium/TestShell.cpp614
-rw-r--r--WebKitTools/DumpRenderTree/chromium/TestShell.h149
-rw-r--r--WebKitTools/DumpRenderTree/chromium/TestShellGtk.cpp64
-rw-r--r--WebKitTools/DumpRenderTree/chromium/TestShellMac.mm125
-rw-r--r--WebKitTools/DumpRenderTree/chromium/TestShellWin.cpp100
-rw-r--r--WebKitTools/DumpRenderTree/chromium/TestWebWorker.h88
-rw-r--r--WebKitTools/DumpRenderTree/chromium/TextInputController.cpp216
-rw-r--r--WebKitTools/DumpRenderTree/chromium/TextInputController.h149
-rw-r--r--WebKitTools/DumpRenderTree/chromium/WebViewHost.cpp1316
-rw-r--r--WebKitTools/DumpRenderTree/chromium/WebViewHost.h271
-rw-r--r--WebKitTools/DumpRenderTree/chromium/config.h54
-rw-r--r--WebKitTools/DumpRenderTree/fonts/ColorBits-A.pngbin0 -> 585 bytes
-rw-r--r--WebKitTools/DumpRenderTree/fonts/ColorBits.ttfbin0 -> 1028 bytes
-rw-r--r--WebKitTools/DumpRenderTree/gtk/AccessibilityControllerGtk.cpp6
-rw-r--r--WebKitTools/DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp35
-rw-r--r--WebKitTools/DumpRenderTree/gtk/DumpRenderTree.cpp128
-rw-r--r--WebKitTools/DumpRenderTree/gtk/EventSender.cpp44
-rw-r--r--WebKitTools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp107
-rw-r--r--WebKitTools/DumpRenderTree/mac/AccessibilityControllerMac.mm6
-rw-r--r--WebKitTools/DumpRenderTree/mac/AccessibilityUIElementMac.mm162
-rw-r--r--WebKitTools/DumpRenderTree/mac/Configurations/Base.xcconfig32
-rw-r--r--WebKitTools/DumpRenderTree/mac/Configurations/DebugRelease.xcconfig4
-rw-r--r--WebKitTools/DumpRenderTree/mac/DumpRenderTree.mm69
-rw-r--r--WebKitTools/DumpRenderTree/mac/EventSendingController.mm105
-rw-r--r--WebKitTools/DumpRenderTree/mac/LayoutTestControllerMac.mm160
-rw-r--r--WebKitTools/DumpRenderTree/mac/ResourceLoadDelegate.mm18
-rw-r--r--WebKitTools/DumpRenderTree/qt/DumpRenderTree.pro8
-rw-r--r--WebKitTools/DumpRenderTree/qt/DumpRenderTreeQt.cpp113
-rw-r--r--WebKitTools/DumpRenderTree/qt/DumpRenderTreeQt.h2
-rw-r--r--WebKitTools/DumpRenderTree/qt/EventSenderQt.cpp36
-rw-r--r--WebKitTools/DumpRenderTree/qt/EventSenderQt.h10
-rw-r--r--WebKitTools/DumpRenderTree/qt/GCControllerQt.cpp12
-rw-r--r--WebKitTools/DumpRenderTree/qt/GCControllerQt.h2
-rw-r--r--WebKitTools/DumpRenderTree/qt/ImageDiff.pro3
-rw-r--r--WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.cpp203
-rw-r--r--WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.h39
-rw-r--r--WebKitTools/DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro1
-rw-r--r--WebKitTools/DumpRenderTree/qt/main.cpp7
-rw-r--r--WebKitTools/DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp25
-rw-r--r--WebKitTools/DumpRenderTree/win/AccessibilityControllerWin.cpp6
-rw-r--r--WebKitTools/DumpRenderTree/win/AccessibilityUIElementWin.cpp27
-rw-r--r--WebKitTools/DumpRenderTree/win/DumpRenderTree.cpp38
-rw-r--r--WebKitTools/DumpRenderTree/win/EventSender.cpp25
-rw-r--r--WebKitTools/DumpRenderTree/win/EventSender.h2
-rw-r--r--WebKitTools/DumpRenderTree/win/FrameLoadDelegate.cpp5
-rw-r--r--WebKitTools/DumpRenderTree/win/LayoutTestControllerWin.cpp130
-rw-r--r--WebKitTools/DumpRenderTree/win/ResourceLoadDelegate.cpp33
-rw-r--r--WebKitTools/DumpRenderTree/win/TestNetscapePlugin/main.cpp29
-rw-r--r--WebKitTools/DumpRenderTree/wx/LayoutTestControllerWx.cpp49
81 files changed, 11147 insertions, 328 deletions
diff --git a/WebKitTools/DumpRenderTree/AccessibilityController.cpp b/WebKitTools/DumpRenderTree/AccessibilityController.cpp
index 045bc80..798389f 100644
--- a/WebKitTools/DumpRenderTree/AccessibilityController.cpp
+++ b/WebKitTools/DumpRenderTree/AccessibilityController.cpp
@@ -77,12 +77,26 @@ static JSValueRef logScrollingStartEventsCallback(JSContextRef ctx, JSObjectRef,
return JSValueMakeUndefined(ctx);
}
+static JSValueRef getElementAtPointCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ int x = 0;
+ int y = 0;
+ if (argumentCount == 2) {
+ x = JSValueToNumber(context, arguments[0], exception);
+ y = JSValueToNumber(context, arguments[1], exception);
+ }
+
+ AccessibilityController* controller = static_cast<AccessibilityController*>(JSObjectGetPrivate(thisObject));
+ return AccessibilityUIElement::makeJSAccessibilityUIElement(context, controller->elementAtPoint(x, y));
+}
+
JSClassRef AccessibilityController::getJSClass()
{
static JSStaticFunction staticFunctions[] = {
{ "logFocusEvents", logFocusEventsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "logValueChangeEvents", logValueChangeEventsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "logScrollingStartEvents", logScrollingStartEventsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "elementAtPoint", getElementAtPointCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ 0, 0, 0 }
};
diff --git a/WebKitTools/DumpRenderTree/AccessibilityController.h b/WebKitTools/DumpRenderTree/AccessibilityController.h
index de58f84..5a6ca13 100644
--- a/WebKitTools/DumpRenderTree/AccessibilityController.h
+++ b/WebKitTools/DumpRenderTree/AccessibilityController.h
@@ -45,6 +45,7 @@ public:
// Controller Methods - platform-independent implementations
AccessibilityUIElement rootElement();
AccessibilityUIElement focusedElement();
+ AccessibilityUIElement elementAtPoint(int x, int y);
void setLogFocusEvents(bool);
void setLogValueChangeEvents(bool);
diff --git a/WebKitTools/DumpRenderTree/AccessibilityUIElement.cpp b/WebKitTools/DumpRenderTree/AccessibilityUIElement.cpp
index 87fe05c..9cf34de 100644
--- a/WebKitTools/DumpRenderTree/AccessibilityUIElement.cpp
+++ b/WebKitTools/DumpRenderTree/AccessibilityUIElement.cpp
@@ -344,6 +344,12 @@ static JSValueRef showMenuCallback(JSContextRef context, JSObjectRef function, J
return JSValueMakeUndefined(context);
}
+static JSValueRef pressCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ toAXElement(thisObject)->press();
+ return JSValueMakeUndefined(context);
+}
+
static JSValueRef takeFocusCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
toAXElement(thisObject)->takeFocus();
@@ -435,6 +441,12 @@ static JSValueRef getLanguageCallback(JSContextRef context, JSObjectRef thisObje
return JSValueMakeString(context, language.get());
}
+static JSValueRef getHelpTextCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> language(Adopt, toAXElement(thisObject)->helpText());
+ return JSValueMakeString(context, language.get());
+}
+
static JSValueRef getOrientationCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
{
JSRetainPtr<JSStringRef> orientation(Adopt, toAXElement(thisObject)->orientation());
@@ -446,6 +458,16 @@ static JSValueRef getChildrenCountCallback(JSContextRef context, JSObjectRef thi
return JSValueMakeNumber(context, toAXElement(thisObject)->childrenCount());
}
+static JSValueRef rowCountCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ return JSValueMakeNumber(context, toAXElement(thisObject)->rowCount());
+}
+
+static JSValueRef columnCountCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ return JSValueMakeNumber(context, toAXElement(thisObject)->columnCount());
+}
+
static JSValueRef getXCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
{
return JSValueMakeNumber(context, toAXElement(thisObject)->x());
@@ -602,6 +624,12 @@ static JSValueRef addNotificationListenerCallback(JSContextRef context, JSObject
return JSValueMakeBoolean(context, succeeded);
}
+static JSValueRef removeNotificationListenerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ toAXElement(thisObject)->removeNotificationListener();
+ return JSValueMakeUndefined(context);
+}
+
// Destruction
static void finalize(JSObjectRef thisObject)
@@ -626,6 +654,7 @@ JSClassRef AccessibilityUIElement::getJSClass()
{ "title", getTitleCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "description", getDescriptionCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "language", getLanguageCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "helpText", getHelpTextCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "stringValue", getStringValueCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "x", getXCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "y", getYCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
@@ -637,6 +666,8 @@ JSClassRef AccessibilityUIElement::getJSClass()
{ "minValue", getMinValueCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "maxValue", getMaxValueCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "childrenCount", getChildrenCountCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "rowCount", rowCountCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "columnCount", columnCountCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "insertionPointLineNumber", getInsertionPointLineNumberCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "selectedTextRange", getSelectedTextRangeCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "isEnabled", getIsEnabledCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
@@ -696,12 +727,14 @@ JSClassRef AccessibilityUIElement::getJSClass()
{ "increment", incrementCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "decrement", decrementCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "showMenu", showMenuCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "press", pressCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "disclosedRowAtIndex", disclosedRowAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "ariaOwnsElementAtIndex", ariaOwnsElementAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "ariaFlowToElementAtIndex", ariaFlowToElementAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "selectedRowAtIndex", selectedRowAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "isEqual", isEqualCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "addNotificationListener", addNotificationListenerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "removeNotificationListener", removeNotificationListenerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "takeFocus", takeFocusCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "takeSelection", takeSelectionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "addSelection", addSelectionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
diff --git a/WebKitTools/DumpRenderTree/AccessibilityUIElement.h b/WebKitTools/DumpRenderTree/AccessibilityUIElement.h
index e7d3bc7..f62ec1a 100644
--- a/WebKitTools/DumpRenderTree/AccessibilityUIElement.h
+++ b/WebKitTools/DumpRenderTree/AccessibilityUIElement.h
@@ -51,6 +51,14 @@ typedef AtkObject* PlatformUIElement;
typedef void* PlatformUIElement;
#endif
+#if PLATFORM(MAC)
+#ifdef __OBJC__
+typedef id NotificationHandler;
+#else
+typedef struct objc_object* NotificationHandler;
+#endif
+#endif
+
class AccessibilityUIElement {
public:
AccessibilityUIElement(PlatformUIElement);
@@ -89,6 +97,7 @@ public:
void increment();
void decrement();
void showMenu();
+ void press();
// Attributes - platform-independent implementations
JSStringRef stringAttributeValue(JSStringRef attribute);
@@ -104,6 +113,7 @@ public:
JSStringRef language();
JSStringRef stringValue();
JSStringRef accessibilityValue() const;
+ JSStringRef helpText() const;
JSStringRef orientation() const;
double x();
double y();
@@ -143,6 +153,8 @@ public:
int indexInTable();
JSStringRef rowIndexRange();
JSStringRef columnIndexRange();
+ int rowCount();
+ int columnCount();
// Tree/Outline specific attributes
AccessibilityUIElement selectedRowAtIndex(unsigned);
@@ -170,12 +182,17 @@ public:
// Notifications
// Function callback should take one argument, the name of the notification.
bool addNotificationListener(JSObjectRef functionCallback);
+ // Make sure you call remove, because you can't rely on objects being deallocated in a timely fashion.
+ void removeNotificationListener();
private:
static JSClassRef getJSClass();
-
PlatformUIElement m_element;
- JSObjectRef m_notificationFunctionCallback;
+
+ // A retained, platform specific object used to help manage notifications for this object.
+#if PLATFORM(MAC)
+ NotificationHandler m_notificationHandler;
+#endif
};
#endif // AccessibilityUIElement_h
diff --git a/WebKitTools/DumpRenderTree/DumpRenderTree.gyp/DumpRenderTree.gyp b/WebKitTools/DumpRenderTree/DumpRenderTree.gyp/DumpRenderTree.gyp
new file mode 100644
index 0000000..82b8671
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/DumpRenderTree.gyp/DumpRenderTree.gyp
@@ -0,0 +1,186 @@
+#
+# Copyright (C) 2010 Google 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.
+#
+
+{
+ 'includes': [
+ '../../../WebKit/chromium/features.gypi',
+ ],
+ 'variables': {
+ 'webkit_top': '../../..',
+ 'webkit_api_dir': '<(webkit_top)/WebKit/chromium',
+ 'conditions': [
+ # Location of the chromium src directory and target type is different
+ # if webkit is built inside chromium or as standalone project.
+ ['inside_chromium_build==0', {
+ # DumpRenderTree is being built outside of the full chromium project.
+ # e.g. via build-dumprendertree --chromium
+ 'chromium_src_dir': '<(webkit_api_dir)',
+ 'webkit_support_gyp': '<(webkit_api_dir)/webkit/support/webkit_support.gyp',
+ },{
+ # WebKit is checked out in src/chromium/third_party/WebKit
+ 'chromium_src_dir': '<(webkit_top)/../..',
+ 'webkit_support_gyp': '<(webkit_top)/../../webkit/webkit.gyp',
+ }],
+ ],
+ },
+ 'target_defaults': {
+ 'target_conditions': [
+ ['OS!="linux" and OS!="freebsd" and OS!="openbsd"', {
+ 'sources/': [
+ ['exclude', '(Gtk|Linux)\\.cpp$']
+ ]
+ }],
+ ['OS!="win"', {
+ 'sources/': [
+ ['exclude', 'Win\\.cpp$'],
+ ]
+ }],
+ ['OS!="mac"', {
+ 'sources/': [
+ # .mm is already excluded by common.gypi
+ ['exclude', 'Mac\\.cpp$'],
+ ]
+ }],
+ ],
+ },
+ 'targets': [
+ {
+ 'target_name': 'DumpRenderTree',
+ 'type': 'executable',
+ 'mac_bundle': 1,
+ 'dependencies': [
+ '<(webkit_api_dir)/WebKit.gyp:webkit',
+ '<(webkit_top)/JavaScriptCore/JavaScriptCore.gyp/JavaScriptCore.gyp:wtf_config',
+ '<(chromium_src_dir)/third_party/icu/icu.gyp:icuuc',
+ '<(chromium_src_dir)/third_party/npapi/npapi.gyp:npapi',
+ '<(chromium_src_dir)/skia/skia.gyp:skia',
+ '<(webkit_support_gyp):webkit_support',
+ ],
+ 'include_dirs': [
+ '.',
+ '<(webkit_api_dir)',
+ '<(webkit_top)/JavaScriptCore',
+ '<(webkit_top)/WebKit/mac/WebCoreSupport', # For WebSystemInterface.h
+ '<(chromium_src_dir)',
+ ],
+ 'defines': [
+ # Technically not a unit test but require functions available only to
+ # unit tests.
+ 'UNIT_TEST',
+ ],
+ 'sources': [
+ '../chromium/AccessibilityController.cpp',
+ '../chromium/AccessibilityController.h',
+ '../chromium/AccessibilityUIElement.cpp',
+ '../chromium/AccessibilityUIElement.h',
+ '../chromium/CppBoundClass.cpp',
+ '../chromium/CppBoundClass.h',
+ '../chromium/CppVariant.cpp',
+ '../chromium/CppVariant.h',
+ '../chromium/DumpRenderTree.cpp',
+ '../chromium/EventSender.cpp',
+ '../chromium/EventSender.h',
+ '../chromium/LayoutTestController.cpp',
+ '../chromium/LayoutTestController.h',
+ '../chromium/MockSpellCheck.cpp',
+ '../chromium/MockSpellCheck.h',
+ '../chromium/PlainTextController.cpp',
+ '../chromium/PlainTextController.h',
+ '../chromium/TestNavigationController.cpp',
+ '../chromium/TestNavigationController.h',
+ '../chromium/TestShell.cpp',
+ '../chromium/TestShell.h',
+ '../chromium/TestShellGtk.cpp',
+ '../chromium/TestShellMac.mm',
+ '../chromium/TestShellWin.cpp',
+ '../chromium/TextInputController.cpp',
+ '../chromium/TextInputController.h',
+ '../chromium/WebViewHost.cpp',
+ '../chromium/WebViewHost.h',
+ ],
+ 'mac_bundle_resources': [
+ '../qt/fonts/AHEM____.TTF',
+ '../fonts/WebKitWeightWatcher100.ttf',
+ '../fonts/WebKitWeightWatcher200.ttf',
+ '../fonts/WebKitWeightWatcher300.ttf',
+ '../fonts/WebKitWeightWatcher400.ttf',
+ '../fonts/WebKitWeightWatcher500.ttf',
+ '../fonts/WebKitWeightWatcher600.ttf',
+ '../fonts/WebKitWeightWatcher700.ttf',
+ '../fonts/WebKitWeightWatcher800.ttf',
+ '../fonts/WebKitWeightWatcher900.ttf',
+ ],
+ 'conditions': [
+ ['OS=="mac"', {
+ 'dependencies': ['LayoutTestHelper'],
+ }],
+ ],
+ },
+
+ {
+ 'target_name': 'ImageDiff',
+ 'type': 'executable',
+ 'dependencies': [
+ '<(webkit_top)/JavaScriptCore/JavaScriptCore.gyp/JavaScriptCore.gyp:wtf',
+ '<(chromium_src_dir)/gfx/gfx.gyp:gfx',
+ ],
+ 'include_dirs': [
+ '<(webkit_top)/JavaScriptCore',
+ '<(chromium_src_dir)',
+ ],
+ 'sources': [
+ '../chromium/ImageDiff.cpp',
+ ],
+ },
+ ], # targets
+
+ 'conditions': [
+ ['OS=="mac"', {
+ 'targets': [
+ {
+ 'target_name': 'LayoutTestHelper',
+ 'type': 'executable',
+ 'sources': ['../chromium/LayoutTestHelper.mm'],
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/AppKit.framework',
+ ],
+ },
+ },
+ ],
+ }],
+ ], # conditions
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/WebKitTools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj b/WebKitTools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj
index 06f0599..3adfaf2 100644
--- a/WebKitTools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj
+++ b/WebKitTools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj
@@ -35,6 +35,8 @@
1AC6C84A0D07638600CD3161 /* PluginObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AC6C7800D07589B00CD3161 /* PluginObject.cpp */; };
1AC6C84B0D07638600CD3161 /* TestObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AC6C7810D07589B00CD3161 /* TestObject.cpp */; };
23BCB8900EA57623003C6289 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 23BCB88F0EA57623003C6289 /* OpenGL.framework */; };
+ 3713EDE2115BE19300705720 /* ColorBits-A.png in Copy Font Files */ = {isa = PBXBuildFile; fileRef = 3713EDDF115BE16F00705720 /* ColorBits-A.png */; };
+ 3713EDE3115BE19300705720 /* ColorBits.ttf in Copy Font Files */ = {isa = PBXBuildFile; fileRef = 3713EDE0115BE16F00705720 /* ColorBits.ttf */; };
5185F6B210714E07007AA393 /* HistoryDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5185F69F10714A57007AA393 /* HistoryDelegate.mm */; };
5185F6B310714E12007AA393 /* HistoryDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 5185F69E10714A57007AA393 /* HistoryDelegate.h */; };
5DB9AC970F722C3600684641 /* AHEM____.TTF in Copy Font Files */ = {isa = PBXBuildFile; fileRef = AA7F10C20CB3C1030003BDC9 /* AHEM____.TTF */; };
@@ -156,6 +158,8 @@
dstSubfolderSpec = 7;
files = (
5DB9AC970F722C3600684641 /* AHEM____.TTF in Copy Font Files */,
+ 3713EDE2115BE19300705720 /* ColorBits-A.png in Copy Font Files */,
+ 3713EDE3115BE19300705720 /* ColorBits.ttf in Copy Font Files */,
5DB9AC980F722C3600684641 /* WebKitWeightWatcher100.ttf in Copy Font Files */,
5DB9AC990F722C3600684641 /* WebKitWeightWatcher200.ttf in Copy Font Files */,
5DB9AC9A0F722C3600684641 /* WebKitWeightWatcher300.ttf in Copy Font Files */,
@@ -182,6 +186,8 @@
1AC6C7810D07589B00CD3161 /* TestObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TestObject.cpp; sourceTree = "<group>"; };
23BCB88F0EA57623003C6289 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = /System/Library/Frameworks/OpenGL.framework; sourceTree = "<absolute>"; };
32A70AAB03705E1F00C91783 /* DumpRenderTreePrefix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DumpRenderTreePrefix.h; sourceTree = "<group>"; };
+ 3713EDDF115BE16F00705720 /* ColorBits-A.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "ColorBits-A.png"; path = "fonts/ColorBits-A.png"; sourceTree = "<group>"; };
+ 3713EDE0115BE16F00705720 /* ColorBits.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = ColorBits.ttf; path = fonts/ColorBits.ttf; sourceTree = "<group>"; };
375F09710DAC3CB600C8B4E5 /* WebKitWeightWatcher100.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = WebKitWeightWatcher100.ttf; path = fonts/WebKitWeightWatcher100.ttf; sourceTree = "<group>"; };
375F09720DAC3CB600C8B4E5 /* WebKitWeightWatcher200.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = WebKitWeightWatcher200.ttf; path = fonts/WebKitWeightWatcher200.ttf; sourceTree = "<group>"; };
375F09730DAC3CB600C8B4E5 /* WebKitWeightWatcher300.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = WebKitWeightWatcher300.ttf; path = fonts/WebKitWeightWatcher300.ttf; sourceTree = "<group>"; };
@@ -417,6 +423,8 @@
9345229B0BD12B2C0086EDA0 /* Resources */ = {
isa = PBXGroup;
children = (
+ 3713EDDF115BE16F00705720 /* ColorBits-A.png */,
+ 3713EDE0115BE16F00705720 /* ColorBits.ttf */,
AA7F10C20CB3C1030003BDC9 /* AHEM____.TTF */,
375F09710DAC3CB600C8B4E5 /* WebKitWeightWatcher100.ttf */,
375F09720DAC3CB600C8B4E5 /* WebKitWeightWatcher200.ttf */,
diff --git a/WebKitTools/DumpRenderTree/LayoutTestController.cpp b/WebKitTools/DumpRenderTree/LayoutTestController.cpp
index f528b31..a736160 100644
--- a/WebKitTools/DumpRenderTree/LayoutTestController.cpp
+++ b/WebKitTools/DumpRenderTree/LayoutTestController.cpp
@@ -74,6 +74,7 @@ LayoutTestController::LayoutTestController(const std::string& testPathOrURL, con
, m_globalFlag(false)
, m_isGeolocationPermissionSet(false)
, m_geolocationPermission(false)
+ , m_handlesAuthenticationChallenges(false)
, m_testPathOrURL(testPathOrURL)
, m_expectedPixelHash(expectedPixelHash)
{
@@ -280,6 +281,14 @@ static JSValueRef addDisallowedURLCallback(JSContextRef context, JSObjectRef fun
return JSValueMakeUndefined(context);
}
+static JSValueRef callShouldCloseOnWebViewCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+
+ return JSValueMakeBoolean(context, controller->callShouldCloseOnWebView());
+}
+
static JSValueRef clearAllDatabasesCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
// Has mac & windows implementation
@@ -456,6 +465,23 @@ static JSValueRef keepWebHistoryCallback(JSContextRef context, JSObjectRef funct
return JSValueMakeUndefined(context);
}
+static JSValueRef computedStyleIncludingVisitedInfoCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount != 1)
+ return JSValueMakeUndefined(context);
+
+ // Has mac implementation
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ return controller->computedStyleIncludingVisitedInfo(context, arguments[0]);
+}
+
+static JSValueRef layerTreeAsTextCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ return JSValueMakeString(context, controller->layerTreeAsText().get());
+}
+
static JSValueRef notifyDoneCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
// Has mac & windows implementation
@@ -914,14 +940,26 @@ static JSValueRef setXSSAuditorEnabledCallback(JSContextRef context, JSObjectRef
return JSValueMakeUndefined(context);
}
-static JSValueRef setFrameSetFlatteningEnabledCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+static JSValueRef setSpatialNavigationEnabledCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setSpatialNavigationEnabled(JSValueToBoolean(context, arguments[0]));
+
+ return JSValueMakeUndefined(context);
+}
+
+
+static JSValueRef setFrameFlatteningEnabledCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
// Has mac & windows implementation
if (argumentCount < 1)
return JSValueMakeUndefined(context);
LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
- controller->setFrameSetFlatteningEnabled(JSValueToBoolean(context, arguments[0]));
+ controller->setFrameFlatteningEnabled(JSValueToBoolean(context, arguments[0]));
return JSValueMakeUndefined(context);
}
@@ -1011,6 +1049,25 @@ static JSValueRef setUserStyleSheetLocationCallback(JSContextRef context, JSObje
return JSValueMakeUndefined(context);
}
+static JSValueRef setWillSendRequestClearHeaderCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> header(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+
+ size_t maxLength = JSStringGetMaximumUTF8CStringSize(header.get());
+ char* headerBuffer = new char[maxLength + 1];
+ JSStringGetUTF8CString(header.get(), headerBuffer, maxLength + 1);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setWillSendRequestClearHeader(headerBuffer);
+
+ return JSValueMakeUndefined(context);
+}
+
static JSValueRef setWillSendRequestReturnsNullCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
// Has cross-platform implementation
@@ -1217,7 +1274,25 @@ static JSValueRef waitForPolicyDelegateCallback(JSContextRef context, JSObjectRe
return JSValueMakeUndefined(context);
}
-static JSValueRef whiteListAccessFromOriginCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+static JSValueRef addOriginAccessWhitelistEntryCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount != 4)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> sourceOrigin(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+ JSRetainPtr<JSStringRef> destinationProtocol(Adopt, JSValueToStringCopy(context, arguments[1], exception));
+ ASSERT(!*exception);
+ JSRetainPtr<JSStringRef> destinationHost(Adopt, JSValueToStringCopy(context, arguments[2], exception));
+ ASSERT(!*exception);
+ bool allowDestinationSubdomains = JSValueToBoolean(context, arguments[3]);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->addOriginAccessWhitelistEntry(sourceOrigin.get(), destinationProtocol.get(), destinationHost.get(), allowDestinationSubdomains);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef removeOriginAccessWhitelistEntryCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
if (argumentCount != 4)
return JSValueMakeUndefined(context);
@@ -1231,7 +1306,22 @@ static JSValueRef whiteListAccessFromOriginCallback(JSContextRef context, JSObje
bool allowDestinationSubdomains = JSValueToBoolean(context, arguments[3]);
LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
- controller->whiteListAccessFromOrigin(sourceOrigin.get(), destinationProtocol.get(), destinationHost.get(), allowDestinationSubdomains);
+ controller->removeOriginAccessWhitelistEntry(sourceOrigin.get(), destinationProtocol.get(), destinationHost.get(), allowDestinationSubdomains);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setScrollbarPolicyCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount != 2)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> orientation(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+ JSRetainPtr<JSStringRef> policy(Adopt, JSValueToStringCopy(context, arguments[1], exception));
+ ASSERT(!*exception);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setScrollbarPolicy(orientation.get(), policy.get());
return JSValueMakeUndefined(context);
}
@@ -1278,6 +1368,51 @@ static JSValueRef apiTestNewWindowDataLoadBaseURLCallback(JSContextRef context,
return JSValueMakeUndefined(context);
}
+static JSValueRef apiTestGoToCurrentBackForwardItemCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->apiTestGoToCurrentBackForwardItem();
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setWebViewEditableCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has Mac implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setWebViewEditable(JSValueToBoolean(context, arguments[0]));
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef markerTextForListItemCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+ return JSValueMakeString(context, controller->markerTextForListItem(context, arguments[0]).get());
+}
+
+static JSValueRef authenticateSessionCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // authenticateSession(url, username, password)
+ if (argumentCount != 3)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> url(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+ JSRetainPtr<JSStringRef> username(Adopt, JSValueToStringCopy(context, arguments[1], exception));
+ ASSERT(!*exception);
+ JSRetainPtr<JSStringRef> password(Adopt, JSValueToStringCopy(context, arguments[2], exception));
+ ASSERT(!*exception);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->authenticateSession(url.get(), username.get(), password.get());
+ return JSValueMakeUndefined(context);
+}
+
// Static Values
static JSValueRef getGlobalFlagCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
@@ -1355,10 +1490,13 @@ JSStaticFunction* LayoutTestController::staticFunctions()
{ "addUserScript", addUserScriptCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "addUserStyleSheet", addUserStyleSheetCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "apiTestNewWindowDataLoadBaseURL", apiTestNewWindowDataLoadBaseURLCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "apiTestGoToCurrentBackForwardItem", apiTestGoToCurrentBackForwardItemCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "callShouldCloseOnWebView", callShouldCloseOnWebViewCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "clearAllDatabases", clearAllDatabasesCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "clearBackForwardList", clearBackForwardListCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "clearPersistentUserStyleSheet", clearPersistentUserStyleSheetCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "closeWebInspector", closeWebInspectorCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "computedStyleIncludingVisitedInfo", computedStyleIncludingVisitedInfoCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "decodeHostName", decodeHostNameCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "disableImageLoading", disableImageLoadingCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "dispatchPendingLoadRequests", dispatchPendingLoadRequestsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
@@ -1387,7 +1525,9 @@ JSStaticFunction* LayoutTestController::staticFunctions()
{ "grantDesktopNotificationPermission", grantDesktopNotificationPermissionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "isCommandEnabled", isCommandEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "keepWebHistory", keepWebHistoryCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "layerTreeAsText", layerTreeAsTextCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "numberOfPages", numberOfPagesCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "markerTextForListItem", markerTextForListItemCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "notifyDone", notifyDoneCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "numberOfActiveAnimations", numberOfActiveAnimationsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "overridePreference", overridePreferenceCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
@@ -1404,6 +1544,7 @@ JSStaticFunction* LayoutTestController::staticFunctions()
{ "queueNonLoadingScript", queueNonLoadingScriptCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "queueReload", queueReloadCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "removeAllVisitedLinks", removeAllVisitedLinksCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "removeOriginAccessWhitelistEntry", removeOriginAccessWhitelistEntryCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "repaintSweepHorizontally", repaintSweepHorizontallyCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setAcceptsEditing", setAcceptsEditingCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setAllowUniversalAccessFromFileURLs", setAllowUniversalAccessFromFileURLsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
@@ -1413,45 +1554,50 @@ JSStaticFunction* LayoutTestController::staticFunctions()
{ "setAuthenticationPassword", setAuthenticationPasswordCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setAuthenticationUsername", setAuthenticationUsernameCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setAuthorAndUserStylesEnabled", setAuthorAndUserStylesEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setCacheModel", setCacheModelCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setCallCloseOnWebViews", setCallCloseOnWebViewsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setCanOpenWindows", setCanOpenWindowsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "setCacheModel", setCacheModelCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setCloseRemainingWindowsWhenComplete", setCloseRemainingWindowsWhenCompleteCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setCustomPolicyDelegate", setCustomPolicyDelegateCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setDatabaseQuota", setDatabaseQuotaCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setDomainRelaxationForbiddenForURLScheme", setDomainRelaxationForbiddenForURLSchemeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setFrameFlatteningEnabled", setFrameFlatteningEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setGeolocationPermission", setGeolocationPermissionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setHandlesAuthenticationChallenges", setHandlesAuthenticationChallengesCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "setPOSIXLocale", setPOSIXLocaleCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setIconDatabaseEnabled", setIconDatabaseEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setJavaScriptProfilingEnabled", setJavaScriptProfilingEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setMainFrameIsFirstResponder", setMainFrameIsFirstResponderCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "setMockGeolocationPosition", setMockGeolocationPositionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setMockGeolocationError", setMockGeolocationErrorCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setMockGeolocationPosition", setMockGeolocationPositionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setNewWindowsCopyBackForwardList", setNewWindowsCopyBackForwardListCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setPOSIXLocale", setPOSIXLocaleCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setPersistentUserStyleSheetLocation", setPersistentUserStyleSheetLocationCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setPopupBlockingEnabled", setPopupBlockingEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setPrivateBrowsingEnabled", setPrivateBrowsingEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "setXSSAuditorEnabled", setXSSAuditorEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "setFrameSetFlatteningEnabled", setFrameSetFlatteningEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setSelectTrailingWhitespaceEnabled", setSelectTrailingWhitespaceEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setSmartInsertDeleteEnabled", setSmartInsertDeleteEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setSpatialNavigationEnabled", setSpatialNavigationEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setStopProvisionalFrameLoads", setStopProvisionalFrameLoadsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setTabKeyCyclesThroughElements", setTabKeyCyclesThroughElementsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setTimelineProfilingEnabled", setTimelineProfilingEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setUseDashboardCompatibilityMode", setUseDashboardCompatibilityModeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setUserStyleSheetEnabled", setUserStyleSheetEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setUserStyleSheetLocation", setUserStyleSheetLocationCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setWebViewEditable", setWebViewEditableCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setWillSendRequestClearHeader", setWillSendRequestClearHeaderCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setWillSendRequestReturnsNull", setWillSendRequestReturnsNullCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setWillSendRequestReturnsNullOnRedirect", setWillSendRequestReturnsNullOnRedirectCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setWindowIsKey", setWindowIsKeyCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setXSSAuditorEnabled", setXSSAuditorEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "showWebInspector", showWebInspectorCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "testOnscreen", testOnscreenCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "testRepaint", testRepaintCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "waitForPolicyDelegate", waitForPolicyDelegateCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "waitUntilDone", waitUntilDoneCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "windowCount", windowCountCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "whiteListAccessFromOrigin", whiteListAccessFromOriginCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "addOriginAccessWhitelistEntry", addOriginAccessWhitelistEntryCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setScrollbarPolicy", setScrollbarPolicyCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "authenticateSession", authenticateSessionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ 0, 0, 0 }
};
diff --git a/WebKitTools/DumpRenderTree/LayoutTestController.h b/WebKitTools/DumpRenderTree/LayoutTestController.h
index 3add32a..198a9f3 100644
--- a/WebKitTools/DumpRenderTree/LayoutTestController.h
+++ b/WebKitTools/DumpRenderTree/LayoutTestController.h
@@ -31,9 +31,10 @@
#include <JavaScriptCore/JSObjectRef.h>
#include <JavaScriptCore/JSRetainPtr.h>
-#include <wtf/RefCounted.h>
+#include <set>
#include <string>
#include <vector>
+#include <wtf/RefCounted.h>
class LayoutTestController : public RefCounted<LayoutTestController> {
public:
@@ -46,6 +47,7 @@ public:
void clearAllDatabases();
void clearBackForwardList();
void clearPersistentUserStyleSheet();
+ bool callShouldCloseOnWebView();
JSStringRef copyDecodedHostName(JSStringRef name);
JSStringRef copyEncodedHostName(JSStringRef name);
void disableImageLoading();
@@ -55,6 +57,7 @@ public:
JSRetainPtr<JSStringRef> counterValueForElementById(JSStringRef id);
bool isCommandEnabled(JSStringRef name);
void keepWebHistory();
+ JSValueRef computedStyleIncludingVisitedInfo(JSContextRef, JSValueRef);
void notifyDone();
int numberOfPages(float pageWidthInPixels, float pageHeightInPixels);
void overridePreference(JSStringRef key, JSStringRef value);
@@ -91,7 +94,9 @@ public:
void setUserStyleSheetEnabled(bool flag);
void setUserStyleSheetLocation(JSStringRef path);
void setXSSAuditorEnabled(bool flag);
- void setFrameSetFlatteningEnabled(bool enable);
+ void setFrameFlatteningEnabled(bool enable);
+ void setSpatialNavigationEnabled(bool enable);
+ void setScrollbarPolicy(JSStringRef orientation, JSStringRef policy);
void waitForPolicyDelegate();
size_t webHistoryItemCount();
@@ -185,6 +190,9 @@ public:
void setWaitToDump(bool waitToDump);
void waitToDumpWatchdogTimerFired();
+ const std::set<std::string>& willSendRequestClearHeaders() const { return m_willSendRequestClearHeaders; }
+ void setWillSendRequestClearHeader(std::string header) { m_willSendRequestClearHeaders.insert(header); }
+
bool willSendRequestReturnsNull() const { return m_willSendRequestReturnsNull; }
void setWillSendRequestReturnsNull(bool returnsNull) { m_willSendRequestReturnsNull = returnsNull; }
@@ -217,7 +225,8 @@ public:
bool sampleSVGAnimationForElementAtTime(JSStringRef animationId, double time, JSStringRef elementId);
unsigned numberOfActiveAnimations() const;
- void whiteListAccessFromOrigin(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains);
+ void addOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains);
+ void removeOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains);
void addUserScript(JSStringRef source, bool runAtStart);
void addUserStyleSheet(JSStringRef source);
@@ -226,6 +235,7 @@ public:
bool isGeolocationPermissionSet() const { return m_isGeolocationPermissionSet; }
bool geolocationPermission() const { return m_geolocationPermission; }
+ void setDeveloperExtrasEnabled(bool);
void showWebInspector();
void closeWebInspector();
void setTimelineProfilingEnabled(bool enabled);
@@ -233,10 +243,20 @@ public:
void evaluateScriptInIsolatedWorld(unsigned worldId, JSObjectRef globalObject, JSStringRef script);
void setPOSIXLocale(JSStringRef locale);
-
+
+ void setWebViewEditable(bool);
+
// The following API test functions should probably be moved to platform-specific
// unit tests outside of DRT once they exist.
void apiTestNewWindowDataLoadBaseURL(JSStringRef utf8Data, JSStringRef baseURL);
+ void apiTestGoToCurrentBackForwardItem();
+
+ // Simulate a request an embedding application could make, populating per-session credential storage.
+ void authenticateSession(JSStringRef url, JSStringRef username, JSStringRef password);
+
+ JSRetainPtr<JSStringRef> layerTreeAsText() const;
+
+ JSRetainPtr<JSStringRef> markerTextForListItem(JSContextRef context, JSValueRef nodeObject) const;
static const unsigned maxViewWidth;
static const unsigned maxViewHeight;
@@ -282,6 +302,8 @@ private:
std::string m_authenticationPassword;
std::string m_testPathOrURL;
std::string m_expectedPixelHash; // empty string if no hash
+
+ std::set<std::string> m_willSendRequestClearHeaders;
// origins which have been granted desktop notification access
std::vector<JSStringRef> m_desktopNotificationAllowedOrigins;
diff --git a/WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp b/WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp
index 8e278f5..7d388d0 100644
--- a/WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp
+++ b/WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
* Copyright (C) 2009 Holger Hans Peter Freyther
+ * Copyright (C) 2010 Collabora Ltd.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -134,6 +135,7 @@ enum {
ID_PROPERTY_PRIVATE_BROWSING_ENABLED,
ID_PROPERTY_CACHED_PRIVATE_BROWSING_ENABLED,
ID_PROPERTY_THROW_EXCEPTION_PROPERTY,
+ ID_LAST_SET_WINDOW_ARGUMENTS,
NUM_PROPERTY_IDENTIFIERS
};
@@ -147,7 +149,8 @@ static const NPUTF8 *pluginPropertyIdentifierNames[NUM_PROPERTY_IDENTIFIERS] = {
"returnErrorFromNewStream",
"privateBrowsingEnabled",
"cachedPrivateBrowsingEnabled",
- "testThrowExceptionProperty"
+ "testThrowExceptionProperty",
+ "lastSetWindowArguments"
};
enum {
@@ -181,6 +184,8 @@ enum {
ID_GET_AND_FORGET_REMEMBERED_OBJECT,
ID_REF_COUNT,
ID_SET_STATUS,
+ ID_RESIZE_TO,
+ ID_NORMALIZE,
NUM_METHOD_IDENTIFIERS
};
@@ -215,7 +220,9 @@ static const NPUTF8 *pluginMethodIdentifierNames[NUM_METHOD_IDENTIFIERS] = {
"getRememberedObject",
"getAndForgetRememberedObject",
"refCount",
- "setStatus"
+ "setStatus",
+ "resizeTo",
+ "normalize"
};
static NPUTF8* createCStringFromNPVariant(const NPVariant* variant)
@@ -283,7 +290,15 @@ static bool pluginGetProperty(NPObject* obj, NPIdentifier name, NPVariant* resul
} else if (name == pluginPropertyIdentifiers[ID_PROPERTY_THROW_EXCEPTION_PROPERTY]) {
browser->setexception(obj, "plugin object testThrowExceptionProperty SUCCESS");
return true;
+ } else if (name == pluginPropertyIdentifiers[ID_LAST_SET_WINDOW_ARGUMENTS]) {
+ char* buf = static_cast<char*>(browser->memalloc(256));
+ snprintf(buf, 256, "x: %d, y: %d, width: %u, height: %u, clipRect: (%u, %u, %u, %u)", (int)plugin->lastWindow.x, (int)plugin->lastWindow.y, (unsigned)plugin->lastWindow.width, (unsigned)plugin->lastWindow.height,
+ plugin->lastWindow.clipRect.left, plugin->lastWindow.clipRect.top, plugin->lastWindow.clipRect.right - plugin->lastWindow.clipRect.left, plugin->lastWindow.clipRect.bottom - plugin->lastWindow.clipRect.top);
+
+ STRINGZ_TO_NPVARIANT(buf, *result);
+ return true;
}
+
return false;
}
@@ -405,8 +420,8 @@ static bool testCallback(PluginObject* obj, const NPVariant* args, uint32_t argC
free(callbackString);
NPVariant browserResult;
- browser->invoke(obj->npp, windowScriptObject, callbackIdentifier, 0, 0, &browserResult);
- browser->releasevariantvalue(&browserResult);
+ if (browser->invoke(obj->npp, windowScriptObject, callbackIdentifier, 0, 0, &browserResult))
+ browser->releasevariantvalue(&browserResult);
browser->releaseobject(windowScriptObject);
@@ -519,8 +534,8 @@ static bool testEnumerate(PluginObject* obj, const NPVariant* args, uint32_t arg
NPVariant args[1];
STRINGZ_TO_NPVARIANT(string, args[0]);
NPVariant browserResult;
- browser->invoke(obj->npp, outArray, pushIdentifier, args, 1, &browserResult);
- browser->releasevariantvalue(&browserResult);
+ if (browser->invoke(obj->npp, outArray, pushIdentifier, args, 1, &browserResult))
+ browser->releasevariantvalue(&browserResult);
browser->memfree(string);
}
@@ -710,8 +725,10 @@ bool testDocumentOpen(NPP npp)
NPVariant docVariant;
browser->getproperty(npp, windowObject, documentId, &docVariant);
- if (docVariant.type != NPVariantType_Object)
+ if (docVariant.type != NPVariantType_Object) {
+ browser->releaseobject(windowObject);
return false;
+ }
NPObject *documentObject = NPVARIANT_TO_OBJECT(docVariant);
@@ -720,17 +737,25 @@ bool testDocumentOpen(NPP npp)
STRINGZ_TO_NPVARIANT("_blank", openArgs[1]);
NPVariant result;
- browser->invoke(npp, documentObject, openId, openArgs, 2, &result);
+ if (!browser->invoke(npp, documentObject, openId, openArgs, 2, &result)) {
+ browser->releaseobject(windowObject);
+ browser->releaseobject(documentObject);
+ return false;
+ }
+
browser->releaseobject(documentObject);
- if (result.type == NPVariantType_Object) {
- pluginLogWithWindowObjectVariableArgs(windowObject, npp, "DOCUMENT OPEN SUCCESS");
- notifyTestCompletion(npp, result.value.objectValue);
- browser->releaseobject(result.value.objectValue);
- return true;
+ if (result.type != NPVariantType_Object) {
+ browser->releaseobject(windowObject);
+ browser->releasevariantvalue(&result);
+ return false;
}
- return false;
+ pluginLogWithWindowObjectVariableArgs(windowObject, npp, "DOCUMENT OPEN SUCCESS");
+ notifyTestCompletion(npp, result.value.objectValue);
+ browser->releaseobject(result.value.objectValue);
+ browser->releaseobject(windowObject);
+ return true;
}
bool testWindowOpen(NPP npp)
@@ -747,14 +772,22 @@ bool testWindowOpen(NPP npp)
STRINGZ_TO_NPVARIANT("_blank", openArgs[1]);
NPVariant result;
- browser->invoke(npp, windowObject, openId, openArgs, 2, &result);
- if (result.type == NPVariantType_Object) {
- pluginLogWithWindowObjectVariableArgs(windowObject, npp, "WINDOW OPEN SUCCESS");
- notifyTestCompletion(npp, result.value.objectValue);
- browser->releaseobject(result.value.objectValue);
- return true;
+ if (!browser->invoke(npp, windowObject, openId, openArgs, 2, &result)) {
+ browser->releaseobject(windowObject);
+ return false;
}
- return false;
+
+ if (result.type != NPVariantType_Object) {
+ browser->releaseobject(windowObject);
+ browser->releasevariantvalue(&result);
+ return false;
+ }
+
+ pluginLogWithWindowObjectVariableArgs(windowObject, npp, "WINDOW OPEN SUCCESS");
+ notifyTestCompletion(npp, result.value.objectValue);
+ browser->releaseobject(result.value.objectValue);
+ browser->releaseobject(windowObject);
+ return true;
}
static bool testSetStatus(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
@@ -771,7 +804,40 @@ static bool testSetStatus(PluginObject* obj, const NPVariant* args, uint32_t arg
return true;
}
-static NPObject* rememberedObject;
+static bool testResizeTo(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
+{
+ VOID_TO_NPVARIANT(*result);
+
+ NPObject* windowObject;
+ if (NPERR_NO_ERROR != browser->getvalue(obj->npp, NPNVWindowNPObject, &windowObject))
+ return false;
+
+ NPVariant callResult;
+ if (browser->invoke(obj->npp, windowObject, browser->getstringidentifier("resizePlugin"), args, argCount, &callResult))
+ browser->releasevariantvalue(&callResult);
+
+ // Force layout.
+ if (browser->getproperty(obj->npp, windowObject, browser->getstringidentifier("pageYOffset"), &callResult))
+ browser->releasevariantvalue(&callResult);
+
+ return true;
+}
+
+static bool normalizeOverride(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
+{
+ VOID_TO_NPVARIANT(*result);
+
+ NPObject* windowObject;
+ if (NPERR_NO_ERROR != browser->getvalue(obj->npp, NPNVWindowNPObject, &windowObject))
+ return false;
+
+ NPVariant callResult;
+ if (browser->invoke(obj->npp, windowObject, browser->getstringidentifier("pluginCallback"), args, argCount, &callResult))
+ browser->releasevariantvalue(&callResult);
+
+ return true;
+}
+
static bool pluginInvoke(NPObject* header, NPIdentifier name, const NPVariant* args, uint32_t argCount, NPVariant* result)
{
@@ -834,21 +900,21 @@ static bool pluginInvoke(NPObject* header, NPIdentifier name, const NPVariant* a
browser->setproperty(plugin->npp, NPVARIANT_TO_OBJECT(args[0]), stringVariantToIdentifier(args[1]), &args[2]);
return true;
} else if (name == pluginMethodIdentifiers[ID_REMEMBER]) {
- if (rememberedObject)
- browser->releaseobject(rememberedObject);
- rememberedObject = NPVARIANT_TO_OBJECT(args[0]);
- browser->retainobject(rememberedObject);
+ if (plugin->rememberedObject)
+ browser->releaseobject(plugin->rememberedObject);
+ plugin->rememberedObject = NPVARIANT_TO_OBJECT(args[0]);
+ browser->retainobject(plugin->rememberedObject);
VOID_TO_NPVARIANT(*result);
return true;
} else if (name == pluginMethodIdentifiers[ID_GET_REMEMBERED_OBJECT]) {
- assert(rememberedObject);
- browser->retainobject(rememberedObject);
- OBJECT_TO_NPVARIANT(rememberedObject, *result);
+ assert(plugin->rememberedObject);
+ browser->retainobject(plugin->rememberedObject);
+ OBJECT_TO_NPVARIANT(plugin->rememberedObject, *result);
return true;
} else if (name == pluginMethodIdentifiers[ID_GET_AND_FORGET_REMEMBERED_OBJECT]) {
- assert(rememberedObject);
- OBJECT_TO_NPVARIANT(rememberedObject, *result);
- rememberedObject = 0;
+ assert(plugin->rememberedObject);
+ OBJECT_TO_NPVARIANT(plugin->rememberedObject, *result);
+ plugin->rememberedObject = 0;
return true;
} else if (name == pluginMethodIdentifiers[ID_REF_COUNT]) {
uint32_t refCount = NPVARIANT_TO_OBJECT(args[0])->referenceCount;
@@ -856,6 +922,10 @@ static bool pluginInvoke(NPObject* header, NPIdentifier name, const NPVariant* a
return true;
} else if (name == pluginMethodIdentifiers[ID_SET_STATUS])
return testSetStatus(plugin, args, argCount, result);
+ else if (name == pluginMethodIdentifiers[ID_RESIZE_TO])
+ return testResizeTo(plugin, args, argCount, result);
+ else if (name == pluginMethodIdentifiers[ID_NORMALIZE])
+ return normalizeOverride(plugin, args, argCount, result);
return false;
}
@@ -870,6 +940,7 @@ static void pluginInvalidate(NPObject* header)
{
PluginObject* plugin = reinterpret_cast<PluginObject*>(header);
plugin->testObject = 0;
+ plugin->rememberedObject = 0;
}
static NPObject *pluginAllocate(NPP npp, NPClass *theClass)
@@ -883,11 +954,13 @@ static NPObject *pluginAllocate(NPP npp, NPClass *theClass)
newInstance->npp = npp;
newInstance->testObject = browser->createobject(npp, getTestClass());
+ newInstance->rememberedObject = 0;
newInstance->eventLogging = FALSE;
newInstance->onStreamLoad = 0;
newInstance->onStreamDestroy = 0;
newInstance->onDestroy = 0;
newInstance->onURLNotify = 0;
+ newInstance->onSetWindow = 0;
newInstance->logDestroy = FALSE;
newInstance->logSetWindow = FALSE;
newInstance->returnErrorFromNewStream = FALSE;
@@ -900,6 +973,7 @@ static NPObject *pluginAllocate(NPP npp, NPClass *theClass)
newInstance->testDocumentOpenInDestroyStream = FALSE;
newInstance->testWindowOpen = FALSE;
+ newInstance->testKeyboardFocusForPlugins = FALSE;
return (NPObject*)newInstance;
}
@@ -909,6 +983,8 @@ static void pluginDeallocate(NPObject* header)
PluginObject* plugin = reinterpret_cast<PluginObject*>(header);
if (plugin->testObject)
browser->releaseobject(plugin->testObject);
+ if (plugin->rememberedObject)
+ browser->releaseobject(plugin->rememberedObject);
free(plugin->firstUrl);
free(plugin->firstHeaders);
@@ -947,8 +1023,8 @@ void handleCallback(PluginObject* object, const char *url, NPReason reason, void
NULL_TO_NPVARIANT(args[1]);
NPVariant browserResult;
- browser->invoke(object->npp, windowScriptObject, callbackIdentifier, args, 2, &browserResult);
- browser->releasevariantvalue(&browserResult);
+ if (browser->invoke(object->npp, windowScriptObject, callbackIdentifier, args, 2, &browserResult))
+ browser->releasevariantvalue(&browserResult);
free(strHdr);
}
diff --git a/WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.h b/WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.h
index 157a1d2..2ae4dbf 100644
--- a/WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.h
+++ b/WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.h
@@ -37,13 +37,16 @@ typedef struct {
NPBool returnErrorFromNewStream;
NPBool cachedPrivateBrowsingMode;
NPObject* testObject;
+ NPObject* rememberedObject;
NPStream* stream;
NPBool testDocumentOpenInDestroyStream;
NPBool testWindowOpen;
+ NPBool testKeyboardFocusForPlugins;
char* onStreamLoad;
char* onStreamDestroy;
char* onDestroy;
char* onURLNotify;
+ char* onSetWindow;
char* firstUrl;
char* firstHeaders;
char* lastUrl;
@@ -51,6 +54,7 @@ typedef struct {
#ifdef XP_MACOSX
NPEventModel eventModel;
#endif
+ NPWindow lastWindow;
} PluginObject;
extern NPClass *getPluginClass(void);
diff --git a/WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/main.cpp b/WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/main.cpp
index 8ef228a..a552774 100644
--- a/WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/main.cpp
+++ b/WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/main.cpp
@@ -93,6 +93,8 @@ NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, ch
else if (strcasecmp(argn[i], "src") == 0 &&
strcasecmp(argv[i], "data:application/x-webkit-test-netscape,returnerrorfromnewstream") == 0)
obj->returnErrorFromNewStream = TRUE;
+ else if (strcasecmp(argn[i], "onSetWindow") == 0 && !obj->onSetWindow)
+ obj->onSetWindow = strdup(argv[i]);
else if (strcasecmp(argn[i], "logfirstsetwindow") == 0)
obj->logSetWindow = TRUE;
else if (strcasecmp(argn[i], "testnpruntime") == 0)
@@ -111,6 +113,8 @@ NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, ch
obj->testDocumentOpenInDestroyStream = TRUE;
else if (strcasecmp(argn[i], "testwindowopen") == 0)
obj->testWindowOpen = TRUE;
+ else if (strcasecmp(argn[i], "src") == 0 && strstr(argv[i], "plugin-document-has-focus.pl"))
+ obj->testKeyboardFocusForPlugins = TRUE;
}
#ifndef NP_NO_CARBON
@@ -160,6 +164,9 @@ NPError NPP_Destroy(NPP instance, NPSavedData **save)
if (obj->onURLNotify)
free(obj->onURLNotify);
+
+ if (obj->onSetWindow)
+ free(obj->onSetWindow);
if (obj->logDestroy)
pluginLog(instance, "NPP_Destroy");
@@ -174,15 +181,25 @@ NPError NPP_SetWindow(NPP instance, NPWindow *window)
PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
if (obj) {
+ obj->lastWindow = *window;
+
if (obj->logSetWindow) {
pluginLog(instance, "NPP_SetWindow: %d %d", (int)window->width, (int)window->height);
- obj->logSetWindow = false;
+ obj->logSetWindow = FALSE;
}
+ if (obj->onSetWindow)
+ executeScript(obj, obj->onSetWindow);
+
if (obj->testWindowOpen) {
testWindowOpen(instance);
obj->testWindowOpen = FALSE;
}
+
+ if (obj->testKeyboardFocusForPlugins) {
+ obj->eventLogging = true;
+ executeScript(obj, "eventSender.keyDown('A');");
+ }
}
return NPERR_NO_ERROR;
@@ -275,6 +292,11 @@ static int16_t handleEventCarbon(NPP instance, PluginObject* obj, EventRecord* e
break;
case keyUp:
pluginLog(instance, "keyUp '%c'", (char)(event->message & 0xFF));
+ if (obj->testKeyboardFocusForPlugins) {
+ obj->eventLogging = false;
+ obj->testKeyboardFocusForPlugins = FALSE;
+ executeScript(obj, "layoutTestController.notifyDone();");
+ }
break;
case autoKey:
pluginLog(instance, "autoKey '%c'", (char)(event->message & 0xFF));
@@ -338,7 +360,21 @@ static int16_t handleEventCocoa(NPP instance, PluginObject* obj, NPCocoaEvent* e
return 1;
case NPCocoaEventKeyDown:
+ if (event->data.key.characters)
+ pluginLog(instance, "keyDown '%c'", CFStringGetCharacterAtIndex(reinterpret_cast<CFStringRef>(event->data.key.characters), 0));
+ return 1;
+
case NPCocoaEventKeyUp:
+ if (event->data.key.characters) {
+ pluginLog(instance, "keyUp '%c'", CFStringGetCharacterAtIndex(reinterpret_cast<CFStringRef>(event->data.key.characters), 0));
+ if (obj->testKeyboardFocusForPlugins) {
+ obj->eventLogging = false;
+ obj->testKeyboardFocusForPlugins = FALSE;
+ executeScript(obj, "layoutTestController.notifyDone();");
+ }
+ }
+ return 1;
+
case NPCocoaEventFlagsChanged:
return 1;
diff --git a/WebKitTools/DumpRenderTree/chromium/AccessibilityController.cpp b/WebKitTools/DumpRenderTree/chromium/AccessibilityController.cpp
new file mode 100644
index 0000000..afe850c
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/AccessibilityController.cpp
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2010 Google 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 "config.h"
+#include "AccessibilityController.h"
+
+#include "TestShell.h"
+#include "public/WebAccessibilityCache.h"
+#include "public/WebAccessibilityObject.h"
+#include "public/WebFrame.h"
+#include "public/WebString.h"
+#include "public/WebView.h"
+
+using namespace WebKit;
+
+AccessibilityController::AccessibilityController(TestShell* shell)
+ : m_shell(shell)
+{
+
+ bindMethod("logFocusEvents",
+ &AccessibilityController::logFocusEventsCallback);
+ bindMethod("logScrollingStartEvents",
+ &AccessibilityController::logScrollingStartEventsCallback);
+
+ bindProperty("focusedElement",
+ &AccessibilityController::focusedElementGetterCallback);
+ bindProperty("rootElement",
+ &AccessibilityController::rootElementGetterCallback);
+
+ bindFallbackMethod(&AccessibilityController::fallbackCallback);
+}
+
+void AccessibilityController::bindToJavascript(WebFrame* frame, const WebString& classname)
+{
+ WebAccessibilityCache::enableAccessibility();
+ CppBoundClass::bindToJavascript(frame, classname);
+}
+
+void AccessibilityController::reset()
+{
+ m_rootElement = WebAccessibilityObject();
+ m_focusedElement = WebAccessibilityObject();
+ m_elements.clear();
+}
+
+void AccessibilityController::setFocusedElement(const WebAccessibilityObject& focusedElement)
+{
+ m_focusedElement = focusedElement;
+}
+
+AccessibilityUIElement* AccessibilityController::getFocusedElement()
+{
+ if (m_focusedElement.isNull())
+ m_focusedElement = m_shell->webView()->accessibilityObject();
+ return m_elements.create(m_focusedElement);
+}
+
+AccessibilityUIElement* AccessibilityController::getRootElement()
+{
+ if (m_rootElement.isNull())
+ m_rootElement = m_shell->webView()->accessibilityObject();
+ return m_elements.createRoot(m_rootElement);
+}
+
+void AccessibilityController::logFocusEventsCallback(const CppArgumentList&, CppVariant* result)
+{
+ // As of r49031, this is not being used upstream.
+ result->setNull();
+}
+
+void AccessibilityController::logScrollingStartEventsCallback(const CppArgumentList&, CppVariant* result)
+{
+ // As of r49031, this is not being used upstream.
+ result->setNull();
+}
+
+void AccessibilityController::focusedElementGetterCallback(CppVariant* result)
+{
+ result->set(*(getFocusedElement()->getAsCppVariant()));
+}
+
+void AccessibilityController::rootElementGetterCallback(CppVariant* result)
+{
+ result->set(*(getRootElement()->getAsCppVariant()));
+}
+
+void AccessibilityController::fallbackCallback(const CppArgumentList&, CppVariant* result)
+{
+ printf("CONSOLE MESSAGE: JavaScript ERROR: unknown method called on "
+ "AccessibilityController\n");
+ result->setNull();
+}
diff --git a/WebKitTools/DumpRenderTree/chromium/AccessibilityController.h b/WebKitTools/DumpRenderTree/chromium/AccessibilityController.h
new file mode 100644
index 0000000..3cde7cc
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/AccessibilityController.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2010 Google 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 AccessibilityController_h
+#define AccessibilityController_h
+
+#include "AccessibilityUIElement.h"
+#include "CppBoundClass.h"
+
+namespace WebKit {
+class WebAccessibilityObject;
+class WebFrame;
+}
+
+class TestShell;
+
+class AccessibilityController : public CppBoundClass {
+public:
+ explicit AccessibilityController(TestShell*);
+
+ // Shadow to include accessibility initialization.
+ void bindToJavascript(WebKit::WebFrame*, const WebKit::WebString& classname);
+ void reset();
+
+ void setFocusedElement(const WebKit::WebAccessibilityObject&);
+ AccessibilityUIElement* getFocusedElement();
+ AccessibilityUIElement* getRootElement();
+
+private:
+ // Bound methods and properties
+ void logFocusEventsCallback(const CppArgumentList&, CppVariant*);
+ void logScrollingStartEventsCallback(const CppArgumentList&, CppVariant*);
+ void fallbackCallback(const CppArgumentList&, CppVariant*);
+
+ void focusedElementGetterCallback(CppVariant*);
+ void rootElementGetterCallback(CppVariant*);
+
+ WebKit::WebAccessibilityObject m_focusedElement;
+ WebKit::WebAccessibilityObject m_rootElement;
+
+ AccessibilityUIElementList m_elements;
+
+ TestShell* m_shell;
+};
+
+#endif // AccessibilityController_h
diff --git a/WebKitTools/DumpRenderTree/chromium/AccessibilityUIElement.cpp b/WebKitTools/DumpRenderTree/chromium/AccessibilityUIElement.cpp
new file mode 100644
index 0000000..8698e25
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/AccessibilityUIElement.cpp
@@ -0,0 +1,585 @@
+/*
+ * Copyright (C) 2010 Google 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 "config.h"
+#include "AccessibilityUIElement.h"
+
+#include "public/WebAccessibilityObject.h"
+#include "public/WebCString.h"
+#include "public/WebString.h"
+#include <wtf/Assertions.h>
+
+using namespace WebKit;
+using namespace std;
+
+// Map role value to string, matching Safari/Mac platform implementation to
+// avoid rebaselining layout tests.
+static string roleToString(WebAccessibilityRole role)
+{
+ string result = "AXRole: AX";
+ switch (role) {
+ case WebAccessibilityRoleButton:
+ return result.append("Button");
+ case WebAccessibilityRoleRadioButton:
+ return result.append("RadioButton");
+ case WebAccessibilityRoleCheckBox:
+ return result.append("CheckBox");
+ case WebAccessibilityRoleSlider:
+ return result.append("Slider");
+ case WebAccessibilityRoleTabGroup:
+ return result.append("TabGroup");
+ case WebAccessibilityRoleTextField:
+ return result.append("TextField");
+ case WebAccessibilityRoleStaticText:
+ return result.append("StaticText");
+ case WebAccessibilityRoleTextArea:
+ return result.append("TextArea");
+ case WebAccessibilityRoleScrollArea:
+ return result.append("ScrollArea");
+ case WebAccessibilityRolePopUpButton:
+ return result.append("PopUpButton");
+ case WebAccessibilityRoleMenuButton:
+ return result.append("MenuButton");
+ case WebAccessibilityRoleTable:
+ return result.append("Table");
+ case WebAccessibilityRoleApplication:
+ return result.append("Application");
+ case WebAccessibilityRoleGroup:
+ return result.append("Group");
+ case WebAccessibilityRoleRadioGroup:
+ return result.append("RadioGroup");
+ case WebAccessibilityRoleList:
+ return result.append("List");
+ case WebAccessibilityRoleScrollBar:
+ return result.append("ScrollBar");
+ case WebAccessibilityRoleValueIndicator:
+ return result.append("ValueIndicator");
+ case WebAccessibilityRoleImage:
+ return result.append("Image");
+ case WebAccessibilityRoleMenuBar:
+ return result.append("MenuBar");
+ case WebAccessibilityRoleMenu:
+ return result.append("Menu");
+ case WebAccessibilityRoleMenuItem:
+ return result.append("MenuItem");
+ case WebAccessibilityRoleColumn:
+ return result.append("Column");
+ case WebAccessibilityRoleRow:
+ return result.append("Row");
+ case WebAccessibilityRoleToolbar:
+ return result.append("Toolbar");
+ case WebAccessibilityRoleBusyIndicator:
+ return result.append("BusyIndicator");
+ case WebAccessibilityRoleProgressIndicator:
+ return result.append("ProgressIndicator");
+ case WebAccessibilityRoleWindow:
+ return result.append("Window");
+ case WebAccessibilityRoleDrawer:
+ return result.append("Drawer");
+ case WebAccessibilityRoleSystemWide:
+ return result.append("SystemWide");
+ case WebAccessibilityRoleOutline:
+ return result.append("Outline");
+ case WebAccessibilityRoleIncrementor:
+ return result.append("Incrementor");
+ case WebAccessibilityRoleBrowser:
+ return result.append("Browser");
+ case WebAccessibilityRoleComboBox:
+ return result.append("ComboBox");
+ case WebAccessibilityRoleSplitGroup:
+ return result.append("SplitGroup");
+ case WebAccessibilityRoleSplitter:
+ return result.append("Splitter");
+ case WebAccessibilityRoleColorWell:
+ return result.append("ColorWell");
+ case WebAccessibilityRoleGrowArea:
+ return result.append("GrowArea");
+ case WebAccessibilityRoleSheet:
+ return result.append("Sheet");
+ case WebAccessibilityRoleHelpTag:
+ return result.append("HelpTag");
+ case WebAccessibilityRoleMatte:
+ return result.append("Matte");
+ case WebAccessibilityRoleRuler:
+ return result.append("Ruler");
+ case WebAccessibilityRoleRulerMarker:
+ return result.append("RulerMarker");
+ case WebAccessibilityRoleLink:
+ return result.append("Link");
+ case WebAccessibilityRoleDisclosureTriangle:
+ return result.append("DisclosureTriangle");
+ case WebAccessibilityRoleGrid:
+ return result.append("Grid");
+ case WebAccessibilityRoleCell:
+ return result.append("Cell");
+ case WebAccessibilityRoleColumnHeader:
+ return result.append("ColumnHeader");
+ case WebAccessibilityRoleRowHeader:
+ return result.append("RowHeader");
+ case WebAccessibilityRoleWebCoreLink:
+ // Maps to Link role.
+ return result.append("Link");
+ case WebAccessibilityRoleImageMapLink:
+ return result.append("ImageMapLink");
+ case WebAccessibilityRoleImageMap:
+ return result.append("ImageMap");
+ case WebAccessibilityRoleListMarker:
+ return result.append("ListMarker");
+ case WebAccessibilityRoleWebArea:
+ return result.append("WebArea");
+ case WebAccessibilityRoleHeading:
+ return result.append("Heading");
+ case WebAccessibilityRoleListBox:
+ return result.append("ListBox");
+ case WebAccessibilityRoleListBoxOption:
+ return result.append("ListBoxOption");
+ case WebAccessibilityRoleTableHeaderContainer:
+ return result.append("TableHeaderContainer");
+ case WebAccessibilityRoleDefinitionListTerm:
+ return result.append("DefinitionListTerm");
+ case WebAccessibilityRoleDefinitionListDefinition:
+ return result.append("DefinitionListDefinition");
+ case WebAccessibilityRoleAnnotation:
+ return result.append("Annotation");
+ case WebAccessibilityRoleSliderThumb:
+ return result.append("SliderThumb");
+ case WebAccessibilityRoleLandmarkApplication:
+ return result.append("LandmarkApplication");
+ case WebAccessibilityRoleLandmarkBanner:
+ return result.append("LandmarkBanner");
+ case WebAccessibilityRoleLandmarkComplementary:
+ return result.append("LandmarkComplementary");
+ case WebAccessibilityRoleLandmarkContentInfo:
+ return result.append("LandmarkContentInfo");
+ case WebAccessibilityRoleLandmarkMain:
+ return result.append("LandmarkMain");
+ case WebAccessibilityRoleLandmarkNavigation:
+ return result.append("LandmarkNavigation");
+ case WebAccessibilityRoleLandmarkSearch:
+ return result.append("LandmarkSearch");
+ case WebAccessibilityRoleApplicationLog:
+ return result.append("ApplicationLog");
+ case WebAccessibilityRoleApplicationMarquee:
+ return result.append("ApplicationMarquee");
+ case WebAccessibilityRoleApplicationStatus:
+ return result.append("ApplicationStatus");
+ case WebAccessibilityRoleApplicationTimer:
+ return result.append("ApplicationTimer");
+ case WebAccessibilityRoleDocument:
+ return result.append("Document");
+ case WebAccessibilityRoleDocumentArticle:
+ return result.append("DocumentArticle");
+ case WebAccessibilityRoleDocumentNote:
+ return result.append("DocumentNote");
+ case WebAccessibilityRoleDocumentRegion:
+ return result.append("DocumentRegion");
+ case WebAccessibilityRoleUserInterfaceTooltip:
+ return result.append("UserInterfaceTooltip");
+ default:
+ // Also matches WebAccessibilityRoleUnknown.
+ return result.append("Unknown");
+ }
+}
+
+string getDescription(const WebAccessibilityObject& object)
+{
+ string description = object.accessibilityDescription().utf8();
+ return description.insert(0, "AXDescription: ");
+}
+
+string getRole(const WebAccessibilityObject& object)
+{
+ return roleToString(object.roleValue());
+}
+
+string getTitle(const WebAccessibilityObject& object)
+{
+ string title = object.title().utf8();
+ return title.insert(0, "AXTitle: ");
+}
+
+string getAttributes(const WebAccessibilityObject& object)
+{
+ // FIXME: Concatenate all attributes of the AccessibilityObject.
+ string attributes(getTitle(object));
+ attributes.append("\n");
+ attributes.append(getRole(object));
+ attributes.append("\n");
+ attributes.append(getDescription(object));
+ return attributes;
+}
+
+
+// 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 WebAccessibilityObject& object)
+ {
+ m_attributes.append("\n------------\n");
+ m_attributes.append(getAttributes(object));
+ }
+
+ string attributes() const { return m_attributes; }
+
+private:
+ string m_attributes;
+};
+
+AccessibilityUIElement::AccessibilityUIElement(const WebAccessibilityObject& object, Factory* factory)
+ : m_accessibilityObject(object)
+ , m_factory(factory)
+{
+
+ ASSERT(factory);
+
+ bindMethod("allAttributes", &AccessibilityUIElement::allAttributesCallback);
+ bindMethod("attributesOfLinkedUIElements",
+ &AccessibilityUIElement::attributesOfLinkedUIElementsCallback);
+ bindMethod("attributesOfDocumentLinks",
+ &AccessibilityUIElement::attributesOfDocumentLinksCallback);
+ bindMethod("attributesOfChildren",
+ &AccessibilityUIElement::attributesOfChildrenCallback);
+ bindMethod("parameterizedAttributeNames",
+ &AccessibilityUIElement::parametrizedAttributeNamesCallback);
+ bindMethod("lineForIndex", &AccessibilityUIElement::lineForIndexCallback);
+ bindMethod("boundsForRange", &AccessibilityUIElement::boundsForRangeCallback);
+ bindMethod("stringForRange", &AccessibilityUIElement::stringForRangeCallback);
+ bindMethod("childAtIndex", &AccessibilityUIElement::childAtIndexCallback);
+ bindMethod("elementAtPoint", &AccessibilityUIElement::elementAtPointCallback);
+ bindMethod("attributesOfColumnHeaders",
+ &AccessibilityUIElement::attributesOfColumnHeadersCallback);
+ bindMethod("attributesOfRowHeaders",
+ &AccessibilityUIElement::attributesOfRowHeadersCallback);
+ bindMethod("attributesOfColumns",
+ &AccessibilityUIElement::attributesOfColumnsCallback);
+ bindMethod("attributesOfRows",
+ &AccessibilityUIElement::attributesOfRowsCallback);
+ bindMethod("attributesOfVisibleCells",
+ &AccessibilityUIElement::attributesOfVisibleCellsCallback);
+ bindMethod("attributesOfHeader",
+ &AccessibilityUIElement::attributesOfHeaderCallback);
+ bindMethod("indexInTable", &AccessibilityUIElement::indexInTableCallback);
+ bindMethod("rowIndexRange", &AccessibilityUIElement::rowIndexRangeCallback);
+ bindMethod("columnIndexRange",
+ &AccessibilityUIElement::columnIndexRangeCallback);
+ bindMethod("cellForColumnAndRow",
+ &AccessibilityUIElement::cellForColumnAndRowCallback);
+ bindMethod("titleUIElement", &AccessibilityUIElement::titleUIElementCallback);
+ bindMethod("setSelectedTextRange",
+ &AccessibilityUIElement::setSelectedTextRangeCallback);
+ bindMethod("attributeValue", &AccessibilityUIElement::attributeValueCallback);
+ bindMethod("isAttributeSettable",
+ &AccessibilityUIElement::isAttributeSettableCallback);
+ bindMethod("isActionSupported",
+ &AccessibilityUIElement::isActionSupportedCallback);
+ bindMethod("parentElement", &AccessibilityUIElement::parentElementCallback);
+ bindMethod("increment", &AccessibilityUIElement::incrementCallback);
+ bindMethod("decrement", &AccessibilityUIElement::decrementCallback);
+
+ bindProperty("role", &AccessibilityUIElement::roleGetterCallback);
+ bindProperty("subrole", &m_subrole);
+ bindProperty("title", &AccessibilityUIElement::titleGetterCallback);
+ bindProperty("description",
+ &AccessibilityUIElement::descriptionGetterCallback);
+ bindProperty("language", &m_language);
+ bindProperty("x", &m_x);
+ bindProperty("y", &m_y);
+ bindProperty("width", &m_width);
+ bindProperty("height", &m_height);
+ bindProperty("clickPointX", &m_clickPointX);
+ bindProperty("clickPointY", &m_clickPointY);
+ bindProperty("intValue", &m_intValue);
+ bindProperty("minValue", &m_minValue);
+ bindProperty("maxValue", &m_maxValue);
+ bindProperty("childrenCount",
+ &AccessibilityUIElement::childrenCountGetterCallback);
+ bindProperty("insertionPointLineNumber", &m_insertionPointLineNumber);
+ bindProperty("selectedTextRange", &m_selectedTextRange);
+ bindProperty("isEnabled", &AccessibilityUIElement::isEnabledGetterCallback);
+ bindProperty("isRequired", &m_isRequired);
+ bindProperty("isSelected", &AccessibilityUIElement::isSelectedGetterCallback);
+ bindProperty("valueDescription", &m_valueDescription);
+
+ bindFallbackMethod(&AccessibilityUIElement::fallbackCallback);
+}
+
+AccessibilityUIElement* AccessibilityUIElement::getChildAtIndex(unsigned index)
+{
+ return m_factory->create(accessibilityObject().childAt(index));
+}
+
+void AccessibilityUIElement::allAttributesCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->set(getAttributes(accessibilityObject()));
+}
+
+void AccessibilityUIElement::attributesOfLinkedUIElementsCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::attributesOfDocumentLinksCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::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 AccessibilityUIElement::parametrizedAttributeNamesCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::lineForIndexCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::boundsForRangeCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::stringForRangeCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::childAtIndexCallback(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (!arguments.size() || !arguments[0].isNumber()) {
+ result->setNull();
+ return;
+ }
+
+ AccessibilityUIElement* child = getChildAtIndex(arguments[0].toInt32());
+ if (!child) {
+ result->setNull();
+ return;
+ }
+
+ result->set(*(child->getAsCppVariant()));
+}
+
+void AccessibilityUIElement::elementAtPointCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::attributesOfColumnHeadersCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::attributesOfRowHeadersCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::attributesOfColumnsCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::attributesOfRowsCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::attributesOfVisibleCellsCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::attributesOfHeaderCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::indexInTableCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::rowIndexRangeCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::columnIndexRangeCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::cellForColumnAndRowCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::titleUIElementCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::setSelectedTextRangeCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::attributeValueCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::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 AccessibilityUIElement::isActionSupportedCallback(const CppArgumentList&, CppVariant* result)
+{
+ // This one may be really hard to implement.
+ // Not exposed by AccessibilityObject.
+ result->setNull();
+}
+
+void AccessibilityUIElement::parentElementCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::incrementCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::decrementCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::fallbackCallback(const CppArgumentList &, CppVariant* result)
+{
+ // FIXME: Implement this.
+ result->setNull();
+}
+
+void AccessibilityUIElement::childrenCountGetterCallback(CppVariant* result)
+{
+ int count = 1; // Root object always has only one child, the WebView.
+ if (!isRoot())
+ count = accessibilityObject().childCount();
+ result->set(count);
+}
+
+void AccessibilityUIElement::descriptionGetterCallback(CppVariant* result)
+{
+ result->set(getDescription(accessibilityObject()));
+}
+
+void AccessibilityUIElement::isEnabledGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().isEnabled());
+}
+
+void AccessibilityUIElement::isSelectedGetterCallback(CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::roleGetterCallback(CppVariant* result)
+{
+ result->set(getRole(accessibilityObject()));
+}
+
+void AccessibilityUIElement::titleGetterCallback(CppVariant* result)
+{
+ result->set(getTitle(accessibilityObject()));
+}
+
+
+RootAccessibilityUIElement::RootAccessibilityUIElement(const WebAccessibilityObject &object, Factory *factory)
+ : AccessibilityUIElement(object, factory) { }
+
+AccessibilityUIElement* RootAccessibilityUIElement::getChildAtIndex(unsigned index)
+{
+ if (index)
+ return 0;
+
+ return factory()->create(accessibilityObject());
+}
+
+
+AccessibilityUIElementList ::~AccessibilityUIElementList()
+{
+ clear();
+}
+
+void AccessibilityUIElementList::clear()
+{
+ for (ElementList::iterator i = m_elements.begin(); i != m_elements.end(); ++i)
+ delete (*i);
+ m_elements.clear();
+}
+
+AccessibilityUIElement* AccessibilityUIElementList::create(const WebAccessibilityObject& object)
+{
+ if (object.isNull())
+ return 0;
+
+ AccessibilityUIElement* element = new AccessibilityUIElement(object, this);
+ m_elements.append(element);
+ return element;
+}
+
+AccessibilityUIElement* AccessibilityUIElementList::createRoot(const WebAccessibilityObject& object)
+{
+ AccessibilityUIElement* element = new RootAccessibilityUIElement(object, this);
+ m_elements.append(element);
+ return element;
+}
diff --git a/WebKitTools/DumpRenderTree/chromium/AccessibilityUIElement.h b/WebKitTools/DumpRenderTree/chromium/AccessibilityUIElement.h
new file mode 100644
index 0000000..df3f5b9
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/AccessibilityUIElement.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2010 Google 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 AccessibilityUIElement_h
+#define AccessibilityUIElement_h
+
+#include "CppBoundClass.h"
+#include "public/WebAccessibilityObject.h"
+#include <wtf/Vector.h>
+
+class AccessibilityUIElement : public CppBoundClass {
+public:
+ class Factory {
+ public:
+ virtual ~Factory() { }
+ virtual AccessibilityUIElement* create(const WebKit::WebAccessibilityObject&) = 0;
+ };
+
+ AccessibilityUIElement(const WebKit::WebAccessibilityObject&, Factory*);
+
+ virtual AccessibilityUIElement* getChildAtIndex(unsigned);
+ virtual bool isRoot() const { return false; }
+
+protected:
+ const WebKit::WebAccessibilityObject& accessibilityObject() const { return m_accessibilityObject; }
+ Factory* factory() const { return m_factory; }
+
+private:
+ // Bound methods and properties.
+ void allAttributesCallback(const CppArgumentList&, CppVariant*);
+ void attributesOfLinkedUIElementsCallback(const CppArgumentList&, CppVariant*);
+ void attributesOfDocumentLinksCallback(const CppArgumentList&, CppVariant*);
+ void attributesOfChildrenCallback(const CppArgumentList&, CppVariant*);
+ void parametrizedAttributeNamesCallback(const CppArgumentList&, CppVariant*);
+ void lineForIndexCallback(const CppArgumentList&, CppVariant*);
+ void boundsForRangeCallback(const CppArgumentList&, CppVariant*);
+ void stringForRangeCallback(const CppArgumentList&, CppVariant*);
+ void childAtIndexCallback(const CppArgumentList&, CppVariant*);
+ void elementAtPointCallback(const CppArgumentList&, CppVariant*);
+ void attributesOfColumnHeadersCallback(const CppArgumentList&, CppVariant*);
+ void attributesOfRowHeadersCallback(const CppArgumentList&, CppVariant*);
+ void attributesOfColumnsCallback(const CppArgumentList&, CppVariant*);
+ void attributesOfRowsCallback(const CppArgumentList&, CppVariant*);
+ void attributesOfVisibleCellsCallback(const CppArgumentList&, CppVariant*);
+ void attributesOfHeaderCallback(const CppArgumentList&, CppVariant*);
+ void indexInTableCallback(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 attributeValueCallback(const CppArgumentList&, CppVariant*);
+ void isAttributeSettableCallback(const CppArgumentList&, CppVariant*);
+ void isActionSupportedCallback(const CppArgumentList&, CppVariant*);
+ void parentElementCallback(const CppArgumentList&, CppVariant*);
+ void incrementCallback(const CppArgumentList&, CppVariant*);
+ void decrementCallback(const CppArgumentList&, CppVariant*);
+ void fallbackCallback(const CppArgumentList&, CppVariant*);
+
+ void childrenCountGetterCallback(CppVariant*);
+ void descriptionGetterCallback(CppVariant*);
+ void isEnabledGetterCallback(CppVariant*);
+ void isSelectedGetterCallback(CppVariant*);
+ void roleGetterCallback(CppVariant*);
+ void titleGetterCallback(CppVariant*);
+
+ CppVariant m_subrole;
+ CppVariant m_language;
+ CppVariant m_x;
+ CppVariant m_y;
+ CppVariant m_width;
+ CppVariant m_height;
+ CppVariant m_clickPointX;
+ CppVariant m_clickPointY;
+ CppVariant m_intValue;
+ CppVariant m_minValue;
+ CppVariant m_maxValue;
+ CppVariant m_childrenCount;
+ CppVariant m_insertionPointLineNumber;
+ CppVariant m_selectedTextRange;
+ CppVariant m_isRequired;
+ CppVariant m_valueDescription;
+
+ WebKit::WebAccessibilityObject m_accessibilityObject;
+ Factory* m_factory;
+};
+
+
+class RootAccessibilityUIElement : public AccessibilityUIElement {
+public:
+ RootAccessibilityUIElement(const WebKit::WebAccessibilityObject&, Factory*);
+
+ virtual AccessibilityUIElement* getChildAtIndex(unsigned);
+ virtual bool isRoot() const { return true; }
+};
+
+
+// Provides simple lifetime management of the AccessibilityUIElement instances:
+// all AccessibilityUIElements ever created from the controller are stored in
+// a list and cleared explicitly.
+class AccessibilityUIElementList : public AccessibilityUIElement::Factory {
+public:
+ AccessibilityUIElementList() { }
+ virtual ~AccessibilityUIElementList();
+
+ void clear();
+ virtual AccessibilityUIElement* create(const WebKit::WebAccessibilityObject&);
+ AccessibilityUIElement* createRoot(const WebKit::WebAccessibilityObject&);
+
+private:
+ typedef Vector<AccessibilityUIElement*> ElementList;
+ ElementList m_elements;
+};
+
+#endif // AccessibilityUIElement_h
diff --git a/WebKitTools/DumpRenderTree/chromium/CppBoundClass.cpp b/WebKitTools/DumpRenderTree/chromium/CppBoundClass.cpp
new file mode 100644
index 0000000..839787a
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/CppBoundClass.cpp
@@ -0,0 +1,350 @@
+/*
+ * 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 "config.h"
+#include "CppBoundClass.h"
+
+#include "public/WebBindings.h"
+#include "public/WebFrame.h"
+#include "public/WebString.h"
+#include <wtf/Assertions.h>
+#include <wtf/OwnPtr.h>
+
+using namespace WebKit;
+using namespace std;
+
+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(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:
+ OwnPtr<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.remove(oldCallback);
+ return;
+ }
+ }
+
+ m_methods.set(ident, callback);
+}
+
+void CppBoundClass::bindGetterCallback(const string& name, GetterCallback* callback)
+{
+ PropertyCallback* propertyCallback = callback ? 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.remove(oldCallback);
+ return;
+ }
+ }
+
+ m_properties.set(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.
+ }
+ 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()));
+ m_boundToFrame = true;
+}
diff --git a/WebKitTools/DumpRenderTree/chromium/CppBoundClass.h b/WebKitTools/DumpRenderTree/chromium/CppBoundClass.h
new file mode 100644
index 0000000..6cb638e
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/CppBoundClass.h
@@ -0,0 +1,241 @@
+/*
+ * 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 "CppVariant.h"
+#include <wtf/HashMap.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebKit {
+class WebFrame;
+class WebString;
+}
+
+typedef 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 Noncopyable {
+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(WebKit::WebFrame*, const WebKit::WebString& classname);
+
+ // Used by a test. Returns true if a method with name |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, |method|
+ // 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&, GetterCallback*);
+
+ // A wrapper for BindGetterCallback, to simplify the common case of binding a
+ // property on the current object. Though not verified here, |method|
+ // must be a method of this CppBoundClass subclass.
+ template<class T>
+ void bindProperty(const std::string& name, void (T::*method)(CppVariant*))
+ {
+ 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(Callback* fallbackCallback)
+ {
+ m_fallbackCallback.set(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) {
+ Callback* callback = new MemberCallback<T>(static_cast<T*>(this), method);
+ bindFallbackCallback(callback);
+ } else
+ bindFallbackCallback(0);
+ }
+
+ // Some fields are protected because some tests depend on accessing them,
+ // but otherwise they should be considered private.
+
+ typedef HashMap<NPIdentifier, PropertyCallback*> PropertyList;
+ typedef HashMap<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.
+ OwnPtr<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/WebKitTools/DumpRenderTree/chromium/CppVariant.cpp b/WebKitTools/DumpRenderTree/chromium/CppVariant.cpp
new file mode 100644
index 0000000..9539907
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/CppVariant.cpp
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2010 Google 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 "config.h"
+#include "CppVariant.h"
+
+#include "public/WebBindings.h"
+#include <limits>
+#include <wtf/Assertions.h>
+#include <wtf/StringExtras.h>
+
+using namespace WebKit;
+using namespace std;
+
+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
+{
+ 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);
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+double CppVariant::toDouble() const
+{
+ if (isInt32())
+ return static_cast<double>(value.intValue);
+ if (isDouble())
+ return value.doubleValue;
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+bool CppVariant::toBoolean() const
+{
+ ASSERT(isBool());
+ return value.boolValue;
+}
+
+Vector<string> CppVariant::toStringVector() const
+{
+
+ 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.append(item);
+ }
+ WebBindings::releaseVariantValue(&indexValue);
+ }
+ return stringVector;
+}
+
+bool CppVariant::invoke(const string& method, const CppVariant* arguments,
+ uint32_t argumentCount, CppVariant& result) const
+{
+ 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;
+}
diff --git a/WebKitTools/DumpRenderTree/chromium/CppVariant.h b/WebKitTools/DumpRenderTree/chromium/CppVariant.h
new file mode 100644
index 0000000..d34a163
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/CppVariant.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2010 Google 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.
+ */
+
+/*
+ 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 "base/basictypes.h"
+#include "public/WebBindings.h"
+#include <string>
+#include <wtf/Vector.h>
+
+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.
+ 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;
+};
+
+#endif // CppVariant_h
diff --git a/WebKitTools/DumpRenderTree/chromium/DumpRenderTree.cpp b/WebKitTools/DumpRenderTree/chromium/DumpRenderTree.cpp
new file mode 100644
index 0000000..c81480f
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/DumpRenderTree.cpp
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2010 Google 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 "config.h"
+
+#include "TestShell.h"
+#include "webkit/support/webkit_support.h"
+#include <wtf/Vector.h>
+#if OS(MAC_OS_X)
+#include "WebSystemInterface.h"
+#endif
+
+using namespace std;
+
+static const char optionComplexText[] = "--complex-text";
+static const char optionDumpAllPixels[] = "--dump-all-pixels";
+static const char optionNotree[] = "--notree";
+static const char optionPixelTests[] = "--pixel-tests";
+static const char optionThreaded[] = "--threaded";
+static const char optionTree[] = "--tree";
+
+static void runTest(TestShell& shell, TestParams& params, const string& testName)
+{
+ string pathOrURL = testName;
+ string::size_type separatorPosition = pathOrURL.find("'");
+ if (separatorPosition != string::npos) {
+ params.pixelHash = pathOrURL.substr(separatorPosition + 1);
+ pathOrURL.erase(separatorPosition);
+ }
+ params.testUrl = webkit_support::CreateURLForPathOrURL(pathOrURL);
+ shell.resetTestController();
+ shell.runFileTest(params);
+}
+
+int main(int argc, char* argv[])
+{
+#if OS(MAC_OS_X)
+ // Need to call before instantiate WebKitClient.
+ InitWebCoreSystemInterface();
+#endif
+ webkit_support::SetUpTestEnvironment();
+
+ TestParams params;
+ Vector<string> tests;
+ bool serverMode = false;
+ for (int i = 1; i < argc; ++i) {
+ string argument(argv[i]);
+ if (argument == "-")
+ serverMode = true;
+ else if (argument == optionNotree)
+ params.dumpTree = false;
+ else if (argument == optionPixelTests)
+ params.dumpPixels = true;
+ else if (argument.size() && argument[0] == '-')
+ fprintf(stderr, "Unknown option: %s\n", argv[i]);
+ else
+ tests.append(argument);
+ }
+
+ { // Explicit scope for the TestShell instance.
+ TestShell shell;
+ if (serverMode && !tests.size()) {
+ params.printSeparators = true;
+ char testString[2048]; // 2048 is the same as the sizes of other platforms.
+ while (fgets(testString, sizeof(testString), stdin)) {
+ char* newLinePosition = strchr(testString, '\n');
+ if (newLinePosition)
+ *newLinePosition = '\0';
+ if (testString[0] == '\0')
+ continue;
+ runTest(shell, params, testString);
+ }
+ } else if (!tests.size())
+ printf("#EOF\n");
+ else {
+ params.printSeparators = tests.size() > 1;
+ for (unsigned i = 0; i < tests.size(); i++)
+ runTest(shell, params, tests[i]);
+ }
+
+ shell.callJSGC();
+ shell.callJSGC();
+
+ // When we finish the last test, cleanup the LayoutTestController.
+ // It may have references to not-yet-cleaned up windows. By
+ // cleaning up here we help purify reports.
+ shell.resetTestController();
+ }
+
+ webkit_support::TearDownTestEnvironment();
+ return EXIT_SUCCESS;
+}
diff --git a/WebKitTools/DumpRenderTree/chromium/EventSender.cpp b/WebKitTools/DumpRenderTree/chromium/EventSender.cpp
new file mode 100644
index 0000000..c48aaf4
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/EventSender.cpp
@@ -0,0 +1,807 @@
+/*
+ * Copyright (C) 2010 Google 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.
+ */
+
+// 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 "config.h"
+#include "EventSender.h"
+
+#include "TestShell.h"
+#include "base/keyboard_codes.h"
+#include "base/time.h"
+#include "public/WebDragData.h"
+#include "public/WebDragOperation.h"
+#include "public/WebPoint.h"
+#include "public/WebString.h"
+#include "public/WebView.h"
+#include "webkit/support/webkit_support.h"
+#include <wtf/Deque.h>
+#include <wtf/StringExtras.h>
+
+#if OS(WINDOWS)
+#include "public/win/WebInputEventFactory.h"
+#endif
+
+// FIXME: layout before each event?
+
+using namespace base;
+using namespace std;
+using namespace WebKit;
+
+TestShell* EventSender::testShell = 0;
+WebPoint EventSender::lastMousePos;
+WebMouseEvent::Button EventSender::pressedButton = WebMouseEvent::ButtonNone;
+WebMouseEvent::Button EventSender::lastButtonType = WebMouseEvent::ButtonNone;
+
+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) {}
+};
+
+static WebDragData currentDragData;
+static WebDragOperation currentDragEffect;
+static WebDragOperationsMask currentDragEffectsAllowed;
+static bool replayingSavedEvents = false;
+static Deque<SavedEvent> mouseEventQueue;
+
+// Time and place of the last mouse up event.
+static double lastClickTimeSec = 0;
+static WebPoint lastClickPos;
+static int clickCount = 0;
+
+// maximum distance (in space and time) for a mouse click
+// to register as a double or triple click
+static const double multipleClickTimeSec = 1;
+static 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.
+static 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).
+static uint32 timeOffsetMs = 0;
+
+static double getCurrentEventTimeSec()
+{
+ return (TimeTicks::Now().ToInternalValue() / Time::kMicrosecondsPerMillisecond + timeOffsetMs) / 1000.0;
+}
+
+static void advanceEventTime(int32_t deltaMs)
+{
+ timeOffsetMs += deltaMs;
+}
+
+static void initMouseEvent(WebInputEvent::Type t, WebMouseEvent::Button b,
+ const gfx::Point& pos, WebMouseEvent* e)
+{
+ 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 = getCurrentEventTimeSec();
+ e->clickCount = clickCount;
+}
+
+// Returns true if the specified key is the system key.
+static bool applyKeyModifier(const string& modifierName, WebInputEvent* event)
+{
+ bool isSystemKey = false;
+ const char* characters = modifierName.c_str();
+ if (!strcmp(characters, "ctrlKey")
+#if !OS(MAC_OS_X)
+ || !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;
+#if !OS(MAC_OS_X)
+ // On Windows all keys with Alt modifier will be marked as system key.
+ // We keep the same behavior on Linux, see:
+ // WebKit/chromium/src/gtk/WebInputEventFactory.cpp
+ // If we want to change this behavior on Linux, this piece of code must be
+ // kept in sync with the related code in above file.
+ isSystemKey = true;
+#endif
+#if OS(MAC_OS_X)
+ } else if (!strcmp(characters, "metaKey") || !strcmp(characters, "addSelectionKey")) {
+ event->modifiers |= WebInputEvent::MetaKey;
+ // On Mac only command key presses are marked as system key.
+ // See the related code in: WebKit/chromium/src/mac/WebInputEventFactory.cpp
+ // It must be kept in sync with the related code in above file.
+ isSystemKey = true;
+#else
+ } else if (!strcmp(characters, "metaKey")) {
+ event->modifiers |= WebInputEvent::MetaKey;
+#endif
+ }
+ return isSystemKey;
+}
+
+static bool applyKeyModifiers(const CppVariant* argument, WebInputEvent* event)
+{
+ bool isSystemKey = false;
+ if (argument->isObject()) {
+ Vector<string> modifiers = argument->toStringVector();
+ for (Vector<string>::const_iterator i = modifiers.begin(); i != modifiers.end(); ++i)
+ isSystemKey |= applyKeyModifier(*i, event);
+ } else if (argument->isString())
+ isSystemKey = applyKeyModifier(argument->toString(), event);
+ return isSystemKey;
+}
+
+// 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)
+{
+#if OS(MAC_OS_X)
+ // 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 base::VKEY_LEFT:
+ *name = "MoveToBeginningOfLine";
+ break;
+ case base::VKEY_RIGHT:
+ *name = "MoveToEndOfLine";
+ break;
+ case base::VKEY_UP:
+ *name = "MoveToBeginningOfDocument";
+ break;
+ case base::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(TestShell* shell)
+ : m_methodFactory(this)
+{
+ // Set static testShell variable since we can't do it in an initializer list.
+ // We also need to be careful not to assign testShell to new windows which are
+ // temporary.
+ if (!testShell)
+ testShell = shell;
+
+ // 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("mouseDown", &EventSender::mouseDown);
+ bindMethod("mouseUp", &EventSender::mouseUp);
+ bindMethod("contextClick", &EventSender::contextClick);
+ bindMethod("mouseMoveTo", &EventSender::mouseMoveTo);
+ bindMethod("mouseWheelTo", &EventSender::mouseWheelTo);
+ bindMethod("leapForward", &EventSender::leapForward);
+ bindMethod("keyDown", &EventSender::keyDown);
+ bindMethod("dispatchMessage", &EventSender::dispatchMessage);
+ bindMethod("enableDOMUIEventLogging", &EventSender::enableDOMUIEventLogging);
+ bindMethod("fireKeyboardEventsToElement", &EventSender::fireKeyboardEventsToElement);
+ bindMethod("clearKillRing", &EventSender::clearKillRing);
+ bindMethod("textZoomIn", &EventSender::textZoomIn);
+ bindMethod("textZoomOut", &EventSender::textZoomOut);
+ bindMethod("zoomPageIn", &EventSender::zoomPageIn);
+ bindMethod("zoomPageOut", &EventSender::zoomPageOut);
+ bindMethod("scheduleAsynchronousClick", &EventSender::scheduleAsynchronousClick);
+ bindMethod("beginDragWithFiles", &EventSender::beginDragWithFiles);
+
+ // When set to true (the default value), we batch mouse move and mouse up
+ // events so we can simulate drag & drop.
+ bindProperty("dragMode", &dragMode);
+#if OS(WINDOWS)
+ 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
+}
+
+void EventSender::reset()
+{
+ // The test should have finished a drag and the mouse button state.
+ ASSERT(currentDragData.isNull());
+ currentDragData.reset();
+ currentDragEffect = WebKit::WebDragOperationNone;
+ currentDragEffectsAllowed = WebKit::WebDragOperationNone;
+ pressedButton = WebMouseEvent::ButtonNone;
+ dragMode.set(true);
+#if OS(WINDOWS)
+ 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;
+}
+
+WebView* EventSender::webview()
+{
+ return testShell->webView();
+}
+
+void EventSender::doDragDrop(const WebKit::WebPoint& eventPos,
+ const WebDragData& dragData,
+ WebDragOperationsMask mask)
+{
+ WebMouseEvent event;
+ initMouseEvent(WebInputEvent::MouseDown, pressedButton, lastMousePos, &event);
+ WebPoint clientPoint(event.x, event.y);
+ WebPoint screenPoint(event.globalX, event.globalY);
+ currentDragData = dragData;
+ currentDragEffectsAllowed = mask;
+ currentDragEffect = webview()->dragTargetDragEnter(dragData, 0, clientPoint, screenPoint, currentDragEffectsAllowed);
+
+ // Finish processing events.
+ replaySavedEvents();
+}
+
+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() - 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();
+
+ webview()->layout();
+
+ int buttonNumber = getButtonNumberFromSingleArg(arguments);
+ ASSERT(buttonNumber != -1);
+
+ WebMouseEvent::Button buttonType = getButtonTypeFromButtonNumber(buttonNumber);
+
+ updateClickCountForButton(buttonType);
+
+ WebMouseEvent event;
+ pressedButton = buttonType;
+ initMouseEvent(WebInputEvent::MouseDown, buttonType, lastMousePos, &event);
+ 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();
+
+ webview()->layout();
+
+ int buttonNumber = getButtonNumberFromSingleArg(arguments);
+ ASSERT(buttonNumber != -1);
+
+ WebMouseEvent::Button buttonType = getButtonTypeFromButtonNumber(buttonNumber);
+
+ if (isDragMode() && !replayingSavedEvents) {
+ SavedEvent savedEvent;
+ savedEvent.type = SavedEvent::MouseUp;
+ savedEvent.buttonType = buttonType;
+ mouseEventQueue.append(savedEvent);
+ replaySavedEvents();
+ } else {
+ WebMouseEvent event;
+ initMouseEvent(WebInputEvent::MouseUp, buttonType, lastMousePos, &event);
+ 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);
+
+ currentDragEffect = webview()->dragTargetDragOver(clientPoint, screenPoint, currentDragEffectsAllowed);
+ if (currentDragEffect)
+ webview()->dragTargetDrop(clientPoint, screenPoint);
+ 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;
+ 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.append(savedEvent);
+ } else {
+ WebMouseEvent event;
+ initMouseEvent(WebInputEvent::MouseMove, pressedButton, mousePos, &event);
+ doMouseMove(event);
+ }
+}
+
+void EventSender::mouseWheelTo(const CppArgumentList& arguments, CppVariant* result)
+{
+ 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). The layout test calling this
+ // (scrollbars/overflow-scrollbar-horizontal-wheel-scroll.html, only one
+ // for now) does not rely on this though.
+ webview()->layout();
+
+ int horizontal = arguments[0].toInt32();
+ int vertical = arguments[1].toInt32();
+
+ WebMouseWheelEvent event;
+ initMouseEvent(WebInputEvent::MouseWheel, pressedButton, lastMousePos, &event);
+ event.wheelTicksX = static_cast<float>(horizontal);
+ event.wheelTicksY = static_cast<float>(vertical);
+ event.deltaX = -horizontal * scrollbarPixelsPerTick;
+ event.deltaY = -vertical * scrollbarPixelsPerTick;
+ webview()->handleInputEvent(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);
+}
+
+void EventSender::keyDown(const CppArgumentList& arguments, CppVariant* 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 = base::VKEY_RETURN;
+ } else if ("rightArrow" == codeStr)
+ code = base::VKEY_RIGHT;
+ else if ("downArrow" == codeStr)
+ code = base::VKEY_DOWN;
+ else if ("leftArrow" == codeStr)
+ code = base::VKEY_LEFT;
+ else if ("upArrow" == codeStr)
+ code = base::VKEY_UP;
+ else if ("delete" == codeStr)
+ code = base::VKEY_BACK;
+ else if ("pageUp" == codeStr)
+ code = base::VKEY_PRIOR;
+ else if ("pageDown" == codeStr)
+ code = base::VKEY_NEXT;
+ else if ("home" == codeStr)
+ code = base::VKEY_HOME;
+ else if ("end" == codeStr)
+ code = base::VKEY_END;
+ 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 = base::VKEY_F1 + (i - 1);
+ break;
+ }
+ }
+ if (!code) {
+ WebString webCodeStr = WebString::fromUTF8(codeStr.data(), codeStr.size());
+ ASSERT(webCodeStr.length() == 1);
+ text = code = webCodeStr.data()[0];
+ needsShiftKeyModifier = needsShiftModifier(code);
+ if ((code & 0xFF) >= 'a' && (code & 0xFF) <= 'z')
+ code -= 'a' - 'A';
+ generateChar = true;
+ }
+ }
+
+ // For one generated keyboard event, we need to generate a keyDown/keyUp
+ // pair; refer to EventSender.cpp in WebKit/WebKitTools/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 (generateChar) {
+ eventDown.text[0] = text;
+ eventDown.unmodifiedText[0] = text;
+ }
+ eventDown.setKeyIdentifierFromWindowsKeyCode();
+
+ if (arguments.size() >= 2 && (arguments[1].isObject() || arguments[1].isString()))
+ eventDown.isSystemKey = applyKeyModifiers(&(arguments[1]), &eventDown);
+
+ 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.
+ 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/WebKit/chromium/src/EditorClientImpl.cpp.
+ // We just simulate the same behavior here.
+ string editCommand;
+ if (getEditCommand(eventDown, &editCommand))
+ testShell->webViewHost()->setEditCommand(editCommand, "");
+
+ webview()->handleInputEvent(eventDown);
+
+ testShell->webViewHost()->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();
+
+#if OS(WINDOWS)
+ 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;
+
+ webview()->layout();
+
+ unsigned long lparam = static_cast<unsigned long>(arguments[2].toDouble());
+ webview()->handleInputEvent(WebInputEventFactory::keyboardEvent(0, msg, arguments[1].toInt32(), lparam));
+ } else
+ 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
+ // WebKit/WebKitTools/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.append(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()->setZoomLevel(true, webview()->zoomLevel() + 1);
+ result->setNull();
+}
+
+void EventSender::textZoomOut(const CppArgumentList&, CppVariant* result)
+{
+ webview()->setZoomLevel(true, webview()->zoomLevel() - 1);
+ result->setNull();
+}
+
+void EventSender::zoomPageIn(const CppArgumentList&, CppVariant* result)
+{
+ webview()->setZoomLevel(false, webview()->zoomLevel() + 1);
+ result->setNull();
+}
+
+void EventSender::zoomPageOut(const CppArgumentList&, CppVariant* result)
+{
+ webview()->setZoomLevel(false, webview()->zoomLevel() - 1);
+ result->setNull();
+}
+
+void EventSender::replaySavedEvents()
+{
+ replayingSavedEvents = true;
+ while (!mouseEventQueue.isEmpty()) {
+ SavedEvent e = mouseEventQueue.first();
+ mouseEventQueue.removeFirst();
+
+ switch (e.type) {
+ case SavedEvent::MouseMove: {
+ WebMouseEvent event;
+ initMouseEvent(WebInputEvent::MouseMove, pressedButton, e.pos, &event);
+ doMouseMove(event);
+ break;
+ }
+ case SavedEvent::LeapForward:
+ doLeapForward(e.milliseconds);
+ break;
+ case SavedEvent::MouseUp: {
+ WebMouseEvent event;
+ initMouseEvent(WebInputEvent::MouseUp, e.buttonType, lastMousePos, &event);
+ doMouseUp(event);
+ break;
+ }
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ }
+
+ replayingSavedEvents = false;
+}
+
+void EventSender::contextClick(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ webview()->layout();
+
+ updateClickCountForButton(WebMouseEvent::ButtonRight);
+
+ // Generate right mouse down and up.
+
+ WebMouseEvent event;
+ pressedButton = WebMouseEvent::ButtonRight;
+ initMouseEvent(WebInputEvent::MouseDown, WebMouseEvent::ButtonRight, lastMousePos, &event);
+ webview()->handleInputEvent(event);
+
+ initMouseEvent(WebInputEvent::MouseUp, WebMouseEvent::ButtonRight, lastMousePos, &event);
+ webview()->handleInputEvent(event);
+
+ pressedButton = WebMouseEvent::ButtonNone;
+}
+
+void EventSender::scheduleAsynchronousClick(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ webkit_support::PostTaskFromHere(m_methodFactory.NewRunnableMethod(
+ &EventSender::mouseDown, arguments, static_cast<CppVariant*>(0)));
+ webkit_support::PostTaskFromHere(m_methodFactory.NewRunnableMethod(
+ &EventSender::mouseUp, arguments, static_cast<CppVariant*>(0)));
+}
+
+void EventSender::beginDragWithFiles(const CppArgumentList& arguments, CppVariant* result)
+{
+ currentDragData.initialize();
+ Vector<string> files = arguments[0].toStringVector();
+ for (size_t i = 0; i < files.size(); ++i)
+ currentDragData.appendToFileNames(webkit_support::GetAbsoluteWebStringFromUTF8Path(files[i]));
+ currentDragEffectsAllowed = WebKit::WebDragOperationCopy;
+
+ // Provide a drag source.
+ webview()->dragTargetDragEnter(currentDragData, 0, lastMousePos, lastMousePos, currentDragEffectsAllowed);
+
+ // 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();
+}
+
+//
+// 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/WebKitTools/DumpRenderTree/chromium/EventSender.h b/WebKitTools/DumpRenderTree/chromium/EventSender.h
new file mode 100644
index 0000000..756b008
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/EventSender.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2010 Google 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.
+ */
+
+/*
+ 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 "CppBoundClass.h"
+#include "base/task.h"
+#include "public/WebDragOperation.h"
+#include "public/WebInputEvent.h"
+#include "public/WebPoint.h"
+
+class TestShell;
+
+namespace WebKit {
+class WebDragData;
+class WebView;
+}
+
+class EventSender : public CppBoundClass {
+public:
+ // Builds the property and method lists needed to bind this class to a JS
+ // object.
+ EventSender(TestShell*);
+
+ // Resets some static variable state.
+ void reset();
+
+ // Simulate drag&drop system call.
+ static void doDragDrop(const WebKit::WebPoint&,
+ const WebKit::WebDragData&,
+ WebKit::WebDragOperationsMask);
+
+ // JS callback methods.
+ void mouseDown(const CppArgumentList&, CppVariant*);
+ void mouseUp(const CppArgumentList&, CppVariant*);
+ void mouseMoveTo(const CppArgumentList&, CppVariant*);
+ void mouseWheelTo(const CppArgumentList&, CppVariant*);
+ void leapForward(const CppArgumentList&, CppVariant*);
+ void keyDown(const CppArgumentList&, CppVariant*);
+ void dispatchMessage(const CppArgumentList&, CppVariant*);
+ void textZoomIn(const CppArgumentList&, CppVariant*);
+ void textZoomOut(const CppArgumentList&, CppVariant*);
+ void zoomPageIn(const CppArgumentList&, CppVariant*);
+ void zoomPageOut(const CppArgumentList&, CppVariant*);
+ void scheduleAsynchronousClick(const CppArgumentList&, CppVariant*);
+ void beginDragWithFiles(const CppArgumentList&, CppVariant*);
+ CppVariant dragMode;
+
+ // Unimplemented stubs
+ void contextClick(const CppArgumentList&, CppVariant*);
+ 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
+
+private:
+ // Returns the test shell's webview.
+ static WebKit::WebView* webview();
+
+ // Returns true if dragMode is true.
+ bool isDragMode() { return dragMode.isBool() && dragMode.toBoolean(); }
+
+ // Sometimes we queue up mouse move and mouse up events for drag drop
+ // handling purposes. These methods dispatch the event.
+ static void doMouseMove(const WebKit::WebMouseEvent&);
+ static void doMouseUp(const WebKit::WebMouseEvent&);
+ static void doLeapForward(int milliseconds);
+ static void replaySavedEvents();
+
+ // Helper to return the button type given a button code
+ static WebKit::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 updateClickCountForButton(WebKit::WebMouseEvent::Button);
+
+ ScopedRunnableMethodFactory<EventSender> m_methodFactory;
+
+ // Non-owning pointer. The EventSender is owned by the TestShell.
+ static TestShell* testShell;
+
+ // Location of last mouseMoveTo event.
+ static WebKit::WebPoint lastMousePos;
+
+ // Currently pressed mouse button (Left/Right/Middle or None)
+ static WebKit::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 WebKit::WebMouseEvent::Button lastButtonType;
+};
+
+#endif // EventSender_h
diff --git a/WebKitTools/DumpRenderTree/chromium/ImageDiff.cpp b/WebKitTools/DumpRenderTree/chromium/ImageDiff.cpp
new file mode 100644
index 0000000..81d5f62
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/ImageDiff.cpp
@@ -0,0 +1,407 @@
+/*
+ * Copyright (C) 2010 Google 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.
+ */
+
+// This file input format is based loosely on
+// WebKitTools/DumpRenderTree/ImageDiff.m
+
+// The exact format of this tool's output to stdout is important, to match
+// what the run-webkit-tests script expects.
+
+#include "config.h"
+
+#include "gfx/codec/png_codec.h"
+#include <algorithm>
+#include <stdio.h>
+#include <string.h>
+#include <string>
+#include <vector>
+#include <wtf/OwnArrayPtr.h>
+#include <wtf/Vector.h>
+
+using namespace gfx;
+using namespace std;
+
+// Causes the app to remain open, waiting for pairs of filenames on stdin.
+// The caller is then responsible for terminating this app.
+static const char optionPollStdin[] = "--use-stdin";
+static const char optionGenerateDiff[] = "--diff";
+
+// Return codes used by this utility.
+static const int statusSame = 0;
+static const int statusDifferent = 1;
+static const int statusError = 2;
+
+// Color codes.
+static const uint32_t rgbaRed = 0x000000ff;
+static const uint32_t rgbaAlpha = 0xff000000;
+
+class Image {
+public:
+ Image()
+ : m_width(0)
+ , m_height(0) {}
+
+ Image(const Image& image)
+ : m_width(image.m_width)
+ , m_height(image.m_height)
+ , m_data(image.m_data) {}
+
+ bool hasImage() const { return m_width > 0 && m_height > 0; }
+ int width() const { return m_width; }
+ int height() const { return m_height; }
+ const unsigned char* data() const { return &m_data.front(); }
+
+ // Creates the image from stdin with the given data length. On success, it
+ // will return true. On failure, no other methods should be accessed.
+ bool craeteFromStdin(size_t byteLength)
+ {
+ if (!byteLength)
+ return false;
+
+ OwnArrayPtr<unsigned char> source(new unsigned char[byteLength]);
+ if (fread(source.get(), 1, byteLength, stdin) != byteLength)
+ return false;
+
+ if (!PNGCodec::Decode(source.get(), byteLength, PNGCodec::FORMAT_RGBA,
+ &m_data, &m_width, &m_height)) {
+ clear();
+ return false;
+ }
+ return true;
+ }
+
+ // Creates the image from the given filename on disk, and returns true on
+ // success.
+ bool createFromFilename(const char* filename)
+ {
+ FILE* f = fopen(filename, "rb");
+ if (!f)
+ return false;
+
+ vector<unsigned char> compressed;
+ const int bufSize = 1024;
+ unsigned char buf[bufSize];
+ size_t numRead = 0;
+ while ((numRead = fread(buf, 1, bufSize, f)) > 0)
+ std::copy(buf, &buf[numRead], std::back_inserter(compressed));
+
+ fclose(f);
+
+ if (!PNGCodec::Decode(&compressed[0], compressed.size(),
+ PNGCodec::FORMAT_RGBA, &m_data, &m_width, &m_height)) {
+ clear();
+ return false;
+ }
+ return true;
+ }
+
+ void clear()
+ {
+ m_width = m_height = 0;
+ m_data.clear();
+ }
+
+ // Returns the RGBA value of the pixel at the given location
+ const uint32_t pixelAt(int x, int y) const
+ {
+ ASSERT(x >= 0 && x < m_width);
+ ASSERT(y >= 0 && y < m_height);
+ return *reinterpret_cast<const uint32_t*>(&(m_data[(y * m_width + x) * 4]));
+ }
+
+ void setPixelAt(int x, int y, uint32_t color) const
+ {
+ ASSERT(x >= 0 && x < m_width);
+ ASSERT(y >= 0 && y < m_height);
+ void* addr = &const_cast<unsigned char*>(&m_data.front())[(y * m_width + x) * 4];
+ *reinterpret_cast<uint32_t*>(addr) = color;
+ }
+
+private:
+ // pixel dimensions of the image
+ int m_width, m_height;
+
+ vector<unsigned char> m_data;
+};
+
+float percentageDifferent(const Image& baseline, const Image& actual)
+{
+ int w = min(baseline.width(), actual.width());
+ int h = min(baseline.height(), actual.height());
+
+ // Compute pixels different in the overlap
+ int pixelsDifferent = 0;
+ for (int y = 0; y < h; y++) {
+ for (int x = 0; x < w; x++) {
+ if (baseline.pixelAt(x, y) != actual.pixelAt(x, y))
+ pixelsDifferent++;
+ }
+ }
+
+ // Count pixels that are a difference in size as also being different
+ int maxWidth = max(baseline.width(), actual.width());
+ int maxHeight = max(baseline.height(), actual.height());
+
+ // ...pixels off the right side, but not including the lower right corner
+ pixelsDifferent += (maxWidth - w) * h;
+
+ // ...pixels along the bottom, including the lower right corner
+ pixelsDifferent += (maxHeight - h) * maxWidth;
+
+ // Like the WebKit ImageDiff tool, we define percentage different in terms
+ // of the size of the 'actual' bitmap.
+ float totalPixels = static_cast<float>(actual.width()) * static_cast<float>(actual.height());
+ if (!totalPixels)
+ return 100.0f; // When the bitmap is empty, they are 100% different.
+ return static_cast<float>(pixelsDifferent) / totalPixels * 100;
+}
+
+void printHelp()
+{
+ fprintf(stderr,
+ "Usage:\n"
+ " ImageDiff <compare file> <reference file>\n"
+ " Compares two files on disk, returning 0 when they are the same\n"
+ " ImageDiff --use-stdin\n"
+ " Stays open reading pairs of filenames from stdin, comparing them,\n"
+ " and sending 0 to stdout when they are the same\n"
+ " ImageDiff --diff <compare file> <reference file> <output file>\n"
+ " Compares two files on disk, outputs an image that visualizes the"
+ " difference to <output file>\n");
+ /* For unfinished webkit-like-mode (see below)
+ "\n"
+ " ImageDiff -s\n"
+ " Reads stream input from stdin, should be EXACTLY of the format\n"
+ " \"Content-length: <byte length> <data>Content-length: ...\n"
+ " it will take as many file pairs as given, and will compare them as\n"
+ " (cmp_file, reference_file) pairs\n");
+ */
+}
+
+int compareImages(const char* file1, const char* file2)
+{
+ Image actualImage;
+ Image baselineImage;
+
+ if (!actualImage.createFromFilename(file1)) {
+ fprintf(stderr, "ImageDiff: Unable to open file \"%s\"\n", file1);
+ return statusError;
+ }
+ if (!baselineImage.createFromFilename(file2)) {
+ fprintf(stderr, "ImageDiff: Unable to open file \"%s\"\n", file2);
+ return statusError;
+ }
+
+ float percent = percentageDifferent(actualImage, baselineImage);
+ if (percent > 0.0) {
+ // failure: The WebKit version also writes the difference image to
+ // stdout, which seems excessive for our needs.
+ printf("diff: %01.2f%% failed\n", percent);
+ return statusDifferent;
+ }
+
+ // success
+ printf("diff: %01.2f%% passed\n", percent);
+ return statusSame;
+
+}
+
+// Untested mode that acts like WebKit's image comparator. I wrote this but
+// decided it's too complicated. We may use it in the future if it looks useful.
+int untestedCompareImages()
+{
+ Image actualImage;
+ Image baselineImage;
+ char buffer[2048];
+ while (fgets(buffer, sizeof(buffer), stdin)) {
+ if (!strncmp("Content-length: ", buffer, 16)) {
+ char* context;
+#if OS(WINDOWS)
+ strtok_s(buffer, " ", &context);
+ int imageSize = strtol(strtok_s(0, " ", &context), 0, 10);
+#else
+ strtok_r(buffer, " ", &context);
+ int imageSize = strtol(strtok_r(0, " ", &context), 0, 10);
+#endif
+
+ bool success = false;
+ if (imageSize > 0 && !actualImage.hasImage()) {
+ if (!actualImage.craeteFromStdin(imageSize)) {
+ fputs("Error, input image can't be decoded.\n", stderr);
+ return 1;
+ }
+ } else if (imageSize > 0 && !baselineImage.hasImage()) {
+ if (!baselineImage.craeteFromStdin(imageSize)) {
+ fputs("Error, baseline image can't be decoded.\n", stderr);
+ return 1;
+ }
+ } else {
+ fputs("Error, image size must be specified.\n", stderr);
+ return 1;
+ }
+ }
+
+ if (actualImage.hasImage() && baselineImage.hasImage()) {
+ float percent = percentageDifferent(actualImage, baselineImage);
+ if (percent > 0.0) {
+ // failure: The WebKit version also writes the difference image to
+ // stdout, which seems excessive for our needs.
+ printf("diff: %01.2f%% failed\n", percent);
+ } else {
+ // success
+ printf("diff: %01.2f%% passed\n", percent);
+ }
+ actualImage.clear();
+ baselineImage.clear();
+ }
+ fflush(stdout);
+ }
+ return 0;
+}
+
+bool createImageDiff(const Image& image1, const Image& image2, Image* out)
+{
+ int w = min(image1.width(), image2.width());
+ int h = min(image1.height(), image2.height());
+ *out = Image(image1);
+ bool same = (image1.width() == image2.width()) && (image1.height() == image2.height());
+
+ // FIXME: do something with the extra pixels if the image sizes are different.
+ for (int y = 0; y < h; y++) {
+ for (int x = 0; x < w; x++) {
+ uint32_t basePixel = image1.pixelAt(x, y);
+ if (basePixel != image2.pixelAt(x, y)) {
+ // Set differing pixels red.
+ out->setPixelAt(x, y, rgbaRed | rgbaAlpha);
+ same = false;
+ } else {
+ // Set same pixels as faded.
+ uint32_t alpha = basePixel & rgbaAlpha;
+ uint32_t newPixel = basePixel - ((alpha / 2) & rgbaAlpha);
+ out->setPixelAt(x, y, newPixel);
+ }
+ }
+ }
+
+ return same;
+}
+
+static bool writeFile(const char* outFile, const unsigned char* data, size_t dataSize)
+{
+ FILE* file = fopen(outFile, "wb");
+ if (!file) {
+ fprintf(stderr, "ImageDiff: Unable to create file \"%s\"\n", file);
+ return false;
+ }
+ if (dataSize != fwrite(data, 1, dataSize, file)) {
+ fclose(file);
+ fprintf(stderr, "ImageDiff: Unable to write data to file \"%s\"\n", file);
+ return false;
+ }
+ fclose(file);
+ return true;
+}
+
+int diffImages(const char* file1, const char* file2, const char* outFile)
+{
+ Image actualImage;
+ Image baselineImage;
+
+ if (!actualImage.createFromFilename(file1)) {
+ fprintf(stderr, "ImageDiff: Unable to open file \"%s\"\n", file1);
+ return statusError;
+ }
+ if (!baselineImage.createFromFilename(file2)) {
+ fprintf(stderr, "ImageDiff: Unable to open file \"%s\"\n", file2);
+ return statusError;
+ }
+
+ Image diffImage;
+ bool same = createImageDiff(baselineImage, actualImage, &diffImage);
+ if (same)
+ return statusSame;
+
+ vector<unsigned char> pngData;
+ PNGCodec::Encode(diffImage.data(), PNGCodec::FORMAT_RGBA, diffImage.width(),
+ diffImage.height(), diffImage.width() * 4, false, &pngData);
+ if (!writeFile(outFile, &pngData.front(), pngData.size()))
+ return statusError;
+ return statusDifferent;
+}
+
+int main(int argc, const char* argv[])
+{
+ Vector<const char*> values;
+ bool pollStdin = false;
+ bool generateDiff = false;
+ for (int i = 1; i < argc; ++i) {
+ if (!strcmp(argv[i], optionPollStdin))
+ pollStdin = true;
+ else if (!strcmp(argv[i], optionGenerateDiff))
+ generateDiff = true;
+ else
+ values.append(argv[i]);
+ }
+
+ if (pollStdin) {
+ // Watch stdin for filenames.
+ const size_t bufferSize = PATH_MAX;
+ char stdinBuffer[bufferSize];
+ char firstName[bufferSize];
+ bool haveFirstName = false;
+ while (fgets(stdinBuffer, bufferSize, stdin)) {
+ if (!stdinBuffer[0])
+ continue;
+
+ if (haveFirstName) {
+ // compareImages writes results to stdout unless an error occurred.
+ if (compareImages(firstName, stdinBuffer) == statusError)
+ printf("error\n");
+ fflush(stdout);
+ haveFirstName = false;
+ } else {
+ // Save the first filename in another buffer and wait for the second
+ // filename to arrive via stdin.
+ strcpy(firstName, stdinBuffer);
+ haveFirstName = true;
+ }
+ }
+ return 0;
+ }
+
+ if (generateDiff) {
+ if (values.size() == 3)
+ return diffImages(values[0], values[1], values[2]);
+ } else if (values.size() == 2)
+ return compareImages(argv[1], argv[2]);
+
+ printHelp();
+ return statusError;
+}
diff --git a/WebKitTools/DumpRenderTree/chromium/LayoutTestController.cpp b/WebKitTools/DumpRenderTree/chromium/LayoutTestController.cpp
new file mode 100644
index 0000000..d0dca69
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/LayoutTestController.cpp
@@ -0,0 +1,1179 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2010 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.
+ */
+
+#include "config.h"
+#include "LayoutTestController.h"
+
+#include "TestShell.h"
+#include "WebViewHost.h"
+#include "base/string_util.h"
+#include "public/WebAnimationController.h"
+#include "public/WebConsoleMessage.h"
+#include "public/WebDocument.h"
+#include "public/WebFrame.h"
+#include "public/WebInputElement.h"
+#include "public/WebKit.h"
+#include "public/WebScriptSource.h"
+#include "public/WebSecurityPolicy.h"
+#include "public/WebSettings.h"
+#include "public/WebSize.h"
+#include "public/WebURL.h"
+#include "public/WebView.h"
+#include "webkit/support/webkit_support.h"
+
+#if OS(WINDOWS)
+#include <wtf/OwnArrayPtr.h>
+#endif
+
+using namespace WebKit;
+using namespace std;
+
+LayoutTestController::LayoutTestController(TestShell* shell)
+ : m_timeoutFactory(this)
+ , m_shell(shell)
+ , m_workQueue(this)
+{
+
+ // 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 LayoutTestController).
+ bindMethod("dumpAsText", &LayoutTestController::dumpAsText);
+ bindMethod("dumpChildFrameScrollPositions", &LayoutTestController::dumpChildFrameScrollPositions);
+ bindMethod("dumpChildFramesAsText", &LayoutTestController::dumpChildFramesAsText);
+ bindMethod("dumpDatabaseCallbacks", &LayoutTestController::dumpDatabaseCallbacks);
+ bindMethod("dumpEditingCallbacks", &LayoutTestController::dumpEditingCallbacks);
+ bindMethod("dumpBackForwardList", &LayoutTestController::dumpBackForwardList);
+ bindMethod("dumpFrameLoadCallbacks", &LayoutTestController::dumpFrameLoadCallbacks);
+ bindMethod("dumpResourceLoadCallbacks", &LayoutTestController::dumpResourceLoadCallbacks);
+ bindMethod("dumpStatusCallbacks", &LayoutTestController::dumpWindowStatusChanges);
+ bindMethod("dumpTitleChanges", &LayoutTestController::dumpTitleChanges);
+ bindMethod("setAcceptsEditing", &LayoutTestController::setAcceptsEditing);
+ bindMethod("waitUntilDone", &LayoutTestController::waitUntilDone);
+ bindMethod("notifyDone", &LayoutTestController::notifyDone);
+ bindMethod("queueReload", &LayoutTestController::queueReload);
+ bindMethod("queueLoadingScript", &LayoutTestController::queueLoadingScript);
+ bindMethod("queueNonLoadingScript", &LayoutTestController::queueNonLoadingScript);
+ bindMethod("queueLoad", &LayoutTestController::queueLoad);
+ bindMethod("queueBackNavigation", &LayoutTestController::queueBackNavigation);
+ bindMethod("queueForwardNavigation", &LayoutTestController::queueForwardNavigation);
+ bindMethod("windowCount", &LayoutTestController::windowCount);
+ bindMethod("setCanOpenWindows", &LayoutTestController::setCanOpenWindows);
+ bindMethod("setCloseRemainingWindowsWhenComplete", &LayoutTestController::setCloseRemainingWindowsWhenComplete);
+ bindMethod("objCIdentityIsEqual", &LayoutTestController::objCIdentityIsEqual);
+ bindMethod("setAlwaysAcceptCookies", &LayoutTestController::setAlwaysAcceptCookies);
+ bindMethod("setWindowIsKey", &LayoutTestController::setWindowIsKey);
+ bindMethod("setTabKeyCyclesThroughElements", &LayoutTestController::setTabKeyCyclesThroughElements);
+ bindMethod("setUserStyleSheetLocation", &LayoutTestController::setUserStyleSheetLocation);
+ bindMethod("setUserStyleSheetEnabled", &LayoutTestController::setUserStyleSheetEnabled);
+ bindMethod("pathToLocalResource", &LayoutTestController::pathToLocalResource);
+ bindMethod("addFileToPasteboardOnDrag", &LayoutTestController::addFileToPasteboardOnDrag);
+ bindMethod("execCommand", &LayoutTestController::execCommand);
+ bindMethod("isCommandEnabled", &LayoutTestController::isCommandEnabled);
+ bindMethod("setPopupBlockingEnabled", &LayoutTestController::setPopupBlockingEnabled);
+ bindMethod("setStopProvisionalFrameLoads", &LayoutTestController::setStopProvisionalFrameLoads);
+ bindMethod("setSmartInsertDeleteEnabled", &LayoutTestController::setSmartInsertDeleteEnabled);
+ bindMethod("setSelectTrailingWhitespaceEnabled", &LayoutTestController::setSelectTrailingWhitespaceEnabled);
+ bindMethod("pauseAnimationAtTimeOnElementWithId", &LayoutTestController::pauseAnimationAtTimeOnElementWithId);
+ bindMethod("pauseTransitionAtTimeOnElementWithId", &LayoutTestController::pauseTransitionAtTimeOnElementWithId);
+ bindMethod("elementDoesAutoCompleteForElementWithId", &LayoutTestController::elementDoesAutoCompleteForElementWithId);
+ bindMethod("numberOfActiveAnimations", &LayoutTestController::numberOfActiveAnimations);
+ bindMethod("disableImageLoading", &LayoutTestController::disableImageLoading);
+ bindMethod("setIconDatabaseEnabled", &LayoutTestController::setIconDatabaseEnabled);
+ bindMethod("setCustomPolicyDelegate", &LayoutTestController::setCustomPolicyDelegate);
+ bindMethod("waitForPolicyDelegate", &LayoutTestController::waitForPolicyDelegate);
+ bindMethod("setWillSendRequestReturnsNullOnRedirect", &LayoutTestController::setWillSendRequestReturnsNullOnRedirect);
+ bindMethod("setWillSendRequestReturnsNull", &LayoutTestController::setWillSendRequestReturnsNull);
+ bindMethod("addOriginAccessWhitelistEntry", &LayoutTestController::addOriginAccessWhitelistEntry);
+ bindMethod("clearAllDatabases", &LayoutTestController::clearAllDatabases);
+ bindMethod("setDatabaseQuota", &LayoutTestController::setDatabaseQuota);
+ bindMethod("setPOSIXLocale", &LayoutTestController::setPOSIXLocale);
+ bindMethod("counterValueForElementById", &LayoutTestController::counterValueForElementById);
+ bindMethod("addUserScript", &LayoutTestController::addUserScript);
+ bindMethod("pageNumberForElementById", &LayoutTestController::pageNumberForElementById);
+ bindMethod("numberOfPages", &LayoutTestController::numberOfPages);
+ bindMethod("dumpSelectionRect", &LayoutTestController::dumpSelectionRect);
+
+ // The following are stubs.
+ bindMethod("dumpAsWebArchive", &LayoutTestController::dumpAsWebArchive);
+ bindMethod("setMainFrameIsFirstResponder", &LayoutTestController::setMainFrameIsFirstResponder);
+ bindMethod("dumpSelectionRect", &LayoutTestController::dumpSelectionRect);
+ bindMethod("display", &LayoutTestController::display);
+ bindMethod("testRepaint", &LayoutTestController::testRepaint);
+ bindMethod("repaintSweepHorizontally", &LayoutTestController::repaintSweepHorizontally);
+ bindMethod("clearBackForwardList", &LayoutTestController::clearBackForwardList);
+ bindMethod("keepWebHistory", &LayoutTestController::keepWebHistory);
+ bindMethod("storeWebScriptObject", &LayoutTestController::storeWebScriptObject);
+ bindMethod("accessStoredWebScriptObject", &LayoutTestController::accessStoredWebScriptObject);
+ bindMethod("objCClassNameOf", &LayoutTestController::objCClassNameOf);
+ bindMethod("addDisallowedURL", &LayoutTestController::addDisallowedURL);
+ bindMethod("setCallCloseOnWebViews", &LayoutTestController::setCallCloseOnWebViews);
+ bindMethod("setPrivateBrowsingEnabled", &LayoutTestController::setPrivateBrowsingEnabled);
+ bindMethod("setUseDashboardCompatibilityMode", &LayoutTestController::setUseDashboardCompatibilityMode);
+
+ bindMethod("setXSSAuditorEnabled", &LayoutTestController::setXSSAuditorEnabled);
+ bindMethod("evaluateScriptInIsolatedWorld", &LayoutTestController::evaluateScriptInIsolatedWorld);
+ bindMethod("overridePreference", &LayoutTestController::overridePreference);
+ bindMethod("setAllowUniversalAccessFromFileURLs", &LayoutTestController::setAllowUniversalAccessFromFileURLs);
+ bindMethod("setAllowFileAccessFromFileURLs", &LayoutTestController::setAllowFileAccessFromFileURLs);
+ bindMethod("setTimelineProfilingEnabled", &LayoutTestController::setTimelineProfilingEnabled);
+ bindMethod("evaluateInWebInspector", &LayoutTestController::evaluateInWebInspector);
+ bindMethod("forceRedSelectionColors", &LayoutTestController::forceRedSelectionColors);
+
+ // The fallback method is called when an unknown method is invoked.
+ bindFallbackMethod(&LayoutTestController::fallbackMethod);
+
+ // Shared properties.
+ // globalFlag is used by a number of layout tests in
+ // LayoutTests\http\tests\security\dataURL.
+ bindProperty("globalFlag", &m_globalFlag);
+ // webHistoryItemCount is used by tests in LayoutTests\http\tests\history
+ bindProperty("webHistoryItemCount", &m_webHistoryItemCount);
+}
+
+LayoutTestController::WorkQueue::~WorkQueue()
+{
+ reset();
+}
+
+void LayoutTestController::WorkQueue::processWorkSoon()
+{
+ if (m_controller->m_shell->webViewHost()->topLoadingFrame())
+ return;
+
+ if (!m_queue.isEmpty()) {
+ // We delay processing queued work to avoid recursion problems.
+ m_timer.Start(base::TimeDelta(), this, &WorkQueue::processWork);
+ } else if (!m_controller->m_waitUntilDone) {
+ m_controller->m_shell->testFinished();
+ }
+}
+
+void LayoutTestController::WorkQueue::processWork()
+{
+ TestShell* shell = m_controller->m_shell;
+ // Quit doing work once a load is in progress.
+ while (!m_queue.isEmpty()) {
+ bool startedLoad = m_queue.first()->run(shell);
+ delete m_queue.first();
+ m_queue.removeFirst();
+ if (startedLoad)
+ return;
+ }
+
+ if (!m_controller->m_waitUntilDone && !shell->webViewHost()->topLoadingFrame())
+ shell->testFinished();
+}
+
+void LayoutTestController::WorkQueue::reset()
+{
+ m_frozen = false;
+ while (!m_queue.isEmpty()) {
+ delete m_queue.first();
+ m_queue.removeFirst();
+ }
+}
+
+void LayoutTestController::WorkQueue::addWork(WorkItem* work)
+{
+ if (m_frozen) {
+ delete work;
+ return;
+ }
+ m_queue.append(work);
+}
+
+void LayoutTestController::dumpAsText(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpAsText = true;
+ result->setNull();
+}
+
+void LayoutTestController::dumpDatabaseCallbacks(const CppArgumentList&, CppVariant* result)
+{
+ // Do nothing; we don't use this flag anywhere for now
+ result->setNull();
+}
+
+void LayoutTestController::dumpEditingCallbacks(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpEditingCallbacks = true;
+ result->setNull();
+}
+
+void LayoutTestController::dumpBackForwardList(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpBackForwardList = true;
+ result->setNull();
+}
+
+void LayoutTestController::dumpFrameLoadCallbacks(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpFrameLoadCallbacks = true;
+ result->setNull();
+}
+
+void LayoutTestController::dumpResourceLoadCallbacks(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpResourceLoadCallbacks = true;
+ result->setNull();
+}
+
+void LayoutTestController::dumpChildFrameScrollPositions(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpChildFrameScrollPositions = true;
+ result->setNull();
+}
+
+void LayoutTestController::dumpChildFramesAsText(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpChildFramesAsText = true;
+ result->setNull();
+}
+
+void LayoutTestController::dumpWindowStatusChanges(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpWindowStatusChanges = true;
+ result->setNull();
+}
+
+void LayoutTestController::dumpTitleChanges(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpTitleChanges = true;
+ result->setNull();
+}
+
+void LayoutTestController::setAcceptsEditing(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_acceptsEditing = arguments[0].value.boolValue;
+ result->setNull();
+}
+
+void LayoutTestController::waitUntilDone(const CppArgumentList&, CppVariant* result)
+{
+ if (!webkit_support::BeingDebugged()) {
+ webkit_support::PostDelayedTaskFromHere(
+ m_timeoutFactory.NewRunnableMethod(&LayoutTestController::notifyDoneTimedOut),
+ m_shell->layoutTestTimeout());
+ }
+ m_waitUntilDone = true;
+ result->setNull();
+}
+
+void LayoutTestController::notifyDone(const CppArgumentList&, CppVariant* result)
+{
+ // Test didn't timeout. Kill the timeout timer.
+ m_timeoutFactory.RevokeAll();
+
+ completeNotifyDone(false);
+ result->setNull();
+}
+
+void LayoutTestController::notifyDoneTimedOut()
+{
+ completeNotifyDone(true);
+}
+
+void LayoutTestController::completeNotifyDone(bool isTimeout)
+{
+ if (m_waitUntilDone && !m_shell->webViewHost()->topLoadingFrame() && m_workQueue.isEmpty()) {
+ if (isTimeout)
+ m_shell->testTimedOut();
+ else
+ m_shell->testFinished();
+ }
+ m_waitUntilDone = false;
+}
+
+class WorkItemBackForward : public LayoutTestController::WorkItem {
+public:
+ WorkItemBackForward(int distance) : m_distance(distance) {}
+ bool run(TestShell* shell)
+ {
+ shell->goToOffset(m_distance);
+ return true; // FIXME: Did it really start a navigation?
+ }
+private:
+ int m_distance;
+};
+
+void LayoutTestController::queueBackNavigation(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isNumber())
+ m_workQueue.addWork(new WorkItemBackForward(-arguments[0].toInt32()));
+ result->setNull();
+}
+
+void LayoutTestController::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 LayoutTestController::WorkItem {
+public:
+ bool run(TestShell* shell)
+ {
+ shell->reload();
+ return true;
+ }
+};
+
+void LayoutTestController::queueReload(const CppArgumentList&, CppVariant* result)
+{
+ m_workQueue.addWork(new WorkItemReload);
+ result->setNull();
+}
+
+class WorkItemLoadingScript : public LayoutTestController::WorkItem {
+public:
+ WorkItemLoadingScript(const string& script) : m_script(script) {}
+ bool run(TestShell* shell)
+ {
+ shell->webView()->mainFrame()->executeScript(WebScriptSource(WebString::fromUTF8(m_script)));
+ return true; // FIXME: Did it really start a navigation?
+ }
+private:
+ string m_script;
+};
+
+class WorkItemNonLoadingScript : public LayoutTestController::WorkItem {
+public:
+ WorkItemNonLoadingScript(const string& script) : m_script(script) {}
+ bool run(TestShell* shell)
+ {
+ shell->webView()->mainFrame()->executeScript(WebScriptSource(WebString::fromUTF8(m_script)));
+ return false;
+ }
+private:
+ string m_script;
+};
+
+void LayoutTestController::queueLoadingScript(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isString())
+ m_workQueue.addWork(new WorkItemLoadingScript(arguments[0].toString()));
+ result->setNull();
+}
+
+void LayoutTestController::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 LayoutTestController::WorkItem {
+public:
+ WorkItemLoad(const WebURL& url, const WebString& target)
+ : m_url(url)
+ , m_target(target) {}
+ bool run(TestShell* shell)
+ {
+ shell->webViewHost()->loadURLForFrame(m_url, m_target);
+ return true; // FIXME: Did it really start a navigation?
+ }
+private:
+ WebURL m_url;
+ WebString m_target;
+};
+
+void LayoutTestController::queueLoad(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isString()) {
+ // FIXME: Implement WebURL::resolve() and avoid GURL.
+ GURL currentURL = m_shell->webView()->mainFrame()->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, WebString::fromUTF8(target)));
+ }
+ result->setNull();
+}
+
+void LayoutTestController::objCIdentityIsEqual(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() < 2) {
+ // This is the best we can do to return an error.
+ result->setNull();
+ return;
+ }
+ result->set(arguments[0].isEqual(arguments[1]));
+}
+
+void LayoutTestController::reset()
+{
+ if (m_shell) {
+ m_shell->webView()->setZoomLevel(false, 0);
+ m_shell->webView()->setTabKeyCyclesThroughElements(true);
+#if defined(OS_LINUX)
+ // (Constants copied because we can't depend on the header that defined
+ // them from this file.)
+ m_shell->webView()->setSelectionColors(0xff1e90ff, 0xff000000, 0xffc8c8c8, 0xff323232);
+#endif // defined(OS_LINUX)
+ m_shell->webView()->removeAllUserContent();
+ }
+ m_dumpAsText = false;
+ m_dumpEditingCallbacks = false;
+ m_dumpFrameLoadCallbacks = false;
+ m_dumpResourceLoadCallbacks = false;
+ m_dumpBackForwardList = false;
+ m_dumpChildFrameScrollPositions = false;
+ m_dumpChildFramesAsText = false;
+ m_dumpWindowStatusChanges = false;
+ m_dumpSelectionRect = false;
+ m_dumpTitleChanges = false;
+ m_acceptsEditing = true;
+ m_waitUntilDone = false;
+ m_canOpenWindows = false;
+ m_testRepaint = false;
+ m_sweepHorizontally = false;
+ m_shouldAddFileToPasteboard = false;
+ m_stopProvisionalFrameLoads = false;
+ m_globalFlag.set(false);
+ m_webHistoryItemCount.set(0);
+
+ webkit_support::SetAcceptAllCookies(false);
+ WebSecurityPolicy::resetOriginAccessWhiteLists();
+
+ // Reset the default quota for each origin to 5MB
+ webkit_support::SetDatabaseQuota(5 * 1024 * 1024);
+
+ setlocale(LC_ALL, "");
+
+ if (m_closeRemainingWindows)
+ m_shell->closeRemainingWindows();
+ else
+ m_closeRemainingWindows = true;
+ m_workQueue.reset();
+}
+
+void LayoutTestController::locationChangeDone()
+{
+ m_webHistoryItemCount.set(m_shell->navigationEntryCount());
+
+ // No more new work after the first complete load.
+ m_workQueue.setFrozen(true);
+
+ if (!m_waitUntilDone)
+ m_workQueue.processWorkSoon();
+}
+
+void LayoutTestController::policyDelegateDone()
+{
+ ASSERT(m_waitUntilDone);
+ m_shell->testFinished();
+ m_waitUntilDone = false;
+}
+
+void LayoutTestController::setCanOpenWindows(const CppArgumentList&, CppVariant* result)
+{
+ m_canOpenWindows = true;
+ result->setNull();
+}
+
+void LayoutTestController::setTabKeyCyclesThroughElements(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_shell->webView()->setTabKeyCyclesThroughElements(arguments[0].toBoolean());
+ result->setNull();
+}
+
+void LayoutTestController::windowCount(const CppArgumentList&, CppVariant* result)
+{
+ result->set(static_cast<int>(m_shell->windowCount()));
+}
+
+void LayoutTestController::setCloseRemainingWindowsWhenComplete(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_closeRemainingWindows = arguments[0].value.boolValue;
+ result->setNull();
+}
+
+void LayoutTestController::setAlwaysAcceptCookies(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0)
+ webkit_support::SetAcceptAllCookies(cppVariantToBool(arguments[0]));
+ result->setNull();
+}
+
+void LayoutTestController::setWindowIsKey(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_shell->setFocus(m_shell->webView(), arguments[0].value.boolValue);
+ result->setNull();
+}
+
+void LayoutTestController::setUserStyleSheetEnabled(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_shell->webView()->settings()->setUserStyleSheetLocation(arguments[0].value.boolValue ? m_userStyleSheetLocation : WebURL());
+ result->setNull();
+}
+
+void LayoutTestController::setUserStyleSheetLocation(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isString()) {
+ m_userStyleSheetLocation = webkit_support::RewriteLayoutTestsURL(arguments[0].toString());
+ m_shell->webView()->settings()->setUserStyleSheetLocation(m_userStyleSheetLocation);
+ }
+ result->setNull();
+}
+
+void LayoutTestController::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_shell->webView()->focusedFrame()->executeCommand(WebString::fromUTF8(command), WebString::fromUTF8(value));
+}
+
+void LayoutTestController::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_shell->webView()->focusedFrame()->isCommandEnabled(WebString::fromUTF8(command));
+ result->set(rv);
+}
+
+void LayoutTestController::setPopupBlockingEnabled(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool()) {
+ bool blockPopups = arguments[0].toBoolean();
+ m_shell->webView()->settings()->setJavaScriptCanOpenWindowsAutomatically(!blockPopups);
+ }
+ result->setNull();
+}
+
+void LayoutTestController::setUseDashboardCompatibilityMode(const CppArgumentList&, CppVariant* result)
+{
+ // We have no need to support Dashboard Compatibility Mode (mac-only)
+ result->setNull();
+}
+
+void LayoutTestController::setCustomPolicyDelegate(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool()) {
+ bool enable = arguments[0].value.boolValue;
+ bool permissive = false;
+ if (arguments.size() > 1 && arguments[1].isBool())
+ permissive = arguments[1].value.boolValue;
+ m_shell->webViewHost()->setCustomPolicyDelegate(enable, permissive);
+ }
+ result->setNull();
+}
+
+void LayoutTestController::waitForPolicyDelegate(const CppArgumentList&, CppVariant* result)
+{
+ m_shell->webViewHost()->waitForPolicyDelegate();
+ m_waitUntilDone = true;
+ result->setNull();
+}
+
+void LayoutTestController::setWillSendRequestReturnsNullOnRedirect(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_shell->webViewHost()->setBlockRedirects(arguments[0].value.boolValue);
+ result->setNull();
+}
+
+void LayoutTestController::setWillSendRequestReturnsNull(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_shell->webViewHost()->setRequestReturnNull(arguments[0].value.boolValue);
+ result->setNull();
+}
+
+void LayoutTestController::pathToLocalResource(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() <= 0 || !arguments[0].isString())
+ return;
+
+ string url = arguments[0].toString();
+#if OS(WINDOWS)
+ if (StartsWithASCII(url, "/tmp/", true)) {
+ // We want a temp file.
+ const unsigned tempPrefixLength = 5;
+ size_t bufferSize = MAX_PATH;
+ OwnArrayPtr<WCHAR> tempPath(new WCHAR[bufferSize]);
+ DWORD tempLength = ::GetTempPathW(bufferSize, tempPath.get());
+ if (tempLength + url.length() - tempPrefixLength + 1 > bufferSize) {
+ bufferSize = tempLength + url.length() - tempPrefixLength + 1;
+ tempPath.set(new WCHAR[bufferSize]);
+ tempLength = GetTempPathW(bufferSize, tempPath.get());
+ ASSERT(tempLength < bufferSize);
+ }
+ std::string resultPath(WebString(tempPath.get(), tempLength).utf8());
+ resultPath.append(url.substr(tempPrefixLength));
+ result->set(resultPath);
+ return;
+ }
+#endif
+
+ // Some layout tests use file://// which we resolve as a UNC path. Normalize
+ // them to just file:///.
+ while (StartsWithASCII(url, "file:////", false))
+ url = url.substr(0, 8) + url.substr(9);
+ result->set(webkit_support::RewriteLayoutTestsURL(url).spec());
+}
+
+void LayoutTestController::addFileToPasteboardOnDrag(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+ m_shouldAddFileToPasteboard = true;
+}
+
+void LayoutTestController::setStopProvisionalFrameLoads(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+ m_stopProvisionalFrameLoads = true;
+}
+
+void LayoutTestController::setSmartInsertDeleteEnabled(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_shell->webViewHost()->setSmartInsertDeleteEnabled(arguments[0].value.boolValue);
+ result->setNull();
+}
+
+void LayoutTestController::setSelectTrailingWhitespaceEnabled(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_shell->webViewHost()->setSelectTrailingWhitespaceEnabled(arguments[0].value.boolValue);
+ result->setNull();
+}
+
+bool LayoutTestController::pauseAnimationAtTimeOnElementWithId(const WebString& animationName, double time, const WebString& elementId)
+{
+ WebFrame* webFrame = m_shell->webView()->mainFrame();
+ if (!webFrame)
+ return false;
+
+ WebAnimationController* controller = webFrame->animationController();
+ if (!controller)
+ return false;
+
+ WebElement element = webFrame->document().getElementById(elementId);
+ if (element.isNull())
+ return false;
+ return controller->pauseAnimationAtTime(element, animationName, time);
+}
+
+bool LayoutTestController::pauseTransitionAtTimeOnElementWithId(const WebString& propertyName, double time, const WebString& elementId)
+{
+ WebFrame* webFrame = m_shell->webView()->mainFrame();
+ if (!webFrame)
+ return false;
+
+ WebAnimationController* controller = webFrame->animationController();
+ if (!controller)
+ return false;
+
+ WebElement element = webFrame->document().getElementById(elementId);
+ if (element.isNull())
+ return false;
+ return controller->pauseTransitionAtTime(element, propertyName, time);
+}
+
+bool LayoutTestController::elementDoesAutoCompleteForElementWithId(const WebString& elementId)
+{
+ WebFrame* webFrame = m_shell->webView()->mainFrame();
+ if (!webFrame)
+ return false;
+
+ WebElement element = webFrame->document().getElementById(elementId);
+ if (element.isNull() || !element.hasTagName("input"))
+ return false;
+
+ WebInputElement inputElement = element.toElement<WebInputElement>();
+ return inputElement.autoComplete();
+}
+
+int LayoutTestController::numberOfActiveAnimations()
+{
+ WebFrame* webFrame = m_shell->webView()->mainFrame();
+ if (!webFrame)
+ return -1;
+
+ WebAnimationController* controller = webFrame->animationController();
+ if (!controller)
+ return -1;
+
+ return controller->numberOfActiveAnimations();
+}
+
+void LayoutTestController::pauseAnimationAtTimeOnElementWithId(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->set(false);
+ if (arguments.size() > 2 && arguments[0].isString() && arguments[1].isNumber() && arguments[2].isString()) {
+ WebString animationName = cppVariantToWebString(arguments[0]);
+ double time = arguments[1].toDouble();
+ WebString elementId = cppVariantToWebString(arguments[2]);
+ result->set(pauseAnimationAtTimeOnElementWithId(animationName, time, elementId));
+ }
+}
+
+void LayoutTestController::pauseTransitionAtTimeOnElementWithId(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->set(false);
+ if (arguments.size() > 2 && arguments[0].isString() && arguments[1].isNumber() && arguments[2].isString()) {
+ WebString propertyName = cppVariantToWebString(arguments[0]);
+ double time = arguments[1].toDouble();
+ WebString elementId = cppVariantToWebString(arguments[2]);
+ result->set(pauseTransitionAtTimeOnElementWithId(propertyName, time, elementId));
+ }
+}
+
+void LayoutTestController::elementDoesAutoCompleteForElementWithId(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() != 1 || !arguments[0].isString()) {
+ result->set(false);
+ return;
+ }
+ WebString elementId = cppVariantToWebString(arguments[0]);
+ result->set(elementDoesAutoCompleteForElementWithId(elementId));
+}
+
+void LayoutTestController::numberOfActiveAnimations(const CppArgumentList&, CppVariant* result)
+{
+ result->set(numberOfActiveAnimations());
+}
+
+void LayoutTestController::disableImageLoading(const CppArgumentList&, CppVariant* result)
+{
+ m_shell->webView()->settings()->setLoadsImagesAutomatically(false);
+ result->setNull();
+}
+
+void LayoutTestController::setIconDatabaseEnabled(const CppArgumentList&, CppVariant* result)
+{
+ // We don't use the WebKit icon database.
+ result->setNull();
+}
+
+//
+// Unimplemented stubs
+//
+
+void LayoutTestController::dumpAsWebArchive(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+}
+
+void LayoutTestController::setMainFrameIsFirstResponder(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+}
+
+void LayoutTestController::dumpSelectionRect(const CppArgumentList& arguments, CppVariant* result)
+{
+ m_dumpSelectionRect = true;
+ result->setNull();
+}
+
+void LayoutTestController::display(const CppArgumentList& arguments, CppVariant* result)
+{
+ WebViewHost* host = m_shell->webViewHost();
+ const WebKit::WebSize& size = m_shell->webView()->size();
+ WebRect rect(0, 0, size.width, size.height);
+ host->updatePaintRect(rect);
+ host->paintInvalidatedRegion();
+ host->displayRepaintMask();
+ result->setNull();
+}
+
+void LayoutTestController::testRepaint(const CppArgumentList&, CppVariant* result)
+{
+ m_testRepaint = true;
+ result->setNull();
+}
+
+void LayoutTestController::repaintSweepHorizontally(const CppArgumentList&, CppVariant* result)
+{
+ m_sweepHorizontally = true;
+ result->setNull();
+}
+
+void LayoutTestController::clearBackForwardList(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+}
+
+void LayoutTestController::keepWebHistory(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+}
+
+void LayoutTestController::storeWebScriptObject(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+}
+
+void LayoutTestController::accessStoredWebScriptObject(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+}
+
+void LayoutTestController::objCClassNameOf(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+}
+
+void LayoutTestController::addDisallowedURL(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+}
+void LayoutTestController::setCallCloseOnWebViews(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+}
+
+void LayoutTestController::setPrivateBrowsingEnabled(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+}
+
+void LayoutTestController::setXSSAuditorEnabled(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_shell->webView()->settings()->setXSSAuditorEnabled(arguments[0].value.boolValue);
+ result->setNull();
+}
+
+void LayoutTestController::evaluateScriptInIsolatedWorld(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() >= 2 && arguments[0].isNumber() && arguments[1].isString()) {
+ WebScriptSource source(WebString::fromUTF8(arguments[1].toString()));
+ // 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_shell->webView()->focusedFrame()->executeScriptInIsolatedWorld(arguments[0].toInt32(), &source, 1, 1);
+ }
+ result->setNull();
+}
+
+void LayoutTestController::setAllowUniversalAccessFromFileURLs(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_shell->webView()->settings()->setAllowUniversalAccessFromFileURLs(arguments[0].value.boolValue);
+ result->setNull();
+}
+
+void LayoutTestController::setAllowFileAccessFromFileURLs(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_shell->webView()->settings()->setAllowFileAccessFromFileURLs(arguments[0].value.boolValue);
+ 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 LayoutTestController::cppVariantToBool(const CppVariant& value)
+{
+ if (value.isBool())
+ return value.toBoolean();
+ if (value.isInt32())
+ return value.toInt32();
+ if (value.isString()) {
+ string valueString = value.toString();
+ if (valueString == "true" || valueString == "1")
+ return true;
+ if (valueString == "false" || valueString == "0")
+ return false;
+ }
+ logErrorToConsole("Invalid value. Expected boolean value.");
+ return false;
+}
+
+int32_t LayoutTestController::cppVariantToInt32(const CppVariant& value)
+{
+ if (value.isInt32())
+ return value.toInt32();
+ if (value.isString()) {
+ int number;
+ if (StringToInt(value.toString(), &number))
+ return number;
+ }
+ logErrorToConsole("Invalid value for preference. Expected integer value.");
+ return 0;
+}
+
+WebString LayoutTestController::cppVariantToWebString(const CppVariant& value)
+{
+ if (!value.isString()) {
+ logErrorToConsole("Invalid value for preference. Expected string value.");
+ return WebString();
+ }
+ return WebString::fromUTF8(value.toString());
+}
+
+void LayoutTestController::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];
+ WebSettings* settings = m_shell->webView()->settings();
+ if (key == "WebKitStandardFont")
+ settings->setStandardFontFamily(cppVariantToWebString(value));
+ else if (key == "WebKitFixedFont")
+ settings->setFixedFontFamily(cppVariantToWebString(value));
+ else if (key == "WebKitSerifFont")
+ settings->setSerifFontFamily(cppVariantToWebString(value));
+ else if (key == "WebKitSansSerifFont")
+ settings->setSansSerifFontFamily(cppVariantToWebString(value));
+ else if (key == "WebKitCursiveFont")
+ settings->setCursiveFontFamily(cppVariantToWebString(value));
+ else if (key == "WebKitFantasyFont")
+ settings->setFantasyFontFamily(cppVariantToWebString(value));
+ else if (key == "WebKitDefaultFontSize")
+ settings->setDefaultFontSize(cppVariantToInt32(value));
+ else if (key == "WebKitDefaultFixedFontSize")
+ settings->setDefaultFixedFontSize(cppVariantToInt32(value));
+ else if (key == "WebKitMinimumFontSize")
+ settings->setMinimumFontSize(cppVariantToInt32(value));
+ else if (key == "WebKitMinimumLogicalFontSize")
+ settings->setMinimumLogicalFontSize(cppVariantToInt32(value));
+ else if (key == "WebKitDefaultTextEncodingName")
+ settings->setDefaultTextEncodingName(cppVariantToWebString(value));
+ else if (key == "WebKitJavaScriptEnabled")
+ settings->setJavaScriptEnabled(cppVariantToBool(value));
+ else if (key == "WebKitWebSecurityEnabled")
+ settings->setWebSecurityEnabled(cppVariantToBool(value));
+ else if (key == "WebKitJavaScriptCanOpenWindowsAutomatically")
+ settings->setJavaScriptCanOpenWindowsAutomatically(cppVariantToBool(value));
+ else if (key == "WebKitDisplayImagesKey")
+ settings->setLoadsImagesAutomatically(cppVariantToBool(value));
+ else if (key == "WebKitPluginsEnabled")
+ settings->setPluginsEnabled(cppVariantToBool(value));
+ else if (key == "WebKitDOMPasteAllowedPreferenceKey")
+ settings->setDOMPasteAllowed(cppVariantToBool(value));
+ else if (key == "WebKitDeveloperExtrasEnabledPreferenceKey")
+ settings->setDeveloperExtrasEnabled(cppVariantToBool(value));
+ else if (key == "WebKitShrinksStandaloneImagesToFit")
+ settings->setShrinksStandaloneImagesToFit(cppVariantToBool(value));
+ else if (key == "WebKitTextAreasAreResizable")
+ settings->setTextAreasAreResizable(cppVariantToBool(value));
+ else if (key == "WebKitJavaEnabled")
+ settings->setJavaEnabled(cppVariantToBool(value));
+ else if (key == "WebKitUsesPageCachePreferenceKey")
+ settings->setUsesPageCache(cppVariantToBool(value));
+ else if (key == "WebKitXSSAuditorEnabled")
+ settings->setXSSAuditorEnabled(cppVariantToBool(value));
+ else if (key == "WebKitLocalStorageEnabledPreferenceKey")
+ settings->setLocalStorageEnabled(cppVariantToBool(value));
+ else if (key == "WebKitOfflineWebApplicationCacheEnabled")
+ settings->setOfflineWebApplicationCacheEnabled(cppVariantToBool(value));
+ else if (key == "WebKitTabToLinksPreferenceKey")
+ m_shell->webView()->setTabsToLinks(cppVariantToBool(value));
+ else if (key == "WebKitWebGLEnabled")
+ settings->setExperimentalWebGLEnabled(cppVariantToBool(value));
+ else {
+ string message("Invalid name for preference: ");
+ message.append(key);
+ logErrorToConsole(message);
+ }
+}
+
+void LayoutTestController::fallbackMethod(const CppArgumentList&, CppVariant* result)
+{
+ printf("CONSOLE MESSAGE: JavaScript ERROR: unknown method called on LayoutTestController\n");
+ result->setNull();
+}
+
+void LayoutTestController::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;
+
+ WebKit::WebURL url(GURL(arguments[0].toString()));
+ if (!url.isValid())
+ return;
+
+ WebSecurityPolicy::whiteListAccessFromOrigin(url,
+ WebString::fromUTF8(arguments[1].toString()),
+ WebString::fromUTF8(arguments[2].toString()),
+ arguments[3].toBoolean());
+}
+
+void LayoutTestController::clearAllDatabases(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ webkit_support::ClearAllDatabases();
+}
+
+void LayoutTestController::setDatabaseQuota(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if ((arguments.size() >= 1) && arguments[0].isInt32())
+ webkit_support::SetDatabaseQuota(arguments[0].toInt32());
+}
+
+void LayoutTestController::setPOSIXLocale(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() == 1 && arguments[0].isString())
+ setlocale(LC_ALL, arguments[0].toString().c_str());
+}
+
+void LayoutTestController::counterValueForElementById(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 1 || !arguments[0].isString())
+ return;
+ WebFrame* frame = m_shell->webView()->mainFrame();
+ if (!frame)
+ return;
+ WebString counterValue = frame->counterValueForElementById(cppVariantToWebString(arguments[0]));
+ if (counterValue.isNull())
+ return;
+ result->set(counterValue.utf8());
+}
+
+static bool parsePageSizeParameters(const CppArgumentList& arguments,
+ int argOffset,
+ float* pageWidthInPixels,
+ float* pageHeightInPixels)
+{
+ // WebKit is using the window width/height of DumpRenderTree as the
+ // default value of the page size.
+ // FIXME: share these values with other ports.
+ *pageWidthInPixels = 800;
+ *pageHeightInPixels = 600;
+ switch (arguments.size() - argOffset) {
+ case 2:
+ if (!arguments[argOffset].isNumber() || !arguments[1 + argOffset].isNumber())
+ return false;
+ *pageWidthInPixels = static_cast<float>(arguments[argOffset].toInt32());
+ *pageHeightInPixels = static_cast<float>(arguments[1 + argOffset].toInt32());
+ // fall through.
+ case 0:
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+void LayoutTestController::pageNumberForElementById(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ float pageWidthInPixels = 0;
+ float pageHeightInPixels = 0;
+ if (!parsePageSizeParameters(arguments, 1,
+ &pageWidthInPixels, &pageHeightInPixels))
+ return;
+ if (!arguments[0].isString())
+ return;
+ WebFrame* frame = m_shell->webView()->mainFrame();
+ if (!frame)
+ return;
+ result->set(frame->pageNumberForElementById(cppVariantToWebString(arguments[0]),
+ pageWidthInPixels, pageHeightInPixels));
+}
+
+void LayoutTestController::numberOfPages(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ float pageWidthInPixels = 0;
+ float pageHeightInPixels = 0;
+ if (!parsePageSizeParameters(arguments, 0, &pageWidthInPixels, &pageHeightInPixels))
+ return;
+
+ WebFrame* frame = m_shell->webView()->mainFrame();
+ if (!frame)
+ return;
+ WebSize size(pageWidthInPixels, pageHeightInPixels);
+ int numberOfPages = frame->printBegin(size);
+ frame->printEnd();
+ result->set(numberOfPages);
+}
+
+void LayoutTestController::logErrorToConsole(const std::string& text)
+{
+ m_shell->webViewHost()->didAddMessageToConsole(
+ WebConsoleMessage(WebConsoleMessage::LevelError, WebString::fromUTF8(text)),
+ WebString(), 0);
+}
+
+void LayoutTestController::setTimelineProfilingEnabled(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 1 || !arguments[0].isBool())
+ return;
+ // FIXME: Should call TestShellDevToolsAgent::setTimelineProfilingEnabled().
+}
+
+void LayoutTestController::evaluateInWebInspector(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 2 || !arguments[0].isInt32() || !arguments[1].isString())
+ return;
+ // FIXME: Should call TestShellDevToolsAgent::evaluateInWebInspector().
+}
+
+void LayoutTestController::forceRedSelectionColors(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ m_shell->webView()->setSelectionColors(0xffee0000, 0xff00ee00, 0xff000000, 0xffc0c0c0);
+}
+
+void LayoutTestController::addUserScript(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 1 || !arguments[0].isString() || !arguments[1].isBool())
+ return;
+ m_shell->webView()->addUserScript(WebString::fromUTF8(arguments[0].toString()), arguments[1].toBoolean());
+}
diff --git a/WebKitTools/DumpRenderTree/chromium/LayoutTestController.h b/WebKitTools/DumpRenderTree/chromium/LayoutTestController.h
new file mode 100644
index 0000000..a8639da
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/LayoutTestController.h
@@ -0,0 +1,440 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2010 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.
+ */
+
+/*
+ LayoutTestController class:
+ Bound to a JavaScript window.layoutTestController object using the
+ CppBoundClass::bindToJavascript(), this allows layout tests that are run in
+ the test_shell (or, in principle, any web page loaded into a client app built
+ with this class) to control various aspects of how the tests are run and what
+ sort of output they produce.
+*/
+
+#ifndef LayoutTestController_h
+#define LayoutTestController_h
+
+#include "CppBoundClass.h"
+#include "base/timer.h" // FIXME: Remove this.
+#include "public/WebString.h"
+#include "public/WebURL.h"
+#include <wtf/Deque.h>
+
+class TestShell;
+
+class LayoutTestController : public CppBoundClass {
+public:
+ // Builds the property and method lists needed to bind this class to a JS
+ // object.
+ LayoutTestController(TestShell*);
+
+ // 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 takes no arguments, and ignores any that may be present.
+ void dumpAsText(const CppArgumentList&, CppVariant*);
+
+ // This function should set a flag that tells the test_shell to print a line
+ // of descriptive text for each database command. It should take no
+ // arguments, and ignore any that may be present. However, at the moment, we
+ // don't have any DB function that prints messages, so for now this function
+ // doesn't do anything.
+ void dumpDatabaseCallbacks(const CppArgumentList&, CppVariant*);
+
+ // 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 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 out a text
+ // representation of the back/forward list. It ignores all arguments.
+ void dumpBackForwardList(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 dump all calls
+ // to window.status().
+ // It takes no arguments, and ignores any that may be present.
+ void dumpWindowStatusChanges(const CppArgumentList&, CppVariant*);
+
+ // When called with a boolean argument, this sets a flag that controls
+ // whether content-editable elements accept editing focus when an editing
+ // attempt is made. It ignores any additional arguments.
+ void setAcceptsEditing(const CppArgumentList&, CppVariant*);
+
+ // Functions for dealing with windows. By default we block all new windows.
+ void windowCount(const CppArgumentList&, CppVariant*);
+ void setCanOpenWindows(const CppArgumentList&, CppVariant*);
+ void setCloseRemainingWindowsWhenComplete(const CppArgumentList&, CppVariant*);
+
+ // 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*);
+ void notifyDoneTimedOut();
+
+ // 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*);
+
+ // Although this is named "objC" to match the Mac version, it actually tests
+ // the identity of its two arguments in C++.
+ void objCIdentityIsEqual(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*);
+
+ // Method that controls whether pressing Tab key cycles through page elements
+ // or inserts a '\t' char in text area
+ void setTabKeyCyclesThroughElements(const CppArgumentList&, CppVariant*);
+
+ // Passes through to WebPreferences which allows the user to have a custom
+ // style sheet.
+ void setUserStyleSheetEnabled(const CppArgumentList&, CppVariant*);
+ void setUserStyleSheetLocation(const CppArgumentList&, CppVariant*);
+
+ // Puts Webkit in "dashboard compatibility mode", which is used in obscure
+ // Mac-only circumstances. It's not really necessary, and will most likely
+ // never be used by Chrome, but some layout tests depend on its presence.
+ void setUseDashboardCompatibilityMode(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*);
+
+ // Causes WillSendRequest to block redirects.
+ void setWillSendRequestReturnsNullOnRedirect(const CppArgumentList&, CppVariant*);
+
+ // Causes WillSendRequest to return an empty request.
+ void setWillSendRequestReturnsNull(const CppArgumentList&, CppVariant*);
+
+ // Converts a URL starting with file:///tmp/ to the local mapping.
+ void pathToLocalResource(const CppArgumentList&, CppVariant*);
+
+ // Sets a bool such that when a drag is started, we fill the drag clipboard
+ // with a fake file object.
+ void addFileToPasteboardOnDrag(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*);
+
+ // Set the WebPreference that controls webkit's popup blocking.
+ void setPopupBlockingEnabled(const CppArgumentList&, CppVariant*);
+
+ // If true, causes provisional frame loads to be stopped for the remainder of
+ // the test.
+ void setStopProvisionalFrameLoads(const CppArgumentList&, CppVariant*);
+
+ // Enable or disable smart insert/delete. This is enabled by default.
+ void setSmartInsertDeleteEnabled(const CppArgumentList&, CppVariant*);
+
+ // Enable or disable trailing whitespace selection on double click.
+ void setSelectTrailingWhitespaceEnabled(const CppArgumentList&, CppVariant*);
+
+ void pauseAnimationAtTimeOnElementWithId(const CppArgumentList&, CppVariant*);
+ void pauseTransitionAtTimeOnElementWithId(const CppArgumentList&, CppVariant*);
+ void elementDoesAutoCompleteForElementWithId(const CppArgumentList&, CppVariant*);
+ void numberOfActiveAnimations(const CppArgumentList&, CppVariant*);
+
+ void disableImageLoading(const CppArgumentList&, CppVariant*);
+
+ void setIconDatabaseEnabled(const CppArgumentList&, CppVariant*);
+
+ void dumpSelectionRect(const CppArgumentList&, CppVariant*);
+
+ // The following are only stubs. TODO(pamg): Implement any of these that
+ // are needed to pass the layout tests.
+ void dumpAsWebArchive(const CppArgumentList&, CppVariant*);
+ void dumpTitleChanges(const CppArgumentList&, CppVariant*);
+ void dumpResourceLoadCallbacks(const CppArgumentList&, CppVariant*);
+ void setMainFrameIsFirstResponder(const CppArgumentList&, CppVariant*);
+ void display(const CppArgumentList&, CppVariant*);
+ void testRepaint(const CppArgumentList&, CppVariant*);
+ void repaintSweepHorizontally(const CppArgumentList&, CppVariant*);
+ void clearBackForwardList(const CppArgumentList&, CppVariant*);
+ void keepWebHistory(const CppArgumentList&, CppVariant*);
+ void storeWebScriptObject(const CppArgumentList&, CppVariant*);
+ void accessStoredWebScriptObject(const CppArgumentList&, CppVariant*);
+ void objCClassNameOf(const CppArgumentList&, CppVariant*);
+ void addDisallowedURL(const CppArgumentList&, CppVariant*);
+ void setCallCloseOnWebViews(const CppArgumentList&, CppVariant*);
+ void setPrivateBrowsingEnabled(const CppArgumentList&, CppVariant*);
+
+ void setXSSAuditorEnabled(const CppArgumentList&, CppVariant*);
+ void evaluateScriptInIsolatedWorld(const CppArgumentList&, CppVariant*);
+ void overridePreference(const CppArgumentList&, CppVariant*);
+ void setAllowUniversalAccessFromFileURLs(const CppArgumentList&, CppVariant*);
+ void setAllowFileAccessFromFileURLs(const CppArgumentList&, CppVariant*);
+
+
+ // 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*);
+
+ // Allows layout tests to call SecurityOrigin::addOriginAccessWhitelistEntry().
+ void addOriginAccessWhitelistEntry(const CppArgumentList&, CppVariant*);
+
+ // Clears all databases.
+ void clearAllDatabases(const CppArgumentList&, CppVariant*);
+ // Sets the default quota for all origins
+ void setDatabaseQuota(const CppArgumentList&, CppVariant*);
+
+ // Calls setlocale(LC_ALL, ...) for a specified locale.
+ // Resets between tests.
+ void setPOSIXLocale(const CppArgumentList&, CppVariant*);
+
+ // Gets the value of the counter in the element specified by its ID.
+ void counterValueForElementById(const CppArgumentList&, CppVariant*);
+
+ // Gets the number of page where the specified element will be put.
+ void pageNumberForElementById(const CppArgumentList&, CppVariant*);
+
+ // Gets the number of pages to be printed.
+ void numberOfPages(const CppArgumentList&, CppVariant*);
+
+
+ // Allows layout tests to start Timeline profiling.
+ void setTimelineProfilingEnabled(const CppArgumentList&, CppVariant*);
+
+ // Allows layout tests to exec scripts at WebInspector side.
+ void evaluateInWebInspector(const CppArgumentList&, CppVariant*);
+
+ // Forces the selection colors for testing under Linux.
+ void forceRedSelectionColors(const CppArgumentList&, CppVariant*);
+
+ // Adds a user script to be injected into new documents.
+ void addUserScript(const CppArgumentList&, CppVariant*);
+
+public:
+ // The following methods are not exposed to JavaScript.
+ void setWorkQueueFrozen(bool frozen) { m_workQueue.setFrozen(frozen); }
+
+ bool shouldDumpAsText() { return m_dumpAsText; }
+ bool shouldDumpEditingCallbacks() { return m_dumpEditingCallbacks; }
+ bool shouldDumpFrameLoadCallbacks() { return m_dumpFrameLoadCallbacks; }
+ void setShouldDumpFrameLoadCallbacks(bool value) { m_dumpFrameLoadCallbacks = value; }
+ bool shouldDumpResourceLoadCallbacks() {return m_dumpResourceLoadCallbacks; }
+ bool shouldDumpStatusCallbacks() { return m_dumpWindowStatusChanges; }
+ bool shouldDumpSelectionRect() { return m_dumpSelectionRect; }
+ bool shouldDumpBackForwardList() { return m_dumpBackForwardList; }
+ bool shouldDumpTitleChanges() { return m_dumpTitleChanges; }
+ bool shouldDumpChildFrameScrollPositions() { return m_dumpChildFrameScrollPositions; }
+ bool shouldDumpChildFramesAsText() { return m_dumpChildFramesAsText; }
+ bool acceptsEditing() { return m_acceptsEditing; }
+ bool canOpenWindows() { return m_canOpenWindows; }
+ bool shouldAddFileToPasteboard() { return m_shouldAddFileToPasteboard; }
+ bool stopProvisionalFrameLoads() { return m_stopProvisionalFrameLoads; }
+
+ bool testRepaint() const { return m_testRepaint; }
+ bool sweepHorizontally() const { return m_sweepHorizontally; }
+
+ // Called by the webview delegate when the toplevel frame load is done.
+ void locationChangeDone();
+
+ // Called by the webview delegate when the policy delegate runs if the
+ // waitForPolicyDelegate was called.
+ void policyDelegateDone();
+
+ // Reinitializes all static values. The reset() method should be called
+ // before the start of each test (currently from
+ // TestShell::runFileTest).
+ void reset();
+
+ // A single item in the work queue.
+ class WorkItem {
+ public:
+ virtual ~WorkItem() {}
+
+ // Returns true if this started a load.
+ virtual bool run(TestShell* shell) = 0;
+ };
+
+private:
+ friend class WorkItem;
+ friend class WorkQueue;
+
+ // Helper class for managing events queued by methods like queueLoad or
+ // queueScript.
+ class WorkQueue {
+ public:
+ WorkQueue(LayoutTestController* controller) : m_controller(controller) {}
+ virtual ~WorkQueue();
+ void processWorkSoon();
+
+ // Reset the state of the class between tests.
+ void reset();
+
+ void addWork(WorkItem* work);
+
+ void setFrozen(bool frozen) { m_frozen = frozen; }
+ bool isEmpty() { return m_queue.isEmpty(); }
+
+ private:
+ void processWork();
+
+ base::OneShotTimer<WorkQueue> m_timer;
+ Deque<WorkItem*> m_queue;
+ bool m_frozen;
+ LayoutTestController* m_controller;
+ };
+
+ // Support for overridePreference.
+ bool cppVariantToBool(const CppVariant&);
+ int32_t cppVariantToInt32(const CppVariant&);
+ WebKit::WebString cppVariantToWebString(const CppVariant&);
+
+ void logErrorToConsole(const std::string&);
+ void completeNotifyDone(bool isTimeout);
+
+ bool pauseAnimationAtTimeOnElementWithId(const WebKit::WebString& animationName, double time, const WebKit::WebString& elementId);
+ bool pauseTransitionAtTimeOnElementWithId(const WebKit::WebString& propertyName, double time, const WebKit::WebString& elementId);
+ bool elementDoesAutoCompleteForElementWithId(const WebKit::WebString&);
+ int numberOfActiveAnimations();
+
+ // Used for test timeouts.
+ ScopedRunnableMethodFactory<LayoutTestController> m_timeoutFactory;
+
+ // Non-owning pointer. The LayoutTestController is owned by the host.
+ TestShell* m_shell;
+
+ // If true, the test_shell will produce a plain text dump rather than a
+ // text representation of the renderer.
+ bool m_dumpAsText;
+
+ // If true, the test_shell will write a descriptive line for each editing
+ // command.
+ bool m_dumpEditingCallbacks;
+
+ // 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, 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 resource
+ // load callback.
+ bool m_dumpResourceLoadCallbacks;
+
+ // 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 print out the child frame scroll offsets as
+ // well.
+ bool m_dumpChildFrameScrollPositions;
+
+ // 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 dump all changes to window.status.
+ bool m_dumpWindowStatusChanges;
+
+ // If true, output a message when the page title is changed.
+ bool m_dumpTitleChanges;
+
+ // If true, the element will be treated as editable. This value is returned
+ // from various editing callbacks that are called just before edit operations
+ // are allowed.
+ bool m_acceptsEditing;
+
+ // 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;
+
+ // 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, 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 and a drag starts, adds a file to the drag&drop clipboard.
+ bool m_shouldAddFileToPasteboard;
+
+ // If true, stops provisional frame loads during the
+ // DidStartProvisionalLoadForFrame callback.
+ bool m_stopProvisionalFrameLoads;
+
+ // If true, don't dump output until notifyDone is called.
+ bool m_waitUntilDone;
+
+ // To prevent infinite loops, only the first page of a test can add to a
+ // work queue (since we may well come back to that same page).
+ bool m_workQueueFrozen;
+
+ WorkQueue m_workQueue;
+
+ CppVariant m_globalFlag;
+
+ // Bound variable counting the number of top URLs visited.
+ CppVariant m_webHistoryItemCount;
+
+ WebKit::WebURL m_userStyleSheetLocation;
+};
+
+#endif // LayoutTestController_h
diff --git a/WebKitTools/DumpRenderTree/chromium/LayoutTestHelper.mm b/WebKitTools/DumpRenderTree/chromium/LayoutTestHelper.mm
new file mode 100644
index 0000000..e34cf5f
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/LayoutTestHelper.mm
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2010 Google 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.
+ */
+
+#import <AppKit/AppKit.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+// This is a simple helper app that changes the color sync profile to the
+// generic profile and back when done. This program is managed by the layout
+// test script, so it can do the job for multiple DumpRenderTree while they are
+// running layout tests.
+
+static CMProfileRef userColorProfile = 0;
+
+static void saveCurrentColorProfile()
+{
+ CGDirectDisplayID displayID = CGMainDisplayID();
+ CMProfileRef previousProfile;
+ CMError error = CMGetProfileByAVID((UInt32)displayID, &previousProfile);
+ if (error) {
+ NSLog(@"failed to get the current color profile, pixmaps won't match. "
+ @"Error: %d", (int)error);
+ } else {
+ userColorProfile = previousProfile;
+ }
+}
+
+static void installLayoutTestColorProfile()
+{
+ // To make sure we get consistent colors (not dependent on the Main display),
+ // we force the generic rgb color profile. This cases a change the user can
+ // see.
+
+ CGDirectDisplayID displayID = CGMainDisplayID();
+ NSColorSpace* genericSpace = [NSColorSpace genericRGBColorSpace];
+ CMProfileRef genericProfile = (CMProfileRef)[genericSpace colorSyncProfile];
+ CMError error = CMSetProfileByAVID((UInt32)displayID, genericProfile);
+ if (error) {
+ NSLog(@"failed install the generic color profile, pixmaps won't match. "
+ @"Error: %d", (int)error);
+ }
+}
+
+static void restoreUserColorProfile(void)
+{
+ if (!userColorProfile)
+ return;
+ CGDirectDisplayID displayID = CGMainDisplayID();
+ CMError error = CMSetProfileByAVID((UInt32)displayID, userColorProfile);
+ CMCloseProfile(userColorProfile);
+ if (error) {
+ NSLog(@"Failed to restore color profile, use System Preferences -> "
+ @"Displays -> Color to reset. Error: %d", (int)error);
+ }
+ userColorProfile = 0;
+}
+
+static void simpleSignalHandler(int sig)
+{
+ // Try to restore the color profile and try to go down cleanly
+ restoreUserColorProfile();
+ exit(128 + sig);
+}
+
+int main(int argc, char* argv[])
+{
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+
+ // Hooks the ways we might get told to clean up...
+ signal(SIGINT, simpleSignalHandler);
+ signal(SIGHUP, simpleSignalHandler);
+ signal(SIGTERM, simpleSignalHandler);
+
+ // Save off the current profile, and then install the layout test profile.
+ saveCurrentColorProfile();
+ installLayoutTestColorProfile();
+
+ // Let the script know we're ready
+ printf("ready\n");
+ fflush(stdout);
+
+ // Wait for any key (or signal)
+ getchar();
+
+ // Restore the profile
+ restoreUserColorProfile();
+
+ [pool release];
+ return 0;
+}
diff --git a/WebKitTools/DumpRenderTree/chromium/MockSpellCheck.cpp b/WebKitTools/DumpRenderTree/chromium/MockSpellCheck.cpp
new file mode 100644
index 0000000..fe70cab
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/MockSpellCheck.cpp
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2010 Google 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 "config.h"
+#include "MockSpellCheck.h"
+
+#include "public/WebString.h"
+#include <wtf/ASCIICType.h>
+#include <wtf/Assertions.h>
+
+using namespace WebCore;
+using namespace WebKit;
+
+MockSpellCheck::MockSpellCheck()
+ : m_initialized(false) {}
+
+MockSpellCheck::~MockSpellCheck() {}
+
+static bool isNotASCIIAlpha(UChar ch) { return !isASCIIAlpha(ch); }
+
+bool MockSpellCheck::spellCheckWord(const WebString& text, int* misspelledOffset, int* misspelledLength)
+{
+ ASSERT(misspelledOffset);
+ ASSERT(misspelledLength);
+
+ // Initialize this spellchecker.
+ initializeIfNeeded();
+
+ // Reset the result values as our spellchecker does.
+ *misspelledOffset = 0;
+ *misspelledLength = 0;
+
+ // Convert to a String because we store String instances in
+ // m_misspelledWords and WebString has no find().
+ const String stringText(text.data(), text.length());
+
+ // 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.
+ // Unfortunately, This implementation splits a contraction, i.e. "isn't" is
+ // split into two pieces "isn" and "t". This is OK because webkit tests
+ // don't have misspelled contractions.
+ int wordOffset = stringText.find(isASCIIAlpha);
+ if (wordOffset == -1)
+ return true;
+ int wordEnd = stringText.find(isNotASCIIAlpha, wordOffset);
+ int wordLength = wordEnd == -1 ? stringText.length() - wordOffset : wordEnd - wordOffset;
+
+ // 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.)
+ String word = stringText.substring(wordOffset, wordLength);
+ if (!m_misspelledWords.contains(word))
+ return true;
+
+ *misspelledOffset = wordOffset;
+ *misspelledLength = wordLength;
+ return false;
+}
+
+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",
+ };
+
+ m_misspelledWords.clear();
+ for (size_t i = 0; i < arraysize(misspelledWords); ++i)
+ m_misspelledWords.add(String::fromUTF8(misspelledWords[i]), false);
+
+ // 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/WebKitTools/DumpRenderTree/chromium/MockSpellCheck.h b/WebKitTools/DumpRenderTree/chromium/MockSpellCheck.h
new file mode 100644
index 0000000..8c2ba92
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/MockSpellCheck.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2010 Google 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 MockSpellCheck_h
+#define MockSpellCheck_h
+
+#include <wtf/HashMap.h>
+#include <wtf/text/StringHash.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebKit {
+class WebString;
+}
+
+// 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:
+ 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 WebKit::WebString& text,
+ int* misspelledOffset,
+ int* misspelledLength);
+
+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.
+ HashMap<WebCore::String, bool> m_misspelledWords;
+
+ // A flag representing whether or not this object is initialized.
+ bool m_initialized;
+};
+
+#endif // MockSpellCheck_h
diff --git a/WebKitTools/DumpRenderTree/chromium/PlainTextController.cpp b/WebKitTools/DumpRenderTree/chromium/PlainTextController.cpp
new file mode 100644
index 0000000..6e6cf11
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/PlainTextController.cpp
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "PlainTextController.h"
+
+#include "TestShell.h"
+#include "public/WebBindings.h"
+#include "public/WebRange.h"
+#include "public/WebString.h"
+
+using namespace WebKit;
+
+PlainTextController::PlainTextController()
+{
+ // 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 PlainTextController).
+ bindMethod("plainText", &PlainTextController::plainText);
+
+ // The fallback method is called when an unknown method is invoked.
+ bindFallbackMethod(&PlainTextController::fallbackMethod);
+}
+
+void PlainTextController::plainText(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ if (arguments.size() < 1 || !arguments[0].isObject())
+ return;
+
+ // Check that passed-in object is, in fact, a range.
+ NPObject* npobject = NPVARIANT_TO_OBJECT(arguments[0]);
+ if (!npobject)
+ return;
+ WebRange range;
+ if (!WebBindings::getRange(npobject, &range))
+ return;
+
+ // Extract the text using the Range's text() method
+ WebString text = range.toPlainText();
+ result->set(text.utf8());
+}
+
+void PlainTextController::fallbackMethod(const CppArgumentList&, CppVariant* result)
+{
+ printf("CONSOLE MESSAGE: JavaScript ERROR: unknown method called on PlainTextController\n");
+ result->setNull();
+}
+
diff --git a/WebKitTools/DumpRenderTree/chromium/PlainTextController.h b/WebKitTools/DumpRenderTree/chromium/PlainTextController.h
new file mode 100644
index 0000000..3d3a04c
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/PlainTextController.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2010 Google 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 PlainTextController_h
+#define PlainTextController_h
+
+#include "CppBoundClass.h"
+
+class TestShell;
+
+class PlainTextController : public CppBoundClass {
+public:
+ // Builds the property and method lists needed to bind this class to a JS
+ // object.
+ explicit PlainTextController();
+
+ // JS callback methods.
+ void plainText(const CppArgumentList&, CppVariant*);
+
+ // Fall-back method: called if an unknown method is invoked.
+ void fallbackMethod(const CppArgumentList&, CppVariant*);
+};
+
+#endif // PlainTextController_h
+
diff --git a/WebKitTools/DumpRenderTree/chromium/TestNavigationController.cpp b/WebKitTools/DumpRenderTree/chromium/TestNavigationController.cpp
new file mode 100644
index 0000000..8b4f954
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/TestNavigationController.cpp
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2010 Google 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 "config.h"
+#include "TestNavigationController.h"
+
+#include "TestShell.h"
+#include <wtf/Assertions.h>
+
+using namespace WebKit;
+using namespace std;
+
+// ----------------------------------------------------------------------------
+// TestNavigationEntry
+
+TestNavigationEntry::TestNavigationEntry()
+ : m_pageID(-1) {}
+
+TestNavigationEntry::TestNavigationEntry(
+ int pageID, const WebURL& url, const WebString& title, const WebString& targetFrame)
+ : m_pageID(pageID)
+ , m_url(url)
+ , m_title(title)
+ , m_targetFrame(targetFrame) {}
+
+TestNavigationEntry::~TestNavigationEntry() {}
+
+void TestNavigationEntry::setContentState(const WebHistoryItem& state)
+{
+ m_state = state;
+}
+
+// ----------------------------------------------------------------------------
+// TestNavigationController
+
+TestNavigationController::TestNavigationController(NavigationHost* host)
+ : m_pendingEntry(0)
+ , m_lastCommittedEntryIndex(-1)
+ , m_pendingEntryIndex(-1)
+ , m_host(host)
+ , m_maxPageID(-1) {}
+
+TestNavigationController::~TestNavigationController()
+{
+ discardPendingEntry();
+}
+
+void TestNavigationController::reset()
+{
+ m_entries.clear();
+ discardPendingEntry();
+
+ m_lastCommittedEntryIndex = -1;
+}
+
+void TestNavigationController::reload()
+{
+ // Base the navigation on where we are now...
+ int currentIndex = currentEntryIndex();
+
+ // If we are no where, then we can't reload. TODO(darin): We should add a
+ // CanReload method.
+ if (currentIndex == -1)
+ return;
+
+ discardPendingEntry();
+
+ m_pendingEntryIndex = currentIndex;
+ navigateToPendingEntry(true);
+}
+
+void TestNavigationController::goToOffset(int offset)
+{
+ int index = m_lastCommittedEntryIndex + offset;
+ if (index < 0 || index >= entryCount())
+ return;
+
+ goToIndex(index);
+}
+
+void TestNavigationController::goToIndex(int index)
+{
+ ASSERT(index >= 0);
+ ASSERT(index < static_cast<int>(m_entries.size()));
+
+ discardPendingEntry();
+
+ m_pendingEntryIndex = index;
+ navigateToPendingEntry(false);
+}
+
+void TestNavigationController::loadEntry(TestNavigationEntry* entry)
+{
+ // When navigating to a new page, we don't know for sure if we will actually
+ // end up leaving the current page. The new page load could for example
+ // result in a download or a 'no content' response (e.g., a mailto: URL).
+ discardPendingEntry();
+ m_pendingEntry = entry;
+ navigateToPendingEntry(false);
+}
+
+
+TestNavigationEntry* TestNavigationController::lastCommittedEntry() const
+{
+ if (m_lastCommittedEntryIndex == -1)
+ return 0;
+ return m_entries[m_lastCommittedEntryIndex].get();
+}
+
+TestNavigationEntry* TestNavigationController::activeEntry() const
+{
+ TestNavigationEntry* entry = m_pendingEntry;
+ if (!entry)
+ entry = lastCommittedEntry();
+ return entry;
+}
+
+int TestNavigationController::currentEntryIndex() const
+{
+ if (m_pendingEntryIndex != -1)
+ return m_pendingEntryIndex;
+ return m_lastCommittedEntryIndex;
+}
+
+
+TestNavigationEntry* TestNavigationController::entryAtIndex(int index) const
+{
+ if (index < 0 || index >= entryCount())
+ return 0;
+ return m_entries[index].get();
+}
+
+TestNavigationEntry* TestNavigationController::entryWithPageID(int32_t pageID) const
+{
+ int index = entryIndexWithPageID(pageID);
+ return (index != -1) ? m_entries[index].get() : 0;
+}
+
+void TestNavigationController::didNavigateToEntry(TestNavigationEntry* entry)
+{
+ // If the entry is that of a page with PageID larger than any this Tab has
+ // seen before, then consider it a new navigation.
+ if (entry->pageID() > maxPageID()) {
+ insertEntry(entry);
+ return;
+ }
+
+ // Otherwise, we just need to update an existing entry with matching PageID.
+ // If the existing entry corresponds to the entry which is pending, then we
+ // must update the current entry index accordingly. When navigating to the
+ // same URL, a new PageID is not created.
+
+ int existingEntryIndex = entryIndexWithPageID(entry->pageID());
+ TestNavigationEntry* existingEntry = (existingEntryIndex != -1) ?
+ m_entries[existingEntryIndex].get() : 0;
+ if (!existingEntry) {
+ // No existing entry, then simply ignore this navigation!
+ } else if (existingEntry == m_pendingEntry) {
+ // The given entry might provide a new URL... e.g., navigating back to a
+ // page in session history could have resulted in a new client redirect.
+ existingEntry->setURL(entry->URL());
+ existingEntry->setContentState(entry->contentState());
+ m_lastCommittedEntryIndex = m_pendingEntryIndex;
+ m_pendingEntryIndex = -1;
+ m_pendingEntry = 0;
+ } else if (m_pendingEntry && m_pendingEntry->pageID() == -1
+ && GURL(m_pendingEntry->URL()) == GURL(existingEntry->URL().spec())) {
+ // Not a new navigation
+ discardPendingEntry();
+ } else {
+ // The given entry might provide a new URL... e.g., navigating to a page
+ // might result in a client redirect, which should override the URL of the
+ // existing entry.
+ existingEntry->setURL(entry->URL());
+ existingEntry->setContentState(entry->contentState());
+
+ // The navigation could have been issued by the renderer, so be sure that
+ // we update our current index.
+ m_lastCommittedEntryIndex = existingEntryIndex;
+ }
+
+ delete entry;
+ updateMaxPageID();
+}
+
+void TestNavigationController::discardPendingEntry()
+{
+ if (m_pendingEntryIndex == -1)
+ delete m_pendingEntry;
+ m_pendingEntry = 0;
+ m_pendingEntryIndex = -1;
+}
+
+void TestNavigationController::insertEntry(TestNavigationEntry* entry)
+{
+ discardPendingEntry();
+
+ // Prune any entry which are in front of the current entry
+ int currentSize = static_cast<int>(m_entries.size());
+ if (currentSize > 0) {
+ while (m_lastCommittedEntryIndex < (currentSize - 1)) {
+ m_entries.removeLast();
+ currentSize--;
+ }
+ }
+
+ m_entries.append(linked_ptr<TestNavigationEntry>(entry));
+ m_lastCommittedEntryIndex = static_cast<int>(m_entries.size()) - 1;
+ updateMaxPageID();
+}
+
+int TestNavigationController::entryIndexWithPageID(int32 pageID) const
+{
+ for (int i = static_cast<int>(m_entries.size()) - 1; i >= 0; --i) {
+ if (m_entries[i]->pageID() == pageID)
+ return i;
+ }
+ return -1;
+}
+
+void TestNavigationController::navigateToPendingEntry(bool reload)
+{
+ // For session history navigations only the pending_entry_index_ is set.
+ if (!m_pendingEntry) {
+ ASSERT(m_pendingEntryIndex != -1);
+ m_pendingEntry = m_entries[m_pendingEntryIndex].get();
+ }
+
+ if (m_host->navigate(*m_pendingEntry, reload)) {
+ // Note: this is redundant if navigation completed synchronously because
+ // DidNavigateToEntry call this as well.
+ updateMaxPageID();
+ } else
+ discardPendingEntry();
+}
+
+void TestNavigationController::updateMaxPageID()
+{
+ TestNavigationEntry* entry = activeEntry();
+ if (entry)
+ m_maxPageID = max(m_maxPageID, entry->pageID());
+}
diff --git a/WebKitTools/DumpRenderTree/chromium/TestNavigationController.h b/WebKitTools/DumpRenderTree/chromium/TestNavigationController.h
new file mode 100644
index 0000000..bd3c2f4
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/TestNavigationController.h
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2010 Google 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 TestNavigationController_h
+#define TestNavigationController_h
+
+#include "base/basictypes.h"
+#include "base/linked_ptr.h"
+#include "public/WebDataSource.h"
+#include "public/WebHistoryItem.h"
+#include "public/WebString.h"
+#include "public/WebURL.h"
+#include <string>
+#include <wtf/Vector.h>
+
+// Associated with browser-initated navigations to hold tracking data.
+class TestShellExtraData : public WebKit::WebDataSource::ExtraData {
+public:
+ TestShellExtraData(int32_t pendingPageID)
+ : pendingPageID(pendingPageID)
+ , requestCommitted(false) {}
+
+ // Contains the page_id for this navigation or -1 if there is none yet.
+ int32_t pendingPageID;
+
+ // True if we have already processed the "DidCommitLoad" event for this
+ // request. Used by session history.
+ bool requestCommitted;
+};
+
+// Stores one back/forward navigation state for the test shell.
+class TestNavigationEntry: public Noncopyable {
+public:
+ TestNavigationEntry();
+ TestNavigationEntry(int pageID,
+ const WebKit::WebURL&,
+ const WebKit::WebString& title,
+ const WebKit::WebString& targetFrame);
+
+ // Virtual to allow test_shell to extend the class.
+ ~TestNavigationEntry();
+
+ // Set / Get the URI
+ void setURL(const WebKit::WebURL& url) { m_url = url; }
+ const WebKit::WebURL& URL() const { return m_url; }
+
+ // Set / Get the title
+ void setTitle(const WebKit::WebString& title) { m_title = title; }
+ const WebKit::WebString& title() const { return m_title; }
+
+ // Set / Get a state.
+ void setContentState(const WebKit::WebHistoryItem&);
+ const WebKit::WebHistoryItem& contentState() const { return m_state; }
+
+ // Get the page id corresponding to the tab's state.
+ void setPageID(int pageID) { m_pageID = pageID; }
+ int32_t pageID() const { return m_pageID; }
+
+ const WebKit::WebString& targetFrame() const { return m_targetFrame; }
+
+private:
+ // Describes the current page that the tab represents. This is not relevant
+ // for all tab contents types.
+ int32_t m_pageID;
+
+ WebKit::WebURL m_url;
+ WebKit::WebString m_title;
+ WebKit::WebHistoryItem m_state;
+ WebKit::WebString m_targetFrame;
+};
+
+class NavigationHost {
+public:
+ virtual bool navigate(const TestNavigationEntry&, bool reload) = 0;
+};
+
+// Test shell's NavigationController. The goal is to be as close to the Chrome
+// version as possible.
+class TestNavigationController: public Noncopyable {
+public:
+ TestNavigationController(NavigationHost*);
+ ~TestNavigationController();
+
+ void reset();
+
+ // Causes the controller to reload the current (or pending) entry.
+ void reload();
+
+ // Causes the controller to go to the specified offset from current. Does
+ // nothing if out of bounds.
+ void goToOffset(int);
+
+ // Causes the controller to go to the specified index.
+ void goToIndex(int);
+
+ // Causes the controller to load the specified entry. The controller
+ // assumes ownership of the entry.
+ // NOTE: Do not pass an entry that the controller already owns!
+ void loadEntry(TestNavigationEntry*);
+
+ // Returns the last committed entry, which may be null if there are no
+ // committed entries.
+ TestNavigationEntry* lastCommittedEntry() const;
+
+ // Returns the number of entries in the NavigationControllerBase, excluding
+ // the pending entry if there is one.
+ int entryCount() const { return static_cast<int>(m_entries.size()); }
+
+ // Returns the active entry, which is the pending entry if a navigation is in
+ // progress or the last committed entry otherwise. NOTE: This can be 0!!
+ //
+ // If you are trying to get the current state of the NavigationControllerBase,
+ // this is the method you will typically want to call.
+ TestNavigationEntry* activeEntry() const;
+
+ // Returns the index from which we would go back/forward or reload. This is
+ // the m_lastCommittedEntryIndex if m_pendingEntryIndex is -1. Otherwise,
+ // it is the m_pendingEntryIndex.
+ int currentEntryIndex() const;
+
+ // Returns the entry at the specified index. Returns 0 if out of
+ // bounds.
+ TestNavigationEntry* entryAtIndex(int) const;
+
+ // Return the entry with the corresponding type and page ID, or 0 if
+ // not found.
+ TestNavigationEntry* entryWithPageID(int32_t) const;
+
+ // Returns the index of the last committed entry.
+ int lastCommittedEntryIndex() const { return m_lastCommittedEntryIndex; }
+
+ // Used to inform us of a navigation being committed for a tab. We will take
+ // ownership of the entry. Any entry located forward to the current entry will
+ // be deleted. The new entry becomes the current entry.
+ void didNavigateToEntry(TestNavigationEntry*);
+
+ // Used to inform us to discard its pending entry.
+ void discardPendingEntry();
+
+private:
+ // Inserts an entry after the current position, removing all entries after it.
+ // The new entry will become the active one.
+ void insertEntry(TestNavigationEntry*);
+
+ int maxPageID() const { return m_maxPageID; }
+ void navigateToPendingEntry(bool reload);
+
+ // Return the index of the entry with the corresponding type and page ID,
+ // or -1 if not found.
+ int entryIndexWithPageID(int32_t) const;
+
+ // Updates the max page ID with that of the given entry, if is larger.
+ void updateMaxPageID();
+
+ // List of NavigationEntry for this tab
+ typedef Vector<linked_ptr<TestNavigationEntry> > NavigationEntryList;
+ typedef NavigationEntryList::iterator NavigationEntryListIterator;
+ NavigationEntryList m_entries;
+
+ // An entry we haven't gotten a response for yet. This will be discarded
+ // when we navigate again. It's used only so we know what the currently
+ // displayed tab is.
+ TestNavigationEntry* m_pendingEntry;
+
+ // currently visible entry
+ int m_lastCommittedEntryIndex;
+
+ // index of pending entry if it is in entries_, or -1 if pending_entry_ is a
+ // new entry (created by LoadURL).
+ int m_pendingEntryIndex;
+
+ NavigationHost* m_host;
+ int m_maxPageID;
+};
+
+#endif // TestNavigationController_h
+
diff --git a/WebKitTools/DumpRenderTree/chromium/TestShell.cpp b/WebKitTools/DumpRenderTree/chromium/TestShell.cpp
new file mode 100644
index 0000000..d2bc110
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/TestShell.cpp
@@ -0,0 +1,614 @@
+/*
+ * Copyright (C) 2010 Google 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 "config.h"
+#include "TestShell.h"
+
+#include "LayoutTestController.h"
+#include "WebViewHost.h"
+#include "base/md5.h" // FIXME: Wrap by webkit_support.
+#include "base/string16.h"
+#include "gfx/codec/png_codec.h" // FIXME: Remove dependecy. WebCore/platform/image-encoder is better?
+#include "net/base/escape.h" // FIXME: Remove dependency.
+#include "public/WebDataSource.h"
+#include "public/WebDocument.h"
+#include "public/WebElement.h"
+#include "public/WebFrame.h"
+#include "public/WebHistoryItem.h"
+#include "public/WebRuntimeFeatures.h"
+#include "public/WebScriptController.h"
+#include "public/WebSettings.h"
+#include "public/WebSize.h"
+#include "public/WebString.h"
+#include "public/WebURLRequest.h"
+#include "public/WebURLResponse.h"
+#include "public/WebView.h"
+#include "skia/ext/bitmap_platform_device.h"
+#include "skia/ext/platform_canvas.h"
+#include "webkit/support/webkit_support.h"
+#include <algorithm>
+#include <cctype>
+#include <vector>
+
+using namespace WebKit;
+using namespace std;
+
+// Content area size for newly created windows.
+static const int testWindowWidth = 800;
+static const int testWindowHeight = 600;
+
+// The W3C SVG layout tests use a different size than the other layout tests.
+static const int SVGTestWindowWidth = 480;
+static const int SVGTestWindowHeight = 360;
+
+static const char layoutTestsPattern[] = "/LayoutTests/";
+static const string::size_type layoutTestsPatternSize = sizeof(layoutTestsPattern) - 1;
+static const char fileUrlPattern[] = "file:/";
+static const char fileTestPrefix[] = "(file test):";
+static const char dataUrlPattern[] = "data:";
+static const string::size_type dataUrlPatternSize = sizeof(dataUrlPattern) - 1;
+
+TestShell::TestShell()
+ : m_testIsPending(false)
+ , m_testIsPreparing(false)
+ , m_focusedWidget(0)
+{
+ m_accessibilityController.set(new AccessibilityController(this));
+ m_layoutTestController.set(new LayoutTestController(this));
+ m_eventSender.set(new EventSender(this));
+ m_plainTextController.set(new PlainTextController());
+ m_textInputController.set(new TextInputController(this));
+
+ m_webViewHost = createWebView();
+ m_webView = m_webViewHost->webView();
+}
+
+TestShell::~TestShell()
+{
+ loadURL(GURL("about:blank"));
+ // Call GC twice to clean up garbage.
+ callJSGC();
+ callJSGC();
+
+ // Destroy the WebView before its WebViewHost.
+ m_webView->close();
+}
+
+void TestShell::resetWebSettings(WebView& webView)
+{
+ // Match the settings used by Mac DumpRenderTree, with the exception of
+ // fonts.
+ WebSettings* settings = webView.settings();
+#if OS(MAC_OS_X)
+ WebString serif = WebString::fromUTF8("Times");
+ settings->setCursiveFontFamily(WebString::fromUTF8("Apple Chancery"));
+ settings->setFantasyFontFamily(WebString::fromUTF8("Papyrus"));
+#else
+ // NOTE: case matters here, this must be 'times new roman', else
+ // some layout tests fail.
+ WebString serif = WebString::fromUTF8("times new roman");
+
+ // These two fonts are picked from the intersection of
+ // Win XP font list and Vista font list :
+ // http://www.microsoft.com/typography/fonts/winxp.htm
+ // http://blogs.msdn.com/michkap/archive/2006/04/04/567881.aspx
+ // Some of them are installed only with CJK and complex script
+ // support enabled on Windows XP and are out of consideration here.
+ // (although we enabled both on our buildbots.)
+ // They (especially Impact for fantasy) are not typical cursive
+ // and fantasy fonts, but it should not matter for layout tests
+ // as long as they're available.
+ settings->setCursiveFontFamily(WebString::fromUTF8("Comic Sans MS"));
+ settings->setFantasyFontFamily(WebString::fromUTF8("Impact"));
+#endif
+ settings->setSerifFontFamily(serif);
+ settings->setStandardFontFamily(serif);
+ settings->setFixedFontFamily(WebString::fromUTF8("Courier"));
+
+ settings->setDefaultTextEncodingName(WebString::fromUTF8("ISO-8859-1"));
+ settings->setDefaultFontSize(16);
+ settings->setDefaultFixedFontSize(13);
+ settings->setMinimumFontSize(1);
+ settings->setMinimumLogicalFontSize(9);
+ settings->setJavaScriptCanOpenWindowsAutomatically(true);
+ settings->setDOMPasteAllowed(true);
+ settings->setDeveloperExtrasEnabled(false);
+ settings->setNeedsSiteSpecificQuirks(true);
+ settings->setShrinksStandaloneImagesToFit(false);
+ settings->setUsesEncodingDetector(false);
+ settings->setTextAreasAreResizable(false);
+ settings->setJavaEnabled(false);
+ settings->setAllowScriptsToCloseWindows(false);
+ settings->setXSSAuditorEnabled(false);
+ settings->setDownloadableBinaryFontsEnabled(true);
+ settings->setLocalStorageEnabled(true);
+ settings->setOfflineWebApplicationCacheEnabled(true);
+ settings->setAllowFileAccessFromFileURLs(true);
+
+ // LayoutTests were written with Safari Mac in mind which does not allow
+ // tabbing to links by default.
+ webView.setTabsToLinks(false);
+
+ // Allow those layout tests running as local files, i.e. under
+ // LayoutTests/http/tests/local, to access http server.
+ settings->setAllowUniversalAccessFromFileURLs(true);
+
+ settings->setJavaScriptEnabled(true);
+ settings->setPluginsEnabled(true);
+ settings->setWebSecurityEnabled(true);
+ settings->setEditableLinkBehaviorNeverLive();
+ settings->setFontRenderingModeNormal();
+ settings->setShouldPaintCustomScrollbars(true);
+ settings->setTextDirectionSubmenuInclusionBehaviorNeverIncluded();
+
+ settings->setLoadsImagesAutomatically(true);
+ settings->setImagesEnabled(true);
+}
+
+void TestShell::runFileTest(const TestParams& params)
+{
+ m_testIsPreparing = true;
+ m_params = params;
+ string testUrl = m_params.testUrl.spec();
+
+ bool inspectorTestMode = testUrl.find("/inspector/") != string::npos
+ || testUrl.find("\\inspector\\") != string::npos;
+ m_webView->settings()->setDeveloperExtrasEnabled(inspectorTestMode);
+ loadURL(m_params.testUrl);
+
+ m_testIsPreparing = false;
+ waitTestFinished();
+}
+
+static inline bool isSVGTestURL(const WebURL& url)
+{
+ return url.isValid() && string(url.spec()).find("W3C-SVG-1.1") != string::npos;
+}
+
+void TestShell::resizeWindowForTest(WebViewHost* window, const WebURL& url)
+{
+ int width, height;
+ if (isSVGTestURL(url)) {
+ width = SVGTestWindowWidth;
+ height = SVGTestWindowHeight;
+ } else {
+ width = testWindowWidth;
+ height = testWindowHeight;
+ }
+ window->setWindowRect(WebRect(0, 0, width + virtualWindowBorder * 2, height + virtualWindowBorder * 2));
+}
+
+void TestShell::resetTestController()
+{
+ m_accessibilityController->reset();
+ m_layoutTestController->reset();
+ m_eventSender->reset();
+ m_webViewHost->reset();
+}
+
+void TestShell::loadURL(const WebURL& url)
+{
+ m_webViewHost->loadURLForFrame(url, WebString());
+}
+
+void TestShell::reload()
+{
+ m_webViewHost->navigationController()->reload();
+}
+
+void TestShell::goToOffset(int offset)
+{
+ m_webViewHost->navigationController()->goToOffset(offset);
+}
+
+int TestShell::navigationEntryCount() const
+{
+ return m_webViewHost->navigationController()->entryCount();
+}
+
+void TestShell::callJSGC()
+{
+ m_webView->mainFrame()->collectGarbage();
+}
+
+void TestShell::setFocus(WebWidget* widget, bool enable)
+{
+ // Simulate the effects of InteractiveSetFocus(), which includes calling
+ // both setFocus() and setIsActive().
+ if (enable) {
+ if (m_focusedWidget != widget) {
+ if (m_focusedWidget)
+ m_focusedWidget->setFocus(false);
+ webView()->setIsActive(enable);
+ widget->setFocus(enable);
+ m_focusedWidget = widget;
+ }
+ } else {
+ if (m_focusedWidget == widget) {
+ widget->setFocus(enable);
+ webView()->setIsActive(enable);
+ m_focusedWidget = 0;
+ }
+ }
+}
+
+void TestShell::testFinished()
+{
+ if (!m_testIsPending)
+ return;
+ m_testIsPending = false;
+ dump();
+ webkit_support::QuitMessageLoop();
+}
+
+void TestShell::testTimedOut()
+{
+ fprintf(stderr, "FAIL: Timed out waiting for notifyDone to be called\n");
+ fprintf(stdout, "FAIL: Timed out waiting for notifyDone to be called\n");
+ testFinished();
+}
+
+static 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();
+}
+
+static 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->name().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;
+}
+
+static void dumpFrameScrollPosition(WebFrame* frame, bool recursive)
+{
+ WebSize offset = frame->scrollOffset();
+ if (offset.width > 0 || offset.height > 0) {
+ if (frame->parent())
+ printf("frame '%s' ", frame->name().utf8().data());
+ printf("scrolled to %d,%d\n", offset.width, offset.height);
+ }
+
+ if (!recursive)
+ return;
+ for (WebFrame* child = frame->firstChild(); child; child = child->nextSibling())
+ dumpFrameScrollPosition(child, recursive);
+}
+
+struct ToLower {
+ char16 operator()(char16 c) { return tolower(c); }
+};
+
+// FIXME: Eliminate std::transform(), std::vector, and std::sort().
+
+// Returns True if item1 < item2.
+static 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;
+}
+
+static 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 = item.urlString().utf8();
+ size_t pos;
+ if (!url.find(fileUrlPattern) && ((pos = url.find(layoutTestsPattern)) != string::npos)) {
+ // adjust file URLs to match upstream results.
+ url.replace(0, pos + layoutTestsPatternSize, fileTestPrefix);
+ } else if (!url.find(dataUrlPattern)) {
+ // URL-escape data URLs to match results upstream.
+ string path = EscapePath(url.substr(dataUrlPatternSize));
+ url.replace(dataUrlPatternSize, url.length(), path);
+ }
+
+ result.append(url);
+ if (!item.target().isEmpty()) {
+ result.append(" (in frame \"");
+ result.append(item.target().utf8());
+ result.append("\")");
+ }
+ if (item.isTargetItem())
+ result.append(" **nav target**");
+ 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;
+}
+
+static void dumpBackForwardList(const TestNavigationController& navigationController, string& result)
+{
+ result.append("\n============== Back Forward List ==============\n");
+ for (int index = 0; index < navigationController.entryCount(); ++index) {
+ int currentIndex = navigationController.lastCommittedEntryIndex();
+ WebHistoryItem historyItem = navigationController.entryAtIndex(index)->contentState();
+ if (historyItem.isNull()) {
+ historyItem.initialize();
+ historyItem.setURLString(navigationController.entryAtIndex(index)->URL().spec().utf16());
+ }
+ result.append(dumpHistoryItem(historyItem, 8, index == currentIndex));
+ }
+ result.append("===============================================\n");
+}
+
+string TestShell::dumpAllBackForwardLists()
+{
+ string result;
+ for (unsigned i = 0; i < m_windowList.size(); ++i)
+ dumpBackForwardList(*m_windowList[i]->navigationController(), result);
+ return result;
+}
+
+void TestShell::dump()
+{
+ WebScriptController::flushConsoleMessages();
+
+ // Dump the requested representation.
+ WebFrame* frame = m_webView->mainFrame();
+ if (!frame)
+ return;
+ bool shouldDumpAsText = m_layoutTestController->shouldDumpAsText();
+ bool dumpedAnything = false;
+ if (m_params.dumpTree) {
+ dumpedAnything = true;
+ printf("Content-Type: text/plain\n");
+ // Text output: the test page can request different types of output
+ // which we handle here.
+ if (!shouldDumpAsText) {
+ // Plain text pages should be dumped as text
+ string mimeType = frame->dataSource()->response().mimeType().utf8();
+ shouldDumpAsText = mimeType == "text/plain";
+ }
+ if (shouldDumpAsText) {
+ bool recursive = m_layoutTestController->shouldDumpChildFramesAsText();
+ string dataUtf8 = dumpFramesAsText(frame, recursive);
+ if (fwrite(dataUtf8.c_str(), 1, dataUtf8.size(), stdout) != dataUtf8.size())
+ FATAL("Short write to stdout, disk full?\n");
+ } else {
+ printf("%s", frame->renderTreeAsText().utf8().data());
+ bool recursive = m_layoutTestController->shouldDumpChildFrameScrollPositions();
+ dumpFrameScrollPosition(frame, recursive);
+ }
+ if (m_layoutTestController->shouldDumpBackForwardList())
+ printf("%s", dumpAllBackForwardLists().c_str());
+ }
+ if (dumpedAnything && m_params.printSeparators)
+ printf("#EOF\n");
+
+ if (m_params.dumpPixels && !shouldDumpAsText) {
+ // Image output: we write the image data to the file given on the
+ // command line (for the dump pixels argument), and the MD5 sum to
+ // stdout.
+ dumpedAnything = true;
+ m_webView->layout();
+ if (m_layoutTestController->testRepaint()) {
+ WebSize viewSize = m_webView->size();
+ int width = viewSize.width;
+ int height = viewSize.height;
+ if (m_layoutTestController->sweepHorizontally()) {
+ for (WebRect column(0, 0, 1, height); column.x < width; column.x++)
+ m_webViewHost->paintRect(column);
+ } else {
+ for (WebRect line(0, 0, width, 1); line.y < height; line.y++)
+ m_webViewHost->paintRect(line);
+ }
+ } else
+ m_webViewHost->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_layoutTestController->shouldDumpSelectionRect()) {
+ // If there is a selection rect - draw a red 1px border enclosing rect
+ WebRect wr = frame->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);
+ m_webViewHost->canvas()->drawIRect(rect, paint);
+ }
+ }
+
+ string md5sum = dumpImage(m_webViewHost->canvas(), m_params.pixelHash);
+ }
+ printf("#EOF\n"); // For the image.
+ fflush(stdout);
+ fflush(stderr);
+}
+
+string TestShell::dumpImage(skia::PlatformCanvas* canvas, const string& expectedHash)
+{
+ skia::BitmapPlatformDevice& device =
+ static_cast<skia::BitmapPlatformDevice&>(canvas->getTopPlatformDevice());
+ const SkBitmap& sourceBitmap = device.accessBitmap(false);
+
+ SkAutoLockPixels sourceBitmapLock(sourceBitmap);
+
+ // Fix the alpha. The expected PNGs on Mac have an alpha channel, so we want
+ // to keep it. On Windows, the alpha channel is wrong since text/form control
+ // drawing may have erased it in a few places. So on Windows we force it to
+ // opaque and also don't write the alpha channel for the reference. Linux
+ // doesn't have the wrong alpha like Windows, but we ignore it anyway.
+#if OS(WINDOWS)
+ bool discardTransparency = true;
+ device.makeOpaque(0, 0, sourceBitmap.width(), sourceBitmap.height());
+#elif OS(MAC_OS_X)
+ bool discardTransparency = false;
+#elif OS(UNIX)
+ bool discardTransparency = true;
+#endif
+
+ // Compute MD5 sum. We should have done this before calling
+ // device.makeOpaque on Windows. Because we do it after the call, there are
+ // some images that are the pixel identical on windows and other platforms
+ // but have different MD5 sums. At this point, rebaselining all the windows
+ // tests is too much of a pain, so we just check in different baselines.
+ MD5Context ctx;
+ MD5Init(&ctx);
+ MD5Update(&ctx, sourceBitmap.getPixels(), sourceBitmap.getSize());
+
+ MD5Digest digest;
+ MD5Final(&digest, &ctx);
+ string md5hash = MD5DigestToBase16(digest);
+ printf("\nActualHash: %s\n", md5hash.c_str());
+ if (!expectedHash.empty())
+ printf("\nExpectedHash: %s\n", expectedHash.c_str());
+
+ // Only encode and dump the png if the hashes don't match. Encoding the image
+ // is really expensive.
+ if (md5hash.compare(expectedHash)) {
+ std::vector<unsigned char> png;
+ gfx::PNGCodec::ColorFormat colorFormat = gfx::PNGCodec::FORMAT_BGRA;
+ gfx::PNGCodec::Encode(
+ reinterpret_cast<const unsigned char*>(sourceBitmap.getPixels()),
+ colorFormat, sourceBitmap.width(), sourceBitmap.height(),
+ static_cast<int>(sourceBitmap.rowBytes()), discardTransparency, &png);
+
+ printf("Content-Type: image/png\n");
+ printf("Content-Length: %u\n", png.size());
+ // Write to disk.
+ if (fwrite(&png[0], 1, png.size(), stdout) != png.size())
+ FATAL("Short write to stdout.\n");
+ }
+
+ return md5hash;
+}
+
+void TestShell::bindJSObjectsToWindow(WebFrame* frame)
+{
+ m_accessibilityController->bindToJavascript(frame, WebString::fromUTF8("accessibilityController"));
+ m_layoutTestController->bindToJavascript(frame, WebString::fromUTF8("layoutTestController"));
+ m_eventSender->bindToJavascript(frame, WebString::fromUTF8("eventSender"));
+ m_plainTextController->bindToJavascript(frame, WebString::fromUTF8("plainText"));
+ m_textInputController->bindToJavascript(frame, WebString::fromUTF8("textInputController"));
+}
+
+int TestShell::layoutTestTimeout()
+{
+ return 10 * 1000;
+}
+
+WebViewHost* TestShell::createWebView()
+{
+ return createNewWindow(WebURL());
+}
+
+WebViewHost* TestShell::createNewWindow(const WebURL& url)
+{
+ WebViewHost* host = new WebViewHost(this);
+ WebView* view = WebView::create(host);
+ host->setWebWidget(view);
+ resetWebSettings(*view);
+ view->initializeMainFrame(host);
+ m_windowList.append(host);
+ host->loadURLForFrame(url, WebString());
+ return host;
+}
+
+void TestShell::closeWindow(WebViewHost* window)
+{
+ size_t i = m_windowList.find(window);
+ if (i == notFound) {
+ ASSERT_NOT_REACHED();
+ return;
+ }
+ m_windowList.remove(i);
+ window->webWidget()->close();
+ delete window;
+}
+
+void TestShell::closeRemainingWindows()
+{
+ // Iterate through the window list and close everything except the main
+ // ihwindow. We don't want to delete elements as we're iterating, so we copy
+ // to a temp vector first.
+ Vector<WebViewHost*> windowsToDelete;
+ for (unsigned i = 0; i < m_windowList.size(); ++i) {
+ if (m_windowList[i] != webViewHost())
+ windowsToDelete.append(m_windowList[i]);
+ }
+ ASSERT(windowsToDelete.size() + 1 == m_windowList.size());
+ for (unsigned i = 0; i < windowsToDelete.size(); ++i)
+ closeWindow(windowsToDelete[i]);
+ ASSERT(m_windowList.size() == 1);
+}
+
+int TestShell::windowCount()
+{
+ return m_windowList.size();
+}
diff --git a/WebKitTools/DumpRenderTree/chromium/TestShell.h b/WebKitTools/DumpRenderTree/chromium/TestShell.h
new file mode 100644
index 0000000..c6a5b2e
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/TestShell.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2010 Google 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 "AccessibilityController.h"
+#include "EventSender.h"
+#include "LayoutTestController.h"
+#include "PlainTextController.h"
+#include "TextInputController.h"
+#include "WebViewHost.h"
+#include <string>
+#include <wtf/OwnPtr.h>
+#include <wtf/Vector.h>
+
+// TestShell is a container of global variables and has bridge functions between
+// various objects. Only one instance is created in one DRT process.
+
+namespace WebKit {
+class WebFrame;
+class WebPreferences;
+class WebView;
+class WebURL;
+}
+namespace skia {
+class PlatformCanvas;
+}
+
+struct TestParams {
+ bool dumpTree;
+ bool dumpPixels;
+ bool printSeparators;
+ WebKit::WebURL testUrl;
+ std::string pixelFileName;
+ std::string pixelHash;
+
+ TestParams()
+ : dumpTree(true)
+ , dumpPixels(false)
+ , printSeparators(false) {}
+};
+
+class TestShell {
+public:
+ TestShell();
+ ~TestShell();
+ // The main WebView.
+ WebKit::WebView* webView() const { return m_webView; }
+ // Returns the host for the main WebView.
+ WebViewHost* webViewHost() const { return m_webViewHost; }
+ LayoutTestController* layoutTestController() const { return m_layoutTestController.get(); }
+ AccessibilityController* accessibilityController() const { return m_accessibilityController.get(); }
+
+ void bindJSObjectsToWindow(WebKit::WebFrame*);
+ void runFileTest(const TestParams&);
+ void callJSGC();
+ void resetTestController();
+ void waitTestFinished();
+
+ // Operations to the main window.
+ void loadURL(const WebKit::WebURL& url);
+ void reload();
+ void goToOffset(int offset);
+ int navigationEntryCount() const;
+
+ void setFocus(WebKit::WebWidget*, bool enable);
+ bool shouldDumpFrameLoadCallbacks() const { return (m_testIsPreparing || m_testIsPending) && layoutTestController()->shouldDumpFrameLoadCallbacks(); }
+ bool shouldDumpResourceLoadCallbacks() const { return (m_testIsPreparing || m_testIsPending) && layoutTestController()->shouldDumpResourceLoadCallbacks(); }
+ void setIsLoading(bool flag) { m_isLoading = flag; }
+
+ // Called by the LayoutTestController to signal test completion.
+ void testFinished();
+ // Called by LayoutTestController when a test hits the timeout, but does not
+ // cause a hang. We can avoid killing TestShell in this case and still dump
+ // the test results.
+ void testTimedOut();
+
+#if defined(OS_WIN)
+ // Access to the finished event. Used by the static WatchDog thread.
+ HANDLE finishedEvent() { return m_finishedEvent; }
+#endif
+
+ // Get the timeout for running a test in milliseconds.
+ static int layoutTestTimeout();
+ static int layoutTestTimeoutForWatchDog() { return layoutTestTimeout() + 1000; }
+
+ WebViewHost* createWebView();
+ WebViewHost* createNewWindow(const WebKit::WebURL&);
+ void closeWindow(WebViewHost*);
+ void closeRemainingWindows();
+ int windowCount();
+ static void resizeWindowForTest(WebViewHost*, const WebKit::WebURL&);
+
+ static const int virtualWindowBorder = 3;
+
+private:
+ static void resetWebSettings(WebKit::WebView&);
+ void dump();
+ std::string dumpAllBackForwardLists();
+ static std::string dumpImage(skia::PlatformCanvas*, const std::string& expectedHash);
+
+ bool m_testIsPending;
+ bool m_testIsPreparing;
+ bool m_isLoading;
+ WebKit::WebView* m_webView;
+ WebKit::WebWidget* m_focusedWidget;
+ WebViewHost* m_webViewHost;
+ OwnPtr<AccessibilityController*> m_accessibilityController;
+ OwnPtr<EventSender*> m_eventSender;
+ OwnPtr<LayoutTestController*> m_layoutTestController;
+ OwnPtr<PlainTextController*> m_plainTextController;
+ OwnPtr<TextInputController*> m_textInputController;
+ TestParams m_params;
+
+ // List of all windows in this process.
+ // The main window should be put into windowList[0].
+ typedef Vector<WebViewHost*> WindowList;
+ WindowList m_windowList;
+
+#if defined(OS_WIN)
+ // Used by the watchdog to know when it's finished.
+ HANDLE m_finishedEvent;
+#endif
+};
diff --git a/WebKitTools/DumpRenderTree/chromium/TestShellGtk.cpp b/WebKitTools/DumpRenderTree/chromium/TestShellGtk.cpp
new file mode 100644
index 0000000..d71881a
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/TestShellGtk.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2010 Google 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 "config.h"
+#include "TestShell.h"
+
+#include "webkit/support/webkit_support.h"
+#include <signal.h>
+
+static void AlarmHandler(int signatl)
+{
+ // If the alarm alarmed, kill the process since we have a really bad hang.
+ puts("\n#TEST_TIMED_OUT\n");
+ puts("#EOF\n");
+ fflush(stdout);
+ exit(0);
+}
+
+void TestShell::waitTestFinished()
+{
+ ASSERT(!m_testIsPending);
+
+ m_testIsPending = true;
+
+ // Install an alarm signal handler that will kill us if we time out.
+ signal(SIGALRM, AlarmHandler);
+ alarm(layoutTestTimeoutForWatchDog() / 1000);
+
+ // TestFinished() will post a quit message to break this loop when the page
+ // finishes loading.
+ while (m_testIsPending)
+ webkit_support::RunMessageLoop();
+
+ // Remove the alarm.
+ alarm(0);
+ signal(SIGALRM, SIG_DFL);
+}
diff --git a/WebKitTools/DumpRenderTree/chromium/TestShellMac.mm b/WebKitTools/DumpRenderTree/chromium/TestShellMac.mm
new file mode 100644
index 0000000..ec8dbac
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/TestShellMac.mm
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2010 Google 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 "config.h"
+
+#include "TestShell.h"
+#include "webkit/support/webkit_support.h"
+#import <AppKit/AppKit.h>
+
+// A class to be the target/selector of the "watchdog" thread that ensures
+// pages timeout if they take too long and tells the test harness via stdout.
+@interface WatchDogTarget : NSObject {
+@private
+ NSTimeInterval _timeout;
+}
+// |timeout| is in seconds
+- (id)initWithTimeout:(NSTimeInterval)timeout;
+// serves as the "run" method of a NSThread.
+- (void)run:(id)sender;
+@end
+
+@implementation WatchDogTarget
+
+- (id)initWithTimeout:(NSTimeInterval)timeout
+{
+ if ((self = [super init]))
+ _timeout = timeout;
+ return self;
+}
+
+- (void)run:(id)ignore
+{
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+
+ // check for debugger, just bail if so. We don't want the timeouts hitting
+ // when we're trying to track down an issue.
+ if (webkit_support::BeingDebugged())
+ return;
+
+ NSThread* currentThread = [NSThread currentThread];
+
+ // Wait to be cancelled. If we are that means the test finished. If it hasn't,
+ // then we need to tell the layout script we timed out and start again.
+ NSDate* limitDate = [NSDate dateWithTimeIntervalSinceNow:_timeout];
+ while ([(NSDate*)[NSDate date] compare:limitDate] == NSOrderedAscending &&
+ ![currentThread isCancelled]) {
+ // sleep for a small increment then check again
+ NSDate* incrementDate = [NSDate dateWithTimeIntervalSinceNow:1.0];
+ [NSThread sleepUntilDate:incrementDate];
+ }
+ if (![currentThread isCancelled]) {
+ // Print a warning to be caught by the layout-test script.
+ // Note: the layout test driver may or may not recognize
+ // this as a timeout.
+ puts("#TEST_TIMED_OUT\n");
+ puts("#EOF\n");
+ fflush(stdout);
+ exit(0);
+ }
+
+ [pool release];
+}
+
+@end
+
+void TestShell::waitTestFinished()
+{
+ ASSERT(!m_testIsPending);
+
+ m_testIsPending = true;
+
+ // Create a watchdog thread which just sets a timer and
+ // kills the process if it times out. This catches really
+ // bad hangs where the shell isn't coming back to the
+ // message loop. If the watchdog is what catches a
+ // timeout, it can't do anything except terminate the test
+ // shell, which is unfortunate.
+ // Windows multiplies by 2.5, but that causes us to run for far, far too
+ // long. We use the passed value and let the scripts flag override
+ // the value as needed.
+ NSTimeInterval timeoutSeconds = layoutTestTimeoutForWatchDog() / 1000;
+ WatchDogTarget* watchdog = [[[WatchDogTarget alloc]
+ initWithTimeout:timeoutSeconds] autorelease];
+ NSThread* thread = [[NSThread alloc] initWithTarget:watchdog
+ selector:@selector(run:)
+ object:nil];
+ [thread start];
+
+ // TestFinished() will post a quit message to break this loop when the page
+ // finishes loading.
+ while (m_testIsPending)
+ webkit_support::RunMessageLoop();
+
+ // Tell the watchdog that we're finished. No point waiting to re-join, it'll
+ // die on its own.
+ [thread cancel];
+ [thread release];
+}
diff --git a/WebKitTools/DumpRenderTree/chromium/TestShellWin.cpp b/WebKitTools/DumpRenderTree/chromium/TestShellWin.cpp
new file mode 100644
index 0000000..2d806a2
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/TestShellWin.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2010 Google 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 "config.h"
+#include "TestShell.h"
+
+#include "webkit/support/webkit_support.h"
+#include <process.h>
+
+// Default timeout in ms for file page loads when in layout test mode.
+const int kDefaultFileTestTimeoutMillisecs = 10 * 1000;
+const int kDefaultWatchDogTimeoutMillisecs = kDefaultFileTestTimeoutMillisecs + 1 * 1000;
+
+// Thread main to run for the thread which just tests for timeout.
+unsigned int __stdcall watchDogThread(void *arg)
+{
+ // If we're debugging a layout test, don't timeout.
+ if (::IsDebuggerPresent())
+ return 0;
+
+ TestShell* shell = static_cast<TestShell*>(arg);
+ // FIXME: Do we need user-specified time settings as with the original
+ // Chromium implementation?
+ DWORD timeout = static_cast<DWORD>(kDefaultWatchDogTimeoutMillisecs);
+ DWORD rv = WaitForSingleObject(shell->finishedEvent(), timeout);
+ if (rv == WAIT_TIMEOUT) {
+ // Print a warning to be caught by the layout-test script.
+ // Note: the layout test driver may or may not recognize
+ // this as a timeout.
+ puts("#TEST_TIMED_OUT\n");
+ puts("#EOF\n");
+ fflush(stdout);
+ TerminateProcess(GetCurrentProcess(), 0);
+ }
+ // Finished normally.
+ return 0;
+}
+
+void TestShell::waitTestFinished()
+{
+ DCHECK(!m_testIsPending) << "cannot be used recursively";
+
+ m_testIsPending = true;
+
+ // Create a watchdog thread which just sets a timer and
+ // kills the process if it times out. This catches really
+ // bad hangs where the shell isn't coming back to the
+ // message loop. If the watchdog is what catches a
+ // timeout, it can't do anything except terminate the test
+ // shell, which is unfortunate.
+ m_finishedEvent = CreateEvent(0, TRUE, FALSE, 0);
+ DCHECK(m_finishedEvent);
+
+ HANDLE threadHandle = reinterpret_cast<HANDLE>(_beginthreadex(
+ 0,
+ 0,
+ &watchDogThread,
+ this,
+ 0,
+ 0));
+ DCHECK(threadHandle);
+
+ // TestFinished() will post a quit message to break this loop when the page
+ // finishes loading.
+ while (m_testIsPending)
+ webkit_support::RunMessageLoop();
+
+ // Tell the watchdog that we are finished.
+ SetEvent(m_finishedEvent);
+
+ // Wait to join the watchdog thread. (up to 1s, then quit)
+ WaitForSingleObject(threadHandle, 1000);
+}
diff --git a/WebKitTools/DumpRenderTree/chromium/TestWebWorker.h b/WebKitTools/DumpRenderTree/chromium/TestWebWorker.h
new file mode 100644
index 0000000..899514e
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/TestWebWorker.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2010 Google 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 TestWebWorker_h
+#define TestWebWorker_h
+
+#include "public/WebMessagePortChannel.h"
+#include "public/WebWorker.h"
+#include "public/WebWorkerClient.h"
+#include <wtf/RefCounted.h>
+
+namespace WebKit {
+class WebNotificationPresenter;
+class WebString;
+class WebURL;
+}
+
+class TestWebWorker : public WebKit::WebWorker,
+ public WebKit::WebWorkerClient,
+ public WTF::RefCounted<TestWebWorker> {
+public:
+ TestWebWorker()
+ {
+ ref();
+ // The initial counter value should be 2. One for a worker object,
+ // another for a worker context object. We need to call ref() just once
+ // because the default counter value of RefCounted is 1.
+ }
+
+ // WebWorker methods:
+ virtual void startWorkerContext(const WebKit::WebURL&, const WebKit::WebString&, const WebKit::WebString&) {}
+ virtual void terminateWorkerContext() {}
+ virtual void postMessageToWorkerContext(const WebKit::WebString&, const WebKit::WebMessagePortChannelArray&) {}
+ virtual void workerObjectDestroyed()
+ {
+ // Releases the reference held for worker object.
+ deref();
+ }
+ virtual void clientDestroyed() {}
+
+ // WebWorkerClient methods:
+ virtual void postMessageToWorkerObject(const WebKit::WebString&, const WebKit::WebMessagePortChannelArray&) {}
+ virtual void postExceptionToWorkerObject(const WebKit::WebString&, int, const WebKit::WebString&) {}
+ virtual void postConsoleMessageToWorkerObject(int, int, int, int, const WebKit::WebString&, int, const WebKit::WebString&) {}
+ virtual void confirmMessageFromWorkerObject(bool) {}
+ virtual void reportPendingActivity(bool) {}
+ virtual void workerContextClosed() {}
+ virtual void workerContextDestroyed()
+ {
+ // Releases the reference held for worker context object.
+ deref();
+ }
+ virtual WebKit::WebWorker* createWorker(WebKit::WebWorkerClient*) { return 0; }
+ virtual WebKit::WebNotificationPresenter* notificationPresenter() { return 0; }
+
+private:
+ ~TestWebWorker() {}
+ friend class WTF::RefCounted<TestWebWorker>;
+};
+
+#endif // TestWebWorker_h
diff --git a/WebKitTools/DumpRenderTree/chromium/TextInputController.cpp b/WebKitTools/DumpRenderTree/chromium/TextInputController.cpp
new file mode 100644
index 0000000..63c4719
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/TextInputController.cpp
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2010 Google 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 "config.h"
+#include "TextInputController.h"
+
+#include "TestShell.h"
+#include "public/WebFrame.h"
+#include "public/WebRange.h"
+#include "public/WebString.h"
+#include "public/WebView.h"
+#include <wtf/StringExtras.h>
+#include <string>
+
+using namespace WebKit;
+using namespace std;
+
+TestShell* TextInputController::testShell = 0;
+
+TextInputController::TextInputController(TestShell* shell)
+{
+ // Set static testShell variable. Be careful not to assign testShell to new
+ // windows which are temporary.
+ if (!testShell)
+ testShell = shell;
+
+ bindMethod("insertText", &TextInputController::insertText);
+ bindMethod("doCommand", &TextInputController::doCommand);
+ bindMethod("setMarkedText", &TextInputController::setMarkedText);
+ bindMethod("unmarkText", &TextInputController::unmarkText);
+ bindMethod("hasMarkedText", &TextInputController::hasMarkedText);
+ bindMethod("conversationIdentifier", &TextInputController::conversationIdentifier);
+ bindMethod("substringFromRange", &TextInputController::substringFromRange);
+ bindMethod("attributedSubstringFromRange", &TextInputController::attributedSubstringFromRange);
+ bindMethod("markedRange", &TextInputController::markedRange);
+ bindMethod("selectedRange", &TextInputController::selectedRange);
+ bindMethod("firstRectForCharacterRange", &TextInputController::firstRectForCharacterRange);
+ bindMethod("characterIndexForPoint", &TextInputController::characterIndexForPoint);
+ bindMethod("validAttributesForMarkedText", &TextInputController::validAttributesForMarkedText);
+ bindMethod("makeAttributedString", &TextInputController::makeAttributedString);
+}
+
+WebFrame* TextInputController::getMainFrame()
+{
+ return testShell->webView()->mainFrame();
+}
+
+void TextInputController::insertText(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ WebFrame* mainFrame = getMainFrame();
+ if (!mainFrame)
+ return;
+ if (arguments.size() < 1 || !arguments[0].isString())
+ return;
+
+ if (mainFrame->hasMarkedText()) {
+ mainFrame->unmarkText();
+ mainFrame->replaceSelection(WebString());
+ }
+ mainFrame->insertText(WebString::fromUTF8(arguments[0].toString()));
+}
+
+void TextInputController::doCommand(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ WebFrame* mainFrame = getMainFrame();
+ 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();
+
+ WebFrame* mainFrame = getMainFrame();
+ if (!mainFrame)
+ return;
+
+ if (arguments.size() >= 3 && arguments[0].isString()
+ && arguments[1].isNumber() && arguments[2].isNumber()) {
+ mainFrame->setMarkedText(WebString::fromUTF8(arguments[0].toString()),
+ arguments[1].toInt32(),
+ arguments[2].toInt32());
+ }
+}
+
+void TextInputController::unmarkText(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+
+ WebFrame* mainFrame = getMainFrame();
+ if (!mainFrame)
+ return;
+
+ mainFrame->unmarkText();
+}
+
+void TextInputController::hasMarkedText(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+
+ WebFrame* mainFrame = getMainFrame();
+ if (!mainFrame)
+ return;
+
+ result->set(mainFrame->hasMarkedText());
+}
+
+void TextInputController::conversationIdentifier(const CppArgumentList&, CppVariant* result)
+{
+ // FIXME: Implement this.
+ result->setNull();
+}
+
+void TextInputController::substringFromRange(const CppArgumentList&, CppVariant* result)
+{
+ // FIXME: Implement this.
+ result->setNull();
+}
+
+void TextInputController::attributedSubstringFromRange(const CppArgumentList&, CppVariant* result)
+{
+ // FIXME: Implement this.
+ result->setNull();
+}
+
+void TextInputController::markedRange(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+
+ WebFrame* mainFrame = getMainFrame();
+ if (!mainFrame)
+ return;
+
+ WebRange range = mainFrame->markedRange();
+ char buffer[30];
+ snprintf(buffer, 30, "%d,%d", range.startOffset(), range.endOffset());
+ result->set(string(buffer));
+}
+
+void TextInputController::selectedRange(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+
+ WebFrame* mainFrame = getMainFrame();
+ if (!mainFrame)
+ return;
+
+ WebRange range = mainFrame->selectionRange();
+ char buffer[30];
+ snprintf(buffer, 30, "%d,%d", range.startOffset(), range.endOffset());
+ result->set(string(buffer));
+}
+
+void TextInputController::firstRectForCharacterRange(const CppArgumentList&, CppVariant* result)
+{
+ // FIXME: Implement this.
+ result->setNull();
+}
+
+void TextInputController::characterIndexForPoint(const CppArgumentList&, CppVariant* result)
+{
+ // FIXME: Implement this.
+ result->setNull();
+}
+
+void TextInputController::validAttributesForMarkedText(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+
+ WebFrame* mainFrame = getMainFrame();
+ if (!mainFrame)
+ return;
+
+ result->set("NSUnderline,NSUnderlineColor,NSMarkedClauseSegment,"
+ "NSTextInputReplacementRangeAttributeName");
+}
+
+void TextInputController::makeAttributedString(const CppArgumentList&, CppVariant* result)
+{
+ // FIXME: Implement this.
+ result->setNull();
+}
diff --git a/WebKitTools/DumpRenderTree/chromium/TextInputController.h b/WebKitTools/DumpRenderTree/chromium/TextInputController.h
new file mode 100644
index 0000000..a912ba1
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/TextInputController.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2010 Google 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.
+ */
+
+<<<<<<< HEAD:WebCore/bindings/v8/custom/V8NavigatorCustom.cpp
+#include "config.h"
+#include "V8Navigator.h"
+
+#include "RuntimeEnabledFeatures.h"
+#include "V8DOMWindow.h"
+#include "V8DOMWrapper.h"
+
+#if PLATFORM(ANDROID)
+#include "ExceptionCode.h"
+#include "V8CustomApplicationInstalledCallback.h"
+#include "V8Proxy.h"
+#endif
+
+namespace WebCore {
+
+v8::Handle<v8::Value> toV8(Navigator* impl)
+{
+ if (!impl)
+ return v8::Null();
+ v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(impl);
+ if (wrapper.IsEmpty()) {
+ wrapper = V8Navigator::wrap(impl);
+ if (!wrapper.IsEmpty())
+ V8DOMWrapper::setHiddenWindowReference(impl->frame(), V8DOMWindow::navigatorIndex, wrapper);
+ }
+ return wrapper;
+}
+
+#if PLATFORM(ANDROID) && ENABLE(APPLICATION_INSTALLED)
+
+static PassRefPtr<ApplicationInstalledCallback> createApplicationInstalledCallback(
+ v8::Local<v8::Value> value, bool& succeeded)
+{
+ succeeded = true;
+
+ if (!value->IsFunction()) {
+ succeeded = false;
+ throwError("The second argument should be a function");
+ return 0;
+ }
+
+ Frame* frame = V8Proxy::retrieveFrameForCurrentContext();
+ return V8CustomApplicationInstalledCallback::create(value, frame);
+}
+
+v8::Handle<v8::Value> V8Navigator::isApplicationInstalledCallback(const v8::Arguments& args)
+{
+ INC_STATS("DOM.isApplicationInstalled()");
+ bool succeeded = false;
+
+ if (args.Length() < 2)
+ return throwError("Two arguments required: an application name and a callback.", V8Proxy::SyntaxError);
+
+ if (!args[0]->IsString())
+ return throwError("The first argument should be a string.");
+
+ RefPtr<ApplicationInstalledCallback> callback =
+ createApplicationInstalledCallback(args[1], succeeded);
+ if (!succeeded)
+ return v8::Undefined();
+
+ ASSERT(callback);
+
+ Navigator* navigator = V8Navigator::toNative(args.Holder());
+ if (!navigator->isApplicationInstalled(toWebCoreString(args[0]), callback.release()))
+ return throwError(INVALID_STATE_ERR);
+
+ return v8::Undefined();
+}
+
+#endif // PLATFORM(ANDROID) && ENABLE(APPLICATION_INSTALLED)
+
+} // namespace WebCore
+=======
+// 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 "CppBoundClass.h"
+
+class TestShell;
+
+namespace WebKit {
+class WebFrame;
+}
+
+class TextInputController : public CppBoundClass {
+public:
+ TextInputController(TestShell*);
+
+ 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 conversationIdentifier(const CppArgumentList&, CppVariant*);
+ void substringFromRange(const CppArgumentList&, CppVariant*);
+ void attributedSubstringFromRange(const CppArgumentList&, CppVariant*);
+ void markedRange(const CppArgumentList&, CppVariant*);
+ void selectedRange(const CppArgumentList&, CppVariant*);
+ void firstRectForCharacterRange(const CppArgumentList&, CppVariant*);
+ void characterIndexForPoint(const CppArgumentList&, CppVariant*);
+ void validAttributesForMarkedText(const CppArgumentList&, CppVariant*);
+ void makeAttributedString(const CppArgumentList&, CppVariant*);
+
+private:
+ // Returns the test shell's main WebFrame.
+ static WebKit::WebFrame* getMainFrame();
+
+ // Non-owning pointer. The TextInputController is owned by the TestShell.
+ static TestShell* testShell;
+};
+
+#endif // TextInputController_h
+>>>>>>> webkit.org at r58033:WebKitTools/DumpRenderTree/chromium/TextInputController.h
diff --git a/WebKitTools/DumpRenderTree/chromium/WebViewHost.cpp b/WebKitTools/DumpRenderTree/chromium/WebViewHost.cpp
new file mode 100644
index 0000000..95b1c7e
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/WebViewHost.cpp
@@ -0,0 +1,1316 @@
+/*
+ * Copyright (C) 2010 Google 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 "config.h"
+#include "WebViewHost.h"
+
+#include "LayoutTestController.h"
+#include "TestNavigationController.h"
+#include "TestShell.h"
+#include "TestWebWorker.h"
+#include "net/base/net_errors.h" // FIXME: can we remove this?
+#include "public/WebCString.h"
+#include "public/WebConsoleMessage.h"
+#include "public/WebContextMenuData.h"
+#include "public/WebDataSource.h"
+#include "public/WebDragData.h"
+#include "public/WebFrame.h"
+#include "public/WebHistoryItem.h"
+#include "public/WebNode.h"
+#include "public/WebRange.h"
+#include "public/WebRect.h"
+#include "public/WebScreenInfo.h"
+#include "public/WebSize.h"
+#include "public/WebStorageNamespace.h"
+#include "public/WebURLRequest.h"
+#include "public/WebURLResponse.h"
+#include "public/WebView.h"
+#include "skia/ext/platform_canvas.h"
+#include "webkit/support/webkit_support.h"
+#include <wtf/Assertions.h>
+
+using namespace WebKit;
+using namespace skia;
+using namespace std;
+
+static const int screenWidth = 1920;
+static const int screenHeight = 1080;
+static const int screenUnavailableBorder = 8;
+
+// WebNavigationType debugging strings taken from PolicyDelegate.mm.
+static const char* linkClickedString = "link clicked";
+static const char* formSubmittedString = "form submitted";
+static const char* backForwardString = "back/forward";
+static const char* reloadString = "reload";
+static const char* formResubmittedString = "form resubmitted";
+static const char* otherString = "other";
+static const char* illegalString = "illegal value";
+
+static int nextPageID = 1;
+
+// Used to write a platform neutral file:/// URL by only taking the filename
+// (e.g., converts "file:///tmp/foo.txt" to just "foo.txt").
+static string urlSuitableForTestResult(const string& url)
+{
+ if (url.empty() || string::npos == url.find("file://"))
+ return url;
+
+ size_t pos = url.rfind('/');
+ if (pos == string::npos) {
+#if OS(WINDOWS)
+ 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;
+}
+
+// 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").
+static 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);
+}
+
+// Adds a file called "DRTFakeFile" to |data_object| (CF_HDROP). Use to fake
+// dragging a file.
+static void addDRTFakeFileToDataObject(WebDragData* dragData)
+{
+ dragData->appendToFileNames(WebString::fromUTF8("DRTFakeFile"));
+}
+
+// Get a debugging string from a WebNavigationType.
+static const char* webNavigationTypeToString(WebNavigationType type)
+{
+ switch (type) {
+ case WebKit::WebNavigationTypeLinkClicked:
+ return linkClickedString;
+ case WebKit::WebNavigationTypeFormSubmitted:
+ return formSubmittedString;
+ case WebKit::WebNavigationTypeBackForward:
+ return backForwardString;
+ case WebKit::WebNavigationTypeReload:
+ return reloadString;
+ case WebKit::WebNavigationTypeFormResubmitted:
+ return formResubmittedString;
+ case WebKit::WebNavigationTypeOther:
+ return otherString;
+ }
+ return illegalString;
+}
+
+static string URLDescription(const GURL& url)
+{
+ if (url.SchemeIs("file"))
+ return url.ExtractFileName();
+ return url.possibly_invalid_spec();
+}
+
+static void printResponseDescription(const WebURLResponse& response)
+{
+ if (response.isNull()) {
+ fputs("(null)", stdout);
+ return;
+ }
+ string url = response.url().spec();
+ printf("<NSURLResponse %s, http status code %d>",
+ descriptionSuitableForTestResult(url).c_str(),
+ response.httpStatusCode());
+}
+
+static void printErrorDescription(const WebURLError& error)
+{
+ string domain = error.domain.utf8();
+ int code = error.reason;
+
+ if (domain == net::kErrorDomain) {
+ domain = "NSURLErrorDomain";
+ switch (error.reason) {
+ case net::ERR_ABORTED:
+ code = -999;
+ break;
+ case net::ERR_UNSAFE_PORT:
+ // Our unsafe port checking happens at the network stack level, but we
+ // make this translation here to match the behavior of stock WebKit.
+ domain = "WebKitErrorDomain";
+ code = 103;
+ break;
+ case net::ERR_ADDRESS_INVALID:
+ case net::ERR_ADDRESS_UNREACHABLE:
+ code = -1004;
+ break;
+ }
+ } else
+ LOG_ERROR("Unknown error domain");
+
+ printf("<NSError domain %s, code %d, failing URL \"%s\">",
+ domain.c_str(), code, error.unreachableURL.spec().data());
+}
+
+static void printNodeDescription(const WebNode& node, int exception)
+{
+ if (exception) {
+ fputs("ERROR", stdout);
+ return;
+ }
+ if (node.isNull()) {
+ fputs("(null)", stdout);
+ return;
+ }
+ fputs(node.nodeName().utf8().data(), stdout);
+ const WebNode& parent = node.parentNode();
+ if (!parent.isNull()) {
+ fputs(" > ", stdout);
+ printNodeDescription(parent, 0);
+ }
+}
+
+static void printRangeDescription(const WebRange& range)
+{
+ if (range.isNull()) {
+ fputs("(null)", stdout);
+ return;
+ }
+ printf("range from %d of ", range.startOffset());
+ int exception = 0;
+ WebNode startNode = range.startContainer(exception);
+ printNodeDescription(startNode, exception);
+ printf(" to %d of ", range.endOffset());
+ WebNode endNode = range.endContainer(exception);
+ printNodeDescription(endNode, exception);
+}
+
+static string editingActionDescription(WebEditingAction action)
+{
+ switch (action) {
+ case WebKit::WebEditingActionTyped:
+ return "WebViewInsertActionTyped";
+ case WebKit::WebEditingActionPasted:
+ return "WebViewInsertActionPasted";
+ case WebKit::WebEditingActionDropped:
+ return "WebViewInsertActionDropped";
+ }
+ return "(UNKNOWN ACTION)";
+}
+
+static string textAffinityDescription(WebTextAffinity affinity)
+{
+ switch (affinity) {
+ case WebKit::WebTextAffinityUpstream:
+ return "NSSelectionAffinityUpstream";
+ case WebKit::WebTextAffinityDownstream:
+ return "NSSelectionAffinityDownstream";
+ }
+ return "(UNKNOWN AFFINITY)";
+}
+
+// WebViewClient -------------------------------------------------------------
+
+WebView* WebViewHost::createView(WebFrame*)
+{
+ if (!layoutTestController()->canOpenWindows())
+ return 0;
+ return m_shell->createWebView()->webView();
+}
+
+WebWidget* WebViewHost::createPopupMenu(bool)
+{
+ return 0;
+}
+
+WebWidget* WebViewHost::createPopupMenu(const WebPopupMenuInfo&)
+{
+ return 0;
+}
+
+WebStorageNamespace* WebViewHost::createSessionStorageNamespace()
+{
+ return WebKit::WebStorageNamespace::createSessionStorageNamespace();
+}
+
+void WebViewHost::didAddMessageToConsole(const WebConsoleMessage& message, const WebString& sourceName, unsigned sourceLine)
+{
+ // This matches win DumpRenderTree's UIDelegate.cpp.
+ string newMessage;
+ if (!message.text.isEmpty()) {
+ newMessage = message.text.utf8();
+ size_t fileProtocol = newMessage.find("file://");
+ if (fileProtocol != string::npos) {
+ newMessage = newMessage.substr(0, fileProtocol)
+ + urlSuitableForTestResult(newMessage.substr(fileProtocol));
+ }
+ }
+ printf("CONSOLE MESSAGE: line %d: %s\n", sourceLine, newMessage.data());
+}
+
+void WebViewHost::didStartLoading()
+{
+ m_shell->setIsLoading(true);
+}
+
+void WebViewHost::didStopLoading()
+{
+ m_shell->setIsLoading(false);
+}
+
+// The output from these methods in layout test mode should match that
+// expected by the layout tests. See EditingDelegate.m in DumpRenderTree.
+
+bool WebViewHost::shouldBeginEditing(const WebRange& range)
+{
+ if (layoutTestController()->shouldDumpEditingCallbacks()) {
+ fputs("EDITING DELEGATE: shouldBeginEditingInDOMRange:", stdout);
+ printRangeDescription(range);
+ fputs("\n", stdout);
+ }
+ return layoutTestController()->acceptsEditing();
+}
+
+bool WebViewHost::shouldEndEditing(const WebRange& range)
+{
+ if (layoutTestController()->shouldDumpEditingCallbacks()) {
+ fputs("EDITING DELEGATE: shouldEndEditingInDOMRange:", stdout);
+ printRangeDescription(range);
+ fputs("\n", stdout);
+ }
+ return layoutTestController()->acceptsEditing();
+}
+
+bool WebViewHost::shouldInsertNode(const WebNode& node, const WebRange& range, WebEditingAction action)
+{
+ if (layoutTestController()->shouldDumpEditingCallbacks()) {
+ fputs("EDITING DELEGATE: shouldInsertNode:", stdout);
+ printNodeDescription(node, 0);
+ fputs(" replacingDOMRange:", stdout);
+ printRangeDescription(range);
+ printf(" givenAction:%s\n", editingActionDescription(action).c_str());
+ }
+ return layoutTestController()->acceptsEditing();
+}
+
+bool WebViewHost::shouldInsertText(const WebString& text, const WebRange& range, WebEditingAction action)
+{
+ if (layoutTestController()->shouldDumpEditingCallbacks()) {
+ printf("EDITING DELEGATE: shouldInsertText:%s replacingDOMRange:", text.utf8().data());
+ printRangeDescription(range);
+ printf(" givenAction:%s\n", editingActionDescription(action).c_str());
+ }
+ return layoutTestController()->acceptsEditing();
+}
+
+bool WebViewHost::shouldChangeSelectedRange(
+ const WebRange& fromRange, const WebRange& toRange, WebTextAffinity affinity, bool stillSelecting)
+{
+ if (layoutTestController()->shouldDumpEditingCallbacks()) {
+ fputs("EDITING DELEGATE: shouldChangeSelectedDOMRange:", stdout);
+ printRangeDescription(fromRange);
+ fputs(" toDOMRange:", stdout);
+ printRangeDescription(toRange);
+ printf(" affinity:%s stillSelecting:%s\n",
+ textAffinityDescription(affinity).c_str(),
+ (stillSelecting ? "TRUE" : "FALSE"));
+ }
+ return layoutTestController()->acceptsEditing();
+}
+
+bool WebViewHost::shouldDeleteRange(const WebRange& range)
+{
+ if (layoutTestController()->shouldDumpEditingCallbacks()) {
+ fputs("EDITING DELEGATE: shouldDeleteDOMRange:", stdout);
+ printRangeDescription(range);
+ fputs("\n", stdout);
+ }
+ return layoutTestController()->acceptsEditing();
+}
+
+bool WebViewHost::shouldApplyStyle(const WebString& style, const WebRange& range)
+{
+ if (layoutTestController()->shouldDumpEditingCallbacks()) {
+ printf("EDITING DELEGATE: shouldApplyStyle:%s toElementsInDOMRange:", style.utf8().data());
+ printRangeDescription(range);
+ fputs("\n", stdout);
+ }
+ return layoutTestController()->acceptsEditing();
+}
+
+bool WebViewHost::isSmartInsertDeleteEnabled()
+{
+ return m_smartInsertDeleteEnabled;
+}
+
+bool WebViewHost::isSelectTrailingWhitespaceEnabled()
+{
+ return m_selectTrailingWhitespaceEnabled;
+}
+
+void WebViewHost::didBeginEditing()
+{
+ if (!layoutTestController()->shouldDumpEditingCallbacks())
+ return;
+ fputs("EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification\n", stdout);
+}
+
+void WebViewHost::didChangeSelection(bool isEmptySelection)
+{
+ if (layoutTestController()->shouldDumpEditingCallbacks())
+ fputs("EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification\n", stdout);
+ // No need to update clipboard with the selected text in DRT.
+}
+
+void WebViewHost::didChangeContents()
+{
+ if (!layoutTestController()->shouldDumpEditingCallbacks())
+ return;
+ fputs("EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification\n", stdout);
+}
+
+void WebViewHost::didEndEditing()
+{
+ if (!layoutTestController()->shouldDumpEditingCallbacks())
+ return;
+ fputs("EDITING DELEGATE: webViewDidEndEditing:WebViewDidEndEditingNotification\n", stdout);
+}
+
+bool WebViewHost::handleCurrentKeyboardEvent()
+{
+ if (m_editCommandName.empty())
+ return false;
+ WebFrame* frame = webView()->focusedFrame();
+ if (!frame)
+ return false;
+
+ return frame->executeCommand(WebString::fromUTF8(m_editCommandName), WebString::fromUTF8(m_editCommandValue));
+}
+
+void WebViewHost::spellCheck(const WebString& text, int& misspelledOffset, int& misspelledLength)
+{
+ // Check the spelling of the given text.
+#if OS(MAC_OS_X)
+ // FIXME: rebaseline layout-test results of Windows and Linux so we
+ // can enable this mock spellchecker on them.
+ m_spellcheck.spellCheckWord(text, &misspelledOffset, &misspelledLength);
+#endif
+}
+
+WebString WebViewHost::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();
+}
+
+void WebViewHost::runModalAlertDialog(WebFrame*, const WebString& message)
+{
+ printf("ALERT: %s\n", message.utf8().data());
+}
+
+bool WebViewHost::runModalConfirmDialog(WebFrame*, const WebString& message)
+{
+ printf("CONFIRM: %s\n", message.utf8().data());
+ return true;
+}
+
+bool WebViewHost::runModalPromptDialog(WebFrame* frame, const WebString& message,
+ const WebString& defaultValue, WebString*)
+{
+ printf("PROMPT: %s, default text: %s\n", message.utf8().data(), defaultValue.utf8().data());
+ return true;
+}
+
+bool WebViewHost::runModalBeforeUnloadDialog(WebFrame*, const WebString&)
+{
+ return true; // Allow window closure.
+}
+
+void WebViewHost::showContextMenu(WebFrame*, const WebContextMenuData&)
+{
+}
+
+
+void WebViewHost::setStatusText(const WebString& text)
+{
+ if (!layoutTestController()->shouldDumpStatusCallbacks())
+ return;
+ // When running tests, write to stdout.
+ printf("UI DELEGATE STATUS CALLBACK: setStatusText:%s\n", text.utf8().data());
+}
+
+void WebViewHost::startDragging(const WebPoint& mouseCoords, const WebDragData& data, WebDragOperationsMask mask)
+{
+ WebDragData mutableDragData = data;
+ if (layoutTestController()->shouldAddFileToPasteboard()) {
+ // Add a file called DRTFakeFile to the drag&drop clipboard.
+ addDRTFakeFileToDataObject(&mutableDragData);
+ }
+
+ // 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.
+ EventSender::doDragDrop(mouseCoords, mutableDragData, mask);
+}
+
+void WebViewHost::navigateBackForwardSoon(int offset)
+{
+ navigationController()->goToOffset(offset);
+}
+
+int WebViewHost::historyBackListCount()
+{
+ return navigationController()->lastCommittedEntryIndex();
+}
+
+int WebViewHost::historyForwardListCount()
+{
+ int currentIndex =navigationController()->lastCommittedEntryIndex();
+ return navigationController()->entryCount() - currentIndex - 1;
+}
+
+void WebViewHost::focusAccessibilityObject(const WebAccessibilityObject& object)
+{
+ m_shell->accessibilityController()->setFocusedElement(object);
+}
+
+// WebWidgetClient -----------------------------------------------------------
+
+void WebViewHost::didInvalidateRect(const WebRect& rect)
+{
+ if (m_isPainting)
+ LOG_ERROR("unexpected invalidation while painting");
+ updatePaintRect(rect);
+}
+
+void WebViewHost::didScrollRect(int, int, const WebRect& clipRect)
+{
+ // This is used for optimizing painting when the renderer is scrolled. We're
+ // currently not doing any optimizations so just invalidate the region.
+ didInvalidateRect(clipRect);
+}
+
+void WebViewHost::didFocus()
+{
+ m_shell->setFocus(webWidget(), true);
+}
+
+void WebViewHost::didBlur()
+{
+ m_shell->setFocus(webWidget(), false);
+}
+
+WebScreenInfo WebViewHost::screenInfo()
+{
+ // We don't need to set actual values.
+ WebScreenInfo info;
+ info.depth = 24;
+ info.depthPerComponent = 8;
+ info.isMonochrome = false;
+ info.rect = WebRect(0, 0, screenWidth, screenHeight);
+ // Use values different from info.rect for testing.
+ info.availableRect = WebRect(screenUnavailableBorder, screenUnavailableBorder,
+ screenWidth - screenUnavailableBorder * 2,
+ screenHeight - screenUnavailableBorder * 2);
+ return info;
+}
+
+void WebViewHost::show(WebNavigationPolicy)
+{
+ m_hasWindow = true;
+ WebSize size = webWidget()->size();
+ updatePaintRect(WebRect(0, 0, size.width, size.height));
+}
+
+void WebViewHost::closeWidgetSoon()
+{
+ m_hasWindow = false;
+ m_shell->closeWindow(this);
+}
+
+void WebViewHost::didChangeCursor(const WebCursorInfo& cursorInfo)
+{
+ if (!hasWindow())
+ return;
+ m_currentCursor = cursorInfo;
+}
+
+WebRect WebViewHost::windowRect()
+{
+ return m_windowRect;
+}
+
+void WebViewHost::setWindowRect(const WebRect& rect)
+{
+ m_windowRect = rect;
+ const int border2 = TestShell::virtualWindowBorder * 2;
+ if (m_windowRect.width <= border2)
+ m_windowRect.width = 1 + border2;
+ if (m_windowRect.height <= border2)
+ m_windowRect.height = 1 + border2;
+ int width = m_windowRect.width - border2;
+ int height = m_windowRect.height - border2;
+ discardBackingStore();
+ webWidget()->resize(WebSize(width, height));
+ updatePaintRect(WebRect(0, 0, width, height));
+}
+
+WebRect WebViewHost::rootWindowRect()
+{
+ return windowRect();
+}
+
+WebRect WebViewHost::windowResizerRect()
+{
+ // Not necessary.
+ return WebRect();
+}
+
+void WebViewHost::runModal()
+{
+ // FIXME: Should we implement this in DRT?
+}
+
+// WebFrameClient ------------------------------------------------------------
+
+WebPlugin* WebViewHost::createPlugin(WebFrame* frame, const WebPluginParams& params)
+{
+ return webkit_support::CreateWebPlugin(frame, params);
+}
+
+WebWorker* WebViewHost::createWorker(WebFrame*, WebWorkerClient*)
+{
+ return new TestWebWorker();
+}
+
+WebMediaPlayer* WebViewHost::createMediaPlayer(WebFrame* frame, WebMediaPlayerClient* client)
+{
+ return webkit_support::CreateMediaPlayer(frame, client);
+}
+
+bool WebViewHost::allowPlugins(WebFrame* frame, bool enabledPerSettings)
+{
+ return enabledPerSettings;
+}
+
+bool WebViewHost::allowImages(WebFrame* frame, bool enabledPerSettings)
+{
+ return enabledPerSettings;
+}
+
+void WebViewHost::loadURLExternally(WebFrame*, const WebURLRequest& request, WebNavigationPolicy policy)
+{
+ ASSERT(policy != WebKit::WebNavigationPolicyCurrentTab);
+ WebViewHost* another = m_shell->createNewWindow(request.url());
+ if (another)
+ another->show(policy);
+}
+
+WebNavigationPolicy WebViewHost::decidePolicyForNavigation(
+ WebFrame*, const WebURLRequest& request,
+ WebNavigationType type, const WebNode& originatingNode,
+ WebNavigationPolicy defaultPolicy, bool isRedirect)
+{
+ WebNavigationPolicy result;
+ if (!m_policyDelegateEnabled)
+ return defaultPolicy;
+
+ printf("Policy delegate: attempt to load %s with navigation type '%s'",
+ URLDescription(request.url()).c_str(), webNavigationTypeToString(type));
+ if (!originatingNode.isNull()) {
+ fputs(" originating from ", stdout);
+ printNodeDescription(originatingNode, 0);
+ }
+ fputs("\n", stdout);
+ if (m_policyDelegateIsPermissive)
+ result = WebKit::WebNavigationPolicyCurrentTab;
+ else
+ result = WebKit::WebNavigationPolicyIgnore;
+
+ if (m_policyDelegateShouldNotifyDone)
+ layoutTestController()->policyDelegateDone();
+ return result;
+}
+
+bool WebViewHost::canHandleRequest(WebFrame*, const WebURLRequest& request)
+{
+ GURL url = request.url();
+ // Just reject the scheme used in
+ // LayoutTests/http/tests/misc/redirect-to-external-url.html
+ return !url.SchemeIs("spaceballs");
+}
+
+WebURLError WebViewHost::cannotHandleRequestError(WebFrame*, const WebURLRequest& request)
+{
+ WebURLError error;
+ // A WebKit layout test expects the following values.
+ // unableToImplementPolicyWithError() below prints them.
+ error.domain = WebString::fromUTF8("WebKitErrorDomain");
+ error.reason = 101;
+ error.unreachableURL = request.url();
+ return error;
+}
+
+WebURLError WebViewHost::cancelledError(WebFrame*, const WebURLRequest& request)
+{
+ WebURLError error;
+ error.domain = WebString::fromUTF8(net::kErrorDomain);
+ error.reason = net::ERR_ABORTED;
+ error.unreachableURL = request.url();
+ return error;
+}
+
+void WebViewHost::unableToImplementPolicyWithError(WebFrame* frame, const WebURLError& error)
+{
+ printf("Policy delegate: unable to implement policy with error domain '%s', "
+ "error code %d, in frame '%s'\n",
+ error.domain.utf8().data(), error.reason, frame->name().utf8().data());
+}
+
+void WebViewHost::willPerformClientRedirect(WebFrame* frame, const WebURL& from, const WebURL& to,
+ double interval, double fire_time)
+{
+ if (!m_shell->shouldDumpFrameLoadCallbacks())
+ return;
+ printFrameDescription(frame);
+ printf(" - willPerformClientRedirectToURL: %s \n", to.spec().data());
+}
+
+void WebViewHost::didCancelClientRedirect(WebFrame* frame)
+{
+ if (!m_shell->shouldDumpFrameLoadCallbacks())
+ return;
+ printFrameDescription(frame);
+ fputs(" - didCancelClientRedirectForFrame\n", stdout);
+}
+
+void WebViewHost::didCreateDataSource(WebFrame*, WebDataSource* ds)
+{
+ ds->setExtraData(m_pendingExtraData.release());
+}
+
+void WebViewHost::didStartProvisionalLoad(WebFrame* frame)
+{
+ if (m_shell->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(frame);
+ fputs(" - didStartProvisionalLoadForFrame\n", stdout);
+ }
+
+ if (!m_topLoadingFrame)
+ m_topLoadingFrame = frame;
+
+ if (layoutTestController()->stopProvisionalFrameLoads()) {
+ printFrameDescription(frame);
+ fputs(" - stopping load in didStartProvisionalLoadForFrame callback\n", stdout);
+ frame->stopLoading();
+ }
+ updateAddressBar(frame->view());
+}
+
+void WebViewHost::didReceiveServerRedirectForProvisionalLoad(WebFrame* frame)
+{
+ if (m_shell->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(frame);
+ fputs(" - didReceiveServerRedirectForProvisionalLoadForFrame\n", stdout);
+ }
+ updateAddressBar(frame->view());
+}
+
+void WebViewHost::didFailProvisionalLoad(WebFrame* frame, const WebURLError& error)
+{
+ if (m_shell->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(frame);
+ fputs(" - didFailProvisionalLoadWithError\n", stdout);
+ }
+
+ locationChangeDone(frame);
+
+ // Don't display an error page if we're running layout tests, because
+ // DumpRenderTree doesn't.
+}
+
+void WebViewHost::didCommitProvisionalLoad(WebFrame* frame, bool isNewNavigation)
+{
+ if (m_shell->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(frame);
+ fputs(" - didCommitLoadForFrame\n", stdout);
+ }
+ updateForCommittedLoad(frame, isNewNavigation);
+}
+
+void WebViewHost::didClearWindowObject(WebFrame* frame)
+{
+ m_shell->bindJSObjectsToWindow(frame);
+}
+
+void WebViewHost::didReceiveTitle(WebFrame* frame, const WebString& title)
+{
+ WebCString title8 = title.utf8();
+
+ if (m_shell->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(frame);
+ printf(" - didReceiveTitle: %s\n", title8.data());
+ }
+
+ if (layoutTestController()->shouldDumpTitleChanges())
+ printf("TITLE CHANGED: %s\n", title8.data());
+
+ setPageTitle(title);
+}
+
+void WebViewHost::didFinishDocumentLoad(WebFrame* frame)
+{
+ if (m_shell->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(frame);
+ fputs(" - didFinishDocumentLoadForFrame\n", stdout);
+ } else {
+ unsigned pendingUnloadEvents = frame->unloadListenerCount();
+ if (pendingUnloadEvents) {
+ printFrameDescription(frame);
+ printf(" - has %u onunload handler(s)\n", pendingUnloadEvents);
+ }
+ }
+}
+
+void WebViewHost::didHandleOnloadEvents(WebFrame* frame)
+{
+ if (m_shell->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(frame);
+ fputs(" - didHandleOnloadEventsForFrame\n", stdout);
+ }
+}
+
+void WebViewHost::didFailLoad(WebFrame* frame, const WebURLError& error)
+{
+ if (m_shell->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(frame);
+ fputs(" - didFailLoadWithError\n", stdout);
+ }
+ locationChangeDone(frame);
+}
+
+void WebViewHost::didFinishLoad(WebFrame* frame)
+{
+ if (m_shell->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(frame);
+ fputs(" - didFinishLoadForFrame\n", stdout);
+ }
+ updateAddressBar(frame->view());
+ locationChangeDone(frame);
+}
+
+void WebViewHost::didChangeLocationWithinPage(WebFrame* frame, bool isNewNavigation)
+{
+ frame->dataSource()->setExtraData(m_pendingExtraData.release());
+ if (m_shell->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(frame);
+ fputs(" - didChangeLocationWithinPageForFrame\n", stdout);
+ }
+ updateForCommittedLoad(frame, isNewNavigation);
+}
+
+void WebViewHost::assignIdentifierToRequest(WebFrame*, unsigned identifier, const WebURLRequest& request)
+{
+ if (!m_shell->shouldDumpResourceLoadCallbacks())
+ return;
+ m_resourceIdentifierMap.set(identifier, descriptionSuitableForTestResult(request.url().spec()));
+}
+
+void WebViewHost::willSendRequest(WebFrame*, unsigned identifier, WebURLRequest& request, const WebURLResponse& redirectResponse)
+{
+ // Need to use GURL for host() and SchemeIs()
+ GURL url = request.url();
+ string requestURL = url.possibly_invalid_spec();
+
+ if (layoutTestController()->shouldDumpResourceLoadCallbacks()) {
+ GURL mainDocumentURL = request.firstPartyForCookies();
+ printResourceDescription(identifier);
+ printf(" - willSendRequest <NSURLRequest URL %s, main document URL %s,"
+ " http method %s> redirectResponse %s\n",
+ descriptionSuitableForTestResult(requestURL).c_str(),
+ URLDescription(mainDocumentURL).c_str(),
+ request.httpMethod().utf8().data());
+ printResponseDescription(redirectResponse);
+ fputs("\n", stdout);
+ }
+
+ if (!redirectResponse.isNull() && m_blocksRedirects) {
+ fputs("Returning null for this redirect\n", stdout);
+ // To block the request, we set its URL to an empty one.
+ request.setURL(WebURL());
+ return;
+ }
+
+ if (m_requestReturnNull) {
+ // To block the request, we set its URL to an empty one.
+ request.setURL(WebURL());
+ return;
+ }
+
+ string host = url.host();
+ // 255.255.255.255 is used in some tests that expect to get back an error.
+ if (!host.empty() && (url.SchemeIs("http") || url.SchemeIs("https"))
+ && host != "127.0.0.1"
+ && host != "255.255.255.255"
+ && host != "localhost") {
+ printf("Blocked access to external URL %s\n", requestURL.c_str());
+
+ // To block the request, we set its URL to an empty one.
+ request.setURL(WebURL());
+ return;
+ }
+
+ // Set the new substituted URL.
+ request.setURL(webkit_support::RewriteLayoutTestsURL(request.url().spec()));
+}
+
+void WebViewHost::didReceiveResponse(WebFrame*, unsigned identifier, const WebURLResponse& response)
+{
+ if (!m_shell->shouldDumpResourceLoadCallbacks())
+ return;
+ printResourceDescription(identifier);
+ fputs(" - didReceiveResponse ", stdout);
+ printResponseDescription(response);
+ fputs("\n", stdout);
+}
+
+void WebViewHost::didFinishResourceLoad(WebFrame*, unsigned identifier)
+{
+ if (m_shell->shouldDumpResourceLoadCallbacks()) {
+ printResourceDescription(identifier);
+ fputs(" - didFinishLoading\n", stdout);
+ }
+ m_resourceIdentifierMap.remove(identifier);
+}
+
+void WebViewHost::didFailResourceLoad(WebFrame*, unsigned identifier, const WebURLError& error)
+{
+ if (m_shell->shouldDumpResourceLoadCallbacks()) {
+ printResourceDescription(identifier);
+ fputs(" - didFailLoadingWithError: ", stdout);
+ printErrorDescription(error);
+ fputs("\n", stdout);
+ }
+ m_resourceIdentifierMap.remove(identifier);
+}
+
+void WebViewHost::didDisplayInsecureContent(WebFrame*)
+{
+ if (m_shell->shouldDumpFrameLoadCallbacks())
+ fputs("didDisplayInsecureContent\n", stdout);
+}
+
+void WebViewHost::didRunInsecureContent(WebFrame*, const WebSecurityOrigin& origin)
+{
+ if (m_shell->shouldDumpFrameLoadCallbacks())
+ fputs("didRunInsecureContent\n", stdout);
+}
+
+bool WebViewHost::allowScript(WebFrame*, bool enabledPerSettings)
+{
+ return enabledPerSettings;
+}
+
+// Public functions -----------------------------------------------------------
+
+WebViewHost::WebViewHost(TestShell* shell)
+ : m_policyDelegateEnabled(false)
+ , m_policyDelegateIsPermissive(false)
+ , m_policyDelegateShouldNotifyDone(false)
+ , m_shell(shell)
+ , m_topLoadingFrame(0)
+ , m_hasWindow(false)
+ , m_pageId(-1)
+ , m_lastPageIdUpdated(-1)
+ , m_smartInsertDeleteEnabled(true)
+#if OS(WINDOWS)
+ , m_selectTrailingWhitespaceEnabled(true)
+#else
+ , m_selectTrailingWhitespaceEnabled(false)
+#endif
+ , m_blocksRedirects(false)
+ , m_requestReturnNull(false)
+ , m_isPainting(false)
+ , m_webWidget(0)
+{
+ m_navigationController.set(new TestNavigationController(this));
+}
+
+WebViewHost::~WebViewHost()
+{
+}
+
+WebView* WebViewHost::webView() const
+{
+ ASSERT(m_webWidget);
+ // DRT does not support popup widgets. So m_webWidget is always a WebView.
+ return static_cast<WebView*>(m_webWidget);
+}
+
+WebWidget* WebViewHost::webWidget() const
+{
+ ASSERT(m_webWidget);
+ return m_webWidget;
+}
+
+void WebViewHost::reset()
+{
+ // Do a little placement new dance...
+ TestShell* shell = m_shell;
+ WebWidget* widget = m_webWidget;
+ this->~WebViewHost();
+ new (this) WebViewHost(shell);
+ setWebWidget(widget);
+}
+
+void WebViewHost::setSelectTrailingWhitespaceEnabled(bool enabled)
+{
+ m_selectTrailingWhitespaceEnabled = enabled;
+ // In upstream WebKit, smart insert/delete is mutually exclusive with select
+ // trailing whitespace, however, we allow both because Chromium on Windows
+ // allows both.
+}
+
+void WebViewHost::setSmartInsertDeleteEnabled(bool enabled)
+{
+ m_smartInsertDeleteEnabled = enabled;
+ // In upstream WebKit, smart insert/delete is mutually exclusive with select
+ // trailing whitespace, however, we allow both because Chromium on Windows
+ // allows both.
+}
+
+void WebViewHost::setCustomPolicyDelegate(bool isCustom, bool isPermissive)
+{
+ m_policyDelegateEnabled = isCustom;
+ m_policyDelegateIsPermissive = isPermissive;
+}
+
+void WebViewHost::waitForPolicyDelegate()
+{
+ m_policyDelegateEnabled = true;
+ m_policyDelegateShouldNotifyDone = true;
+}
+
+void WebViewHost::setEditCommand(const string& name, const string& value)
+{
+ m_editCommandName = name;
+ m_editCommandValue = value;
+}
+
+void WebViewHost::clearEditCommand()
+{
+ m_editCommandName.clear();
+ m_editCommandValue.clear();
+}
+
+void WebViewHost::loadURLForFrame(const WebURL& url, const WebString& frameName)
+{
+ if (!url.isValid())
+ return;
+ TestShell::resizeWindowForTest(this, url);
+ navigationController()->loadEntry(new TestNavigationEntry(-1, url, WebString(), frameName));
+}
+
+bool WebViewHost::navigate(const TestNavigationEntry& entry, bool reload)
+{
+ // Get the right target frame for the entry.
+ WebFrame* frame = webView()->mainFrame();
+ if (!entry.targetFrame().isEmpty())
+ frame = webView()->findFrameByName(entry.targetFrame());
+
+ // TODO(mpcomplete): should we clear the target frame, or should
+ // back/forward navigations maintain the target frame?
+
+ // A navigation resulting from loading a javascript URL should not be
+ // treated as a browser initiated event. Instead, we want it to look as if
+ // the page initiated any load resulting from JS execution.
+ if (!GURL(entry.URL()).SchemeIs("javascript"))
+ setPendingExtraData(new TestShellExtraData(entry.pageID()));
+
+ // If we are reloading, then WebKit will use the state of the current page.
+ // Otherwise, we give it the state to navigate to.
+ if (reload) {
+ frame->reload(false);
+ } else if (!entry.contentState().isNull()) {
+ ASSERT(entry.pageID() != -1);
+ frame->loadHistoryItem(entry.contentState());
+ } else {
+ ASSERT(entry.pageID() == -1);
+ frame->loadRequest(WebURLRequest(entry.URL()));
+ }
+
+ // In case LoadRequest failed before DidCreateDataSource was called.
+ setPendingExtraData(0);
+
+ // Restore focus to the main frame prior to loading new request.
+ // This makes sure that we don't have a focused iframe. Otherwise, that
+ // iframe would keep focus when the SetFocus called immediately after
+ // LoadRequest, thus making some tests fail (see http://b/issue?id=845337
+ // for more details).
+ webView()->setFocusedFrame(frame);
+ m_shell->setFocus(webView(), true);
+
+ return true;
+}
+
+// Private functions ----------------------------------------------------------
+
+LayoutTestController* WebViewHost::layoutTestController() const
+{
+ return m_shell->layoutTestController();
+}
+
+void WebViewHost::updateAddressBar(WebView* webView)
+{
+ WebFrame* mainFrame = webView->mainFrame();
+ WebDataSource* dataSource = mainFrame->dataSource();
+ if (!dataSource)
+ dataSource = mainFrame->provisionalDataSource();
+ if (!dataSource)
+ return;
+
+ setAddressBarURL(dataSource->request().firstPartyForCookies());
+}
+
+void WebViewHost::locationChangeDone(WebFrame* frame)
+{
+ if (frame != m_topLoadingFrame)
+ return;
+ m_topLoadingFrame = 0;
+ layoutTestController()->locationChangeDone();
+}
+
+void WebViewHost::updateForCommittedLoad(WebFrame* frame, bool isNewNavigation)
+{
+ // Code duplicated from RenderView::DidCommitLoadForFrame.
+ TestShellExtraData* extraData = static_cast<TestShellExtraData*>(frame->dataSource()->extraData());
+
+ if (isNewNavigation) {
+ // New navigation.
+ updateSessionHistory(frame);
+ m_pageId = nextPageID++;
+ } else if (extraData && extraData->pendingPageID != -1 && !extraData->requestCommitted) {
+ // This is a successful session history navigation!
+ updateSessionHistory(frame);
+ m_pageId = extraData->pendingPageID;
+ }
+
+ // Don't update session history multiple times.
+ if (extraData)
+ extraData->requestCommitted = true;
+
+ updateURL(frame);
+}
+
+void WebViewHost::updateURL(WebFrame* frame)
+{
+ WebDataSource* ds = frame->dataSource();
+ ASSERT(ds);
+ const WebURLRequest& request = ds->request();
+ OwnPtr<TestNavigationEntry> entry(new TestNavigationEntry);
+
+ // The referrer will be empty on https->http transitions. It
+ // would be nice if we could get the real referrer from somewhere.
+ entry->setPageID(m_pageId);
+ if (ds->hasUnreachableURL())
+ entry->setURL(ds->unreachableURL());
+ else
+ entry->setURL(request.url());
+
+ const WebHistoryItem& historyItem = frame->currentHistoryItem();
+ if (!historyItem.isNull())
+ entry->setContentState(historyItem);
+
+ navigationController()->didNavigateToEntry(entry.release());
+ m_lastPageIdUpdated = max(m_lastPageIdUpdated, m_pageId);
+}
+
+void WebViewHost::updateSessionHistory(WebFrame* frame)
+{
+ // If we have a valid page ID at this point, then it corresponds to the page
+ // we are navigating away from. Otherwise, this is the first navigation, so
+ // there is no past session history to record.
+ if (m_pageId == -1)
+ return;
+
+ TestNavigationEntry* entry = static_cast<TestNavigationEntry*>(navigationController()->entryWithPageID(m_pageId));
+ if (!entry)
+ return;
+
+ const WebHistoryItem& historyItem = webView()->mainFrame()->previousHistoryItem();
+ if (historyItem.isNull())
+ return;
+
+ entry->setContentState(historyItem);
+}
+
+void WebViewHost::printFrameDescription(WebFrame* webframe)
+{
+ string name8 = webframe->name().utf8();
+ if (webframe == webView()->mainFrame()) {
+ if (!name8.length()) {
+ fputs("main frame", stdout);
+ return;
+ }
+ printf("main frame \"%s\"", name8.c_str());
+ return;
+ }
+ if (!name8.length()) {
+ fputs("frame (anonymous)", stdout);
+ return;
+ }
+ printf("frame \"%s\"", name8.c_str());
+}
+
+void WebViewHost::printResourceDescription(unsigned identifier)
+{
+ ResourceMap::iterator it = m_resourceIdentifierMap.find(identifier);
+ printf("%s", it != m_resourceIdentifierMap.end() ? it->second.c_str() : "<unknown>");
+}
+
+void WebViewHost::setPendingExtraData(TestShellExtraData* extraData)
+{
+ m_pendingExtraData.set(extraData);
+}
+
+void WebViewHost::setPageTitle(const WebString&)
+{
+ // Nothing to do in layout test.
+}
+
+void WebViewHost::setAddressBarURL(const WebURL&)
+{
+ // Nothing to do in layout test.
+}
+
+// Painting functions ---------------------------------------------------------
+
+void WebViewHost::updatePaintRect(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 WebViewHost::paintRect(const WebRect& rect)
+{
+ ASSERT(!m_isPainting);
+ ASSERT(canvas());
+ m_isPainting = true;
+#if PLATFORM(CG)
+ webWidget()->paint(m_canvas->getTopPlatformDevice().GetBitmapContext(), rect);
+#else
+ webWidget()->paint(m_canvas.get(), rect);
+#endif
+ m_isPainting = false;
+}
+
+void WebViewHost::paintInvalidatedRegion()
+{
+ 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 the
+ // first time we call it. 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 < 2; ++i) {
+ // m_paintRect = intersect(m_paintRect , clientRect)
+ int left = max(m_paintRect.x, clientRect.x);
+ int top = max(m_paintRect.y, clientRect.y);
+ int right = min(m_paintRect.x + m_paintRect.width, clientRect.x + clientRect.width);
+ int bottom = min(m_paintRect.y + m_paintRect.height, clientRect.y + clientRect.height);
+ if (left >= right || top >= bottom)
+ m_paintRect = WebRect();
+ else
+ m_paintRect = WebRect(left, top, right - left, bottom - top);
+
+ if (m_paintRect.isEmpty())
+ continue;
+ WebRect rect(m_paintRect);
+ m_paintRect = WebRect();
+ paintRect(rect);
+ if (i == 1)
+ LOG_ERROR("painting caused additional invalidations");
+ }
+ ASSERT(m_paintRect.isEmpty());
+}
+
+PlatformCanvas* WebViewHost::canvas()
+{
+ if (m_canvas)
+ return m_canvas.get();
+ WebSize widgetSize = webWidget()->size();
+ resetScrollRect();
+ m_paintRect = WebRect(0, 0, widgetSize.width, widgetSize.height);
+ m_canvas.set(new PlatformCanvas(widgetSize.width, widgetSize.height, true));
+ return m_canvas.get();
+}
+
+void WebViewHost::resetScrollRect()
+{
+}
+
+void WebViewHost::discardBackingStore()
+{
+ m_canvas.clear();
+}
+
+// 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 WebViewHost::displayRepaintMask()
+{
+ canvas()->drawARGB(167, 0, 0, 0);
+}
diff --git a/WebKitTools/DumpRenderTree/chromium/WebViewHost.h b/WebKitTools/DumpRenderTree/chromium/WebViewHost.h
new file mode 100644
index 0000000..fd1e0f5
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/WebViewHost.h
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2010 Google 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 WebViewHost_h
+#define WebViewHost_h
+
+#include "MockSpellCheck.h"
+#include "TestNavigationController.h"
+#include "public/WebCursorInfo.h"
+#include "public/WebFrameClient.h"
+#include "public/WebViewClient.h"
+#include <wtf/HashMap.h>
+#include <wtf/Vector.h>
+
+class LayoutTestController;
+class TestShell;
+namespace WebKit {
+class WebFrame;
+class WebURL;
+struct WebURLError;
+struct WebRect;
+}
+namespace skia {
+class PlatformCanvas;
+}
+
+class WebViewHost : public WebKit::WebViewClient, public WebKit::WebFrameClient, public NavigationHost {
+ public:
+ WebViewHost(TestShell* shell);
+ ~WebViewHost();
+ void setWebWidget(WebKit::WebWidget* widget) { m_webWidget = widget; }
+ WebKit::WebView* webView() const;
+ WebKit::WebWidget* webWidget() const;
+ void reset();
+ void setSelectTrailingWhitespaceEnabled(bool);
+ void setSmartInsertDeleteEnabled(bool);
+ void waitForPolicyDelegate();
+ void setCustomPolicyDelegate(bool, bool);
+ WebKit::WebFrame* topLoadingFrame() { return m_topLoadingFrame; }
+ void setBlockRedirects(bool block) { m_blocksRedirects = block; }
+ void setRequestReturnNull(bool returnNull) { m_requestReturnNull = returnNull; }
+ void setEditCommand(const std::string& name, const std::string& value);
+ void clearEditCommand();
+ void setPendingExtraData(TestShellExtraData*);
+
+ void paintRect(const WebKit::WebRect&);
+ void updatePaintRect(const WebKit::WebRect&);
+ void paintInvalidatedRegion();
+ skia::PlatformCanvas* canvas();
+ void displayRepaintMask();
+
+ void loadURLForFrame(const WebKit::WebURL&, const WebKit::WebString& frameName);
+ TestNavigationController* navigationController() { return m_navigationController.get(); }
+
+ // NavigationHost
+ virtual bool navigate(const TestNavigationEntry&, bool reload);
+
+ // WebKit::WebViewClient
+ virtual WebKit::WebView* createView(WebKit::WebFrame*);
+ virtual WebKit::WebWidget* createPopupMenu(bool activatable);
+ virtual WebKit::WebWidget* createPopupMenu(const WebKit::WebPopupMenuInfo&);
+ virtual WebKit::WebStorageNamespace* createSessionStorageNamespace();
+ virtual void didAddMessageToConsole(const WebKit::WebConsoleMessage&, const WebKit::WebString& sourceName, unsigned sourceLine);
+ virtual void didStartLoading();
+ virtual void didStopLoading();
+ virtual bool shouldBeginEditing(const WebKit::WebRange&);
+ virtual bool shouldEndEditing(const WebKit::WebRange&);
+ virtual bool shouldInsertNode(const WebKit::WebNode&, const WebKit::WebRange&, WebKit::WebEditingAction);
+ virtual bool shouldInsertText(const WebKit::WebString&, const WebKit::WebRange&, WebKit::WebEditingAction);
+ virtual bool shouldChangeSelectedRange(const WebKit::WebRange& from, const WebKit::WebRange& to, WebKit::WebTextAffinity, bool stillSelecting);
+ virtual bool shouldDeleteRange(const WebKit::WebRange&);
+ virtual bool shouldApplyStyle(const WebKit::WebString& style, const WebKit::WebRange&);
+ virtual bool isSmartInsertDeleteEnabled();
+ virtual bool isSelectTrailingWhitespaceEnabled();
+ virtual void didBeginEditing();
+ virtual void didChangeSelection(bool isSelectionEmpty);
+ virtual void didChangeContents();
+ virtual void didEndEditing();
+ virtual bool handleCurrentKeyboardEvent();
+ virtual void spellCheck(const WebKit::WebString&, int& offset, int& length);
+ virtual WebKit::WebString autoCorrectWord(const WebKit::WebString&);
+ virtual void runModalAlertDialog(WebKit::WebFrame*, const WebKit::WebString&);
+ virtual bool runModalConfirmDialog(WebKit::WebFrame*, const WebKit::WebString&);
+ virtual bool runModalPromptDialog(WebKit::WebFrame*, const WebKit::WebString& message, const WebKit::WebString& defaultValue, WebKit::WebString* actualValue);
+ virtual bool runModalBeforeUnloadDialog(WebKit::WebFrame*, const WebKit::WebString&);
+ virtual void showContextMenu(WebKit::WebFrame*, const WebKit::WebContextMenuData&);
+ virtual void setStatusText(const WebKit::WebString&);
+ virtual void startDragging(const WebKit::WebPoint&, const WebKit::WebDragData&, WebKit::WebDragOperationsMask);
+ virtual void navigateBackForwardSoon(int offset);
+ virtual int historyBackListCount();
+ virtual int historyForwardListCount();
+ virtual void focusAccessibilityObject(const WebKit::WebAccessibilityObject&);
+
+ // WebKit::WebWidgetClient
+ virtual void didInvalidateRect(const WebKit::WebRect&);
+ virtual void didScrollRect(int dx, int dy, const WebKit::WebRect&);
+ virtual void didFocus();
+ virtual void didBlur();
+ virtual void didChangeCursor(const WebKit::WebCursorInfo&);
+ virtual void closeWidgetSoon();
+ virtual void show(WebKit::WebNavigationPolicy);
+ virtual void runModal();
+ virtual WebKit::WebRect windowRect();
+ virtual void setWindowRect(const WebKit::WebRect&);
+ virtual WebKit::WebRect rootWindowRect();
+ virtual WebKit::WebRect windowResizerRect();
+ virtual WebKit::WebScreenInfo screenInfo();
+
+ // WebKit::WebFrameClient
+ virtual WebKit::WebPlugin* createPlugin(WebKit::WebFrame*, const WebKit::WebPluginParams&);
+ virtual WebKit::WebWorker* createWorker(WebKit::WebFrame*, WebKit::WebWorkerClient*);
+ virtual WebKit::WebMediaPlayer* createMediaPlayer(WebKit::WebFrame*, WebKit::WebMediaPlayerClient*);
+ virtual bool allowPlugins(WebKit::WebFrame*, bool enabledPerSettings);
+ virtual bool allowImages(WebKit::WebFrame*, bool enabledPerSettings);
+ virtual void loadURLExternally(WebKit::WebFrame*, const WebKit::WebURLRequest&, WebKit::WebNavigationPolicy);
+ virtual WebKit::WebNavigationPolicy decidePolicyForNavigation(
+ WebKit::WebFrame*, const WebKit::WebURLRequest&,
+ WebKit::WebNavigationType, const WebKit::WebNode&,
+ WebKit::WebNavigationPolicy, bool isRedirect);
+ virtual bool canHandleRequest(WebKit::WebFrame*, const WebKit::WebURLRequest&);
+ virtual WebKit::WebURLError cannotHandleRequestError(WebKit::WebFrame*, const WebKit::WebURLRequest&);
+ virtual WebKit::WebURLError cancelledError(WebKit::WebFrame*, const WebKit::WebURLRequest&);
+ virtual void unableToImplementPolicyWithError(WebKit::WebFrame*, const WebKit::WebURLError&);
+ virtual void willPerformClientRedirect(
+ WebKit::WebFrame*, const WebKit::WebURL& from, const WebKit::WebURL& to,
+ double interval, double fireTime);
+ virtual void didCancelClientRedirect(WebKit::WebFrame*);
+ virtual void didCreateDataSource(WebKit::WebFrame*, WebKit::WebDataSource*);
+ virtual void didStartProvisionalLoad(WebKit::WebFrame*);
+ virtual void didReceiveServerRedirectForProvisionalLoad(WebKit::WebFrame*);
+ virtual void didFailProvisionalLoad(WebKit::WebFrame*, const WebKit::WebURLError&);
+ virtual void didCommitProvisionalLoad(WebKit::WebFrame*, bool isNewNavigation);
+ virtual void didClearWindowObject(WebKit::WebFrame*);
+ virtual void didReceiveTitle(WebKit::WebFrame*, const WebKit::WebString&);
+ virtual void didFinishDocumentLoad(WebKit::WebFrame*);
+ virtual void didHandleOnloadEvents(WebKit::WebFrame*);
+ virtual void didFailLoad(WebKit::WebFrame*, const WebKit::WebURLError&);
+ virtual void didFinishLoad(WebKit::WebFrame*);
+ virtual void didChangeLocationWithinPage(WebKit::WebFrame*, bool isNewNavigation);
+ virtual void assignIdentifierToRequest(WebKit::WebFrame*, unsigned identifier, const WebKit::WebURLRequest&);
+ virtual void willSendRequest(WebKit::WebFrame*, unsigned identifier, WebKit::WebURLRequest&, const WebKit::WebURLResponse&);
+ virtual void didReceiveResponse(WebKit::WebFrame*, unsigned identifier, const WebKit::WebURLResponse&);
+ virtual void didFinishResourceLoad(WebKit::WebFrame*, unsigned identifier);
+ virtual void didFailResourceLoad(WebKit::WebFrame*, unsigned identifier, const WebKit::WebURLError&);
+ virtual void didDisplayInsecureContent(WebKit::WebFrame*);
+ virtual void didRunInsecureContent(WebKit::WebFrame*, const WebKit::WebSecurityOrigin&);
+ virtual bool allowScript(WebKit::WebFrame*, bool enabledPerSettings);
+
+private:
+ LayoutTestController* layoutTestController() const;
+
+ // Called the title of the page changes.
+ // Can be used to update the title of the window.
+ void setPageTitle(const WebKit::WebString&);
+
+ // Called when the URL of the page changes.
+ // Extracts the URL and forwards on to SetAddressBarURL().
+ void updateAddressBar(WebKit::WebView*);
+
+ // Called when the URL of the page changes.
+ // Should be used to update the text of the URL bar.
+ void setAddressBarURL(const WebKit::WebURL&);
+
+ // 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(WebKit::WebFrame*);
+
+ void updateForCommittedLoad(WebKit::WebFrame*, bool isNewNavigation);
+ void updateURL(WebKit::WebFrame*);
+ void updateSessionHistory(WebKit::WebFrame*);
+
+ // Dumping a frame to the console.
+ void printFrameDescription(WebKit::WebFrame*);
+
+ bool hasWindow() const { return m_hasWindow; }
+ void resetScrollRect();
+ void discardBackingStore();
+
+ // 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;
+
+ // Non-owning pointer. The WebViewHost instance is owned by this TestShell instance.
+ TestShell* m_shell;
+
+ // This delegate works for the following widget.
+ WebKit::WebWidget* m_webWidget;
+
+ // This is non-0 IFF a load is in progress.
+ WebKit::WebFrame* m_topLoadingFrame;
+
+ // For tracking session history. See RenderView.
+ int m_pageId;
+ int m_lastPageIdUpdated;
+
+ OwnPtr<TestShellExtraData> m_pendingExtraData;
+
+ // Maps resource identifiers to a descriptive string.
+ typedef HashMap<unsigned, std::string> ResourceMap;
+ ResourceMap m_resourceIdentifierMap;
+ void printResourceDescription(unsigned identifier);
+
+ WebKit::WebCursorInfo m_currentCursor;
+
+ bool m_hasWindow;
+ WebKit::WebRect m_windowRect;
+
+ // true if we want to enable smart insert/delete.
+ bool m_smartInsertDeleteEnabled;
+
+ // true if we want to enable selection of trailing whitespaces
+ bool m_selectTrailingWhitespaceEnabled;
+
+ // true if we should block any redirects
+ bool m_blocksRedirects;
+
+ // true if we should block (set an empty request for) any requests
+ bool m_requestReturnNull;
+
+ // Edit command associated to the current keyboard event.
+ std::string m_editCommandName;
+ std::string m_editCommandValue;
+
+ // The mock spellchecker used in spellCheck().
+ MockSpellCheck m_spellcheck;
+
+ // Painting.
+ OwnPtr<skia::PlatformCanvas> m_canvas;
+ WebKit::WebRect m_paintRect;
+ bool m_isPainting;
+
+ OwnPtr<TestNavigationController*> m_navigationController;
+};
+
+#endif // WebViewHost_h
diff --git a/WebKitTools/DumpRenderTree/chromium/config.h b/WebKitTools/DumpRenderTree/chromium/config.h
new file mode 100644
index 0000000..6029532
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/config.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2010 Google 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 config_h
+#define config_h
+
+// To avoid confict of LOG in wtf/Assertions.h and LOG in base/logging.h,
+// skip base/loggin.h by defining BASE_LOGGING_H_ and define some macros
+// provided by base/logging.h.
+// FIXME: Remove this hack!
+#include <iostream>
+#define BASE_LOGGING_H_
+#define CHECK(condition) while (false && (condition)) std::cerr
+#define DCHECK(condition) while (false && (condition)) std::cerr
+#define DCHECK_EQ(a, b) while (false && (a) == (b)) std::cerr
+#define DCHECK_NE(a, b) while (false && (a) != (b)) std::cerr
+
+#include <wtf/Platform.h>
+
+// JS_EXPORTDATA is needed to inlucde wtf/WTFString.h.
+#if OS(WINDOWS) && !COMPILER(GCC)
+#define JS_EXPORTDATA __declspec(dllimport)
+#else
+#define JS_EXPORTDATA
+#endif
+
+#endif // config_h
diff --git a/WebKitTools/DumpRenderTree/fonts/ColorBits-A.png b/WebKitTools/DumpRenderTree/fonts/ColorBits-A.png
new file mode 100644
index 0000000..8b9319c
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/fonts/ColorBits-A.png
Binary files differ
diff --git a/WebKitTools/DumpRenderTree/fonts/ColorBits.ttf b/WebKitTools/DumpRenderTree/fonts/ColorBits.ttf
new file mode 100644
index 0000000..cd919e8
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/fonts/ColorBits.ttf
Binary files differ
diff --git a/WebKitTools/DumpRenderTree/gtk/AccessibilityControllerGtk.cpp b/WebKitTools/DumpRenderTree/gtk/AccessibilityControllerGtk.cpp
index 12653fc..ab9f021 100644
--- a/WebKitTools/DumpRenderTree/gtk/AccessibilityControllerGtk.cpp
+++ b/WebKitTools/DumpRenderTree/gtk/AccessibilityControllerGtk.cpp
@@ -46,6 +46,12 @@ AccessibilityController::~AccessibilityController()
{
}
+AccessibilityUIElement AccessibilityController::elementAtPoint(int x, int y)
+{
+ // FIXME: implement
+ return 0;
+}
+
AccessibilityUIElement AccessibilityController::focusedElement()
{
AtkObject* accessible = webkit_web_frame_get_focused_accessible_element(mainFrame);
diff --git a/WebKitTools/DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp b/WebKitTools/DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp
index abfe115..fabada3 100644
--- a/WebKitTools/DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp
+++ b/WebKitTools/DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp
@@ -75,6 +75,26 @@ void AccessibilityUIElement::getChildrenWithRange(Vector<AccessibilityUIElement>
}
}
+int AccessibilityUIElement::rowCount()
+{
+ if (!m_element)
+ return 0;
+
+ ASSERT(ATK_IS_TABLE(m_element));
+
+ return atk_table_get_n_rows(ATK_TABLE(m_element));
+}
+
+int AccessibilityUIElement::columnCount()
+{
+ if (!m_element)
+ return 0;
+
+ ASSERT(ATK_IS_TABLE(m_element));
+
+ return atk_table_get_n_columns(ATK_TABLE(m_element));
+}
+
int AccessibilityUIElement::childrenCount()
{
if (!m_element)
@@ -204,6 +224,11 @@ JSStringRef AccessibilityUIElement::language()
return JSStringCreateWithCharacters(0, 0);
}
+JSStringRef AccessibilityUIElement::helpText() const
+{
+ return 0;
+}
+
double AccessibilityUIElement::x()
{
int x, y;
@@ -492,6 +517,11 @@ void AccessibilityUIElement::decrement()
// FIXME: implement
}
+void AccessibilityUIElement::press()
+{
+ // FIXME: implement
+}
+
void AccessibilityUIElement::showMenu()
{
// FIXME: implement
@@ -558,6 +588,11 @@ bool AccessibilityUIElement::addNotificationListener(JSObjectRef functionCallbac
return false;
}
+void AccessibilityUIElement::removeNotificationListener()
+{
+ // FIXME: implement
+}
+
bool AccessibilityUIElement::isSelectable() const
{
// FIXME: implement
diff --git a/WebKitTools/DumpRenderTree/gtk/DumpRenderTree.cpp b/WebKitTools/DumpRenderTree/gtk/DumpRenderTree.cpp
index a2fc79b..e37613d 100644
--- a/WebKitTools/DumpRenderTree/gtk/DumpRenderTree.cpp
+++ b/WebKitTools/DumpRenderTree/gtk/DumpRenderTree.cpp
@@ -117,6 +117,11 @@ static bool shouldOpenWebInspector(const char* pathOrURL)
return strstr(pathOrURL, "inspector/");
}
+static bool shouldEnableDeveloperExtras(const char* pathOrURL)
+{
+ return shouldOpenWebInspector(pathOrURL) || strstr(pathOrURL, "inspector-enabled/");
+}
+
void dumpFrameScrollPosition(WebKitWebFrame* frame)
{
@@ -319,6 +324,7 @@ static void resetDefaultsToConsistentValues()
"enable-html5-database", TRUE,
"enable-html5-local-storage", TRUE,
"enable-xss-auditor", FALSE,
+ "enable-spatial-navigation", FALSE,
"javascript-can-open-windows-automatically", TRUE,
"enable-offline-web-application-cache", TRUE,
"enable-universal-access-from-file-uris", TRUE,
@@ -335,6 +341,7 @@ static void resetDefaultsToConsistentValues()
"enable-page-cache", FALSE,
"auto-resize-window", TRUE,
"enable-java-applet", FALSE,
+ "enable-plugins", TRUE,
NULL);
webkit_web_frame_clear_main_frame_name(mainFrame);
@@ -346,6 +353,16 @@ static void resetDefaultsToConsistentValues()
webkit_reset_origin_access_white_lists();
+#ifdef HAVE_LIBSOUP_2_29_90
+ SoupSession* session = webkit_get_default_session();
+ SoupCookieJar* jar = reinterpret_cast<SoupCookieJar*>(soup_session_get_feature(session, SOUP_TYPE_COOKIE_JAR));
+
+ // We only create the jar when the soup backend needs to do
+ // HTTP. Should we initialize it earlier, perhaps?
+ if (jar)
+ g_object_set(G_OBJECT(jar), SOUP_COOKIE_JAR_ACCEPT_POLICY, SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY, NULL);
+#endif
+
setlocale(LC_ALL, "");
}
@@ -468,8 +485,11 @@ static void runTest(const string& testPathOrURL)
if (shouldLogFrameLoadDelegates(pathOrURL.c_str()))
gLayoutTestController->setDumpFrameLoadCallbacks(true);
- if (shouldOpenWebInspector(pathOrURL.c_str()))
- gLayoutTestController->showWebInspector();
+ if (shouldEnableDeveloperExtras(pathOrURL.c_str())) {
+ gLayoutTestController->setDeveloperExtrasEnabled(true);
+ if (shouldOpenWebInspector(pathOrURL.c_str()))
+ gLayoutTestController->showWebInspector();
+ }
WorkQueue::shared()->clear();
WorkQueue::shared()->setFrozen(false);
@@ -502,7 +522,8 @@ static void runTest(const string& testPathOrURL)
gtk_main();
- if (shouldOpenWebInspector(pathOrURL.c_str()))
+ // If developer extras enabled Web Inspector may have been open by the test.
+ if (shouldEnableDeveloperExtras(pathOrURL.c_str()))
gLayoutTestController->closeWebInspector();
// Also check if we still have opened webViews and free them.
@@ -550,7 +571,7 @@ static char* getFrameNameSuitableForTestResult(WebKitWebView* view, WebKitWebFra
// This is a bit strange. Shouldn't web_frame_get_name return NULL?
if (frameName && (frameName[0] != '\0')) {
char* tmp = g_strdup_printf("main frame \"%s\"", frameName);
- g_free (frameName);
+ g_free(frameName);
frameName = tmp;
} else {
g_free(frameName);
@@ -559,20 +580,31 @@ static char* getFrameNameSuitableForTestResult(WebKitWebView* view, WebKitWebFra
} else if (!frameName || (frameName[0] == '\0')) {
g_free(frameName);
frameName = g_strdup("frame (anonymous)");
+ } else {
+ char* tmp = g_strdup_printf("frame \"%s\"", frameName);
+ g_free(frameName);
+ frameName = tmp;
}
return frameName;
}
+static void webViewLoadCommitted(WebKitWebView* view, WebKitWebFrame* frame, void*)
+{
+ if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) {
+ char* frameName = getFrameNameSuitableForTestResult(view, frame);
+ printf("%s - didCommitLoadForFrame\n", frameName);
+ g_free(frameName);
+ }
+}
+
+
static void webViewLoadFinished(WebKitWebView* view, WebKitWebFrame* frame, void*)
{
- if (!done && !gLayoutTestController->dumpFrameLoadCallbacks()) {
- guint pendingFrameUnloadEvents = webkit_web_frame_get_pending_unload_event_count(frame);
- if (pendingFrameUnloadEvents) {
- char* frameName = getFrameNameSuitableForTestResult(view, frame);
- printf("%s - has %u onunload handler(s)\n", frameName, pendingFrameUnloadEvents);
- g_free(frameName);
- }
+ if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) {
+ char* frameName = getFrameNameSuitableForTestResult(view, frame);
+ printf("%s - didFinishLoadForFrame\n", frameName);
+ g_free(frameName);
}
if (frame != topLoadingFrame)
@@ -589,6 +621,31 @@ static void webViewLoadFinished(WebKitWebView* view, WebKitWebFrame* frame, void
dump();
}
+static void webViewDocumentLoadFinished(WebKitWebView* view, WebKitWebFrame* frame, void*)
+{
+ if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) {
+ char* frameName = getFrameNameSuitableForTestResult(view, frame);
+ printf("%s - didFinishDocumentLoadForFrame\n", frameName);
+ g_free(frameName);
+ } else if (!done) {
+ guint pendingFrameUnloadEvents = webkit_web_frame_get_pending_unload_event_count(frame);
+ if (pendingFrameUnloadEvents) {
+ char* frameName = getFrameNameSuitableForTestResult(view, frame);
+ printf("%s - has %u onunload handler(s)\n", frameName, pendingFrameUnloadEvents);
+ g_free(frameName);
+ }
+ }
+}
+
+static void webViewOnloadEvent(WebKitWebView* view, WebKitWebFrame* frame, void*)
+{
+ if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) {
+ char* frameName = getFrameNameSuitableForTestResult(view, frame);
+ printf("%s - didHandleOnloadEventsForFrame\n", frameName);
+ g_free(frameName);
+ }
+}
+
static void webViewWindowObjectCleared(WebKitWebView* view, WebKitWebFrame* frame, JSGlobalContextRef context, JSObjectRef windowObject, gpointer data)
{
JSValueRef exception = 0;
@@ -611,7 +668,26 @@ static void webViewWindowObjectCleared(WebKitWebView* view, WebKitWebFrame* fram
static gboolean webViewConsoleMessage(WebKitWebView* view, const gchar* message, unsigned int line, const gchar* sourceId, gpointer data)
{
- fprintf(stdout, "CONSOLE MESSAGE: line %d: %s\n", line, message);
+ gchar* testMessage = 0;
+ const gchar* uriScheme;
+
+ // Tests expect only the filename part of local URIs
+ uriScheme = g_strstr_len(message, -1, "file://");
+ if (uriScheme) {
+ GString* tempString = g_string_sized_new(strlen(message));
+ gchar* filename = g_strrstr(uriScheme, G_DIR_SEPARATOR_S);
+
+ if (filename) {
+ filename += strlen(G_DIR_SEPARATOR_S);
+ tempString = g_string_append_len(tempString, message, (uriScheme - message));
+ tempString = g_string_append_len(tempString, filename, strlen(filename));
+ testMessage = g_string_free(tempString, FALSE);
+ }
+ }
+
+ fprintf(stdout, "CONSOLE MESSAGE: line %d: %s\n", line, testMessage ? testMessage : message);
+ g_free(testMessage);
+
return TRUE;
}
@@ -725,6 +801,19 @@ static void databaseQuotaExceeded(WebKitWebView* view, WebKitWebFrame* frame, We
webkit_security_origin_set_web_database_quota(origin, 5 * 1024 * 1024);
}
+static bool
+geolocationPolicyDecisionRequested(WebKitWebView*, WebKitWebFrame*, WebKitGeolocationPolicyDecision* decision)
+{
+ if (!gLayoutTestController->isGeolocationPermissionSet())
+ return FALSE;
+ if (gLayoutTestController->geolocationPermission())
+ webkit_geolocation_policy_allow(decision);
+ else
+ webkit_geolocation_policy_deny(decision);
+
+ return TRUE;
+}
+
static WebKitWebView* webViewCreate(WebKitWebView*, WebKitWebFrame*);
@@ -764,6 +853,7 @@ static WebKitWebView* createWebView()
g_object_connect(G_OBJECT(view),
"signal::load-started", webViewLoadStarted, 0,
"signal::load-finished", webViewLoadFinished, 0,
+ "signal::load-committed", webViewLoadCommitted, 0,
"signal::window-object-cleared", webViewWindowObjectCleared, 0,
"signal::console-message", webViewConsoleMessage, 0,
"signal::script-alert", webViewScriptAlert, 0,
@@ -775,6 +865,9 @@ static WebKitWebView* createWebView()
"signal::create-web-view", webViewCreate, 0,
"signal::close-web-view", webViewClose, 0,
"signal::database-quota-exceeded", databaseQuotaExceeded, 0,
+ "signal::document-load-finished", webViewDocumentLoadFinished, 0,
+ "signal::geolocation-policy-decision-requested", geolocationPolicyDecisionRequested, 0,
+ "signal::onload-event", webViewOnloadEvent, 0,
NULL);
WebKitWebInspector* inspector = webkit_web_view_get_inspector(view);
@@ -806,11 +899,22 @@ static WebKitWebView* webViewCreate(WebKitWebView* view, WebKitWebFrame* frame)
return newWebView;
}
+static void logHandler(const gchar* domain, GLogLevelFlags level, const gchar* message, gpointer data)
+{
+ if (level < G_LOG_LEVEL_DEBUG)
+ fprintf(stderr, "%s\n", message);
+}
+
int main(int argc, char* argv[])
{
g_thread_init(NULL);
gtk_init(&argc, &argv);
+ // Some plugins might try to use the GLib logger for printing debug
+ // messages. This will cause tests to fail because of unexpected output.
+ // We squelch all debug messages sent to the logger.
+ g_log_set_default_handler(logHandler, 0);
+
#if PLATFORM(X11)
FcInit();
initializeFonts();
diff --git a/WebKitTools/DumpRenderTree/gtk/EventSender.cpp b/WebKitTools/DumpRenderTree/gtk/EventSender.cpp
index 458e0ba..9c27d8c 100644
--- a/WebKitTools/DumpRenderTree/gtk/EventSender.cpp
+++ b/WebKitTools/DumpRenderTree/gtk/EventSender.cpp
@@ -557,8 +557,18 @@ static JSValueRef keyDownCallback(JSContextRef context, JSObjectRef function, JS
event.key.state = state;
event.key.window = GTK_WIDGET(view)->window;
+ // When synthesizing an event, an invalid hardware_keycode value
+ // can cause it to be badly processed by Gtk+.
+ GdkKeymapKey* keys;
+ gint n_keys;
+ if (gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(), gdkKeySym, &keys, &n_keys)) {
+ event.key.hardware_keycode = keys[0].keycode;
+ g_free(keys);
+ }
+
gboolean return_val;
event.key.type = GDK_KEY_PRESS;
+
g_signal_emit_by_name(view, "key-press-event", &event.key, &return_val);
event.key.type = GDK_KEY_RELEASE;
@@ -567,47 +577,49 @@ static JSValueRef keyDownCallback(JSContextRef context, JSObjectRef function, JS
return JSValueMakeUndefined(context);
}
-static JSValueRef textZoomInCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+static void zoomIn(gboolean fullContentsZoom)
{
WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
if (!view)
- return JSValueMakeUndefined(context);
+ return;
+ webkit_web_view_set_full_content_zoom(view, fullContentsZoom);
gfloat currentZoom = webkit_web_view_get_zoom_level(view);
webkit_web_view_set_zoom_level(view, currentZoom * zoomMultiplierRatio);
-
- return JSValueMakeUndefined(context);
}
-static JSValueRef textZoomOutCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+static void zoomOut(gboolean fullContentsZoom)
{
WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
if (!view)
- return JSValueMakeUndefined(context);
+ return;
+ webkit_web_view_set_full_content_zoom(view, fullContentsZoom);
gfloat currentZoom = webkit_web_view_get_zoom_level(view);
webkit_web_view_set_zoom_level(view, currentZoom / zoomMultiplierRatio);
+}
+static JSValueRef textZoomInCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ zoomIn(FALSE);
return JSValueMakeUndefined(context);
}
-static JSValueRef zoomPageInCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+static JSValueRef textZoomOutCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
- WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
- if (!view)
- return JSValueMakeUndefined(context);
+ zoomOut(FALSE);
+ return JSValueMakeUndefined(context);
+}
- webkit_web_view_zoom_in(view);
+static JSValueRef zoomPageInCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ zoomIn(TRUE);
return JSValueMakeUndefined(context);
}
static JSValueRef zoomPageOutCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
- WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
- if (!view)
- return JSValueMakeUndefined(context);
-
- webkit_web_view_zoom_out(view);
+ zoomOut(TRUE);
return JSValueMakeUndefined(context);
}
diff --git a/WebKitTools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp b/WebKitTools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp
index 668b852..58d2631 100644
--- a/WebKitTools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp
+++ b/WebKitTools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp
@@ -56,7 +56,9 @@ unsigned int webkit_worker_thread_count(void);
void webkit_white_list_access_from_origin(const gchar* sourceOrigin, const gchar* destinationProtocol, const gchar* destinationHost, bool allowDestinationSubdomains);
gchar* webkit_web_frame_counter_value_for_element_by_id(WebKitWebFrame* frame, const gchar* id);
int webkit_web_frame_page_number_for_element_by_id(WebKitWebFrame* frame, const gchar* id, float pageWidth, float pageHeight);
+int webkit_web_frame_number_of_pages(WebKitWebFrame* frame, float pageWidth, float pageHeight);
void webkit_web_inspector_execute_script(WebKitWebInspector* inspector, long callId, const gchar* script);
+gchar* webkit_web_frame_marker_text_for_list_item(WebKitWebFrame* frame, JSContextRef context, JSValueRef nodeObject);
}
static gchar* copyWebSettingKey(gchar* preferenceKey)
@@ -65,12 +67,13 @@ static gchar* copyWebSettingKey(gchar* preferenceKey)
if (!keyTable) {
// If you add a pref here, make sure you reset the value in
- // DumpRenderTree::resetWebViewToConsistentStateBeforeTesting.
+ // DumpRenderTree::resetDefaultsToConsistentValues.
keyTable = g_hash_table_new(g_str_hash, g_str_equal);
g_hash_table_insert(keyTable, g_strdup("WebKitJavaScriptEnabled"), g_strdup("enable-scripts"));
g_hash_table_insert(keyTable, g_strdup("WebKitDefaultFontSize"), g_strdup("default-font-size"));
g_hash_table_insert(keyTable, g_strdup("WebKitEnableCaretBrowsing"), g_strdup("enable-caret-browsing"));
g_hash_table_insert(keyTable, g_strdup("WebKitUsesPageCachePreferenceKey"), g_strdup("enable-page-cache"));
+ g_hash_table_insert(keyTable, g_strdup("WebKitPluginsEnabled"), g_strdup("enable-plugins"));
}
return g_strdup(static_cast<gchar*>(g_hash_table_lookup(keyTable, preferenceKey)));
@@ -141,6 +144,19 @@ void LayoutTestController::keepWebHistory()
// FIXME: implement
}
+JSValueRef LayoutTestController::computedStyleIncludingVisitedInfo(JSContextRef context, JSValueRef value)
+{
+ // FIXME: Implement this.
+ return JSValueMakeUndefined(context);
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::layerTreeAsText() const
+{
+ // FIXME: implement
+ JSRetainPtr<JSStringRef> string(Adopt, JSStringCreateWithUTF8CString(""));
+ return string;
+}
+
int LayoutTestController::pageNumberForElementById(JSStringRef id, float pageWidth, float pageHeight)
{
gchar* idGChar = JSStringCopyUTF8CString(id);
@@ -149,10 +165,9 @@ int LayoutTestController::pageNumberForElementById(JSStringRef id, float pageWid
return pageNumber;
}
-int LayoutTestController::numberOfPages(float, float)
+int LayoutTestController::numberOfPages(float pageWidth, float pageHeight)
{
- // FIXME: implement
- return -1;
+ return webkit_web_frame_number_of_pages(mainFrame, pageWidth, pageHeight);
}
size_t LayoutTestController::webHistoryItemCount()
@@ -210,7 +225,19 @@ void LayoutTestController::setAcceptsEditing(bool acceptsEditing)
void LayoutTestController::setAlwaysAcceptCookies(bool alwaysAcceptCookies)
{
- // FIXME: Implement this (and restore the default value before running each test in DumpRenderTree.cpp).
+#ifdef HAVE_LIBSOUP_2_29_90
+ SoupSession* session = webkit_get_default_session();
+ SoupCookieJar* jar = reinterpret_cast<SoupCookieJar*>(soup_session_get_feature(session, SOUP_TYPE_COOKIE_JAR));
+
+ SoupCookieJarAcceptPolicy policy;
+
+ if (alwaysAcceptCookies)
+ policy = SOUP_COOKIE_JAR_ACCEPT_ALWAYS;
+ else
+ policy = SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY;
+
+ g_object_set(G_OBJECT(jar), SOUP_COOKIE_JAR_ACCEPT_POLICY, policy, NULL);
+#endif
}
void LayoutTestController::setCustomPolicyDelegate(bool setDelegate, bool permissive)
@@ -224,7 +251,12 @@ void LayoutTestController::waitForPolicyDelegate()
setWaitToDump(true);
}
-void LayoutTestController::whiteListAccessFromOrigin(JSStringRef sourceOrigin, JSStringRef protocol, JSStringRef host, bool includeSubdomains)
+void LayoutTestController::setScrollbarPolicy(JSStringRef orientation, JSStringRef policy)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::addOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef protocol, JSStringRef host, bool includeSubdomains)
{
gchar* sourceOriginGChar = JSStringCopyUTF8CString(sourceOrigin);
gchar* protocolGChar = JSStringCopyUTF8CString(protocol);
@@ -235,6 +267,11 @@ void LayoutTestController::whiteListAccessFromOrigin(JSStringRef sourceOrigin, J
g_free(hostGChar);
}
+void LayoutTestController::removeOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef protocol, JSStringRef host, bool includeSubdomains)
+{
+ // FIXME: implement
+}
+
void LayoutTestController::setMainFrameIsFirstResponder(bool flag)
{
// FIXME: implement
@@ -303,7 +340,7 @@ static gboolean waitToDumpWatchdogFired(void*)
void LayoutTestController::setWaitToDump(bool waitUntilDone)
{
- static const int timeoutSeconds = 15;
+ static const int timeoutSeconds = 30;
m_waitToDump = waitUntilDone;
if (m_waitToDump && !waitToDumpWatchdog)
@@ -334,11 +371,20 @@ void LayoutTestController::setXSSAuditorEnabled(bool flag)
g_object_set(G_OBJECT(settings), "enable-xss-auditor", flag, NULL);
}
-void LayoutTestController::setFrameSetFlatteningEnabled(bool flag)
+void LayoutTestController::setFrameFlatteningEnabled(bool flag)
{
// FIXME: implement
}
+void LayoutTestController::setSpatialNavigationEnabled(bool flag)
+{
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ ASSERT(view);
+
+ WebKitWebSettings* settings = webkit_web_view_get_settings(view);
+ g_object_set(G_OBJECT(settings), "enable-spatial-navigation", flag, NULL);
+}
+
void LayoutTestController::setAllowUniversalAccessFromFileURLs(bool flag)
{
WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
@@ -390,8 +436,7 @@ void LayoutTestController::setJavaScriptProfilingEnabled(bool flag)
WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
ASSERT(view);
- WebKitWebSettings* settings = webkit_web_view_get_settings(view);
- g_object_set(G_OBJECT(settings), "enable-developer-extras", flag, NULL);
+ setDeveloperExtrasEnabled(flag);
WebKitWebInspector* inspector = webkit_web_view_get_inspector(view);
g_object_set(G_OBJECT(inspector), "javascript-profiling-enabled", flag, NULL);
@@ -556,24 +601,28 @@ void LayoutTestController::addUserStyleSheet(JSStringRef source)
printf("LayoutTestController::addUserStyleSheet not implemented.\n");
}
-void LayoutTestController::showWebInspector()
+void LayoutTestController::setDeveloperExtrasEnabled(bool enabled)
{
WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame);
WebKitWebSettings* webSettings = webkit_web_view_get_settings(webView);
+
+ g_object_set(webSettings, "enable-developer-extras", enabled, NULL);
+}
+
+void LayoutTestController::showWebInspector()
+{
+ WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame);
WebKitWebInspector* inspector = webkit_web_view_get_inspector(webView);
- g_object_set(webSettings, "enable-developer-extras", TRUE, NULL);
webkit_web_inspector_show(inspector);
}
void LayoutTestController::closeWebInspector()
{
WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame);
- WebKitWebSettings* webSettings = webkit_web_view_get_settings(webView);
WebKitWebInspector* inspector = webkit_web_view_get_inspector(webView);
webkit_web_inspector_close(inspector);
- g_object_set(webSettings, "enable-developer-extras", FALSE, NULL);
}
void LayoutTestController::evaluateInWebInspector(long callId, JSStringRef script)
@@ -596,7 +645,37 @@ void LayoutTestController::removeAllVisitedLinks()
// FIXME: Implement this.
}
+bool LayoutTestController::callShouldCloseOnWebView()
+{
+ // FIXME: Implement for testing fix for https://bugs.webkit.org/show_bug.cgi?id=27481
+ return false;
+}
+
void LayoutTestController::apiTestNewWindowDataLoadBaseURL(JSStringRef utf8Data, JSStringRef baseURL)
{
}
+
+void LayoutTestController::apiTestGoToCurrentBackForwardItem()
+{
+
+}
+
+void LayoutTestController::setWebViewEditable(bool)
+{
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::markerTextForListItem(JSContextRef context, JSValueRef nodeObject) const
+{
+ gchar* markerTextGChar = webkit_web_frame_marker_text_for_list_item(mainFrame, context, nodeObject);
+ if (!markerTextGChar)
+ return 0;
+
+ JSRetainPtr<JSStringRef> markerText(Adopt, JSStringCreateWithUTF8CString(markerTextGChar));
+ g_free(markerTextGChar);
+ return markerText;
+}
+
+void LayoutTestController::authenticateSession(JSStringRef, JSStringRef, JSStringRef)
+{
+}
diff --git a/WebKitTools/DumpRenderTree/mac/AccessibilityControllerMac.mm b/WebKitTools/DumpRenderTree/mac/AccessibilityControllerMac.mm
index 4d2da6e..9d7edef 100644
--- a/WebKitTools/DumpRenderTree/mac/AccessibilityControllerMac.mm
+++ b/WebKitTools/DumpRenderTree/mac/AccessibilityControllerMac.mm
@@ -40,6 +40,12 @@ AccessibilityController::~AccessibilityController()
{
}
+AccessibilityUIElement AccessibilityController::elementAtPoint(int x, int y)
+{
+ id accessibilityObject = [[[mainFrame frameView] documentView] accessibilityHitTest:NSMakePoint(x, y)];
+ return AccessibilityUIElement(accessibilityObject);
+}
+
AccessibilityUIElement AccessibilityController::focusedElement()
{
// FIXME: we could do some caching here.
diff --git a/WebKitTools/DumpRenderTree/mac/AccessibilityUIElementMac.mm b/WebKitTools/DumpRenderTree/mac/AccessibilityUIElementMac.mm
index e9361f2..a39dabb 100644
--- a/WebKitTools/DumpRenderTree/mac/AccessibilityUIElementMac.mm
+++ b/WebKitTools/DumpRenderTree/mac/AccessibilityUIElementMac.mm
@@ -57,32 +57,11 @@ typedef void (*AXPostedNotificationCallback)(id element, NSString* notification,
@interface NSObject (WebKitAccessibilityAdditions)
- (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount;
-- (void)accessibilitySetPostedNotificationCallback:(AXPostedNotificationCallback)function withContext:(void*)context;
+- (void)accessibilitySetShouldRepostNotifications:(BOOL)repost;
- (NSUInteger)accessibilityIndexOfChild:(id)child;
+- (NSUInteger)accessibilityArrayAttributeCount:(NSString *)attribute;
@end
-AccessibilityUIElement::AccessibilityUIElement(PlatformUIElement element)
- : m_element(element)
- , m_notificationFunctionCallback(0)
-{
- [m_element retain];
-}
-
-AccessibilityUIElement::AccessibilityUIElement(const AccessibilityUIElement& other)
- : m_element(other.m_element)
- , m_notificationFunctionCallback(0)
-{
- [m_element retain];
-}
-
-AccessibilityUIElement::~AccessibilityUIElement()
-{
- // Make sure that our notification callback does not stick around.
- if (m_notificationFunctionCallback)
- [m_element accessibilitySetPostedNotificationCallback:0 withContext:0];
- [m_element release];
-}
-
@interface NSString (JSStringRefAdditions)
+ (NSString *)stringWithJSStringRef:(JSStringRef)jsStringRef;
- (JSStringRef)createJSStringRef;
@@ -106,6 +85,88 @@ AccessibilityUIElement::~AccessibilityUIElement()
@end
+@interface AccessibilityNotificationHandler : NSObject
+{
+ id m_platformElement;
+ JSObjectRef m_notificationFunctionCallback;
+}
+
+@end
+
+@implementation AccessibilityNotificationHandler
+
+- (id)initWithPlatformElement:(id)platformElement
+{
+ self = [super init];
+
+ m_platformElement = platformElement;
+
+ // Once an object starts requesting notifications, it's on for the duration of the program.
+ // This is to avoid any race conditions between tests turning this flag on and off. Instead
+ // AccessibilityNotificationHandler can just listen when they want to.
+ [m_platformElement accessibilitySetShouldRepostNotifications:YES];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_notificationReceived:) name:@"AXDRTNotification" object:nil];
+
+ return self;
+}
+
+- (void)dealloc
+{
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ JSValueUnprotect([mainFrame globalContext], m_notificationFunctionCallback);
+ m_notificationFunctionCallback = 0;
+
+ [super dealloc];
+}
+
+- (void)_notificationReceived:(NSNotification *)notification
+{
+ NSString *notificationName = [[notification userInfo] objectForKey:@"notificationName"];
+ if (!notificationName)
+ return;
+
+ JSRetainPtr<JSStringRef> jsNotification(Adopt, [notificationName createJSStringRef]);
+ JSValueRef argument = JSValueMakeString([mainFrame globalContext], jsNotification.get());
+ JSObjectCallAsFunction([mainFrame globalContext], m_notificationFunctionCallback, 0, 1, &argument, 0);
+}
+
+- (void)setCallback:(JSObjectRef)callback
+{
+ if (!callback)
+ return;
+
+ // Release the old callback.
+ if (m_notificationFunctionCallback)
+ JSValueUnprotect([mainFrame globalContext], m_notificationFunctionCallback);
+
+ m_notificationFunctionCallback = callback;
+ JSValueProtect([mainFrame globalContext], m_notificationFunctionCallback);
+}
+
+@end
+
+AccessibilityUIElement::AccessibilityUIElement(PlatformUIElement element)
+ : m_element(element)
+ , m_notificationHandler(0)
+{
+ // FIXME: ap@webkit.org says ObjC objects need to be CFRetained/CFRelease to be GC-compliant on the mac.
+ [m_element retain];
+}
+
+AccessibilityUIElement::AccessibilityUIElement(const AccessibilityUIElement& other)
+ : m_element(other.m_element)
+ , m_notificationHandler(0)
+{
+ [m_element retain];
+}
+
+AccessibilityUIElement::~AccessibilityUIElement()
+{
+ // The notification handler should be nil because removeNotificationListener() should have been called in the test.
+ ASSERT(!m_notificationHandler);
+ [m_element release];
+}
+
static NSString* descriptionOfValue(id valueObject, id focusedAccessibilityObject)
{
if (!valueObject)
@@ -439,6 +500,12 @@ JSStringRef AccessibilityUIElement::language()
return concatenateAttributeAndValue(@"AXLanguage", description);
}
+JSStringRef AccessibilityUIElement::helpText() const
+{
+ id description = descriptionOfValue([m_element accessibilityAttributeValue:NSAccessibilityHelpAttribute], m_element);
+ return concatenateAttributeAndValue(@"AXHelp", description);
+}
+
double AccessibilityUIElement::x()
{
NSValue* positionValue = [m_element accessibilityAttributeValue:NSAccessibilityPositionAttribute];
@@ -676,6 +743,16 @@ JSStringRef AccessibilityUIElement::attributesOfHeader()
return descriptionOfElements(headerVector);
}
+int AccessibilityUIElement::rowCount()
+{
+ return [m_element accessibilityArrayAttributeCount:NSAccessibilityRowsAttribute];
+}
+
+int AccessibilityUIElement::columnCount()
+{
+ return [m_element accessibilityArrayAttributeCount:NSAccessibilityColumnsAttribute];
+}
+
int AccessibilityUIElement::indexInTable()
{
NSNumber* indexNumber = [m_element accessibilityAttributeValue:NSAccessibilityIndexAttribute];
@@ -736,6 +813,11 @@ void AccessibilityUIElement::showMenu()
[m_element accessibilityPerformAction:NSAccessibilityShowMenuAction];
}
+void AccessibilityUIElement::press()
+{
+ [m_element accessibilityPerformAction:NSAccessibilityPressAction];
+}
+
JSStringRef AccessibilityUIElement::accessibilityValue() const
{
// FIXME: implement
@@ -758,28 +840,30 @@ JSStringRef AccessibilityUIElement::url()
return [[url absoluteString] createJSStringRef];
}
-static void _accessibilityNotificationCallback(id element, NSString* notification, void* context)
-{
- if (!context)
- return;
-
- JSObjectRef functionCallback = static_cast<JSObjectRef>(context);
-
- JSRetainPtr<JSStringRef> jsNotification(Adopt, [notification createJSStringRef]);
- JSValueRef argument = JSValueMakeString([mainFrame globalContext], jsNotification.get());
- JSObjectCallAsFunction([mainFrame globalContext], functionCallback, NULL, 1, &argument, NULL);
-}
-
bool AccessibilityUIElement::addNotificationListener(JSObjectRef functionCallback)
{
if (!functionCallback)
return false;
- m_notificationFunctionCallback = functionCallback;
- [platformUIElement() accessibilitySetPostedNotificationCallback:_accessibilityNotificationCallback withContext:reinterpret_cast<void*>(m_notificationFunctionCallback)];
+ // Mac programmers should not be adding more than one notification listener per element.
+ // Other platforms may be different.
+ if (m_notificationHandler)
+ return false;
+ m_notificationHandler = [[AccessibilityNotificationHandler alloc] initWithPlatformElement:platformUIElement()];
+ [m_notificationHandler setCallback:functionCallback];
+
return true;
}
+void AccessibilityUIElement::removeNotificationListener()
+{
+ // Mac programmers should not be trying to remove a listener that's already removed.
+ ASSERT(m_notificationHandler);
+
+ [m_notificationHandler release];
+ m_notificationHandler = nil;
+}
+
bool AccessibilityUIElement::isSelectable() const
{
// FIXME: implement
@@ -812,7 +896,9 @@ bool AccessibilityUIElement::isCollapsed() const
bool AccessibilityUIElement::hasPopup() const
{
- // FIXME: implement
+ id value = [m_element accessibilityAttributeValue:@"AXHasPopup"];
+ if ([value isKindOfClass:[NSNumber class]])
+ return [value boolValue];
return false;
}
diff --git a/WebKitTools/DumpRenderTree/mac/Configurations/Base.xcconfig b/WebKitTools/DumpRenderTree/mac/Configurations/Base.xcconfig
index a72dd7d..5f989e0 100644
--- a/WebKitTools/DumpRenderTree/mac/Configurations/Base.xcconfig
+++ b/WebKitTools/DumpRenderTree/mac/Configurations/Base.xcconfig
@@ -34,3 +34,35 @@ GCC_WARN_UNUSED_VARIABLE = YES
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO
WARNING_CFLAGS = -Wall -W -Wno-unused-parameter
LINKER_DISPLAYS_MANGLED_NAMES = YES;
+
+
+TARGET_MAC_OS_X_VERSION_MAJOR = $(MAC_OS_X_VERSION_MAJOR);
+
+
+// Use GCC 4.2 with Xcode 3.1, which includes GCC 4.2 but defaults to GCC 4.0.
+// Note that Xcode versions as new as 3.1.2 use XCODE_VERSION_ACTUAL for the minor version
+// number. Newer versions of Xcode use XCODE_VERSION_MINOR for the minor version, and
+// XCODE_VERSION_ACTUAL for the full version number.
+TARGET_GCC_VERSION = $(TARGET_GCC_VERSION_$(TARGET_MAC_OS_X_VERSION_MAJOR));
+TARGET_GCC_VERSION_ = $(TARGET_GCC_VERSION_1040);
+TARGET_GCC_VERSION_1040 = GCC_40;
+TARGET_GCC_VERSION_1050 = $(TARGET_GCC_VERSION_1050_$(XCODE_VERSION_MINOR));
+TARGET_GCC_VERSION_1050_ = $(TARGET_GCC_VERSION_1050_$(XCODE_VERSION_ACTUAL));
+TARGET_GCC_VERSION_1050_0310 = GCC_42;
+TARGET_GCC_VERSION_1050_0320 = GCC_42;
+TARGET_GCC_VERSION_1060 = GCC_42;
+TARGET_GCC_VERSION_1070 = LLVM_GCC_42;
+
+GCC_VERSION = $(GCC_VERSION_$(TARGET_GCC_VERSION));
+GCC_VERSION_GCC_40 = 4.0;
+GCC_VERSION_GCC_42 = 4.2;
+GCC_VERSION_LLVM_GCC_42 = com.apple.compilers.llvmgcc42;
+
+// If the target Mac OS X version does not match the current Mac OS X version then we'll want to build using the target version's SDK.
+SDKROOT = $(SDKROOT_$(MAC_OS_X_VERSION_MAJOR)_$(TARGET_MAC_OS_X_VERSION_MAJOR));
+SDKROOT_1050_1040 = macosx10.4;
+SDKROOT_1060_1040 = macosx10.4;
+SDKROOT_1060_1050 = macosx10.5;
+SDKROOT_1070_1040 = macosx10.4;
+SDKROOT_1070_1050 = macosx10.5;
+SDKROOT_1070_1060 = macosx10.6;
diff --git a/WebKitTools/DumpRenderTree/mac/Configurations/DebugRelease.xcconfig b/WebKitTools/DumpRenderTree/mac/Configurations/DebugRelease.xcconfig
index 96a39a9..ab3278e 100644
--- a/WebKitTools/DumpRenderTree/mac/Configurations/DebugRelease.xcconfig
+++ b/WebKitTools/DumpRenderTree/mac/Configurations/DebugRelease.xcconfig
@@ -23,7 +23,7 @@
#include "Base.xcconfig"
-ARCHS = $(ARCHS_$(MAC_OS_X_VERSION_MAJOR));
+ARCHS = $(ARCHS_$(TARGET_MAC_OS_X_VERSION_MAJOR));
ARCHS_ = $(ARCHS_1040);
ARCHS_1040 = $(NATIVE_ARCH);
ARCHS_1050 = $(NATIVE_ARCH);
@@ -32,7 +32,7 @@ ARCHS_1070 = $(ARCHS_STANDARD_32_64_BIT);
ONLY_ACTIVE_ARCH = YES;
-MACOSX_DEPLOYMENT_TARGET = $(MACOSX_DEPLOYMENT_TARGET_$(MAC_OS_X_VERSION_MAJOR))
+MACOSX_DEPLOYMENT_TARGET = $(MACOSX_DEPLOYMENT_TARGET_$(TARGET_MAC_OS_X_VERSION_MAJOR))
MACOSX_DEPLOYMENT_TARGET_ = 10.4;
MACOSX_DEPLOYMENT_TARGET_1040 = 10.4;
MACOSX_DEPLOYMENT_TARGET_1050 = 10.5;
diff --git a/WebKitTools/DumpRenderTree/mac/DumpRenderTree.mm b/WebKitTools/DumpRenderTree/mac/DumpRenderTree.mm
index c7ddf21..0210cf0 100644
--- a/WebKitTools/DumpRenderTree/mac/DumpRenderTree.mm
+++ b/WebKitTools/DumpRenderTree/mac/DumpRenderTree.mm
@@ -76,15 +76,21 @@
#import <WebKit/WebTypesInternal.h>
#import <WebKit/WebViewPrivate.h>
#import <getopt.h>
-#import <mach-o/getsect.h>
#import <objc/objc-runtime.h>
#import <wtf/Assertions.h>
#import <wtf/RetainPtr.h>
#import <wtf/Threading.h>
#import <wtf/OwnPtr.h>
+extern "C" {
+#import <mach-o/getsect.h>
+}
+
using namespace std;
+@interface DumpRenderTreeApplication : NSApplication
+@end
+
@interface DumpRenderTreeEvent : NSEvent
@end
@@ -246,6 +252,7 @@ static void activateFonts()
static const char* fontFileNames[] = {
"AHEM____.TTF",
+ "ColorBits.ttf",
"WebKitWeightWatcher100.ttf",
"WebKitWeightWatcher200.ttf",
"WebKitWeightWatcher300.ttf",
@@ -355,7 +362,14 @@ void testStringByEvaluatingJavaScriptFromString()
static NSString *libraryPathForDumpRenderTree()
{
- return [@"~/Library/Application Support/DumpRenderTree" stringByExpandingTildeInPath];
+ //FIXME: This may not be sufficient to prevent interactions/crashes
+ //when running more than one copy of DumpRenderTree.
+ //See https://bugs.webkit.org/show_bug.cgi?id=10906
+ char* dumpRenderTreeTemp = getenv("DUMPRENDERTREE_TEMP");
+ if (dumpRenderTreeTemp)
+ return [[NSFileManager defaultManager] stringWithFileSystemRepresentation:dumpRenderTreeTemp length:strlen(dumpRenderTreeTemp)];
+ else
+ return [@"~/Library/Application Support/DumpRenderTree" stringByExpandingTildeInPath];
}
// Called before each test.
@@ -420,7 +434,7 @@ static void resetDefaultsToConsistentValues()
[preferences setOfflineWebApplicationCacheEnabled:YES];
[preferences setDeveloperExtrasEnabled:NO];
[preferences setLoadsImagesAutomatically:YES];
- [preferences setFrameSetFlatteningEnabled:NO];
+ [preferences setFrameFlatteningEnabled:NO];
if (persistentUserStyleSheetLocation) {
[preferences setUserStyleSheetLocation:[NSURL URLWithString:(NSString *)(persistentUserStyleSheetLocation.get())]];
[preferences setUserStyleSheetEnabled:YES];
@@ -430,20 +444,8 @@ static void resetDefaultsToConsistentValues()
// The back/forward cache is causing problems due to layouts during transition from one page to another.
// So, turn it off for now, but we might want to turn it back on some day.
[preferences setUsesPageCache:NO];
-
-#if defined(BUILDING_ON_LEOPARD)
- // Disable hardware composititing to avoid timeouts and crashes from buggy CoreVideo teardown code.
- // https://bugs.webkit.org/show_bug.cgi?id=28845 and rdar://problem/7228836
- SInt32 qtVersion;
- OSErr err = Gestalt(gestaltQuickTimeVersion, &qtVersion);
- assert(err == noErr);
- // Bug 7228836 exists in at least 7.6.3 through 7.6.4, hopefully it will be fixed in 7.6.5.
- // FIXME: Once we know the exact versions of QuickTime affected, we can update this check.
- if (qtVersion <= 0x07648000) // 7.6.4, final release (0x8). See http://developer.apple.com/mac/library/techn
- [preferences setAcceleratedCompositingEnabled:NO];
- else
-#endif
- [preferences setAcceleratedCompositingEnabled:YES];
+ [preferences setAcceleratedCompositingEnabled:YES];
+ [preferences setWebGLEnabled:NO];
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain];
@@ -686,7 +688,7 @@ void dumpRenderTree(int argc, const char *argv[])
int main(int argc, const char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- [NSApplication sharedApplication]; // Force AppKit to init itself
+ [DumpRenderTreeApplication sharedApplication]; // Force AppKit to init itself
dumpRenderTree(argc, argv);
[WebCoreStatistics garbageCollectJavaScriptObjects];
[WebCoreStatistics emptyCache]; // Otherwise SVGImages trigger false positives for Frame/Node counts
@@ -1139,9 +1141,15 @@ static bool shouldOpenWebInspector(const char* pathOrURL)
return strstr(pathOrURL, "inspector/");
}
+static bool shouldEnableDeveloperExtras(const char* pathOrURL)
+{
+ return shouldOpenWebInspector(pathOrURL) || strstr(pathOrURL, "inspector-enabled/");
+}
+
static void resetWebViewToConsistentStateBeforeTesting()
{
WebView *webView = [mainFrame webView];
+ [webView setEditable:NO];
[(EditingDelegate *)[webView editingDelegate] setAcceptsEditing:YES];
[webView makeTextStandardSize:nil];
[webView resetPageZoom:nil];
@@ -1162,7 +1170,7 @@ static void resetWebViewToConsistentStateBeforeTesting()
[[[mainFrame webView] inspector] setJavaScriptProfilingEnabled:NO];
[WebView _setUsesTestModeFocusRingColor:YES];
- [WebView _resetOriginAccessWhiteLists];
+ [WebView _resetOriginAccessWhitelists];
}
static void runTest(const string& testPathOrURL)
@@ -1217,8 +1225,11 @@ static void runTest(const string& testPathOrURL)
else
[[mainFrame webView] setHistoryDelegate:nil];
- if (shouldOpenWebInspector(pathOrURL.c_str()))
- gLayoutTestController->showWebInspector();
+ if (shouldEnableDeveloperExtras(pathOrURL.c_str())) {
+ gLayoutTestController->setDeveloperExtrasEnabled(true);
+ if (shouldOpenWebInspector(pathOrURL.c_str()))
+ gLayoutTestController->showWebInspector();
+ }
if ([WebHistory optionalSharedHistory])
[WebHistory setOptionalSharedHistory:nil];
@@ -1238,9 +1249,10 @@ static void runTest(const string& testPathOrURL)
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[mainFrame loadRequest:[NSURLRequest requestWithURL:url]];
[pool release];
+
while (!done) {
pool = [[NSAutoreleasePool alloc] init];
- [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantPast]];
+ [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantPast]];
[pool release];
}
@@ -1268,7 +1280,8 @@ static void runTest(const string& testPathOrURL)
}
}
- if (shouldOpenWebInspector(pathOrURL.c_str()))
+ // If developer extras enabled Web Inspector may have been open by the test.
+ if (shouldEnableDeveloperExtras(pathOrURL.c_str()))
gLayoutTestController->closeWebInspector();
resetWebViewToConsistentStateBeforeTesting();
@@ -1307,3 +1320,13 @@ void displayWebView()
}
@end
+
+@implementation DumpRenderTreeApplication
+
+- (BOOL)isRunning
+{
+ // <rdar://problem/7686123> Java plug-in freezes unless NSApplication is running
+ return YES;
+}
+
+@end
diff --git a/WebKitTools/DumpRenderTree/mac/EventSendingController.mm b/WebKitTools/DumpRenderTree/mac/EventSendingController.mm
index feaeddc..8c5cebf 100644
--- a/WebKitTools/DumpRenderTree/mac/EventSendingController.mm
+++ b/WebKitTools/DumpRenderTree/mac/EventSendingController.mm
@@ -134,7 +134,9 @@ BOOL replayingSavedEvents;
|| aSelector == @selector(textZoomIn)
|| aSelector == @selector(textZoomOut)
|| aSelector == @selector(zoomPageIn)
- || aSelector == @selector(zoomPageOut))
+ || aSelector == @selector(zoomPageOut)
+ || aSelector == @selector(mouseScrollByX:andY:)
+ || aSelector == @selector(continuousMouseScrollByX:andY:))
return NO;
return YES;
}
@@ -166,6 +168,10 @@ BOOL replayingSavedEvents;
return @"mouseMoveTo";
if (aSelector == @selector(setDragMode:))
return @"setDragMode";
+ if (aSelector == @selector(mouseScrollByX:andY:))
+ return @"mouseScrollBy";
+ if (aSelector == @selector(continuousMouseScrollByX:andY:))
+ return @"continuousMouseScrollBy";
return nil;
}
@@ -453,6 +459,39 @@ static int buildModifierFlags(const WebScriptObject* modifiers)
}
}
+- (void)mouseScrollByX:(int)x andY:(int)y continuously:(BOOL)c
+{
+ // CGEventCreateScrollWheelEvent() was introduced in 10.5
+#if !defined(BUILDING_ON_TIGER)
+ CGScrollEventUnit unit = c?kCGScrollEventUnitPixel:kCGScrollEventUnitLine;
+ CGEventRef cgScrollEvent = CGEventCreateScrollWheelEvent(NULL, unit, 2, y, x);
+
+ // CGEvent locations are in global display coordinates.
+ CGPoint lastGlobalMousePosition = {
+ lastMousePosition.x,
+ [[NSScreen mainScreen] frame].size.height - lastMousePosition.y
+ };
+ CGEventSetLocation(cgScrollEvent, lastGlobalMousePosition);
+
+ NSEvent *scrollEvent = [NSEvent eventWithCGEvent:cgScrollEvent];
+ CFRelease(cgScrollEvent);
+
+ NSView *subView = [[mainFrame webView] hitTest:[scrollEvent locationInWindow]];
+ if (subView)
+ [subView scrollWheel:scrollEvent];
+#endif
+}
+
+- (void)continuousMouseScrollByX:(int)x andY:(int)y
+{
+ [self mouseScrollByX:x andY:y continuously:YES];
+}
+
+- (void)mouseScrollByX:(int)x andY:(int)y
+{
+ [self mouseScrollByX:x andY:y continuously:NO];
+}
+
- (void)contextClick
{
[[[mainFrame frameView] documentView] layout];
@@ -507,33 +546,43 @@ static int buildModifierFlags(const WebScriptObject* modifiers)
- (void)keyDown:(NSString *)character withModifiers:(WebScriptObject *)modifiers withLocation:(unsigned long)keyLocation
{
NSString *eventCharacter = character;
+ unsigned short keyCode = 0;
if ([character isEqualToString:@"leftArrow"]) {
const unichar ch = NSLeftArrowFunctionKey;
eventCharacter = [NSString stringWithCharacters:&ch length:1];
+ keyCode = 0x7B;
} else if ([character isEqualToString:@"rightArrow"]) {
const unichar ch = NSRightArrowFunctionKey;
eventCharacter = [NSString stringWithCharacters:&ch length:1];
+ keyCode = 0x7C;
} else if ([character isEqualToString:@"upArrow"]) {
const unichar ch = NSUpArrowFunctionKey;
eventCharacter = [NSString stringWithCharacters:&ch length:1];
+ keyCode = 0x7E;
} else if ([character isEqualToString:@"downArrow"]) {
const unichar ch = NSDownArrowFunctionKey;
eventCharacter = [NSString stringWithCharacters:&ch length:1];
+ keyCode = 0x7D;
} else if ([character isEqualToString:@"pageUp"]) {
const unichar ch = NSPageUpFunctionKey;
eventCharacter = [NSString stringWithCharacters:&ch length:1];
+ keyCode = 0x74;
} else if ([character isEqualToString:@"pageDown"]) {
const unichar ch = NSPageDownFunctionKey;
eventCharacter = [NSString stringWithCharacters:&ch length:1];
+ keyCode = 0x79;
} else if ([character isEqualToString:@"home"]) {
const unichar ch = NSHomeFunctionKey;
eventCharacter = [NSString stringWithCharacters:&ch length:1];
+ keyCode = 0x73;
} else if ([character isEqualToString:@"end"]) {
const unichar ch = NSEndFunctionKey;
eventCharacter = [NSString stringWithCharacters:&ch length:1];
+ keyCode = 0x77;
} else if ([character isEqualToString:@"delete"]) {
const unichar ch = 0x7f;
eventCharacter = [NSString stringWithCharacters:&ch length:1];
+ keyCode = 0x75;
}
// Compare the input string with the function-key names defined by the DOM spec (i.e. "F1",...,"F24").
@@ -542,9 +591,59 @@ static int buildModifierFlags(const WebScriptObject* modifiers)
if ([character isEqualToString:[NSString stringWithFormat:@"F%u", i]]) {
const unichar ch = NSF1FunctionKey + (i - 1);
eventCharacter = [NSString stringWithCharacters:&ch length:1];
+ switch (i) {
+ case 1: keyCode = 0x7A; break;
+ case 2: keyCode = 0x78; break;
+ case 3: keyCode = 0x63; break;
+ case 4: keyCode = 0x76; break;
+ case 5: keyCode = 0x60; break;
+ case 6: keyCode = 0x61; break;
+ case 7: keyCode = 0x62; break;
+ case 8: keyCode = 0x64; break;
+ case 9: keyCode = 0x65; break;
+ case 10: keyCode = 0x6D; break;
+ case 11: keyCode = 0x67; break;
+ case 12: keyCode = 0x6F; break;
+ case 13: keyCode = 0x69; break;
+ case 14: keyCode = 0x6B; break;
+ case 15: keyCode = 0x71; break;
+ case 16: keyCode = 0x6A; break;
+ case 17: keyCode = 0x40; break;
+ case 18: keyCode = 0x4F; break;
+ case 19: keyCode = 0x50; break;
+ case 20: keyCode = 0x5A; break;
+ }
}
}
+ // FIXME: No keyCode is set for most keys.
+ if ([character isEqualToString:@"\t"])
+ keyCode = 0x30;
+ else if ([character isEqualToString:@" "])
+ keyCode = 0x31;
+ else if ([character isEqualToString:@"\r"])
+ keyCode = 0x24;
+ else if ([character isEqualToString:@"\n"])
+ keyCode = 0x4C;
+ else if ([character isEqualToString:@"\x8"])
+ keyCode = 0x33;
+ else if ([character isEqualToString:@"7"])
+ keyCode = 0x1A;
+ else if ([character isEqualToString:@"5"])
+ keyCode = 0x17;
+ else if ([character isEqualToString:@"9"])
+ keyCode = 0x19;
+ else if ([character isEqualToString:@"0"])
+ keyCode = 0x1D;
+ else if ([character isEqualToString:@"a"])
+ keyCode = 0x00;
+ else if ([character isEqualToString:@"b"])
+ keyCode = 0x0B;
+ else if ([character isEqualToString:@"d"])
+ keyCode = 0x02;
+ else if ([character isEqualToString:@"e"])
+ keyCode = 0x0E;
+
NSString *charactersIgnoringModifiers = eventCharacter;
int modifierFlags = 0;
@@ -570,7 +669,7 @@ static int buildModifierFlags(const WebScriptObject* modifiers)
characters:eventCharacter
charactersIgnoringModifiers:charactersIgnoringModifiers
isARepeat:NO
- keyCode:0];
+ keyCode:keyCode];
[[[[mainFrame webView] window] firstResponder] keyDown:event];
@@ -583,7 +682,7 @@ static int buildModifierFlags(const WebScriptObject* modifiers)
characters:eventCharacter
charactersIgnoringModifiers:charactersIgnoringModifiers
isARepeat:NO
- keyCode:0];
+ keyCode:keyCode];
[[[[mainFrame webView] window] firstResponder] keyUp:event];
}
diff --git a/WebKitTools/DumpRenderTree/mac/LayoutTestControllerMac.mm b/WebKitTools/DumpRenderTree/mac/LayoutTestControllerMac.mm
index 66ba5f0..e62e411 100644
--- a/WebKitTools/DumpRenderTree/mac/LayoutTestControllerMac.mm
+++ b/WebKitTools/DumpRenderTree/mac/LayoutTestControllerMac.mm
@@ -115,6 +115,11 @@ void LayoutTestController::addDisallowedURL(JSStringRef url)
CFSetAddValue(disallowedURLs, [request URL]);
}
+bool LayoutTestController::callShouldCloseOnWebView()
+{
+ return [[mainFrame webView] shouldClose];
+}
+
void LayoutTestController::clearAllDatabases()
{
[[WebDatabaseManager sharedWebDatabaseManager] deleteAllDatabases];
@@ -176,6 +181,23 @@ void LayoutTestController::keepWebHistory()
}
}
+JSValueRef LayoutTestController::computedStyleIncludingVisitedInfo(JSContextRef context, JSValueRef value)
+{
+ return [[mainFrame webView] _computedStyleIncludingVisitedInfo:context forElement:value];
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::layerTreeAsText() const
+{
+ JSRetainPtr<JSStringRef> string(Adopt, JSStringCreateWithCFString((CFStringRef)[mainFrame _layerTreeAsText]));
+ return string;
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::markerTextForListItem(JSContextRef context, JSValueRef nodeObject) const
+{
+ // FIXME: Implement me.
+ return JSRetainPtr<JSStringRef>();
+}
+
int LayoutTestController::pageNumberForElementById(JSStringRef id, float pageWidthInPixels, float pageHeightInPixels)
{
RetainPtr<CFStringRef> idCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, id));
@@ -302,7 +324,7 @@ void LayoutTestController::setIconDatabaseEnabled(bool iconDatabaseEnabled)
void LayoutTestController::setJavaScriptProfilingEnabled(bool profilingEnabled)
{
- [[[mainFrame webView] preferences] setDeveloperExtrasEnabled:profilingEnabled];
+ setDeveloperExtrasEnabled(profilingEnabled);
[[[mainFrame webView] inspector] setJavaScriptProfilingEnabled:profilingEnabled];
}
@@ -324,9 +346,14 @@ void LayoutTestController::setXSSAuditorEnabled(bool enabled)
[[[mainFrame webView] preferences] setXSSAuditorEnabled:enabled];
}
-void LayoutTestController::setFrameSetFlatteningEnabled(bool enabled)
+void LayoutTestController::setFrameFlatteningEnabled(bool enabled)
{
- [[[mainFrame webView] preferences] setFrameSetFlatteningEnabled:enabled];
+ [[[mainFrame webView] preferences] setFrameFlatteningEnabled:enabled];
+}
+
+void LayoutTestController::setSpatialNavigationEnabled(bool enabled)
+{
+ // FIXME: Implement for SpatialNavigation layout tests.
}
void LayoutTestController::setAllowUniversalAccessFromFileURLs(bool enabled)
@@ -424,7 +451,7 @@ void LayoutTestController::setSelectTrailingWhitespaceEnabled(bool flag)
[[mainFrame webView] setSelectTrailingWhitespaceEnabled:flag];
}
-static const CFTimeInterval waitToDumpWatchdogInterval = 15.0;
+static const CFTimeInterval waitToDumpWatchdogInterval = 30.0;
static void waitUntilDoneWatchdogFired(CFRunLoopTimerRef timer, void* info)
{
@@ -541,7 +568,7 @@ void LayoutTestController::waitForPolicyDelegate()
[[mainFrame webView] setPolicyDelegate:policyDelegate];
}
-void LayoutTestController::whiteListAccessFromOrigin(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains)
+void LayoutTestController::addOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains)
{
RetainPtr<CFStringRef> sourceOriginCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, sourceOrigin));
NSString *sourceOriginNS = (NSString *)sourceOriginCF.get();
@@ -549,7 +576,23 @@ void LayoutTestController::whiteListAccessFromOrigin(JSStringRef sourceOrigin, J
NSString *destinationProtocolNS = (NSString *)protocolCF.get();
RetainPtr<CFStringRef> hostCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, destinationHost));
NSString *destinationHostNS = (NSString *)hostCF.get();
- [WebView _whiteListAccessFromOrigin:sourceOriginNS destinationProtocol:destinationProtocolNS destinationHost:destinationHostNS allowDestinationSubdomains:allowDestinationSubdomains];
+ [WebView _addOriginAccessWhitelistEntryWithSourceOrigin:sourceOriginNS destinationProtocol:destinationProtocolNS destinationHost:destinationHostNS allowDestinationSubdomains:allowDestinationSubdomains];
+}
+
+void LayoutTestController::removeOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains)
+{
+ RetainPtr<CFStringRef> sourceOriginCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, sourceOrigin));
+ NSString *sourceOriginNS = (NSString *)sourceOriginCF.get();
+ RetainPtr<CFStringRef> protocolCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, destinationProtocol));
+ NSString *destinationProtocolNS = (NSString *)protocolCF.get();
+ RetainPtr<CFStringRef> hostCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, destinationHost));
+ NSString *destinationHostNS = (NSString *)hostCF.get();
+ [WebView _removeOriginAccessWhitelistEntryWithSourceOrigin:sourceOriginNS destinationProtocol:destinationProtocolNS destinationHost:destinationHostNS allowDestinationSubdomains:allowDestinationSubdomains];
+}
+
+void LayoutTestController::setScrollbarPolicy(JSStringRef orientation, JSStringRef policy)
+{
+ // FIXME: implement
}
void LayoutTestController::addUserScript(JSStringRef source, bool runAtStart)
@@ -566,16 +609,19 @@ void LayoutTestController::addUserStyleSheet(JSStringRef source)
[WebView _addUserStyleSheetToGroup:@"org.webkit.DumpRenderTree" world:[WebScriptWorld world] source:sourceNS url:nil whitelist:nil blacklist:nil];
}
+void LayoutTestController::setDeveloperExtrasEnabled(bool enabled)
+{
+ [[[mainFrame webView] preferences] setDeveloperExtrasEnabled:enabled];
+}
+
void LayoutTestController::showWebInspector()
{
- [[[mainFrame webView] preferences] setDeveloperExtrasEnabled:true];
[[[mainFrame webView] inspector] show:nil];
}
void LayoutTestController::closeWebInspector()
{
[[[mainFrame webView] inspector] close:nil];
- [[[mainFrame webView] preferences] setDeveloperExtrasEnabled:false];
}
void LayoutTestController::evaluateInWebInspector(long callId, JSStringRef script)
@@ -686,3 +732,101 @@ void LayoutTestController::apiTestNewWindowDataLoadBaseURL(JSStringRef utf8Data,
[delegate release];
[pool release];
}
+
+void LayoutTestController::apiTestGoToCurrentBackForwardItem()
+{
+ WebView *view = [mainFrame webView];
+ [view goToBackForwardItem:[[view backForwardList] currentItem]];
+}
+
+void LayoutTestController::setWebViewEditable(bool editable)
+{
+ WebView *view = [mainFrame webView];
+ [view setEditable:editable];
+}
+
+#ifndef BUILDING_ON_TIGER
+static NSString *SynchronousLoaderRunLoopMode = @"DumpRenderTreeSynchronousLoaderRunLoopMode";
+
+@interface SynchronousLoader : NSObject
+{
+ NSString *m_username;
+ NSString *m_password;
+ BOOL m_isDone;
+}
++ (void)makeRequest:(NSURLRequest *)request withUsername:(NSString *)username password:(NSString *)password;
+@end
+
+@implementation SynchronousLoader : NSObject
+- (void)dealloc
+{
+ [m_username release];
+ [m_password release];
+
+ [super dealloc];
+}
+
+- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)connection
+{
+ return YES;
+}
+
+- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
+{
+ if ([challenge previousFailureCount] == 0) {
+ NSURLCredential *credential = [[NSURLCredential alloc] initWithUser:m_username password:m_password persistence:NSURLCredentialPersistenceForSession];
+ [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
+ return;
+ }
+ [[challenge sender] cancelAuthenticationChallenge:challenge];
+}
+
+- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
+{
+ printf("SynchronousLoader failed: %s\n", [[error description] UTF8String]);
+ m_isDone = YES;
+}
+
+- (void)connectionDidFinishLoading:(NSURLConnection *)connection
+{
+ m_isDone = YES;
+}
+
++ (void)makeRequest:(NSURLRequest *)request withUsername:(NSString *)username password:(NSString *)password
+{
+ ASSERT(![[request URL] user]);
+ ASSERT(![[request URL] password]);
+
+ SynchronousLoader *delegate = [[SynchronousLoader alloc] init];
+ delegate->m_username = [username copy];
+ delegate->m_password = [password copy];
+
+ NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:delegate startImmediately:NO];
+ [connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:SynchronousLoaderRunLoopMode];
+ [connection start];
+
+ while (!delegate->m_isDone)
+ [[NSRunLoop currentRunLoop] runMode:SynchronousLoaderRunLoopMode beforeDate:[NSDate distantFuture]];
+
+ [connection cancel];
+
+ [connection release];
+ [delegate release];
+}
+
+@end
+#endif
+
+void LayoutTestController::authenticateSession(JSStringRef url, JSStringRef username, JSStringRef password)
+{
+ // See <rdar://problem/7880699>.
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+ RetainPtr<CFStringRef> urlStringCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, url));
+ RetainPtr<CFStringRef> usernameCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, username));
+ RetainPtr<CFStringRef> passwordCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, password));
+
+ NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:(NSString *)urlStringCF.get()]];
+
+ [SynchronousLoader makeRequest:request withUsername:(NSString *)usernameCF.get() password:(NSString *)passwordCF.get()];
+#endif
+}
diff --git a/WebKitTools/DumpRenderTree/mac/ResourceLoadDelegate.mm b/WebKitTools/DumpRenderTree/mac/ResourceLoadDelegate.mm
index 6f82e01..9244110 100644
--- a/WebKitTools/DumpRenderTree/mac/ResourceLoadDelegate.mm
+++ b/WebKitTools/DumpRenderTree/mac/ResourceLoadDelegate.mm
@@ -35,6 +35,8 @@
#import <WebKit/WebTypesInternal.h>
#import <wtf/Assertions.h>
+using namespace std;
+
@interface NSURL (DRTExtras)
- (NSString *)_drt_descriptionSuitableForTestResult;
@end
@@ -121,10 +123,10 @@
return @"<unknown>";
}
--(NSURLRequest *)webView: (WebView *)wv resource:identifier willSendRequest: (NSURLRequest *)newRequest redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource
+-(NSURLRequest *)webView: (WebView *)wv resource:identifier willSendRequest: (NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource
{
if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) {
- NSString *string = [NSString stringWithFormat:@"%@ - willSendRequest %@ redirectResponse %@", identifier, [newRequest _drt_descriptionSuitableForTestResult],
+ NSString *string = [NSString stringWithFormat:@"%@ - willSendRequest %@ redirectResponse %@", identifier, [request _drt_descriptionSuitableForTestResult],
[redirectResponse _drt_descriptionSuitableForTestResult]];
printf("%s\n", [string UTF8String]);
}
@@ -137,7 +139,7 @@
return nil;
}
- NSURL *url = [newRequest URL];
+ NSURL *url = [request URL];
NSString *host = [url host];
if (host
&& (NSOrderedSame == [[url scheme] caseInsensitiveCompare:@"http"] || NSOrderedSame == [[url scheme] caseInsensitiveCompare:@"https"])
@@ -151,7 +153,15 @@
if (disallowedURLs && CFSetContainsValue(disallowedURLs, url))
return nil;
- return newRequest;
+ NSMutableURLRequest *newRequest = [request mutableCopy];
+ const set<string>& clearHeaders = gLayoutTestController->willSendRequestClearHeaders();
+ for (set<string>::const_iterator header = clearHeaders.begin(); header != clearHeaders.end(); ++header) {
+ NSString *nsHeader = [[NSString alloc] initWithUTF8String:header->c_str()];
+ [newRequest setValue:nil forHTTPHeaderField:nsHeader];
+ [nsHeader release];
+ }
+
+ return [newRequest autorelease];
}
- (void)webView:(WebView *)wv resource:(id)identifier didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge fromDataSource:(WebDataSource *)dataSource
diff --git a/WebKitTools/DumpRenderTree/qt/DumpRenderTree.pro b/WebKitTools/DumpRenderTree/qt/DumpRenderTree.pro
index ad42bdd..b66eb5d 100644
--- a/WebKitTools/DumpRenderTree/qt/DumpRenderTree.pro
+++ b/WebKitTools/DumpRenderTree/qt/DumpRenderTree.pro
@@ -2,12 +2,8 @@ TARGET = DumpRenderTree
CONFIG -= app_bundle
CONFIG += uitools
-mac:!static:contains(QT_CONFIG, qt_framework):!CONFIG(webkit_no_framework) {
- CONFIG -= debug
- CONFIG += release
-}
-
BASEDIR = $$PWD/../
+isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../../..
include(../../../WebKit.pri)
INCLUDEPATH += /usr/include/freetype2
@@ -17,7 +13,7 @@ INCLUDEPATH += ../../../JavaScriptCore/ForwardingHeaders
INCLUDEPATH += $$BASEDIR
DESTDIR = ../../../bin
-!win32 {
+!win32:!symbian {
CONFIG += link_pkgconfig
PKGCONFIG += fontconfig
}
diff --git a/WebKitTools/DumpRenderTree/qt/DumpRenderTreeQt.cpp b/WebKitTools/DumpRenderTree/qt/DumpRenderTreeQt.cpp
index 43f1318..2c2db92 100644
--- a/WebKitTools/DumpRenderTree/qt/DumpRenderTreeQt.cpp
+++ b/WebKitTools/DumpRenderTree/qt/DumpRenderTreeQt.cpp
@@ -32,6 +32,7 @@
#include "config.h"
#include "DumpRenderTreeQt.h"
+#include "../../../WebKit/qt/WebCoreSupport/DumpRenderTreeSupportQt.h"
#include "EventSenderQt.h"
#include "GCControllerQt.h"
#include "LayoutTestControllerQt.h"
@@ -39,12 +40,11 @@
#include "testplugin.h"
#include "WorkQueue.h"
+#include <QApplication>
#include <QBuffer>
#include <QCryptographicHash>
#include <QDir>
#include <QFile>
-#include <QApplication>
-#include <QUrl>
#include <QFileInfo>
#include <QFocusEvent>
#include <QFontDatabase>
@@ -52,7 +52,13 @@
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
+#include <QPaintDevice>
+#include <QPaintEngine>
+#ifndef QT_NO_PRINTER
+#include <QPrinter>
+#endif
#include <QUndoStack>
+#include <QUrl>
#include <qwebsettings.h>
#include <qwebsecurityorigin.h>
@@ -66,6 +72,7 @@
#endif
#include <limits.h>
+#include <locale.h>
#ifndef Q_OS_WIN
#include <unistd.h>
@@ -73,20 +80,12 @@
#include <qdebug.h>
-extern void qt_drt_run(bool b);
extern void qt_dump_set_accepts_editing(bool b);
extern void qt_dump_frame_loader(bool b);
-extern void qt_drt_clearFrameName(QWebFrame* qFrame);
-extern void qt_drt_overwritePluginDirectories();
-extern void qt_drt_resetOriginAccessWhiteLists();
-extern bool qt_drt_hasDocumentElement(QWebFrame* qFrame);
+extern void qt_dump_resource_load_callbacks(bool b);
namespace WebCore {
-// Choose some default values.
-const unsigned int maxViewWidth = 800;
-const unsigned int maxViewHeight = 600;
-
NetworkAccessManager::NetworkAccessManager(QObject* parent)
: QNetworkAccessManager(parent)
{
@@ -116,6 +115,26 @@ void NetworkAccessManager::sslErrorsEncountered(QNetworkReply* reply, const QLis
}
#endif
+
+#ifndef QT_NO_PRINTER
+class NullPrinter : public QPrinter {
+public:
+ class NullPaintEngine : public QPaintEngine {
+ public:
+ virtual bool begin(QPaintDevice*) { return true; }
+ virtual bool end() { return true; }
+ virtual QPaintEngine::Type type() const { return QPaintEngine::User; }
+ virtual void drawPixmap(const QRectF& r, const QPixmap& pm, const QRectF& sr) { }
+ virtual void updateState(const QPaintEngineState& state) { }
+ };
+
+ virtual QPaintEngine* paintEngine() const { return const_cast<NullPaintEngine*>(&m_engine); }
+
+ NullPaintEngine m_engine;
+};
+#endif
+
+
WebPage::WebPage(QObject* parent, DumpRenderTree* drt)
: QWebPage(parent)
, m_webInspector(0)
@@ -135,6 +154,7 @@ WebPage::WebPage(QObject* parent, DumpRenderTree* drt)
globalSettings->setAttribute(QWebSettings::LocalContentCanAccessRemoteUrls, true);
globalSettings->setAttribute(QWebSettings::JavascriptEnabled, true);
globalSettings->setAttribute(QWebSettings::PrivateBrowsingEnabled, false);
+ globalSettings->setAttribute(QWebSettings::SpatialNavigationEnabled, false);
connect(this, SIGNAL(geometryChangeRequested(const QRect &)),
this, SLOT(setViewGeometry(const QRect & )));
@@ -165,9 +185,16 @@ void WebPage::resetSettings()
settings()->resetAttribute(QWebSettings::JavascriptCanOpenWindows);
settings()->resetAttribute(QWebSettings::JavascriptEnabled);
settings()->resetAttribute(QWebSettings::PrivateBrowsingEnabled);
+ settings()->resetAttribute(QWebSettings::SpatialNavigationEnabled);
settings()->resetAttribute(QWebSettings::LinksIncludedInFocusChain);
settings()->resetAttribute(QWebSettings::OfflineWebApplicationCacheEnabled);
settings()->resetAttribute(QWebSettings::LocalContentCanAccessRemoteUrls);
+ settings()->resetAttribute(QWebSettings::PluginsEnabled);
+
+ m_drt->layoutTestController()->setCaretBrowsingEnabled(false);
+ m_drt->layoutTestController()->setFrameFlatteningEnabled(false);
+ m_drt->layoutTestController()->setSmartInsertDeleteEnabled(true);
+ m_drt->layoutTestController()->setSelectTrailingWhitespaceEnabled(false);
// globalSettings must be reset explicitly.
m_drt->layoutTestController()->setXSSAuditorEnabled(false);
@@ -315,16 +342,25 @@ DumpRenderTree::DumpRenderTree()
, m_enableTextOutput(false)
, m_singleFileMode(false)
{
- qt_drt_overwritePluginDirectories();
- QWebSettings::enablePersistentStorage();
+ DumpRenderTreeSupportQt::overwritePluginDirectories();
+
+ char* dumpRenderTreeTemp = getenv("DUMPRENDERTREE_TEMP");
+ if (dumpRenderTreeTemp)
+ QWebSettings::enablePersistentStorage(QString(dumpRenderTreeTemp));
+ else
+ QWebSettings::enablePersistentStorage();
// create our primary testing page/view.
m_mainView = new QWebView(0);
- m_mainView->resize(QSize(maxViewWidth, maxViewHeight));
+ m_mainView->resize(QSize(LayoutTestController::maxViewWidth, LayoutTestController::maxViewHeight));
m_page = new WebPage(m_mainView, this);
m_mainView->setPage(m_page);
m_mainView->setContextMenuPolicy(Qt::NoContextMenu);
+ // clean up cache by resetting quota.
+ qint64 quota = webPage()->settings()->offlineWebApplicationCacheQuota();
+ webPage()->settings()->setOfflineWebApplicationCacheQuota(quota);
+
// create our controllers. This has to be done before connectFrame,
// as it exports there to the JavaScript DOM window.
m_controller = new LayoutTestController(this);
@@ -348,6 +384,7 @@ DumpRenderTree::DumpRenderTree()
connect(m_page, SIGNAL(loadStarted()),
m_controller, SLOT(resetLoadFinished()));
connect(m_page, SIGNAL(windowCloseRequested()), this, SLOT(windowCloseRequested()));
+ connect(m_page, SIGNAL(printRequested(QWebFrame*)), this, SLOT(dryRunPrint(QWebFrame*)));
connect(m_page->mainFrame(), SIGNAL(titleChanged(const QString&)),
SLOT(titleChanged(const QString&)));
@@ -357,7 +394,8 @@ DumpRenderTree::DumpRenderTree()
this, SLOT(statusBarMessage(const QString&)));
QObject::connect(this, SIGNAL(quit()), qApp, SLOT(quit()), Qt::QueuedConnection);
- qt_drt_run(true);
+
+ DumpRenderTreeSupportQt::setDumpRenderTreeModeEnabled(true);
QFocusEvent event(QEvent::FocusIn, Qt::ActiveWindowFocusReason);
QApplication::sendEvent(m_mainView, &event);
}
@@ -381,6 +419,14 @@ static void clearHistory(QWebPage* page)
history->setMaximumItemCount(itemCount);
}
+void DumpRenderTree::dryRunPrint(QWebFrame* frame)
+{
+#ifndef QT_NO_PRINTER
+ NullPrinter printer;
+ frame->print(&printer);
+#endif
+}
+
void DumpRenderTree::resetToConsistentStateBeforeTesting()
{
// reset so that any current loads are stopped
@@ -395,18 +441,24 @@ void DumpRenderTree::resetToConsistentStateBeforeTesting()
// of the DRT.
m_controller->reset();
+ // reset mouse clicks counter
+ m_eventSender->resetClickCount();
+
closeRemainingWindows();
m_page->resetSettings();
m_page->undoStack()->clear();
m_page->mainFrame()->setZoomFactor(1.0);
clearHistory(m_page);
- qt_drt_clearFrameName(m_page->mainFrame());
+ DumpRenderTreeSupportQt::clearFrameName(m_page->mainFrame());
+
+ m_page->mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAsNeeded);
+ m_page->mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAsNeeded);
WorkQueue::shared()->clear();
WorkQueue::shared()->setFrozen(false);
- qt_drt_resetOriginAccessWhiteLists();
+ DumpRenderTreeSupportQt::resetOriginAccessWhiteLists();
QLocale::setDefault(QLocale::c());
setlocale(LC_ALL, "");
@@ -419,20 +471,30 @@ static bool isWebInspectorTest(const QUrl& url)
return false;
}
+static bool shouldEnableDeveloperExtras(const QUrl& url)
+{
+ return isWebInspectorTest(url) || url.path().contains("inspector-enabled/");
+}
+
void DumpRenderTree::open(const QUrl& url)
{
resetToConsistentStateBeforeTesting();
- if (isWebInspectorTest(m_page->mainFrame()->url()))
+ if (shouldEnableDeveloperExtras(m_page->mainFrame()->url())) {
layoutTestController()->closeWebInspector();
+ layoutTestController()->setDeveloperExtrasEnabled(false);
+ }
- if (isWebInspectorTest(url))
- layoutTestController()->showWebInspector();
+ if (shouldEnableDeveloperExtras(url)) {
+ layoutTestController()->setDeveloperExtrasEnabled(true);
+ if (isWebInspectorTest(url))
+ layoutTestController()->showWebInspector();
+ }
// W3C SVG tests expect to be 480x360
bool isW3CTest = url.toString().contains("svg/W3C-SVG-1.1");
- int width = isW3CTest ? 480 : maxViewWidth;
- int height = isW3CTest ? 360 : maxViewHeight;
+ int width = isW3CTest ? 480 : LayoutTestController::maxViewWidth;
+ int height = isW3CTest ? 360 : LayoutTestController::maxViewHeight;
m_mainView->resize(QSize(width, height));
m_page->setPreferredContentsSize(QSize());
m_page->setViewportSize(QSize(width, height));
@@ -441,7 +503,9 @@ void DumpRenderTree::open(const QUrl& url)
m_page->event(&ev);
QWebSettings::clearMemoryCaches();
+#if !(defined(Q_WS_S60) && QT_VERSION <= QT_VERSION_CHECK(4, 6, 2))
QFontDatabase::removeAllApplicationFonts();
+#endif
#if defined(Q_WS_X11)
initializeFonts();
#endif
@@ -557,7 +621,7 @@ void DumpRenderTree::hidePage()
QString DumpRenderTree::dumpFramesAsText(QWebFrame* frame)
{
- if (!frame || !qt_drt_hasDocumentElement(frame))
+ if (!frame || !DumpRenderTreeSupportQt::hasDocumentElement(frame))
return QString();
QString result;
@@ -666,8 +730,9 @@ static const char *methodNameStringForFailedTest(LayoutTestController *controlle
void DumpRenderTree::dump()
{
- // Prevent any further frame load callbacks from appearing after we dump the result.
+ // Prevent any further frame load or resource load callbacks from appearing after we dump the result.
qt_dump_frame_loader(false);
+ qt_dump_resource_load_callbacks(false);
QWebFrame *mainFrame = m_page->mainFrame();
diff --git a/WebKitTools/DumpRenderTree/qt/DumpRenderTreeQt.h b/WebKitTools/DumpRenderTree/qt/DumpRenderTreeQt.h
index 8d80f87..8309492 100644
--- a/WebKitTools/DumpRenderTree/qt/DumpRenderTreeQt.h
+++ b/WebKitTools/DumpRenderTree/qt/DumpRenderTreeQt.h
@@ -53,6 +53,7 @@ QT_END_NAMESPACE
class QWebFrame;
class LayoutTestController;
+class DumpRenderTreeSupportQt;
class EventSender;
class TextInputController;
class GCController;
@@ -118,6 +119,7 @@ Q_SIGNALS:
private Q_SLOTS:
void showPage();
void hidePage();
+ void dryRunPrint(QWebFrame*);
private:
QString dumpFramesAsText(QWebFrame* frame);
diff --git a/WebKitTools/DumpRenderTree/qt/EventSenderQt.cpp b/WebKitTools/DumpRenderTree/qt/EventSenderQt.cpp
index 1ef2d3f..7432052 100644
--- a/WebKitTools/DumpRenderTree/qt/EventSenderQt.cpp
+++ b/WebKitTools/DumpRenderTree/qt/EventSenderQt.cpp
@@ -67,6 +67,8 @@ EventSender::EventSender(QWebPage* parent)
endOfQueue = 0;
startOfQueue = 0;
m_eventLoop = 0;
+ m_currentButton = 0;
+ resetClickCount();
m_page->view()->installEventFilter(this);
}
@@ -92,11 +94,28 @@ void EventSender::mouseDown(int button)
break;
}
+ // only consider a click to count, an event originated by the
+ // same previous button and at the same position.
+ if (m_currentButton == button
+ && m_mousePos == m_clickPos
+ && m_clickTimer.isActive())
+ m_clickCount++;
+ else
+ m_clickCount = 1;
+
+ m_currentButton = button;
+ m_clickPos = m_mousePos;
m_mouseButtons |= mouseButton;
// qDebug() << "EventSender::mouseDown" << frame;
- QMouseEvent* event = new QMouseEvent(QEvent::MouseButtonPress, m_mousePos, m_mousePos, mouseButton, m_mouseButtons, Qt::NoModifier);
+ QMouseEvent* event;
+ event = new QMouseEvent((m_clickCount == 2) ? QEvent::MouseButtonDblClick :
+ QEvent::MouseButtonPress, m_mousePos, m_mousePos,
+ mouseButton, m_mouseButtons, Qt::NoModifier);
+
sendOrQueueEvent(event);
+
+ m_clickTimer.start(QApplication::doubleClickInterval(), this);
}
void EventSender::mouseUp(int button)
@@ -289,11 +308,15 @@ void EventSender::scheduleAsynchronousClick()
void EventSender::addTouchPoint(int x, int y)
{
#if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)
- int id = m_touchPoints.count();
+ // Use index to refer to the position in the vector that this touch
+ // is stored. We then create a unique id for the touch that will be
+ // passed into WebCore.
+ int index = m_touchPoints.count();
+ int id = m_touchPoints.isEmpty() ? 0 : m_touchPoints.last().id() + 1;
QTouchEvent::TouchPoint point(id);
m_touchPoints.append(point);
- updateTouchPoint(id, x, y);
- m_touchPoints[id].setState(Qt::TouchPointPressed);
+ updateTouchPoint(index, x, y);
+ m_touchPoints[index].setState(Qt::TouchPointPressed);
#endif
}
@@ -510,3 +533,8 @@ bool EventSender::eventFilter(QObject* watched, QEvent* event)
}
return false;
}
+
+void EventSender::timerEvent(QTimerEvent* ev)
+{
+ m_clickTimer.stop();
+}
diff --git a/WebKitTools/DumpRenderTree/qt/EventSenderQt.h b/WebKitTools/DumpRenderTree/qt/EventSenderQt.h
index 38bca89..e824e0f 100644
--- a/WebKitTools/DumpRenderTree/qt/EventSenderQt.h
+++ b/WebKitTools/DumpRenderTree/qt/EventSenderQt.h
@@ -30,6 +30,7 @@
#define EventSenderQt_h
#include <QApplication>
+#include <QBasicTimer>
#include <QEvent>
#include <QEventLoop>
#include <QMouseEvent>
@@ -50,6 +51,7 @@ class EventSender : public QObject {
public:
EventSender(QWebPage* parent);
virtual bool eventFilter(QObject* watched, QEvent* event);
+ void resetClickCount() { m_clickCount = 0; }
public slots:
void mouseDown(int button = 0);
@@ -73,18 +75,24 @@ public slots:
void clearTouchPoints();
void releaseTouchPoint(int index);
+protected:
+ void timerEvent(QTimerEvent*);
+
private:
void sendTouchEvent(QEvent::Type);
void sendOrQueueEvent(QEvent*);
void replaySavedEvents(bool flush);
QPoint m_mousePos;
+ QPoint m_clickPos;
Qt::MouseButtons m_mouseButtons;
QWebPage* m_page;
- int m_timeLeap;
+ int m_clickCount;
+ int m_currentButton;
bool m_mouseButtonPressed;
bool m_drag;
QEventLoop* m_eventLoop;
QWebFrame* frameUnderMouse() const;
+ QBasicTimer m_clickTimer;
#if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)
QList<QTouchEvent::TouchPoint> m_touchPoints;
Qt::KeyboardModifiers m_touchModifiers;
diff --git a/WebKitTools/DumpRenderTree/qt/GCControllerQt.cpp b/WebKitTools/DumpRenderTree/qt/GCControllerQt.cpp
index 9cc3aa7..ba7e2c3 100644
--- a/WebKitTools/DumpRenderTree/qt/GCControllerQt.cpp
+++ b/WebKitTools/DumpRenderTree/qt/GCControllerQt.cpp
@@ -29,14 +29,10 @@
#include "config.h"
#include "GCControllerQt.h"
+#include "../../../WebKit/qt/WebCoreSupport/DumpRenderTreeSupportQt.h"
#include <qwebpage.h>
-extern int qt_drt_javaScriptObjectsCount();
-extern void qt_drt_garbageCollector_collect();
-
-extern void qt_drt_garbageCollector_collectOnAlternateThread(bool waitUntilDone);
-
GCController::GCController(QWebPage* parent)
: QObject(parent)
{
@@ -44,15 +40,15 @@ GCController::GCController(QWebPage* parent)
void GCController::collect() const
{
- qt_drt_garbageCollector_collect();
+ DumpRenderTreeSupportQt::garbageCollectorCollect();
}
void GCController::collectOnAlternateThread(bool waitUntilDone) const
{
- qt_drt_garbageCollector_collectOnAlternateThread(waitUntilDone);
+ DumpRenderTreeSupportQt::garbageCollectorCollectOnAlternateThread(waitUntilDone);
}
size_t GCController::getJSObjectCount() const
{
- return qt_drt_javaScriptObjectsCount();
+ return DumpRenderTreeSupportQt::javaScriptObjectsCount();
}
diff --git a/WebKitTools/DumpRenderTree/qt/GCControllerQt.h b/WebKitTools/DumpRenderTree/qt/GCControllerQt.h
index 8f5b432..ed2a858 100644
--- a/WebKitTools/DumpRenderTree/qt/GCControllerQt.h
+++ b/WebKitTools/DumpRenderTree/qt/GCControllerQt.h
@@ -32,6 +32,7 @@
#include <QObject>
class QWebPage;
+class DumpRenderTreeSupportQt;
class GCController : public QObject
{
@@ -43,6 +44,7 @@ public slots:
void collect() const;
void collectOnAlternateThread(bool waitUntilDone) const;
size_t getJSObjectCount() const;
+
};
#endif
diff --git a/WebKitTools/DumpRenderTree/qt/ImageDiff.pro b/WebKitTools/DumpRenderTree/qt/ImageDiff.pro
index 636835a..74fabf8 100644
--- a/WebKitTools/DumpRenderTree/qt/ImageDiff.pro
+++ b/WebKitTools/DumpRenderTree/qt/ImageDiff.pro
@@ -1,9 +1,10 @@
TARGET = ImageDiff
CONFIG -= app_bundle
+isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../../..
include(../../../WebKit.pri)
INCLUDEPATH += ../../../JavaScriptCore
-DESTDIR = ../../../bin
+DESTDIR = $$OUTPUT_DIR/bin
QT = core gui
diff --git a/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.cpp b/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.cpp
index a26bc3d..b95fe23 100644
--- a/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.cpp
+++ b/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.cpp
@@ -28,6 +28,7 @@
*/
#include "config.h"
#include "LayoutTestControllerQt.h"
+#include "../../../WebKit/qt/WebCoreSupport/DumpRenderTreeSupportQt.h"
#include "DumpRenderTreeQt.h"
#include "WorkQueue.h"
@@ -36,32 +37,23 @@
#include <QLocale>
#include <qwebsettings.h>
+extern void qt_wrt_setViewMode(QWebPage* page, const QString& mode);
extern void qt_dump_editing_callbacks(bool b);
extern void qt_dump_frame_loader(bool b);
extern void qt_dump_resource_load_callbacks(bool b);
-extern void qt_drt_setFrameSetFlatteningEnabled(QWebPage*, bool);
-extern void qt_drt_setJavaScriptProfilingEnabled(QWebFrame*, bool enabled);
-extern void qt_drt_setTimelineProfilingEnabled(QWebPage*, bool enabled);
-extern bool qt_drt_pauseAnimation(QWebFrame*, const QString& name, double time, const QString& elementId);
-extern bool qt_drt_pauseTransitionOfProperty(QWebFrame*, const QString& name, double time, const QString& elementId);
-extern bool qt_drt_pauseSVGAnimation(QWebFrame*, const QString& animationId, double time, const QString& elementId);
-extern int qt_drt_numberOfActiveAnimations(QWebFrame*);
-extern void qt_drt_setDomainRelaxationForbiddenForURLScheme(bool forbidden, const QString& scheme);
-
-extern void qt_drt_whiteListAccessFromOrigin(const QString& sourceOrigin, const QString& destinationProtocol, const QString& destinationHost, bool allowDestinationSubdomains);
-extern QString qt_drt_counterValueForElementById(QWebFrame* qFrame, const QString& id);
-extern int qt_drt_workerThreadCount();
-extern int qt_drt_pageNumberForElementById(QWebFrame* qFrame, const QString& id, float width, float height);
-extern int qt_drt_numberOfPages(QWebFrame* qFrame, float width, float height);
-extern void qt_drt_webinspector_executeScript(QWebPage* page, long callId, const QString& script);
-extern void qt_drt_webinspector_show(QWebPage *page);
-extern void qt_drt_webinspector_close(QWebPage *page);
+extern void qt_set_will_send_request_returns_null_on_redirect(bool b);
+extern void qt_set_will_send_request_returns_null(bool b);
+extern void qt_set_will_send_request_clear_headers(const QStringList& headers);
+
+extern void qt_dump_notification(bool b);
LayoutTestController::LayoutTestController(WebCore::DumpRenderTree* drt)
: QObject()
, m_drt(drt)
{
+ qRegisterMetaType<QWebElement>("QWebElement");
reset();
+ qt_dump_notification(true);
}
void LayoutTestController::reset()
@@ -85,6 +77,9 @@ void LayoutTestController::reset()
qt_dump_editing_callbacks(false);
qt_dump_frame_loader(false);
qt_dump_resource_load_callbacks(false);
+ qt_set_will_send_request_returns_null_on_redirect(false);
+ qt_set_will_send_request_returns_null(false);
+ qt_set_will_send_request_clear_headers(QStringList());
emit hidePage();
}
@@ -136,12 +131,17 @@ void LayoutTestController::waitUntilDone()
{
//qDebug() << ">>>>waitForDone";
m_waitForDone = true;
- m_timeoutTimer.start(15000, this);
+ m_timeoutTimer.start(30000, this);
}
QString LayoutTestController::counterValueForElementById(const QString& id)
{
- return qt_drt_counterValueForElementById(m_drt->webPage()->mainFrame(), id);
+ return DumpRenderTreeSupportQt::counterValueForElementById(m_drt->webPage()->mainFrame(), id);
+}
+
+void LayoutTestController::setViewModeMediaFeature(const QString& mode)
+{
+ qt_wrt_setViewMode(m_drt->webPage(), mode);
}
int LayoutTestController::webHistoryItemCount()
@@ -188,6 +188,17 @@ int LayoutTestController::windowCount()
return m_drt->windowCount();
}
+void LayoutTestController::grantDesktopNotificationPermission(const QString& origin)
+{
+ // FIXME: Implement for notification security
+}
+
+bool LayoutTestController::checkDesktopNotificationPermission(const QString& origin)
+{
+ // FIXME: Implement for notification security
+ return true;
+}
+
void LayoutTestController::display()
{
emit showPage();
@@ -220,6 +231,21 @@ void LayoutTestController::dumpResourceLoadCallbacks()
qt_dump_resource_load_callbacks(true);
}
+void LayoutTestController::setWillSendRequestReturnsNullOnRedirect(bool enabled)
+{
+ qt_set_will_send_request_returns_null_on_redirect(enabled);
+}
+
+void LayoutTestController::setWillSendRequestReturnsNull(bool enabled)
+{
+ qt_set_will_send_request_returns_null(enabled);
+}
+
+void LayoutTestController::setWillSendRequestClearHeader(const QStringList& headers)
+{
+ qt_set_will_send_request_clear_headers(headers);
+}
+
void LayoutTestController::queueBackNavigation(int howFarBackward)
{
//qDebug() << ">>>queueBackNavigation" << howFarBackward;
@@ -290,27 +316,36 @@ QString LayoutTestController::decodeHostName(const QString& host)
return decoded;
}
+void LayoutTestController::setMediaType(const QString& type)
+{
+ DumpRenderTreeSupportQt::setMediaType(m_drt->webPage()->mainFrame(), type);
+}
void LayoutTestController::closeWebInspector()
{
- qt_drt_webinspector_close(m_drt->webPage());
+ DumpRenderTreeSupportQt::webInspectorClose(m_drt->webPage());
m_drt->webPage()->settings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, false);
}
+void LayoutTestController::setDeveloperExtrasEnabled(bool enabled)
+{
+ m_drt->webPage()->settings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, enabled);
+}
+
void LayoutTestController::showWebInspector()
{
m_drt->webPage()->settings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true);
- qt_drt_webinspector_show(m_drt->webPage());
+ DumpRenderTreeSupportQt::webInspectorShow(m_drt->webPage());
}
void LayoutTestController::evaluateInWebInspector(long callId, const QString& script)
{
- qt_drt_webinspector_executeScript(m_drt->webPage(), callId, script);
+ DumpRenderTreeSupportQt::webInspectorExecuteScript(m_drt->webPage(), callId, script);
}
-void LayoutTestController::setFrameSetFlatteningEnabled(bool enabled)
+void LayoutTestController::setFrameFlatteningEnabled(bool enabled)
{
- qt_drt_setFrameSetFlatteningEnabled(m_drt->webPage(), enabled);
+ DumpRenderTreeSupportQt::setFrameFlatteningEnabled(m_drt->webPage(), enabled);
}
void LayoutTestController::setAllowUniversalAccessFromFileURLs(bool enabled)
@@ -323,15 +358,20 @@ void LayoutTestController::setAllowFileAccessFromFileURLs(bool enabled)
m_drt->webPage()->settings()->setAttribute(QWebSettings::LocalContentCanAccessFileUrls, enabled);
}
+void LayoutTestController::setAppCacheMaximumSize(unsigned long long quota)
+{
+ m_drt->webPage()->settings()->setOfflineWebApplicationCacheQuota(quota);
+}
+
void LayoutTestController::setJavaScriptProfilingEnabled(bool enable)
{
- m_topLoadingFrame->page()->settings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true);
- qt_drt_setJavaScriptProfilingEnabled(m_topLoadingFrame, enable);
+ setDeveloperExtrasEnabled(enable);
+ DumpRenderTreeSupportQt::setJavaScriptProfilingEnabled(m_topLoadingFrame, enable);
}
void LayoutTestController::setTimelineProfilingEnabled(bool enable)
{
- qt_drt_setTimelineProfilingEnabled(m_drt->webPage(), enable);
+ DumpRenderTreeSupportQt::setTimelineProfilingEnabled(m_drt->webPage(), enable);
}
void LayoutTestController::setFixedContentsSize(int width, int height)
@@ -344,6 +384,11 @@ void LayoutTestController::setPrivateBrowsingEnabled(bool enable)
m_drt->webPage()->settings()->setAttribute(QWebSettings::PrivateBrowsingEnabled, enable);
}
+void LayoutTestController::setSpatialNavigationEnabled(bool enable)
+{
+ m_drt->webPage()->settings()->setAttribute(QWebSettings::SpatialNavigationEnabled, enable);
+}
+
void LayoutTestController::setPopupBlockingEnabled(bool enable)
{
m_drt->webPage()->settings()->setAttribute(QWebSettings::JavascriptCanOpenWindows, !enable);
@@ -367,12 +412,12 @@ void LayoutTestController::setMainFrameIsFirstResponder(bool isFirst)
void LayoutTestController::setXSSAuditorEnabled(bool enable)
{
- // Set XSSAuditorEnabled globally so that windows created by the test inherit it too.
+ // Set XSSAuditingEnabled globally so that windows created by the test inherit it too.
// resetSettings() will call this to reset the page and global setting to false again.
// Needed by http/tests/security/xssAuditor/link-opens-new-window.html
QWebSettings* globalSettings = QWebSettings::globalSettings();
- globalSettings->setAttribute(QWebSettings::XSSAuditorEnabled, enable);
- m_drt->webPage()->settings()->setAttribute(QWebSettings::XSSAuditorEnabled, enable);
+ globalSettings->setAttribute(QWebSettings::XSSAuditingEnabled, enable);
+ m_drt->webPage()->settings()->setAttribute(QWebSettings::XSSAuditingEnabled, enable);
}
bool LayoutTestController::pauseAnimationAtTimeOnElementWithId(const QString& animationName,
@@ -381,7 +426,7 @@ bool LayoutTestController::pauseAnimationAtTimeOnElementWithId(const QString& an
{
QWebFrame* frame = m_drt->webPage()->mainFrame();
Q_ASSERT(frame);
- return qt_drt_pauseAnimation(frame, animationName, time, elementId);
+ return DumpRenderTreeSupportQt::pauseAnimation(frame, animationName, time, elementId);
}
bool LayoutTestController::pauseTransitionAtTimeOnElementWithId(const QString& propertyName,
@@ -390,7 +435,7 @@ bool LayoutTestController::pauseTransitionAtTimeOnElementWithId(const QString& p
{
QWebFrame* frame = m_drt->webPage()->mainFrame();
Q_ASSERT(frame);
- return qt_drt_pauseTransitionOfProperty(frame, propertyName, time, elementId);
+ return DumpRenderTreeSupportQt::pauseTransitionOfProperty(frame, propertyName, time, elementId);
}
bool LayoutTestController::sampleSVGAnimationForElementAtTime(const QString& animationId,
@@ -399,14 +444,14 @@ bool LayoutTestController::sampleSVGAnimationForElementAtTime(const QString& ani
{
QWebFrame* frame = m_drt->webPage()->mainFrame();
Q_ASSERT(frame);
- return qt_drt_pauseSVGAnimation(frame, animationId, time, elementId);
+ return DumpRenderTreeSupportQt::pauseSVGAnimation(frame, animationId, time, elementId);
}
unsigned LayoutTestController::numberOfActiveAnimations() const
{
QWebFrame* frame = m_drt->webPage()->mainFrame();
Q_ASSERT(frame);
- return qt_drt_numberOfActiveAnimations(frame);
+ return DumpRenderTreeSupportQt::numberOfActiveAnimations(frame);
}
void LayoutTestController::disableImageLoading()
@@ -432,9 +477,14 @@ void LayoutTestController::clearAllDatabases()
QWebDatabase::removeAllDatabases();
}
-void LayoutTestController::whiteListAccessFromOrigin(const QString& sourceOrigin, const QString& destinationProtocol, const QString& destinationHost, bool allowDestinationSubdomains)
+void LayoutTestController::addOriginAccessWhitelistEntry(const QString& sourceOrigin, const QString& destinationProtocol, const QString& destinationHost, bool allowDestinationSubdomains)
+{
+ DumpRenderTreeSupportQt::whiteListAccessFromOrigin(sourceOrigin, destinationProtocol, destinationHost, allowDestinationSubdomains);
+}
+
+void LayoutTestController::removeOriginAccessWhitelistEntry(const QString& sourceOrigin, const QString& destinationProtocol, const QString& destinationHost, bool allowDestinationSubdomains)
{
- qt_drt_whiteListAccessFromOrigin(sourceOrigin, destinationProtocol, destinationHost, allowDestinationSubdomains);
+ // FIXME: Implement.
}
void LayoutTestController::waitForPolicyDelegate()
@@ -457,6 +507,10 @@ void LayoutTestController::overridePreference(const QString& name, const QVarian
settings->setFontSize(QWebSettings::DefaultFontSize, value.toInt());
else if (name == "WebKitUsesPageCachePreferenceKey")
QWebSettings::setMaximumPagesInCache(value.toInt());
+ else if (name == "WebKitEnableCaretBrowsing")
+ setCaretBrowsingEnabled(value.toBool());
+ else if (name == "WebKitPluginsEnabled")
+ settings->setAttribute(QWebSettings::PluginsEnabled, value.toBool());
else
printf("ERROR: LayoutTestController::overridePreference() does not support the '%s' preference\n",
name.toLatin1().data());
@@ -467,6 +521,11 @@ void LayoutTestController::setUserStyleSheetLocation(const QString& url)
m_userStyleSheetLocation = QUrl(url);
}
+void LayoutTestController::setCaretBrowsingEnabled(bool value)
+{
+ DumpRenderTreeSupportQt::setCaretBrowsingEnabled(m_drt->webPage(), value);
+}
+
void LayoutTestController::setUserStyleSheetEnabled(bool enabled)
{
if (enabled)
@@ -477,12 +536,12 @@ void LayoutTestController::setUserStyleSheetEnabled(bool enabled)
void LayoutTestController::setDomainRelaxationForbiddenForURLScheme(bool forbidden, const QString& scheme)
{
- qt_drt_setDomainRelaxationForbiddenForURLScheme(forbidden, scheme);
+ DumpRenderTreeSupportQt::setDomainRelaxationForbiddenForURLScheme(forbidden, scheme);
}
int LayoutTestController::workerThreadCount()
{
- return qt_drt_workerThreadCount();
+ return DumpRenderTreeSupportQt::workerThreadCount();
}
int LayoutTestController::pageNumberForElementById(const QString& id, float width, float height)
@@ -493,10 +552,74 @@ int LayoutTestController::pageNumberForElementById(const QString& id, float widt
height = m_drt->webPage()->viewportSize().height();
}
- return qt_drt_pageNumberForElementById(m_drt->webPage()->mainFrame(), id, width, height);
+ return DumpRenderTreeSupportQt::pageNumberForElementById(m_drt->webPage()->mainFrame(), id, width, height);
}
int LayoutTestController::numberOfPages(float width, float height)
{
- return qt_drt_numberOfPages(m_drt->webPage()->mainFrame(), width, height);
+ return DumpRenderTreeSupportQt::numberOfPages(m_drt->webPage()->mainFrame(), width, height);
+}
+
+bool LayoutTestController::callShouldCloseOnWebView()
+{
+ // FIXME: Implement for testing fix for https://bugs.webkit.org/show_bug.cgi?id=27481
+ return false;
+}
+
+void LayoutTestController::setScrollbarPolicy(const QString& orientation, const QString& policy)
+{
+ Qt::Orientation o;
+ Qt::ScrollBarPolicy p;
+
+ if (orientation == "vertical")
+ o = Qt::Vertical;
+ else if (orientation == "horizontal")
+ o = Qt::Horizontal;
+ else
+ return;
+
+ if (policy == "on")
+ p = Qt::ScrollBarAlwaysOn;
+ else if (policy == "auto")
+ p = Qt::ScrollBarAsNeeded;
+ else if (policy == "off")
+ p = Qt::ScrollBarAlwaysOff;
+ else
+ return;
+
+ m_drt->webPage()->mainFrame()->setScrollBarPolicy(o, p);
+}
+
+void LayoutTestController::setSmartInsertDeleteEnabled(bool enable)
+{
+ DumpRenderTreeSupportQt::setSmartInsertDeleteEnabled(m_drt->webPage(), enable);
}
+
+void LayoutTestController::setSelectTrailingWhitespaceEnabled(bool enable)
+{
+ DumpRenderTreeSupportQt::setSelectTrailingWhitespaceEnabled(m_drt->webPage(), enable);
+}
+
+void LayoutTestController::execCommand(const QString& name, const QString& value)
+{
+ DumpRenderTreeSupportQt::executeCoreCommandByName(m_drt->webPage(), name, value);
+}
+
+bool LayoutTestController::isCommandEnabled(const QString& name) const
+{
+ return DumpRenderTreeSupportQt::isCommandEnabled(m_drt->webPage(), name);
+}
+
+QString LayoutTestController::markerTextForListItem(const QWebElement& listItem)
+{
+ return DumpRenderTreeSupportQt::markerTextForListItem(listItem);
+}
+
+void LayoutTestController::authenticateSession(const QString&, const QString&, const QString&)
+{
+ // FIXME: If there is a concept per-session (per-process) credential storage, the credentials should be added to it for later use.
+}
+
+
+const unsigned LayoutTestController::maxViewWidth = 800;
+const unsigned LayoutTestController::maxViewHeight = 600;
diff --git a/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.h b/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.h
index d73794e..df645e1 100644
--- a/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.h
+++ b/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.h
@@ -40,12 +40,14 @@
#include <QVariant>
#include <qwebdatabase.h>
+#include <qwebelement.h>
#include <qwebframe.h>
#include <qwebhistory.h>
#include <qwebpage.h>
#include <qwebsecurityorigin.h>
class QWebFrame;
+class DumpRenderTreeSupportQt;
namespace WebCore {
class DumpRenderTree;
}
@@ -70,6 +72,9 @@ public:
void reset();
+ static const unsigned int maxViewWidth;
+ static const unsigned int maxViewHeight;
+
protected:
void timerEvent(QTimerEvent*);
@@ -98,6 +103,9 @@ public slots:
void dumpEditingCallbacks();
void dumpFrameLoadCallbacks();
void dumpResourceLoadCallbacks();
+ void setWillSendRequestReturnsNullOnRedirect(bool enabled);
+ void setWillSendRequestReturnsNull(bool enabled);
+ void setWillSendRequestClearHeader(const QStringList& headers);
void queueBackNavigation(int howFarBackward);
void queueForwardNavigation(int howFarForward);
void queueLoad(const QString& url, const QString& target = QString());
@@ -107,6 +115,8 @@ public slots:
void provisionalLoad();
void setCloseRemainingWindowsWhenComplete(bool = false) {}
int windowCount();
+ void grantDesktopNotificationPermission(const QString& origin);
+ bool checkDesktopNotificationPermission(const QString& origin);
void display();
void clearBackForwardList();
QString pathToLocalResource(const QString& url);
@@ -114,23 +124,33 @@ public slots:
QString encodeHostName(const QString& host);
QString decodeHostName(const QString& host);
void dumpSelectionRect() const {}
+ void setDeveloperExtrasEnabled(bool);
void showWebInspector();
void closeWebInspector();
void evaluateInWebInspector(long callId, const QString& script);
- void setFrameSetFlatteningEnabled(bool enable);
+ void setMediaType(const QString& type);
+ void setFrameFlatteningEnabled(bool enable);
void setAllowUniversalAccessFromFileURLs(bool enable);
void setAllowFileAccessFromFileURLs(bool enable);
+ void setAppCacheMaximumSize(unsigned long long quota);
void setJavaScriptProfilingEnabled(bool enable);
void setTimelineProfilingEnabled(bool enable);
void setFixedContentsSize(int width, int height);
void setPrivateBrowsingEnabled(bool enable);
+ void setSpatialNavigationEnabled(bool enabled);
void setPopupBlockingEnabled(bool enable);
void setPOSIXLocale(const QString& locale);
void resetLoadFinished() { m_loadFinished = false; }
void setWindowIsKey(bool isKey);
void setMainFrameIsFirstResponder(bool isFirst);
void setXSSAuditorEnabled(bool enable);
+ void setCaretBrowsingEnabled(bool enable);
+ void setViewModeMediaFeature(const QString& mode);
+ void setSmartInsertDeleteEnabled(bool enable);
+ void setSelectTrailingWhitespaceEnabled(bool enable);
+ void execCommand(const QString& name, const QString& value = QString());
+ bool isCommandEnabled(const QString& name) const;
bool pauseAnimationAtTimeOnElementWithId(const QString& animationName, double time, const QString& elementId);
bool pauseTransitionAtTimeOnElementWithId(const QString& propertyName, double time, const QString& elementId);
@@ -138,7 +158,8 @@ public slots:
unsigned numberOfActiveAnimations() const;
- void whiteListAccessFromOrigin(const QString& sourceOrigin, const QString& destinationProtocol, const QString& destinationHost, bool allowDestinationSubdomains);
+ void addOriginAccessWhitelistEntry(const QString& sourceOrigin, const QString& destinationProtocol, const QString& destinationHost, bool allowDestinationSubdomains);
+ void removeOriginAccessWhitelistEntry(const QString& sourceOrigin, const QString& destinationProtocol, const QString& destinationHost, bool allowDestinationSubdomains);
void dispatchPendingLoadRequests();
void disableImageLoading();
@@ -153,7 +174,19 @@ public slots:
void setDomainRelaxationForbiddenForURLScheme(bool forbidden, const QString& scheme);
int workerThreadCount();
int pageNumberForElementById(const QString& id, float width = 0, float height = 0);
- int numberOfPages(float width, float height);
+ int numberOfPages(float width = maxViewWidth, float height = maxViewHeight);
+ bool callShouldCloseOnWebView();
+
+ /*
+ Policy values: 'on', 'auto' or 'off'.
+ Orientation values: 'vertical' or 'horizontal'.
+ */
+ void setScrollbarPolicy(const QString& orientation, const QString& policy);
+
+ QString markerTextForListItem(const QWebElement& listItem);
+
+ // Simulate a request an embedding application could make, populating per-session credential storage.
+ void authenticateSession(const QString& url, const QString& username, const QString& password);
private slots:
void processWork();
diff --git a/WebKitTools/DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro b/WebKitTools/DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro
index 7b8162b..9b19231 100644
--- a/WebKitTools/DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro
+++ b/WebKitTools/DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro
@@ -2,6 +2,7 @@ TEMPLATE = lib
TARGET = TestNetscapePlugIn
VPATH = ../../unix/TestNetscapePlugin ../../TestNetscapePlugIn.subproj
+isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../../../..
include(../../../../WebKit.pri)
DESTDIR = $$OUTPUT_DIR/lib/plugins
diff --git a/WebKitTools/DumpRenderTree/qt/main.cpp b/WebKitTools/DumpRenderTree/qt/main.cpp
index 7d72982..7d1c08c 100644
--- a/WebKitTools/DumpRenderTree/qt/main.cpp
+++ b/WebKitTools/DumpRenderTree/qt/main.cpp
@@ -93,7 +93,7 @@ QString get_backtrace() {
return s;
}
-#ifndef Q_OS_WIN
+#if HAVE(SIGNAL_H)
static NO_RETURN void crashHandler(int sig)
{
fprintf(stderr, "%s\n", strsignal(sig));
@@ -114,10 +114,7 @@ int main(int argc, char* argv[])
WebCore::DumpRenderTree::initializeFonts();
#endif
-#if QT_VERSION >= 0x040500
QApplication::setGraphicsSystem("raster");
-#endif
-
QApplication::setStyle(new QWindowsStyle);
QFont f("Sans Serif");
@@ -132,7 +129,7 @@ int main(int argc, char* argv[])
QX11Info::setAppDpiX(0, 96);
#endif
-#ifndef Q_OS_WIN
+#if HAVE(SIGNAL_H)
signal(SIGILL, crashHandler); /* 4: illegal instruction (not reset when caught) */
signal(SIGTRAP, crashHandler); /* 5: trace trap (not reset when caught) */
signal(SIGFPE, crashHandler); /* 8: floating point exception */
diff --git a/WebKitTools/DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp b/WebKitTools/DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp
index cb01267..a3c6773 100644
--- a/WebKitTools/DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp
+++ b/WebKitTools/DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp
@@ -58,6 +58,7 @@ webkit_test_plugin_new_instance(NPMIMEType /*mimetype*/,
{
if (browser->version >= 14) {
PluginObject* obj = (PluginObject*)browser->createobject(instance, getPluginClass());
+ instance->pdata = obj;
for (int i = 0; i < argc; i++) {
if (strcasecmp(argn[i], "onstreamload") == 0 && !obj->onStreamLoad)
@@ -85,8 +86,11 @@ webkit_test_plugin_new_instance(NPMIMEType /*mimetype*/,
obj->testDocumentOpenInDestroyStream = TRUE;
else if (strcasecmp(argn[i], "testwindowopen") == 0)
obj->testWindowOpen = TRUE;
+ else if (strcasecmp(argn[i], "onSetWindow") == 0 && !obj->onSetWindow)
+ obj->onSetWindow = strdup(argv[i]);
}
- instance->pdata = obj;
+
+ browser->getvalue(instance, NPNVprivateModeBool, (void *)&obj->cachedPrivateBrowsingMode);
}
return NPERR_NO_ERROR;
@@ -114,6 +118,9 @@ webkit_test_plugin_destroy_instance(NPP instance, NPSavedData** /*save*/)
if (obj->logDestroy)
pluginLog(instance, "NPP_Destroy");
+ if (obj->onSetWindow)
+ free(obj->onSetWindow);
+
browser->releaseobject(&obj->header);
}
@@ -126,10 +133,14 @@ webkit_test_plugin_set_window(NPP instance, NPWindow *window)
PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
if (obj) {
+ obj->lastWindow = *window;
+
if (obj->logSetWindow) {
pluginLog(instance, "NPP_SetWindow: %d %d", (int)window->width, (int)window->height);
obj->logSetWindow = false;
}
+ if (obj->onSetWindow)
+ executeScript(obj, obj->onSetWindow);
if (obj->testWindowOpen) {
testWindowOpen(instance);
@@ -282,9 +293,17 @@ webkit_test_plugin_get_value(NPP instance, NPPVariable variable, void *value)
}
static NPError
-webkit_test_plugin_set_value(NPP /*instance*/, NPNVariable /*variable*/, void* /*value*/)
+webkit_test_plugin_set_value(NPP instance, NPNVariable variable, void* value)
{
- return NPERR_NO_ERROR;
+ PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
+
+ switch (variable) {
+ case NPNVprivateModeBool:
+ obj->cachedPrivateBrowsingMode = *(NPBool*)value;
+ return NPERR_NO_ERROR;
+ default:
+ return NPERR_GENERIC_ERROR;
+ }
}
char *
diff --git a/WebKitTools/DumpRenderTree/win/AccessibilityControllerWin.cpp b/WebKitTools/DumpRenderTree/win/AccessibilityControllerWin.cpp
index 6b35948..255bfc3 100644
--- a/WebKitTools/DumpRenderTree/win/AccessibilityControllerWin.cpp
+++ b/WebKitTools/DumpRenderTree/win/AccessibilityControllerWin.cpp
@@ -59,6 +59,12 @@ AccessibilityController::~AccessibilityController()
JSValueUnprotect(frame->globalContext(), it->second);
}
+AccessibilityUIElement AccessibilityController::elementAtPoint(int x, int y)
+{
+ // FIXME: implement
+ return 0;
+}
+
AccessibilityUIElement AccessibilityController::focusedElement()
{
COMPtr<IAccessible> rootAccessible = rootElement().platformUIElement();
diff --git a/WebKitTools/DumpRenderTree/win/AccessibilityUIElementWin.cpp b/WebKitTools/DumpRenderTree/win/AccessibilityUIElementWin.cpp
index 301112f..9f00ae4 100644
--- a/WebKitTools/DumpRenderTree/win/AccessibilityUIElementWin.cpp
+++ b/WebKitTools/DumpRenderTree/win/AccessibilityUIElementWin.cpp
@@ -83,6 +83,18 @@ int AccessibilityUIElement::childrenCount()
return childCount;
}
+int AccessibilityUIElement::rowCount()
+{
+ // FIXME: implement
+ return 0;
+}
+
+int AccessibilityUIElement::columnCount()
+{
+ // FIXME: implement
+ return 0;
+}
+
AccessibilityUIElement AccessibilityUIElement::elementAtPoint(int x, int y)
{
return 0;
@@ -224,6 +236,11 @@ JSStringRef AccessibilityUIElement::language()
return JSStringCreateWithCharacters(0, 0);
}
+JSStringRef AccessibilityUIElement::helpText() const
+{
+ return 0;
+}
+
double AccessibilityUIElement::x()
{
long x, y, width, height;
@@ -477,6 +494,11 @@ void AccessibilityUIElement::showMenu()
m_element->accDoDefaultAction(self());
}
+void AccessibilityUIElement::press()
+{
+ // FIXME: implement
+}
+
AccessibilityUIElement AccessibilityUIElement::disclosedRowAtIndex(unsigned index)
{
return 0;
@@ -540,6 +562,11 @@ bool AccessibilityUIElement::addNotificationListener(JSObjectRef functionCallbac
return true;
}
+void AccessibilityUIElement::removeNotificationListener()
+{
+ // FIXME: implement
+}
+
bool AccessibilityUIElement::isSelectable() const
{
DWORD state = accessibilityState(m_element);
diff --git a/WebKitTools/DumpRenderTree/win/DumpRenderTree.cpp b/WebKitTools/DumpRenderTree/win/DumpRenderTree.cpp
index ddfca95..f9b40d1 100644
--- a/WebKitTools/DumpRenderTree/win/DumpRenderTree.cpp
+++ b/WebKitTools/DumpRenderTree/win/DumpRenderTree.cpp
@@ -84,6 +84,7 @@ static bool printSeparators;
static bool leakChecking = false;
static bool threaded = false;
static bool forceComplexText = false;
+static bool printSupportedFeatures = false;
static RetainPtr<CFStringRef> persistentUserStyleSheetLocation;
volatile bool done;
@@ -731,6 +732,11 @@ static bool shouldOpenWebInspector(const char* pathOrURL)
return strstr(pathOrURL, "/inspector/") || strstr(pathOrURL, "\\inspector\\");
}
+static bool shouldEnableDeveloperExtras(const char* pathOrURL)
+{
+ return shouldOpenWebInspector(pathOrURL) || strstr(pathOrURL, "/inspector-enabled/") || strstr(pathOrURL, "\\inspector-enabled\\");
+}
+
static void resetDefaultsToConsistentValues(IWebPreferences* preferences)
{
#ifdef USE_MAC_FONTS
@@ -790,7 +796,7 @@ static void resetDefaultsToConsistentValues(IWebPreferences* preferences)
prefsPrivate->setExperimentalNotificationsEnabled(TRUE);
prefsPrivate->setShouldPaintNativeControls(FALSE); // FIXME - need to make DRT pass with Windows native controls <http://bugs.webkit.org/show_bug.cgi?id=25592>
prefsPrivate->setXSSAuditorEnabled(FALSE);
- prefsPrivate->setFrameSetFlatteningEnabled(FALSE);
+ prefsPrivate->setFrameFlatteningEnabled(FALSE);
prefsPrivate->setOfflineWebApplicationCacheEnabled(TRUE);
}
setAlwaysAcceptCookies(false);
@@ -836,7 +842,7 @@ static void resetWebViewToConsistentStateBeforeTesting()
SetFocus(viewWindow);
webViewPrivate->clearMainFrameName();
- webViewPrivate->resetOriginAccessWhiteLists();
+ webViewPrivate->resetOriginAccessWhitelists();
BSTR groupName;
if (SUCCEEDED(webView->groupName(&groupName))) {
@@ -910,8 +916,11 @@ static void runTest(const string& testPathOrURL)
resetWebViewToConsistentStateBeforeTesting();
- if (shouldOpenWebInspector(pathOrURL.c_str()))
- gLayoutTestController->showWebInspector();
+ if (shouldEnableDeveloperExtras(pathOrURL.c_str())) {
+ gLayoutTestController->setDeveloperExtrasEnabled(true);
+ if (shouldOpenWebInspector(pathOrURL.c_str()))
+ gLayoutTestController->showWebInspector();
+ }
prevTestBFItem = 0;
if (webView) {
@@ -947,7 +956,7 @@ static void runTest(const string& testPathOrURL)
DispatchMessage(&msg);
}
- if (shouldOpenWebInspector(pathOrURL.c_str()))
+ if (shouldEnableDeveloperExtras(pathOrURL.c_str()))
gLayoutTestController->closeWebInspector();
resetWebViewToConsistentStateBeforeTesting();
@@ -1222,6 +1231,11 @@ int main(int argc, char* argv[])
continue;
}
+ if (!stricmp(argv[i], "--print-supported-features")) {
+ printSupportedFeatures = true;
+ continue;
+ }
+
tests.append(argv[i]);
}
@@ -1246,6 +1260,20 @@ int main(int argc, char* argv[])
standardPreferences->setJavaScriptEnabled(TRUE);
standardPreferences->setDefaultFontSize(16);
+ if (printSupportedFeatures) {
+ BOOL acceleratedCompositingAvailable;
+ standardPreferences->acceleratedCompositingEnabled(&acceleratedCompositingAvailable);
+ BOOL threeDRenderingAvailable =
+#if ENABLE(3D_RENDERING)
+ true;
+#else
+ false;
+#endif
+
+ printf("SupportedFeatures:%s %s\n", acceleratedCompositingAvailable ? "AcceleratedCompositing" : "", threeDRenderingAvailable ? "3DRendering" : "");
+ return 0;
+ }
+
COMPtr<IWebView> webView(AdoptCOM, createWebViewAndOffscreenWindow(&webViewWindow));
if (!webView)
return -1;
diff --git a/WebKitTools/DumpRenderTree/win/EventSender.cpp b/WebKitTools/DumpRenderTree/win/EventSender.cpp
index 5a42b00..2a36d8d 100644
--- a/WebKitTools/DumpRenderTree/win/EventSender.cpp
+++ b/WebKitTools/DumpRenderTree/win/EventSender.cpp
@@ -667,20 +667,21 @@ static JSClassRef getClass(JSContextRef context)
return eventSenderClass;
}
-JSObjectRef makeEventSender(JSContextRef context)
+JSObjectRef makeEventSender(JSContextRef context, bool isTopFrame)
{
- down = false;
- dragMode = true;
- replayingSavedEvents = false;
- timeOffset = 0;
- lastMousePosition.x = 0;
- lastMousePosition.y = 0;
-
- endOfQueue = 0;
- startOfQueue = 0;
+ if (isTopFrame) {
+ down = false;
+ dragMode = true;
+ replayingSavedEvents = false;
+ timeOffset = 0;
+ lastMousePosition.x = 0;
+ lastMousePosition.y = 0;
- didDragEnter = false;
- draggingInfo = 0;
+ endOfQueue = 0;
+ startOfQueue = 0;
+ didDragEnter = false;
+ draggingInfo = 0;
+ }
return JSObjectMake(context, getClass(context), 0);
}
diff --git a/WebKitTools/DumpRenderTree/win/EventSender.h b/WebKitTools/DumpRenderTree/win/EventSender.h
index 79d7dab..a0add85 100644
--- a/WebKitTools/DumpRenderTree/win/EventSender.h
+++ b/WebKitTools/DumpRenderTree/win/EventSender.h
@@ -35,7 +35,7 @@ typedef long HRESULT;
typedef const struct OpaqueJSContext* JSContextRef;
typedef struct OpaqueJSValue* JSObjectRef;
-JSObjectRef makeEventSender(JSContextRef context);
+JSObjectRef makeEventSender(JSContextRef context, bool isTopFrame);
void replaySavedEvents(HRESULT* oleDragAndDropReturnValue = 0);
extern DraggingInfo* draggingInfo;
diff --git a/WebKitTools/DumpRenderTree/win/FrameLoadDelegate.cpp b/WebKitTools/DumpRenderTree/win/FrameLoadDelegate.cpp
index 37d5e1c..29f99ab 100644
--- a/WebKitTools/DumpRenderTree/win/FrameLoadDelegate.cpp
+++ b/WebKitTools/DumpRenderTree/win/FrameLoadDelegate.cpp
@@ -336,6 +336,9 @@ void FrameLoadDelegate::didClearWindowObjectForFrameInStandardWorld(IWebFrame* f
JSGlobalContextRef context = frame->globalContext();
JSObjectRef windowObject = JSContextGetGlobalObject(context);
+ IWebFrame* parentFrame = 0;
+ frame->parentFrame(&parentFrame);
+
JSValueRef exception = 0;
::gLayoutTestController->makeWindowObject(context, windowObject, &exception);
@@ -348,7 +351,7 @@ void FrameLoadDelegate::didClearWindowObjectForFrameInStandardWorld(IWebFrame* f
ASSERT(!exception);
JSStringRef eventSenderStr = JSStringCreateWithUTF8CString("eventSender");
- JSValueRef eventSender = makeEventSender(context);
+ JSValueRef eventSender = makeEventSender(context, !parentFrame);
JSObjectSetProperty(context, windowObject, eventSenderStr, eventSender, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, 0);
JSStringRelease(eventSenderStr);
}
diff --git a/WebKitTools/DumpRenderTree/win/LayoutTestControllerWin.cpp b/WebKitTools/DumpRenderTree/win/LayoutTestControllerWin.cpp
index 9f84488..24ddc3b 100644
--- a/WebKitTools/DumpRenderTree/win/LayoutTestControllerWin.cpp
+++ b/WebKitTools/DumpRenderTree/win/LayoutTestControllerWin.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -110,6 +110,21 @@ void LayoutTestController::clearBackForwardList()
backForwardList->goToItem(item.get());
}
+bool LayoutTestController::callShouldCloseOnWebView()
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return false;
+
+ COMPtr<IWebViewPrivate> viewPrivate;
+ if (FAILED(webView->QueryInterface(&viewPrivate)))
+ return false;
+
+ BOOL result;
+ viewPrivate->shouldClose(&result);
+ return result;
+}
+
JSStringRef LayoutTestController::copyDecodedHostName(JSStringRef name)
{
// FIXME: Implement!
@@ -158,6 +173,33 @@ void LayoutTestController::keepWebHistory()
history->setOptionalSharedHistory(sharedHistory.get());
}
+JSValueRef LayoutTestController::computedStyleIncludingVisitedInfo(JSContextRef context, JSValueRef value)
+{
+ // FIXME: Implement this.
+ return JSValueMakeUndefined(context);
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::layerTreeAsText() const
+{
+ COMPtr<IWebFramePrivate> framePrivate(Query, frame);
+ if (!framePrivate)
+ return false;
+
+ BSTR textBSTR = 0;
+ HRESULT hr = framePrivate->layerTreeAsText(&textBSTR);
+
+ wstring text(textBSTR, SysStringLen(textBSTR));
+ SysFreeString(textBSTR);
+ JSRetainPtr<JSStringRef> textValueJS(Adopt, JSStringCreateWithCharacters(text.data(), text.length()));
+ return textValueJS;
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::markerTextForListItem(JSContextRef context, JSValueRef nodeObject) const
+{
+ // FIXME: Implement me.
+ return JSRetainPtr<JSStringRef>();
+}
+
void LayoutTestController::waitForPolicyDelegate()
{
// FIXME: Implement this.
@@ -372,7 +414,7 @@ void LayoutTestController::setXSSAuditorEnabled(bool enabled)
prefsPrivate->setXSSAuditorEnabled(enabled);
}
-void LayoutTestController::setFrameSetFlatteningEnabled(bool enabled)
+void LayoutTestController::setFrameFlatteningEnabled(bool enabled)
{
COMPtr<IWebView> webView;
if (FAILED(frame->webView(&webView)))
@@ -386,7 +428,12 @@ void LayoutTestController::setFrameSetFlatteningEnabled(bool enabled)
if (!prefsPrivate)
return;
- prefsPrivate->setFrameSetFlatteningEnabled(enabled);
+ prefsPrivate->setFrameFlatteningEnabled(enabled);
+}
+
+void LayoutTestController::setSpatialNavigationEnabled(bool enabled)
+{
+ // FIXME: Implement for SpatialNavigation layout tests.
}
void LayoutTestController::setAllowUniversalAccessFromFileURLs(bool enabled)
@@ -688,19 +735,11 @@ void LayoutTestController::setJavaScriptProfilingEnabled(bool flag)
if (FAILED(webView->QueryInterface(&viewPrivate)))
return;
- COMPtr<IWebPreferences> preferences;
- if (FAILED(webView->preferences(&preferences)))
- return;
-
- COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
- if (!prefsPrivate)
- return;
-
COMPtr<IWebInspector> inspector;
if (FAILED(viewPrivate->inspector(&inspector)))
return;
- prefsPrivate->setDeveloperExtrasEnabled(flag);
+ setDeveloperExtrasEnabled(flag);
inspector->setJavaScriptProfilingEnabled(flag);
}
@@ -717,7 +756,7 @@ void LayoutTestController::setSelectTrailingWhitespaceEnabled(bool flag)
viewEditing->setSelectTrailingWhitespaceEnabled(flag ? TRUE : FALSE);
}
-static const CFTimeInterval waitToDumpWatchdogInterval = 15.0;
+static const CFTimeInterval waitToDumpWatchdogInterval = 30.0;
static void CALLBACK waitUntilDoneWatchdogFired(HWND, UINT, UINT_PTR, DWORD)
{
@@ -950,13 +989,27 @@ static _bstr_t bstrT(JSStringRef jsString)
return _bstr_t(JSStringCopyBSTR(jsString), false);
}
-void LayoutTestController::whiteListAccessFromOrigin(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains)
+void LayoutTestController::addOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains)
{
COMPtr<IWebViewPrivate> webView;
if (FAILED(WebKitCreateInstance(__uuidof(WebView), 0, __uuidof(webView), reinterpret_cast<void**>(&webView))))
return;
- webView->whiteListAccessFromOrigin(bstrT(sourceOrigin).GetBSTR(), bstrT(destinationProtocol).GetBSTR(), bstrT(destinationHost).GetBSTR(), allowDestinationSubdomains);
+ webView->addOriginAccessWhitelistEntry(bstrT(sourceOrigin).GetBSTR(), bstrT(destinationProtocol).GetBSTR(), bstrT(destinationHost).GetBSTR(), allowDestinationSubdomains);
+}
+
+void LayoutTestController::removeOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains)
+{
+ COMPtr<IWebViewPrivate> webView;
+ if (FAILED(WebKitCreateInstance(__uuidof(WebView), 0, __uuidof(webView), reinterpret_cast<void**>(&webView))))
+ return;
+
+ webView->removeOriginAccessWhitelistEntry(bstrT(sourceOrigin).GetBSTR(), bstrT(destinationProtocol).GetBSTR(), bstrT(destinationHost).GetBSTR(), allowDestinationSubdomains);
+}
+
+void LayoutTestController::setScrollbarPolicy(JSStringRef orientation, JSStringRef policy)
+{
+ // FIXME: implement
}
void LayoutTestController::addUserScript(JSStringRef source, bool runAtStart)
@@ -986,7 +1039,7 @@ void LayoutTestController::addUserStyleSheet(JSStringRef source)
webView->addUserStyleSheetToGroup(_bstr_t(L"org.webkit.DumpRenderTree").GetBSTR(), world.get(), bstrT(source).GetBSTR(), 0, 0, 0, 0, 0);
}
-void LayoutTestController::showWebInspector()
+void LayoutTestController::setDeveloperExtrasEnabled(bool enabled)
{
COMPtr<IWebView> webView;
if (FAILED(frame->webView(&webView)))
@@ -1000,7 +1053,14 @@ void LayoutTestController::showWebInspector()
if (!prefsPrivate)
return;
- prefsPrivate->setDeveloperExtrasEnabled(true);
+ prefsPrivate->setDeveloperExtrasEnabled(enabled);
+}
+
+void LayoutTestController::showWebInspector()
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return;
COMPtr<IWebViewPrivate> viewPrivate(Query, webView);
if (!viewPrivate)
@@ -1026,16 +1086,6 @@ void LayoutTestController::closeWebInspector()
return;
inspector->close();
-
- COMPtr<IWebPreferences> preferences;
- if (FAILED(webView->preferences(&preferences)))
- return;
-
- COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
- if (!prefsPrivate)
- return;
-
- prefsPrivate->setDeveloperExtrasEnabled(false);
}
void LayoutTestController::evaluateInWebInspector(long callId, JSStringRef script)
@@ -1169,3 +1219,29 @@ void LayoutTestController::apiTestNewWindowDataLoadBaseURL(JSStringRef utf8Data,
{
}
+
+void LayoutTestController::apiTestGoToCurrentBackForwardItem()
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return;
+
+ COMPtr<IWebBackForwardList> backForwardList;
+ if (FAILED(webView->backForwardList(&backForwardList)))
+ return;
+
+ COMPtr<IWebHistoryItem> item;
+ if (FAILED(backForwardList->currentItem(&item)))
+ return;
+
+ BOOL success;
+ webView->goToBackForwardItem(item.get(), &success);
+}
+
+void LayoutTestController::setWebViewEditable(bool)
+{
+}
+
+void LayoutTestController::authenticateSession(JSStringRef, JSStringRef, JSStringRef)
+{
+}
diff --git a/WebKitTools/DumpRenderTree/win/ResourceLoadDelegate.cpp b/WebKitTools/DumpRenderTree/win/ResourceLoadDelegate.cpp
index 19bf84a..2e031da 100644
--- a/WebKitTools/DumpRenderTree/win/ResourceLoadDelegate.cpp
+++ b/WebKitTools/DumpRenderTree/win/ResourceLoadDelegate.cpp
@@ -31,28 +31,35 @@
#include "DumpRenderTree.h"
#include "LayoutTestController.h"
-#include <comutil.h>
#include <WebKit/WebKitCOMAPI.h>
+#include <comutil.h>
+#include <sstream>
+#include <tchar.h>
#include <wtf/HashMap.h>
#include <wtf/Vector.h>
-#include <sstream>
-
-using std::wstring;
-using std::wiostream;
+using namespace std;
static inline wstring wstringFromBSTR(BSTR str)
{
return wstring(str, ::SysStringLen(str));
}
-wstring wstringFromInt(int i)
+static inline wstring wstringFromInt(int i)
{
- std::wostringstream ss;
+ wostringstream ss;
ss << i;
return ss.str();
}
+static inline BSTR BSTRFromString(const string& str)
+{
+ int length = ::MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), 0, 0);
+ BSTR result = ::SysAllocStringLen(0, length);
+ ::MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), result, length);
+ return result;
+}
+
typedef HashMap<unsigned long, wstring> IdentifierMap;
IdentifierMap& urlMap()
@@ -254,8 +261,16 @@ HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::willSendRequest(
return S_OK;
}
- request->AddRef();
- *newRequest = request;
+ IWebMutableURLRequest* requestCopy = 0;
+ request->mutableCopy(&requestCopy);
+ const set<string>& clearHeaders = gLayoutTestController->willSendRequestClearHeaders();
+ for (set<string>::const_iterator header = clearHeaders.begin(); header != clearHeaders.end(); ++header) {
+ BSTR bstrHeader = BSTRFromString(*header);
+ requestCopy->setValue(0, bstrHeader);
+ SysFreeString(bstrHeader);
+ }
+
+ *newRequest = requestCopy;
return S_OK;
}
diff --git a/WebKitTools/DumpRenderTree/win/TestNetscapePlugin/main.cpp b/WebKitTools/DumpRenderTree/win/TestNetscapePlugin/main.cpp
index 08a2f6a..eeacb7e 100644
--- a/WebKitTools/DumpRenderTree/win/TestNetscapePlugin/main.cpp
+++ b/WebKitTools/DumpRenderTree/win/TestNetscapePlugin/main.cpp
@@ -6,7 +6,7 @@
redistribute this Apple software.
In consideration of your agreement to abide by the following terms, and subject to these
- terms, Apple grants you a personal, non-exclusive license, under AppleÕs copyrights in
+ terms, Apple grants you a personal, non-exclusive license, under Apple's copyrights in
this original Apple software (the "Apple Software"), to use, reproduce, modify and
redistribute the Apple Software, with or without modifications, in source and/or binary
forms; provided that if you redistribute the Apple Software in its entirety and without
@@ -89,7 +89,8 @@ NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, ch
{
if (browser->version >= 14) {
PluginObject* obj = (PluginObject*)browser->createobject(instance, getPluginClass());
-
+ instance->pdata = obj;
+
for (int16 i = 0; i < argc; i++) {
if (_stricmp(argn[i], "onstreamload") == 0 && !obj->onStreamLoad)
obj->onStreamLoad = _strdup(argv[i]);
@@ -107,9 +108,11 @@ NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, ch
obj->testDocumentOpenInDestroyStream = TRUE;
else if (_stricmp(argn[i], "testwindowopen") == 0)
obj->testWindowOpen = TRUE;
+ else if (_stricmp(argn[i], "onSetWindow") == 0 && !obj->onSetWindow)
+ obj->onSetWindow = strdup(argv[i]);
}
-
- instance->pdata = obj;
+
+ browser->getvalue(instance, NPNVprivateModeBool, (void *)&obj->cachedPrivateBrowsingMode);
}
return NPERR_NO_ERROR;
@@ -136,6 +139,9 @@ NPError NPP_Destroy(NPP instance, NPSavedData **save)
if (obj->logDestroy)
printf("PLUGIN: NPP_Destroy\n");
+ if (obj->onSetWindow)
+ free(obj->onSetWindow);
+
browser->releaseobject(&obj->header);
}
return NPERR_NO_ERROR;
@@ -146,6 +152,11 @@ NPError NPP_SetWindow(NPP instance, NPWindow *window)
PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
if (obj) {
+ obj->lastWindow = *window;
+
+ if (obj->onSetWindow)
+ executeScript(obj, obj->onSetWindow);
+
if (obj->testWindowOpen) {
testWindowOpen(instance);
obj->testWindowOpen = FALSE;
@@ -238,5 +249,13 @@ NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value)
NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value)
{
- return NPERR_GENERIC_ERROR;
+ PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
+
+ switch (variable) {
+ case NPNVprivateModeBool:
+ obj->cachedPrivateBrowsingMode = *(NPBool*)value;
+ return NPERR_NO_ERROR;
+ default:
+ return NPERR_GENERIC_ERROR;
+ }
}
diff --git a/WebKitTools/DumpRenderTree/wx/LayoutTestControllerWx.cpp b/WebKitTools/DumpRenderTree/wx/LayoutTestControllerWx.cpp
index ce1bda5..873e8d8 100644
--- a/WebKitTools/DumpRenderTree/wx/LayoutTestControllerWx.cpp
+++ b/WebKitTools/DumpRenderTree/wx/LayoutTestControllerWx.cpp
@@ -35,6 +35,8 @@
#include <JavaScriptCore/JSRetainPtr.h>
#include <JavaScriptCore/JSStringRef.h>
+#include <stdio.h>
+
LayoutTestController::~LayoutTestController()
@@ -170,7 +172,7 @@ void LayoutTestController::setXSSAuditorEnabled(bool enabled)
// FIXME: implement
}
-void LayoutTestController::setFrameSetFlatteningEnabled(bool enabled)
+void LayoutTestController::setFrameFlatteningEnabled(bool enabled)
{
// FIXME: implement
}
@@ -360,9 +362,19 @@ void LayoutTestController::disableImageLoading()
}
-void LayoutTestController::whiteListAccessFromOrigin(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains)
+void LayoutTestController::addOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains)
{
+ // FIXME: implement
+}
+void LayoutTestController::removeOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::setScrollbarPolicy(JSStringRef orientation, JSStringRef policy)
+{
+ // FIXME: implement
}
JSRetainPtr<JSStringRef> LayoutTestController::counterValueForElementById(JSStringRef id)
@@ -386,3 +398,36 @@ void LayoutTestController::apiTestNewWindowDataLoadBaseURL(JSStringRef utf8Data,
{
}
+
+void LayoutTestController::apiTestGoToCurrentBackForwardItem()
+{
+
+}
+
+void LayoutTestController::setSpatialNavigationEnabled(bool)
+{
+
+}
+
+void LayoutTestController::setWebViewEditable(bool)
+{
+}
+
+bool LayoutTestController::callShouldCloseOnWebView()
+{
+ return false;
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::layerTreeAsText() const
+{
+ return 0;
+}
+
+JSValueRef LayoutTestController::computedStyleIncludingVisitedInfo(JSContextRef, JSValueRef)
+{
+ return 0;
+}
+
+void LayoutTestController::authenticateSession(JSStringRef, JSStringRef, JSStringRef)
+{
+}