summaryrefslogtreecommitdiffstats
path: root/Tools/DumpRenderTree/chromium
diff options
context:
space:
mode:
Diffstat (limited to 'Tools/DumpRenderTree/chromium')
-rw-r--r--Tools/DumpRenderTree/chromium/AccessibilityController.cpp124
-rw-r--r--Tools/DumpRenderTree/chromium/AccessibilityController.h84
-rw-r--r--Tools/DumpRenderTree/chromium/AccessibilityUIElement.cpp585
-rw-r--r--Tools/DumpRenderTree/chromium/AccessibilityUIElement.h142
-rw-r--r--Tools/DumpRenderTree/chromium/CppBoundClass.cpp350
-rw-r--r--Tools/DumpRenderTree/chromium/CppBoundClass.h241
-rw-r--r--Tools/DumpRenderTree/chromium/CppVariant.cpp310
-rw-r--r--Tools/DumpRenderTree/chromium/CppVariant.h133
-rw-r--r--Tools/DumpRenderTree/chromium/DRTDevToolsAgent.cpp161
-rw-r--r--Tools/DumpRenderTree/chromium/DRTDevToolsAgent.h105
-rw-r--r--Tools/DumpRenderTree/chromium/DRTDevToolsCallArgs.cpp36
-rw-r--r--Tools/DumpRenderTree/chromium/DRTDevToolsCallArgs.h65
-rw-r--r--Tools/DumpRenderTree/chromium/DRTDevToolsClient.cpp124
-rw-r--r--Tools/DumpRenderTree/chromium/DRTDevToolsClient.h90
-rw-r--r--Tools/DumpRenderTree/chromium/DumpRenderTree.cpp214
-rw-r--r--Tools/DumpRenderTree/chromium/EventSender.cpp1008
-rw-r--r--Tools/DumpRenderTree/chromium/EventSender.h163
-rw-r--r--Tools/DumpRenderTree/chromium/ImageDiff.cpp408
-rw-r--r--Tools/DumpRenderTree/chromium/LayoutTestController.cpp1590
-rw-r--r--Tools/DumpRenderTree/chromium/LayoutTestController.h551
-rw-r--r--Tools/DumpRenderTree/chromium/LayoutTestHelper.mm118
-rw-r--r--Tools/DumpRenderTree/chromium/LayoutTestHelperWin.cpp84
-rw-r--r--Tools/DumpRenderTree/chromium/MockSpellCheck.cpp156
-rw-r--r--Tools/DumpRenderTree/chromium/MockSpellCheck.h83
-rw-r--r--Tools/DumpRenderTree/chromium/NotificationPresenter.cpp148
-rw-r--r--Tools/DumpRenderTree/chromium/NotificationPresenter.h77
-rw-r--r--Tools/DumpRenderTree/chromium/PlainTextController.cpp79
-rw-r--r--Tools/DumpRenderTree/chromium/PlainTextController.h52
-rw-r--r--Tools/DumpRenderTree/chromium/Task.cpp75
-rw-r--r--Tools/DumpRenderTree/chromium/Task.h88
-rw-r--r--Tools/DumpRenderTree/chromium/TestEventPrinter.cpp168
-rw-r--r--Tools/DumpRenderTree/chromium/TestEventPrinter.h43
-rw-r--r--Tools/DumpRenderTree/chromium/TestNavigationController.cpp277
-rw-r--r--Tools/DumpRenderTree/chromium/TestNavigationController.h211
-rw-r--r--Tools/DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npapi.h9
-rw-r--r--Tools/DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npfunctions.h8
-rw-r--r--Tools/DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npruntime.h1
-rw-r--r--Tools/DumpRenderTree/chromium/TestNetscapePlugIn/Info.plist60
-rw-r--r--Tools/DumpRenderTree/chromium/TestShell.cpp621
-rw-r--r--Tools/DumpRenderTree/chromium/TestShell.h221
-rw-r--r--Tools/DumpRenderTree/chromium/TestShellGtk.cpp211
-rw-r--r--Tools/DumpRenderTree/chromium/TestShellMac.mm145
-rw-r--r--Tools/DumpRenderTree/chromium/TestShellWin.cpp244
-rw-r--r--Tools/DumpRenderTree/chromium/TestWebWorker.h93
-rw-r--r--Tools/DumpRenderTree/chromium/TextInputController.cpp262
-rw-r--r--Tools/DumpRenderTree/chromium/TextInputController.h74
-rw-r--r--Tools/DumpRenderTree/chromium/WebPreferences.cpp166
-rw-r--r--Tools/DumpRenderTree/chromium/WebPreferences.h88
-rwxr-xr-xTools/DumpRenderTree/chromium/WebThemeControlDRTWin.cpp523
-rw-r--r--Tools/DumpRenderTree/chromium/WebThemeControlDRTWin.h203
-rwxr-xr-xTools/DumpRenderTree/chromium/WebThemeEngineDRTWin.cpp758
-rw-r--r--Tools/DumpRenderTree/chromium/WebThemeEngineDRTWin.h97
-rw-r--r--Tools/DumpRenderTree/chromium/WebViewHost.cpp1519
-rw-r--r--Tools/DumpRenderTree/chromium/WebViewHost.h332
-rw-r--r--Tools/DumpRenderTree/chromium/config.h56
-rw-r--r--Tools/DumpRenderTree/chromium/fonts.conf155
56 files changed, 13989 insertions, 0 deletions
diff --git a/Tools/DumpRenderTree/chromium/AccessibilityController.cpp b/Tools/DumpRenderTree/chromium/AccessibilityController.cpp
new file mode 100644
index 0000000..5601d9d
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/AccessibilityController.cpp
@@ -0,0 +1,124 @@
+/*
+ * 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 "WebAccessibilityCache.h"
+#include "WebAccessibilityObject.h"
+#include "WebFrame.h"
+#include "WebString.h"
+#include "WebView.h"
+
+using namespace WebKit;
+
+AccessibilityController::AccessibilityController(TestShell* shell)
+ : m_shell(shell)
+{
+
+ bindMethod("dumpAccessibilityNotifications", &AccessibilityController::dumpAccessibilityNotifications);
+ 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();
+
+ m_dumpAccessibilityNotifications = false;
+}
+
+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::dumpAccessibilityNotifications(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpAccessibilityNotifications = true;
+ result->setNull();
+}
+
+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/Tools/DumpRenderTree/chromium/AccessibilityController.h b/Tools/DumpRenderTree/chromium/AccessibilityController.h
new file mode 100644
index 0000000..0817ec3
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/AccessibilityController.h
@@ -0,0 +1,84 @@
+/*
+ * 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();
+
+ // This function sets a flag that tells the test_shell to dump all
+ // accessibility notifications.
+ void dumpAccessibilityNotifications(const CppArgumentList&, CppVariant*);
+
+public:
+ // The following methods are not exposed to JavaScript.
+ bool shouldDumpAccessibilityNotifications() { return m_dumpAccessibilityNotifications; }
+
+private:
+ // If true, the test_shell will dump all accessibility notifications.
+ bool m_dumpAccessibilityNotifications;
+
+ // 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/Tools/DumpRenderTree/chromium/AccessibilityUIElement.cpp b/Tools/DumpRenderTree/chromium/AccessibilityUIElement.cpp
new file mode 100644
index 0000000..dbd025a
--- /dev/null
+++ b/Tools/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 "WebAccessibilityObject.h"
+#include "WebCString.h"
+#include "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/Tools/DumpRenderTree/chromium/AccessibilityUIElement.h b/Tools/DumpRenderTree/chromium/AccessibilityUIElement.h
new file mode 100644
index 0000000..366ed42
--- /dev/null
+++ b/Tools/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 "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/Tools/DumpRenderTree/chromium/CppBoundClass.cpp b/Tools/DumpRenderTree/chromium/CppBoundClass.cpp
new file mode 100644
index 0000000..1348bbf
--- /dev/null
+++ b/Tools/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 "WebBindings.h"
+#include "WebFrame.h"
+#include "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/Tools/DumpRenderTree/chromium/CppBoundClass.h b/Tools/DumpRenderTree/chromium/CppBoundClass.h
new file mode 100644
index 0000000..6cb638e
--- /dev/null
+++ b/Tools/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/Tools/DumpRenderTree/chromium/CppVariant.cpp b/Tools/DumpRenderTree/chromium/CppVariant.cpp
new file mode 100644
index 0000000..22e0013
--- /dev/null
+++ b/Tools/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 "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/Tools/DumpRenderTree/chromium/CppVariant.h b/Tools/DumpRenderTree/chromium/CppVariant.h
new file mode 100644
index 0000000..3032310
--- /dev/null
+++ b/Tools/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 "WebBindings.h"
+#include "webkit/support/webkit_support.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/Tools/DumpRenderTree/chromium/DRTDevToolsAgent.cpp b/Tools/DumpRenderTree/chromium/DRTDevToolsAgent.cpp
new file mode 100644
index 0000000..78c86e7
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/DRTDevToolsAgent.cpp
@@ -0,0 +1,161 @@
+/*
+ * 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 "DRTDevToolsAgent.h"
+
+#include "DRTDevToolsCallArgs.h"
+#include "DRTDevToolsClient.h"
+
+#include "WebCString.h"
+#include "WebDevToolsAgent.h"
+#include "WebString.h"
+#include "WebView.h"
+#include "webkit/support/webkit_support.h"
+
+using namespace WebKit;
+
+DRTDevToolsAgent::DRTDevToolsAgent()
+ : m_drtDevToolsClient(0)
+ , m_webView(0)
+{
+ static int devToolsAgentCounter = 0;
+
+ m_routingID = ++devToolsAgentCounter;
+ if (m_routingID == 1)
+ WebDevToolsAgent::setMessageLoopDispatchHandler(&DRTDevToolsAgent::dispatchMessageLoop);
+}
+
+void DRTDevToolsAgent::reset()
+{
+ m_taskList.revokeAll();
+}
+
+void DRTDevToolsAgent::setWebView(WebView* webView)
+{
+ m_webView = webView;
+}
+
+void DRTDevToolsAgent::sendMessageToInspectorFrontend(const WebKit::WebString& data)
+{
+ if (m_drtDevToolsClient)
+ m_drtDevToolsClient->asyncCall(DRTDevToolsCallArgs(data));
+}
+
+void DRTDevToolsAgent::runtimePropertyChanged(const WebKit::WebString& name, const WebKit::WebString& value)
+{
+ // FIXME: Implement.
+}
+
+WebCString DRTDevToolsAgent::debuggerScriptSource()
+{
+ return webkit_support::GetDevToolsDebuggerScriptSource();
+}
+
+WebDevToolsAgentClient::WebKitClientMessageLoop* DRTDevToolsAgent::createClientMessageLoop()
+{
+ return webkit_support::CreateDevToolsMessageLoop();
+}
+
+void DRTDevToolsAgent::asyncCall(const DRTDevToolsCallArgs& args)
+{
+ postTask(new AsyncCallTask(this, args));
+}
+
+void DRTDevToolsAgent::call(const DRTDevToolsCallArgs &args)
+{
+ WebDevToolsAgent* agent = webDevToolsAgent();
+ if (agent)
+ agent->dispatchOnInspectorBackend(args.m_data);
+ if (DRTDevToolsCallArgs::callsCount() == 1 && m_drtDevToolsClient)
+ m_drtDevToolsClient->allMessagesProcessed();
+}
+
+void DRTDevToolsAgent::delayedFrontendLoaded()
+{
+ WebDevToolsAgent* agent = webDevToolsAgent();
+ if (agent)
+ agent->frontendLoaded();
+}
+
+
+WebDevToolsAgent* DRTDevToolsAgent::webDevToolsAgent()
+{
+ if (!m_webView)
+ return 0;
+ return m_webView->devToolsAgent();
+}
+
+void DRTDevToolsAgent::attach(DRTDevToolsClient* client)
+{
+ ASSERT(!m_drtDevToolsClient);
+ m_drtDevToolsClient = client;
+ WebDevToolsAgent* agent = webDevToolsAgent();
+ if (agent)
+ agent->attach();
+}
+
+void DRTDevToolsAgent::detach()
+{
+ ASSERT(m_drtDevToolsClient);
+ WebDevToolsAgent* agent = webDevToolsAgent();
+ if (agent)
+ agent->detach();
+ m_drtDevToolsClient = 0;
+}
+
+void DRTDevToolsAgent::frontendLoaded()
+{
+ postTask(new DelayedFrontendLoadedTask(this));
+}
+
+bool DRTDevToolsAgent::setTimelineProfilingEnabled(bool enabled)
+{
+ WebDevToolsAgent* agent = webDevToolsAgent();
+ if (!agent)
+ return false;
+ agent->setTimelineProfilingEnabled(enabled);
+ return true;
+}
+
+bool DRTDevToolsAgent::evaluateInWebInspector(long callID, const std::string& script)
+{
+ WebDevToolsAgent* agent = webDevToolsAgent();
+ if (!agent)
+ return false;
+ agent->evaluateInWebInspector(callID, WebString::fromUTF8(script));
+ return true;
+}
+
+// static method
+void DRTDevToolsAgent::dispatchMessageLoop()
+{
+ webkit_support::DispatchMessageLoop();
+}
diff --git a/Tools/DumpRenderTree/chromium/DRTDevToolsAgent.h b/Tools/DumpRenderTree/chromium/DRTDevToolsAgent.h
new file mode 100644
index 0000000..e1478d0
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/DRTDevToolsAgent.h
@@ -0,0 +1,105 @@
+/*
+ * 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 DRTDevToolsAgent_h
+#define DRTDevToolsAgent_h
+
+#include "DRTDevToolsCallArgs.h"
+#include "Task.h"
+#include "WebDevToolsAgentClient.h"
+#include <wtf/HashMap.h>
+#include <wtf/Noncopyable.h>
+
+namespace WebKit {
+
+class WebCString;
+class WebDevToolsAgent;
+class WebString;
+class WebView;
+struct WebDevToolsMessageData;
+
+} // namespace WebKit
+
+class DRTDevToolsClient;
+
+class DRTDevToolsAgent : public WebKit::WebDevToolsAgentClient
+ , public Noncopyable {
+public:
+ DRTDevToolsAgent();
+ virtual ~DRTDevToolsAgent() {}
+ void reset();
+
+ void setWebView(WebKit::WebView*);
+
+ // WebDevToolsAgentClient implementation.
+ virtual void sendMessageToInspectorFrontend(const WebKit::WebString&);
+ virtual int hostIdentifier() { return m_routingID; }
+ virtual void runtimePropertyChanged(const WebKit::WebString& name, const WebKit::WebString& value);
+ virtual WebKit::WebCString debuggerScriptSource();
+ virtual WebKitClientMessageLoop* createClientMessageLoop();
+
+ void asyncCall(const DRTDevToolsCallArgs&);
+
+ void attach(DRTDevToolsClient*);
+ void detach();
+ void frontendLoaded();
+
+ bool evaluateInWebInspector(long callID, const std::string& script);
+ bool setTimelineProfilingEnabled(bool enable);
+ TaskList* taskList() { return &m_taskList; }
+
+private:
+ void call(const DRTDevToolsCallArgs&);
+ void delayedFrontendLoaded();
+ static void dispatchMessageLoop();
+ WebKit::WebDevToolsAgent* webDevToolsAgent();
+
+ class AsyncCallTask: public MethodTask<DRTDevToolsAgent> {
+ public:
+ AsyncCallTask(DRTDevToolsAgent* object, const DRTDevToolsCallArgs& args)
+ : MethodTask<DRTDevToolsAgent>(object), m_args(args) {}
+ virtual void runIfValid() { m_object->call(m_args); }
+ private:
+ DRTDevToolsCallArgs m_args;
+ };
+
+ struct DelayedFrontendLoadedTask: public MethodTask<DRTDevToolsAgent> {
+ DelayedFrontendLoadedTask(DRTDevToolsAgent* object) : MethodTask<DRTDevToolsAgent>(object) {}
+ virtual void runIfValid() { m_object->delayedFrontendLoaded(); }
+ };
+
+ TaskList m_taskList;
+ DRTDevToolsClient* m_drtDevToolsClient;
+ int m_routingID;
+ WebKit::WebDevToolsAgent* m_webDevToolsAgent;
+ WebKit::WebView* m_webView;
+};
+
+#endif // DRTDevToolsAgent_h
diff --git a/Tools/DumpRenderTree/chromium/DRTDevToolsCallArgs.cpp b/Tools/DumpRenderTree/chromium/DRTDevToolsCallArgs.cpp
new file mode 100644
index 0000000..dacd6f7
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/DRTDevToolsCallArgs.cpp
@@ -0,0 +1,36 @@
+/*
+ * 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 "DRTDevToolsCallArgs.h"
+
+// static
+int DRTDevToolsCallArgs::m_callsCount = 0;
+
diff --git a/Tools/DumpRenderTree/chromium/DRTDevToolsCallArgs.h b/Tools/DumpRenderTree/chromium/DRTDevToolsCallArgs.h
new file mode 100644
index 0000000..a548159
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/DRTDevToolsCallArgs.h
@@ -0,0 +1,65 @@
+/*
+ * 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 DRTDevToolsCallArgs_h
+#define DRTDevToolsCallArgs_h
+
+#include "WebString.h"
+#include <wtf/Assertions.h>
+
+class DRTDevToolsCallArgs {
+public:
+ DRTDevToolsCallArgs(const WebKit::WebString& data)
+ : m_data(data)
+ {
+ ++m_callsCount;
+ }
+
+ DRTDevToolsCallArgs(const DRTDevToolsCallArgs& args)
+ : m_data(args.m_data)
+ {
+ ++m_callsCount;
+ }
+
+ ~DRTDevToolsCallArgs()
+ {
+ --m_callsCount;
+ ASSERT(m_callsCount >= 0);
+ }
+
+ static int callsCount() { return m_callsCount; }
+
+ WebKit::WebString m_data;
+
+private:
+ static int m_callsCount;
+};
+
+#endif // DRTDevToolsCallArgs_h
diff --git a/Tools/DumpRenderTree/chromium/DRTDevToolsClient.cpp b/Tools/DumpRenderTree/chromium/DRTDevToolsClient.cpp
new file mode 100644
index 0000000..acccf18
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/DRTDevToolsClient.cpp
@@ -0,0 +1,124 @@
+/*
+ * 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 "DRTDevToolsClient.h"
+
+#include "DRTDevToolsAgent.h"
+#include "DRTDevToolsCallArgs.h"
+
+#include "WebDevToolsAgent.h"
+#include "WebDevToolsFrontend.h"
+#include "WebFrame.h"
+#include "WebScriptSource.h"
+#include "WebString.h"
+#include "WebView.h"
+#include "webkit/support/webkit_support.h"
+
+using namespace WebKit;
+
+DRTDevToolsClient::DRTDevToolsClient(DRTDevToolsAgent* agent, WebView* webView)
+ : m_webView(webView)
+ , m_drtDevToolsAgent(agent)
+{
+ m_webDevToolsFrontend.set(WebDevToolsFrontend::create(m_webView,
+ this,
+ WebString::fromUTF8("en-US")));
+ m_drtDevToolsAgent->attach(this);
+}
+
+DRTDevToolsClient::~DRTDevToolsClient()
+{
+ // There is a chance that the page will be destroyed at detach step of
+ // m_drtDevToolsAgent and we should clean pending requests a bit earlier.
+ m_taskList.revokeAll();
+ if (m_drtDevToolsAgent)
+ m_drtDevToolsAgent->detach();
+}
+
+void DRTDevToolsClient::reset()
+{
+ m_taskList.revokeAll();
+}
+
+void DRTDevToolsClient::sendFrontendLoaded() {
+ if (m_drtDevToolsAgent)
+ m_drtDevToolsAgent->frontendLoaded();
+}
+
+void DRTDevToolsClient::sendMessageToBackend(const WebString& data)
+{
+ if (m_drtDevToolsAgent)
+ m_drtDevToolsAgent->asyncCall(DRTDevToolsCallArgs(data));
+}
+
+void DRTDevToolsClient::sendDebuggerCommandToAgent(const WebString& command)
+{
+ WebDevToolsAgent::executeDebuggerCommand(command, 1);
+}
+
+void DRTDevToolsClient::activateWindow()
+{
+ // Not implemented.
+}
+
+void DRTDevToolsClient::closeWindow()
+{
+ // Not implemented.
+}
+
+void DRTDevToolsClient::dockWindow()
+{
+ // Not implemented.
+}
+
+void DRTDevToolsClient::undockWindow()
+{
+ // Not implemented.
+}
+
+void DRTDevToolsClient::asyncCall(const DRTDevToolsCallArgs& args)
+{
+ postTask(new AsyncCallTask(this, args));
+}
+
+void DRTDevToolsClient::call(const DRTDevToolsCallArgs& args)
+{
+ m_webDevToolsFrontend->dispatchOnInspectorFrontend(args.m_data);
+ if (DRTDevToolsCallArgs::callsCount() == 1)
+ allMessagesProcessed();
+}
+
+void DRTDevToolsClient::allMessagesProcessed()
+{
+ m_webView->mainFrame()->executeScript(
+ WebKit::WebScriptSource(WebString::fromUTF8(
+ "if (window.WebInspector && WebInspector.queuesAreEmpty) WebInspector.queuesAreEmpty();")));
+}
diff --git a/Tools/DumpRenderTree/chromium/DRTDevToolsClient.h b/Tools/DumpRenderTree/chromium/DRTDevToolsClient.h
new file mode 100644
index 0000000..9ca1402
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/DRTDevToolsClient.h
@@ -0,0 +1,90 @@
+/*
+ * 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 DRTDevToolsClient_h
+#define DRTDevToolsClient_h
+
+#include "DRTDevToolsCallArgs.h"
+#include "Task.h"
+#include "WebDevToolsFrontendClient.h"
+#include <wtf/Noncopyable.h>
+#include <wtf/OwnPtr.h>
+
+namespace WebKit {
+
+class WebDevToolsFrontend;
+struct WebDevToolsMessageData;
+class WebString;
+class WebView;
+
+} // namespace WebKit
+
+class DRTDevToolsAgent;
+
+class DRTDevToolsClient : public WebKit::WebDevToolsFrontendClient
+ , public Noncopyable {
+public:
+ DRTDevToolsClient(DRTDevToolsAgent*, WebKit::WebView*);
+ virtual ~DRTDevToolsClient();
+ void reset();
+
+ // WebDevToolsFrontendClient implementation
+ virtual void sendFrontendLoaded();
+ virtual void sendMessageToBackend(const WebKit::WebString&);
+ virtual void sendDebuggerCommandToAgent(const WebKit::WebString& command);
+
+ virtual void activateWindow();
+ virtual void closeWindow();
+ virtual void dockWindow();
+ virtual void undockWindow();
+
+ void asyncCall(const DRTDevToolsCallArgs&);
+
+ void allMessagesProcessed();
+ TaskList* taskList() { return &m_taskList; }
+
+ private:
+ void call(const DRTDevToolsCallArgs&);
+ class AsyncCallTask: public MethodTask<DRTDevToolsClient> {
+ public:
+ AsyncCallTask(DRTDevToolsClient* object, const DRTDevToolsCallArgs& args)
+ : MethodTask<DRTDevToolsClient>(object), m_args(args) {}
+ virtual void runIfValid() { m_object->call(m_args); }
+ private:
+ DRTDevToolsCallArgs m_args;
+ };
+
+ TaskList m_taskList;
+ WebKit::WebView* m_webView;
+ DRTDevToolsAgent* m_drtDevToolsAgent;
+ WTF::OwnPtr<WebKit::WebDevToolsFrontend> m_webDevToolsFrontend;
+};
+
+#endif // DRTDevToolsClient_h
diff --git a/Tools/DumpRenderTree/chromium/DumpRenderTree.cpp b/Tools/DumpRenderTree/chromium/DumpRenderTree.cpp
new file mode 100644
index 0000000..3bbba98
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/DumpRenderTree.cpp
@@ -0,0 +1,214 @@
+/*
+ * 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 <v8/include/v8.h>
+#include <wtf/Vector.h>
+
+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 const char optionPixelTestsWithName[] = "--pixel-tests=";
+static const char optionTestShell[] = "--test-shell";
+static const char optionAllowExternalPages[] = "--allow-external-pages";
+static const char optionStartupDialog[] = "--testshell-startup-dialog";
+static const char optionCheckLayoutTestSystemDeps[] = "--check-layout-test-sys-deps";
+static const char optionEnableAcceleratedCompositing[] = "--enable-accelerated-compositing";
+static const char optionEnableAccelerated2DCanvas[] = "--enable-accelerated-2d-canvas";
+
+static const char optionMultipleLoads[] = "--multiple-loads=";
+static const char optionJavaScriptFlags[] = "--js-flags=";
+
+static void runTest(TestShell& shell, TestParams& params, const string& testName, bool testShellMode)
+{
+ int oldTimeoutMsec = shell.layoutTestTimeout();
+ params.pixelHash = "";
+ string pathOrURL = testName;
+ if (testShellMode) {
+ string timeOut;
+ string::size_type separatorPosition = pathOrURL.find(' ');
+ if (separatorPosition != string::npos) {
+ timeOut = pathOrURL.substr(separatorPosition + 1);
+ pathOrURL.erase(separatorPosition);
+ separatorPosition = timeOut.find_first_of(' ');
+ if (separatorPosition != string::npos) {
+ params.pixelHash = timeOut.substr(separatorPosition + 1);
+ timeOut.erase(separatorPosition);
+ }
+ shell.setLayoutTestTimeout(atoi(timeOut.c_str()));
+ }
+ } else {
+ 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);
+ webkit_support::SetCurrentDirectoryForFileURL(params.testUrl);
+ for (int i = 0; i < shell.loadCount(); i++) {
+ string javaScriptFlags = shell.javaScriptFlagsForLoad(i);
+ v8::V8::SetFlagsFromString(javaScriptFlags.data(), static_cast<int>(javaScriptFlags.size()));
+ bool isLastLoad = (i == (shell.loadCount() - 1));
+ shell.setDumpWhenFinished(isLastLoad);
+ shell.resetTestController();
+ shell.runFileTest(params);
+ }
+ shell.setLayoutTestTimeout(oldTimeoutMsec);
+}
+
+int main(int argc, char* argv[])
+{
+ webkit_support::SetUpTestEnvironment();
+ platformInit(&argc, &argv);
+
+ TestParams params;
+ Vector<string> tests;
+ bool serverMode = false;
+ bool testShellMode = false;
+ bool allowExternalPages = false;
+ bool startupDialog = false;
+ bool acceleratedCompositingEnabled = false;
+ bool accelerated2DCanvasEnabled = false;
+ int loadCount = 1;
+ string javaScriptFlags;
+ 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.find(optionPixelTestsWithName)) {
+ params.dumpPixels = true;
+ params.pixelFileName = argument.substr(strlen(optionPixelTestsWithName));
+ } else if (argument == optionTestShell) {
+ testShellMode = true;
+ serverMode = true;
+ } else if (argument == optionAllowExternalPages)
+ allowExternalPages = true;
+ else if (argument == optionStartupDialog)
+ startupDialog = true;
+ else if (argument == optionCheckLayoutTestSystemDeps)
+ exit(checkLayoutTestSystemDependencies() ? EXIT_SUCCESS : EXIT_FAILURE);
+ else if (argument == optionEnableAcceleratedCompositing)
+ acceleratedCompositingEnabled = true;
+ else if (argument == optionEnableAccelerated2DCanvas)
+ accelerated2DCanvasEnabled = true;
+ else if (!argument.find(optionMultipleLoads)) {
+ string multipleLoadsStr = argument.substr(strlen(optionMultipleLoads));
+ loadCount = atoi(multipleLoadsStr.c_str());
+ } else if (!argument.find(optionJavaScriptFlags)) {
+ javaScriptFlags = argument.substr(strlen(optionJavaScriptFlags));
+ } else if (argument.size() && argument[0] == '-')
+ fprintf(stderr, "Unknown option: %s\n", argv[i]);
+ else
+ tests.append(argument);
+ }
+ if (testShellMode && params.dumpPixels && params.pixelFileName.empty()) {
+ fprintf(stderr, "--pixel-tests with --test-shell requires a file name.\n");
+ return EXIT_FAILURE;
+ }
+ if (loadCount < 1) {
+ fprintf(stderr, "--multiple-loads requires a positive numeric argument.\n");
+ return EXIT_FAILURE;
+ }
+
+ // The test runner might send a quoted string which needs to be unquoted before further processing.
+ if (javaScriptFlags.length() > 1 && javaScriptFlags[0] == '"' && javaScriptFlags[javaScriptFlags.length() - 1] == '"')
+ javaScriptFlags = javaScriptFlags.substr(1, javaScriptFlags.length() - 2);
+ // Split the JavaScript flags into a list.
+ Vector<string> flagsList;
+ size_t start = 0;
+ while (true) {
+ size_t commaPos = javaScriptFlags.find_first_of(',', start);
+ string flags;
+ if (commaPos == string::npos)
+ flags = javaScriptFlags.substr(start, javaScriptFlags.length() - start);
+ else {
+ flags = javaScriptFlags.substr(start, commaPos - start);
+ start = commaPos + 1;
+ }
+ flagsList.append(flags);
+ if (commaPos == string::npos)
+ break;
+ }
+
+ if (startupDialog)
+ openStartupDialog();
+
+ { // Explicit scope for the TestShell instance.
+ TestShell shell(testShellMode);
+ shell.setAllowExternalPages(allowExternalPages);
+ shell.setAcceleratedCompositingEnabled(acceleratedCompositingEnabled);
+ shell.setAccelerated2dCanvasEnabled(accelerated2DCanvasEnabled);
+ shell.setLoadCount(loadCount);
+ shell.setJavaScriptFlags(flagsList);
+ 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, testShellMode);
+ }
+ } 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], testShellMode);
+ }
+
+ 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/Tools/DumpRenderTree/chromium/EventSender.cpp b/Tools/DumpRenderTree/chromium/EventSender.cpp
new file mode 100644
index 0000000..6104a90
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/EventSender.cpp
@@ -0,0 +1,1008 @@
+/*
+ * 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 "WebContextMenuData.h"
+#include "WebDragData.h"
+#include "WebDragOperation.h"
+#include "WebPoint.h"
+#include "WebString.h"
+#include "WebTouchPoint.h"
+#include "WebView.h"
+#include "webkit/support/webkit_support.h"
+#include <wtf/Deque.h>
+#include <wtf/StringExtras.h>
+
+#if OS(WINDOWS)
+#include "win/WebInputEventFactory.h"
+#endif
+
+// FIXME: layout before each event?
+
+using namespace std;
+using namespace WebKit;
+
+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;
+static int touchModifiers;
+static Vector<WebTouchPoint> touchPoints;
+
+// 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 (webkit_support::GetCurrentTimeInMillisecond() + 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 and everywhere non-Mac, 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 webkit_support::VKEY_LEFT:
+ *name = "MoveToBeginningOfLine";
+ break;
+ case webkit_support::VKEY_RIGHT:
+ *name = "MoveToEndOfLine";
+ break;
+ case webkit_support::VKEY_UP:
+ *name = "MoveToBeginningOfDocument";
+ break;
+ case webkit_support::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_shell(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("addTouchPoint", &EventSender::addTouchPoint);
+ bindMethod("beginDragWithFiles", &EventSender::beginDragWithFiles);
+ bindMethod("cancelTouchPoint", &EventSender::cancelTouchPoint);
+ bindMethod("clearKillRing", &EventSender::clearKillRing);
+ bindMethod("clearTouchPoints", &EventSender::clearTouchPoints);
+ bindMethod("contextClick", &EventSender::contextClick);
+ bindMethod("continuousMouseScrollBy", &EventSender::continuousMouseScrollBy);
+ bindMethod("dispatchMessage", &EventSender::dispatchMessage);
+ bindMethod("enableDOMUIEventLogging", &EventSender::enableDOMUIEventLogging);
+ bindMethod("fireKeyboardEventsToElement", &EventSender::fireKeyboardEventsToElement);
+ bindMethod("keyDown", &EventSender::keyDown);
+ bindMethod("leapForward", &EventSender::leapForward);
+ bindMethod("mouseDown", &EventSender::mouseDown);
+ bindMethod("mouseMoveTo", &EventSender::mouseMoveTo);
+ bindMethod("mouseScrollBy", &EventSender::mouseScrollBy);
+ bindMethod("mouseUp", &EventSender::mouseUp);
+ bindMethod("releaseTouchPoint", &EventSender::releaseTouchPoint);
+ bindMethod("scheduleAsynchronousClick", &EventSender::scheduleAsynchronousClick);
+ bindMethod("setTouchModifier", &EventSender::setTouchModifier);
+ bindMethod("textZoomIn", &EventSender::textZoomIn);
+ bindMethod("textZoomOut", &EventSender::textZoomOut);
+ bindMethod("touchCancel", &EventSender::touchCancel);
+ bindMethod("touchEnd", &EventSender::touchEnd);
+ bindMethod("touchMove", &EventSender::touchMove);
+ bindMethod("touchStart", &EventSender::touchStart);
+ bindMethod("updateTouchPoint", &EventSender::updateTouchPoint);
+ bindMethod("zoomPageIn", &EventSender::zoomPageIn);
+ bindMethod("zoomPageOut", &EventSender::zoomPageOut);
+
+ // 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;
+ touchModifiers = 0;
+ touchPoints.clear();
+ m_taskList.revokeAll();
+}
+
+WebView* EventSender::webview()
+{
+ return m_shell->webView();
+}
+
+void EventSender::doDragDrop(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::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 = webkit_support::VKEY_RETURN;
+ } else if ("rightArrow" == codeStr)
+ code = webkit_support::VKEY_RIGHT;
+ else if ("downArrow" == codeStr)
+ code = webkit_support::VKEY_DOWN;
+ else if ("leftArrow" == codeStr)
+ code = webkit_support::VKEY_LEFT;
+ else if ("upArrow" == codeStr)
+ code = webkit_support::VKEY_UP;
+ else if ("insert" == codeStr)
+ code = webkit_support::VKEY_INSERT;
+ else if ("delete" == codeStr)
+ code = webkit_support::VKEY_DELETE;
+ else if ("pageUp" == codeStr)
+ code = webkit_support::VKEY_PRIOR;
+ else if ("pageDown" == codeStr)
+ code = webkit_support::VKEY_NEXT;
+ else if ("home" == codeStr)
+ code = webkit_support::VKEY_HOME;
+ else if ("end" == codeStr)
+ code = webkit_support::VKEY_END;
+ else if ("printScreen" == codeStr)
+ code = webkit_support::VKEY_SNAPSHOT;
+ 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 = webkit_support::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))
+ m_shell->webViewHost()->setEditCommand(editCommand, "");
+
+ webview()->handleInputEvent(eventDown);
+
+ m_shell->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::mouseScrollBy(const CppArgumentList& arguments, CppVariant* result)
+{
+ handleMouseWheel(arguments, result, false);
+}
+
+void EventSender::continuousMouseScrollBy(const CppArgumentList& arguments, CppVariant* result)
+{
+ handleMouseWheel(arguments, result, true);
+}
+
+void EventSender::replaySavedEvents()
+{
+ replayingSavedEvents = true;
+ while (!mouseEventQueue.isEmpty()) {
+ SavedEvent e = mouseEventQueue.takeFirst();
+
+ 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;
+}
+
+// Because actual context menu is implemented by the browser side,
+// this function does only what LayoutTests are expecting:
+// - Many test checks the count of items. So returning non-zero value makes sense.
+// - Some test compares the count before and after some action. So changing the count based on flags
+// also makes sense. This function is doing such for some flags.
+// - Some test even checks actual string content. So providing it would be also helpful.
+//
+static Vector<WebString> makeMenuItemStringsFor(WebContextMenuData* contextMenu, MockSpellCheck* spellcheck)
+{
+ // These constants are based on Safari's context menu because tests are made for it.
+ static const char* nonEditableMenuStrings[] = { "Back", "Reload Page", "Open in Dashbaord", "<separator>", "View Source", "Save Page As", "Print Page", "Inspect Element", 0 };
+ static const char* editableMenuStrings[] = { "Cut", "Copy", "<separator>", "Paste", "Spelling and Grammar", "Substitutions, Transformations", "Font", "Speech", "Paragraph Direction", "<separator>", 0 };
+
+ // This is possible because mouse events are cancelleable.
+ if (!contextMenu)
+ return Vector<WebString>();
+
+ Vector<WebString> strings;
+
+ if (contextMenu->isEditable) {
+ for (const char** item = editableMenuStrings; *item; ++item)
+ strings.append(WebString::fromUTF8(*item));
+ Vector<WebString> suggestions;
+ spellcheck->fillSuggestionList(contextMenu->misspelledWord, &suggestions);
+ for (size_t i = 0; i < suggestions.size(); ++i)
+ strings.append(suggestions[i]);
+ } else {
+ for (const char** item = nonEditableMenuStrings; *item; ++item)
+ strings.append(WebString::fromUTF8(*item));
+ }
+
+ return strings;
+}
+
+
+void EventSender::contextClick(const CppArgumentList& arguments, CppVariant* result)
+{
+ webview()->layout();
+
+ updateClickCountForButton(WebMouseEvent::ButtonRight);
+
+ // Clears last context menu data because we need to know if the context menu be requested
+ // after following mouse events.
+ m_shell->webViewHost()->clearContextMenuData();
+
+ // 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;
+
+ WebContextMenuData* lastContextMenu = m_shell->webViewHost()->lastContextMenuData();
+ result->set(WebBindings::makeStringArray(makeMenuItemStringsFor(lastContextMenu, m_shell->webViewHost()->mockSpellCheck())));
+}
+
+class MouseDownTask: public MethodTask<EventSender> {
+public:
+ MouseDownTask(EventSender* obj, const CppArgumentList& arg)
+ : MethodTask<EventSender>(obj), m_arguments(arg) {}
+ virtual void runIfValid() { m_object->mouseDown(m_arguments, 0); }
+private:
+ CppArgumentList m_arguments;
+};
+
+class MouseUpTask: public MethodTask<EventSender> {
+public:
+ MouseUpTask(EventSender* obj, const CppArgumentList& arg)
+ : MethodTask<EventSender>(obj), m_arguments(arg) {}
+ virtual void runIfValid() { m_object->mouseUp(m_arguments, 0); }
+private:
+ CppArgumentList m_arguments;
+};
+
+void EventSender::scheduleAsynchronousClick(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ postTask(new MouseDownTask(this, arguments));
+ postTask(new MouseUpTask(this, arguments));
+}
+
+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();
+}
+
+void EventSender::addTouchPoint(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ WebTouchPoint touchPoint;
+ touchPoint.state = WebTouchPoint::StatePressed;
+ touchPoint.position = WebPoint(arguments[0].toInt32(), arguments[1].toInt32());
+ touchPoint.screenPosition = touchPoint.position;
+ touchPoint.id = touchPoints.size();
+ touchPoints.append(touchPoint);
+}
+
+void EventSender::clearTouchPoints(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+ touchPoints.clear();
+}
+
+void EventSender::releaseTouchPoint(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ const unsigned index = arguments[0].toInt32();
+ ASSERT(index < touchPoints.size());
+
+ WebTouchPoint* touchPoint = &touchPoints[index];
+ touchPoint->state = WebTouchPoint::StateReleased;
+}
+
+void EventSender::setTouchModifier(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ int mask = 0;
+ const string keyName = arguments[0].toString();
+ if (keyName == "shift")
+ mask = WebInputEvent::ShiftKey;
+ else if (keyName == "alt")
+ mask = WebInputEvent::AltKey;
+ else if (keyName == "ctrl")
+ mask = WebInputEvent::ControlKey;
+ else if (keyName == "meta")
+ mask = WebInputEvent::MetaKey;
+
+ if (arguments[1].toBoolean())
+ touchModifiers |= mask;
+ else
+ touchModifiers &= ~mask;
+}
+
+void EventSender::updateTouchPoint(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ const unsigned index = arguments[0].toInt32();
+ ASSERT(index < touchPoints.size());
+
+ WebPoint position(arguments[1].toInt32(), arguments[2].toInt32());
+ WebTouchPoint* touchPoint = &touchPoints[index];
+ touchPoint->state = WebTouchPoint::StateMoved;
+ touchPoint->position = position;
+ touchPoint->screenPosition = position;
+}
+
+void EventSender::cancelTouchPoint(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ const unsigned index = arguments[0].toInt32();
+ ASSERT(index < touchPoints.size());
+
+ WebTouchPoint* touchPoint = &touchPoints[index];
+ touchPoint->state = WebTouchPoint::StateCancelled;
+}
+
+void EventSender::sendCurrentTouchEvent(const WebInputEvent::Type type)
+{
+ ASSERT(static_cast<unsigned>(WebTouchEvent::touchPointsLengthCap) > touchPoints.size());
+ webview()->layout();
+
+ WebTouchEvent touchEvent;
+ touchEvent.type = type;
+ touchEvent.modifiers = touchModifiers;
+ touchEvent.timeStampSeconds = getCurrentEventTimeSec();
+ touchEvent.touchPointsLength = touchPoints.size();
+ for (unsigned i = 0; i < touchPoints.size(); ++i)
+ touchEvent.touchPoints[i] = touchPoints[i];
+ webview()->handleInputEvent(touchEvent);
+
+ for (unsigned i = 0; i < touchPoints.size(); ++i) {
+ WebTouchPoint* touchPoint = &touchPoints[i];
+ if (touchPoint->state == WebTouchPoint::StateReleased) {
+ touchPoints.remove(i);
+ --i;
+ } else
+ touchPoint->state = WebTouchPoint::StateStationary;
+ }
+}
+
+void EventSender::handleMouseWheel(const CppArgumentList& arguments, CppVariant* result, bool continuous)
+{
+ 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).
+ 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 = event.wheelTicksX;
+ event.deltaY = event.wheelTicksY;
+ if (continuous) {
+ event.wheelTicksX /= scrollbarPixelsPerTick;
+ event.wheelTicksY /= scrollbarPixelsPerTick;
+ } else {
+ event.deltaX *= scrollbarPixelsPerTick;
+ event.deltaY *= scrollbarPixelsPerTick;
+ }
+ webview()->handleInputEvent(event);
+}
+
+void EventSender::touchEnd(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+ sendCurrentTouchEvent(WebInputEvent::TouchEnd);
+}
+
+void EventSender::touchMove(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+ sendCurrentTouchEvent(WebInputEvent::TouchMove);
+}
+
+void EventSender::touchStart(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+ sendCurrentTouchEvent(WebInputEvent::TouchStart);
+}
+
+void EventSender::touchCancel(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+ sendCurrentTouchEvent(WebInputEvent::TouchCancel);
+}
+
+//
+// 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/Tools/DumpRenderTree/chromium/EventSender.h b/Tools/DumpRenderTree/chromium/EventSender.h
new file mode 100644
index 0000000..118509b
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/EventSender.h
@@ -0,0 +1,163 @@
+/*
+ * 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 "Task.h"
+#include "WebDragOperation.h"
+#include "WebInputEvent.h"
+#include "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.
+ void doDragDrop(const WebKit::WebDragData&, WebKit::WebDragOperationsMask);
+
+ // JS callback methods.
+ void mouseDown(const CppArgumentList&, CppVariant*);
+ void mouseUp(const CppArgumentList&, CppVariant*);
+ void mouseMoveTo(const CppArgumentList&, CppVariant*);
+ void leapForward(const CppArgumentList&, CppVariant*);
+ void keyDown(const CppArgumentList&, CppVariant*);
+ void dispatchMessage(const CppArgumentList&, CppVariant*);
+ void textZoomIn(const CppArgumentList&, CppVariant*);
+ void textZoomOut(const CppArgumentList&, CppVariant*);
+ void zoomPageIn(const CppArgumentList&, CppVariant*);
+ void zoomPageOut(const CppArgumentList&, CppVariant*);
+ void mouseScrollBy(const CppArgumentList&, CppVariant*);
+ void continuousMouseScrollBy(const CppArgumentList&, CppVariant*);
+ void scheduleAsynchronousClick(const CppArgumentList&, CppVariant*);
+ void beginDragWithFiles(const CppArgumentList&, CppVariant*);
+ CppVariant dragMode;
+
+ void addTouchPoint(const CppArgumentList&, CppVariant*);
+ void cancelTouchPoint(const CppArgumentList&, CppVariant*);
+ void clearTouchPoints(const CppArgumentList&, CppVariant*);
+ void releaseTouchPoint(const CppArgumentList&, CppVariant*);
+ void setTouchModifier(const CppArgumentList&, CppVariant*);
+ void touchCancel(const CppArgumentList&, CppVariant*);
+ void touchEnd(const CppArgumentList&, CppVariant*);
+ void touchMove(const CppArgumentList&, CppVariant*);
+ void touchStart(const CppArgumentList&, CppVariant*);
+ void updateTouchPoint(const CppArgumentList&, CppVariant*);
+
+ // 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
+
+ TaskList* taskList() { return &m_taskList; }
+
+private:
+ // Returns the test shell's webview.
+ 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.
+ void doMouseMove(const WebKit::WebMouseEvent&);
+ void doMouseUp(const WebKit::WebMouseEvent&);
+ static void doLeapForward(int milliseconds);
+ 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);
+
+ // Compose a touch event from the current touch points and send it.
+ void sendCurrentTouchEvent(const WebKit::WebInputEvent::Type);
+
+ // Handle a request to send a wheel event.
+ void handleMouseWheel(const CppArgumentList&, CppVariant*, bool continuous);
+
+ TaskList m_taskList;
+
+ // Non-owning pointer. The EventSender is owned by the TestShell.
+ TestShell* m_shell;
+
+ // 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/Tools/DumpRenderTree/chromium/ImageDiff.cpp b/Tools/DumpRenderTree/chromium/ImageDiff.cpp
new file mode 100644
index 0000000..f2875dd
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/ImageDiff.cpp
@@ -0,0 +1,408 @@
+/*
+ * 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 "webkit/support/webkit_support_gfx.h"
+#include <algorithm>
+#include <stdio.h>
+#include <string.h>
+#include <vector>
+#include <wtf/OwnArrayPtr.h>
+#include <wtf/Vector.h>
+
+#if OS(WINDOWS)
+#include <windows.h>
+#define PATH_MAX MAX_PATH
+#endif
+
+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 (!webkit_support::DecodePNG(source.get(), byteLength, &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 (!webkit_support::DecodePNG(&compressed[0], compressed.size(), &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", outFile);
+ return false;
+ }
+ if (dataSize != fwrite(data, 1, dataSize, file)) {
+ fclose(file);
+ fprintf(stderr, "ImageDiff: Unable to write data to file \"%s\"\n", outFile);
+ 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;
+ webkit_support::EncodeRGBAPNG(diffImage.data(), diffImage.width(), diffImage.height(),
+ diffImage.width() * 4, &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/Tools/DumpRenderTree/chromium/LayoutTestController.cpp b/Tools/DumpRenderTree/chromium/LayoutTestController.cpp
new file mode 100644
index 0000000..e3af738
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/LayoutTestController.cpp
@@ -0,0 +1,1590 @@
+/*
+ * 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 "DRTDevToolsAgent.h"
+#include "TestShell.h"
+#include "WebAnimationController.h"
+#include "WebBindings.h"
+#include "WebConsoleMessage.h"
+#include "WebData.h"
+#include "WebDeviceOrientation.h"
+#include "WebDeviceOrientationClientMock.h"
+#include "WebDocument.h"
+#include "WebElement.h"
+#include "WebFrame.h"
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+#include "WebGeolocationClientMock.h"
+#else
+#include "WebGeolocationServiceMock.h"
+#endif
+#include "WebInputElement.h"
+#include "WebKit.h"
+#include "WebNotificationPresenter.h"
+#include "WebScriptSource.h"
+#include "WebSecurityPolicy.h"
+#include "WebSettings.h"
+#include "WebSize.h"
+#include "WebSpeechInputControllerMock.h"
+#include "WebURL.h"
+#include "WebView.h"
+#include "WebViewHost.h"
+#include "webkit/support/webkit_support.h"
+#include <algorithm>
+#include <cstdlib>
+#include <limits>
+#include <wtf/text/WTFString.h>
+
+#if OS(WINDOWS)
+#include <wtf/OwnArrayPtr.h>
+#endif
+
+using namespace WebCore;
+using namespace WebKit;
+using namespace std;
+
+LayoutTestController::LayoutTestController(TestShell* shell)
+ : m_shell(shell)
+ , m_closeRemainingWindows(false)
+ , m_deferMainResourceDataLoad(false)
+ , 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("addFileToPasteboardOnDrag", &LayoutTestController::addFileToPasteboardOnDrag);
+ bindMethod("addOriginAccessWhitelistEntry", &LayoutTestController::addOriginAccessWhitelistEntry);
+ bindMethod("addUserScript", &LayoutTestController::addUserScript);
+ bindMethod("addUserStyleSheet", &LayoutTestController::addUserStyleSheet);
+ bindMethod("clearAllDatabases", &LayoutTestController::clearAllDatabases);
+ bindMethod("closeWebInspector", &LayoutTestController::closeWebInspector);
+ bindMethod("counterValueForElementById", &LayoutTestController::counterValueForElementById);
+ bindMethod("disableImageLoading", &LayoutTestController::disableImageLoading);
+ bindMethod("display", &LayoutTestController::display);
+ bindMethod("dumpAsText", &LayoutTestController::dumpAsText);
+ bindMethod("dumpBackForwardList", &LayoutTestController::dumpBackForwardList);
+ bindMethod("dumpChildFramesAsText", &LayoutTestController::dumpChildFramesAsText);
+ bindMethod("dumpChildFrameScrollPositions", &LayoutTestController::dumpChildFrameScrollPositions);
+ bindMethod("dumpDatabaseCallbacks", &LayoutTestController::dumpDatabaseCallbacks);
+ bindMethod("dumpEditingCallbacks", &LayoutTestController::dumpEditingCallbacks);
+ bindMethod("dumpFrameLoadCallbacks", &LayoutTestController::dumpFrameLoadCallbacks);
+ bindMethod("dumpUserGestureInFrameLoadCallbacks", &LayoutTestController::dumpUserGestureInFrameLoadCallbacks);
+ bindMethod("dumpResourceLoadCallbacks", &LayoutTestController::dumpResourceLoadCallbacks);
+ bindMethod("dumpResourceResponseMIMETypes", &LayoutTestController::dumpResourceResponseMIMETypes);
+ bindMethod("dumpSelectionRect", &LayoutTestController::dumpSelectionRect);
+ bindMethod("dumpStatusCallbacks", &LayoutTestController::dumpWindowStatusChanges);
+ bindMethod("dumpTitleChanges", &LayoutTestController::dumpTitleChanges);
+ bindMethod("elementDoesAutoCompleteForElementWithId", &LayoutTestController::elementDoesAutoCompleteForElementWithId);
+ bindMethod("evaluateInWebInspector", &LayoutTestController::evaluateInWebInspector);
+ bindMethod("evaluateScriptInIsolatedWorld", &LayoutTestController::evaluateScriptInIsolatedWorld);
+ bindMethod("execCommand", &LayoutTestController::execCommand);
+ bindMethod("forceRedSelectionColors", &LayoutTestController::forceRedSelectionColors);
+ bindMethod("grantDesktopNotificationPermission", &LayoutTestController::grantDesktopNotificationPermission);
+ bindMethod("isCommandEnabled", &LayoutTestController::isCommandEnabled);
+ bindMethod("layerTreeAsText", &LayoutTestController::layerTreeAsText);
+ bindMethod("markerTextForListItem", &LayoutTestController::markerTextForListItem);
+ bindMethod("hasSpellingMarker", &LayoutTestController::hasSpellingMarker);
+ bindMethod("notifyDone", &LayoutTestController::notifyDone);
+ bindMethod("numberOfActiveAnimations", &LayoutTestController::numberOfActiveAnimations);
+ bindMethod("numberOfPages", &LayoutTestController::numberOfPages);
+ bindMethod("objCIdentityIsEqual", &LayoutTestController::objCIdentityIsEqual);
+ bindMethod("overridePreference", &LayoutTestController::overridePreference);
+ bindMethod("pageNumberForElementById", &LayoutTestController::pageNumberForElementById);
+ bindMethod("pathToLocalResource", &LayoutTestController::pathToLocalResource);
+ bindMethod("pauseAnimationAtTimeOnElementWithId", &LayoutTestController::pauseAnimationAtTimeOnElementWithId);
+ bindMethod("pauseTransitionAtTimeOnElementWithId", &LayoutTestController::pauseTransitionAtTimeOnElementWithId);
+ bindMethod("queueBackNavigation", &LayoutTestController::queueBackNavigation);
+ bindMethod("queueForwardNavigation", &LayoutTestController::queueForwardNavigation);
+ bindMethod("queueLoadingScript", &LayoutTestController::queueLoadingScript);
+ bindMethod("queueLoad", &LayoutTestController::queueLoad);
+ bindMethod("queueLoadHTMLString", &LayoutTestController::queueLoadHTMLString);
+ bindMethod("queueNonLoadingScript", &LayoutTestController::queueNonLoadingScript);
+ bindMethod("queueReload", &LayoutTestController::queueReload);
+ bindMethod("removeOriginAccessWhitelistEntry", &LayoutTestController::removeOriginAccessWhitelistEntry);
+ bindMethod("repaintSweepHorizontally", &LayoutTestController::repaintSweepHorizontally);
+ bindMethod("resumeAnimations", &LayoutTestController::resumeAnimations);
+ bindMethod("sampleSVGAnimationForElementAtTime", &LayoutTestController::sampleSVGAnimationForElementAtTime);
+ bindMethod("setAcceptsEditing", &LayoutTestController::setAcceptsEditing);
+ bindMethod("setAllowFileAccessFromFileURLs", &LayoutTestController::setAllowFileAccessFromFileURLs);
+ bindMethod("setAllowUniversalAccessFromFileURLs", &LayoutTestController::setAllowUniversalAccessFromFileURLs);
+ bindMethod("setAlwaysAcceptCookies", &LayoutTestController::setAlwaysAcceptCookies);
+ bindMethod("setAuthorAndUserStylesEnabled", &LayoutTestController::setAuthorAndUserStylesEnabled);
+ bindMethod("setCanOpenWindows", &LayoutTestController::setCanOpenWindows);
+ bindMethod("setCloseRemainingWindowsWhenComplete", &LayoutTestController::setCloseRemainingWindowsWhenComplete);
+ bindMethod("setCustomPolicyDelegate", &LayoutTestController::setCustomPolicyDelegate);
+ bindMethod("setDatabaseQuota", &LayoutTestController::setDatabaseQuota);
+ bindMethod("setDeferMainResourceDataLoad", &LayoutTestController::setDeferMainResourceDataLoad);
+ bindMethod("setDomainRelaxationForbiddenForURLScheme", &LayoutTestController::setDomainRelaxationForbiddenForURLScheme);
+ bindMethod("setEditingBehavior", &LayoutTestController::setEditingBehavior);
+ bindMethod("setGeolocationPermission", &LayoutTestController::setGeolocationPermission);
+ bindMethod("setIconDatabaseEnabled", &LayoutTestController::setIconDatabaseEnabled);
+ bindMethod("setJavaScriptCanAccessClipboard", &LayoutTestController::setJavaScriptCanAccessClipboard);
+ bindMethod("setMockDeviceOrientation", &LayoutTestController::setMockDeviceOrientation);
+ bindMethod("setMockGeolocationError", &LayoutTestController::setMockGeolocationError);
+ bindMethod("setMockGeolocationPosition", &LayoutTestController::setMockGeolocationPosition);
+ bindMethod("addMockSpeechInputResult", &LayoutTestController::addMockSpeechInputResult);
+ bindMethod("setPopupBlockingEnabled", &LayoutTestController::setPopupBlockingEnabled);
+ bindMethod("setPOSIXLocale", &LayoutTestController::setPOSIXLocale);
+ bindMethod("setScrollbarPolicy", &LayoutTestController::setScrollbarPolicy);
+ bindMethod("setSelectTrailingWhitespaceEnabled", &LayoutTestController::setSelectTrailingWhitespaceEnabled);
+ bindMethod("setSmartInsertDeleteEnabled", &LayoutTestController::setSmartInsertDeleteEnabled);
+ bindMethod("setStopProvisionalFrameLoads", &LayoutTestController::setStopProvisionalFrameLoads);
+ bindMethod("setTabKeyCyclesThroughElements", &LayoutTestController::setTabKeyCyclesThroughElements);
+ bindMethod("setTimelineProfilingEnabled", &LayoutTestController::setTimelineProfilingEnabled);
+ bindMethod("setUserStyleSheetEnabled", &LayoutTestController::setUserStyleSheetEnabled);
+ bindMethod("setUserStyleSheetLocation", &LayoutTestController::setUserStyleSheetLocation);
+ bindMethod("setWillSendRequestClearHeader", &LayoutTestController::setWillSendRequestClearHeader);
+ bindMethod("setWillSendRequestReturnsNull", &LayoutTestController::setWillSendRequestReturnsNull);
+ bindMethod("setWillSendRequestReturnsNullOnRedirect", &LayoutTestController::setWillSendRequestReturnsNullOnRedirect);
+ bindMethod("setWindowIsKey", &LayoutTestController::setWindowIsKey);
+ bindMethod("setXSSAuditorEnabled", &LayoutTestController::setXSSAuditorEnabled);
+ bindMethod("setAsynchronousSpellCheckingEnabled", &LayoutTestController::setAsynchronousSpellCheckingEnabled);
+ bindMethod("showWebInspector", &LayoutTestController::showWebInspector);
+ bindMethod("simulateDesktopNotificationClick", &LayoutTestController::simulateDesktopNotificationClick);
+ bindMethod("suspendAnimations", &LayoutTestController::suspendAnimations);
+ bindMethod("testRepaint", &LayoutTestController::testRepaint);
+ bindMethod("waitForPolicyDelegate", &LayoutTestController::waitForPolicyDelegate);
+ bindMethod("waitUntilDone", &LayoutTestController::waitUntilDone);
+ bindMethod("windowCount", &LayoutTestController::windowCount);
+
+ // The following are stubs.
+ bindMethod("abortModal", &LayoutTestController::abortModal);
+ bindMethod("accessStoredWebScriptObject", &LayoutTestController::accessStoredWebScriptObject);
+ bindMethod("addDisallowedURL", &LayoutTestController::addDisallowedURL);
+ bindMethod("callShouldCloseOnWebView", &LayoutTestController::callShouldCloseOnWebView);
+ bindMethod("clearAllApplicationCaches", &LayoutTestController::clearAllApplicationCaches);
+ bindMethod("clearBackForwardList", &LayoutTestController::clearBackForwardList);
+ bindMethod("dumpAsWebArchive", &LayoutTestController::dumpAsWebArchive);
+ bindMethod("keepWebHistory", &LayoutTestController::keepWebHistory);
+ bindMethod("objCClassNameOf", &LayoutTestController::objCClassNameOf);
+ bindMethod("setApplicationCacheOriginQuota", &LayoutTestController::setApplicationCacheOriginQuota);
+ bindMethod("setCallCloseOnWebViews", &LayoutTestController::setCallCloseOnWebViews);
+ bindMethod("setMainFrameIsFirstResponder", &LayoutTestController::setMainFrameIsFirstResponder);
+ bindMethod("setPrivateBrowsingEnabled", &LayoutTestController::setPrivateBrowsingEnabled);
+ bindMethod("setUseDashboardCompatibilityMode", &LayoutTestController::setUseDashboardCompatibilityMode);
+ bindMethod("storeWebScriptObject", &LayoutTestController::storeWebScriptObject);
+
+ // 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::~LayoutTestController()
+{
+}
+
+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.
+ postTask(new WorkQueueTask(this));
+ } 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.takeFirst();
+ 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.takeFirst();
+ }
+}
+
+void LayoutTestController::WorkQueue::addWork(WorkItem* work)
+{
+ if (m_frozen) {
+ delete work;
+ return;
+ }
+ m_queue.append(work);
+}
+
+void LayoutTestController::dumpAsText(const CppArgumentList& arguments, CppVariant* result)
+{
+ m_dumpAsText = true;
+ m_generatePixelResults = false;
+
+ // Optional paramater, describing whether it's allowed to dump pixel results in dumpAsText mode.
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_generatePixelResults = arguments[0].value.boolValue;
+
+ 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::dumpUserGestureInFrameLoadCallbacks(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpUserGestureInFrameLoadCallbacks = true;
+ result->setNull();
+}
+
+void LayoutTestController::dumpResourceLoadCallbacks(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpResourceLoadCallbacks = true;
+ result->setNull();
+}
+
+void LayoutTestController::dumpResourceResponseMIMETypes(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpResourceResponseMIMETypes = 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())
+ postDelayedTask(new NotifyDoneTimedOutTask(this), m_shell->layoutTestTimeout());
+ m_waitUntilDone = true;
+ result->setNull();
+}
+
+void LayoutTestController::notifyDone(const CppArgumentList&, CppVariant* result)
+{
+ // Test didn't timeout. Kill the timeout timer.
+ m_taskList.revokeAll();
+
+ completeNotifyDone(false);
+ result->setNull();
+}
+
+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();
+}
+
+class WorkItemLoadHTMLString : public LayoutTestController::WorkItem {
+public:
+ WorkItemLoadHTMLString(const std::string& html, const WebURL& baseURL)
+ : m_html(html)
+ , m_baseURL(baseURL) {}
+ bool run(TestShell* shell)
+ {
+ shell->webView()->mainFrame()->loadHTMLString(
+ WebKit::WebData(m_html.data(), m_html.length()), m_baseURL);
+ return true;
+ }
+private:
+ std::string m_html;
+ WebURL m_baseURL;
+};
+
+void LayoutTestController::queueLoadHTMLString(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isString()) {
+ string html = arguments[0].toString();
+ WebURL baseURL;
+ if (arguments.size() > 1 && arguments[1].isString())
+ baseURL = WebURL(GURL(arguments[1].toString()));
+ m_workQueue.addWork(new WorkItemLoadHTMLString(html, baseURL));
+ }
+ 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 !OS(DARWIN) && !OS(WINDOWS) // Actually, TOOLKIT_GTK
+ // (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
+ m_shell->webView()->removeAllUserContent();
+ }
+ m_dumpAsText = false;
+ m_dumpEditingCallbacks = false;
+ m_dumpFrameLoadCallbacks = false;
+ m_dumpUserGestureInFrameLoadCallbacks = false;
+ m_dumpResourceLoadCallbacks = false;
+ m_dumpResourceResponseMIMETypes = false;
+ m_dumpBackForwardList = false;
+ m_dumpChildFrameScrollPositions = false;
+ m_dumpChildFramesAsText = false;
+ m_dumpWindowStatusChanges = false;
+ m_dumpSelectionRect = false;
+ m_dumpTitleChanges = false;
+ m_generatePixelResults = true;
+ m_acceptsEditing = true;
+ m_waitUntilDone = false;
+ m_canOpenWindows = false;
+ m_testRepaint = false;
+ m_sweepHorizontally = false;
+ m_shouldAddFileToPasteboard = false;
+ m_stopProvisionalFrameLoads = false;
+ m_deferMainResourceDataLoad = true;
+ m_globalFlag.set(false);
+ m_webHistoryItemCount.set(0);
+ m_userStyleSheetLocation = WebURL();
+
+ 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();
+ m_taskList.revokeAll();
+}
+
+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::setAsynchronousSpellCheckingEnabled(const CppArgumentList&, CppVariant*)
+{
+ // FIXME: Implement this.
+}
+
+void LayoutTestController::showWebInspector(const CppArgumentList&, CppVariant* result)
+{
+ m_shell->showDevTools();
+ result->setNull();
+}
+
+void LayoutTestController::closeWebInspector(const CppArgumentList& args, CppVariant* result)
+{
+ m_shell->closeDevTools();
+ 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->preferences()->userStyleSheetLocation = arguments[0].value.boolValue ? m_userStyleSheetLocation : WebURL();
+ m_shell->applyPreferences();
+ }
+ result->setNull();
+}
+
+void LayoutTestController::setUserStyleSheetLocation(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isString()) {
+ m_userStyleSheetLocation = webkit_support::LocalFileToDataURL(
+ webkit_support::RewriteLayoutTestsURL(arguments[0].toString()));
+ m_shell->preferences()->userStyleSheetLocation = m_userStyleSheetLocation;
+ m_shell->applyPreferences();
+ }
+ result->setNull();
+}
+
+void LayoutTestController::setAuthorAndUserStylesEnabled(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool()) {
+ m_shell->preferences()->authorAndUserStylesEnabled = arguments[0].value.boolValue;
+ m_shell->applyPreferences();
+ }
+ 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->preferences()->javaScriptCanOpenWindowsAutomatically = !blockPopups;
+ m_shell->applyPreferences();
+ }
+ result->setNull();
+}
+
+void LayoutTestController::setUseDashboardCompatibilityMode(const CppArgumentList&, CppVariant* result)
+{
+ // We have no need to support Dashboard Compatibility Mode (mac-only)
+ result->setNull();
+}
+
+void LayoutTestController::clearAllApplicationCaches(const CppArgumentList&, CppVariant* result)
+{
+ // FIXME: implement to support Application Cache Quotas.
+ result->setNull();
+}
+
+void LayoutTestController::setApplicationCacheOriginQuota(const CppArgumentList&, CppVariant* result)
+{
+ // FIXME: implement to support Application Cache Quotas.
+ result->setNull();
+}
+
+void LayoutTestController::setScrollbarPolicy(const CppArgumentList&, CppVariant* result)
+{
+ // FIXME: implement.
+ // Currently only has a non-null implementation on QT.
+ 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::setWillSendRequestClearHeader(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isString()) {
+ string header = arguments[0].toString();
+ if (!header.empty())
+ m_shell->webViewHost()->addClearHeader(String::fromUTF8(header.c_str()));
+ }
+ 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 (!url.find("/tmp/")) {
+ // 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);
+ }
+ 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:///.
+ string lowerUrl = url;
+ transform(lowerUrl.begin(), lowerUrl.end(), lowerUrl.begin(), ::tolower);
+ while (!lowerUrl.find("file:////")) {
+ url = url.substr(0, 8) + url.substr(9);
+ lowerUrl = lowerUrl.substr(0, 8) + lowerUrl.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.to<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::suspendAnimations()
+{
+ WebFrame* webFrame = m_shell->webView()->mainFrame();
+ if (!webFrame)
+ return;
+
+ WebAnimationController* controller = webFrame->animationController();
+ if (!controller)
+ return;
+
+ controller->suspendAnimations();
+}
+
+void LayoutTestController::resumeAnimations()
+{
+ WebFrame* webFrame = m_shell->webView()->mainFrame();
+ if (!webFrame)
+ return;
+
+ WebAnimationController* controller = webFrame->animationController();
+ if (!controller)
+ return;
+
+ controller->resumeAnimations();
+}
+
+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::suspendAnimations(const CppArgumentList&, CppVariant* result)
+{
+ suspendAnimations();
+ result->setNull();
+}
+
+void LayoutTestController::resumeAnimations(const CppArgumentList&, CppVariant* result)
+{
+ resumeAnimations();
+ result->setNull();
+}
+
+void LayoutTestController::sampleSVGAnimationForElementAtTime(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() != 3) {
+ result->setNull();
+ return;
+ }
+ WebString animationId = cppVariantToWebString(arguments[0]);
+ double time = arguments[1].toDouble();
+ WebString elementId = cppVariantToWebString(arguments[2]);
+ bool success = m_shell->webView()->mainFrame()->pauseSVGAnimation(animationId, time, elementId);
+ result->set(success);
+}
+
+void LayoutTestController::disableImageLoading(const CppArgumentList&, CppVariant* result)
+{
+ m_shell->preferences()->loadsImagesAutomatically = false;
+ m_shell->applyPreferences();
+ result->setNull();
+}
+
+void LayoutTestController::setIconDatabaseEnabled(const CppArgumentList&, CppVariant* result)
+{
+ // We don't use the WebKit icon database.
+ result->setNull();
+}
+
+void LayoutTestController::callShouldCloseOnWebView(const CppArgumentList&, CppVariant* result)
+{
+ result->set(m_shell->webView()->dispatchBeforeUnloadEvent());
+}
+
+void LayoutTestController::grantDesktopNotificationPermission(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() != 1 || !arguments[0].isString()) {
+ result->set(false);
+ return;
+ }
+ m_shell->notificationPresenter()->grantPermission(cppVariantToWebString(arguments[0]));
+ result->set(true);
+}
+
+void LayoutTestController::simulateDesktopNotificationClick(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() != 1 || !arguments[0].isString()) {
+ result->set(false);
+ return;
+ }
+ if (m_shell->notificationPresenter()->simulateClick(cppVariantToWebString(arguments[0])))
+ result->set(true);
+ else
+ result->set(false);
+}
+
+void LayoutTestController::setDomainRelaxationForbiddenForURLScheme(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() != 2 || !arguments[0].isBool() || !arguments[1].isString())
+ return;
+ m_shell->webView()->setDomainRelaxationForbidden(cppVariantToBool(arguments[0]), cppVariantToWebString(arguments[1]));
+}
+
+void LayoutTestController::setDeferMainResourceDataLoad(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() == 1)
+ m_deferMainResourceDataLoad = cppVariantToBool(arguments[0]);
+}
+
+//
+// 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::setJavaScriptCanAccessClipboard(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool()) {
+ m_shell->preferences()->javaScriptCanAccessClipboard = arguments[0].value.boolValue;
+ m_shell->applyPreferences();
+ }
+ result->setNull();
+}
+
+void LayoutTestController::setXSSAuditorEnabled(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool()) {
+ m_shell->preferences()->XSSAuditorEnabled = arguments[0].value.boolValue;
+ m_shell->applyPreferences();
+ }
+ result->setNull();
+}
+
+void LayoutTestController::evaluateScriptInIsolatedWorld(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() >= 2 && arguments[0].isNumber() && arguments[1].isString()) {
+ WebScriptSource source(cppVariantToWebString(arguments[1]));
+ // This relies on the iframe focusing itself when it loads. This is a bit
+ // sketchy, but it seems to be what other tests do.
+ m_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->preferences()->allowUniversalAccessFromFileURLs = arguments[0].value.boolValue;
+ m_shell->applyPreferences();
+ }
+ result->setNull();
+}
+
+void LayoutTestController::setAllowFileAccessFromFileURLs(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool()) {
+ m_shell->preferences()->allowFileAccessFromFileURLs = arguments[0].value.boolValue;
+ m_shell->applyPreferences();
+ }
+ 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.isNumber())
+ 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.isNumber())
+ return value.toInt32();
+ if (value.isString()) {
+ string stringSource = value.toString();
+ const char* source = stringSource.data();
+ char* end;
+ long number = strtol(source, &end, 10);
+ if (end == source + stringSource.length() && number >= numeric_limits<int32_t>::min() && number <= numeric_limits<int32_t>::max())
+ return static_cast<int32_t>(number);
+ }
+ 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];
+ WebPreferences* prefs = m_shell->preferences();
+ if (key == "WebKitStandardFont")
+ prefs->standardFontFamily = cppVariantToWebString(value);
+ else if (key == "WebKitFixedFont")
+ prefs->fixedFontFamily = cppVariantToWebString(value);
+ else if (key == "WebKitSerifFont")
+ prefs->serifFontFamily = cppVariantToWebString(value);
+ else if (key == "WebKitSansSerifFont")
+ prefs->sansSerifFontFamily = cppVariantToWebString(value);
+ else if (key == "WebKitCursiveFont")
+ prefs->cursiveFontFamily = cppVariantToWebString(value);
+ else if (key == "WebKitFantasyFont")
+ prefs->fantasyFontFamily = cppVariantToWebString(value);
+ else if (key == "WebKitDefaultFontSize")
+ prefs->defaultFontSize = cppVariantToInt32(value);
+ else if (key == "WebKitDefaultFixedFontSize")
+ prefs->defaultFixedFontSize = cppVariantToInt32(value);
+ else if (key == "WebKitMinimumFontSize")
+ prefs->minimumFontSize = cppVariantToInt32(value);
+ else if (key == "WebKitMinimumLogicalFontSize")
+ prefs->minimumLogicalFontSize = cppVariantToInt32(value);
+ else if (key == "WebKitDefaultTextEncodingName")
+ prefs->defaultTextEncodingName = cppVariantToWebString(value);
+ else if (key == "WebKitJavaScriptEnabled")
+ prefs->javaScriptEnabled = cppVariantToBool(value);
+ else if (key == "WebKitWebSecurityEnabled")
+ prefs->webSecurityEnabled = cppVariantToBool(value);
+ else if (key == "WebKitJavaScriptCanOpenWindowsAutomatically")
+ prefs->javaScriptCanOpenWindowsAutomatically = cppVariantToBool(value);
+ else if (key == "WebKitDisplayImagesKey")
+ prefs->loadsImagesAutomatically = cppVariantToBool(value);
+ else if (key == "WebKitPluginsEnabled")
+ prefs->pluginsEnabled = cppVariantToBool(value);
+ else if (key == "WebKitDOMPasteAllowedPreferenceKey")
+ prefs->DOMPasteAllowed = cppVariantToBool(value);
+ else if (key == "WebKitDeveloperExtrasEnabledPreferenceKey")
+ prefs->developerExtrasEnabled = cppVariantToBool(value);
+ else if (key == "WebKitShrinksStandaloneImagesToFit")
+ prefs->shrinksStandaloneImagesToFit = cppVariantToBool(value);
+ else if (key == "WebKitTextAreasAreResizable")
+ prefs->textAreasAreResizable = cppVariantToBool(value);
+ else if (key == "WebKitJavaEnabled")
+ prefs->javaEnabled = cppVariantToBool(value);
+ else if (key == "WebKitUsesPageCachePreferenceKey")
+ prefs->usesPageCache = cppVariantToBool(value);
+ else if (key == "WebKitJavaScriptCanAccessClipboard")
+ prefs->javaScriptCanAccessClipboard = cppVariantToBool(value);
+ else if (key == "WebKitXSSAuditorEnabled")
+ prefs->XSSAuditorEnabled = cppVariantToBool(value);
+ else if (key == "WebKitLocalStorageEnabledPreferenceKey")
+ prefs->localStorageEnabled = cppVariantToBool(value);
+ else if (key == "WebKitOfflineWebApplicationCacheEnabled")
+ prefs->offlineWebApplicationCacheEnabled = cppVariantToBool(value);
+ else if (key == "WebKitTabToLinksPreferenceKey")
+ prefs->tabsToLinks = cppVariantToBool(value);
+ else if (key == "WebKitWebGLEnabled")
+ prefs->experimentalWebGLEnabled = cppVariantToBool(value);
+ else if (key == "WebKitHyperlinkAuditingEnabled")
+ prefs->hyperlinkAuditingEnabled = cppVariantToBool(value);
+ else if (key == "WebKitEnableCaretBrowsing")
+ prefs->caretBrowsingEnabled = cppVariantToBool(value);
+ else {
+ string message("Invalid name for preference: ");
+ message.append(key);
+ logErrorToConsole(message);
+ }
+ m_shell->applyPreferences();
+}
+
+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::addOriginAccessWhitelistEntry(
+ url,
+ cppVariantToWebString(arguments[1]),
+ cppVariantToWebString(arguments[2]),
+ arguments[3].toBoolean());
+}
+
+void LayoutTestController::removeOriginAccessWhitelistEntry(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ if (arguments.size() != 4 || !arguments[0].isString() || !arguments[1].isString()
+ || !arguments[2].isString() || !arguments[3].isBool())
+ return;
+
+ WebKit::WebURL url(GURL(arguments[0].toString()));
+ if (!url.isValid())
+ return;
+
+ WebSecurityPolicy::removeOriginAccessWhitelistEntry(
+ url,
+ cppVariantToWebString(arguments[1]),
+ cppVariantToWebString(arguments[2]),
+ 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].isNumber())
+ 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;
+ m_shell->drtDevToolsAgent()->setTimelineProfilingEnabled(arguments[0].toBoolean());
+}
+
+void LayoutTestController::evaluateInWebInspector(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isString())
+ return;
+ m_shell->drtDevToolsAgent()->evaluateInWebInspector(arguments[0].toInt32(), arguments[1].toString());
+}
+
+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() < 3 || !arguments[0].isString() || !arguments[1].isBool() || !arguments[2].isBool())
+ return;
+ WebView::addUserScript(
+ cppVariantToWebString(arguments[0]), WebVector<WebString>(),
+ arguments[1].toBoolean() ? WebView::UserScriptInjectAtDocumentStart : WebView::UserScriptInjectAtDocumentEnd,
+ arguments[2].toBoolean() ? WebView::UserContentInjectInAllFrames : WebView::UserContentInjectInTopFrameOnly);
+}
+
+void LayoutTestController::addUserStyleSheet(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 2 || !arguments[0].isString() || !arguments[1].isBool())
+ return;
+ WebView::addUserStyleSheet(
+ cppVariantToWebString(arguments[0]), WebVector<WebString>(),
+ arguments[1].toBoolean() ? WebView::UserContentInjectInAllFrames : WebView::UserContentInjectInTopFrameOnly,
+ // Chromium defaults to InjectInSubsequentDocuments, but for compatibility
+ // with the other ports' DRTs, we use UserStyleInjectInExistingDocuments.
+ WebView::UserStyleInjectInExistingDocuments);
+}
+
+void LayoutTestController::setEditingBehavior(const CppArgumentList& arguments, CppVariant* results)
+{
+ string key = arguments[0].toString();
+ if (key == "mac") {
+ m_shell->preferences()->editingBehavior = WebSettings::EditingBehaviorMac;
+ m_shell->applyPreferences();
+ } else if (key == "win") {
+ m_shell->preferences()->editingBehavior = WebSettings::EditingBehaviorWin;
+ m_shell->applyPreferences();
+ } else if (key == "unix") {
+ m_shell->preferences()->editingBehavior = WebSettings::EditingBehaviorUnix;
+ m_shell->applyPreferences();
+ } else
+ logErrorToConsole("Passed invalid editing behavior. Should be 'mac', 'win', or 'unix'.");
+}
+
+void LayoutTestController::setMockDeviceOrientation(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 6 || !arguments[0].isBool() || !arguments[1].isNumber() || !arguments[2].isBool() || !arguments[3].isNumber() || !arguments[4].isBool() || !arguments[5].isNumber())
+ return;
+
+ WebDeviceOrientation orientation(arguments[0].toBoolean(), arguments[1].toDouble(), arguments[2].toBoolean(), arguments[3].toDouble(), arguments[4].toBoolean(), arguments[5].toDouble());
+ // Note that we only call setOrientation on the main page's mock since this is all that the
+ // tests require. If necessary, we could get a list of WebViewHosts from the TestShell and
+ // call setOrientation on each DeviceOrientationClientMock.
+ m_shell->webViewHost()->deviceOrientationClientMock()->setOrientation(orientation);
+}
+
+void LayoutTestController::setGeolocationPermission(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 1 || !arguments[0].isBool())
+ return;
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+ m_shell->webViewHost()->geolocationClientMock()->setPermission(arguments[0].toBoolean());
+#else
+ WebGeolocationServiceMock::setMockGeolocationPermission(arguments[0].toBoolean());
+#endif
+}
+
+void LayoutTestController::setMockGeolocationPosition(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 3 || !arguments[0].isNumber() || !arguments[1].isNumber() || !arguments[2].isNumber())
+ return;
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+ m_shell->webViewHost()->geolocationClientMock()->setPosition(arguments[0].toDouble(), arguments[1].toDouble(), arguments[2].toDouble());
+#else
+ WebGeolocationServiceMock::setMockGeolocationPosition(arguments[0].toDouble(), arguments[1].toDouble(), arguments[2].toDouble());
+#endif
+}
+
+void LayoutTestController::setMockGeolocationError(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isString())
+ return;
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+ m_shell->webViewHost()->geolocationClientMock()->setError(arguments[0].toInt32(), cppVariantToWebString(arguments[1]));
+#else
+ WebGeolocationServiceMock::setMockGeolocationError(arguments[0].toInt32(), cppVariantToWebString(arguments[1]));
+#endif
+}
+
+void LayoutTestController::abortModal(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+}
+
+void LayoutTestController::addMockSpeechInputResult(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 3 || !arguments[0].isString() || !arguments[1].isNumber() || !arguments[2].isString())
+ return;
+
+ m_shell->webViewHost()->speechInputControllerMock()->addMockRecognitionResult(cppVariantToWebString(arguments[0]), arguments[1].toDouble(), cppVariantToWebString(arguments[2]));
+}
+
+void LayoutTestController::layerTreeAsText(const CppArgumentList& args, CppVariant* result)
+{
+ result->set(m_shell->webView()->mainFrame()->layerTreeAsText().utf8());
+}
+
+void LayoutTestController::markerTextForListItem(const CppArgumentList& args, CppVariant* result)
+{
+ WebElement element;
+ if (!WebBindings::getElement(args[0].value.objectValue, &element))
+ result->setNull();
+ else
+ result->set(element.document().frame()->markerTextForListItem(element).utf8());
+}
+
+void LayoutTestController::hasSpellingMarker(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isNumber())
+ return;
+ result->set(m_shell->webView()->mainFrame()->selectionStartHasSpellingMarkerFor(arguments[0].toInt32(), arguments[1].toInt32()));
+}
diff --git a/Tools/DumpRenderTree/chromium/LayoutTestController.h b/Tools/DumpRenderTree/chromium/LayoutTestController.h
new file mode 100644
index 0000000..13d1447
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/LayoutTestController.h
@@ -0,0 +1,551 @@
+/*
+ * 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 "Task.h"
+#include "WebString.h"
+#include "WebURL.h"
+#include <wtf/Deque.h>
+#include <wtf/OwnPtr.h>
+
+namespace WebKit {
+class WebGeolocationClientMock;
+class WebSpeechInputController;
+class WebSpeechInputControllerMock;
+class WebSpeechInputListener;
+}
+
+class TestShell;
+
+class LayoutTestController : public CppBoundClass {
+public:
+ // Builds the property and method lists needed to bind this class to a JS
+ // object.
+ LayoutTestController(TestShell*);
+
+ ~LayoutTestController();
+
+ // 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 an optional argument, whether to dump pixels results or not.
+ 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 a line of
+ // user gesture status text for some frame load callbacks. It takes no
+ // arguments, and ignores any that may be present.
+ void dumpUserGestureInFrameLoadCallbacks(const CppArgumentList&, CppVariant*);
+
+ // 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 a descriptive
+ // line for each resource load callback. It takes no arguments, and ignores
+ // any that may be present.
+ void dumpResourceLoadCallbacks(const CppArgumentList&, CppVariant*);
+
+ // This function sets a flag that tells the test_shell to dump the MIME type
+ // for each resource that was loaded. It takes no arguments, and ignores any
+ // that may be present.
+ void dumpResourceResponseMIMETypes(const CppArgumentList&, CppVariant*);
+
+ // 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*);
+
+ // Methods for adding actions to the work queue. Used in conjunction with
+ // waitUntilDone/notifyDone above.
+ void queueBackNavigation(const CppArgumentList&, CppVariant*);
+ void queueForwardNavigation(const CppArgumentList&, CppVariant*);
+ void queueReload(const CppArgumentList&, CppVariant*);
+ void queueLoadingScript(const CppArgumentList&, CppVariant*);
+ void queueNonLoadingScript(const CppArgumentList&, CppVariant*);
+ void queueLoad(const CppArgumentList&, CppVariant*);
+ void queueLoadHTMLString(const CppArgumentList&, CppVariant*);
+
+ // 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*);
+
+ // Changes asynchronous spellchecking flag on the settings.
+ void setAsynchronousSpellCheckingEnabled(const CppArgumentList&, CppVariant*);
+
+ // Shows DevTools window.
+ void showWebInspector(const CppArgumentList&, CppVariant*);
+ void closeWebInspector(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*);
+
+ // Passes this preference through to WebSettings.
+ void setAuthorAndUserStylesEnabled(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*);
+
+ void setScrollbarPolicy(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 clear certain headers.
+ void setWillSendRequestClearHeader(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 suspendAnimations(const CppArgumentList&, CppVariant*);
+ void resumeAnimations(const CppArgumentList&, CppVariant*);
+ void sampleSVGAnimationForElementAtTime(const CppArgumentList&, CppVariant*);
+ void disableImageLoading(const CppArgumentList&, CppVariant*);
+ void setIconDatabaseEnabled(const CppArgumentList&, CppVariant*);
+ void dumpSelectionRect(const CppArgumentList&, CppVariant*);
+
+ // Grants permission for desktop notifications to an origin
+ void grantDesktopNotificationPermission(const CppArgumentList&, CppVariant*);
+ // Simulates a click on a desktop notification.
+ void simulateDesktopNotificationClick(const CppArgumentList&, CppVariant*);
+
+ void setDomainRelaxationForbiddenForURLScheme(const CppArgumentList&, CppVariant*);
+ void setDeferMainResourceDataLoad(const CppArgumentList&, CppVariant*);
+ void setEditingBehavior(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 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 callShouldCloseOnWebView(const CppArgumentList&, CppVariant*);
+ void setCallCloseOnWebViews(const CppArgumentList&, CppVariant*);
+ void setPrivateBrowsingEnabled(const CppArgumentList&, CppVariant*);
+
+ void setJavaScriptCanAccessClipboard(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 manage origins' whitelisting.
+ void addOriginAccessWhitelistEntry(const CppArgumentList&, CppVariant*);
+ void removeOriginAccessWhitelistEntry(const CppArgumentList&, CppVariant*);
+
+ // Clears all Application Caches.
+ void clearAllApplicationCaches(const CppArgumentList&, CppVariant*);
+ // Sets the Application Quota for the localhost origin.
+ void setApplicationCacheOriginQuota(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 or user style sheet to be injected into new documents.
+ void addUserScript(const CppArgumentList&, CppVariant*);
+ void addUserStyleSheet(const CppArgumentList&, CppVariant*);
+
+ // DeviceOrientation related functions
+ void setMockDeviceOrientation(const CppArgumentList&, CppVariant*);
+
+ // Geolocation related functions.
+ void setGeolocationPermission(const CppArgumentList&, CppVariant*);
+ void setMockGeolocationPosition(const CppArgumentList&, CppVariant*);
+ void setMockGeolocationError(const CppArgumentList&, CppVariant*);
+
+ // Empty stub method to keep parity with object model exposed by global LayoutTestController.
+ void abortModal(const CppArgumentList&, CppVariant*);
+
+ // Speech input related functions.
+ void addMockSpeechInputResult(const CppArgumentList&, CppVariant*);
+
+ void layerTreeAsText(const CppArgumentList& args, CppVariant* result);
+
+ void markerTextForListItem(const CppArgumentList&, CppVariant*);
+ void hasSpellingMarker(const CppArgumentList&, CppVariant*);
+
+public:
+ // The following methods are not exposed to JavaScript.
+ void setWorkQueueFrozen(bool frozen) { m_workQueue.setFrozen(frozen); }
+
+ WebKit::WebSpeechInputController* speechInputController(WebKit::WebSpeechInputListener*);
+ bool shouldDumpAsText() { return m_dumpAsText; }
+ bool shouldDumpEditingCallbacks() { return m_dumpEditingCallbacks; }
+ bool shouldDumpFrameLoadCallbacks() { return m_dumpFrameLoadCallbacks; }
+ void setShouldDumpFrameLoadCallbacks(bool value) { m_dumpFrameLoadCallbacks = value; }
+ bool shouldDumpUserGestureInFrameLoadCallbacks() { return m_dumpUserGestureInFrameLoadCallbacks; }
+ void setShouldDumpUserGestureInFrameLoadCallbacks(bool value) { m_dumpUserGestureInFrameLoadCallbacks = value; }
+ bool shouldDumpResourceLoadCallbacks() {return m_dumpResourceLoadCallbacks; }
+ void setShouldDumpResourceResponseMIMETypes(bool value) { m_dumpResourceResponseMIMETypes = value; }
+ bool shouldDumpResourceResponseMIMETypes() {return m_dumpResourceResponseMIMETypes; }
+ 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 shouldGeneratePixelResults() { return m_generatePixelResults; }
+ bool acceptsEditing() { return m_acceptsEditing; }
+ bool canOpenWindows() { return m_canOpenWindows; }
+ bool shouldAddFileToPasteboard() { return m_shouldAddFileToPasteboard; }
+ bool stopProvisionalFrameLoads() { return m_stopProvisionalFrameLoads; }
+ bool deferMainResourceDataLoad() { return m_deferMainResourceDataLoad; }
+
+ 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;
+ };
+
+ TaskList* taskList() { return &m_taskList; }
+
+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_frozen(false), 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(); }
+ TaskList* taskList() { return &m_taskList; }
+
+ private:
+ void processWork();
+ class WorkQueueTask: public MethodTask<WorkQueue> {
+ public:
+ WorkQueueTask(WorkQueue* object): MethodTask<WorkQueue>(object) {}
+ virtual void runIfValid() { m_object->processWork(); }
+ };
+
+ TaskList m_taskList;
+ 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);
+ class NotifyDoneTimedOutTask: public MethodTask<LayoutTestController> {
+ public:
+ NotifyDoneTimedOutTask(LayoutTestController* object): MethodTask<LayoutTestController>(object) {}
+ virtual void runIfValid() { m_object->completeNotifyDone(true); }
+ };
+
+
+ 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();
+ void suspendAnimations();
+ void resumeAnimations();
+
+ // Used for test timeouts.
+ TaskList m_taskList;
+
+ // 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 line of the user gesture status
+ // text for some frame load callbacks.
+ bool m_dumpUserGestureInFrameLoadCallbacks;
+
+ // If true, the test_shell will output a descriptive line for each resource
+ // load callback.
+ bool m_dumpResourceLoadCallbacks;
+
+ // If true, the test_shell will output the MIME type for each resource that
+ // was loaded.
+ bool m_dumpResourceResponseMIMETypes;
+
+ // 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 test_shell will generate pixel results in dumpAsText mode
+ bool m_generatePixelResults;
+
+ // 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;
+
+ // If false, all new requests will not defer the main resource data load.
+ bool m_deferMainResourceDataLoad;
+
+ WorkQueue m_workQueue;
+
+ CppVariant m_globalFlag;
+
+ // Bound variable counting the number of top URLs visited.
+ CppVariant m_webHistoryItemCount;
+
+ WebKit::WebURL m_userStyleSheetLocation;
+
+ OwnPtr<WebKit::WebSpeechInputControllerMock> m_speechInputControllerMock;
+};
+
+#endif // LayoutTestController_h
diff --git a/Tools/DumpRenderTree/chromium/LayoutTestHelper.mm b/Tools/DumpRenderTree/chromium/LayoutTestHelper.mm
new file mode 100644
index 0000000..e34cf5f
--- /dev/null
+++ b/Tools/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/Tools/DumpRenderTree/chromium/LayoutTestHelperWin.cpp b/Tools/DumpRenderTree/chromium/LayoutTestHelperWin.cpp
new file mode 100644
index 0000000..25efdcd
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/LayoutTestHelperWin.cpp
@@ -0,0 +1,84 @@
+/*
+ * 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 <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <windows.h>
+
+static BOOL fontSmoothingEnabled = FALSE;
+
+static void saveInitialSettings(void)
+{
+ ::SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &fontSmoothingEnabled, 0);
+}
+
+// Technically, all we need to do is disable ClearType. However,
+// for some reason, the call to SPI_SETFONTSMOOTHINGTYPE doesn't
+// seem to work, so we just disable font smoothing all together
+// (which works reliably)
+static void installLayoutTestSettings(void)
+{
+ ::SystemParametersInfo(SPI_SETFONTSMOOTHING, FALSE, 0, 0);
+}
+
+static void restoreInitialSettings(void)
+{
+ ::SystemParametersInfo(SPI_SETFONTSMOOTHING, static_cast<UINT>(fontSmoothingEnabled), 0, 0);
+}
+
+static void simpleSignalHandler(int signalNumber)
+{
+ // Try to restore the settings and then go down cleanly
+ restoreInitialSettings();
+ exit(128 + signalNumber);
+}
+
+int main(int, char*[])
+{
+ // Hooks the ways we might get told to clean up...
+ signal(SIGINT, simpleSignalHandler);
+ signal(SIGTERM, simpleSignalHandler);
+
+ saveInitialSettings();
+
+ installLayoutTestSettings();
+
+ // Let the script know we're ready
+ printf("ready\n");
+ fflush(stdout);
+
+ // Wait for any key (or signal)
+ getchar();
+
+ restoreInitialSettings();
+
+ return EXIT_SUCCESS;
+}
diff --git a/Tools/DumpRenderTree/chromium/MockSpellCheck.cpp b/Tools/DumpRenderTree/chromium/MockSpellCheck.cpp
new file mode 100644
index 0000000..7243152
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/MockSpellCheck.cpp
@@ -0,0 +1,156 @@
+/*
+ * 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 "WebString.h"
+#include <wtf/ASCIICType.h>
+#include <wtf/Assertions.h>
+#include <wtf/text/WTFString.h>
+
+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 WTF::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.)
+ WTF::String word = stringText.substring(wordOffset, wordLength);
+ if (!m_misspelledWords.contains(word))
+ return true;
+
+ *misspelledOffset = wordOffset;
+ *misspelledLength = wordLength;
+ return false;
+}
+
+void MockSpellCheck::fillSuggestionList(const WebString& word, Vector<WebString>* suggestions)
+{
+ if (word == WebString::fromUTF8("wellcome"))
+ suggestions->append(WebString::fromUTF8("welcome"));
+}
+
+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",
+ "wellcome"
+ };
+
+ m_misspelledWords.clear();
+ for (size_t i = 0; i < arraysize(misspelledWords); ++i)
+ m_misspelledWords.add(WTF::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/Tools/DumpRenderTree/chromium/MockSpellCheck.h b/Tools/DumpRenderTree/chromium/MockSpellCheck.h
new file mode 100644
index 0000000..dcd37f3
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/MockSpellCheck.h
@@ -0,0 +1,83 @@
+/*
+ * 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);
+
+ void fillSuggestionList(const WebKit::WebString& word, Vector<WebKit::WebString>* suggestions);
+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<WTF::String, bool> m_misspelledWords;
+
+ // A flag representing whether or not this object is initialized.
+ bool m_initialized;
+};
+
+#endif // MockSpellCheck_h
diff --git a/Tools/DumpRenderTree/chromium/NotificationPresenter.cpp b/Tools/DumpRenderTree/chromium/NotificationPresenter.cpp
new file mode 100644
index 0000000..7e7053b
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/NotificationPresenter.cpp
@@ -0,0 +1,148 @@
+/*
+ * 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 "NotificationPresenter.h"
+
+#include "WebKit.h"
+#include "WebKitClient.h"
+#include "WebNotification.h"
+#include "WebNotificationPermissionCallback.h"
+#include "WebSecurityOrigin.h"
+#include "WebString.h"
+#include "WebURL.h"
+#include "googleurl/src/gurl.h"
+#include <wtf/text/CString.h>
+#include <wtf/text/WTFString.h>
+
+using namespace WebKit;
+
+static WebString identifierForNotification(const WebNotification& notification)
+{
+ if (notification.isHTML())
+ return notification.url().spec().utf16();
+ return notification.title();
+}
+
+static void deferredDisplayDispatch(void* context)
+{
+ WebNotification* notification = static_cast<WebNotification*>(context);
+ notification->dispatchDisplayEvent();
+ delete notification;
+}
+
+void NotificationPresenter::grantPermission(const WebString& origin)
+{
+ // Make sure it's in the form of an origin.
+ GURL url(origin);
+ m_allowedOrigins.add(WTF::String(url.GetOrigin().spec().c_str()));
+}
+
+bool NotificationPresenter::simulateClick(const WebString& title)
+{
+ WTF::String id(title.data(), title.length());
+ if (m_activeNotifications.find(id) == m_activeNotifications.end())
+ return false;
+
+ const WebNotification& notification = m_activeNotifications.find(id)->second;
+ WebNotification eventTarget(notification);
+ eventTarget.dispatchClickEvent();
+ return true;
+}
+
+// The output from all these methods matches what DumpRenderTree produces.
+bool NotificationPresenter::show(const WebNotification& notification)
+{
+ WebString identifier = identifierForNotification(notification);
+ if (!notification.replaceId().isEmpty()) {
+ WTF::String replaceId(notification.replaceId().data(), notification.replaceId().length());
+ if (m_replacements.find(replaceId) != m_replacements.end())
+ printf("REPLACING NOTIFICATION %s\n",
+ m_replacements.find(replaceId)->second.utf8().data());
+
+ m_replacements.set(replaceId, WTF::String(identifier.data(), identifier.length()));
+ }
+
+ if (notification.isHTML()) {
+ printf("DESKTOP NOTIFICATION: contents at %s\n",
+ notification.url().spec().data());
+ } else {
+ printf("DESKTOP NOTIFICATION:%s icon %s, title %s, text %s\n",
+ notification.dir() == "rtl" ? "(RTL)" : "",
+ notification.iconURL().isEmpty() ? "" :
+ notification.iconURL().spec().data(),
+ notification.title().isEmpty() ? "" :
+ notification.title().utf8().data(),
+ notification.body().isEmpty() ? "" :
+ notification.body().utf8().data());
+ }
+
+ WTF::String id(identifier.data(), identifier.length());
+ m_activeNotifications.set(id, notification);
+
+ webKitClient()->callOnMainThread(deferredDisplayDispatch, new WebNotification(notification));
+ return true;
+}
+
+void NotificationPresenter::cancel(const WebNotification& notification)
+{
+ WebString identifier = identifierForNotification(notification);
+ printf("DESKTOP NOTIFICATION CLOSED: %s\n", identifier.utf8().data());
+ WebNotification eventTarget(notification);
+ eventTarget.dispatchCloseEvent(false);
+
+ WTF::String id(identifier.data(), identifier.length());
+ m_activeNotifications.remove(id);
+}
+
+void NotificationPresenter::objectDestroyed(const WebKit::WebNotification& notification)
+{
+ WebString identifier = identifierForNotification(notification);
+ WTF::String id(identifier.data(), identifier.length());
+ m_activeNotifications.remove(id);
+}
+
+WebNotificationPresenter::Permission NotificationPresenter::checkPermission(const WebURL& url)
+{
+ // Check with the layout test controller
+ WTF::String origin = WTF::String(static_cast<GURL>(url).GetOrigin().spec().c_str());
+ bool allowed = m_allowedOrigins.find(origin) != m_allowedOrigins.end();
+ return allowed ? WebNotificationPresenter::PermissionAllowed
+ : WebNotificationPresenter::PermissionDenied;
+}
+
+void NotificationPresenter::requestPermission(
+ const WebSecurityOrigin& origin,
+ WebNotificationPermissionCallback* callback)
+{
+ printf("DESKTOP NOTIFICATION PERMISSION REQUESTED: %s\n",
+ origin.toString().utf8().data());
+ callback->permissionRequestComplete();
+}
diff --git a/Tools/DumpRenderTree/chromium/NotificationPresenter.h b/Tools/DumpRenderTree/chromium/NotificationPresenter.h
new file mode 100644
index 0000000..689a908
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/NotificationPresenter.h
@@ -0,0 +1,77 @@
+/*
+ * 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 NotificationPresenter_h
+#define NotificationPresenter_h
+
+#include "WebNotification.h"
+#include "WebNotificationPresenter.h"
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#include <wtf/text/StringHash.h>
+#include <wtf/text/WTFString.h>
+
+class TestShell;
+
+// A class that implements WebNotificationPresenter for DRT.
+class NotificationPresenter : public WebKit::WebNotificationPresenter {
+public:
+ explicit NotificationPresenter(TestShell* shell) : m_shell(shell) {}
+
+ // Called by the LayoutTestController to simulate a user granting permission.
+ void grantPermission(const WebKit::WebString& origin);
+
+ // Called by the LayoutTestController to simulate a user clicking on a notification.
+ bool simulateClick(const WebKit::WebString& notificationIdentifier);
+
+ // WebKit::WebNotificationPresenter interface
+ virtual bool show(const WebKit::WebNotification&);
+ virtual void cancel(const WebKit::WebNotification&);
+ virtual void objectDestroyed(const WebKit::WebNotification&);
+ virtual Permission checkPermission(const WebKit::WebURL&);
+ virtual void requestPermission(const WebKit::WebSecurityOrigin&, WebKit::WebNotificationPermissionCallback*);
+
+ void reset() { m_allowedOrigins.clear(); }
+
+private:
+ // Non-owned pointer. The NotificationPresenter is owned by the test shell.
+ TestShell* m_shell;
+
+ // Set of allowed origins.
+ HashSet<WTF::String> m_allowedOrigins;
+
+ // Map of active notifications.
+ HashMap<WTF::String, WebKit::WebNotification> m_activeNotifications;
+
+ // Map of active replacement IDs to the titles of those notifications
+ HashMap<WTF::String, WTF::String> m_replacements;
+};
+
+#endif // NotificationPresenter_h
diff --git a/Tools/DumpRenderTree/chromium/PlainTextController.cpp b/Tools/DumpRenderTree/chromium/PlainTextController.cpp
new file mode 100644
index 0000000..c8bdabd
--- /dev/null
+++ b/Tools/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 "WebBindings.h"
+#include "WebRange.h"
+#include "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/Tools/DumpRenderTree/chromium/PlainTextController.h b/Tools/DumpRenderTree/chromium/PlainTextController.h
new file mode 100644
index 0000000..3d3a04c
--- /dev/null
+++ b/Tools/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/Tools/DumpRenderTree/chromium/Task.cpp b/Tools/DumpRenderTree/chromium/Task.cpp
new file mode 100644
index 0000000..007a479
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/Task.cpp
@@ -0,0 +1,75 @@
+/*
+ * 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 "Task.h"
+
+#include "WebKit.h"
+#include "WebKitClient.h"
+#include "webkit/support/webkit_support.h"
+
+WebTask::WebTask(TaskList* list): m_taskList(list) { m_taskList->registerTask(this); }
+WebTask::~WebTask()
+{
+ if (m_taskList)
+ m_taskList->unregisterTask(this);
+}
+
+void TaskList::unregisterTask(WebTask* task)
+{
+ size_t index = m_tasks.find(task);
+ if (index != notFound)
+ m_tasks.remove(index);
+}
+
+void TaskList::revokeAll()
+{
+ while (!m_tasks.isEmpty())
+ m_tasks[0]->cancel();
+}
+
+static void invokeTask(void* context)
+{
+ WebTask* task = static_cast<WebTask*>(context);
+ task->run();
+ delete task;
+}
+
+void postTask(WebTask* task)
+{
+ WebKit::webKitClient()->callOnMainThread(invokeTask, static_cast<void*>(task));
+}
+
+void postDelayedTask(WebTask* task, int64_t ms)
+{
+ webkit_support::PostDelayedTask(invokeTask, static_cast<void*>(task), ms);
+}
+
+
diff --git a/Tools/DumpRenderTree/chromium/Task.h b/Tools/DumpRenderTree/chromium/Task.h
new file mode 100644
index 0000000..f29dc7d
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/Task.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 Task_h
+#define Task_h
+
+#include <wtf/Vector.h>
+
+class TaskList;
+
+// WebTask represents a task which can run by postTask() or postDelayedTask().
+// it is named "WebTask", not "Task", to avoid conflist with base/task.h.
+class WebTask {
+public:
+ WebTask(TaskList*);
+ // The main code of this task.
+ // An implementation of run() should return immediately if cancel() was called.
+ virtual void run() = 0;
+ virtual void cancel() = 0;
+ virtual ~WebTask();
+protected:
+ TaskList* m_taskList;
+};
+
+class TaskList {
+public:
+ TaskList() {}
+ ~TaskList() { revokeAll(); }
+ void registerTask(WebTask* task) { m_tasks.append(task); }
+ void unregisterTask(WebTask* task);
+ void revokeAll();
+private:
+ Vector<WebTask*> m_tasks;
+};
+
+// A task containing an object pointer of class T. Is is supposed that
+// runifValid() calls a member function of the object pointer.
+// Class T must have "TaskList* taskList()".
+template<class T> class MethodTask: public WebTask {
+public:
+ MethodTask(T* object): WebTask(object->taskList()), m_object(object) {}
+ virtual void run()
+ {
+ if (m_object)
+ runIfValid();
+ }
+ virtual void cancel()
+ {
+ m_object = 0;
+ m_taskList->unregisterTask(this);
+ m_taskList = 0;
+ }
+ virtual void runIfValid() = 0;
+protected:
+ T* m_object;
+};
+
+void postTask(WebTask* task);
+void postDelayedTask(WebTask* task, int64_t ms);
+
+#endif // Task_h
diff --git a/Tools/DumpRenderTree/chromium/TestEventPrinter.cpp b/Tools/DumpRenderTree/chromium/TestEventPrinter.cpp
new file mode 100644
index 0000000..2130534
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TestEventPrinter.cpp
@@ -0,0 +1,168 @@
+/*
+ * 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 "TestEventPrinter.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <wtf/Assertions.h>
+
+class DRTPrinter : public TestEventPrinter {
+public:
+ DRTPrinter() {}
+ void handleTestHeader(const char* url) const;
+ void handleTimedOut() const;
+ void handleTextHeader() const;
+ void handleTextFooter() const;
+ void handleImage(const char* actualHash, const char* expectedHash, const unsigned char* imageData, size_t imageSize, const char* fileName) const;
+ void handleImageFooter() const;
+ void handleTestFooter(bool dumpedAnything) const;
+};
+
+class TestShellPrinter : public TestEventPrinter {
+public:
+ TestShellPrinter() {}
+ void handleTestHeader(const char* url) const;
+ void handleTimedOut() const;
+ void handleTextHeader() const;
+ void handleTextFooter() const;
+ void handleImage(const char* actualHash, const char* expectedHash, const unsigned char* imageData, size_t imageSize, const char* fileName) const;
+ void handleImageFooter() const;
+ void handleTestFooter(bool dumpedAnything) const;
+};
+
+TestEventPrinter* TestEventPrinter::createDRTPrinter()
+{
+ return new DRTPrinter;
+}
+
+TestEventPrinter* TestEventPrinter::createTestShellPrinter()
+{
+ return new TestShellPrinter;
+}
+
+// ----------------------------------------------------------------
+
+void DRTPrinter::handleTestHeader(const char*) const
+{
+}
+
+void DRTPrinter::handleTimedOut() const
+{
+ fprintf(stderr, "FAIL: Timed out waiting for notifyDone to be called\n");
+ fprintf(stdout, "FAIL: Timed out waiting for notifyDone to be called\n");
+}
+
+void DRTPrinter::handleTextHeader() const
+{
+ printf("Content-Type: text/plain\n");
+}
+
+void DRTPrinter::handleTextFooter() const
+{
+ printf("#EOF\n");
+}
+
+void DRTPrinter::handleImage(const char* actualHash, const char* expectedHash, const unsigned char* imageData, size_t imageSize, const char*) const
+{
+ ASSERT(actualHash);
+ printf("\nActualHash: %s\n", actualHash);
+ if (expectedHash && expectedHash[0])
+ printf("\nExpectedHash: %s\n", expectedHash);
+ if (imageData && imageSize) {
+ printf("Content-Type: image/png\n");
+ // Printf formatting for size_t on 32-bit, 64-bit, and on Windows is hard so just cast to an int.
+ printf("Content-Length: %d\n", static_cast<int>(imageSize));
+ if (fwrite(imageData, 1, imageSize, stdout) != imageSize) {
+ fprintf(stderr, "Short write to stdout.\n");
+ exit(1);
+ }
+ }
+}
+
+void DRTPrinter::handleImageFooter() const
+{
+ printf("#EOF\n");
+}
+
+void DRTPrinter::handleTestFooter(bool) const
+{
+}
+
+// ----------------------------------------------------------------
+
+void TestShellPrinter::handleTestHeader(const char* url) const
+{
+ printf("#URL:%s\n", url);
+}
+
+void TestShellPrinter::handleTimedOut() const
+{
+ puts("#TEST_TIMED_OUT\n");
+}
+
+void TestShellPrinter::handleTextHeader() const
+{
+}
+
+void TestShellPrinter::handleTextFooter() const
+{
+}
+
+void TestShellPrinter::handleImage(const char* actualHash, const char*, const unsigned char* imageData, size_t imageSize, const char* fileName) const
+{
+ ASSERT(actualHash);
+ if (imageData && imageSize) {
+ ASSERT(fileName);
+ FILE* fp = fopen(fileName, "wb");
+ if (!fp) {
+ perror(fileName);
+ exit(EXIT_FAILURE);
+ }
+ if (fwrite(imageData, 1, imageSize, fp) != imageSize) {
+ perror(fileName);
+ fclose(fp);
+ exit(EXIT_FAILURE);
+ }
+ fclose(fp);
+ }
+ printf("#MD5:%s\n", actualHash);
+}
+
+void TestShellPrinter::handleImageFooter() const
+{
+}
+
+void TestShellPrinter::handleTestFooter(bool dumpedAnything) const
+{
+ if (dumpedAnything)
+ printf("#EOF\n");
+}
diff --git a/Tools/DumpRenderTree/chromium/TestEventPrinter.h b/Tools/DumpRenderTree/chromium/TestEventPrinter.h
new file mode 100644
index 0000000..fdbfd02
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TestEventPrinter.h
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+class TestEventPrinter {
+public:
+ static TestEventPrinter* createDRTPrinter();
+ static TestEventPrinter* createTestShellPrinter();
+
+ virtual void handleTestHeader(const char* url) const = 0;
+ virtual void handleTimedOut() const = 0;
+ virtual void handleTextHeader() const = 0;
+ virtual void handleTextFooter() const = 0;
+ virtual void handleImage(const char* actualHash, const char* expectedHash, const unsigned char* imageData, size_t imageSize, const char* fileName) const = 0;
+ virtual void handleImageFooter() const = 0;
+ virtual void handleTestFooter(bool dumpedAnything) const = 0;
+};
diff --git a/Tools/DumpRenderTree/chromium/TestNavigationController.cpp b/Tools/DumpRenderTree/chromium/TestNavigationController.cpp
new file mode 100644
index 0000000..9653c07
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TestNavigationController.cpp
@@ -0,0 +1,277 @@
+/*
+ * 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
+
+PassRefPtr<TestNavigationEntry> TestNavigationEntry::create()
+{
+ return adoptRef(new TestNavigationEntry);
+}
+
+PassRefPtr<TestNavigationEntry> TestNavigationEntry::create(
+ int pageID, const WebURL& url, const WebString& title, const WebString& targetFrame)
+{
+ return adoptRef(new TestNavigationEntry(pageID, url, title, targetFrame));
+}
+
+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.get();
+ 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.get()) {
+ // 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.clear();
+ } 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;
+ }
+
+ updateMaxPageID();
+}
+
+void TestNavigationController::discardPendingEntry()
+{
+ m_pendingEntry.clear();
+ 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(RefPtr<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];
+ }
+
+ if (m_host->navigate(*m_pendingEntry.get(), 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/Tools/DumpRenderTree/chromium/TestNavigationController.h b/Tools/DumpRenderTree/chromium/TestNavigationController.h
new file mode 100644
index 0000000..b671489
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TestNavigationController.h
@@ -0,0 +1,211 @@
+/*
+ * 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 "WebDataSource.h"
+#include "WebHistoryItem.h"
+#include "WebString.h"
+#include "WebURL.h"
+#include "webkit/support/webkit_support.h"
+#include <string>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+#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 RefCounted<TestNavigationEntry> {
+public:
+ static PassRefPtr<TestNavigationEntry> create();
+ static PassRefPtr<TestNavigationEntry> create(
+ int pageID,
+ const WebKit::WebURL&,
+ const WebKit::WebString& title,
+ const WebKit::WebString& targetFrame);
+
+ // Virtual to allow test_shell to extend the class.
+ virtual ~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:
+ TestNavigationEntry();
+ TestNavigationEntry(int pageID,
+ const WebKit::WebURL&,
+ const WebKit::WebString& title,
+ const WebKit::WebString& targetFrame);
+
+ // 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.
+ // 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. 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<RefPtr<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.
+ RefPtr<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/Tools/DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npapi.h b/Tools/DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npapi.h
new file mode 100644
index 0000000..9fa3fff
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npapi.h
@@ -0,0 +1,9 @@
+#include "bindings/npapi.h"
+
+// These are defined in WebCore/brdige/npapi.h and we need them on Linux/Win.
+#ifndef FALSE
+#define FALSE (0)
+#endif
+#ifndef TRUE
+#define TRUE (1)
+#endif
diff --git a/Tools/DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npfunctions.h b/Tools/DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npfunctions.h
new file mode 100644
index 0000000..59ae666
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npfunctions.h
@@ -0,0 +1,8 @@
+#include "npapi.h"
+#include "bindings/npfunctions.h"
+
+// Non-standard event types can be passed to HandleEvent.
+// npapi.h that comes with WebKit.framework adds these events.
+#define getFocusEvent (osEvt + 16)
+#define loseFocusEvent (osEvt + 17)
+#define adjustCursorEvent (osEvt + 18)
diff --git a/Tools/DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npruntime.h b/Tools/DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npruntime.h
new file mode 100644
index 0000000..597d4ad
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npruntime.h
@@ -0,0 +1 @@
+#include "bindings/npruntime.h"
diff --git a/Tools/DumpRenderTree/chromium/TestNetscapePlugIn/Info.plist b/Tools/DumpRenderTree/chromium/TestNetscapePlugIn/Info.plist
new file mode 100644
index 0000000..663f058
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TestNetscapePlugIn/Info.plist
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>WebKitTestNetscapePlugIn</string>
+ <key>CFBundleGetInfoString</key>
+ <string>420+, Copyright 2006-2009 Apple Inc.</string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>com.apple.testnetscapeplugin</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>BRPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+ <key>CFPlugInDynamicRegisterFunction</key>
+ <string></string>
+ <key>CFPlugInDynamicRegistration</key>
+ <string>NO</string>
+ <key>CFPlugInFactories</key>
+ <dict>
+ <key>00000000-0000-0000-0000-000000000000</key>
+ <string>MyFactoryFunction</string>
+ </dict>
+ <key>CFPlugInTypes</key>
+ <dict>
+ <key>00000000-0000-0000-0000-000000000000</key>
+ <array>
+ <string>00000000-0000-0000-0000-000000000000</string>
+ </array>
+ </dict>
+ <key>CFPlugInUnloadFunction</key>
+ <string></string>
+ <key>WebPluginDescription</key>
+ <string>Simple Netscape plug-in that handles test content for WebKit</string>
+ <key>WebPluginMIMETypes</key>
+ <dict>
+ <key>application/x-webkit-test-netscape</key>
+ <dict>
+ <key>WebPluginExtensions</key>
+ <array>
+ <string>testnetscape</string>
+ </array>
+ <key>WebPluginTypeDescription</key>
+ <string>test netscape content</string>
+ </dict>
+ </dict>
+ <key>WebPluginName</key>
+ <string>WebKit Test PlugIn</string>
+</dict>
+</plist>
diff --git a/Tools/DumpRenderTree/chromium/TestShell.cpp b/Tools/DumpRenderTree/chromium/TestShell.cpp
new file mode 100644
index 0000000..21f4208
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TestShell.cpp
@@ -0,0 +1,621 @@
+/*
+ * 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 "DRTDevToolsAgent.h"
+#include "DRTDevToolsClient.h"
+#include "LayoutTestController.h"
+#include "WebDataSource.h"
+#include "WebDocument.h"
+#include "WebElement.h"
+#include "WebFrame.h"
+#include "WebHistoryItem.h"
+#include "WebKit.h"
+#include "WebRuntimeFeatures.h"
+#include "WebScriptController.h"
+#include "WebSettings.h"
+#include "WebSize.h"
+#include "WebSpeechInputControllerMock.h"
+#include "WebString.h"
+#include "WebURLRequest.h"
+#include "WebURLResponse.h"
+#include "WebView.h"
+#include "WebViewHost.h"
+#include "skia/ext/bitmap_platform_device.h"
+#include "skia/ext/platform_canvas.h"
+#include "webkit/support/webkit_support.h"
+#include "webkit/support/webkit_support_gfx.h"
+#include <algorithm>
+#include <cctype>
+#include <vector>
+#include <wtf/MD5.h>
+
+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(bool testShellMode)
+ : m_testIsPending(false)
+ , m_testIsPreparing(false)
+ , m_focusedWidget(0)
+ , m_testShellMode(testShellMode)
+ , m_devTools(0)
+ , m_allowExternalPages(false)
+ , m_acceleratedCompositingEnabled(false)
+ , m_accelerated2dCanvasEnabled(false)
+ , m_loadCount(1)
+ , m_dumpWhenFinished(true)
+{
+ WebRuntimeFeatures::enableGeolocation(true);
+ WebRuntimeFeatures::enableIndexedDatabase(true);
+ WebRuntimeFeatures::enableFileSystem(true);
+ 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_notificationPresenter.set(new NotificationPresenter(this));
+ m_printer.set(m_testShellMode ? TestEventPrinter::createTestShellPrinter() : TestEventPrinter::createDRTPrinter());
+
+ // 30 second is the same as the value in Mac DRT.
+ // If we use a value smaller than the timeout value of
+ // (new-)run-webkit-tests, (new-)run-webkit-tests misunderstands that a
+ // timed-out DRT process was crashed.
+ m_timeout = 30 * 1000;
+
+ m_drtDevToolsAgent.set(new DRTDevToolsAgent);
+ m_webViewHost = createWebView();
+ m_webView = m_webViewHost->webView();
+ m_drtDevToolsAgent->setWebView(m_webView);
+}
+
+TestShell::~TestShell()
+{
+ // Note: DevTools are closed together with all the other windows in the
+ // windows list.
+
+ // Destroy the WebView before its WebViewHost.
+ m_drtDevToolsAgent->setWebView(0);
+}
+
+void TestShell::createDRTDevToolsClient(DRTDevToolsAgent* agent)
+{
+ m_drtDevToolsClient.set(new DRTDevToolsClient(agent, m_devTools->webView()));
+}
+
+void TestShell::showDevTools()
+{
+ if (!m_devTools) {
+ WebURL url = webkit_support::GetDevToolsPathAsURL();
+ if (!url.isValid()) {
+ ASSERT(false);
+ return;
+ }
+ m_devTools = createNewWindow(url);
+ ASSERT(m_devTools);
+ createDRTDevToolsClient(m_drtDevToolsAgent.get());
+ }
+ m_devTools->show(WebKit::WebNavigationPolicyNewWindow);
+}
+
+void TestShell::closeDevTools()
+{
+ if (m_devTools) {
+ m_drtDevToolsAgent->reset();
+ m_drtDevToolsClient.clear();
+ closeWindow(m_devTools);
+ m_devTools = 0;
+ }
+}
+
+void TestShell::resetWebSettings(WebView& webView)
+{
+ m_prefs.reset();
+ m_prefs.acceleratedCompositingEnabled = m_acceleratedCompositingEnabled;
+ m_prefs.accelerated2dCanvasEnabled = m_accelerated2dCanvasEnabled;
+ m_prefs.applyTo(&webView);
+}
+
+void TestShell::runFileTest(const TestParams& params)
+{
+ ASSERT(params.testUrl.isValid());
+ 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_prefs.developerExtrasEnabled = inspectorTestMode;
+ applyPreferences();
+
+ if (testUrl.find("loading/") != string::npos
+ || testUrl.find("loading\\") != string::npos)
+ m_layoutTestController->setShouldDumpFrameLoadCallbacks(true);
+
+ if (inspectorTestMode)
+ showDevTools();
+
+ if (m_dumpWhenFinished)
+ m_printer->handleTestHeader(testUrl.c_str());
+ 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()
+{
+ resetWebSettings(*webView());
+ m_accessibilityController->reset();
+ m_layoutTestController->reset();
+ m_eventSender->reset();
+ m_webViewHost->reset();
+ m_notificationPresenter->reset();
+ m_drtDevToolsAgent->reset();
+ if (m_drtDevToolsClient)
+ m_drtDevToolsClient->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;
+ if (m_dumpWhenFinished)
+ dump();
+ webkit_support::QuitMessageLoop();
+}
+
+void TestShell::testTimedOut()
+{
+ m_printer->handleTimedOut();
+ 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 = webkit_support::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 shouldGeneratePixelResults = m_layoutTestController->shouldGeneratePixelResults();
+ bool dumpedAnything = false;
+ if (m_params.dumpTree) {
+ dumpedAnything = true;
+ m_printer->handleTextHeader();
+ // 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();
+ if (mimeType == "text/plain") {
+ shouldDumpAsText = true;
+ shouldGeneratePixelResults = false;
+ }
+ }
+ 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)
+ m_printer->handleTextFooter();
+
+ if (m_params.dumpPixels && shouldGeneratePixelResults) {
+ // 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);
+ }
+ }
+
+ dumpImage(m_webViewHost->canvas());
+ }
+ m_printer->handleImageFooter();
+ m_printer->handleTestFooter(dumpedAnything);
+ fflush(stdout);
+ fflush(stderr);
+}
+
+void TestShell::dumpImage(skia::PlatformCanvas* canvas) const
+{
+ 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 match Windows.
+#if OS(MAC_OS_X)
+ bool discardTransparency = false;
+#else
+ bool discardTransparency = true;
+ device.makeOpaque(0, 0, sourceBitmap.width(), sourceBitmap.height());
+#endif
+
+ // Compute MD5 sum.
+ MD5 digester;
+ Vector<uint8_t, 16> digestValue;
+ digester.addBytes(reinterpret_cast<const uint8_t*>(sourceBitmap.getPixels()), sourceBitmap.getSize());
+ digester.checksum(digestValue);
+ string md5hash;
+ md5hash.reserve(16 * 2);
+ for (unsigned i = 0; i < 16; ++i) {
+ char hex[3];
+ // Use "x", not "X". The string must be lowercased.
+ sprintf(hex, "%02x", digestValue[i]);
+ md5hash.append(hex);
+ }
+
+ // Only encode and dump the png if the hashes don't match. Encoding the image
+ // is really expensive.
+ if (md5hash.compare(m_params.pixelHash)) {
+ std::vector<unsigned char> png;
+ webkit_support::EncodeBGRAPNG(
+ reinterpret_cast<const unsigned char*>(sourceBitmap.getPixels()),
+ sourceBitmap.width(), sourceBitmap.height(),
+ static_cast<int>(sourceBitmap.rowBytes()), discardTransparency, &png);
+
+ m_printer->handleImage(md5hash.c_str(), m_params.pixelHash.c_str(), &png[0], png.size(), m_params.pixelFileName.c_str());
+ } else
+ m_printer->handleImage(md5hash.c_str(), m_params.pixelHash.c_str(), 0, 0, m_params.pixelFileName.c_str());
+}
+
+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"));
+}
+
+WebViewHost* TestShell::createWebView()
+{
+ return createNewWindow(WebURL());
+}
+
+WebViewHost* TestShell::createNewWindow(const WebURL& url)
+{
+ WebViewHost* host = new WebViewHost(this);
+ WebView* view = WebView::create(host, m_drtDevToolsAgent.get());
+ host->setWebWidget(view);
+ m_prefs.applyTo(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);
+ WebWidget* focusedWidget = m_focusedWidget;
+ if (window->webWidget() == m_focusedWidget)
+ focusedWidget = 0;
+
+ delete window;
+ // We set the focused widget after deleting the web view host because it
+ // can change the focus.
+ m_focusedWidget = focusedWidget;
+ if (m_focusedWidget) {
+ webView()->setIsActive(true);
+ m_focusedWidget->setFocus(true);
+ }
+}
+
+void TestShell::closeRemainingWindows()
+{
+ // Just close devTools window manually because we have custom deinitialization code for it.
+ closeDevTools();
+
+ // Iterate through the window list and close everything except the main
+ // window. 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/Tools/DumpRenderTree/chromium/TestShell.h b/Tools/DumpRenderTree/chromium/TestShell.h
new file mode 100644
index 0000000..1da4e17
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TestShell.h
@@ -0,0 +1,221 @@
+/*
+ * 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 TestShell_h
+#define TestShell_h
+
+#include "AccessibilityController.h"
+#include "EventSender.h"
+#include "LayoutTestController.h"
+#include "NotificationPresenter.h"
+#include "PlainTextController.h"
+#include "TestEventPrinter.h"
+#include "TextInputController.h"
+#include "WebPreferences.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 WebDevToolsAgentClient;
+class WebFrame;
+class WebNotificationPresenter;
+class WebView;
+class WebURL;
+}
+namespace skia {
+class PlatformCanvas;
+}
+
+class DRTDevToolsAgent;
+class DRTDevToolsCallArgs;
+class DRTDevToolsClient;
+
+struct TestParams {
+ bool dumpTree;
+ bool dumpPixels;
+ bool printSeparators;
+ WebKit::WebURL testUrl;
+ // Resultant image file name. Required only if the test_shell mode.
+ std::string pixelFileName;
+ std::string pixelHash;
+
+ TestParams()
+ : dumpTree(true)
+ , dumpPixels(false)
+ , printSeparators(false) {}
+};
+
+class TestShell {
+public:
+ TestShell(bool testShellMode);
+ ~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(); }
+ EventSender* eventSender() const { return m_eventSender.get(); }
+ AccessibilityController* accessibilityController() const { return m_accessibilityController.get(); }
+ NotificationPresenter* notificationPresenter() const { return m_notificationPresenter.get(); }
+ TestEventPrinter* printer() const { return m_printer.get(); }
+
+ WebPreferences* preferences() { return &m_prefs; }
+ void applyPreferences() { m_prefs.applyTo(m_webView); }
+
+ 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 shouldDumpUserGestureInFrameLoadCallbacks() const { return (m_testIsPreparing || m_testIsPending) && layoutTestController()->shouldDumpUserGestureInFrameLoadCallbacks(); }
+ bool shouldDumpResourceLoadCallbacks() const { return (m_testIsPreparing || m_testIsPending) && layoutTestController()->shouldDumpResourceLoadCallbacks(); }
+ bool shouldDumpResourceResponseMIMETypes() const { return (m_testIsPreparing || m_testIsPending) && layoutTestController()->shouldDumpResourceResponseMIMETypes(); }
+ 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();
+
+ bool allowExternalPages() const { return m_allowExternalPages; }
+ void setAllowExternalPages(bool allowExternalPages) { m_allowExternalPages = allowExternalPages; }
+
+ void setAcceleratedCompositingEnabled(bool enabled) { m_acceleratedCompositingEnabled = enabled; }
+ void setAccelerated2dCanvasEnabled(bool enabled) { m_accelerated2dCanvasEnabled = enabled; }
+
+#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.
+ int layoutTestTimeout() { return m_timeout; }
+ int layoutTestTimeoutForWatchDog() { return layoutTestTimeout() + 1000; }
+ void setLayoutTestTimeout(int timeout) { m_timeout = timeout; }
+
+ // Number of times to load each URL.
+ int loadCount() { return m_loadCount; }
+ void setLoadCount(int loadCount) { m_loadCount = loadCount; }
+
+ // The JavaScript flags are specified as a vector of strings. Each element of the vector is full flags string
+ // which can contain multiple flags (e.g. "--xxx --yyy"). With multiple load testing it is possible to specify
+ // separate sets of flags to each load.
+ std::string javaScriptFlagsForLoad(size_t load) { return (load < m_javaScriptFlags.size()) ? m_javaScriptFlags[load] : ""; }
+ void setJavaScriptFlags(Vector<std::string> javaScriptFlags) { m_javaScriptFlags = javaScriptFlags; }
+
+ // Set whether to dump when the loaded page has finished processing. This is used with multiple load
+ // testing where we only want to have the output from the last load.
+ void setDumpWhenFinished(bool dumpWhenFinished) { m_dumpWhenFinished = dumpWhenFinished; }
+
+ WebViewHost* createWebView();
+ WebViewHost* createNewWindow(const WebKit::WebURL&);
+ void closeWindow(WebViewHost*);
+ void closeRemainingWindows();
+ int windowCount();
+ static void resizeWindowForTest(WebViewHost*, const WebKit::WebURL&);
+
+ void showDevTools();
+ void closeDevTools();
+
+ DRTDevToolsAgent* drtDevToolsAgent() { return m_drtDevToolsAgent.get(); }
+ DRTDevToolsClient* drtDevToolsClient() { return m_drtDevToolsClient.get(); }
+ WebViewHost* devToolsWebView() { return m_devTools; }
+
+ static const int virtualWindowBorder = 3;
+
+private:
+ void createDRTDevToolsClient(DRTDevToolsAgent*);
+
+ void resetWebSettings(WebKit::WebView&);
+ void dump();
+ std::string dumpAllBackForwardLists();
+ void dumpImage(skia::PlatformCanvas*) const;
+
+ bool m_testIsPending;
+ bool m_testIsPreparing;
+ bool m_isLoading;
+ WebKit::WebView* m_webView;
+ WebKit::WebWidget* m_focusedWidget;
+ bool m_testShellMode;
+ WebViewHost* m_webViewHost;
+ WebViewHost* m_devTools;
+ OwnPtr<DRTDevToolsAgent> m_drtDevToolsAgent;
+ OwnPtr<DRTDevToolsClient> m_drtDevToolsClient;
+ OwnPtr<AccessibilityController> m_accessibilityController;
+ OwnPtr<EventSender> m_eventSender;
+ OwnPtr<LayoutTestController> m_layoutTestController;
+ OwnPtr<PlainTextController> m_plainTextController;
+ OwnPtr<TextInputController> m_textInputController;
+ OwnPtr<NotificationPresenter> m_notificationPresenter;
+ OwnPtr<TestEventPrinter> m_printer;
+ TestParams m_params;
+ int m_timeout; // timeout value in millisecond
+ bool m_allowExternalPages;
+ bool m_acceleratedCompositingEnabled;
+ bool m_accelerated2dCanvasEnabled;
+ WebPreferences m_prefs;
+ int m_loadCount;
+ Vector<std::string> m_javaScriptFlags;
+ bool m_dumpWhenFinished;
+
+
+ // 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
+};
+
+void platformInit(int*, char***);
+void openStartupDialog();
+bool checkLayoutTestSystemDependencies();
+
+#endif // TestShell_h
diff --git a/Tools/DumpRenderTree/chromium/TestShellGtk.cpp b/Tools/DumpRenderTree/chromium/TestShellGtk.cpp
new file mode 100644
index 0000000..1cf7c56
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TestShellGtk.cpp
@@ -0,0 +1,211 @@
+/*
+ * 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 <fontconfig/fontconfig.h>
+#include <gtk/gtk.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);
+}
+
+static void setupFontconfig()
+{
+ // We wish to make the layout tests reproducable with respect to fonts. Skia
+ // uses fontconfig to resolve font family names from WebKit into actual font
+ // files found on the current system. This means that fonts vary based on the
+ // system and also on the fontconfig configuration.
+ //
+ // To avoid this we initialise fontconfig here and install a configuration
+ // which only knows about a few, select, fonts.
+
+ // We have fontconfig parse a config file from our resources file. This
+ // sets a number of aliases ("sans"->"Arial" etc), but doesn't include any
+ // font directories.
+ FcInit();
+
+ char drtPath[PATH_MAX + 1];
+ int drtPathSize = readlink("/proc/self/exe", drtPath, PATH_MAX);
+ if (drtPathSize < 0 || drtPathSize > PATH_MAX) {
+ fputs("Unable to resolve /proc/self/exe.", stderr);
+ exit(1);
+ }
+ drtPath[drtPathSize] = 0;
+ std::string drtDirPath(drtPath);
+ size_t lastPathPos = drtDirPath.rfind("/");
+ ASSERT(lastPathPos != std::string::npos);
+ drtDirPath.erase(lastPathPos + 1);
+
+ FcConfig* fontcfg = FcConfigCreate();
+ std::string fontconfigPath = drtDirPath + "fonts.conf";
+ if (!FcConfigParseAndLoad(fontcfg, reinterpret_cast<const FcChar8*>(fontconfigPath.c_str()), true)) {
+ fputs("Failed to parse fontconfig config file\n", stderr);
+ exit(1);
+ }
+
+ // This is the list of fonts that fontconfig will know about. It
+ // will try its best to match based only on the fonts here in. The
+ // paths are where these fonts are found on our Ubuntu boxes.
+ static const char *const fonts[] = {
+ "/usr/share/fonts/truetype/kochi/kochi-gothic.ttf",
+ "/usr/share/fonts/truetype/kochi/kochi-mincho.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Arial.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Arial_Bold.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Arial_Bold_Italic.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Arial_Italic.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Comic_Sans_MS.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Comic_Sans_MS_Bold.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Courier_New.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Courier_New_Bold.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Courier_New_Bold_Italic.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Courier_New_Italic.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Georgia.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Georgia_Bold.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Georgia_Bold_Italic.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Georgia_Italic.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Impact.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Trebuchet_MS.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Trebuchet_MS_Bold.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Trebuchet_MS_Bold_Italic.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Trebuchet_MS_Italic.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Times_New_Roman.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Times_New_Roman_Bold.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Times_New_Roman_Bold_Italic.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Times_New_Roman_Italic.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Verdana.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Verdana_Bold.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Verdana_Bold_Italic.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Verdana_Italic.ttf",
+ // The DejaVuSans font is used by the css2.1 tests.
+ "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf",
+ "/usr/share/fonts/truetype/ttf-indic-fonts-core/lohit_ta.ttf",
+ "/usr/share/fonts/truetype/ttf-indic-fonts-core/MuktiNarrow.ttf",
+ };
+ for (size_t i = 0; i < arraysize(fonts); ++i) {
+ if (access(fonts[i], R_OK)) {
+ fprintf(stderr, "You are missing %s. Try installing msttcorefonts. Also see "
+ "http://code.google.com/p/chromium/wiki/LinuxBuildInstructions",
+ fonts[i]);
+ exit(1);
+ }
+ if (!FcConfigAppFontAddFile(fontcfg, (FcChar8 *) fonts[i])) {
+ fprintf(stderr, "Failed to load font %s\n", fonts[i]);
+ exit(1);
+ }
+ }
+
+ // We special case these fonts because they're only needed in a
+ // few layout tests.
+ static const char* const optionalFonts[] = {
+ "/usr/share/fonts/truetype/ttf-lucida/LucidaSansRegular.ttf",
+ "/usr/share/fonts/truetype/ttf-indic-fonts-core/lohit_pa.ttf",
+ };
+ for (size_t i = 0; i < arraysize(optionalFonts); ++i) {
+ const char* font = optionalFonts[i];
+
+ // This font changed paths across Ubuntu releases, so try checking in both locations.
+ if (!strcmp(font, "/usr/share/fonts/truetype/ttf-indic-fonts-core/lohit_pa.ttf")
+ && access(font, R_OK) < 0)
+ font = "/usr/share/fonts/truetype/ttf-punjabi-fonts/lohit_pa.ttf";
+
+ if (access(font, R_OK) < 0) {
+ fprintf(stderr, "You are missing %s. Without this, some layout tests may fail. "
+ "See http://code.google.com/p/chromium/wiki/LinuxBuildInstructionsPrerequisites "
+ "for more.\n", font);
+ } else if (!FcConfigAppFontAddFile(fontcfg, (FcChar8 *) font)) {
+ fprintf(stderr, "Failed to load font %s\n", font);
+ exit(1);
+ }
+ }
+
+ // Also load the layout-test-specific "Ahem" font.
+ std::string ahemPath = drtDirPath + "AHEM____.TTF";
+ if (!FcConfigAppFontAddFile(fontcfg, reinterpret_cast<const FcChar8*>(ahemPath.c_str()))) {
+ fprintf(stderr, "Failed to load font %s\n", ahemPath.c_str());
+ exit(1);
+ }
+
+ if (!FcConfigSetCurrent(fontcfg)) {
+ fputs("Failed to set the default font configuration\n", stderr);
+ exit(1);
+ }
+}
+
+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);
+}
+
+void platformInit(int* argc, char*** argv)
+{
+ // FIXME: It's better call gtk_init() only when we run plugin tests.
+ // See http://groups.google.com/a/chromium.org/group/chromium-dev/browse_thread/thread/633ea167cde196ca#
+ gtk_init(argc, argv);
+
+ setupFontconfig();
+}
+
+void openStartupDialog()
+{
+ GtkWidget* dialog = gtk_message_dialog_new(
+ 0, GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "Attach to me?");
+ gtk_window_set_title(GTK_WINDOW(dialog), "DumpRenderTree");
+ gtk_dialog_run(GTK_DIALOG(dialog)); // Runs a nested message loop.
+ gtk_widget_destroy(dialog);
+}
+
+bool checkLayoutTestSystemDependencies()
+{
+ return true;
+}
diff --git a/Tools/DumpRenderTree/chromium/TestShellMac.mm b/Tools/DumpRenderTree/chromium/TestShellMac.mm
new file mode 100644
index 0000000..53ede56
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TestShellMac.mm
@@ -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.
+ */
+
+#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];
+}
+
+void platformInit(int*, char***)
+{
+}
+
+void openStartupDialog()
+{
+ // FIXME: This code doesn't work. Need NSApplication event loop?
+ NSAlert* alert = [[[NSAlert alloc] init] autorelease];
+ alert.messageText = @"Attach to me?";
+ alert.informativeText = @"This would probably be a good time to attach your debugger.";
+ [alert addButtonWithTitle:@"OK"];
+ [alert runModal];
+}
+
+bool checkLayoutTestSystemDependencies()
+{
+ return true;
+}
+
diff --git a/Tools/DumpRenderTree/chromium/TestShellWin.cpp b/Tools/DumpRenderTree/chromium/TestShellWin.cpp
new file mode 100644
index 0000000..3b3ddd9
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TestShellWin.cpp
@@ -0,0 +1,244 @@
+/*
+ * 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 "WebThemeEngineDRTWin.h"
+#include "webkit/support/webkit_support.h"
+#include <fcntl.h>
+#include <io.h>
+#include <list>
+#include <process.h>
+#include <shlwapi.h>
+#include <string>
+#include <sys/stat.h>
+#include <windows.h>
+
+#define SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(structName, member) \
+ offsetof(structName, member) + \
+ (sizeof static_cast<structName*>(0)->member)
+#define NONCLIENTMETRICS_SIZE_PRE_VISTA \
+ SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(NONCLIENTMETRICS, lfMessageFont)
+
+// Theme engine
+static WebThemeEngineDRTWin themeEngine;
+
+// 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>(shell->layoutTestTimeoutForWatchDog());
+ 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("\n#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);
+}
+
+void platformInit(int*, char***)
+{
+ // Set stdout/stderr binary mode.
+ _setmode(_fileno(stdout), _O_BINARY);
+ _setmode(_fileno(stderr), _O_BINARY);
+
+ // Set theme engine.
+ webkit_support::SetThemeEngine(&themeEngine);
+
+ // Load Ahem font.
+ // AHEM____.TTF is copied to the directory of DumpRenderTree.exe by WebKit.gyp.
+ WCHAR path[_MAX_PATH];
+ if (!::GetModuleFileName(0, path, _MAX_PATH)) {
+ fprintf(stderr, "Can't get the module path.\n");
+ exit(1);
+ }
+ ::PathRemoveFileSpec(path);
+ wcscat_s(path, _MAX_PATH, L"/AHEM____.TTF");
+ struct _stat ahemStat;
+ if (_wstat(path, &ahemStat) == -1) {
+ fprintf(stderr, "Can't access: '%S'\n", path);
+ exit(1);
+ }
+
+ FILE* fp = _wfopen(path, L"rb");
+ if (!fp) {
+ _wperror(path);
+ exit(1);
+ }
+ size_t size = ahemStat.st_size;
+ char* fontBuffer = new char[size];
+ if (fread(fontBuffer, 1, size, fp) != size) {
+ fprintf(stderr, "Can't read the font: '%S'\n", path);
+ fclose(fp);
+ exit(1);
+ }
+ fclose(fp);
+ DWORD numFonts = 1;
+ HANDLE fontHandle = ::AddFontMemResourceEx(fontBuffer, size, 0, &numFonts);
+ delete[] fontBuffer; // OS owns a copy of the buffer.
+ if (!fontHandle) {
+ fprintf(stderr, "Failed to register Ahem font: '%S'\n", path);
+ exit(1);
+ }
+ // We don't need to release the font explicitly.
+}
+
+void openStartupDialog()
+{
+ ::MessageBox(0, L"Attach to me?", L"DumpRenderTree", MB_OK);
+}
+
+bool checkLayoutTestSystemDependencies()
+{
+ std::list<std::string> errors;
+
+ OSVERSIONINFOEX versionInfo;
+ ::ZeroMemory(&versionInfo, sizeof(OSVERSIONINFOEX));
+ versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+ ::GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&versionInfo));
+
+ // Default to XP metrics, override if on Vista or win 7.
+ int requiredVScrollSize = 17;
+ int requiredFontSize = -11; // 8 pt
+ const wchar_t* requiredFont = L"Tahoma";
+ bool isVista = false;
+ bool isWin7 = false;
+ const DWORD major = versionInfo.dwMajorVersion;
+ const DWORD minor = versionInfo.dwMinorVersion;
+ const WORD type = versionInfo.wProductType;
+ if (major == 6 && minor == 1 && type == VER_NT_WORKSTATION) {
+ requiredFont = L"Segoe UI";
+ requiredFontSize = -12;
+ isWin7 = true;
+ } else if (major == 6 && !minor && type == VER_NT_WORKSTATION) {
+ requiredFont = L"Segoe UI";
+ requiredFontSize = -12; // 9 pt
+ isVista = true;
+ } else if (!(major == 5 && minor == 1 && type == VER_NT_WORKSTATION)) {
+ // The above check is for XP, so that means ...
+ errors.push_back("Unsupported Operating System version "
+ "(must use XP, Vista, or Windows 7).");
+ }
+
+ // This metric will be 17 when font size is "Normal".
+ // The size of drop-down menus depends on it.
+ int verticalScrollSize = ::GetSystemMetrics(SM_CXVSCROLL);
+ if (verticalScrollSize != requiredVScrollSize)
+ errors.push_back("Must use normal size fonts (96 dpi).");
+
+ // ClearType must be disabled, because the rendering is unpredictable.
+ BOOL fontSmoothingEnabled;
+ ::SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &fontSmoothingEnabled, 0);
+ int fontSmoothingType;
+ ::SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &fontSmoothingType, 0);
+ if (fontSmoothingEnabled && (fontSmoothingType == FE_FONTSMOOTHINGCLEARTYPE))
+ errors.push_back("ClearType must be disabled.");
+
+ // Check that we're using the default system fonts
+ NONCLIENTMETRICS metrics;
+ // Checks Vista or later.
+ metrics.cbSize = major >= 6 ? sizeof(NONCLIENTMETRICS) : NONCLIENTMETRICS_SIZE_PRE_VISTA;
+ const bool success = !!::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, metrics.cbSize, &metrics, 0);
+ ASSERT(success);
+ LOGFONTW* systemFonts[] =
+ {&metrics.lfStatusFont, &metrics.lfMenuFont, &metrics.lfSmCaptionFont};
+
+ for (size_t i = 0; i < arraysize(systemFonts); ++i) {
+ if (systemFonts[i]->lfHeight != requiredFontSize || wcscmp(requiredFont, systemFonts[i]->lfFaceName)) {
+ if (isVista || isWin7)
+ errors.push_back("Must use either the Aero or Basic theme.");
+ else
+ errors.push_back("Must use the default XP theme (Luna).");
+ break;
+ }
+ }
+
+ if (!errors.empty()) {
+ fprintf(stderr, "%s",
+ "##################################################################\n"
+ "## Layout test system dependencies check failed.\n"
+ "##\n");
+ for (std::list<std::string>::iterator it = errors.begin(); it != errors.end(); ++it)
+ fprintf(stderr, "## %s\n", it->c_str());
+ fprintf(stderr, "%s",
+ "##\n"
+ "##################################################################\n");
+ }
+ return errors.empty();
+}
diff --git a/Tools/DumpRenderTree/chromium/TestWebWorker.h b/Tools/DumpRenderTree/chromium/TestWebWorker.h
new file mode 100644
index 0000000..89e19af
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TestWebWorker.h
@@ -0,0 +1,93 @@
+/*
+ * 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 "WebMessagePortChannel.h"
+#include "WebWorker.h"
+#include "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()
+ {
+ // This class expects refcounting semantics like those found in
+ // Chromium's base::RefCounted, so it's OK to call ref() directly.
+ relaxAdoptionRequirement();
+ 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; }
+ virtual WebKit::WebApplicationCacheHost* createApplicationCacheHost(WebKit::WebApplicationCacheHostClient*) { return 0; }
+ virtual bool allowDatabase(WebKit::WebFrame*, const WebKit::WebString&, const WebKit::WebString&, unsigned long) { return true; }
+
+private:
+ ~TestWebWorker() {}
+ friend class WTF::RefCounted<TestWebWorker>;
+};
+
+#endif // TestWebWorker_h
diff --git a/Tools/DumpRenderTree/chromium/TextInputController.cpp b/Tools/DumpRenderTree/chromium/TextInputController.cpp
new file mode 100644
index 0000000..3603840
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TextInputController.cpp
@@ -0,0 +1,262 @@
+/*
+ * 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 "WebBindings.h"
+#include "WebCompositionUnderline.h"
+#include "WebFrame.h"
+#include "WebRange.h"
+#include "WebString.h"
+#include "WebVector.h"
+#include "WebView.h"
+#include <wtf/StringExtras.h>
+#include <string>
+
+using namespace WebKit;
+
+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("attributedSubstringFromRange", &TextInputController::attributedSubstringFromRange);
+ bindMethod("characterIndexForPoint", &TextInputController::characterIndexForPoint);
+ bindMethod("conversationIdentifier", &TextInputController::conversationIdentifier);
+ bindMethod("doCommand", &TextInputController::doCommand);
+ bindMethod("firstRectForCharacterRange", &TextInputController::firstRectForCharacterRange);
+ bindMethod("hasMarkedText", &TextInputController::hasMarkedText);
+ bindMethod("insertText", &TextInputController::insertText);
+ bindMethod("makeAttributedString", &TextInputController::makeAttributedString);
+ bindMethod("markedRange", &TextInputController::markedRange);
+ bindMethod("selectedRange", &TextInputController::selectedRange);
+ bindMethod("setMarkedText", &TextInputController::setMarkedText);
+ bindMethod("substringFromRange", &TextInputController::substringFromRange);
+ bindMethod("unmarkText", &TextInputController::unmarkText);
+ bindMethod("validAttributesForMarkedText", &TextInputController::validAttributesForMarkedText);
+ bindMethod("setComposition", &TextInputController::setComposition);
+}
+
+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();
+ Vector<int> intArray(2);
+ intArray[0] = range.startOffset();
+ intArray[1] = range.endOffset();
+ result->set(WebBindings::makeIntArray(intArray));
+}
+
+void TextInputController::selectedRange(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+
+ WebFrame* mainFrame = getMainFrame();
+ if (!mainFrame)
+ return;
+
+ WebRange range = mainFrame->selectionRange();
+ Vector<int> intArray(2);
+ intArray[0] = range.startOffset();
+ intArray[1] = range.endOffset();
+ result->set(WebBindings::makeIntArray(intArray));
+}
+
+void TextInputController::firstRectForCharacterRange(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ WebFrame* mainFrame = getMainFrame();
+ if (!mainFrame)
+ return;
+
+ if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isNumber())
+ return;
+
+ WebRect rect;
+ if (!mainFrame->firstRectForCharacterRange(arguments[0].toInt32(), arguments[1].toInt32(), rect))
+ return;
+
+ Vector<int> intArray(4);
+ intArray[0] = rect.x;
+ intArray[1] = rect.y;
+ intArray[2] = rect.width;
+ intArray[3] = rect.height;
+ result->set(WebBindings::makeIntArray(intArray));
+}
+
+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();
+}
+
+void TextInputController::setComposition(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ WebView* view = getMainFrame() ? getMainFrame()->view() : 0;
+ if (!view)
+ return;
+
+ if (arguments.size() < 1)
+ return;
+
+ // Sends a keydown event with key code = 0xE5 to emulate input method behavior.
+ WebKeyboardEvent keyDown;
+ keyDown.type = WebInputEvent::RawKeyDown;
+ keyDown.modifiers = 0;
+ keyDown.windowsKeyCode = 0xE5; // VKEY_PROCESSKEY
+ keyDown.setKeyIdentifierFromWindowsKeyCode();
+ view->handleInputEvent(keyDown);
+
+ WebVector<WebCompositionUnderline> underlines;
+ WebString text(WebString::fromUTF8(arguments[0].toString()));
+ view->setComposition(text, underlines, 0, text.length());
+}
diff --git a/Tools/DumpRenderTree/chromium/TextInputController.h b/Tools/DumpRenderTree/chromium/TextInputController.h
new file mode 100644
index 0000000..3a3907f
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TextInputController.h
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+// 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*);
+ void setComposition(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
diff --git a/Tools/DumpRenderTree/chromium/WebPreferences.cpp b/Tools/DumpRenderTree/chromium/WebPreferences.cpp
new file mode 100644
index 0000000..7c274c3
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/WebPreferences.cpp
@@ -0,0 +1,166 @@
+/*
+ * 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 "WebPreferences.h"
+
+#include "WebView.h"
+
+using namespace WebKit;
+
+void WebPreferences::reset()
+{
+#if OS(MAC_OS_X)
+ cursiveFontFamily = WebString::fromUTF8("Apple Chancery");
+ fantasyFontFamily = WebString::fromUTF8("Papyrus");
+ WebString serif = WebString::fromUTF8("Times");
+#else
+ // 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.
+ cursiveFontFamily = WebString::fromUTF8("Comic Sans MS");
+ fantasyFontFamily = WebString::fromUTF8("Impact");
+ // NOTE: case matters here, this must be 'times new roman', else
+ // some layout tests fail.
+ WebString serif = WebString::fromUTF8("times new roman");
+#endif
+ serifFontFamily = serif;
+ standardFontFamily = serif;
+ fixedFontFamily = WebString::fromUTF8("Courier");
+ sansSerifFontFamily = WebString::fromUTF8("Helvetica");
+
+ defaultFontSize = 16;
+ defaultFixedFontSize = 13;
+ minimumFontSize = 0;
+ minimumLogicalFontSize = 9;
+
+ DOMPasteAllowed = true;
+ XSSAuditorEnabled = false;
+ allowFileAccessFromFileURLs = true;
+ authorAndUserStylesEnabled = true;
+ defaultTextEncodingName = WebString::fromUTF8("ISO-8859-1");
+ developerExtrasEnabled = false;
+ experimentalWebGLEnabled = false;
+ javaEnabled = false;
+ javaScriptCanAccessClipboard = true;
+ javaScriptCanOpenWindowsAutomatically = true;
+ javaScriptEnabled = true;
+ loadsImagesAutomatically = true;
+ localStorageEnabled = true;
+ offlineWebApplicationCacheEnabled = true;
+ pluginsEnabled = true;
+ shrinksStandaloneImagesToFit = false;
+ textAreasAreResizable = false;
+ userStyleSheetLocation = WebURL();
+ usesPageCache = false;
+ webSecurityEnabled = true;
+ caretBrowsingEnabled = false;
+
+ // Allow those layout tests running as local files, i.e. under
+ // LayoutTests/http/tests/local, to access http server.
+ allowUniversalAccessFromFileURLs = true;
+
+#if OS(DARWIN)
+ editingBehavior = WebSettings::EditingBehaviorMac;
+#else
+ editingBehavior = WebSettings::EditingBehaviorWin;
+#endif
+
+ tabsToLinks = false;
+ hyperlinkAuditingEnabled = false;
+ acceleratedCompositingEnabled = false;
+ accelerated2dCanvasEnabled = false;
+}
+
+void WebPreferences::applyTo(WebView* webView)
+{
+ WebSettings* settings = webView->settings();
+ settings->setCursiveFontFamily(cursiveFontFamily);
+ settings->setFantasyFontFamily(fantasyFontFamily);
+ settings->setSerifFontFamily(serifFontFamily);
+ settings->setStandardFontFamily(standardFontFamily);
+ settings->setFixedFontFamily(fixedFontFamily);
+ settings->setSansSerifFontFamily(sansSerifFontFamily);
+
+ settings->setDefaultFontSize(defaultFontSize);
+ settings->setDefaultFixedFontSize(defaultFixedFontSize);
+ settings->setMinimumFontSize(minimumFontSize);
+ settings->setMinimumLogicalFontSize(minimumLogicalFontSize);
+
+ settings->setDOMPasteAllowed(DOMPasteAllowed);
+ settings->setXSSAuditorEnabled(XSSAuditorEnabled);
+ settings->setAllowFileAccessFromFileURLs(allowFileAccessFromFileURLs);
+ settings->setAuthorAndUserStylesEnabled(authorAndUserStylesEnabled);
+ settings->setDefaultTextEncodingName(defaultTextEncodingName);
+ settings->setDeveloperExtrasEnabled(developerExtrasEnabled);
+ settings->setExperimentalWebGLEnabled(experimentalWebGLEnabled);
+ settings->setJavaEnabled(javaEnabled);
+ settings->setJavaScriptCanAccessClipboard(javaScriptCanAccessClipboard);
+ settings->setJavaScriptCanOpenWindowsAutomatically(javaScriptCanOpenWindowsAutomatically);
+ settings->setJavaScriptEnabled(javaScriptEnabled);
+ settings->setLoadsImagesAutomatically(loadsImagesAutomatically);
+ settings->setLocalStorageEnabled(localStorageEnabled);
+ settings->setOfflineWebApplicationCacheEnabled(offlineWebApplicationCacheEnabled);
+ settings->setPluginsEnabled(pluginsEnabled);
+ settings->setShrinksStandaloneImagesToFit(shrinksStandaloneImagesToFit);
+ settings->setTextAreasAreResizable(textAreasAreResizable);
+ settings->setUserStyleSheetLocation(userStyleSheetLocation);
+ settings->setUsesPageCache(usesPageCache);
+ settings->setWebSecurityEnabled(webSecurityEnabled);
+ settings->setAllowUniversalAccessFromFileURLs(allowUniversalAccessFromFileURLs);
+ settings->setEditingBehavior(editingBehavior);
+ settings->setHyperlinkAuditingEnabled(hyperlinkAuditingEnabled);
+ // LayoutTests were written with Safari Mac in mind which does not allow
+ // tabbing to links by default.
+ webView->setTabsToLinks(tabsToLinks);
+ settings->setCaretBrowsingEnabled(caretBrowsingEnabled);
+
+ // Fixed values.
+ settings->setShouldPaintCustomScrollbars(true);
+ settings->setTextDirectionSubmenuInclusionBehaviorNeverIncluded();
+ settings->setDownloadableBinaryFontsEnabled(true);
+ settings->setAllowScriptsToCloseWindows(false);
+ settings->setNeedsSiteSpecificQuirks(true);
+ settings->setEditableLinkBehaviorNeverLive();
+ settings->setFontRenderingModeNormal();
+ settings->setTextDirectionSubmenuInclusionBehaviorNeverIncluded();
+ settings->setUsesEncodingDetector(false);
+ settings->setImagesEnabled(true);
+ settings->setAcceleratedCompositingEnabled(acceleratedCompositingEnabled);
+ settings->setAccelerated2dCanvasEnabled(accelerated2dCanvasEnabled);
+}
+
diff --git a/Tools/DumpRenderTree/chromium/WebPreferences.h b/Tools/DumpRenderTree/chromium/WebPreferences.h
new file mode 100644
index 0000000..46877c0
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/WebPreferences.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 WebPreferences_h
+#define WebPerferences_h
+
+#include "WebSettings.h"
+#include "WebString.h"
+#include "WebURL.h"
+
+namespace WebKit {
+class WebView;
+}
+
+struct WebPreferences {
+ WebKit::WebString cursiveFontFamily;
+ WebKit::WebString fantasyFontFamily;
+ WebKit::WebString serifFontFamily;
+ WebKit::WebString standardFontFamily;
+ WebKit::WebString fixedFontFamily;
+ WebKit::WebString sansSerifFontFamily;
+
+ int defaultFontSize;
+ int defaultFixedFontSize;
+ int minimumFontSize;
+ int minimumLogicalFontSize;
+
+ bool DOMPasteAllowed;
+ bool XSSAuditorEnabled;
+ bool allowFileAccessFromFileURLs;
+ bool authorAndUserStylesEnabled;
+ WebKit::WebString defaultTextEncodingName;
+ bool developerExtrasEnabled;
+ bool experimentalWebGLEnabled;
+ bool javaEnabled;
+ bool javaScriptCanAccessClipboard;
+ bool javaScriptCanOpenWindowsAutomatically;
+ bool javaScriptEnabled;
+ bool loadsImagesAutomatically;
+ bool localStorageEnabled;
+ bool offlineWebApplicationCacheEnabled;
+ bool pluginsEnabled;
+ bool shrinksStandaloneImagesToFit;
+ bool textAreasAreResizable;
+ WebKit::WebURL userStyleSheetLocation;
+ bool usesPageCache;
+ bool webSecurityEnabled;
+ bool allowUniversalAccessFromFileURLs;
+ WebKit::WebSettings::EditingBehavior editingBehavior;
+ bool tabsToLinks;
+ bool hyperlinkAuditingEnabled;
+ bool caretBrowsingEnabled;
+ bool acceleratedCompositingEnabled;
+ bool accelerated2dCanvasEnabled;
+
+ WebPreferences() { reset(); }
+ void reset();
+ void applyTo(WebKit::WebView*);
+};
+
+#endif // WebPreferences_h
diff --git a/Tools/DumpRenderTree/chromium/WebThemeControlDRTWin.cpp b/Tools/DumpRenderTree/chromium/WebThemeControlDRTWin.cpp
new file mode 100755
index 0000000..b1d9fa1
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/WebThemeControlDRTWin.cpp
@@ -0,0 +1,523 @@
+/*
+ * 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 implements a simple generic version of the WebThemeEngine,
+// which is used to draw all the native controls on a web page. We use this
+// file when running in layout test mode in order to remove any
+// platform-specific rendering differences due to themes, colors, etc.
+//
+
+#include "config.h"
+#include "WebThemeControlDRTWin.h"
+
+#include "skia/ext/platform_canvas.h"
+#include "skia/ext/skia_utils_win.h"
+#include "third_party/skia/include/core/SkPaint.h"
+#include "third_party/skia/include/core/SkPath.h"
+#include "third_party/skia/include/core/SkRect.h"
+
+#include <wtf/Assertions.h>
+
+using namespace std;
+using namespace skia;
+
+static const SkColor edgeColor = SK_ColorBLACK;
+static const SkColor readOnlyColor = SkColorSetRGB(0xe9, 0xc2, 0xa6);
+static const SkColor fgColor = SK_ColorBLACK;
+static const SkColor bgColors[] = {
+ SK_ColorBLACK, // Unknown
+ SkColorSetRGB(0xc9, 0xc9, 0xc9), // Disabled
+ SkColorSetRGB(0xf3, 0xe0, 0xd0), // Readonly
+ SkColorSetRGB(0x89, 0xc4, 0xff), // Normal
+ SkColorSetRGB(0x43, 0xf9, 0xff), // Hot
+ SkColorSetRGB(0x20, 0xf6, 0xcc), // Focused
+ SkColorSetRGB(0x00, 0xf3, 0xac), // Hover
+ SkColorSetRGB(0xa9, 0xff, 0x12), // Pressed
+ SkColorSetRGB(0xcc, 0xcc, 0xcc) // Indeterminate
+};
+
+static SkIRect validate(const SkIRect& rect, WebThemeControlDRTWin::Type ctype)
+{
+ switch (ctype) {
+ case WebThemeControlDRTWin::UncheckedBoxType:
+ case WebThemeControlDRTWin::CheckedBoxType:
+ case WebThemeControlDRTWin::UncheckedRadioType:
+ case WebThemeControlDRTWin::CheckedRadioType: {
+ SkIRect retval = rect;
+
+ // The maximum width and height is 13.
+ // Center the square in the passed rectangle.
+ const int maxControlSize = 13;
+ int controlSize = min(rect.width(), rect.height());
+ controlSize = min(controlSize, maxControlSize);
+
+ retval.fLeft = rect.fLeft + (rect.width() / 2) - (controlSize / 2);
+ retval.fRight = retval.fLeft + controlSize - 1;
+ retval.fTop = rect.fTop + (rect.height() / 2) - (controlSize / 2);
+ retval.fBottom = retval.fTop + controlSize - 1;
+
+ return retval;
+ }
+
+ default:
+ return rect;
+ }
+}
+
+// WebThemeControlDRTWin
+
+WebThemeControlDRTWin::WebThemeControlDRTWin(PlatformCanvas* canvas,
+ const SkIRect& irect,
+ Type ctype,
+ State cstate)
+ : m_canvas(canvas)
+ , m_irect(validate(irect, ctype))
+ , m_type(ctype)
+ , m_state(cstate)
+ , m_left(m_irect.fLeft)
+ , m_right(m_irect.fRight)
+ , m_top(m_irect.fTop)
+ , m_bottom(m_irect.fBottom)
+ , m_height(m_irect.height())
+ , m_width(m_irect.width())
+ , m_edgeColor(edgeColor)
+ , m_bgColor(bgColors[cstate])
+ , m_fgColor(fgColor)
+{
+}
+
+WebThemeControlDRTWin::~WebThemeControlDRTWin()
+{
+}
+
+void WebThemeControlDRTWin::box(const SkIRect& rect, SkColor fillColor)
+{
+ SkPaint paint;
+
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setColor(fillColor);
+ m_canvas->drawIRect(rect, paint);
+
+ paint.setColor(m_edgeColor);
+ paint.setStyle(SkPaint::kStroke_Style);
+ m_canvas->drawIRect(rect, paint);
+}
+
+void WebThemeControlDRTWin::line(int x0, int y0, int x1, int y1, SkColor color)
+{
+ SkPaint paint;
+ paint.setColor(color);
+ m_canvas->drawLine(SkIntToScalar(x0), SkIntToScalar(y0),
+ SkIntToScalar(x1), SkIntToScalar(y1),
+ paint);
+}
+
+void WebThemeControlDRTWin::triangle(int x0, int y0,
+ int x1, int y1,
+ int x2, int y2,
+ SkColor color)
+{
+ SkPath path;
+ SkPaint paint;
+
+ paint.setColor(color);
+ paint.setStyle(SkPaint::kFill_Style);
+ path.incReserve(4);
+ path.moveTo(SkIntToScalar(x0), SkIntToScalar(y0));
+ path.lineTo(SkIntToScalar(x1), SkIntToScalar(y1));
+ path.lineTo(SkIntToScalar(x2), SkIntToScalar(y2));
+ path.close();
+ m_canvas->drawPath(path, paint);
+
+ paint.setColor(m_edgeColor);
+ paint.setStyle(SkPaint::kStroke_Style);
+ m_canvas->drawPath(path, paint);
+}
+
+void WebThemeControlDRTWin::roundRect(SkColor color)
+{
+ SkRect rect;
+ SkScalar radius = SkIntToScalar(5);
+ SkPaint paint;
+
+ rect.set(m_irect);
+ paint.setColor(color);
+ paint.setStyle(SkPaint::kFill_Style);
+ m_canvas->drawRoundRect(rect, radius, radius, paint);
+
+ paint.setColor(m_edgeColor);
+ paint.setStyle(SkPaint::kStroke_Style);
+ m_canvas->drawRoundRect(rect, radius, radius, paint);
+}
+
+void WebThemeControlDRTWin::oval(SkColor color)
+{
+ SkRect rect;
+ SkPaint paint;
+
+ rect.set(m_irect);
+ paint.setColor(color);
+ paint.setStyle(SkPaint::kFill_Style);
+ m_canvas->drawOval(rect, paint);
+
+ paint.setColor(m_edgeColor);
+ paint.setStyle(SkPaint::kStroke_Style);
+ m_canvas->drawOval(rect, paint);
+}
+
+void WebThemeControlDRTWin::circle(SkScalar radius, SkColor color)
+{
+ SkScalar cy = SkIntToScalar(m_top + m_height / 2);
+ SkScalar cx = SkIntToScalar(m_left + m_width / 2);
+ SkPaint paint;
+
+ paint.setColor(color);
+ paint.setStyle(SkPaint::kFill_Style);
+ m_canvas->drawCircle(cx, cy, radius, paint);
+
+ paint.setColor(m_edgeColor);
+ paint.setStyle(SkPaint::kStroke_Style);
+ m_canvas->drawCircle(cx, cy, radius, paint);
+}
+
+void WebThemeControlDRTWin::nestedBoxes(int indentLeft,
+ int indentTop,
+ int indentRight,
+ int indentBottom,
+ SkColor outerColor,
+ SkColor innerColor)
+{
+ SkIRect lirect;
+ box(m_irect, outerColor);
+ lirect.set(m_irect.fLeft + indentLeft,
+ m_irect.fTop + indentTop,
+ m_irect.fRight - indentRight,
+ m_irect.fBottom - indentBottom);
+ box(lirect, innerColor);
+}
+
+void WebThemeControlDRTWin::markState()
+{
+ // The horizontal lines in a read only control are spaced by this amount.
+ const int readOnlyLineOffset = 5;
+
+ // The length of a triangle side for the corner marks.
+ const int triangleSize = 5;
+
+ switch (m_state) {
+ case UnknownState:
+ case DisabledState:
+ case NormalState:
+ // Don't visually mark these states (color is enough).
+ break;
+ case ReadOnlyState:
+ // Drawing lines across the control.
+ for (int i = m_top + readOnlyLineOffset; i < m_bottom; i += readOnlyLineOffset)
+ line(m_left + 1, i, m_right - 1, i, readOnlyColor);
+ break;
+
+ case HotState:
+ // Draw a triangle in the upper left corner of the control.
+ triangle(m_left, m_top,
+ m_left + triangleSize, m_top,
+ m_left, m_top + triangleSize, m_edgeColor);
+ break;
+
+ case HoverState:
+ // Draw a triangle in the upper right corner of the control.
+ triangle(m_right, m_top,
+ m_right, m_top + triangleSize,
+ m_right - triangleSize, m_top, m_edgeColor);
+ break;
+
+ case FocusedState:
+ // Draw a triangle in the bottom right corner of the control.
+ triangle(m_right, m_bottom,
+ m_right - triangleSize, m_bottom,
+ m_right, m_bottom - triangleSize, m_edgeColor);
+ break;
+
+ case PressedState:
+ // Draw a triangle in the bottom left corner of the control.
+ triangle(m_left, m_bottom,
+ m_left, m_bottom - triangleSize,
+ m_left + triangleSize, m_bottom, m_edgeColor);
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
+ CRASH();
+ break;
+ }
+}
+
+void WebThemeControlDRTWin::draw()
+{
+ int halfWidth = m_width / 2;
+ int halfHeight = m_height / 2;
+ int quarterWidth = m_width / 4;
+ int quarterHeight = m_height / 4;
+
+ // Indent amounts for the check in a checkbox or radio button.
+ const int checkIndent = 3;
+
+ // Indent amounts for short and long sides of the scrollbar notches.
+ const int notchLongOffset = 1;
+ const int notchShortOffset = 4;
+ const int noOffset = 0;
+
+ // Indent amounts for the short and long sides of a scroll thumb box.
+ const int thumbLongIndent = 0;
+ const int thumbShortIndent = 2;
+
+ // Indents for the crosshatch on a scroll grip.
+ const int gripLongIndent = 3;
+ const int gripShortIndent = 5;
+
+ // Indents for the the slider track.
+ const int sliderIndent = 2;
+
+ m_canvas->beginPlatformPaint();
+
+ switch (m_type) {
+ case UnknownType:
+ ASSERT_NOT_REACHED();
+ CRASH();
+ break;
+
+ case TextFieldType:
+ // We render this by hand outside of this function.
+ ASSERT_NOT_REACHED();
+ CRASH();
+ break;
+
+ case PushButtonType:
+ // push buttons render as a rounded rectangle
+ roundRect(m_bgColor);
+ break;
+
+ case UncheckedBoxType:
+ // Unchecked boxes are simply plain boxes.
+ box(m_irect, m_bgColor);
+ break;
+
+ case CheckedBoxType:
+ nestedBoxes(checkIndent, checkIndent, checkIndent, checkIndent, m_bgColor, m_fgColor);
+ break;
+
+ case IndeterminateCheckboxType:
+ // Indeterminate checkbox is a box containing '-'.
+ nestedBoxes(checkIndent, halfHeight, checkIndent, halfHeight, m_bgColor, m_fgColor);
+ break;
+
+ case UncheckedRadioType:
+ circle(SkIntToScalar(halfHeight), m_bgColor);
+ break;
+
+ case CheckedRadioType:
+ circle(SkIntToScalar(halfHeight), m_bgColor);
+ circle(SkIntToScalar(halfHeight - checkIndent), m_fgColor);
+ break;
+
+ case HorizontalScrollTrackBackType: {
+ // Draw a box with a notch at the left.
+ int longOffset = halfHeight - notchLongOffset;
+ int shortOffset = m_width - notchShortOffset;
+ nestedBoxes(noOffset, longOffset, shortOffset, longOffset, m_bgColor, m_edgeColor);
+ break;
+ }
+
+ case HorizontalScrollTrackForwardType: {
+ // Draw a box with a notch at the right.
+ int longOffset = halfHeight - notchLongOffset;
+ int shortOffset = m_width - notchShortOffset;
+ nestedBoxes(shortOffset, longOffset, noOffset, longOffset, m_bgColor, m_fgColor);
+ break;
+ }
+
+ case VerticalScrollTrackBackType: {
+ // Draw a box with a notch at the top.
+ int longOffset = halfWidth - notchLongOffset;
+ int shortOffset = m_height - notchShortOffset;
+ nestedBoxes(longOffset, noOffset, longOffset, shortOffset, m_bgColor, m_fgColor);
+ break;
+ }
+
+ case VerticalScrollTrackForwardType: {
+ // Draw a box with a notch at the bottom.
+ int longOffset = halfWidth - notchLongOffset;
+ int shortOffset = m_height - notchShortOffset;
+ nestedBoxes(longOffset, shortOffset, longOffset, noOffset, m_bgColor, m_fgColor);
+ break;
+ }
+
+ case HorizontalScrollThumbType:
+ // Draw a narrower box on top of the outside box.
+ nestedBoxes(thumbLongIndent, thumbShortIndent, thumbLongIndent, thumbShortIndent, m_bgColor, m_bgColor);
+ break;
+
+ case VerticalScrollThumbType:
+ // Draw a shorter box on top of the outside box.
+ nestedBoxes(thumbShortIndent, thumbLongIndent, thumbShortIndent, thumbLongIndent, m_bgColor, m_bgColor);
+ break;
+
+ case HorizontalSliderThumbType:
+ // Slider thumbs are ovals.
+ oval(m_bgColor);
+ break;
+
+ case HorizontalScrollGripType: {
+ // Draw a horizontal crosshatch for the grip.
+ int longOffset = halfWidth - gripLongIndent;
+ line(m_left + gripLongIndent, m_top + halfHeight,
+ m_right - gripLongIndent, m_top + halfHeight, m_fgColor);
+ line(m_left + longOffset, m_top + gripShortIndent,
+ m_left + longOffset, m_bottom - gripShortIndent, m_fgColor);
+ line(m_right - longOffset, m_top + gripShortIndent,
+ m_right - longOffset, m_bottom - gripShortIndent, m_fgColor);
+ break;
+ }
+
+ case VerticalScrollGripType: {
+ // Draw a vertical crosshatch for the grip.
+ int longOffset = halfHeight - gripLongIndent;
+ line(m_left + halfWidth, m_top + gripLongIndent,
+ m_left + halfWidth, m_bottom - gripLongIndent, m_fgColor);
+ line(m_left + gripShortIndent, m_top + longOffset,
+ m_right - gripShortIndent, m_top + longOffset, m_fgColor);
+ line(m_left + gripShortIndent, m_bottom - longOffset,
+ m_right - gripShortIndent, m_bottom - longOffset, m_fgColor);
+ break;
+ }
+
+ case LeftArrowType:
+ // Draw a left arrow inside a box.
+ box(m_irect, m_bgColor);
+ triangle(m_right - quarterWidth, m_top + quarterHeight,
+ m_right - quarterWidth, m_bottom - quarterHeight,
+ m_left + quarterWidth, m_top + halfHeight, m_fgColor);
+ break;
+
+ case RightArrowType:
+ // Draw a left arrow inside a box.
+ box(m_irect, m_bgColor);
+ triangle(m_left + quarterWidth, m_top + quarterHeight,
+ m_right - quarterWidth, m_top + halfHeight,
+ m_left + quarterWidth, m_bottom - quarterHeight, m_fgColor);
+ break;
+
+ case UpArrowType:
+ // Draw an up arrow inside a box.
+ box(m_irect, m_bgColor);
+ triangle(m_left + quarterWidth, m_bottom - quarterHeight,
+ m_left + halfWidth, m_top + quarterHeight,
+ m_right - quarterWidth, m_bottom - quarterHeight, m_fgColor);
+ break;
+
+ case DownArrowType:
+ // Draw a down arrow inside a box.
+ box(m_irect, m_bgColor);
+ triangle(m_left + quarterWidth, m_top + quarterHeight,
+ m_right - quarterWidth, m_top + quarterHeight,
+ m_left + halfWidth, m_bottom - quarterHeight, m_fgColor);
+ break;
+
+ case HorizontalSliderTrackType: {
+ // Draw a narrow rect for the track plus box hatches on the ends.
+ SkIRect lirect;
+ lirect = m_irect;
+ lirect.inset(noOffset, halfHeight - sliderIndent);
+ box(lirect, m_bgColor);
+ line(m_left, m_top, m_left, m_bottom, m_edgeColor);
+ line(m_right, m_top, m_right, m_bottom, m_edgeColor);
+ break;
+ }
+
+ case DropDownButtonType:
+ // Draw a box with a big down arrow on top.
+ box(m_irect, m_bgColor);
+ triangle(m_left + quarterWidth, m_top,
+ m_right - quarterWidth, m_top,
+ m_left + halfWidth, m_bottom, m_fgColor);
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
+ CRASH();
+ break;
+ }
+
+ markState();
+ m_canvas->endPlatformPaint();
+}
+
+// Because rendering a text field is dependent on input
+// parameters the other controls don't have, we render it directly
+// rather than trying to overcomplicate draw() further.
+void WebThemeControlDRTWin::drawTextField(bool drawEdges, bool fillContentArea, SkColor color)
+{
+ SkPaint paint;
+
+ m_canvas->beginPlatformPaint();
+ if (fillContentArea) {
+ paint.setColor(color);
+ paint.setStyle(SkPaint::kFill_Style);
+ m_canvas->drawIRect(m_irect, paint);
+ }
+ if (drawEdges) {
+ paint.setColor(m_edgeColor);
+ paint.setStyle(SkPaint::kStroke_Style);
+ m_canvas->drawIRect(m_irect, paint);
+ }
+
+ markState();
+ m_canvas->endPlatformPaint();
+}
+
+void WebThemeControlDRTWin::drawProgressBar(const SkIRect& fillRect)
+{
+ SkPaint paint;
+
+ m_canvas->beginPlatformPaint();
+ paint.setColor(m_bgColor);
+ paint.setStyle(SkPaint::kFill_Style);
+ m_canvas->drawIRect(m_irect, paint);
+
+ // Emulate clipping
+ SkIRect tofill;
+ tofill.intersect(m_irect, fillRect);
+ paint.setColor(m_fgColor);
+ paint.setStyle(SkPaint::kFill_Style);
+ m_canvas->drawIRect(tofill, paint);
+
+ markState();
+ m_canvas->endPlatformPaint();
+}
+
diff --git a/Tools/DumpRenderTree/chromium/WebThemeControlDRTWin.h b/Tools/DumpRenderTree/chromium/WebThemeControlDRTWin.h
new file mode 100644
index 0000000..4e22461
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/WebThemeControlDRTWin.h
@@ -0,0 +1,203 @@
+/*
+ * 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.
+ */
+
+// WebThemeControlDRTWin implements the generic rendering of controls
+// needed by WebThemeEngineDRTWin. See the comments in that class
+// header file for why this class is needed and used.
+//
+// This class implements a generic set of widgets using Skia. The widgets
+// are optimized for testability, not a pleasing appearance.
+//
+
+#ifndef WebThemeControlDRTWin_h
+#define WebThemeControlDRTWin_h
+
+#include "skia/ext/platform_canvas.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include <wtf/Noncopyable.h>
+
+// Skia forward declarations
+struct SkIRect;
+
+class WebThemeControlDRTWin : public Noncopyable {
+public:
+ // This list of states mostly mirrors the list in WebCore/platform/ThemeTypes.h
+ // but is maintained separately since that isn't public and also to minimize
+ // dependencies.
+ // Note that the WebKit ThemeTypes seem to imply that a control can be
+ // in multiple states simultaneously but WebThemeEngine only allows for
+ // a single state at a time.
+ //
+ // Some definitions for the various states:
+ // Disabled - indicates that a control can't be modified or selected
+ // (corresponds to HTML 'disabled' attribute)
+ // ReadOnly - indicates that a control can't be modified but can be
+ // selected
+ // Normal - the normal state of control on the page when it isn't
+ // focused or otherwise active
+ // Hot - when the mouse is hovering over a part of the control,
+ // all the other parts are considered "hot"
+ // Hover - when the mouse is directly over a control (the CSS
+ // :hover pseudo-class)
+ // Focused - when the control has the keyboard focus
+ // Pressed - when the control is being triggered (by a mousedown or
+ // a key event).
+ // Indeterminate - when set to indeterminate (only for progress bar)
+ enum State {
+ UnknownState = 0,
+ DisabledState,
+ ReadOnlyState,
+ NormalState,
+ HotState,
+ HoverState,
+ FocusedState,
+ PressedState,
+ IndeterminateState
+ };
+
+ // This list of types mostly mirrors the list in
+ // WebCore/platform/ThemeTypes.h but is maintained
+ // separately since that isn't public and also to minimize dependencies.
+ //
+ // Note that what the user might think of as a single control can be
+ // made up of multiple parts. For example, a single scroll bar contains
+ // six clickable parts - two arrows, the "thumb" indicating the current
+ // position on the bar, the other two parts of the bar (before and after
+ // the thumb) and the "gripper" on the thumb itself.
+ //
+ enum Type {
+ UnknownType = 0,
+ TextFieldType,
+ PushButtonType,
+ UncheckedBoxType,
+ CheckedBoxType,
+ IndeterminateCheckboxType,
+ UncheckedRadioType,
+ CheckedRadioType,
+ HorizontalScrollTrackBackType,
+ HorizontalScrollTrackForwardType,
+ HorizontalScrollThumbType,
+ HorizontalScrollGripType,
+ VerticalScrollTrackBackType,
+ VerticalScrollTrackForwardType,
+ VerticalScrollThumbType,
+ VerticalScrollGripType,
+ LeftArrowType,
+ RightArrowType,
+ UpArrowType,
+ DownArrowType,
+ HorizontalSliderTrackType,
+ HorizontalSliderThumbType,
+ DropDownButtonType,
+ ProgressBarType
+ };
+
+ // canvas is the canvas to draw onto, and rect gives the size of the
+ // control. ctype and cstate specify the type and state of the control.
+ WebThemeControlDRTWin(skia::PlatformCanvas* canvas,
+ const SkIRect& rect,
+ Type ctype,
+ State cstate);
+ ~WebThemeControlDRTWin();
+
+ // Draws the control.
+ void draw();
+
+ // Use this for TextField controls instead, because the logic
+ // for drawing them is dependent on what WebKit tells us to do.
+ // If drawEdges is true, draw an edge around the control. If
+ // fillContentArea is true, fill the content area with the given color.
+ void drawTextField(bool drawEdges, bool fillContentArea, SkColor color);
+
+ // Use this for drawing ProgressBar controls instead, since we
+ // need to know the rect to fill inside the bar.
+ void drawProgressBar(const SkIRect& fillRect);
+
+private:
+ // Draws a box of size specified by irect, filled with the given color.
+ // The box will have a border drawn in the default edge color.
+ void box(const SkIRect& irect, SkColor color);
+
+
+ // Draws a triangle of size specified by the three pairs of coordinates,
+ // filled with the given color. The box will have an edge drawn in the
+ // default edge color.
+ void triangle(int x0, int y0, int x1, int y1, int x2, int y2, SkColor color);
+
+ // Draws a rectangle the size of the control with rounded corners, filled
+ // with the specified color (and with a border in the default edge color).
+ void roundRect(SkColor color);
+
+ // Draws an oval the size of the control, filled with the specified color
+ // and with a border in the default edge color.
+ void oval(SkColor color);
+
+ // Draws a circle centered in the control with the specified radius,
+ // filled with the specified color, and with a border draw in the
+ // default edge color.
+ void circle(SkScalar radius, SkColor color);
+
+ // Draws a box the size of the control, filled with the outerColor and
+ // with a border in the default edge color, and then draws another box
+ // indented on all four sides by the specified amounts, filled with the
+ // inner color and with a border in the default edge color.
+ void nestedBoxes(int indentLeft,
+ int indentTop,
+ int indentRight,
+ int indentBottom,
+ SkColor outerColor,
+ SkColor innerColor);
+
+ // Draws a line between the two points in the given color.
+ void line(int x0, int y0, int x1, int y1, SkColor color);
+
+ // Draws a distinctive mark on the control for each state, so that the
+ // state of the control can be determined without needing to know which
+ // color is which.
+ void markState();
+
+ skia::PlatformCanvas* m_canvas;
+ const SkIRect m_irect;
+ const Type m_type;
+ const State m_state;
+ const SkColor m_edgeColor;
+ const SkColor m_bgColor;
+ const SkColor m_fgColor;
+
+ // The following are convenience accessors for m_irect.
+ const int m_left;
+ const int m_right;
+ const int m_top;
+ const int m_bottom;
+ const int m_width;
+ const int m_height;
+};
+
+#endif // WebThemeControlDRTWin_h
diff --git a/Tools/DumpRenderTree/chromium/WebThemeEngineDRTWin.cpp b/Tools/DumpRenderTree/chromium/WebThemeEngineDRTWin.cpp
new file mode 100755
index 0000000..103b295
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/WebThemeEngineDRTWin.cpp
@@ -0,0 +1,758 @@
+/*
+ * 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 "WebThemeEngineDRTWin.h"
+
+#include "WebRect.h"
+#include "WebThemeControlDRTWin.h"
+#include "third_party/skia/include/core/SkRect.h"
+
+// Although all this code is generic, we include these headers
+// to pull in the Windows #defines for the parts and states of
+// the controls.
+#include <vsstyle.h>
+#include <windows.h>
+
+#include <wtf/Assertions.h>
+
+using namespace WebKit;
+
+// We define this for clarity, although there really should be a DFCS_NORMAL in winuser.h.
+static const int dfcsNormal = 0x0000;
+
+static SkIRect webRectToSkIRect(const WebRect& webRect)
+{
+ SkIRect irect;
+ irect.set(webRect.x, webRect.y, webRect.x + webRect.width, webRect.y + webRect.height);
+ return irect;
+}
+
+static void drawControl(WebCanvas* canvas,
+ const WebRect& rect,
+ WebThemeControlDRTWin::Type ctype,
+ WebThemeControlDRTWin::State cstate)
+{
+ WebThemeControlDRTWin control(canvas, webRectToSkIRect(rect), ctype, cstate);
+ control.draw();
+}
+
+static void drawTextField(WebCanvas* canvas,
+ const WebRect& rect,
+ WebThemeControlDRTWin::Type ctype,
+ WebThemeControlDRTWin::State cstate,
+ bool drawEdges,
+ bool fillContentArea,
+ WebColor color)
+{
+ WebThemeControlDRTWin control(canvas, webRectToSkIRect(rect), ctype, cstate);
+ control.drawTextField(drawEdges, fillContentArea, color);
+}
+
+static void drawProgressBar(WebCanvas* canvas,
+ WebThemeControlDRTWin::Type ctype,
+ WebThemeControlDRTWin::State cstate,
+ const WebRect& barRect,
+ const WebRect& fillRect)
+{
+ WebThemeControlDRTWin control(canvas, webRectToSkIRect(barRect), ctype, cstate);
+ control.drawProgressBar(webRectToSkIRect(fillRect));
+}
+
+// WebThemeEngineDRTWin
+
+void WebThemeEngineDRTWin::paintButton(WebCanvas* canvas,
+ int part,
+ int state,
+ int classicState,
+ const WebRect& rect)
+{
+ WebThemeControlDRTWin::Type ctype = WebThemeControlDRTWin::UnknownType;
+ WebThemeControlDRTWin::State cstate = WebThemeControlDRTWin::UnknownState;
+
+ if (part == BP_CHECKBOX) {
+ switch (state) {
+ case CBS_UNCHECKEDNORMAL:
+ ASSERT(classicState == dfcsNormal);
+ ctype = WebThemeControlDRTWin::UncheckedBoxType;
+ cstate = WebThemeControlDRTWin::NormalState;
+ break;
+
+ case CBS_UNCHECKEDHOT:
+ ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_HOT));
+ ctype = WebThemeControlDRTWin::UncheckedBoxType;
+ cstate = WebThemeControlDRTWin::HotState;
+ break;
+
+ case CBS_UNCHECKEDPRESSED:
+ ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_PUSHED));
+ ctype = WebThemeControlDRTWin::UncheckedBoxType;
+ cstate = WebThemeControlDRTWin::PressedState;
+ break;
+
+ case CBS_UNCHECKEDDISABLED:
+ ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_INACTIVE));
+ ctype = WebThemeControlDRTWin::UncheckedBoxType;
+ cstate = WebThemeControlDRTWin::DisabledState;
+ break;
+
+ case CBS_CHECKEDNORMAL:
+ ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_CHECKED));
+ ctype = WebThemeControlDRTWin::CheckedBoxType;
+ cstate = WebThemeControlDRTWin::NormalState;
+ break;
+
+ case CBS_CHECKEDHOT:
+ ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_CHECKED | DFCS_HOT));
+ ctype = WebThemeControlDRTWin::CheckedBoxType;
+ cstate = WebThemeControlDRTWin::HotState;
+ break;
+
+ case CBS_CHECKEDPRESSED:
+ ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_CHECKED | DFCS_PUSHED));
+ ctype = WebThemeControlDRTWin::CheckedBoxType;
+ cstate = WebThemeControlDRTWin::PressedState;
+ break;
+
+ case CBS_CHECKEDDISABLED:
+ ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_CHECKED | DFCS_INACTIVE));
+ ctype = WebThemeControlDRTWin::CheckedBoxType;
+ cstate = WebThemeControlDRTWin::DisabledState;
+ break;
+
+ case CBS_MIXEDNORMAL:
+ // Classic theme can't represent mixed state checkbox. We assume
+ // it's equivalent to unchecked.
+ ASSERT(classicState == DFCS_BUTTONCHECK);
+ ctype = WebThemeControlDRTWin::IndeterminateCheckboxType;
+ cstate = WebThemeControlDRTWin::NormalState;
+ break;
+
+ case CBS_MIXEDHOT:
+ ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_HOT));
+ ctype = WebThemeControlDRTWin::IndeterminateCheckboxType;
+ cstate = WebThemeControlDRTWin::HotState;
+ break;
+
+ case CBS_MIXEDPRESSED:
+ ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_PUSHED));
+ ctype = WebThemeControlDRTWin::IndeterminateCheckboxType;
+ cstate = WebThemeControlDRTWin::PressedState;
+ break;
+
+ case CBS_MIXEDDISABLED:
+ ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_INACTIVE));
+ ctype = WebThemeControlDRTWin::IndeterminateCheckboxType;
+ cstate = WebThemeControlDRTWin::DisabledState;
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+ } else if (BP_RADIOBUTTON == part) {
+ switch (state) {
+ case RBS_UNCHECKEDNORMAL:
+ ASSERT(classicState == DFCS_BUTTONRADIO);
+ ctype = WebThemeControlDRTWin::UncheckedRadioType;
+ cstate = WebThemeControlDRTWin::NormalState;
+ break;
+
+ case RBS_UNCHECKEDHOT:
+ ASSERT(classicState == (DFCS_BUTTONRADIO | DFCS_HOT));
+ ctype = WebThemeControlDRTWin::UncheckedRadioType;
+ cstate = WebThemeControlDRTWin::HotState;
+ break;
+
+ case RBS_UNCHECKEDPRESSED:
+ ASSERT(classicState == (DFCS_BUTTONRADIO | DFCS_PUSHED));
+ ctype = WebThemeControlDRTWin::UncheckedRadioType;
+ cstate = WebThemeControlDRTWin::PressedState;
+ break;
+
+ case RBS_UNCHECKEDDISABLED:
+ ASSERT(classicState == (DFCS_BUTTONRADIO | DFCS_INACTIVE));
+ ctype = WebThemeControlDRTWin::UncheckedRadioType;
+ cstate = WebThemeControlDRTWin::DisabledState;
+ break;
+
+ case RBS_CHECKEDNORMAL:
+ ASSERT(classicState == (DFCS_BUTTONRADIO | DFCS_CHECKED));
+ ctype = WebThemeControlDRTWin::CheckedRadioType;
+ cstate = WebThemeControlDRTWin::NormalState;
+ break;
+
+ case RBS_CHECKEDHOT:
+ ASSERT(classicState == (DFCS_BUTTONRADIO | DFCS_CHECKED | DFCS_HOT));
+ ctype = WebThemeControlDRTWin::CheckedRadioType;
+ cstate = WebThemeControlDRTWin::HotState;
+ break;
+
+ case RBS_CHECKEDPRESSED:
+ ASSERT(classicState == (DFCS_BUTTONRADIO | DFCS_CHECKED | DFCS_PUSHED));
+ ctype = WebThemeControlDRTWin::CheckedRadioType;
+ cstate = WebThemeControlDRTWin::PressedState;
+ break;
+
+ case RBS_CHECKEDDISABLED:
+ ASSERT(classicState == (DFCS_BUTTONRADIO | DFCS_CHECKED | DFCS_INACTIVE));
+ ctype = WebThemeControlDRTWin::CheckedRadioType;
+ cstate = WebThemeControlDRTWin::DisabledState;
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+ } else if (BP_PUSHBUTTON == part) {
+ switch (state) {
+ case PBS_NORMAL:
+ ASSERT(classicState == DFCS_BUTTONPUSH);
+ ctype = WebThemeControlDRTWin::PushButtonType;
+ cstate = WebThemeControlDRTWin::NormalState;
+ break;
+
+ case PBS_HOT:
+ ASSERT(classicState == (DFCS_BUTTONPUSH | DFCS_HOT));
+ ctype = WebThemeControlDRTWin::PushButtonType;
+ cstate = WebThemeControlDRTWin::HotState;
+ break;
+
+ case PBS_PRESSED:
+ ASSERT(classicState == (DFCS_BUTTONPUSH | DFCS_PUSHED));
+ ctype = WebThemeControlDRTWin::PushButtonType;
+ cstate = WebThemeControlDRTWin::PressedState;
+ break;
+
+ case PBS_DISABLED:
+ ASSERT(classicState == (DFCS_BUTTONPUSH | DFCS_INACTIVE));
+ ctype = WebThemeControlDRTWin::PushButtonType;
+ cstate = WebThemeControlDRTWin::DisabledState;
+ break;
+
+ case PBS_DEFAULTED:
+ ASSERT(classicState == DFCS_BUTTONPUSH);
+ ctype = WebThemeControlDRTWin::PushButtonType;
+ cstate = WebThemeControlDRTWin::FocusedState;
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+ } else {
+ ASSERT_NOT_REACHED();
+ }
+
+ drawControl(canvas, rect, ctype, cstate);
+}
+
+
+void WebThemeEngineDRTWin::paintMenuList(WebCanvas* canvas,
+ int part,
+ int state,
+ int classicState,
+ const WebRect& rect)
+{
+ WebThemeControlDRTWin::Type ctype = WebThemeControlDRTWin::UnknownType;
+ WebThemeControlDRTWin::State cstate = WebThemeControlDRTWin::UnknownState;
+
+ if (CP_DROPDOWNBUTTON == part) {
+ ctype = WebThemeControlDRTWin::DropDownButtonType;
+ switch (state) {
+ case CBXS_NORMAL:
+ ASSERT(classicState == DFCS_MENUARROW);
+ cstate = WebThemeControlDRTWin::NormalState;
+ break;
+
+ case CBXS_HOT:
+ ASSERT(classicState == (DFCS_MENUARROW | DFCS_HOT));
+ cstate = WebThemeControlDRTWin::HoverState;
+ break;
+
+ case CBXS_PRESSED:
+ ASSERT(classicState == (DFCS_MENUARROW | DFCS_PUSHED));
+ cstate = WebThemeControlDRTWin::PressedState;
+ break;
+
+ case CBXS_DISABLED:
+ ASSERT(classicState == (DFCS_MENUARROW | DFCS_INACTIVE));
+ cstate = WebThemeControlDRTWin::DisabledState;
+ break;
+
+ default:
+ CRASH();
+ break;
+ }
+ } else {
+ CRASH();
+ }
+
+ drawControl(canvas, rect, ctype, cstate);
+}
+
+void WebThemeEngineDRTWin::paintScrollbarArrow(WebCanvas* canvas,
+ int state,
+ int classicState,
+ const WebRect& rect)
+{
+ WebThemeControlDRTWin::Type ctype = WebThemeControlDRTWin::UnknownType;
+ WebThemeControlDRTWin::State cstate = WebThemeControlDRTWin::UnknownState;
+
+ switch (state) {
+ case ABS_UPNORMAL:
+ ASSERT(classicState == DFCS_SCROLLUP);
+ ctype = WebThemeControlDRTWin::UpArrowType;
+ cstate = WebThemeControlDRTWin::NormalState;
+ break;
+
+ case ABS_DOWNNORMAL:
+ ASSERT(classicState == DFCS_SCROLLDOWN);
+ ctype = WebThemeControlDRTWin::DownArrowType;
+ cstate = WebThemeControlDRTWin::NormalState;
+ break;
+
+ case ABS_LEFTNORMAL:
+ ASSERT(classicState == DFCS_SCROLLLEFT);
+ ctype = WebThemeControlDRTWin::LeftArrowType;
+ cstate = WebThemeControlDRTWin::NormalState;
+ break;
+
+ case ABS_RIGHTNORMAL:
+ ASSERT(classicState == DFCS_SCROLLRIGHT);
+ ctype = WebThemeControlDRTWin::RightArrowType;
+ cstate = WebThemeControlDRTWin::NormalState;
+ break;
+
+ case ABS_UPHOT:
+ ASSERT(classicState == (DFCS_SCROLLUP | DFCS_HOT));
+ ctype = WebThemeControlDRTWin::UpArrowType;
+ cstate = WebThemeControlDRTWin::HotState;
+ break;
+
+ case ABS_DOWNHOT:
+ ASSERT(classicState == (DFCS_SCROLLDOWN | DFCS_HOT));
+ ctype = WebThemeControlDRTWin::DownArrowType;
+ cstate = WebThemeControlDRTWin::HotState;
+ break;
+
+ case ABS_LEFTHOT:
+ ASSERT(classicState == (DFCS_SCROLLLEFT | DFCS_HOT));
+ ctype = WebThemeControlDRTWin::LeftArrowType;
+ cstate = WebThemeControlDRTWin::HotState;
+ break;
+
+ case ABS_RIGHTHOT:
+ ASSERT(classicState == (DFCS_SCROLLRIGHT | DFCS_HOT));
+ ctype = WebThemeControlDRTWin::RightArrowType;
+ cstate = WebThemeControlDRTWin::HotState;
+ break;
+
+ case ABS_UPHOVER:
+ ASSERT(classicState == DFCS_SCROLLUP);
+ ctype = WebThemeControlDRTWin::UpArrowType;
+ cstate = WebThemeControlDRTWin::HoverState;
+ break;
+
+ case ABS_DOWNHOVER:
+ ASSERT(classicState == DFCS_SCROLLDOWN);
+ ctype = WebThemeControlDRTWin::DownArrowType;
+ cstate = WebThemeControlDRTWin::HoverState;
+ break;
+
+ case ABS_LEFTHOVER:
+ ASSERT(classicState == DFCS_SCROLLLEFT);
+ ctype = WebThemeControlDRTWin::LeftArrowType;
+ cstate = WebThemeControlDRTWin::HoverState;
+ break;
+
+ case ABS_RIGHTHOVER:
+ ASSERT(classicState == DFCS_SCROLLRIGHT);
+ ctype = WebThemeControlDRTWin::RightArrowType;
+ cstate = WebThemeControlDRTWin::HoverState;
+ break;
+
+ case ABS_UPPRESSED:
+ ASSERT(classicState == (DFCS_SCROLLUP | DFCS_PUSHED | DFCS_FLAT));
+ ctype = WebThemeControlDRTWin::UpArrowType;
+ cstate = WebThemeControlDRTWin::PressedState;
+ break;
+
+ case ABS_DOWNPRESSED:
+ ASSERT(classicState == (DFCS_SCROLLDOWN | DFCS_PUSHED | DFCS_FLAT));
+ ctype = WebThemeControlDRTWin::DownArrowType;
+ cstate = WebThemeControlDRTWin::PressedState;
+ break;
+
+ case ABS_LEFTPRESSED:
+ ASSERT(classicState == (DFCS_SCROLLLEFT | DFCS_PUSHED | DFCS_FLAT));
+ ctype = WebThemeControlDRTWin::LeftArrowType;
+ cstate = WebThemeControlDRTWin::PressedState;
+ break;
+
+ case ABS_RIGHTPRESSED:
+ ASSERT(classicState == (DFCS_SCROLLRIGHT | DFCS_PUSHED | DFCS_FLAT));
+ ctype = WebThemeControlDRTWin::RightArrowType;
+ cstate = WebThemeControlDRTWin::PressedState;
+ break;
+
+ case ABS_UPDISABLED:
+ ASSERT(classicState == (DFCS_SCROLLUP | DFCS_INACTIVE));
+ ctype = WebThemeControlDRTWin::UpArrowType;
+ cstate = WebThemeControlDRTWin::DisabledState;
+ break;
+
+ case ABS_DOWNDISABLED:
+ ASSERT(classicState == (DFCS_SCROLLDOWN | DFCS_INACTIVE));
+ ctype = WebThemeControlDRTWin::DownArrowType;
+ cstate = WebThemeControlDRTWin::DisabledState;
+ break;
+
+ case ABS_LEFTDISABLED:
+ ASSERT(classicState == (DFCS_SCROLLLEFT | DFCS_INACTIVE));
+ ctype = WebThemeControlDRTWin::LeftArrowType;
+ cstate = WebThemeControlDRTWin::DisabledState;
+ break;
+
+ case ABS_RIGHTDISABLED:
+ ASSERT(classicState == (DFCS_SCROLLRIGHT | DFCS_INACTIVE));
+ ctype = WebThemeControlDRTWin::RightArrowType;
+ cstate = WebThemeControlDRTWin::DisabledState;
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+
+ drawControl(canvas, rect, ctype, cstate);
+}
+
+void WebThemeEngineDRTWin::paintScrollbarThumb(WebCanvas* canvas,
+ int part,
+ int state,
+ int classicState,
+ const WebRect& rect)
+{
+ WebThemeControlDRTWin::Type ctype = WebThemeControlDRTWin::UnknownType;
+ WebThemeControlDRTWin::State cstate = WebThemeControlDRTWin::UnknownState;
+
+ switch (part) {
+ case SBP_THUMBBTNHORZ:
+ ctype = WebThemeControlDRTWin::HorizontalScrollThumbType;
+ break;
+
+ case SBP_THUMBBTNVERT:
+ ctype = WebThemeControlDRTWin::VerticalScrollThumbType;
+ break;
+
+ case SBP_GRIPPERHORZ:
+ ctype = WebThemeControlDRTWin::HorizontalScrollGripType;
+ break;
+
+ case SBP_GRIPPERVERT:
+ ctype = WebThemeControlDRTWin::VerticalScrollGripType;
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+
+ switch (state) {
+ case SCRBS_NORMAL:
+ ASSERT(classicState == dfcsNormal);
+ cstate = WebThemeControlDRTWin::NormalState;
+ break;
+
+ case SCRBS_HOT:
+ ASSERT(classicState == DFCS_HOT);
+ cstate = WebThemeControlDRTWin::HotState;
+ break;
+
+ case SCRBS_HOVER:
+ ASSERT(classicState == dfcsNormal);
+ cstate = WebThemeControlDRTWin::HoverState;
+ break;
+
+ case SCRBS_PRESSED:
+ ASSERT(classicState == dfcsNormal);
+ cstate = WebThemeControlDRTWin::PressedState;
+ break;
+
+ case SCRBS_DISABLED:
+ ASSERT_NOT_REACHED(); // This should never happen in practice.
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+
+ drawControl(canvas, rect, ctype, cstate);
+}
+
+void WebThemeEngineDRTWin::paintScrollbarTrack(WebCanvas* canvas,
+ int part,
+ int state,
+ int classicState,
+ const WebRect& rect,
+ const WebRect& alignRect)
+{
+ WebThemeControlDRTWin::Type ctype = WebThemeControlDRTWin::UnknownType;
+ WebThemeControlDRTWin::State cstate = WebThemeControlDRTWin::UnknownState;
+
+ switch (part) {
+ case SBP_UPPERTRACKHORZ:
+ ctype = WebThemeControlDRTWin::HorizontalScrollTrackBackType;
+ break;
+
+ case SBP_LOWERTRACKHORZ:
+ ctype = WebThemeControlDRTWin::HorizontalScrollTrackForwardType;
+ break;
+
+ case SBP_UPPERTRACKVERT:
+ ctype = WebThemeControlDRTWin::VerticalScrollTrackBackType;
+ break;
+
+ case SBP_LOWERTRACKVERT:
+ ctype = WebThemeControlDRTWin::VerticalScrollTrackForwardType;
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+
+ switch (state) {
+ case SCRBS_NORMAL:
+ ASSERT(classicState == dfcsNormal);
+ cstate = WebThemeControlDRTWin::NormalState;
+ break;
+
+ case SCRBS_HOT:
+ ASSERT_NOT_REACHED(); // This should never happen in practice.
+ break;
+
+ case SCRBS_HOVER:
+ ASSERT(classicState == dfcsNormal);
+ cstate = WebThemeControlDRTWin::HoverState;
+ break;
+
+ case SCRBS_PRESSED:
+ ASSERT_NOT_REACHED(); // This should never happen in practice.
+ break;
+
+ case SCRBS_DISABLED:
+ ASSERT(classicState == DFCS_INACTIVE);
+ cstate = WebThemeControlDRTWin::DisabledState;
+ break;
+
+ default:
+ CRASH();
+ break;
+ }
+
+ drawControl(canvas, rect, ctype, cstate);
+}
+
+void WebThemeEngineDRTWin::paintSpinButton(WebCanvas* canvas,
+ int part,
+ int state,
+ int classicState,
+ const WebRect& rect)
+{
+ WebThemeControlDRTWin::Type ctype = WebThemeControlDRTWin::UnknownType;
+ WebThemeControlDRTWin::State cstate = WebThemeControlDRTWin::UnknownState;
+
+ if (part == SPNP_UP) {
+ ctype = WebThemeControlDRTWin::UpArrowType;
+ switch (state) {
+ case UPS_NORMAL:
+ ASSERT(classicState == DFCS_SCROLLUP);
+ cstate = WebThemeControlDRTWin::NormalState;
+ break;
+ case UPS_DISABLED:
+ ASSERT(classicState == (DFCS_SCROLLUP | DFCS_INACTIVE));
+ cstate = WebThemeControlDRTWin::DisabledState;
+ break;
+ case UPS_PRESSED:
+ ASSERT(classicState == (DFCS_SCROLLUP | DFCS_PUSHED));
+ cstate = WebThemeControlDRTWin::PressedState;
+ break;
+ case UPS_HOT:
+ ASSERT(classicState == (DFCS_SCROLLUP | DFCS_HOT));
+ cstate = WebThemeControlDRTWin::HoverState;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ } else if (part == SPNP_DOWN) {
+ ctype = WebThemeControlDRTWin::DownArrowType;
+ switch (state) {
+ case DNS_NORMAL:
+ ASSERT(classicState == DFCS_SCROLLDOWN);
+ cstate = WebThemeControlDRTWin::NormalState;
+ break;
+ case DNS_DISABLED:
+ ASSERT(classicState == (DFCS_SCROLLDOWN | DFCS_INACTIVE));
+ cstate = WebThemeControlDRTWin::DisabledState;
+ break;
+ case DNS_PRESSED:
+ ASSERT(classicState == (DFCS_SCROLLDOWN | DFCS_PUSHED));
+ cstate = WebThemeControlDRTWin::PressedState;
+ break;
+ case DNS_HOT:
+ ASSERT(classicState == (DFCS_SCROLLDOWN | DFCS_HOT));
+ cstate = WebThemeControlDRTWin::HoverState;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ } else
+ ASSERT_NOT_REACHED();
+ drawControl(canvas, rect, ctype, cstate);
+}
+
+void WebThemeEngineDRTWin::paintTextField(WebCanvas* canvas,
+ int part,
+ int state,
+ int classicState,
+ const WebRect& rect,
+ WebColor color,
+ bool fillContentArea,
+ bool drawEdges)
+{
+ WebThemeControlDRTWin::Type ctype = WebThemeControlDRTWin::UnknownType;
+ WebThemeControlDRTWin::State cstate = WebThemeControlDRTWin::UnknownState;
+
+ ASSERT(EP_EDITTEXT == part);
+ ctype = WebThemeControlDRTWin::TextFieldType;
+
+ switch (state) {
+ case ETS_NORMAL:
+ ASSERT(classicState == dfcsNormal);
+ cstate = WebThemeControlDRTWin::NormalState;
+ break;
+
+ case ETS_HOT:
+ ASSERT(classicState == DFCS_HOT);
+ cstate = WebThemeControlDRTWin::HotState;
+ break;
+
+ case ETS_DISABLED:
+ ASSERT(classicState == DFCS_INACTIVE);
+ cstate = WebThemeControlDRTWin::DisabledState;
+ break;
+
+ case ETS_SELECTED:
+ ASSERT(classicState == DFCS_PUSHED);
+ cstate = WebThemeControlDRTWin::PressedState;
+ break;
+
+ case ETS_FOCUSED:
+ ASSERT(classicState == dfcsNormal);
+ cstate = WebThemeControlDRTWin::FocusedState;
+ break;
+
+ case ETS_READONLY:
+ ASSERT(classicState == dfcsNormal);
+ cstate = WebThemeControlDRTWin::ReadOnlyState;
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+
+ drawTextField(canvas, rect, ctype, cstate, drawEdges, fillContentArea, color);
+}
+
+void WebThemeEngineDRTWin::paintTrackbar(WebCanvas* canvas,
+ int part,
+ int state,
+ int classicState,
+ const WebRect& rect)
+{
+ WebThemeControlDRTWin::Type ctype = WebThemeControlDRTWin::UnknownType;
+ WebThemeControlDRTWin::State cstate = WebThemeControlDRTWin::UnknownState;
+
+ if (TKP_THUMBBOTTOM == part) {
+ ctype = WebThemeControlDRTWin::HorizontalSliderThumbType;
+ switch (state) {
+ case TUS_NORMAL:
+ ASSERT(classicState == dfcsNormal);
+ cstate = WebThemeControlDRTWin::NormalState;
+ break;
+
+ case TUS_HOT:
+ ASSERT(classicState == DFCS_HOT);
+ cstate = WebThemeControlDRTWin::HotState;
+ break;
+
+ case TUS_DISABLED:
+ ASSERT(classicState == DFCS_INACTIVE);
+ cstate = WebThemeControlDRTWin::DisabledState;
+ break;
+
+ case TUS_PRESSED:
+ ASSERT(classicState == DFCS_PUSHED);
+ cstate = WebThemeControlDRTWin::PressedState;
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+ } else if (TKP_TRACK == part) {
+ ctype = WebThemeControlDRTWin::HorizontalSliderTrackType;
+ ASSERT(part == TUS_NORMAL);
+ ASSERT(classicState == dfcsNormal);
+ cstate = WebThemeControlDRTWin::NormalState;
+ } else {
+ ASSERT_NOT_REACHED();
+ }
+
+ drawControl(canvas, rect, ctype, cstate);
+}
+
+
+void WebThemeEngineDRTWin::paintProgressBar(WebKit::WebCanvas* canvas,
+ const WebKit::WebRect& barRect,
+ const WebKit::WebRect& valueRect,
+ bool determinate,
+ double)
+{
+ WebThemeControlDRTWin::Type ctype = WebThemeControlDRTWin::ProgressBarType;
+ WebThemeControlDRTWin::State cstate = determinate ? WebThemeControlDRTWin::NormalState
+ : WebThemeControlDRTWin::IndeterminateState;
+ drawProgressBar(canvas, ctype, cstate, barRect, valueRect);
+}
+
diff --git a/Tools/DumpRenderTree/chromium/WebThemeEngineDRTWin.h b/Tools/DumpRenderTree/chromium/WebThemeEngineDRTWin.h
new file mode 100644
index 0000000..2e15cf8
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/WebThemeEngineDRTWin.h
@@ -0,0 +1,97 @@
+/*
+ * 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 implements the WebThemeEngine API used by the Windows version of
+// Chromium to render native form controls like checkboxes, radio buttons,
+// and scroll bars.
+// The normal implementation (native_theme) renders the controls using either
+// the UXTheme theming engine present in XP, Vista, and Win 7, or the "classic"
+// theme used if that theme is selected in the Desktop settings.
+// Unfortunately, both of these themes render controls differently on the
+// different versions of Windows.
+//
+// In order to ensure maximum consistency of baselines across the different
+// Windows versions, we provide a simple implementation for DRT here
+// instead. These controls are actually platform-independent (they're rendered
+// using Skia) and could be used on Linux and the Mac as well, should we
+// choose to do so at some point.
+//
+
+#ifndef WebThemeEngineDRTWin_h
+#define WebThemeEngineDRTWin_h
+
+#include "win/WebThemeEngine.h"
+#include <wtf/Noncopyable.h>
+
+class WebThemeEngineDRTWin : public WebKit::WebThemeEngine, public Noncopyable {
+public:
+ WebThemeEngineDRTWin() {}
+
+ // WebThemeEngine methods:
+ virtual void paintButton(
+ WebKit::WebCanvas*, int part, int state, int classicState,
+ const WebKit::WebRect&);
+
+ virtual void paintMenuList(
+ WebKit::WebCanvas*, int part, int state, int classicState,
+ const WebKit::WebRect&);
+
+ virtual void paintScrollbarArrow(
+ WebKit::WebCanvas*, int state, int classicState,
+ const WebKit::WebRect&);
+
+ virtual void paintScrollbarThumb(
+ WebKit::WebCanvas*, int part, int state, int classicState,
+ const WebKit::WebRect&);
+
+ virtual void paintScrollbarTrack(
+ WebKit::WebCanvas*, int part, int state, int classicState,
+ const WebKit::WebRect&, const WebKit::WebRect& alignRect);
+
+ virtual void paintSpinButton(
+ WebKit::WebCanvas*, int part, int state, int classicState,
+ const WebKit::WebRect&);
+
+ virtual void paintTextField(
+ WebKit::WebCanvas*, int part, int state, int classicState,
+ const WebKit::WebRect&, WebKit::WebColor, bool fillContentArea,
+ bool drawEdges);
+
+ virtual void paintTrackbar(
+ WebKit::WebCanvas*, int part, int state, int classicState,
+ const WebKit::WebRect&);
+
+ virtual void paintProgressBar(
+ WebKit::WebCanvas*, const WebKit::WebRect& barRect,
+ const WebKit::WebRect& valueRect,
+ bool determinate, double time);
+};
+
+#endif // WebThemeEngineDRTWin_h
diff --git a/Tools/DumpRenderTree/chromium/WebViewHost.cpp b/Tools/DumpRenderTree/chromium/WebViewHost.cpp
new file mode 100644
index 0000000..e3c8c28
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/WebViewHost.cpp
@@ -0,0 +1,1519 @@
+/*
+ * 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 "WebCString.h"
+#include "WebConsoleMessage.h"
+#include "WebContextMenuData.h"
+#include "WebDataSource.h"
+#include "WebDeviceOrientationClientMock.h"
+#include "WebDragData.h"
+#include "WebElement.h"
+#include "WebFrame.h"
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+#include "WebGeolocationClientMock.h"
+#else
+#include "WebGeolocationServiceMock.h"
+#endif
+#include "WebHistoryItem.h"
+#include "WebNode.h"
+#include "WebRange.h"
+#include "WebRect.h"
+#include "WebScreenInfo.h"
+#include "WebSize.h"
+#include "WebSpeechInputControllerMock.h"
+#include "WebStorageNamespace.h"
+#include "WebURLRequest.h"
+#include "WebURLResponse.h"
+#include "WebView.h"
+#include "WebWindowFeatures.h"
+#include "skia/ext/platform_canvas.h"
+#include "webkit/support/webkit_support.h"
+#include <wtf/Assertions.h>
+#include <wtf/PassOwnPtr.h>
+
+using namespace WebCore;
+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 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*, const WebWindowFeatures&, const WebString&)
+{
+ if (!layoutTestController()->canOpenWindows())
+ return 0;
+ return m_shell->createWebView()->webView();
+}
+
+WebWidget* WebViewHost::createPopupMenu(WebPopupType)
+{
+ return 0;
+}
+
+WebWidget* WebViewHost::createPopupMenu(const WebPopupMenuInfo&)
+{
+ return 0;
+}
+
+WebStorageNamespace* WebViewHost::createSessionStorageNamespace(unsigned quota)
+{
+ return WebKit::WebStorageNamespace::createSessionStorageNamespace(quota);
+}
+
+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& contextMenuData)
+{
+ m_lastContextMenuData = adoptPtr(new WebContextMenuData(contextMenuData));
+}
+
+void WebViewHost::clearContextMenuData()
+{
+ m_lastContextMenuData.clear();
+}
+
+WebContextMenuData* WebViewHost::lastContextMenuData() const
+{
+ return m_lastContextMenuData.get();
+}
+
+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 WebDragData& data, WebDragOperationsMask mask, const WebImage&, const WebPoint&)
+{
+ 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.
+ m_shell->eventSender()->doDragDrop(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::postAccessibilityNotification(const WebAccessibilityObject& obj, WebAccessibilityNotification notification)
+{
+ if (notification == WebAccessibilityNotificationFocusedUIElementChanged)
+ m_shell->accessibilityController()->setFocusedElement(obj);
+
+ if (m_shell->accessibilityController()->shouldDumpAccessibilityNotifications()) {
+ printf("AccessibilityNotification - ");
+
+ switch (notification) {
+ case WebAccessibilityNotificationActiveDescendantChanged:
+ printf("ActiveDescendantChanged");
+ break;
+ case WebAccessibilityNotificationCheckedStateChanged:
+ printf("CheckedStateChanged");
+ break;
+ case WebAccessibilityNotificationChildrenChanged:
+ printf("ChildrenChanged");
+ break;
+ case WebAccessibilityNotificationFocusedUIElementChanged:
+ printf("FocusedUIElementChanged");
+ break;
+ case WebAccessibilityNotificationLayoutComplete:
+ printf("LayoutComplete");
+ break;
+ case WebAccessibilityNotificationLoadComplete:
+ printf("LoadComplete");
+ break;
+ case WebAccessibilityNotificationSelectedChildrenChanged:
+ printf("SelectedChildrenChanged");
+ break;
+ case WebAccessibilityNotificationSelectedTextChanged:
+ printf("SelectedTextChanged");
+ break;
+ case WebAccessibilityNotificationValueChanged:
+ printf("ValueChanged");
+ break;
+ case WebAccessibilityNotificationScrolledToAnchor:
+ printf("ScrolledToAnchor");
+ break;
+ case WebAccessibilityNotificationLiveRegionChanged:
+ printf("LiveRegionChanged");
+ break;
+ case WebAccessibilityNotificationMenuListValueChanged:
+ printf("MenuListValueChanged");
+ break;
+ case WebAccessibilityNotificationRowCountChanged:
+ printf("RowCountChanged");
+ break;
+ case WebAccessibilityNotificationRowCollapsed:
+ printf("RowCollapsed");
+ break;
+ case WebAccessibilityNotificationRowExpanded:
+ printf("RowExpanded");
+ break;
+ default:
+ break;
+ }
+
+ WebKit::WebNode node = obj.node();
+ if (!node.isNull() && node.isElementNode()) {
+ WebKit::WebElement element = node.to<WebKit::WebElement>();
+ if (element.hasAttribute("id"))
+ printf(" - id:%s", element.getAttribute("id").utf8().data());
+ }
+
+ printf("\n");
+ }
+}
+
+WebNotificationPresenter* WebViewHost::notificationPresenter()
+{
+ return m_shell->notificationPresenter();
+}
+
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+WebKit::WebGeolocationClient* WebViewHost::geolocationClient()
+{
+ return geolocationClientMock();
+}
+
+WebKit::WebGeolocationClientMock* WebViewHost::geolocationClientMock()
+{
+ if (!m_geolocationClientMock)
+ m_geolocationClientMock.set(WebGeolocationClientMock::create());
+ return m_geolocationClientMock.get();
+}
+#else
+WebKit::WebGeolocationService* WebViewHost::geolocationService()
+{
+ if (!m_geolocationServiceMock)
+ m_geolocationServiceMock.set(WebGeolocationServiceMock::createWebGeolocationServiceMock());
+ return m_geolocationServiceMock.get();
+}
+#endif
+
+WebSpeechInputController* WebViewHost::speechInputController(WebKit::WebSpeechInputListener* listener)
+{
+ if (!m_speechInputControllerMock)
+ m_speechInputControllerMock.set(WebSpeechInputControllerMock::create(listener));
+ return m_speechInputControllerMock.get();
+}
+
+WebDeviceOrientationClientMock* WebViewHost::deviceOrientationClientMock()
+{
+ if (!m_deviceOrientationClientMock.get())
+ m_deviceOrientationClientMock.set(WebDeviceOrientationClientMock::create());
+ return m_deviceOrientationClientMock.get();
+}
+
+MockSpellCheck* WebViewHost::mockSpellCheck()
+{
+ return &m_spellcheck;
+}
+
+WebDeviceOrientationClient* WebViewHost::deviceOrientationClient()
+{
+ return deviceOrientationClientMock();
+}
+
+// WebWidgetClient -----------------------------------------------------------
+
+void WebViewHost::didInvalidateRect(const WebRect& rect)
+{
+ 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::scheduleComposite()
+{
+ WebSize widgetSize = webWidget()->size();
+ WebRect clientRect(0, 0, widgetSize.width, widgetSize.height);
+ didInvalidateRect(clientRect);
+}
+
+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::closeWidget()
+{
+ m_hasWindow = false;
+ m_shell->closeWindow(this);
+ // No more code here, we should be deleted at this point.
+}
+
+static void invokeCloseWidget(void* context)
+{
+ WebViewHost* wvh = static_cast<WebViewHost*>(context);
+ wvh->closeWidget();
+}
+
+void WebViewHost::closeWidgetSoon()
+{
+ webkit_support::PostDelayedTask(invokeCloseWidget, static_cast<void*>(this), 0);
+}
+
+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()
+{
+ bool oldState = webkit_support::MessageLoopNestableTasksAllowed();
+ webkit_support::MessageLoopSetNestableTasksAllowed(true);
+ m_inModalLoop = true;
+ webkit_support::RunMessageLoop();
+ webkit_support::MessageLoopSetNestableTasksAllowed(oldState);
+}
+
+// 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);
+}
+
+WebApplicationCacheHost* WebViewHost::createApplicationCacheHost(WebFrame* frame, WebApplicationCacheHostClient* client)
+{
+ return webkit_support::CreateApplicationCacheHost(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)
+{
+ return webkit_support::CreateCancelledError(request);
+}
+
+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.leakPtr());
+ if (!layoutTestController()->deferMainResourceDataLoad())
+ ds->setDeferMainResourceDataLoad(false);
+}
+
+void WebViewHost::didStartProvisionalLoad(WebFrame* frame)
+{
+ if (m_shell->shouldDumpUserGestureInFrameLoadCallbacks())
+ printFrameUserGestureStatus(frame, " - in didStartProvisionalLoadForFrame\n");
+ 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::didNavigateWithinPage(WebFrame* frame, bool isNewNavigation)
+{
+ frame->dataSource()->setExtraData(m_pendingExtraData.leakPtr());
+
+ updateForCommittedLoad(frame, isNewNavigation);
+}
+
+void WebViewHost::didChangeLocationWithinPage(WebFrame* frame)
+{
+ if (m_shell->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(frame);
+ fputs(" - didChangeLocationWithinPageForFrame\n", stdout);
+ }
+}
+
+void WebViewHost::assignIdentifierToRequest(WebFrame*, unsigned identifier, const WebURLRequest& request)
+{
+ if (!m_shell->shouldDumpResourceLoadCallbacks())
+ return;
+ ASSERT(!m_resourceIdentifierMap.contains(identifier));
+ m_resourceIdentifierMap.set(identifier, descriptionSuitableForTestResult(request.url().spec()));
+}
+
+void WebViewHost::removeIdentifierForRequest(unsigned identifier)
+{
+ m_resourceIdentifierMap.remove(identifier);
+}
+
+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 ",
+ 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"
+ && !m_shell->allowExternalPages()) {
+ 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;
+ }
+
+ HashSet<String>::const_iterator end = m_clearHeaders.end();
+ for (HashSet<String>::const_iterator header = m_clearHeaders.begin(); header != end; ++header)
+ request.clearHTTPHeaderField(WebString(header->characters(), header->length()));
+
+ // 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()) {
+ printResourceDescription(identifier);
+ fputs(" - didReceiveResponse ", stdout);
+ printResponseDescription(response);
+ fputs("\n", stdout);
+ }
+ if (m_shell->shouldDumpResourceResponseMIMETypes()) {
+ GURL url = response.url();
+ WebString mimeType = response.mimeType();
+ printf("%s has MIME type %s\n",
+ url.ExtractFileName().c_str(),
+ // Simulate NSURLResponse's mapping of empty/unknown MIME types to application/octet-stream
+ mimeType.isEmpty() ? "application/octet-stream" : mimeType.utf8().data());
+ }
+}
+
+void WebViewHost::didFinishResourceLoad(WebFrame*, unsigned identifier)
+{
+ if (m_shell->shouldDumpResourceLoadCallbacks()) {
+ printResourceDescription(identifier);
+ fputs(" - didFinishLoading\n", stdout);
+ }
+ removeIdentifierForRequest(identifier);
+}
+
+void WebViewHost::didFailResourceLoad(WebFrame*, unsigned identifier, const WebURLError& error)
+{
+ if (m_shell->shouldDumpResourceLoadCallbacks()) {
+ printResourceDescription(identifier);
+ fputs(" - didFailLoadingWithError: ", stdout);
+ fputs(webkit_support::MakeURLErrorDescription(error).c_str(), stdout);
+ fputs("\n", stdout);
+ }
+ removeIdentifierForRequest(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;
+}
+
+void WebViewHost::openFileSystem(WebFrame* frame, WebFileSystem::Type type, long long size, bool create, WebFileSystemCallbacks* callbacks)
+{
+ webkit_support::OpenFileSystem(frame, type, size, create, callbacks);
+}
+
+// Public functions -----------------------------------------------------------
+
+WebViewHost::WebViewHost(TestShell* shell)
+ : m_shell(shell)
+ , m_webWidget(0)
+{
+ reset();
+}
+
+WebViewHost::~WebViewHost()
+{
+ // DevTools frontend page is supposed to be navigated only once and
+ // loading another URL in that Page is an error.
+ if (m_shell->devToolsWebView() != this) {
+ // Navigate to an empty page to fire all the destruction logic for the
+ // current page.
+ loadURLForFrame(GURL("about:blank"), WebString());
+ }
+
+ // Call GC twice to clean up garbage.
+ m_shell->callJSGC();
+ m_shell->callJSGC();
+
+ webWidget()->close();
+
+ if (m_inModalLoop)
+ webkit_support::QuitMessageLoop();
+}
+
+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()
+{
+ m_policyDelegateEnabled = false;
+ m_policyDelegateIsPermissive = false;
+ m_policyDelegateShouldNotifyDone = false;
+ m_topLoadingFrame = 0;
+ m_pageId = -1;
+ m_lastPageIdUpdated = -1;
+ m_hasWindow = false;
+ m_inModalLoop = false;
+ m_smartInsertDeleteEnabled = true;
+#if OS(WINDOWS)
+ m_selectTrailingWhitespaceEnabled = true;
+#else
+ m_selectTrailingWhitespaceEnabled = false;
+#endif
+ m_blocksRedirects = false;
+ m_requestReturnNull = false;
+ m_isPainting = false;
+ m_canvas.clear();
+
+ m_navigationController.set(new TestNavigationController(this));
+
+ m_pendingExtraData.clear();
+ m_resourceIdentifierMap.clear();
+ m_clearHeaders.clear();
+ m_editCommandName.clear();
+ m_editCommandValue.clear();
+
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+ if (m_geolocationClientMock.get())
+ m_geolocationClientMock->resetMock();
+#else
+ m_geolocationServiceMock.clear();
+#endif
+
+ if (m_speechInputControllerMock.get())
+ m_speechInputControllerMock->clearResults();
+
+ m_currentCursor = WebCursorInfo();
+ m_windowRect = WebRect();
+ m_paintRect = WebRect();
+
+ if (m_webWidget)
+ webView()->mainFrame()->setName(WebString());
+}
+
+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(TestNavigationEntry::create(-1, url, WebString(), frameName).get());
+}
+
+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().url());
+}
+
+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();
+ RefPtr<TestNavigationEntry> entry(TestNavigationEntry::create());
+
+ // 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.get());
+ updateAddressBar(frame->view());
+ 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 = 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::printFrameUserGestureStatus(WebFrame* webframe, const char* msg)
+{
+ bool isUserGesture = webframe->isProcessingUserGesture();
+ printf("Frame with user gesture \"%s\"%s", isUserGesture ? "true" : "false", msg);
+}
+
+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(canvas()->getTopPlatformDevice().GetBitmapContext(), rect);
+#else
+ webWidget()->paint(canvas(), 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
+ // for the first two calls. This is necessary because some WebCore rendering
+ // objects update their layout only when painted.
+ // Store the total area painted in total_paint. Then tell the gdk window
+ // to update that area after we're done painting it.
+ for (int i = 0; i < 3; ++i) {
+ // 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);
+ }
+ ASSERT(m_paintRect.isEmpty());
+}
+
+PlatformCanvas* WebViewHost::canvas()
+{
+ if (m_canvas)
+ return m_canvas.get();
+ WebSize widgetSize = webWidget()->size();
+ resetScrollRect();
+ 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/Tools/DumpRenderTree/chromium/WebViewHost.h b/Tools/DumpRenderTree/chromium/WebViewHost.h
new file mode 100644
index 0000000..20b29c0
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/WebViewHost.h
@@ -0,0 +1,332 @@
+/*
+ * 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 "WebAccessibilityNotification.h"
+#include "WebCursorInfo.h"
+#include "WebFrameClient.h"
+#include "WebViewClient.h"
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#include <wtf/Vector.h>
+#include <wtf/text/WTFString.h>
+
+class LayoutTestController;
+class TestShell;
+namespace WebKit {
+class WebFrame;
+class WebDeviceOrientationClient;
+class WebDeviceOrientationClientMock;
+class WebGeolocationClient;
+class WebGeolocationClientMock;
+class WebGeolocationServiceMock;
+class WebSpeechInputController;
+class WebSpeechInputControllerMock;
+class WebSpeechInputListener;
+class WebURL;
+struct WebRect;
+struct WebURLError;
+struct WebWindowFeatures;
+}
+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(); }
+
+ void addClearHeader(const WTF::String& header) { m_clearHeaders.add(header); }
+ const HashSet<WTF::String>& clearHeaders() const { return m_clearHeaders; }
+ void closeWidget();
+
+ WebKit::WebContextMenuData* lastContextMenuData() const;
+ void clearContextMenuData();
+
+ WebKit::WebSpeechInputControllerMock* speechInputControllerMock() { return m_speechInputControllerMock.get(); }
+
+ // NavigationHost
+ virtual bool navigate(const TestNavigationEntry&, bool reload);
+
+ // WebKit::WebViewClient
+ virtual WebKit::WebView* createView(WebKit::WebFrame*, const WebKit::WebWindowFeatures&, const WebKit::WebString&);
+ virtual WebKit::WebWidget* createPopupMenu(WebKit::WebPopupType);
+ virtual WebKit::WebWidget* createPopupMenu(const WebKit::WebPopupMenuInfo&);
+ virtual WebKit::WebStorageNamespace* createSessionStorageNamespace(unsigned quota);
+ 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::WebDragData&, WebKit::WebDragOperationsMask, const WebKit::WebImage&, const WebKit::WebPoint&);
+ virtual void navigateBackForwardSoon(int offset);
+ virtual int historyBackListCount();
+ virtual int historyForwardListCount();
+ virtual void postAccessibilityNotification(const WebKit::WebAccessibilityObject&, WebKit::WebAccessibilityNotification);
+ virtual WebKit::WebNotificationPresenter* notificationPresenter();
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+ virtual WebKit::WebGeolocationClient* geolocationClient();
+#else
+ virtual WebKit::WebGeolocationService* geolocationService();
+#endif
+ virtual WebKit::WebSpeechInputController* speechInputController(WebKit::WebSpeechInputListener*);
+ virtual WebKit::WebDeviceOrientationClient* deviceOrientationClient();
+
+ // WebKit::WebWidgetClient
+ virtual void didInvalidateRect(const WebKit::WebRect&);
+ virtual void didScrollRect(int dx, int dy, const WebKit::WebRect&);
+ virtual void scheduleComposite();
+ 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 WebKit::WebApplicationCacheHost* createApplicationCacheHost(WebKit::WebFrame*, WebKit::WebApplicationCacheHostClient*);
+ 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 didNavigateWithinPage(WebKit::WebFrame*, bool isNewNavigation);
+ virtual void didChangeLocationWithinPage(WebKit::WebFrame*);
+ virtual void assignIdentifierToRequest(WebKit::WebFrame*, unsigned identifier, const WebKit::WebURLRequest&);
+ virtual void removeIdentifierForRequest(unsigned identifier);
+ 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);
+ virtual void openFileSystem(WebKit::WebFrame*, WebKit::WebFileSystem::Type, long long size, bool create, WebKit::WebFileSystemCallbacks*);
+
+ WebKit::WebDeviceOrientationClientMock* deviceOrientationClientMock();
+ MockSpellCheck* mockSpellCheck();
+
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+ // Geolocation client mocks for LayoutTestController
+ WebKit::WebGeolocationClientMock* geolocationClientMock();
+#endif
+
+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*);
+
+ // Dumping the user gesture status to the console.
+ void printFrameUserGestureStatus(WebKit::WebFrame*, const char*);
+
+ 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;
+ bool m_inModalLoop;
+ 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;
+
+ // Set of headers to clear in willSendRequest.
+ HashSet<WTF::String> m_clearHeaders;
+
+ // 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<WebKit::WebContextMenuData> m_lastContextMenuData;
+
+ // Geolocation
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+ OwnPtr<WebKit::WebGeolocationClientMock> m_geolocationClientMock;
+#else
+ OwnPtr<WebKit::WebGeolocationServiceMock> m_geolocationServiceMock;
+#endif
+
+ OwnPtr<WebKit::WebDeviceOrientationClientMock> m_deviceOrientationClientMock;
+ OwnPtr<WebKit::WebSpeechInputControllerMock> m_speechInputControllerMock;
+
+ OwnPtr<TestNavigationController*> m_navigationController;
+};
+
+#endif // WebViewHost_h
diff --git a/Tools/DumpRenderTree/chromium/config.h b/Tools/DumpRenderTree/chromium/config.h
new file mode 100644
index 0000000..7dfda18
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/config.h
@@ -0,0 +1,56 @@
+/*
+ * 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>
+
+#if OS(WINDOWS) && !COMPILER(GCC)
+// Allow 'this' to be used in base member initializer list.
+#pragma warning(disable : 4355)
+// JS_EXPORTDATA is needed to inlucde wtf/WTFString.h.
+#define JS_EXPORTDATA __declspec(dllimport)
+#else
+#define JS_EXPORTDATA
+#endif
+
+#endif // config_h
diff --git a/Tools/DumpRenderTree/chromium/fonts.conf b/Tools/DumpRenderTree/chromium/fonts.conf
new file mode 100644
index 0000000..be214c6
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/fonts.conf
@@ -0,0 +1,155 @@
+<?xml version="1.0"?>
+<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
+<!-- /etc/fonts/fonts.conf file to configure system font access -->
+<fontconfig>
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>Times</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Times New Roman</string>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>sans</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Arial</string>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>sans serif</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Arial</string>
+ </edit>
+ </match>
+
+ <!-- Some layout tests specify Helvetica as a family and we need to make sure
+ that we don't fallback to Times New Roman for them -->
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>Helvetica</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Arial</string>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>sans-serif</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Arial</string>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>serif</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Times New Roman</string>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>mono</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Courier New</string>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>monospace</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Courier New</string>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>Courier</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Courier New</string>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>cursive</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Comic Sans MS</string>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>fantasy</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Impact</string>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>Monaco</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Times New Roman</string>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test name="family" compare="eq">
+ <string>NonAntiAliasedSans</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Arial</string>
+ </edit>
+ <edit name="antialias" mode="assign">
+ <bool>false</bool>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test name="family" compare="eq">
+ <string>SlightHintedGeorgia</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Georgia</string>
+ </edit>
+ <edit name="hintstyle" mode="assign">
+ <const>hintslight</const>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test name="family" compare="eq">
+ <string>NonHintedSans</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Verdana</string>
+ </edit>
+ <!-- These deliberately contradict each other. The 'hinting' preference
+ should take priority -->
+ <edit name="hintstyle" mode="assign">
+ <const>hintfull</const>
+ </edit>
+ <edit name="hinting" mode="assign">
+ <bool>false</bool>
+ </edit>
+ </match>
+</fontconfig>