summaryrefslogtreecommitdiffstats
path: root/WebKitTools/DumpRenderTree/chromium
diff options
context:
space:
mode:
Diffstat (limited to 'WebKitTools/DumpRenderTree/chromium')
-rw-r--r--WebKitTools/DumpRenderTree/chromium/AccessibilityController.cpp119
-rw-r--r--WebKitTools/DumpRenderTree/chromium/AccessibilityController.h73
-rw-r--r--WebKitTools/DumpRenderTree/chromium/AccessibilityUIElement.cpp585
-rw-r--r--WebKitTools/DumpRenderTree/chromium/AccessibilityUIElement.h142
-rw-r--r--WebKitTools/DumpRenderTree/chromium/CppBoundClass.cpp350
-rw-r--r--WebKitTools/DumpRenderTree/chromium/CppBoundClass.h241
-rw-r--r--WebKitTools/DumpRenderTree/chromium/CppVariant.cpp310
-rw-r--r--WebKitTools/DumpRenderTree/chromium/CppVariant.h133
-rw-r--r--WebKitTools/DumpRenderTree/chromium/DumpRenderTree.cpp119
-rw-r--r--WebKitTools/DumpRenderTree/chromium/EventSender.cpp807
-rw-r--r--WebKitTools/DumpRenderTree/chromium/EventSender.h145
-rw-r--r--WebKitTools/DumpRenderTree/chromium/ImageDiff.cpp407
-rw-r--r--WebKitTools/DumpRenderTree/chromium/LayoutTestController.cpp1179
-rw-r--r--WebKitTools/DumpRenderTree/chromium/LayoutTestController.h440
-rw-r--r--WebKitTools/DumpRenderTree/chromium/LayoutTestHelper.mm118
-rw-r--r--WebKitTools/DumpRenderTree/chromium/MockSpellCheck.cpp149
-rw-r--r--WebKitTools/DumpRenderTree/chromium/MockSpellCheck.h82
-rw-r--r--WebKitTools/DumpRenderTree/chromium/PlainTextController.cpp79
-rw-r--r--WebKitTools/DumpRenderTree/chromium/PlainTextController.h52
-rw-r--r--WebKitTools/DumpRenderTree/chromium/TestNavigationController.cpp269
-rw-r--r--WebKitTools/DumpRenderTree/chromium/TestNavigationController.h204
-rw-r--r--WebKitTools/DumpRenderTree/chromium/TestShell.cpp614
-rw-r--r--WebKitTools/DumpRenderTree/chromium/TestShell.h149
-rw-r--r--WebKitTools/DumpRenderTree/chromium/TestShellGtk.cpp64
-rw-r--r--WebKitTools/DumpRenderTree/chromium/TestShellMac.mm125
-rw-r--r--WebKitTools/DumpRenderTree/chromium/TestShellWin.cpp100
-rw-r--r--WebKitTools/DumpRenderTree/chromium/TestWebWorker.h88
-rw-r--r--WebKitTools/DumpRenderTree/chromium/TextInputController.cpp216
-rw-r--r--WebKitTools/DumpRenderTree/chromium/TextInputController.h149
-rw-r--r--WebKitTools/DumpRenderTree/chromium/WebViewHost.cpp1316
-rw-r--r--WebKitTools/DumpRenderTree/chromium/WebViewHost.h271
-rw-r--r--WebKitTools/DumpRenderTree/chromium/config.h54
32 files changed, 9149 insertions, 0 deletions
diff --git a/WebKitTools/DumpRenderTree/chromium/AccessibilityController.cpp b/WebKitTools/DumpRenderTree/chromium/AccessibilityController.cpp
new file mode 100644
index 0000000..afe850c
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/AccessibilityController.cpp
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "AccessibilityController.h"
+
+#include "TestShell.h"
+#include "public/WebAccessibilityCache.h"
+#include "public/WebAccessibilityObject.h"
+#include "public/WebFrame.h"
+#include "public/WebString.h"
+#include "public/WebView.h"
+
+using namespace WebKit;
+
+AccessibilityController::AccessibilityController(TestShell* shell)
+ : m_shell(shell)
+{
+
+ bindMethod("logFocusEvents",
+ &AccessibilityController::logFocusEventsCallback);
+ bindMethod("logScrollingStartEvents",
+ &AccessibilityController::logScrollingStartEventsCallback);
+
+ bindProperty("focusedElement",
+ &AccessibilityController::focusedElementGetterCallback);
+ bindProperty("rootElement",
+ &AccessibilityController::rootElementGetterCallback);
+
+ bindFallbackMethod(&AccessibilityController::fallbackCallback);
+}
+
+void AccessibilityController::bindToJavascript(WebFrame* frame, const WebString& classname)
+{
+ WebAccessibilityCache::enableAccessibility();
+ CppBoundClass::bindToJavascript(frame, classname);
+}
+
+void AccessibilityController::reset()
+{
+ m_rootElement = WebAccessibilityObject();
+ m_focusedElement = WebAccessibilityObject();
+ m_elements.clear();
+}
+
+void AccessibilityController::setFocusedElement(const WebAccessibilityObject& focusedElement)
+{
+ m_focusedElement = focusedElement;
+}
+
+AccessibilityUIElement* AccessibilityController::getFocusedElement()
+{
+ if (m_focusedElement.isNull())
+ m_focusedElement = m_shell->webView()->accessibilityObject();
+ return m_elements.create(m_focusedElement);
+}
+
+AccessibilityUIElement* AccessibilityController::getRootElement()
+{
+ if (m_rootElement.isNull())
+ m_rootElement = m_shell->webView()->accessibilityObject();
+ return m_elements.createRoot(m_rootElement);
+}
+
+void AccessibilityController::logFocusEventsCallback(const CppArgumentList&, CppVariant* result)
+{
+ // As of r49031, this is not being used upstream.
+ result->setNull();
+}
+
+void AccessibilityController::logScrollingStartEventsCallback(const CppArgumentList&, CppVariant* result)
+{
+ // As of r49031, this is not being used upstream.
+ result->setNull();
+}
+
+void AccessibilityController::focusedElementGetterCallback(CppVariant* result)
+{
+ result->set(*(getFocusedElement()->getAsCppVariant()));
+}
+
+void AccessibilityController::rootElementGetterCallback(CppVariant* result)
+{
+ result->set(*(getRootElement()->getAsCppVariant()));
+}
+
+void AccessibilityController::fallbackCallback(const CppArgumentList&, CppVariant* result)
+{
+ printf("CONSOLE MESSAGE: JavaScript ERROR: unknown method called on "
+ "AccessibilityController\n");
+ result->setNull();
+}
diff --git a/WebKitTools/DumpRenderTree/chromium/AccessibilityController.h b/WebKitTools/DumpRenderTree/chromium/AccessibilityController.h
new file mode 100644
index 0000000..3cde7cc
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/AccessibilityController.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef AccessibilityController_h
+#define AccessibilityController_h
+
+#include "AccessibilityUIElement.h"
+#include "CppBoundClass.h"
+
+namespace WebKit {
+class WebAccessibilityObject;
+class WebFrame;
+}
+
+class TestShell;
+
+class AccessibilityController : public CppBoundClass {
+public:
+ explicit AccessibilityController(TestShell*);
+
+ // Shadow to include accessibility initialization.
+ void bindToJavascript(WebKit::WebFrame*, const WebKit::WebString& classname);
+ void reset();
+
+ void setFocusedElement(const WebKit::WebAccessibilityObject&);
+ AccessibilityUIElement* getFocusedElement();
+ AccessibilityUIElement* getRootElement();
+
+private:
+ // Bound methods and properties
+ void logFocusEventsCallback(const CppArgumentList&, CppVariant*);
+ void logScrollingStartEventsCallback(const CppArgumentList&, CppVariant*);
+ void fallbackCallback(const CppArgumentList&, CppVariant*);
+
+ void focusedElementGetterCallback(CppVariant*);
+ void rootElementGetterCallback(CppVariant*);
+
+ WebKit::WebAccessibilityObject m_focusedElement;
+ WebKit::WebAccessibilityObject m_rootElement;
+
+ AccessibilityUIElementList m_elements;
+
+ TestShell* m_shell;
+};
+
+#endif // AccessibilityController_h
diff --git a/WebKitTools/DumpRenderTree/chromium/AccessibilityUIElement.cpp b/WebKitTools/DumpRenderTree/chromium/AccessibilityUIElement.cpp
new file mode 100644
index 0000000..8698e25
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/AccessibilityUIElement.cpp
@@ -0,0 +1,585 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "AccessibilityUIElement.h"
+
+#include "public/WebAccessibilityObject.h"
+#include "public/WebCString.h"
+#include "public/WebString.h"
+#include <wtf/Assertions.h>
+
+using namespace WebKit;
+using namespace std;
+
+// Map role value to string, matching Safari/Mac platform implementation to
+// avoid rebaselining layout tests.
+static string roleToString(WebAccessibilityRole role)
+{
+ string result = "AXRole: AX";
+ switch (role) {
+ case WebAccessibilityRoleButton:
+ return result.append("Button");
+ case WebAccessibilityRoleRadioButton:
+ return result.append("RadioButton");
+ case WebAccessibilityRoleCheckBox:
+ return result.append("CheckBox");
+ case WebAccessibilityRoleSlider:
+ return result.append("Slider");
+ case WebAccessibilityRoleTabGroup:
+ return result.append("TabGroup");
+ case WebAccessibilityRoleTextField:
+ return result.append("TextField");
+ case WebAccessibilityRoleStaticText:
+ return result.append("StaticText");
+ case WebAccessibilityRoleTextArea:
+ return result.append("TextArea");
+ case WebAccessibilityRoleScrollArea:
+ return result.append("ScrollArea");
+ case WebAccessibilityRolePopUpButton:
+ return result.append("PopUpButton");
+ case WebAccessibilityRoleMenuButton:
+ return result.append("MenuButton");
+ case WebAccessibilityRoleTable:
+ return result.append("Table");
+ case WebAccessibilityRoleApplication:
+ return result.append("Application");
+ case WebAccessibilityRoleGroup:
+ return result.append("Group");
+ case WebAccessibilityRoleRadioGroup:
+ return result.append("RadioGroup");
+ case WebAccessibilityRoleList:
+ return result.append("List");
+ case WebAccessibilityRoleScrollBar:
+ return result.append("ScrollBar");
+ case WebAccessibilityRoleValueIndicator:
+ return result.append("ValueIndicator");
+ case WebAccessibilityRoleImage:
+ return result.append("Image");
+ case WebAccessibilityRoleMenuBar:
+ return result.append("MenuBar");
+ case WebAccessibilityRoleMenu:
+ return result.append("Menu");
+ case WebAccessibilityRoleMenuItem:
+ return result.append("MenuItem");
+ case WebAccessibilityRoleColumn:
+ return result.append("Column");
+ case WebAccessibilityRoleRow:
+ return result.append("Row");
+ case WebAccessibilityRoleToolbar:
+ return result.append("Toolbar");
+ case WebAccessibilityRoleBusyIndicator:
+ return result.append("BusyIndicator");
+ case WebAccessibilityRoleProgressIndicator:
+ return result.append("ProgressIndicator");
+ case WebAccessibilityRoleWindow:
+ return result.append("Window");
+ case WebAccessibilityRoleDrawer:
+ return result.append("Drawer");
+ case WebAccessibilityRoleSystemWide:
+ return result.append("SystemWide");
+ case WebAccessibilityRoleOutline:
+ return result.append("Outline");
+ case WebAccessibilityRoleIncrementor:
+ return result.append("Incrementor");
+ case WebAccessibilityRoleBrowser:
+ return result.append("Browser");
+ case WebAccessibilityRoleComboBox:
+ return result.append("ComboBox");
+ case WebAccessibilityRoleSplitGroup:
+ return result.append("SplitGroup");
+ case WebAccessibilityRoleSplitter:
+ return result.append("Splitter");
+ case WebAccessibilityRoleColorWell:
+ return result.append("ColorWell");
+ case WebAccessibilityRoleGrowArea:
+ return result.append("GrowArea");
+ case WebAccessibilityRoleSheet:
+ return result.append("Sheet");
+ case WebAccessibilityRoleHelpTag:
+ return result.append("HelpTag");
+ case WebAccessibilityRoleMatte:
+ return result.append("Matte");
+ case WebAccessibilityRoleRuler:
+ return result.append("Ruler");
+ case WebAccessibilityRoleRulerMarker:
+ return result.append("RulerMarker");
+ case WebAccessibilityRoleLink:
+ return result.append("Link");
+ case WebAccessibilityRoleDisclosureTriangle:
+ return result.append("DisclosureTriangle");
+ case WebAccessibilityRoleGrid:
+ return result.append("Grid");
+ case WebAccessibilityRoleCell:
+ return result.append("Cell");
+ case WebAccessibilityRoleColumnHeader:
+ return result.append("ColumnHeader");
+ case WebAccessibilityRoleRowHeader:
+ return result.append("RowHeader");
+ case WebAccessibilityRoleWebCoreLink:
+ // Maps to Link role.
+ return result.append("Link");
+ case WebAccessibilityRoleImageMapLink:
+ return result.append("ImageMapLink");
+ case WebAccessibilityRoleImageMap:
+ return result.append("ImageMap");
+ case WebAccessibilityRoleListMarker:
+ return result.append("ListMarker");
+ case WebAccessibilityRoleWebArea:
+ return result.append("WebArea");
+ case WebAccessibilityRoleHeading:
+ return result.append("Heading");
+ case WebAccessibilityRoleListBox:
+ return result.append("ListBox");
+ case WebAccessibilityRoleListBoxOption:
+ return result.append("ListBoxOption");
+ case WebAccessibilityRoleTableHeaderContainer:
+ return result.append("TableHeaderContainer");
+ case WebAccessibilityRoleDefinitionListTerm:
+ return result.append("DefinitionListTerm");
+ case WebAccessibilityRoleDefinitionListDefinition:
+ return result.append("DefinitionListDefinition");
+ case WebAccessibilityRoleAnnotation:
+ return result.append("Annotation");
+ case WebAccessibilityRoleSliderThumb:
+ return result.append("SliderThumb");
+ case WebAccessibilityRoleLandmarkApplication:
+ return result.append("LandmarkApplication");
+ case WebAccessibilityRoleLandmarkBanner:
+ return result.append("LandmarkBanner");
+ case WebAccessibilityRoleLandmarkComplementary:
+ return result.append("LandmarkComplementary");
+ case WebAccessibilityRoleLandmarkContentInfo:
+ return result.append("LandmarkContentInfo");
+ case WebAccessibilityRoleLandmarkMain:
+ return result.append("LandmarkMain");
+ case WebAccessibilityRoleLandmarkNavigation:
+ return result.append("LandmarkNavigation");
+ case WebAccessibilityRoleLandmarkSearch:
+ return result.append("LandmarkSearch");
+ case WebAccessibilityRoleApplicationLog:
+ return result.append("ApplicationLog");
+ case WebAccessibilityRoleApplicationMarquee:
+ return result.append("ApplicationMarquee");
+ case WebAccessibilityRoleApplicationStatus:
+ return result.append("ApplicationStatus");
+ case WebAccessibilityRoleApplicationTimer:
+ return result.append("ApplicationTimer");
+ case WebAccessibilityRoleDocument:
+ return result.append("Document");
+ case WebAccessibilityRoleDocumentArticle:
+ return result.append("DocumentArticle");
+ case WebAccessibilityRoleDocumentNote:
+ return result.append("DocumentNote");
+ case WebAccessibilityRoleDocumentRegion:
+ return result.append("DocumentRegion");
+ case WebAccessibilityRoleUserInterfaceTooltip:
+ return result.append("UserInterfaceTooltip");
+ default:
+ // Also matches WebAccessibilityRoleUnknown.
+ return result.append("Unknown");
+ }
+}
+
+string getDescription(const WebAccessibilityObject& object)
+{
+ string description = object.accessibilityDescription().utf8();
+ return description.insert(0, "AXDescription: ");
+}
+
+string getRole(const WebAccessibilityObject& object)
+{
+ return roleToString(object.roleValue());
+}
+
+string getTitle(const WebAccessibilityObject& object)
+{
+ string title = object.title().utf8();
+ return title.insert(0, "AXTitle: ");
+}
+
+string getAttributes(const WebAccessibilityObject& object)
+{
+ // FIXME: Concatenate all attributes of the AccessibilityObject.
+ string attributes(getTitle(object));
+ attributes.append("\n");
+ attributes.append(getRole(object));
+ attributes.append("\n");
+ attributes.append(getDescription(object));
+ return attributes;
+}
+
+
+// Collects attributes into a string, delimited by dashes. Used by all methods
+// that output lists of attributes: attributesOfLinkedUIElementsCallback,
+// AttributesOfChildrenCallback, etc.
+class AttributesCollector {
+public:
+ void collectAttributes(const WebAccessibilityObject& object)
+ {
+ m_attributes.append("\n------------\n");
+ m_attributes.append(getAttributes(object));
+ }
+
+ string attributes() const { return m_attributes; }
+
+private:
+ string m_attributes;
+};
+
+AccessibilityUIElement::AccessibilityUIElement(const WebAccessibilityObject& object, Factory* factory)
+ : m_accessibilityObject(object)
+ , m_factory(factory)
+{
+
+ ASSERT(factory);
+
+ bindMethod("allAttributes", &AccessibilityUIElement::allAttributesCallback);
+ bindMethod("attributesOfLinkedUIElements",
+ &AccessibilityUIElement::attributesOfLinkedUIElementsCallback);
+ bindMethod("attributesOfDocumentLinks",
+ &AccessibilityUIElement::attributesOfDocumentLinksCallback);
+ bindMethod("attributesOfChildren",
+ &AccessibilityUIElement::attributesOfChildrenCallback);
+ bindMethod("parameterizedAttributeNames",
+ &AccessibilityUIElement::parametrizedAttributeNamesCallback);
+ bindMethod("lineForIndex", &AccessibilityUIElement::lineForIndexCallback);
+ bindMethod("boundsForRange", &AccessibilityUIElement::boundsForRangeCallback);
+ bindMethod("stringForRange", &AccessibilityUIElement::stringForRangeCallback);
+ bindMethod("childAtIndex", &AccessibilityUIElement::childAtIndexCallback);
+ bindMethod("elementAtPoint", &AccessibilityUIElement::elementAtPointCallback);
+ bindMethod("attributesOfColumnHeaders",
+ &AccessibilityUIElement::attributesOfColumnHeadersCallback);
+ bindMethod("attributesOfRowHeaders",
+ &AccessibilityUIElement::attributesOfRowHeadersCallback);
+ bindMethod("attributesOfColumns",
+ &AccessibilityUIElement::attributesOfColumnsCallback);
+ bindMethod("attributesOfRows",
+ &AccessibilityUIElement::attributesOfRowsCallback);
+ bindMethod("attributesOfVisibleCells",
+ &AccessibilityUIElement::attributesOfVisibleCellsCallback);
+ bindMethod("attributesOfHeader",
+ &AccessibilityUIElement::attributesOfHeaderCallback);
+ bindMethod("indexInTable", &AccessibilityUIElement::indexInTableCallback);
+ bindMethod("rowIndexRange", &AccessibilityUIElement::rowIndexRangeCallback);
+ bindMethod("columnIndexRange",
+ &AccessibilityUIElement::columnIndexRangeCallback);
+ bindMethod("cellForColumnAndRow",
+ &AccessibilityUIElement::cellForColumnAndRowCallback);
+ bindMethod("titleUIElement", &AccessibilityUIElement::titleUIElementCallback);
+ bindMethod("setSelectedTextRange",
+ &AccessibilityUIElement::setSelectedTextRangeCallback);
+ bindMethod("attributeValue", &AccessibilityUIElement::attributeValueCallback);
+ bindMethod("isAttributeSettable",
+ &AccessibilityUIElement::isAttributeSettableCallback);
+ bindMethod("isActionSupported",
+ &AccessibilityUIElement::isActionSupportedCallback);
+ bindMethod("parentElement", &AccessibilityUIElement::parentElementCallback);
+ bindMethod("increment", &AccessibilityUIElement::incrementCallback);
+ bindMethod("decrement", &AccessibilityUIElement::decrementCallback);
+
+ bindProperty("role", &AccessibilityUIElement::roleGetterCallback);
+ bindProperty("subrole", &m_subrole);
+ bindProperty("title", &AccessibilityUIElement::titleGetterCallback);
+ bindProperty("description",
+ &AccessibilityUIElement::descriptionGetterCallback);
+ bindProperty("language", &m_language);
+ bindProperty("x", &m_x);
+ bindProperty("y", &m_y);
+ bindProperty("width", &m_width);
+ bindProperty("height", &m_height);
+ bindProperty("clickPointX", &m_clickPointX);
+ bindProperty("clickPointY", &m_clickPointY);
+ bindProperty("intValue", &m_intValue);
+ bindProperty("minValue", &m_minValue);
+ bindProperty("maxValue", &m_maxValue);
+ bindProperty("childrenCount",
+ &AccessibilityUIElement::childrenCountGetterCallback);
+ bindProperty("insertionPointLineNumber", &m_insertionPointLineNumber);
+ bindProperty("selectedTextRange", &m_selectedTextRange);
+ bindProperty("isEnabled", &AccessibilityUIElement::isEnabledGetterCallback);
+ bindProperty("isRequired", &m_isRequired);
+ bindProperty("isSelected", &AccessibilityUIElement::isSelectedGetterCallback);
+ bindProperty("valueDescription", &m_valueDescription);
+
+ bindFallbackMethod(&AccessibilityUIElement::fallbackCallback);
+}
+
+AccessibilityUIElement* AccessibilityUIElement::getChildAtIndex(unsigned index)
+{
+ return m_factory->create(accessibilityObject().childAt(index));
+}
+
+void AccessibilityUIElement::allAttributesCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->set(getAttributes(accessibilityObject()));
+}
+
+void AccessibilityUIElement::attributesOfLinkedUIElementsCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::attributesOfDocumentLinksCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::attributesOfChildrenCallback(const CppArgumentList& arguments, CppVariant* result)
+{
+ AttributesCollector collector;
+ unsigned size = accessibilityObject().childCount();
+ for (unsigned i = 0; i < size; ++i)
+ collector.collectAttributes(accessibilityObject().childAt(i));
+ result->set(collector.attributes());
+}
+
+void AccessibilityUIElement::parametrizedAttributeNamesCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::lineForIndexCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::boundsForRangeCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::stringForRangeCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::childAtIndexCallback(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (!arguments.size() || !arguments[0].isNumber()) {
+ result->setNull();
+ return;
+ }
+
+ AccessibilityUIElement* child = getChildAtIndex(arguments[0].toInt32());
+ if (!child) {
+ result->setNull();
+ return;
+ }
+
+ result->set(*(child->getAsCppVariant()));
+}
+
+void AccessibilityUIElement::elementAtPointCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::attributesOfColumnHeadersCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::attributesOfRowHeadersCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::attributesOfColumnsCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::attributesOfRowsCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::attributesOfVisibleCellsCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::attributesOfHeaderCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::indexInTableCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::rowIndexRangeCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::columnIndexRangeCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::cellForColumnAndRowCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::titleUIElementCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::setSelectedTextRangeCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::attributeValueCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::isAttributeSettableCallback(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() < 1 && !arguments[0].isString()) {
+ result->setNull();
+ return;
+ }
+
+ string attribute = arguments[0].toString();
+ bool settable = false;
+ if (attribute == "AXValue")
+ settable = accessibilityObject().canSetValueAttribute();
+ result->set(settable);
+}
+
+void AccessibilityUIElement::isActionSupportedCallback(const CppArgumentList&, CppVariant* result)
+{
+ // This one may be really hard to implement.
+ // Not exposed by AccessibilityObject.
+ result->setNull();
+}
+
+void AccessibilityUIElement::parentElementCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::incrementCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::decrementCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::fallbackCallback(const CppArgumentList &, CppVariant* result)
+{
+ // FIXME: Implement this.
+ result->setNull();
+}
+
+void AccessibilityUIElement::childrenCountGetterCallback(CppVariant* result)
+{
+ int count = 1; // Root object always has only one child, the WebView.
+ if (!isRoot())
+ count = accessibilityObject().childCount();
+ result->set(count);
+}
+
+void AccessibilityUIElement::descriptionGetterCallback(CppVariant* result)
+{
+ result->set(getDescription(accessibilityObject()));
+}
+
+void AccessibilityUIElement::isEnabledGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().isEnabled());
+}
+
+void AccessibilityUIElement::isSelectedGetterCallback(CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::roleGetterCallback(CppVariant* result)
+{
+ result->set(getRole(accessibilityObject()));
+}
+
+void AccessibilityUIElement::titleGetterCallback(CppVariant* result)
+{
+ result->set(getTitle(accessibilityObject()));
+}
+
+
+RootAccessibilityUIElement::RootAccessibilityUIElement(const WebAccessibilityObject &object, Factory *factory)
+ : AccessibilityUIElement(object, factory) { }
+
+AccessibilityUIElement* RootAccessibilityUIElement::getChildAtIndex(unsigned index)
+{
+ if (index)
+ return 0;
+
+ return factory()->create(accessibilityObject());
+}
+
+
+AccessibilityUIElementList ::~AccessibilityUIElementList()
+{
+ clear();
+}
+
+void AccessibilityUIElementList::clear()
+{
+ for (ElementList::iterator i = m_elements.begin(); i != m_elements.end(); ++i)
+ delete (*i);
+ m_elements.clear();
+}
+
+AccessibilityUIElement* AccessibilityUIElementList::create(const WebAccessibilityObject& object)
+{
+ if (object.isNull())
+ return 0;
+
+ AccessibilityUIElement* element = new AccessibilityUIElement(object, this);
+ m_elements.append(element);
+ return element;
+}
+
+AccessibilityUIElement* AccessibilityUIElementList::createRoot(const WebAccessibilityObject& object)
+{
+ AccessibilityUIElement* element = new RootAccessibilityUIElement(object, this);
+ m_elements.append(element);
+ return element;
+}
diff --git a/WebKitTools/DumpRenderTree/chromium/AccessibilityUIElement.h b/WebKitTools/DumpRenderTree/chromium/AccessibilityUIElement.h
new file mode 100644
index 0000000..df3f5b9
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/AccessibilityUIElement.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef AccessibilityUIElement_h
+#define AccessibilityUIElement_h
+
+#include "CppBoundClass.h"
+#include "public/WebAccessibilityObject.h"
+#include <wtf/Vector.h>
+
+class AccessibilityUIElement : public CppBoundClass {
+public:
+ class Factory {
+ public:
+ virtual ~Factory() { }
+ virtual AccessibilityUIElement* create(const WebKit::WebAccessibilityObject&) = 0;
+ };
+
+ AccessibilityUIElement(const WebKit::WebAccessibilityObject&, Factory*);
+
+ virtual AccessibilityUIElement* getChildAtIndex(unsigned);
+ virtual bool isRoot() const { return false; }
+
+protected:
+ const WebKit::WebAccessibilityObject& accessibilityObject() const { return m_accessibilityObject; }
+ Factory* factory() const { return m_factory; }
+
+private:
+ // Bound methods and properties.
+ void allAttributesCallback(const CppArgumentList&, CppVariant*);
+ void attributesOfLinkedUIElementsCallback(const CppArgumentList&, CppVariant*);
+ void attributesOfDocumentLinksCallback(const CppArgumentList&, CppVariant*);
+ void attributesOfChildrenCallback(const CppArgumentList&, CppVariant*);
+ void parametrizedAttributeNamesCallback(const CppArgumentList&, CppVariant*);
+ void lineForIndexCallback(const CppArgumentList&, CppVariant*);
+ void boundsForRangeCallback(const CppArgumentList&, CppVariant*);
+ void stringForRangeCallback(const CppArgumentList&, CppVariant*);
+ void childAtIndexCallback(const CppArgumentList&, CppVariant*);
+ void elementAtPointCallback(const CppArgumentList&, CppVariant*);
+ void attributesOfColumnHeadersCallback(const CppArgumentList&, CppVariant*);
+ void attributesOfRowHeadersCallback(const CppArgumentList&, CppVariant*);
+ void attributesOfColumnsCallback(const CppArgumentList&, CppVariant*);
+ void attributesOfRowsCallback(const CppArgumentList&, CppVariant*);
+ void attributesOfVisibleCellsCallback(const CppArgumentList&, CppVariant*);
+ void attributesOfHeaderCallback(const CppArgumentList&, CppVariant*);
+ void indexInTableCallback(const CppArgumentList&, CppVariant*);
+ void rowIndexRangeCallback(const CppArgumentList&, CppVariant*);
+ void columnIndexRangeCallback(const CppArgumentList&, CppVariant*);
+ void cellForColumnAndRowCallback(const CppArgumentList&, CppVariant*);
+ void titleUIElementCallback(const CppArgumentList&, CppVariant*);
+ void setSelectedTextRangeCallback(const CppArgumentList&, CppVariant*);
+ void attributeValueCallback(const CppArgumentList&, CppVariant*);
+ void isAttributeSettableCallback(const CppArgumentList&, CppVariant*);
+ void isActionSupportedCallback(const CppArgumentList&, CppVariant*);
+ void parentElementCallback(const CppArgumentList&, CppVariant*);
+ void incrementCallback(const CppArgumentList&, CppVariant*);
+ void decrementCallback(const CppArgumentList&, CppVariant*);
+ void fallbackCallback(const CppArgumentList&, CppVariant*);
+
+ void childrenCountGetterCallback(CppVariant*);
+ void descriptionGetterCallback(CppVariant*);
+ void isEnabledGetterCallback(CppVariant*);
+ void isSelectedGetterCallback(CppVariant*);
+ void roleGetterCallback(CppVariant*);
+ void titleGetterCallback(CppVariant*);
+
+ CppVariant m_subrole;
+ CppVariant m_language;
+ CppVariant m_x;
+ CppVariant m_y;
+ CppVariant m_width;
+ CppVariant m_height;
+ CppVariant m_clickPointX;
+ CppVariant m_clickPointY;
+ CppVariant m_intValue;
+ CppVariant m_minValue;
+ CppVariant m_maxValue;
+ CppVariant m_childrenCount;
+ CppVariant m_insertionPointLineNumber;
+ CppVariant m_selectedTextRange;
+ CppVariant m_isRequired;
+ CppVariant m_valueDescription;
+
+ WebKit::WebAccessibilityObject m_accessibilityObject;
+ Factory* m_factory;
+};
+
+
+class RootAccessibilityUIElement : public AccessibilityUIElement {
+public:
+ RootAccessibilityUIElement(const WebKit::WebAccessibilityObject&, Factory*);
+
+ virtual AccessibilityUIElement* getChildAtIndex(unsigned);
+ virtual bool isRoot() const { return true; }
+};
+
+
+// Provides simple lifetime management of the AccessibilityUIElement instances:
+// all AccessibilityUIElements ever created from the controller are stored in
+// a list and cleared explicitly.
+class AccessibilityUIElementList : public AccessibilityUIElement::Factory {
+public:
+ AccessibilityUIElementList() { }
+ virtual ~AccessibilityUIElementList();
+
+ void clear();
+ virtual AccessibilityUIElement* create(const WebKit::WebAccessibilityObject&);
+ AccessibilityUIElement* createRoot(const WebKit::WebAccessibilityObject&);
+
+private:
+ typedef Vector<AccessibilityUIElement*> ElementList;
+ ElementList m_elements;
+};
+
+#endif // AccessibilityUIElement_h
diff --git a/WebKitTools/DumpRenderTree/chromium/CppBoundClass.cpp b/WebKitTools/DumpRenderTree/chromium/CppBoundClass.cpp
new file mode 100644
index 0000000..839787a
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/CppBoundClass.cpp
@@ -0,0 +1,350 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2009 Pawel Hajdan (phajdan.jr@chromium.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// This file contains definitions for CppBoundClass
+
+// Here's the control flow of a JS method getting forwarded to a class.
+// - Something calls our NPObject with a function like "Invoke".
+// - CppNPObject's static invoke() function forwards it to its attached
+// CppBoundClass's invoke() method.
+// - CppBoundClass has then overridden invoke() to look up the function
+// name in its internal map of methods, and then calls the appropriate
+// method.
+
+#include "config.h"
+#include "CppBoundClass.h"
+
+#include "public/WebBindings.h"
+#include "public/WebFrame.h"
+#include "public/WebString.h"
+#include <wtf/Assertions.h>
+#include <wtf/OwnPtr.h>
+
+using namespace WebKit;
+using namespace std;
+
+class CppVariantPropertyCallback : public CppBoundClass::PropertyCallback {
+public:
+ CppVariantPropertyCallback(CppVariant* value) : m_value(value) { }
+
+ virtual bool getValue(CppVariant* value)
+ {
+ value->set(*m_value);
+ return true;
+ }
+
+ virtual bool setValue(const CppVariant& value)
+ {
+ m_value->set(value);
+ return true;
+ }
+
+private:
+ CppVariant* m_value;
+};
+
+class GetterPropertyCallback : public CppBoundClass::PropertyCallback {
+public:
+ GetterPropertyCallback(CppBoundClass::GetterCallback* callback)
+ : m_callback(callback) { }
+
+ virtual bool getValue(CppVariant* value)
+ {
+ m_callback->run(value);
+ return true;
+ }
+
+ virtual bool setValue(const CppVariant& value) { return false; }
+
+private:
+ OwnPtr<CppBoundClass::GetterCallback> m_callback;
+};
+
+// Our special NPObject type. We extend an NPObject with a pointer to a
+// CppBoundClass, which is just a C++ interface that we forward all NPObject
+// callbacks to.
+struct CppNPObject {
+ NPObject parent; // This must be the first field in the struct.
+ CppBoundClass* boundClass;
+
+ //
+ // All following objects and functions are static, and just used to interface
+ // with NPObject/NPClass.
+ //
+
+ // An NPClass associates static functions of CppNPObject with the
+ // function pointers used by the JS runtime.
+ static NPClass npClass;
+
+ // Allocate a new NPObject with the specified class.
+ static NPObject* allocate(NPP, NPClass*);
+
+ // Free an object.
+ static void deallocate(NPObject*);
+
+ // Returns true if the C++ class associated with this NPObject exposes the
+ // given property. Called by the JS runtime.
+ static bool hasProperty(NPObject*, NPIdentifier);
+
+ // Returns true if the C++ class associated with this NPObject exposes the
+ // given method. Called by the JS runtime.
+ static bool hasMethod(NPObject*, NPIdentifier);
+
+ // If the given method is exposed by the C++ class associated with this
+ // NPObject, invokes it with the given arguments and returns a result. Otherwise,
+ // returns "undefined" (in the JavaScript sense). Called by the JS runtime.
+ static bool invoke(NPObject*, NPIdentifier,
+ const NPVariant* arguments, uint32_t argumentCount,
+ NPVariant* result);
+
+ // If the given property is exposed by the C++ class associated with this
+ // NPObject, returns its value. Otherwise, returns "undefined" (in the
+ // JavaScript sense). Called by the JS runtime.
+ static bool getProperty(NPObject*, NPIdentifier, NPVariant* result);
+
+ // If the given property is exposed by the C++ class associated with this
+ // NPObject, sets its value. Otherwise, does nothing. Called by the JS
+ // runtime.
+ static bool setProperty(NPObject*, NPIdentifier, const NPVariant* value);
+};
+
+// Build CppNPObject's static function pointers into an NPClass, for use
+// in constructing NPObjects for the C++ classes.
+NPClass CppNPObject::npClass = {
+ NP_CLASS_STRUCT_VERSION,
+ CppNPObject::allocate,
+ CppNPObject::deallocate,
+ /* NPInvalidateFunctionPtr */ 0,
+ CppNPObject::hasMethod,
+ CppNPObject::invoke,
+ /* NPInvokeDefaultFunctionPtr */ 0,
+ CppNPObject::hasProperty,
+ CppNPObject::getProperty,
+ CppNPObject::setProperty,
+ /* NPRemovePropertyFunctionPtr */ 0
+};
+
+NPObject* CppNPObject::allocate(NPP npp, NPClass* aClass)
+{
+ CppNPObject* obj = new CppNPObject;
+ // obj->parent will be initialized by the NPObject code calling this.
+ obj->boundClass = 0;
+ return &obj->parent;
+}
+
+void CppNPObject::deallocate(NPObject* npObj)
+{
+ CppNPObject* obj = reinterpret_cast<CppNPObject*>(npObj);
+ delete obj;
+}
+
+bool CppNPObject::hasMethod(NPObject* npObj, NPIdentifier ident)
+{
+ CppNPObject* obj = reinterpret_cast<CppNPObject*>(npObj);
+ return obj->boundClass->hasMethod(ident);
+}
+
+bool CppNPObject::hasProperty(NPObject* npObj, NPIdentifier ident)
+{
+ CppNPObject* obj = reinterpret_cast<CppNPObject*>(npObj);
+ return obj->boundClass->hasProperty(ident);
+}
+
+bool CppNPObject::invoke(NPObject* npObj, NPIdentifier ident,
+ const NPVariant* arguments, uint32_t argumentCount,
+ NPVariant* result)
+{
+ CppNPObject* obj = reinterpret_cast<CppNPObject*>(npObj);
+ return obj->boundClass->invoke(ident, arguments, argumentCount, result);
+}
+
+bool CppNPObject::getProperty(NPObject* npObj, NPIdentifier ident, NPVariant* result)
+{
+ CppNPObject* obj = reinterpret_cast<CppNPObject*>(npObj);
+ return obj->boundClass->getProperty(ident, result);
+}
+
+bool CppNPObject::setProperty(NPObject* npObj, NPIdentifier ident, const NPVariant* value)
+{
+ CppNPObject* obj = reinterpret_cast<CppNPObject*>(npObj);
+ return obj->boundClass->setProperty(ident, value);
+}
+
+CppBoundClass::~CppBoundClass()
+{
+ for (MethodList::iterator i = m_methods.begin(); i != m_methods.end(); ++i)
+ delete i->second;
+
+ for (PropertyList::iterator i = m_properties.begin(); i != m_properties.end(); ++i)
+ delete i->second;
+
+ // Unregister ourselves if we were bound to a frame.
+ if (m_boundToFrame)
+ WebBindings::unregisterObject(NPVARIANT_TO_OBJECT(m_selfVariant));
+}
+
+bool CppBoundClass::hasMethod(NPIdentifier ident) const
+{
+ return m_methods.find(ident) != m_methods.end();
+}
+
+bool CppBoundClass::hasProperty(NPIdentifier ident) const
+{
+ return m_properties.find(ident) != m_properties.end();
+}
+
+bool CppBoundClass::invoke(NPIdentifier ident,
+ const NPVariant* arguments,
+ size_t argumentCount,
+ NPVariant* result) {
+ MethodList::const_iterator end = m_methods.end();
+ MethodList::const_iterator method = m_methods.find(ident);
+ Callback* callback;
+ if (method == end) {
+ if (!m_fallbackCallback.get()) {
+ VOID_TO_NPVARIANT(*result);
+ return false;
+ }
+ callback = m_fallbackCallback.get();
+ } else
+ callback = (*method).second;
+
+ // Build a CppArgumentList argument vector from the NPVariants coming in.
+ CppArgumentList cppArguments(argumentCount);
+ for (size_t i = 0; i < argumentCount; i++)
+ cppArguments[i].set(arguments[i]);
+
+ CppVariant cppResult;
+ callback->run(cppArguments, &cppResult);
+
+ cppResult.copyToNPVariant(result);
+ return true;
+}
+
+bool CppBoundClass::getProperty(NPIdentifier ident, NPVariant* result) const
+{
+ PropertyList::const_iterator callback = m_properties.find(ident);
+ if (callback == m_properties.end()) {
+ VOID_TO_NPVARIANT(*result);
+ return false;
+ }
+
+ CppVariant cppValue;
+ if (!callback->second->getValue(&cppValue))
+ return false;
+ cppValue.copyToNPVariant(result);
+ return true;
+}
+
+bool CppBoundClass::setProperty(NPIdentifier ident, const NPVariant* value)
+{
+ PropertyList::iterator callback = m_properties.find(ident);
+ if (callback == m_properties.end())
+ return false;
+
+ CppVariant cppValue;
+ cppValue.set(*value);
+ return (*callback).second->setValue(cppValue);
+}
+
+void CppBoundClass::bindCallback(const string& name, Callback* callback)
+{
+ NPIdentifier ident = WebBindings::getStringIdentifier(name.c_str());
+ MethodList::iterator oldCallback = m_methods.find(ident);
+ if (oldCallback != m_methods.end()) {
+ delete oldCallback->second;
+ if (!callback) {
+ m_methods.remove(oldCallback);
+ return;
+ }
+ }
+
+ m_methods.set(ident, callback);
+}
+
+void CppBoundClass::bindGetterCallback(const string& name, GetterCallback* callback)
+{
+ PropertyCallback* propertyCallback = callback ? new GetterPropertyCallback(callback) : 0;
+ bindProperty(name, propertyCallback);
+}
+
+void CppBoundClass::bindProperty(const string& name, CppVariant* prop)
+{
+ PropertyCallback* propertyCallback = prop ? new CppVariantPropertyCallback(prop) : 0;
+ bindProperty(name, propertyCallback);
+}
+
+void CppBoundClass::bindProperty(const string& name, PropertyCallback* callback)
+{
+ NPIdentifier ident = WebBindings::getStringIdentifier(name.c_str());
+ PropertyList::iterator oldCallback = m_properties.find(ident);
+ if (oldCallback != m_properties.end()) {
+ delete oldCallback->second;
+ if (!callback) {
+ m_properties.remove(oldCallback);
+ return;
+ }
+ }
+
+ m_properties.set(ident, callback);
+}
+
+bool CppBoundClass::isMethodRegistered(const string& name) const
+{
+ NPIdentifier ident = WebBindings::getStringIdentifier(name.c_str());
+ MethodList::const_iterator callback = m_methods.find(ident);
+ return callback != m_methods.end();
+}
+
+CppVariant* CppBoundClass::getAsCppVariant()
+{
+ if (!m_selfVariant.isObject()) {
+ // Create an NPObject using our static NPClass. The first argument (a
+ // plugin's instance handle) is passed through to the allocate function
+ // directly, and we don't use it, so it's ok to be 0.
+ NPObject* npObj = WebBindings::createObject(0, &CppNPObject::npClass);
+ CppNPObject* obj = reinterpret_cast<CppNPObject*>(npObj);
+ obj->boundClass = this;
+ m_selfVariant.set(npObj);
+ WebBindings::releaseObject(npObj); // CppVariant takes the reference.
+ }
+ ASSERT(m_selfVariant.isObject());
+ return &m_selfVariant;
+}
+
+void CppBoundClass::bindToJavascript(WebFrame* frame, const WebString& classname)
+{
+ // BindToWindowObject will take its own reference to the NPObject, and clean
+ // up after itself. It will also (indirectly) register the object with V8,
+ // so we must remember this so we can unregister it when we're destroyed.
+ frame->bindToWindowObject(classname, NPVARIANT_TO_OBJECT(*getAsCppVariant()));
+ m_boundToFrame = true;
+}
diff --git a/WebKitTools/DumpRenderTree/chromium/CppBoundClass.h b/WebKitTools/DumpRenderTree/chromium/CppBoundClass.h
new file mode 100644
index 0000000..6cb638e
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/CppBoundClass.h
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2009 Pawel Hajdan (phajdan.jr@chromium.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ CppBoundClass class:
+ This base class serves as a parent for C++ classes designed to be bound to
+ JavaScript objects.
+
+ Subclasses should define the constructor to build the property and method
+ lists needed to bind this class to a JS object. They should also declare
+ and define member variables and methods to be exposed to JS through
+ that object.
+*/
+
+#ifndef CppBoundClass_h
+#define CppBoundClass_h
+
+#include "CppVariant.h"
+#include <wtf/HashMap.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebKit {
+class WebFrame;
+class WebString;
+}
+
+typedef Vector<CppVariant> CppArgumentList;
+
+// CppBoundClass lets you map Javascript method calls and property accesses
+// directly to C++ method calls and CppVariant* variable access.
+class CppBoundClass : public Noncopyable {
+public:
+ class PropertyCallback {
+ public:
+ virtual ~PropertyCallback() { }
+
+ // Sets |value| to the value of the property. Returns false in case of
+ // failure. |value| is always non-0.
+ virtual bool getValue(CppVariant* result) = 0;
+
+ // sets the property value to |value|. Returns false in case of failure.
+ virtual bool setValue(const CppVariant&) = 0;
+ };
+
+ // Callback class for "void function(CppVariant*)"
+ class GetterCallback {
+ public:
+ virtual ~GetterCallback() {}
+ virtual void run(CppVariant*) = 0;
+ };
+
+ // The constructor should call BindMethod, BindProperty, and
+ // SetFallbackMethod as needed to set up the methods, properties, and
+ // fallback method.
+ CppBoundClass() : m_boundToFrame(false) {}
+ virtual ~CppBoundClass();
+
+ // Return a CppVariant representing this class, for use with BindProperty().
+ // The variant type is guaranteed to be NPVariantType_Object.
+ CppVariant* getAsCppVariant();
+
+ // Given a WebFrame, BindToJavascript builds the NPObject that will represent
+ // the class and binds it to the frame's window under the given name. This
+ // should generally be called from the WebView delegate's
+ // WindowObjectCleared(). A class so bound will be accessible to JavaScript
+ // as window.<classname>. The owner of the CppBoundObject is responsible for
+ // keeping the object around while the frame is alive, and for destroying it
+ // afterwards.
+ void bindToJavascript(WebKit::WebFrame*, const WebKit::WebString& classname);
+
+ // Used by a test. Returns true if a method with name |name| exists,
+ // regardless of whether a fallback is registered.
+ bool isMethodRegistered(const std::string&) const;
+
+protected:
+ // Callback for "void function(const CppArguemntList&, CppVariant*)"
+ class Callback {
+ public:
+ virtual ~Callback() {}
+ virtual void run(const CppArgumentList&, CppVariant*) = 0;
+ };
+
+ // Callback for "void T::method(const CppArguemntList&, CppVariant*)"
+ template <class T> class MemberCallback : public Callback {
+ public:
+ typedef void (T::*MethodType)(const CppArgumentList&, CppVariant*);
+ MemberCallback(T* object, MethodType method)
+ : m_object(object)
+ , m_method(method) {}
+ virtual ~MemberCallback() {}
+
+ virtual void run(const CppArgumentList& arguments, CppVariant* result)
+ {
+ (m_object->*m_method)(arguments, result);
+ }
+ private:
+ T* m_object;
+ MethodType m_method;
+ };
+
+ // Callback class for "void T::method(CppVariant*)"
+ template <class T> class MemberGetterCallback : public GetterCallback {
+ public:
+ typedef void (T::*MethodType)(CppVariant*);
+ MemberGetterCallback(T* object, MethodType method)
+ : m_object(object)
+ , m_method(method) {}
+ virtual ~MemberGetterCallback() {}
+
+ virtual void run(CppVariant* result) { (m_object->*m_method)(result); }
+ private:
+ T* m_object;
+ MethodType m_method;
+ };
+
+ // Bind the Javascript method called the string parameter to the C++ method.
+ void bindCallback(const std::string&, Callback*);
+
+ // A wrapper for bindCallback, to simplify the common case of binding a
+ // method on the current object. Though not verified here, |method|
+ // must be a method of this CppBoundClass subclass.
+ template<class T>
+ void bindMethod(const std::string& name, void (T::*method)(const CppArgumentList&, CppVariant*))
+ {
+ Callback* callback = new MemberCallback<T>(static_cast<T*>(this), method);
+ bindCallback(name, callback);
+ }
+
+ // Bind Javascript property |name| to the C++ getter callback |callback|.
+ // This can be used to create read-only properties.
+ void bindGetterCallback(const std::string&, GetterCallback*);
+
+ // A wrapper for BindGetterCallback, to simplify the common case of binding a
+ // property on the current object. Though not verified here, |method|
+ // must be a method of this CppBoundClass subclass.
+ template<class T>
+ void bindProperty(const std::string& name, void (T::*method)(CppVariant*))
+ {
+ GetterCallback* callback = new MemberGetterCallback<T>(static_cast<T*>(this), method);
+ bindGetterCallback(name, callback);
+ }
+
+ // Bind the Javascript property called |name| to a CppVariant.
+ void bindProperty(const std::string&, CppVariant*);
+
+ // Bind Javascript property called |name| to a PropertyCallback.
+ // CppBoundClass assumes control over the life time of the callback.
+ void bindProperty(const std::string&, PropertyCallback*);
+
+ // Set the fallback callback, which is called when when a callback is
+ // invoked that isn't bound.
+ // If it is 0 (its default value), a JavaScript exception is thrown in
+ // that case (as normally expected). If non 0, the fallback method is
+ // invoked and the script continues its execution.
+ // Passing 0 clears out any existing binding.
+ // It is used for tests and should probably only be used in such cases
+ // as it may cause unexpected behaviors (a JavaScript object with a
+ // fallback always returns true when checked for a method's
+ // existence).
+ void bindFallbackCallback(Callback* fallbackCallback)
+ {
+ m_fallbackCallback.set(fallbackCallback);
+ }
+
+ // A wrapper for BindFallbackCallback, to simplify the common case of
+ // binding a method on the current object. Though not verified here,
+ // |method| must be a method of this CppBoundClass subclass.
+ // Passing 0 for |method| clears out any existing binding.
+ template<class T>
+ void bindFallbackMethod(void (T::*method)(const CppArgumentList&, CppVariant*))
+ {
+ if (method) {
+ Callback* callback = new MemberCallback<T>(static_cast<T*>(this), method);
+ bindFallbackCallback(callback);
+ } else
+ bindFallbackCallback(0);
+ }
+
+ // Some fields are protected because some tests depend on accessing them,
+ // but otherwise they should be considered private.
+
+ typedef HashMap<NPIdentifier, PropertyCallback*> PropertyList;
+ typedef HashMap<NPIdentifier, Callback*> MethodList;
+ // These maps associate names with property and method pointers to be
+ // exposed to JavaScript.
+ PropertyList m_properties;
+ MethodList m_methods;
+
+ // The callback gets invoked when a call is made to an nonexistent method.
+ OwnPtr<Callback> m_fallbackCallback;
+
+private:
+ // NPObject callbacks.
+ friend struct CppNPObject;
+ bool hasMethod(NPIdentifier) const;
+ bool invoke(NPIdentifier, const NPVariant* args, size_t argCount,
+ NPVariant* result);
+ bool hasProperty(NPIdentifier) const;
+ bool getProperty(NPIdentifier, NPVariant* result) const;
+ bool setProperty(NPIdentifier, const NPVariant*);
+
+ // A lazily-initialized CppVariant representing this class. We retain 1
+ // reference to this object, and it is released on deletion.
+ CppVariant m_selfVariant;
+
+ // True if our np_object has been bound to a WebFrame, in which case it must
+ // be unregistered with V8 when we delete it.
+ bool m_boundToFrame;
+};
+
+#endif // CppBoundClass_h
diff --git a/WebKitTools/DumpRenderTree/chromium/CppVariant.cpp b/WebKitTools/DumpRenderTree/chromium/CppVariant.cpp
new file mode 100644
index 0000000..9539907
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/CppVariant.cpp
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "CppVariant.h"
+
+#include "public/WebBindings.h"
+#include <limits>
+#include <wtf/Assertions.h>
+#include <wtf/StringExtras.h>
+
+using namespace WebKit;
+using namespace std;
+
+CppVariant::CppVariant()
+{
+ type = NPVariantType_Null;
+}
+
+// Note that Set() performs a deep copy, which is necessary to safely
+// call FreeData() on the value in the destructor.
+CppVariant::CppVariant(const CppVariant& original)
+{
+ type = NPVariantType_Null;
+ set(original);
+}
+
+// See comment for copy constructor, above.
+CppVariant& CppVariant::operator=(const CppVariant& original)
+{
+ if (&original != this)
+ set(original);
+ return *this;
+}
+
+CppVariant::~CppVariant()
+{
+ freeData();
+}
+
+void CppVariant::freeData()
+{
+ WebBindings::releaseVariantValue(this);
+}
+
+bool CppVariant::isEqual(const CppVariant& other) const
+{
+ if (type != other.type)
+ return false;
+
+ switch (type) {
+ case NPVariantType_Bool:
+ return (value.boolValue == other.value.boolValue);
+ case NPVariantType_Int32:
+ return (value.intValue == other.value.intValue);
+ case NPVariantType_Double:
+ return (value.doubleValue == other.value.doubleValue);
+ case NPVariantType_String: {
+ const NPString *this_value = &value.stringValue;
+ const NPString *other_value = &other.value.stringValue;
+ uint32_t len = this_value->UTF8Length;
+ return len == other_value->UTF8Length
+ && !strncmp(this_value->UTF8Characters,
+ other_value->UTF8Characters, len);
+ }
+ case NPVariantType_Null:
+ case NPVariantType_Void:
+ return true;
+ case NPVariantType_Object: {
+ NPObject* thisValue = value.objectValue;
+ NPObject* otherValue = other.value.objectValue;
+ return thisValue->_class == otherValue->_class
+ && thisValue->referenceCount == otherValue->referenceCount;
+ }
+ }
+ return false;
+}
+
+void CppVariant::copyToNPVariant(NPVariant* result) const
+{
+ result->type = type;
+ switch (type) {
+ case NPVariantType_Bool:
+ result->value.boolValue = value.boolValue;
+ break;
+ case NPVariantType_Int32:
+ result->value.intValue = value.intValue;
+ break;
+ case NPVariantType_Double:
+ result->value.doubleValue = value.doubleValue;
+ break;
+ case NPVariantType_String:
+ WebBindings::initializeVariantWithStringCopy(result, &value.stringValue);
+ break;
+ case NPVariantType_Null:
+ case NPVariantType_Void:
+ // Nothing to set.
+ break;
+ case NPVariantType_Object:
+ result->type = NPVariantType_Object;
+ result->value.objectValue = WebBindings::retainObject(value.objectValue);
+ break;
+ }
+}
+
+void CppVariant::set(const NPVariant& newValue)
+{
+ freeData();
+ switch (newValue.type) {
+ case NPVariantType_Bool:
+ set(newValue.value.boolValue);
+ break;
+ case NPVariantType_Int32:
+ set(newValue.value.intValue);
+ break;
+ case NPVariantType_Double:
+ set(newValue.value.doubleValue);
+ break;
+ case NPVariantType_String:
+ set(newValue.value.stringValue);
+ break;
+ case NPVariantType_Null:
+ case NPVariantType_Void:
+ type = newValue.type;
+ break;
+ case NPVariantType_Object:
+ set(newValue.value.objectValue);
+ break;
+ }
+}
+
+void CppVariant::setNull()
+{
+ freeData();
+ type = NPVariantType_Null;
+}
+
+void CppVariant::set(bool newValue)
+{
+ freeData();
+ type = NPVariantType_Bool;
+ value.boolValue = newValue;
+}
+
+void CppVariant::set(int32_t newValue)
+{
+ freeData();
+ type = NPVariantType_Int32;
+ value.intValue = newValue;
+}
+
+void CppVariant::set(double newValue)
+{
+ freeData();
+ type = NPVariantType_Double;
+ value.doubleValue = newValue;
+}
+
+// The newValue must be a null-terminated string.
+void CppVariant::set(const char* newValue)
+{
+ freeData();
+ type = NPVariantType_String;
+ NPString newString = {newValue,
+ static_cast<uint32_t>(strlen(newValue))};
+ WebBindings::initializeVariantWithStringCopy(this, &newString);
+}
+
+void CppVariant::set(const string& newValue)
+{
+ freeData();
+ type = NPVariantType_String;
+ NPString newString = {newValue.data(),
+ static_cast<uint32_t>(newValue.size())};
+ WebBindings::initializeVariantWithStringCopy(this, &newString);
+}
+
+void CppVariant::set(const NPString& newValue)
+{
+ freeData();
+ type = NPVariantType_String;
+ WebBindings::initializeVariantWithStringCopy(this, &newValue);
+}
+
+void CppVariant::set(NPObject* newValue)
+{
+ freeData();
+ type = NPVariantType_Object;
+ value.objectValue = WebBindings::retainObject(newValue);
+}
+
+string CppVariant::toString() const
+{
+ ASSERT(isString());
+ return string(value.stringValue.UTF8Characters,
+ value.stringValue.UTF8Length);
+}
+
+int32_t CppVariant::toInt32() const
+{
+ if (isInt32())
+ return value.intValue;
+ if (isDouble())
+ return static_cast<int32_t>(value.doubleValue);
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+double CppVariant::toDouble() const
+{
+ if (isInt32())
+ return static_cast<double>(value.intValue);
+ if (isDouble())
+ return value.doubleValue;
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+bool CppVariant::toBoolean() const
+{
+ ASSERT(isBool());
+ return value.boolValue;
+}
+
+Vector<string> CppVariant::toStringVector() const
+{
+
+ ASSERT(isObject());
+ Vector<string> stringVector;
+ NPObject* npValue = value.objectValue;
+ NPIdentifier lengthId = WebBindings::getStringIdentifier("length");
+
+ if (!WebBindings::hasProperty(0, npValue, lengthId))
+ return stringVector;
+
+ NPVariant lengthValue;
+ if (!WebBindings::getProperty(0, npValue, lengthId, &lengthValue))
+ return stringVector;
+
+ int length = 0;
+ // The length is a double in some cases.
+ if (NPVARIANT_IS_DOUBLE(lengthValue))
+ length = static_cast<int>(NPVARIANT_TO_DOUBLE(lengthValue));
+ else if (NPVARIANT_IS_INT32(lengthValue))
+ length = NPVARIANT_TO_INT32(lengthValue);
+ WebBindings::releaseVariantValue(&lengthValue);
+
+ // For sanity, only allow 100 items.
+ length = min(100, length);
+ for (int i = 0; i < length; ++i) {
+ // Get each of the items.
+ char indexInChar[20]; // Enough size to store 32-bit integer
+ snprintf(indexInChar, 20, "%d", i);
+ string index(indexInChar);
+ NPIdentifier indexId = WebBindings::getStringIdentifier(index.c_str());
+ if (!WebBindings::hasProperty(0, npValue, indexId))
+ continue;
+ NPVariant indexValue;
+ if (!WebBindings::getProperty(0, npValue, indexId, &indexValue))
+ continue;
+ if (NPVARIANT_IS_STRING(indexValue)) {
+ string item(NPVARIANT_TO_STRING(indexValue).UTF8Characters,
+ NPVARIANT_TO_STRING(indexValue).UTF8Length);
+ stringVector.append(item);
+ }
+ WebBindings::releaseVariantValue(&indexValue);
+ }
+ return stringVector;
+}
+
+bool CppVariant::invoke(const string& method, const CppVariant* arguments,
+ uint32_t argumentCount, CppVariant& result) const
+{
+ ASSERT(isObject());
+ NPIdentifier methodName = WebBindings::getStringIdentifier(method.c_str());
+ NPObject* npObject = value.objectValue;
+ if (!WebBindings::hasMethod(0, npObject, methodName))
+ return false;
+ NPVariant r;
+ bool status = WebBindings::invoke(0, npObject, methodName, arguments, argumentCount, &r);
+ result.set(r);
+ return status;
+}
diff --git a/WebKitTools/DumpRenderTree/chromium/CppVariant.h b/WebKitTools/DumpRenderTree/chromium/CppVariant.h
new file mode 100644
index 0000000..d34a163
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/CppVariant.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ This file contains the declaration for CppVariant, a type used by C++ classes
+ that are to be bound to JavaScript objects.
+
+ CppVariant exists primarily as an interface between C++ callers and the
+ corresponding NPVariant type. CppVariant also provides a number of
+ convenience constructors and accessors, so that the NPVariantType values
+ don't need to be exposed, and a destructor to free any memory allocated for
+ string values.
+*/
+
+#ifndef CppVariant_h
+#define CppVariant_h
+
+#include "base/basictypes.h"
+#include "public/WebBindings.h"
+#include <string>
+#include <wtf/Vector.h>
+
+class CppVariant : public NPVariant {
+public:
+ CppVariant();
+ ~CppVariant();
+ void setNull();
+ void set(bool);
+ void set(int32_t);
+ void set(double);
+
+ // Note that setting a CppVariant to a string value involves copying the
+ // string data, which must be freed with a call to freeData() when the
+ // CppVariant is set to a different value or is no longer needed. Normally
+ // this is handled by the other set() methods and by the destructor.
+ void set(const char*); // Must be a null-terminated string.
+ void set(const std::string&);
+ void set(const NPString&);
+ void set(const NPVariant&);
+
+ // Note that setting a CppVariant to an NPObject involves ref-counting
+ // the actual object. freeData() should only be called if the CppVariant
+ // is no longer needed. The other set() methods handle this internally.
+ // Also, the object's NPClass is expected to be a static object: neither
+ // the NP runtime nor CppVariant will ever free it.
+ void set(NPObject*_value);
+
+ // These three methods all perform deep copies of any string data. This
+ // allows local CppVariants to be released by the destructor without
+ // corrupting their sources. In performance-critical code, or when strings
+ // are very long, avoid creating new CppVariants.
+ // In case of NPObject as the data, the copying involves ref-counting
+ // as opposed to deep-copying. The ref-counting ensures that sources don't
+ // get corrupted when the copies get destroyed.
+ void copyToNPVariant(NPVariant* result) const;
+ CppVariant& operator=(const CppVariant& original);
+ CppVariant(const CppVariant& original);
+
+ // Calls NPN_ReleaseVariantValue, which frees any string data
+ // held by the object and sets its type to null.
+ // In case of NPObject, the NPN_ReleaseVariantValue decrements
+ // the ref-count (releases when ref-count becomes 0)
+ void freeData();
+
+ // Compares this CppVariant's type and value to another's. They must be
+ // identical in both type and value to be considered equal. For string and
+ // object types, a deep comparison is performed; that is, the contents of the
+ // strings, or the classes and refcounts of the objects, must be the same,
+ // but they need not be the same pointers.
+ bool isEqual(const CppVariant&) const;
+
+ // The value of a CppVariant may be read directly from its NPVariant (but
+ // should only be set using one of the set() methods above). Although the
+ // type of a CppVariant is likewise public, it can be accessed through these
+ // functions rather than directly if a caller wishes to avoid dependence on
+ // the NPVariantType values.
+ bool isBool() const { return (type == NPVariantType_Bool); }
+ bool isInt32() const { return (type == NPVariantType_Int32); }
+ bool isDouble() const { return (type == NPVariantType_Double); }
+ bool isNumber() const { return (isInt32() || isDouble()); }
+ bool isString() const { return (type == NPVariantType_String); }
+ bool isVoid() const { return (type == NPVariantType_Void); }
+ bool isNull() const { return (type == NPVariantType_Null); }
+ bool isEmpty() const { return (isVoid() || isNull()); }
+ bool isObject() const { return (type == NPVariantType_Object); }
+
+ // Converters. The CppVariant must be of a type convertible to these values.
+ // For example, toInt32() works only if isNumber() is true.
+ std::string toString() const;
+ int32_t toInt32() const;
+ double toDouble() const;
+ bool toBoolean() const;
+ // Returns a vector of strings for the specified argument. This is useful
+ // for converting a JavaScript array of strings into a vector of strings.
+ Vector<std::string> toStringVector() const;
+
+ // Invoke method of the given name on an object with the supplied arguments.
+ // The first argument should be the object on which the method is to be
+ // invoked. Returns whether the method was successfully invoked. If the
+ // method was invoked successfully, any return value is stored in the
+ // CppVariant specified by result.
+ bool invoke(const std::string&, const CppVariant* arguments,
+ uint32_t argumentCount, CppVariant& result) const;
+};
+
+#endif // CppVariant_h
diff --git a/WebKitTools/DumpRenderTree/chromium/DumpRenderTree.cpp b/WebKitTools/DumpRenderTree/chromium/DumpRenderTree.cpp
new file mode 100644
index 0000000..c81480f
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/DumpRenderTree.cpp
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "TestShell.h"
+#include "webkit/support/webkit_support.h"
+#include <wtf/Vector.h>
+#if OS(MAC_OS_X)
+#include "WebSystemInterface.h"
+#endif
+
+using namespace std;
+
+static const char optionComplexText[] = "--complex-text";
+static const char optionDumpAllPixels[] = "--dump-all-pixels";
+static const char optionNotree[] = "--notree";
+static const char optionPixelTests[] = "--pixel-tests";
+static const char optionThreaded[] = "--threaded";
+static const char optionTree[] = "--tree";
+
+static void runTest(TestShell& shell, TestParams& params, const string& testName)
+{
+ string pathOrURL = testName;
+ string::size_type separatorPosition = pathOrURL.find("'");
+ if (separatorPosition != string::npos) {
+ params.pixelHash = pathOrURL.substr(separatorPosition + 1);
+ pathOrURL.erase(separatorPosition);
+ }
+ params.testUrl = webkit_support::CreateURLForPathOrURL(pathOrURL);
+ shell.resetTestController();
+ shell.runFileTest(params);
+}
+
+int main(int argc, char* argv[])
+{
+#if OS(MAC_OS_X)
+ // Need to call before instantiate WebKitClient.
+ InitWebCoreSystemInterface();
+#endif
+ webkit_support::SetUpTestEnvironment();
+
+ TestParams params;
+ Vector<string> tests;
+ bool serverMode = false;
+ for (int i = 1; i < argc; ++i) {
+ string argument(argv[i]);
+ if (argument == "-")
+ serverMode = true;
+ else if (argument == optionNotree)
+ params.dumpTree = false;
+ else if (argument == optionPixelTests)
+ params.dumpPixels = true;
+ else if (argument.size() && argument[0] == '-')
+ fprintf(stderr, "Unknown option: %s\n", argv[i]);
+ else
+ tests.append(argument);
+ }
+
+ { // Explicit scope for the TestShell instance.
+ TestShell shell;
+ if (serverMode && !tests.size()) {
+ params.printSeparators = true;
+ char testString[2048]; // 2048 is the same as the sizes of other platforms.
+ while (fgets(testString, sizeof(testString), stdin)) {
+ char* newLinePosition = strchr(testString, '\n');
+ if (newLinePosition)
+ *newLinePosition = '\0';
+ if (testString[0] == '\0')
+ continue;
+ runTest(shell, params, testString);
+ }
+ } else if (!tests.size())
+ printf("#EOF\n");
+ else {
+ params.printSeparators = tests.size() > 1;
+ for (unsigned i = 0; i < tests.size(); i++)
+ runTest(shell, params, tests[i]);
+ }
+
+ shell.callJSGC();
+ shell.callJSGC();
+
+ // When we finish the last test, cleanup the LayoutTestController.
+ // It may have references to not-yet-cleaned up windows. By
+ // cleaning up here we help purify reports.
+ shell.resetTestController();
+ }
+
+ webkit_support::TearDownTestEnvironment();
+ return EXIT_SUCCESS;
+}
diff --git a/WebKitTools/DumpRenderTree/chromium/EventSender.cpp b/WebKitTools/DumpRenderTree/chromium/EventSender.cpp
new file mode 100644
index 0000000..c48aaf4
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/EventSender.cpp
@@ -0,0 +1,807 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// This file contains the definition for EventSender.
+//
+// Some notes about drag and drop handling:
+// Windows drag and drop goes through a system call to doDragDrop. At that
+// point, program control is given to Windows which then periodically makes
+// callbacks into the webview. This won't work for layout tests, so instead,
+// we queue up all the mouse move and mouse up events. When the test tries to
+// start a drag (by calling EvenSendingController::doDragDrop), we take the
+// events in the queue and replay them.
+// The behavior of queuing events and replaying them can be disabled by a
+// layout test by setting eventSender.dragMode to false.
+
+#include "config.h"
+#include "EventSender.h"
+
+#include "TestShell.h"
+#include "base/keyboard_codes.h"
+#include "base/time.h"
+#include "public/WebDragData.h"
+#include "public/WebDragOperation.h"
+#include "public/WebPoint.h"
+#include "public/WebString.h"
+#include "public/WebView.h"
+#include "webkit/support/webkit_support.h"
+#include <wtf/Deque.h>
+#include <wtf/StringExtras.h>
+
+#if OS(WINDOWS)
+#include "public/win/WebInputEventFactory.h"
+#endif
+
+// FIXME: layout before each event?
+
+using namespace base;
+using namespace std;
+using namespace WebKit;
+
+TestShell* EventSender::testShell = 0;
+WebPoint EventSender::lastMousePos;
+WebMouseEvent::Button EventSender::pressedButton = WebMouseEvent::ButtonNone;
+WebMouseEvent::Button EventSender::lastButtonType = WebMouseEvent::ButtonNone;
+
+struct SavedEvent {
+ enum SavedEventType {
+ Unspecified,
+ MouseUp,
+ MouseMove,
+ LeapForward
+ };
+
+ SavedEventType type;
+ WebMouseEvent::Button buttonType; // For MouseUp.
+ WebPoint pos; // For MouseMove.
+ int milliseconds; // For LeapForward.
+
+ SavedEvent()
+ : type(Unspecified)
+ , buttonType(WebMouseEvent::ButtonNone)
+ , milliseconds(0) {}
+};
+
+static WebDragData currentDragData;
+static WebDragOperation currentDragEffect;
+static WebDragOperationsMask currentDragEffectsAllowed;
+static bool replayingSavedEvents = false;
+static Deque<SavedEvent> mouseEventQueue;
+
+// Time and place of the last mouse up event.
+static double lastClickTimeSec = 0;
+static WebPoint lastClickPos;
+static int clickCount = 0;
+
+// maximum distance (in space and time) for a mouse click
+// to register as a double or triple click
+static const double multipleClickTimeSec = 1;
+static const int multipleClickRadiusPixels = 5;
+
+// How much we should scroll per event - the value here is chosen to
+// match the WebKit impl and layout test results.
+static const float scrollbarPixelsPerTick = 40.0f;
+
+inline bool outsideMultiClickRadius(const WebPoint& a, const WebPoint& b)
+{
+ return ((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)) >
+ multipleClickRadiusPixels * multipleClickRadiusPixels;
+}
+
+// Used to offset the time the event hander things an event happened. This is
+// done so tests can run without a delay, but bypass checks that are time
+// dependent (e.g., dragging has a timeout vs selection).
+static uint32 timeOffsetMs = 0;
+
+static double getCurrentEventTimeSec()
+{
+ return (TimeTicks::Now().ToInternalValue() / Time::kMicrosecondsPerMillisecond + timeOffsetMs) / 1000.0;
+}
+
+static void advanceEventTime(int32_t deltaMs)
+{
+ timeOffsetMs += deltaMs;
+}
+
+static void initMouseEvent(WebInputEvent::Type t, WebMouseEvent::Button b,
+ const gfx::Point& pos, WebMouseEvent* e)
+{
+ e->type = t;
+ e->button = b;
+ e->modifiers = 0;
+ e->x = pos.x();
+ e->y = pos.y();
+ e->globalX = pos.x();
+ e->globalY = pos.y();
+ e->timeStampSeconds = getCurrentEventTimeSec();
+ e->clickCount = clickCount;
+}
+
+// Returns true if the specified key is the system key.
+static bool applyKeyModifier(const string& modifierName, WebInputEvent* event)
+{
+ bool isSystemKey = false;
+ const char* characters = modifierName.c_str();
+ if (!strcmp(characters, "ctrlKey")
+#if !OS(MAC_OS_X)
+ || !strcmp(characters, "addSelectionKey")
+#endif
+ ) {
+ event->modifiers |= WebInputEvent::ControlKey;
+ } else if (!strcmp(characters, "shiftKey") || !strcmp(characters, "rangeSelectionKey"))
+ event->modifiers |= WebInputEvent::ShiftKey;
+ else if (!strcmp(characters, "altKey")) {
+ event->modifiers |= WebInputEvent::AltKey;
+#if !OS(MAC_OS_X)
+ // On Windows all keys with Alt modifier will be marked as system key.
+ // We keep the same behavior on Linux, see:
+ // WebKit/chromium/src/gtk/WebInputEventFactory.cpp
+ // If we want to change this behavior on Linux, this piece of code must be
+ // kept in sync with the related code in above file.
+ isSystemKey = true;
+#endif
+#if OS(MAC_OS_X)
+ } else if (!strcmp(characters, "metaKey") || !strcmp(characters, "addSelectionKey")) {
+ event->modifiers |= WebInputEvent::MetaKey;
+ // On Mac only command key presses are marked as system key.
+ // See the related code in: WebKit/chromium/src/mac/WebInputEventFactory.cpp
+ // It must be kept in sync with the related code in above file.
+ isSystemKey = true;
+#else
+ } else if (!strcmp(characters, "metaKey")) {
+ event->modifiers |= WebInputEvent::MetaKey;
+#endif
+ }
+ return isSystemKey;
+}
+
+static bool applyKeyModifiers(const CppVariant* argument, WebInputEvent* event)
+{
+ bool isSystemKey = false;
+ if (argument->isObject()) {
+ Vector<string> modifiers = argument->toStringVector();
+ for (Vector<string>::const_iterator i = modifiers.begin(); i != modifiers.end(); ++i)
+ isSystemKey |= applyKeyModifier(*i, event);
+ } else if (argument->isString())
+ isSystemKey = applyKeyModifier(argument->toString(), event);
+ return isSystemKey;
+}
+
+// Get the edit command corresponding to a keyboard event.
+// Returns true if the specified event corresponds to an edit command, the name
+// of the edit command will be stored in |*name|.
+bool getEditCommand(const WebKeyboardEvent& event, string* name)
+{
+#if OS(MAC_OS_X)
+ // We only cares about Left,Right,Up,Down keys with Command or Command+Shift
+ // modifiers. These key events correspond to some special movement and
+ // selection editor commands, and was supposed to be handled in
+ // WebKit/chromium/src/EditorClientImpl.cpp. But these keys will be marked
+ // as system key, which prevents them from being handled. Thus they must be
+ // handled specially.
+ if ((event.modifiers & ~WebKeyboardEvent::ShiftKey) != WebKeyboardEvent::MetaKey)
+ return false;
+
+ switch (event.windowsKeyCode) {
+ case base::VKEY_LEFT:
+ *name = "MoveToBeginningOfLine";
+ break;
+ case base::VKEY_RIGHT:
+ *name = "MoveToEndOfLine";
+ break;
+ case base::VKEY_UP:
+ *name = "MoveToBeginningOfDocument";
+ break;
+ case base::VKEY_DOWN:
+ *name = "MoveToEndOfDocument";
+ break;
+ default:
+ return false;
+ }
+
+ if (event.modifiers & WebKeyboardEvent::ShiftKey)
+ name->append("AndModifySelection");
+
+ return true;
+#else
+ return false;
+#endif
+}
+
+// Key event location code introduced in DOM Level 3.
+// See also: http://www.w3.org/TR/DOM-Level-3-Events/#events-keyboardevents
+enum KeyLocationCode {
+ DOMKeyLocationStandard = 0x00,
+ DOMKeyLocationLeft = 0x01,
+ DOMKeyLocationRight = 0x02,
+ DOMKeyLocationNumpad = 0x03
+};
+
+EventSender::EventSender(TestShell* shell)
+ : m_methodFactory(this)
+{
+ // Set static testShell variable since we can't do it in an initializer list.
+ // We also need to be careful not to assign testShell to new windows which are
+ // temporary.
+ if (!testShell)
+ testShell = shell;
+
+ // Initialize the map that associates methods of this class with the names
+ // they will use when called by JavaScript. The actual binding of those
+ // names to their methods will be done by calling bindToJavaScript() (defined
+ // by CppBoundClass, the parent to EventSender).
+ bindMethod("mouseDown", &EventSender::mouseDown);
+ bindMethod("mouseUp", &EventSender::mouseUp);
+ bindMethod("contextClick", &EventSender::contextClick);
+ bindMethod("mouseMoveTo", &EventSender::mouseMoveTo);
+ bindMethod("mouseWheelTo", &EventSender::mouseWheelTo);
+ bindMethod("leapForward", &EventSender::leapForward);
+ bindMethod("keyDown", &EventSender::keyDown);
+ bindMethod("dispatchMessage", &EventSender::dispatchMessage);
+ bindMethod("enableDOMUIEventLogging", &EventSender::enableDOMUIEventLogging);
+ bindMethod("fireKeyboardEventsToElement", &EventSender::fireKeyboardEventsToElement);
+ bindMethod("clearKillRing", &EventSender::clearKillRing);
+ bindMethod("textZoomIn", &EventSender::textZoomIn);
+ bindMethod("textZoomOut", &EventSender::textZoomOut);
+ bindMethod("zoomPageIn", &EventSender::zoomPageIn);
+ bindMethod("zoomPageOut", &EventSender::zoomPageOut);
+ bindMethod("scheduleAsynchronousClick", &EventSender::scheduleAsynchronousClick);
+ bindMethod("beginDragWithFiles", &EventSender::beginDragWithFiles);
+
+ // When set to true (the default value), we batch mouse move and mouse up
+ // events so we can simulate drag & drop.
+ bindProperty("dragMode", &dragMode);
+#if OS(WINDOWS)
+ bindProperty("WM_KEYDOWN", &wmKeyDown);
+ bindProperty("WM_KEYUP", &wmKeyUp);
+ bindProperty("WM_CHAR", &wmChar);
+ bindProperty("WM_DEADCHAR", &wmDeadChar);
+ bindProperty("WM_SYSKEYDOWN", &wmSysKeyDown);
+ bindProperty("WM_SYSKEYUP", &wmSysKeyUp);
+ bindProperty("WM_SYSCHAR", &wmSysChar);
+ bindProperty("WM_SYSDEADCHAR", &wmSysDeadChar);
+#endif
+}
+
+void EventSender::reset()
+{
+ // The test should have finished a drag and the mouse button state.
+ ASSERT(currentDragData.isNull());
+ currentDragData.reset();
+ currentDragEffect = WebKit::WebDragOperationNone;
+ currentDragEffectsAllowed = WebKit::WebDragOperationNone;
+ pressedButton = WebMouseEvent::ButtonNone;
+ dragMode.set(true);
+#if OS(WINDOWS)
+ wmKeyDown.set(WM_KEYDOWN);
+ wmKeyUp.set(WM_KEYUP);
+ wmChar.set(WM_CHAR);
+ wmDeadChar.set(WM_DEADCHAR);
+ wmSysKeyDown.set(WM_SYSKEYDOWN);
+ wmSysKeyUp.set(WM_SYSKEYUP);
+ wmSysChar.set(WM_SYSCHAR);
+ wmSysDeadChar.set(WM_SYSDEADCHAR);
+#endif
+ lastMousePos = WebPoint(0, 0);
+ lastClickTimeSec = 0;
+ lastClickPos = WebPoint(0, 0);
+ clickCount = 0;
+ lastButtonType = WebMouseEvent::ButtonNone;
+ timeOffsetMs = 0;
+}
+
+WebView* EventSender::webview()
+{
+ return testShell->webView();
+}
+
+void EventSender::doDragDrop(const WebKit::WebPoint& eventPos,
+ const WebDragData& dragData,
+ WebDragOperationsMask mask)
+{
+ WebMouseEvent event;
+ initMouseEvent(WebInputEvent::MouseDown, pressedButton, lastMousePos, &event);
+ WebPoint clientPoint(event.x, event.y);
+ WebPoint screenPoint(event.globalX, event.globalY);
+ currentDragData = dragData;
+ currentDragEffectsAllowed = mask;
+ currentDragEffect = webview()->dragTargetDragEnter(dragData, 0, clientPoint, screenPoint, currentDragEffectsAllowed);
+
+ // Finish processing events.
+ replaySavedEvents();
+}
+
+WebMouseEvent::Button EventSender::getButtonTypeFromButtonNumber(int buttonCode)
+{
+ if (!buttonCode)
+ return WebMouseEvent::ButtonLeft;
+ if (buttonCode == 2)
+ return WebMouseEvent::ButtonRight;
+ return WebMouseEvent::ButtonMiddle;
+}
+
+int EventSender::getButtonNumberFromSingleArg(const CppArgumentList& arguments)
+{
+ int buttonCode = 0;
+ if (arguments.size() > 0 && arguments[0].isNumber())
+ buttonCode = arguments[0].toInt32();
+ return buttonCode;
+}
+
+void EventSender::updateClickCountForButton(WebMouseEvent::Button buttonType)
+{
+ if ((getCurrentEventTimeSec() - lastClickTimeSec < multipleClickTimeSec)
+ && (!outsideMultiClickRadius(lastMousePos, lastClickPos))
+ && (buttonType == lastButtonType))
+ ++clickCount;
+ else {
+ clickCount = 1;
+ lastButtonType = buttonType;
+ }
+}
+
+//
+// Implemented javascript methods.
+//
+
+void EventSender::mouseDown(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (result) // Could be 0 if invoked asynchronously.
+ result->setNull();
+
+ webview()->layout();
+
+ int buttonNumber = getButtonNumberFromSingleArg(arguments);
+ ASSERT(buttonNumber != -1);
+
+ WebMouseEvent::Button buttonType = getButtonTypeFromButtonNumber(buttonNumber);
+
+ updateClickCountForButton(buttonType);
+
+ WebMouseEvent event;
+ pressedButton = buttonType;
+ initMouseEvent(WebInputEvent::MouseDown, buttonType, lastMousePos, &event);
+ if (arguments.size() >= 2 && (arguments[1].isObject() || arguments[1].isString()))
+ applyKeyModifiers(&(arguments[1]), &event);
+ webview()->handleInputEvent(event);
+}
+
+void EventSender::mouseUp(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (result) // Could be 0 if invoked asynchronously.
+ result->setNull();
+
+ webview()->layout();
+
+ int buttonNumber = getButtonNumberFromSingleArg(arguments);
+ ASSERT(buttonNumber != -1);
+
+ WebMouseEvent::Button buttonType = getButtonTypeFromButtonNumber(buttonNumber);
+
+ if (isDragMode() && !replayingSavedEvents) {
+ SavedEvent savedEvent;
+ savedEvent.type = SavedEvent::MouseUp;
+ savedEvent.buttonType = buttonType;
+ mouseEventQueue.append(savedEvent);
+ replaySavedEvents();
+ } else {
+ WebMouseEvent event;
+ initMouseEvent(WebInputEvent::MouseUp, buttonType, lastMousePos, &event);
+ if (arguments.size() >= 2 && (arguments[1].isObject() || arguments[1].isString()))
+ applyKeyModifiers(&(arguments[1]), &event);
+ doMouseUp(event);
+ }
+}
+
+void EventSender::doMouseUp(const WebMouseEvent& e)
+{
+ webview()->handleInputEvent(e);
+
+ pressedButton = WebMouseEvent::ButtonNone;
+ lastClickTimeSec = e.timeStampSeconds;
+ lastClickPos = lastMousePos;
+
+ // If we're in a drag operation, complete it.
+ if (currentDragData.isNull())
+ return;
+ WebPoint clientPoint(e.x, e.y);
+ WebPoint screenPoint(e.globalX, e.globalY);
+
+ currentDragEffect = webview()->dragTargetDragOver(clientPoint, screenPoint, currentDragEffectsAllowed);
+ if (currentDragEffect)
+ webview()->dragTargetDrop(clientPoint, screenPoint);
+ else
+ webview()->dragTargetDragLeave();
+ webview()->dragSourceEndedAt(clientPoint, screenPoint, currentDragEffect);
+ webview()->dragSourceSystemDragEnded();
+
+ currentDragData.reset();
+}
+
+void EventSender::mouseMoveTo(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isNumber())
+ return;
+ webview()->layout();
+
+ WebPoint mousePos(arguments[0].toInt32(), arguments[1].toInt32());
+
+ if (isDragMode() && pressedButton == WebMouseEvent::ButtonLeft && !replayingSavedEvents) {
+ SavedEvent savedEvent;
+ savedEvent.type = SavedEvent::MouseMove;
+ savedEvent.pos = mousePos;
+ mouseEventQueue.append(savedEvent);
+ } else {
+ WebMouseEvent event;
+ initMouseEvent(WebInputEvent::MouseMove, pressedButton, mousePos, &event);
+ doMouseMove(event);
+ }
+}
+
+void EventSender::mouseWheelTo(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isNumber())
+ return;
+
+ // Force a layout here just to make sure every position has been
+ // determined before we send events (as well as all the other methods
+ // that send an event do). The layout test calling this
+ // (scrollbars/overflow-scrollbar-horizontal-wheel-scroll.html, only one
+ // for now) does not rely on this though.
+ webview()->layout();
+
+ int horizontal = arguments[0].toInt32();
+ int vertical = arguments[1].toInt32();
+
+ WebMouseWheelEvent event;
+ initMouseEvent(WebInputEvent::MouseWheel, pressedButton, lastMousePos, &event);
+ event.wheelTicksX = static_cast<float>(horizontal);
+ event.wheelTicksY = static_cast<float>(vertical);
+ event.deltaX = -horizontal * scrollbarPixelsPerTick;
+ event.deltaY = -vertical * scrollbarPixelsPerTick;
+ webview()->handleInputEvent(event);
+}
+
+void EventSender::doMouseMove(const WebMouseEvent& e)
+{
+ lastMousePos = WebPoint(e.x, e.y);
+
+ webview()->handleInputEvent(e);
+
+ if (pressedButton == WebMouseEvent::ButtonNone || currentDragData.isNull())
+ return;
+ WebPoint clientPoint(e.x, e.y);
+ WebPoint screenPoint(e.globalX, e.globalY);
+ currentDragEffect = webview()->dragTargetDragOver(clientPoint, screenPoint, currentDragEffectsAllowed);
+}
+
+void EventSender::keyDown(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 1 || !arguments[0].isString())
+ return;
+ bool generateChar = false;
+
+ // FIXME: I'm not exactly sure how we should convert the string to a key
+ // event. This seems to work in the cases I tested.
+ // FIXME: Should we also generate a KEY_UP?
+ string codeStr = arguments[0].toString();
+
+ // Convert \n -> VK_RETURN. Some layout tests use \n to mean "Enter", when
+ // Windows uses \r for "Enter".
+ int code = 0;
+ int text = 0;
+ bool needsShiftKeyModifier = false;
+ if ("\n" == codeStr) {
+ generateChar = true;
+ text = code = base::VKEY_RETURN;
+ } else if ("rightArrow" == codeStr)
+ code = base::VKEY_RIGHT;
+ else if ("downArrow" == codeStr)
+ code = base::VKEY_DOWN;
+ else if ("leftArrow" == codeStr)
+ code = base::VKEY_LEFT;
+ else if ("upArrow" == codeStr)
+ code = base::VKEY_UP;
+ else if ("delete" == codeStr)
+ code = base::VKEY_BACK;
+ else if ("pageUp" == codeStr)
+ code = base::VKEY_PRIOR;
+ else if ("pageDown" == codeStr)
+ code = base::VKEY_NEXT;
+ else if ("home" == codeStr)
+ code = base::VKEY_HOME;
+ else if ("end" == codeStr)
+ code = base::VKEY_END;
+ else {
+ // Compare the input string with the function-key names defined by the
+ // DOM spec (i.e. "F1",...,"F24"). If the input string is a function-key
+ // name, set its key code.
+ for (int i = 1; i <= 24; ++i) {
+ char functionChars[10];
+ snprintf(functionChars, 10, "F%d", i);
+ string functionKeyName(functionChars);
+ if (functionKeyName == codeStr) {
+ code = base::VKEY_F1 + (i - 1);
+ break;
+ }
+ }
+ if (!code) {
+ WebString webCodeStr = WebString::fromUTF8(codeStr.data(), codeStr.size());
+ ASSERT(webCodeStr.length() == 1);
+ text = code = webCodeStr.data()[0];
+ needsShiftKeyModifier = needsShiftModifier(code);
+ if ((code & 0xFF) >= 'a' && (code & 0xFF) <= 'z')
+ code -= 'a' - 'A';
+ generateChar = true;
+ }
+ }
+
+ // For one generated keyboard event, we need to generate a keyDown/keyUp
+ // pair; refer to EventSender.cpp in WebKit/WebKitTools/DumpRenderTree/win.
+ // On Windows, we might also need to generate a char event to mimic the
+ // Windows event flow; on other platforms we create a merged event and test
+ // the event flow that that platform provides.
+ WebKeyboardEvent eventDown, eventChar, eventUp;
+ eventDown.type = WebInputEvent::RawKeyDown;
+ eventDown.modifiers = 0;
+ eventDown.windowsKeyCode = code;
+ if (generateChar) {
+ eventDown.text[0] = text;
+ eventDown.unmodifiedText[0] = text;
+ }
+ eventDown.setKeyIdentifierFromWindowsKeyCode();
+
+ if (arguments.size() >= 2 && (arguments[1].isObject() || arguments[1].isString()))
+ eventDown.isSystemKey = applyKeyModifiers(&(arguments[1]), &eventDown);
+
+ if (needsShiftKeyModifier)
+ eventDown.modifiers |= WebInputEvent::ShiftKey;
+
+ // See if KeyLocation argument is given.
+ if (arguments.size() >= 3 && arguments[2].isNumber()) {
+ int location = arguments[2].toInt32();
+ if (location == DOMKeyLocationNumpad)
+ eventDown.modifiers |= WebInputEvent::IsKeyPad;
+ }
+
+ eventChar = eventUp = eventDown;
+ eventUp.type = WebInputEvent::KeyUp;
+ // EventSender.m forces a layout here, with at least one
+ // test (fast/forms/focus-control-to-page.html) relying on this.
+ webview()->layout();
+
+ // In the browser, if a keyboard event corresponds to an editor command,
+ // the command will be dispatched to the renderer just before dispatching
+ // the keyboard event, and then it will be executed in the
+ // RenderView::handleCurrentKeyboardEvent() method, which is called from
+ // third_party/WebKit/WebKit/chromium/src/EditorClientImpl.cpp.
+ // We just simulate the same behavior here.
+ string editCommand;
+ if (getEditCommand(eventDown, &editCommand))
+ testShell->webViewHost()->setEditCommand(editCommand, "");
+
+ webview()->handleInputEvent(eventDown);
+
+ testShell->webViewHost()->clearEditCommand();
+
+ if (generateChar) {
+ eventChar.type = WebInputEvent::Char;
+ eventChar.keyIdentifier[0] = '\0';
+ webview()->handleInputEvent(eventChar);
+ }
+
+ webview()->handleInputEvent(eventUp);
+}
+
+void EventSender::dispatchMessage(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+#if OS(WINDOWS)
+ if (arguments.size() == 3) {
+ // Grab the message id to see if we need to dispatch it.
+ int msg = arguments[0].toInt32();
+
+ // WebKit's version of this function stuffs a MSG struct and uses
+ // TranslateMessage and DispatchMessage. We use a WebKeyboardEvent, which
+ // doesn't need to receive the DeadChar and SysDeadChar messages.
+ if (msg == WM_DEADCHAR || msg == WM_SYSDEADCHAR)
+ return;
+
+ webview()->layout();
+
+ unsigned long lparam = static_cast<unsigned long>(arguments[2].toDouble());
+ webview()->handleInputEvent(WebInputEventFactory::keyboardEvent(0, msg, arguments[1].toInt32(), lparam));
+ } else
+ ASSERT_NOT_REACHED();
+#endif
+}
+
+bool EventSender::needsShiftModifier(int keyCode)
+{
+ // If code is an uppercase letter, assign a SHIFT key to
+ // eventDown.modifier, this logic comes from
+ // WebKit/WebKitTools/DumpRenderTree/Win/EventSender.cpp
+ return (keyCode & 0xFF) >= 'A' && (keyCode & 0xFF) <= 'Z';
+}
+
+void EventSender::leapForward(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ if (arguments.size() < 1 || !arguments[0].isNumber())
+ return;
+
+ int milliseconds = arguments[0].toInt32();
+ if (isDragMode() && pressedButton == WebMouseEvent::ButtonLeft && !replayingSavedEvents) {
+ SavedEvent savedEvent;
+ savedEvent.type = SavedEvent::LeapForward;
+ savedEvent.milliseconds = milliseconds;
+ mouseEventQueue.append(savedEvent);
+ } else
+ doLeapForward(milliseconds);
+}
+
+void EventSender::doLeapForward(int milliseconds)
+{
+ advanceEventTime(milliseconds);
+}
+
+// Apple's port of WebKit zooms by a factor of 1.2 (see
+// WebKit/WebView/WebView.mm)
+void EventSender::textZoomIn(const CppArgumentList&, CppVariant* result)
+{
+ webview()->setZoomLevel(true, webview()->zoomLevel() + 1);
+ result->setNull();
+}
+
+void EventSender::textZoomOut(const CppArgumentList&, CppVariant* result)
+{
+ webview()->setZoomLevel(true, webview()->zoomLevel() - 1);
+ result->setNull();
+}
+
+void EventSender::zoomPageIn(const CppArgumentList&, CppVariant* result)
+{
+ webview()->setZoomLevel(false, webview()->zoomLevel() + 1);
+ result->setNull();
+}
+
+void EventSender::zoomPageOut(const CppArgumentList&, CppVariant* result)
+{
+ webview()->setZoomLevel(false, webview()->zoomLevel() - 1);
+ result->setNull();
+}
+
+void EventSender::replaySavedEvents()
+{
+ replayingSavedEvents = true;
+ while (!mouseEventQueue.isEmpty()) {
+ SavedEvent e = mouseEventQueue.first();
+ mouseEventQueue.removeFirst();
+
+ switch (e.type) {
+ case SavedEvent::MouseMove: {
+ WebMouseEvent event;
+ initMouseEvent(WebInputEvent::MouseMove, pressedButton, e.pos, &event);
+ doMouseMove(event);
+ break;
+ }
+ case SavedEvent::LeapForward:
+ doLeapForward(e.milliseconds);
+ break;
+ case SavedEvent::MouseUp: {
+ WebMouseEvent event;
+ initMouseEvent(WebInputEvent::MouseUp, e.buttonType, lastMousePos, &event);
+ doMouseUp(event);
+ break;
+ }
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ }
+
+ replayingSavedEvents = false;
+}
+
+void EventSender::contextClick(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ webview()->layout();
+
+ updateClickCountForButton(WebMouseEvent::ButtonRight);
+
+ // Generate right mouse down and up.
+
+ WebMouseEvent event;
+ pressedButton = WebMouseEvent::ButtonRight;
+ initMouseEvent(WebInputEvent::MouseDown, WebMouseEvent::ButtonRight, lastMousePos, &event);
+ webview()->handleInputEvent(event);
+
+ initMouseEvent(WebInputEvent::MouseUp, WebMouseEvent::ButtonRight, lastMousePos, &event);
+ webview()->handleInputEvent(event);
+
+ pressedButton = WebMouseEvent::ButtonNone;
+}
+
+void EventSender::scheduleAsynchronousClick(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ webkit_support::PostTaskFromHere(m_methodFactory.NewRunnableMethod(
+ &EventSender::mouseDown, arguments, static_cast<CppVariant*>(0)));
+ webkit_support::PostTaskFromHere(m_methodFactory.NewRunnableMethod(
+ &EventSender::mouseUp, arguments, static_cast<CppVariant*>(0)));
+}
+
+void EventSender::beginDragWithFiles(const CppArgumentList& arguments, CppVariant* result)
+{
+ currentDragData.initialize();
+ Vector<string> files = arguments[0].toStringVector();
+ for (size_t i = 0; i < files.size(); ++i)
+ currentDragData.appendToFileNames(webkit_support::GetAbsoluteWebStringFromUTF8Path(files[i]));
+ currentDragEffectsAllowed = WebKit::WebDragOperationCopy;
+
+ // Provide a drag source.
+ webview()->dragTargetDragEnter(currentDragData, 0, lastMousePos, lastMousePos, currentDragEffectsAllowed);
+
+ // dragMode saves events and then replays them later. We don't need/want that.
+ dragMode.set(false);
+
+ // Make the rest of eventSender think a drag is in progress.
+ pressedButton = WebMouseEvent::ButtonLeft;
+
+ result->setNull();
+}
+
+//
+// Unimplemented stubs
+//
+
+void EventSender::enableDOMUIEventLogging(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void EventSender::fireKeyboardEventsToElement(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void EventSender::clearKillRing(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
diff --git a/WebKitTools/DumpRenderTree/chromium/EventSender.h b/WebKitTools/DumpRenderTree/chromium/EventSender.h
new file mode 100644
index 0000000..756b008
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/EventSender.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ EventSender class:
+ Bound to a JavaScript window.eventSender object using
+ CppBoundClass::bindToJavascript(), this allows layout tests to fire DOM events.
+*/
+
+#ifndef EventSender_h
+#define EventSender_h
+
+#include "CppBoundClass.h"
+#include "base/task.h"
+#include "public/WebDragOperation.h"
+#include "public/WebInputEvent.h"
+#include "public/WebPoint.h"
+
+class TestShell;
+
+namespace WebKit {
+class WebDragData;
+class WebView;
+}
+
+class EventSender : public CppBoundClass {
+public:
+ // Builds the property and method lists needed to bind this class to a JS
+ // object.
+ EventSender(TestShell*);
+
+ // Resets some static variable state.
+ void reset();
+
+ // Simulate drag&drop system call.
+ static void doDragDrop(const WebKit::WebPoint&,
+ const WebKit::WebDragData&,
+ WebKit::WebDragOperationsMask);
+
+ // JS callback methods.
+ void mouseDown(const CppArgumentList&, CppVariant*);
+ void mouseUp(const CppArgumentList&, CppVariant*);
+ void mouseMoveTo(const CppArgumentList&, CppVariant*);
+ void mouseWheelTo(const CppArgumentList&, CppVariant*);
+ void leapForward(const CppArgumentList&, CppVariant*);
+ void keyDown(const CppArgumentList&, CppVariant*);
+ void dispatchMessage(const CppArgumentList&, CppVariant*);
+ void textZoomIn(const CppArgumentList&, CppVariant*);
+ void textZoomOut(const CppArgumentList&, CppVariant*);
+ void zoomPageIn(const CppArgumentList&, CppVariant*);
+ void zoomPageOut(const CppArgumentList&, CppVariant*);
+ void scheduleAsynchronousClick(const CppArgumentList&, CppVariant*);
+ void beginDragWithFiles(const CppArgumentList&, CppVariant*);
+ CppVariant dragMode;
+
+ // Unimplemented stubs
+ void contextClick(const CppArgumentList&, CppVariant*);
+ void enableDOMUIEventLogging(const CppArgumentList&, CppVariant*);
+ void fireKeyboardEventsToElement(const CppArgumentList&, CppVariant*);
+ void clearKillRing(const CppArgumentList&, CppVariant*);
+
+ // Properties used in layout tests.
+#if defined(OS_WIN)
+ CppVariant wmKeyDown;
+ CppVariant wmKeyUp;
+ CppVariant wmChar;
+ CppVariant wmDeadChar;
+ CppVariant wmSysKeyDown;
+ CppVariant wmSysKeyUp;
+ CppVariant wmSysChar;
+ CppVariant wmSysDeadChar;
+#endif
+
+private:
+ // Returns the test shell's webview.
+ static WebKit::WebView* webview();
+
+ // Returns true if dragMode is true.
+ bool isDragMode() { return dragMode.isBool() && dragMode.toBoolean(); }
+
+ // Sometimes we queue up mouse move and mouse up events for drag drop
+ // handling purposes. These methods dispatch the event.
+ static void doMouseMove(const WebKit::WebMouseEvent&);
+ static void doMouseUp(const WebKit::WebMouseEvent&);
+ static void doLeapForward(int milliseconds);
+ static void replaySavedEvents();
+
+ // Helper to return the button type given a button code
+ static WebKit::WebMouseEvent::Button getButtonTypeFromButtonNumber(int);
+
+ // Helper to extract the button number from the optional argument in
+ // mouseDown and mouseUp
+ static int getButtonNumberFromSingleArg(const CppArgumentList&);
+
+ // Returns true if the specified key code passed in needs a shift key
+ // modifier to be passed into the generated event.
+ bool needsShiftModifier(int);
+
+ void updateClickCountForButton(WebKit::WebMouseEvent::Button);
+
+ ScopedRunnableMethodFactory<EventSender> m_methodFactory;
+
+ // Non-owning pointer. The EventSender is owned by the TestShell.
+ static TestShell* testShell;
+
+ // Location of last mouseMoveTo event.
+ static WebKit::WebPoint lastMousePos;
+
+ // Currently pressed mouse button (Left/Right/Middle or None)
+ static WebKit::WebMouseEvent::Button pressedButton;
+
+ // The last button number passed to mouseDown and mouseUp.
+ // Used to determine whether the click count continues to
+ // increment or not.
+ static WebKit::WebMouseEvent::Button lastButtonType;
+};
+
+#endif // EventSender_h
diff --git a/WebKitTools/DumpRenderTree/chromium/ImageDiff.cpp b/WebKitTools/DumpRenderTree/chromium/ImageDiff.cpp
new file mode 100644
index 0000000..81d5f62
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/ImageDiff.cpp
@@ -0,0 +1,407 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// This file input format is based loosely on
+// WebKitTools/DumpRenderTree/ImageDiff.m
+
+// The exact format of this tool's output to stdout is important, to match
+// what the run-webkit-tests script expects.
+
+#include "config.h"
+
+#include "gfx/codec/png_codec.h"
+#include <algorithm>
+#include <stdio.h>
+#include <string.h>
+#include <string>
+#include <vector>
+#include <wtf/OwnArrayPtr.h>
+#include <wtf/Vector.h>
+
+using namespace gfx;
+using namespace std;
+
+// Causes the app to remain open, waiting for pairs of filenames on stdin.
+// The caller is then responsible for terminating this app.
+static const char optionPollStdin[] = "--use-stdin";
+static const char optionGenerateDiff[] = "--diff";
+
+// Return codes used by this utility.
+static const int statusSame = 0;
+static const int statusDifferent = 1;
+static const int statusError = 2;
+
+// Color codes.
+static const uint32_t rgbaRed = 0x000000ff;
+static const uint32_t rgbaAlpha = 0xff000000;
+
+class Image {
+public:
+ Image()
+ : m_width(0)
+ , m_height(0) {}
+
+ Image(const Image& image)
+ : m_width(image.m_width)
+ , m_height(image.m_height)
+ , m_data(image.m_data) {}
+
+ bool hasImage() const { return m_width > 0 && m_height > 0; }
+ int width() const { return m_width; }
+ int height() const { return m_height; }
+ const unsigned char* data() const { return &m_data.front(); }
+
+ // Creates the image from stdin with the given data length. On success, it
+ // will return true. On failure, no other methods should be accessed.
+ bool craeteFromStdin(size_t byteLength)
+ {
+ if (!byteLength)
+ return false;
+
+ OwnArrayPtr<unsigned char> source(new unsigned char[byteLength]);
+ if (fread(source.get(), 1, byteLength, stdin) != byteLength)
+ return false;
+
+ if (!PNGCodec::Decode(source.get(), byteLength, PNGCodec::FORMAT_RGBA,
+ &m_data, &m_width, &m_height)) {
+ clear();
+ return false;
+ }
+ return true;
+ }
+
+ // Creates the image from the given filename on disk, and returns true on
+ // success.
+ bool createFromFilename(const char* filename)
+ {
+ FILE* f = fopen(filename, "rb");
+ if (!f)
+ return false;
+
+ vector<unsigned char> compressed;
+ const int bufSize = 1024;
+ unsigned char buf[bufSize];
+ size_t numRead = 0;
+ while ((numRead = fread(buf, 1, bufSize, f)) > 0)
+ std::copy(buf, &buf[numRead], std::back_inserter(compressed));
+
+ fclose(f);
+
+ if (!PNGCodec::Decode(&compressed[0], compressed.size(),
+ PNGCodec::FORMAT_RGBA, &m_data, &m_width, &m_height)) {
+ clear();
+ return false;
+ }
+ return true;
+ }
+
+ void clear()
+ {
+ m_width = m_height = 0;
+ m_data.clear();
+ }
+
+ // Returns the RGBA value of the pixel at the given location
+ const uint32_t pixelAt(int x, int y) const
+ {
+ ASSERT(x >= 0 && x < m_width);
+ ASSERT(y >= 0 && y < m_height);
+ return *reinterpret_cast<const uint32_t*>(&(m_data[(y * m_width + x) * 4]));
+ }
+
+ void setPixelAt(int x, int y, uint32_t color) const
+ {
+ ASSERT(x >= 0 && x < m_width);
+ ASSERT(y >= 0 && y < m_height);
+ void* addr = &const_cast<unsigned char*>(&m_data.front())[(y * m_width + x) * 4];
+ *reinterpret_cast<uint32_t*>(addr) = color;
+ }
+
+private:
+ // pixel dimensions of the image
+ int m_width, m_height;
+
+ vector<unsigned char> m_data;
+};
+
+float percentageDifferent(const Image& baseline, const Image& actual)
+{
+ int w = min(baseline.width(), actual.width());
+ int h = min(baseline.height(), actual.height());
+
+ // Compute pixels different in the overlap
+ int pixelsDifferent = 0;
+ for (int y = 0; y < h; y++) {
+ for (int x = 0; x < w; x++) {
+ if (baseline.pixelAt(x, y) != actual.pixelAt(x, y))
+ pixelsDifferent++;
+ }
+ }
+
+ // Count pixels that are a difference in size as also being different
+ int maxWidth = max(baseline.width(), actual.width());
+ int maxHeight = max(baseline.height(), actual.height());
+
+ // ...pixels off the right side, but not including the lower right corner
+ pixelsDifferent += (maxWidth - w) * h;
+
+ // ...pixels along the bottom, including the lower right corner
+ pixelsDifferent += (maxHeight - h) * maxWidth;
+
+ // Like the WebKit ImageDiff tool, we define percentage different in terms
+ // of the size of the 'actual' bitmap.
+ float totalPixels = static_cast<float>(actual.width()) * static_cast<float>(actual.height());
+ if (!totalPixels)
+ return 100.0f; // When the bitmap is empty, they are 100% different.
+ return static_cast<float>(pixelsDifferent) / totalPixels * 100;
+}
+
+void printHelp()
+{
+ fprintf(stderr,
+ "Usage:\n"
+ " ImageDiff <compare file> <reference file>\n"
+ " Compares two files on disk, returning 0 when they are the same\n"
+ " ImageDiff --use-stdin\n"
+ " Stays open reading pairs of filenames from stdin, comparing them,\n"
+ " and sending 0 to stdout when they are the same\n"
+ " ImageDiff --diff <compare file> <reference file> <output file>\n"
+ " Compares two files on disk, outputs an image that visualizes the"
+ " difference to <output file>\n");
+ /* For unfinished webkit-like-mode (see below)
+ "\n"
+ " ImageDiff -s\n"
+ " Reads stream input from stdin, should be EXACTLY of the format\n"
+ " \"Content-length: <byte length> <data>Content-length: ...\n"
+ " it will take as many file pairs as given, and will compare them as\n"
+ " (cmp_file, reference_file) pairs\n");
+ */
+}
+
+int compareImages(const char* file1, const char* file2)
+{
+ Image actualImage;
+ Image baselineImage;
+
+ if (!actualImage.createFromFilename(file1)) {
+ fprintf(stderr, "ImageDiff: Unable to open file \"%s\"\n", file1);
+ return statusError;
+ }
+ if (!baselineImage.createFromFilename(file2)) {
+ fprintf(stderr, "ImageDiff: Unable to open file \"%s\"\n", file2);
+ return statusError;
+ }
+
+ float percent = percentageDifferent(actualImage, baselineImage);
+ if (percent > 0.0) {
+ // failure: The WebKit version also writes the difference image to
+ // stdout, which seems excessive for our needs.
+ printf("diff: %01.2f%% failed\n", percent);
+ return statusDifferent;
+ }
+
+ // success
+ printf("diff: %01.2f%% passed\n", percent);
+ return statusSame;
+
+}
+
+// Untested mode that acts like WebKit's image comparator. I wrote this but
+// decided it's too complicated. We may use it in the future if it looks useful.
+int untestedCompareImages()
+{
+ Image actualImage;
+ Image baselineImage;
+ char buffer[2048];
+ while (fgets(buffer, sizeof(buffer), stdin)) {
+ if (!strncmp("Content-length: ", buffer, 16)) {
+ char* context;
+#if OS(WINDOWS)
+ strtok_s(buffer, " ", &context);
+ int imageSize = strtol(strtok_s(0, " ", &context), 0, 10);
+#else
+ strtok_r(buffer, " ", &context);
+ int imageSize = strtol(strtok_r(0, " ", &context), 0, 10);
+#endif
+
+ bool success = false;
+ if (imageSize > 0 && !actualImage.hasImage()) {
+ if (!actualImage.craeteFromStdin(imageSize)) {
+ fputs("Error, input image can't be decoded.\n", stderr);
+ return 1;
+ }
+ } else if (imageSize > 0 && !baselineImage.hasImage()) {
+ if (!baselineImage.craeteFromStdin(imageSize)) {
+ fputs("Error, baseline image can't be decoded.\n", stderr);
+ return 1;
+ }
+ } else {
+ fputs("Error, image size must be specified.\n", stderr);
+ return 1;
+ }
+ }
+
+ if (actualImage.hasImage() && baselineImage.hasImage()) {
+ float percent = percentageDifferent(actualImage, baselineImage);
+ if (percent > 0.0) {
+ // failure: The WebKit version also writes the difference image to
+ // stdout, which seems excessive for our needs.
+ printf("diff: %01.2f%% failed\n", percent);
+ } else {
+ // success
+ printf("diff: %01.2f%% passed\n", percent);
+ }
+ actualImage.clear();
+ baselineImage.clear();
+ }
+ fflush(stdout);
+ }
+ return 0;
+}
+
+bool createImageDiff(const Image& image1, const Image& image2, Image* out)
+{
+ int w = min(image1.width(), image2.width());
+ int h = min(image1.height(), image2.height());
+ *out = Image(image1);
+ bool same = (image1.width() == image2.width()) && (image1.height() == image2.height());
+
+ // FIXME: do something with the extra pixels if the image sizes are different.
+ for (int y = 0; y < h; y++) {
+ for (int x = 0; x < w; x++) {
+ uint32_t basePixel = image1.pixelAt(x, y);
+ if (basePixel != image2.pixelAt(x, y)) {
+ // Set differing pixels red.
+ out->setPixelAt(x, y, rgbaRed | rgbaAlpha);
+ same = false;
+ } else {
+ // Set same pixels as faded.
+ uint32_t alpha = basePixel & rgbaAlpha;
+ uint32_t newPixel = basePixel - ((alpha / 2) & rgbaAlpha);
+ out->setPixelAt(x, y, newPixel);
+ }
+ }
+ }
+
+ return same;
+}
+
+static bool writeFile(const char* outFile, const unsigned char* data, size_t dataSize)
+{
+ FILE* file = fopen(outFile, "wb");
+ if (!file) {
+ fprintf(stderr, "ImageDiff: Unable to create file \"%s\"\n", file);
+ return false;
+ }
+ if (dataSize != fwrite(data, 1, dataSize, file)) {
+ fclose(file);
+ fprintf(stderr, "ImageDiff: Unable to write data to file \"%s\"\n", file);
+ return false;
+ }
+ fclose(file);
+ return true;
+}
+
+int diffImages(const char* file1, const char* file2, const char* outFile)
+{
+ Image actualImage;
+ Image baselineImage;
+
+ if (!actualImage.createFromFilename(file1)) {
+ fprintf(stderr, "ImageDiff: Unable to open file \"%s\"\n", file1);
+ return statusError;
+ }
+ if (!baselineImage.createFromFilename(file2)) {
+ fprintf(stderr, "ImageDiff: Unable to open file \"%s\"\n", file2);
+ return statusError;
+ }
+
+ Image diffImage;
+ bool same = createImageDiff(baselineImage, actualImage, &diffImage);
+ if (same)
+ return statusSame;
+
+ vector<unsigned char> pngData;
+ PNGCodec::Encode(diffImage.data(), PNGCodec::FORMAT_RGBA, diffImage.width(),
+ diffImage.height(), diffImage.width() * 4, false, &pngData);
+ if (!writeFile(outFile, &pngData.front(), pngData.size()))
+ return statusError;
+ return statusDifferent;
+}
+
+int main(int argc, const char* argv[])
+{
+ Vector<const char*> values;
+ bool pollStdin = false;
+ bool generateDiff = false;
+ for (int i = 1; i < argc; ++i) {
+ if (!strcmp(argv[i], optionPollStdin))
+ pollStdin = true;
+ else if (!strcmp(argv[i], optionGenerateDiff))
+ generateDiff = true;
+ else
+ values.append(argv[i]);
+ }
+
+ if (pollStdin) {
+ // Watch stdin for filenames.
+ const size_t bufferSize = PATH_MAX;
+ char stdinBuffer[bufferSize];
+ char firstName[bufferSize];
+ bool haveFirstName = false;
+ while (fgets(stdinBuffer, bufferSize, stdin)) {
+ if (!stdinBuffer[0])
+ continue;
+
+ if (haveFirstName) {
+ // compareImages writes results to stdout unless an error occurred.
+ if (compareImages(firstName, stdinBuffer) == statusError)
+ printf("error\n");
+ fflush(stdout);
+ haveFirstName = false;
+ } else {
+ // Save the first filename in another buffer and wait for the second
+ // filename to arrive via stdin.
+ strcpy(firstName, stdinBuffer);
+ haveFirstName = true;
+ }
+ }
+ return 0;
+ }
+
+ if (generateDiff) {
+ if (values.size() == 3)
+ return diffImages(values[0], values[1], values[2]);
+ } else if (values.size() == 2)
+ return compareImages(argv[1], argv[2]);
+
+ printHelp();
+ return statusError;
+}
diff --git a/WebKitTools/DumpRenderTree/chromium/LayoutTestController.cpp b/WebKitTools/DumpRenderTree/chromium/LayoutTestController.cpp
new file mode 100644
index 0000000..d0dca69
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/LayoutTestController.cpp
@@ -0,0 +1,1179 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2010 Pawel Hajdan (phajdan.jr@chromium.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "LayoutTestController.h"
+
+#include "TestShell.h"
+#include "WebViewHost.h"
+#include "base/string_util.h"
+#include "public/WebAnimationController.h"
+#include "public/WebConsoleMessage.h"
+#include "public/WebDocument.h"
+#include "public/WebFrame.h"
+#include "public/WebInputElement.h"
+#include "public/WebKit.h"
+#include "public/WebScriptSource.h"
+#include "public/WebSecurityPolicy.h"
+#include "public/WebSettings.h"
+#include "public/WebSize.h"
+#include "public/WebURL.h"
+#include "public/WebView.h"
+#include "webkit/support/webkit_support.h"
+
+#if OS(WINDOWS)
+#include <wtf/OwnArrayPtr.h>
+#endif
+
+using namespace WebKit;
+using namespace std;
+
+LayoutTestController::LayoutTestController(TestShell* shell)
+ : m_timeoutFactory(this)
+ , m_shell(shell)
+ , m_workQueue(this)
+{
+
+ // Initialize the map that associates methods of this class with the names
+ // they will use when called by JavaScript. The actual binding of those
+ // names to their methods will be done by calling bindToJavaScript() (defined
+ // by CppBoundClass, the parent to LayoutTestController).
+ bindMethod("dumpAsText", &LayoutTestController::dumpAsText);
+ bindMethod("dumpChildFrameScrollPositions", &LayoutTestController::dumpChildFrameScrollPositions);
+ bindMethod("dumpChildFramesAsText", &LayoutTestController::dumpChildFramesAsText);
+ bindMethod("dumpDatabaseCallbacks", &LayoutTestController::dumpDatabaseCallbacks);
+ bindMethod("dumpEditingCallbacks", &LayoutTestController::dumpEditingCallbacks);
+ bindMethod("dumpBackForwardList", &LayoutTestController::dumpBackForwardList);
+ bindMethod("dumpFrameLoadCallbacks", &LayoutTestController::dumpFrameLoadCallbacks);
+ bindMethod("dumpResourceLoadCallbacks", &LayoutTestController::dumpResourceLoadCallbacks);
+ bindMethod("dumpStatusCallbacks", &LayoutTestController::dumpWindowStatusChanges);
+ bindMethod("dumpTitleChanges", &LayoutTestController::dumpTitleChanges);
+ bindMethod("setAcceptsEditing", &LayoutTestController::setAcceptsEditing);
+ bindMethod("waitUntilDone", &LayoutTestController::waitUntilDone);
+ bindMethod("notifyDone", &LayoutTestController::notifyDone);
+ bindMethod("queueReload", &LayoutTestController::queueReload);
+ bindMethod("queueLoadingScript", &LayoutTestController::queueLoadingScript);
+ bindMethod("queueNonLoadingScript", &LayoutTestController::queueNonLoadingScript);
+ bindMethod("queueLoad", &LayoutTestController::queueLoad);
+ bindMethod("queueBackNavigation", &LayoutTestController::queueBackNavigation);
+ bindMethod("queueForwardNavigation", &LayoutTestController::queueForwardNavigation);
+ bindMethod("windowCount", &LayoutTestController::windowCount);
+ bindMethod("setCanOpenWindows", &LayoutTestController::setCanOpenWindows);
+ bindMethod("setCloseRemainingWindowsWhenComplete", &LayoutTestController::setCloseRemainingWindowsWhenComplete);
+ bindMethod("objCIdentityIsEqual", &LayoutTestController::objCIdentityIsEqual);
+ bindMethod("setAlwaysAcceptCookies", &LayoutTestController::setAlwaysAcceptCookies);
+ bindMethod("setWindowIsKey", &LayoutTestController::setWindowIsKey);
+ bindMethod("setTabKeyCyclesThroughElements", &LayoutTestController::setTabKeyCyclesThroughElements);
+ bindMethod("setUserStyleSheetLocation", &LayoutTestController::setUserStyleSheetLocation);
+ bindMethod("setUserStyleSheetEnabled", &LayoutTestController::setUserStyleSheetEnabled);
+ bindMethod("pathToLocalResource", &LayoutTestController::pathToLocalResource);
+ bindMethod("addFileToPasteboardOnDrag", &LayoutTestController::addFileToPasteboardOnDrag);
+ bindMethod("execCommand", &LayoutTestController::execCommand);
+ bindMethod("isCommandEnabled", &LayoutTestController::isCommandEnabled);
+ bindMethod("setPopupBlockingEnabled", &LayoutTestController::setPopupBlockingEnabled);
+ bindMethod("setStopProvisionalFrameLoads", &LayoutTestController::setStopProvisionalFrameLoads);
+ bindMethod("setSmartInsertDeleteEnabled", &LayoutTestController::setSmartInsertDeleteEnabled);
+ bindMethod("setSelectTrailingWhitespaceEnabled", &LayoutTestController::setSelectTrailingWhitespaceEnabled);
+ bindMethod("pauseAnimationAtTimeOnElementWithId", &LayoutTestController::pauseAnimationAtTimeOnElementWithId);
+ bindMethod("pauseTransitionAtTimeOnElementWithId", &LayoutTestController::pauseTransitionAtTimeOnElementWithId);
+ bindMethod("elementDoesAutoCompleteForElementWithId", &LayoutTestController::elementDoesAutoCompleteForElementWithId);
+ bindMethod("numberOfActiveAnimations", &LayoutTestController::numberOfActiveAnimations);
+ bindMethod("disableImageLoading", &LayoutTestController::disableImageLoading);
+ bindMethod("setIconDatabaseEnabled", &LayoutTestController::setIconDatabaseEnabled);
+ bindMethod("setCustomPolicyDelegate", &LayoutTestController::setCustomPolicyDelegate);
+ bindMethod("waitForPolicyDelegate", &LayoutTestController::waitForPolicyDelegate);
+ bindMethod("setWillSendRequestReturnsNullOnRedirect", &LayoutTestController::setWillSendRequestReturnsNullOnRedirect);
+ bindMethod("setWillSendRequestReturnsNull", &LayoutTestController::setWillSendRequestReturnsNull);
+ bindMethod("addOriginAccessWhitelistEntry", &LayoutTestController::addOriginAccessWhitelistEntry);
+ bindMethod("clearAllDatabases", &LayoutTestController::clearAllDatabases);
+ bindMethod("setDatabaseQuota", &LayoutTestController::setDatabaseQuota);
+ bindMethod("setPOSIXLocale", &LayoutTestController::setPOSIXLocale);
+ bindMethod("counterValueForElementById", &LayoutTestController::counterValueForElementById);
+ bindMethod("addUserScript", &LayoutTestController::addUserScript);
+ bindMethod("pageNumberForElementById", &LayoutTestController::pageNumberForElementById);
+ bindMethod("numberOfPages", &LayoutTestController::numberOfPages);
+ bindMethod("dumpSelectionRect", &LayoutTestController::dumpSelectionRect);
+
+ // The following are stubs.
+ bindMethod("dumpAsWebArchive", &LayoutTestController::dumpAsWebArchive);
+ bindMethod("setMainFrameIsFirstResponder", &LayoutTestController::setMainFrameIsFirstResponder);
+ bindMethod("dumpSelectionRect", &LayoutTestController::dumpSelectionRect);
+ bindMethod("display", &LayoutTestController::display);
+ bindMethod("testRepaint", &LayoutTestController::testRepaint);
+ bindMethod("repaintSweepHorizontally", &LayoutTestController::repaintSweepHorizontally);
+ bindMethod("clearBackForwardList", &LayoutTestController::clearBackForwardList);
+ bindMethod("keepWebHistory", &LayoutTestController::keepWebHistory);
+ bindMethod("storeWebScriptObject", &LayoutTestController::storeWebScriptObject);
+ bindMethod("accessStoredWebScriptObject", &LayoutTestController::accessStoredWebScriptObject);
+ bindMethod("objCClassNameOf", &LayoutTestController::objCClassNameOf);
+ bindMethod("addDisallowedURL", &LayoutTestController::addDisallowedURL);
+ bindMethod("setCallCloseOnWebViews", &LayoutTestController::setCallCloseOnWebViews);
+ bindMethod("setPrivateBrowsingEnabled", &LayoutTestController::setPrivateBrowsingEnabled);
+ bindMethod("setUseDashboardCompatibilityMode", &LayoutTestController::setUseDashboardCompatibilityMode);
+
+ bindMethod("setXSSAuditorEnabled", &LayoutTestController::setXSSAuditorEnabled);
+ bindMethod("evaluateScriptInIsolatedWorld", &LayoutTestController::evaluateScriptInIsolatedWorld);
+ bindMethod("overridePreference", &LayoutTestController::overridePreference);
+ bindMethod("setAllowUniversalAccessFromFileURLs", &LayoutTestController::setAllowUniversalAccessFromFileURLs);
+ bindMethod("setAllowFileAccessFromFileURLs", &LayoutTestController::setAllowFileAccessFromFileURLs);
+ bindMethod("setTimelineProfilingEnabled", &LayoutTestController::setTimelineProfilingEnabled);
+ bindMethod("evaluateInWebInspector", &LayoutTestController::evaluateInWebInspector);
+ bindMethod("forceRedSelectionColors", &LayoutTestController::forceRedSelectionColors);
+
+ // The fallback method is called when an unknown method is invoked.
+ bindFallbackMethod(&LayoutTestController::fallbackMethod);
+
+ // Shared properties.
+ // globalFlag is used by a number of layout tests in
+ // LayoutTests\http\tests\security\dataURL.
+ bindProperty("globalFlag", &m_globalFlag);
+ // webHistoryItemCount is used by tests in LayoutTests\http\tests\history
+ bindProperty("webHistoryItemCount", &m_webHistoryItemCount);
+}
+
+LayoutTestController::WorkQueue::~WorkQueue()
+{
+ reset();
+}
+
+void LayoutTestController::WorkQueue::processWorkSoon()
+{
+ if (m_controller->m_shell->webViewHost()->topLoadingFrame())
+ return;
+
+ if (!m_queue.isEmpty()) {
+ // We delay processing queued work to avoid recursion problems.
+ m_timer.Start(base::TimeDelta(), this, &WorkQueue::processWork);
+ } else if (!m_controller->m_waitUntilDone) {
+ m_controller->m_shell->testFinished();
+ }
+}
+
+void LayoutTestController::WorkQueue::processWork()
+{
+ TestShell* shell = m_controller->m_shell;
+ // Quit doing work once a load is in progress.
+ while (!m_queue.isEmpty()) {
+ bool startedLoad = m_queue.first()->run(shell);
+ delete m_queue.first();
+ m_queue.removeFirst();
+ if (startedLoad)
+ return;
+ }
+
+ if (!m_controller->m_waitUntilDone && !shell->webViewHost()->topLoadingFrame())
+ shell->testFinished();
+}
+
+void LayoutTestController::WorkQueue::reset()
+{
+ m_frozen = false;
+ while (!m_queue.isEmpty()) {
+ delete m_queue.first();
+ m_queue.removeFirst();
+ }
+}
+
+void LayoutTestController::WorkQueue::addWork(WorkItem* work)
+{
+ if (m_frozen) {
+ delete work;
+ return;
+ }
+ m_queue.append(work);
+}
+
+void LayoutTestController::dumpAsText(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpAsText = true;
+ result->setNull();
+}
+
+void LayoutTestController::dumpDatabaseCallbacks(const CppArgumentList&, CppVariant* result)
+{
+ // Do nothing; we don't use this flag anywhere for now
+ result->setNull();
+}
+
+void LayoutTestController::dumpEditingCallbacks(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpEditingCallbacks = true;
+ result->setNull();
+}
+
+void LayoutTestController::dumpBackForwardList(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpBackForwardList = true;
+ result->setNull();
+}
+
+void LayoutTestController::dumpFrameLoadCallbacks(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpFrameLoadCallbacks = true;
+ result->setNull();
+}
+
+void LayoutTestController::dumpResourceLoadCallbacks(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpResourceLoadCallbacks = true;
+ result->setNull();
+}
+
+void LayoutTestController::dumpChildFrameScrollPositions(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpChildFrameScrollPositions = true;
+ result->setNull();
+}
+
+void LayoutTestController::dumpChildFramesAsText(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpChildFramesAsText = true;
+ result->setNull();
+}
+
+void LayoutTestController::dumpWindowStatusChanges(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpWindowStatusChanges = true;
+ result->setNull();
+}
+
+void LayoutTestController::dumpTitleChanges(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpTitleChanges = true;
+ result->setNull();
+}
+
+void LayoutTestController::setAcceptsEditing(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_acceptsEditing = arguments[0].value.boolValue;
+ result->setNull();
+}
+
+void LayoutTestController::waitUntilDone(const CppArgumentList&, CppVariant* result)
+{
+ if (!webkit_support::BeingDebugged()) {
+ webkit_support::PostDelayedTaskFromHere(
+ m_timeoutFactory.NewRunnableMethod(&LayoutTestController::notifyDoneTimedOut),
+ m_shell->layoutTestTimeout());
+ }
+ m_waitUntilDone = true;
+ result->setNull();
+}
+
+void LayoutTestController::notifyDone(const CppArgumentList&, CppVariant* result)
+{
+ // Test didn't timeout. Kill the timeout timer.
+ m_timeoutFactory.RevokeAll();
+
+ completeNotifyDone(false);
+ result->setNull();
+}
+
+void LayoutTestController::notifyDoneTimedOut()
+{
+ completeNotifyDone(true);
+}
+
+void LayoutTestController::completeNotifyDone(bool isTimeout)
+{
+ if (m_waitUntilDone && !m_shell->webViewHost()->topLoadingFrame() && m_workQueue.isEmpty()) {
+ if (isTimeout)
+ m_shell->testTimedOut();
+ else
+ m_shell->testFinished();
+ }
+ m_waitUntilDone = false;
+}
+
+class WorkItemBackForward : public LayoutTestController::WorkItem {
+public:
+ WorkItemBackForward(int distance) : m_distance(distance) {}
+ bool run(TestShell* shell)
+ {
+ shell->goToOffset(m_distance);
+ return true; // FIXME: Did it really start a navigation?
+ }
+private:
+ int m_distance;
+};
+
+void LayoutTestController::queueBackNavigation(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isNumber())
+ m_workQueue.addWork(new WorkItemBackForward(-arguments[0].toInt32()));
+ result->setNull();
+}
+
+void LayoutTestController::queueForwardNavigation(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isNumber())
+ m_workQueue.addWork(new WorkItemBackForward(arguments[0].toInt32()));
+ result->setNull();
+}
+
+class WorkItemReload : public LayoutTestController::WorkItem {
+public:
+ bool run(TestShell* shell)
+ {
+ shell->reload();
+ return true;
+ }
+};
+
+void LayoutTestController::queueReload(const CppArgumentList&, CppVariant* result)
+{
+ m_workQueue.addWork(new WorkItemReload);
+ result->setNull();
+}
+
+class WorkItemLoadingScript : public LayoutTestController::WorkItem {
+public:
+ WorkItemLoadingScript(const string& script) : m_script(script) {}
+ bool run(TestShell* shell)
+ {
+ shell->webView()->mainFrame()->executeScript(WebScriptSource(WebString::fromUTF8(m_script)));
+ return true; // FIXME: Did it really start a navigation?
+ }
+private:
+ string m_script;
+};
+
+class WorkItemNonLoadingScript : public LayoutTestController::WorkItem {
+public:
+ WorkItemNonLoadingScript(const string& script) : m_script(script) {}
+ bool run(TestShell* shell)
+ {
+ shell->webView()->mainFrame()->executeScript(WebScriptSource(WebString::fromUTF8(m_script)));
+ return false;
+ }
+private:
+ string m_script;
+};
+
+void LayoutTestController::queueLoadingScript(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isString())
+ m_workQueue.addWork(new WorkItemLoadingScript(arguments[0].toString()));
+ result->setNull();
+}
+
+void LayoutTestController::queueNonLoadingScript(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isString())
+ m_workQueue.addWork(new WorkItemNonLoadingScript(arguments[0].toString()));
+ result->setNull();
+}
+
+class WorkItemLoad : public LayoutTestController::WorkItem {
+public:
+ WorkItemLoad(const WebURL& url, const WebString& target)
+ : m_url(url)
+ , m_target(target) {}
+ bool run(TestShell* shell)
+ {
+ shell->webViewHost()->loadURLForFrame(m_url, m_target);
+ return true; // FIXME: Did it really start a navigation?
+ }
+private:
+ WebURL m_url;
+ WebString m_target;
+};
+
+void LayoutTestController::queueLoad(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isString()) {
+ // FIXME: Implement WebURL::resolve() and avoid GURL.
+ GURL currentURL = m_shell->webView()->mainFrame()->url();
+ GURL fullURL = currentURL.Resolve(arguments[0].toString());
+
+ string target = "";
+ if (arguments.size() > 1 && arguments[1].isString())
+ target = arguments[1].toString();
+
+ m_workQueue.addWork(new WorkItemLoad(fullURL, WebString::fromUTF8(target)));
+ }
+ result->setNull();
+}
+
+void LayoutTestController::objCIdentityIsEqual(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() < 2) {
+ // This is the best we can do to return an error.
+ result->setNull();
+ return;
+ }
+ result->set(arguments[0].isEqual(arguments[1]));
+}
+
+void LayoutTestController::reset()
+{
+ if (m_shell) {
+ m_shell->webView()->setZoomLevel(false, 0);
+ m_shell->webView()->setTabKeyCyclesThroughElements(true);
+#if defined(OS_LINUX)
+ // (Constants copied because we can't depend on the header that defined
+ // them from this file.)
+ m_shell->webView()->setSelectionColors(0xff1e90ff, 0xff000000, 0xffc8c8c8, 0xff323232);
+#endif // defined(OS_LINUX)
+ m_shell->webView()->removeAllUserContent();
+ }
+ m_dumpAsText = false;
+ m_dumpEditingCallbacks = false;
+ m_dumpFrameLoadCallbacks = false;
+ m_dumpResourceLoadCallbacks = false;
+ m_dumpBackForwardList = false;
+ m_dumpChildFrameScrollPositions = false;
+ m_dumpChildFramesAsText = false;
+ m_dumpWindowStatusChanges = false;
+ m_dumpSelectionRect = false;
+ m_dumpTitleChanges = false;
+ m_acceptsEditing = true;
+ m_waitUntilDone = false;
+ m_canOpenWindows = false;
+ m_testRepaint = false;
+ m_sweepHorizontally = false;
+ m_shouldAddFileToPasteboard = false;
+ m_stopProvisionalFrameLoads = false;
+ m_globalFlag.set(false);
+ m_webHistoryItemCount.set(0);
+
+ webkit_support::SetAcceptAllCookies(false);
+ WebSecurityPolicy::resetOriginAccessWhiteLists();
+
+ // Reset the default quota for each origin to 5MB
+ webkit_support::SetDatabaseQuota(5 * 1024 * 1024);
+
+ setlocale(LC_ALL, "");
+
+ if (m_closeRemainingWindows)
+ m_shell->closeRemainingWindows();
+ else
+ m_closeRemainingWindows = true;
+ m_workQueue.reset();
+}
+
+void LayoutTestController::locationChangeDone()
+{
+ m_webHistoryItemCount.set(m_shell->navigationEntryCount());
+
+ // No more new work after the first complete load.
+ m_workQueue.setFrozen(true);
+
+ if (!m_waitUntilDone)
+ m_workQueue.processWorkSoon();
+}
+
+void LayoutTestController::policyDelegateDone()
+{
+ ASSERT(m_waitUntilDone);
+ m_shell->testFinished();
+ m_waitUntilDone = false;
+}
+
+void LayoutTestController::setCanOpenWindows(const CppArgumentList&, CppVariant* result)
+{
+ m_canOpenWindows = true;
+ result->setNull();
+}
+
+void LayoutTestController::setTabKeyCyclesThroughElements(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_shell->webView()->setTabKeyCyclesThroughElements(arguments[0].toBoolean());
+ result->setNull();
+}
+
+void LayoutTestController::windowCount(const CppArgumentList&, CppVariant* result)
+{
+ result->set(static_cast<int>(m_shell->windowCount()));
+}
+
+void LayoutTestController::setCloseRemainingWindowsWhenComplete(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_closeRemainingWindows = arguments[0].value.boolValue;
+ result->setNull();
+}
+
+void LayoutTestController::setAlwaysAcceptCookies(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0)
+ webkit_support::SetAcceptAllCookies(cppVariantToBool(arguments[0]));
+ result->setNull();
+}
+
+void LayoutTestController::setWindowIsKey(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_shell->setFocus(m_shell->webView(), arguments[0].value.boolValue);
+ result->setNull();
+}
+
+void LayoutTestController::setUserStyleSheetEnabled(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_shell->webView()->settings()->setUserStyleSheetLocation(arguments[0].value.boolValue ? m_userStyleSheetLocation : WebURL());
+ result->setNull();
+}
+
+void LayoutTestController::setUserStyleSheetLocation(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isString()) {
+ m_userStyleSheetLocation = webkit_support::RewriteLayoutTestsURL(arguments[0].toString());
+ m_shell->webView()->settings()->setUserStyleSheetLocation(m_userStyleSheetLocation);
+ }
+ result->setNull();
+}
+
+void LayoutTestController::execCommand(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() <= 0 || !arguments[0].isString())
+ return;
+
+ std::string command = arguments[0].toString();
+ std::string value("");
+ // Ignore the second parameter (which is userInterface)
+ // since this command emulates a manual action.
+ if (arguments.size() >= 3 && arguments[2].isString())
+ value = arguments[2].toString();
+
+ // Note: webkit's version does not return the boolean, so neither do we.
+ m_shell->webView()->focusedFrame()->executeCommand(WebString::fromUTF8(command), WebString::fromUTF8(value));
+}
+
+void LayoutTestController::isCommandEnabled(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() <= 0 || !arguments[0].isString()) {
+ result->setNull();
+ return;
+ }
+
+ std::string command = arguments[0].toString();
+ bool rv = m_shell->webView()->focusedFrame()->isCommandEnabled(WebString::fromUTF8(command));
+ result->set(rv);
+}
+
+void LayoutTestController::setPopupBlockingEnabled(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool()) {
+ bool blockPopups = arguments[0].toBoolean();
+ m_shell->webView()->settings()->setJavaScriptCanOpenWindowsAutomatically(!blockPopups);
+ }
+ result->setNull();
+}
+
+void LayoutTestController::setUseDashboardCompatibilityMode(const CppArgumentList&, CppVariant* result)
+{
+ // We have no need to support Dashboard Compatibility Mode (mac-only)
+ result->setNull();
+}
+
+void LayoutTestController::setCustomPolicyDelegate(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool()) {
+ bool enable = arguments[0].value.boolValue;
+ bool permissive = false;
+ if (arguments.size() > 1 && arguments[1].isBool())
+ permissive = arguments[1].value.boolValue;
+ m_shell->webViewHost()->setCustomPolicyDelegate(enable, permissive);
+ }
+ result->setNull();
+}
+
+void LayoutTestController::waitForPolicyDelegate(const CppArgumentList&, CppVariant* result)
+{
+ m_shell->webViewHost()->waitForPolicyDelegate();
+ m_waitUntilDone = true;
+ result->setNull();
+}
+
+void LayoutTestController::setWillSendRequestReturnsNullOnRedirect(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_shell->webViewHost()->setBlockRedirects(arguments[0].value.boolValue);
+ result->setNull();
+}
+
+void LayoutTestController::setWillSendRequestReturnsNull(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_shell->webViewHost()->setRequestReturnNull(arguments[0].value.boolValue);
+ result->setNull();
+}
+
+void LayoutTestController::pathToLocalResource(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() <= 0 || !arguments[0].isString())
+ return;
+
+ string url = arguments[0].toString();
+#if OS(WINDOWS)
+ if (StartsWithASCII(url, "/tmp/", true)) {
+ // We want a temp file.
+ const unsigned tempPrefixLength = 5;
+ size_t bufferSize = MAX_PATH;
+ OwnArrayPtr<WCHAR> tempPath(new WCHAR[bufferSize]);
+ DWORD tempLength = ::GetTempPathW(bufferSize, tempPath.get());
+ if (tempLength + url.length() - tempPrefixLength + 1 > bufferSize) {
+ bufferSize = tempLength + url.length() - tempPrefixLength + 1;
+ tempPath.set(new WCHAR[bufferSize]);
+ tempLength = GetTempPathW(bufferSize, tempPath.get());
+ ASSERT(tempLength < bufferSize);
+ }
+ std::string resultPath(WebString(tempPath.get(), tempLength).utf8());
+ resultPath.append(url.substr(tempPrefixLength));
+ result->set(resultPath);
+ return;
+ }
+#endif
+
+ // Some layout tests use file://// which we resolve as a UNC path. Normalize
+ // them to just file:///.
+ while (StartsWithASCII(url, "file:////", false))
+ url = url.substr(0, 8) + url.substr(9);
+ result->set(webkit_support::RewriteLayoutTestsURL(url).spec());
+}
+
+void LayoutTestController::addFileToPasteboardOnDrag(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+ m_shouldAddFileToPasteboard = true;
+}
+
+void LayoutTestController::setStopProvisionalFrameLoads(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+ m_stopProvisionalFrameLoads = true;
+}
+
+void LayoutTestController::setSmartInsertDeleteEnabled(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_shell->webViewHost()->setSmartInsertDeleteEnabled(arguments[0].value.boolValue);
+ result->setNull();
+}
+
+void LayoutTestController::setSelectTrailingWhitespaceEnabled(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_shell->webViewHost()->setSelectTrailingWhitespaceEnabled(arguments[0].value.boolValue);
+ result->setNull();
+}
+
+bool LayoutTestController::pauseAnimationAtTimeOnElementWithId(const WebString& animationName, double time, const WebString& elementId)
+{
+ WebFrame* webFrame = m_shell->webView()->mainFrame();
+ if (!webFrame)
+ return false;
+
+ WebAnimationController* controller = webFrame->animationController();
+ if (!controller)
+ return false;
+
+ WebElement element = webFrame->document().getElementById(elementId);
+ if (element.isNull())
+ return false;
+ return controller->pauseAnimationAtTime(element, animationName, time);
+}
+
+bool LayoutTestController::pauseTransitionAtTimeOnElementWithId(const WebString& propertyName, double time, const WebString& elementId)
+{
+ WebFrame* webFrame = m_shell->webView()->mainFrame();
+ if (!webFrame)
+ return false;
+
+ WebAnimationController* controller = webFrame->animationController();
+ if (!controller)
+ return false;
+
+ WebElement element = webFrame->document().getElementById(elementId);
+ if (element.isNull())
+ return false;
+ return controller->pauseTransitionAtTime(element, propertyName, time);
+}
+
+bool LayoutTestController::elementDoesAutoCompleteForElementWithId(const WebString& elementId)
+{
+ WebFrame* webFrame = m_shell->webView()->mainFrame();
+ if (!webFrame)
+ return false;
+
+ WebElement element = webFrame->document().getElementById(elementId);
+ if (element.isNull() || !element.hasTagName("input"))
+ return false;
+
+ WebInputElement inputElement = element.toElement<WebInputElement>();
+ return inputElement.autoComplete();
+}
+
+int LayoutTestController::numberOfActiveAnimations()
+{
+ WebFrame* webFrame = m_shell->webView()->mainFrame();
+ if (!webFrame)
+ return -1;
+
+ WebAnimationController* controller = webFrame->animationController();
+ if (!controller)
+ return -1;
+
+ return controller->numberOfActiveAnimations();
+}
+
+void LayoutTestController::pauseAnimationAtTimeOnElementWithId(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->set(false);
+ if (arguments.size() > 2 && arguments[0].isString() && arguments[1].isNumber() && arguments[2].isString()) {
+ WebString animationName = cppVariantToWebString(arguments[0]);
+ double time = arguments[1].toDouble();
+ WebString elementId = cppVariantToWebString(arguments[2]);
+ result->set(pauseAnimationAtTimeOnElementWithId(animationName, time, elementId));
+ }
+}
+
+void LayoutTestController::pauseTransitionAtTimeOnElementWithId(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->set(false);
+ if (arguments.size() > 2 && arguments[0].isString() && arguments[1].isNumber() && arguments[2].isString()) {
+ WebString propertyName = cppVariantToWebString(arguments[0]);
+ double time = arguments[1].toDouble();
+ WebString elementId = cppVariantToWebString(arguments[2]);
+ result->set(pauseTransitionAtTimeOnElementWithId(propertyName, time, elementId));
+ }
+}
+
+void LayoutTestController::elementDoesAutoCompleteForElementWithId(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() != 1 || !arguments[0].isString()) {
+ result->set(false);
+ return;
+ }
+ WebString elementId = cppVariantToWebString(arguments[0]);
+ result->set(elementDoesAutoCompleteForElementWithId(elementId));
+}
+
+void LayoutTestController::numberOfActiveAnimations(const CppArgumentList&, CppVariant* result)
+{
+ result->set(numberOfActiveAnimations());
+}
+
+void LayoutTestController::disableImageLoading(const CppArgumentList&, CppVariant* result)
+{
+ m_shell->webView()->settings()->setLoadsImagesAutomatically(false);
+ result->setNull();
+}
+
+void LayoutTestController::setIconDatabaseEnabled(const CppArgumentList&, CppVariant* result)
+{
+ // We don't use the WebKit icon database.
+ result->setNull();
+}
+
+//
+// Unimplemented stubs
+//
+
+void LayoutTestController::dumpAsWebArchive(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+}
+
+void LayoutTestController::setMainFrameIsFirstResponder(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+}
+
+void LayoutTestController::dumpSelectionRect(const CppArgumentList& arguments, CppVariant* result)
+{
+ m_dumpSelectionRect = true;
+ result->setNull();
+}
+
+void LayoutTestController::display(const CppArgumentList& arguments, CppVariant* result)
+{
+ WebViewHost* host = m_shell->webViewHost();
+ const WebKit::WebSize& size = m_shell->webView()->size();
+ WebRect rect(0, 0, size.width, size.height);
+ host->updatePaintRect(rect);
+ host->paintInvalidatedRegion();
+ host->displayRepaintMask();
+ result->setNull();
+}
+
+void LayoutTestController::testRepaint(const CppArgumentList&, CppVariant* result)
+{
+ m_testRepaint = true;
+ result->setNull();
+}
+
+void LayoutTestController::repaintSweepHorizontally(const CppArgumentList&, CppVariant* result)
+{
+ m_sweepHorizontally = true;
+ result->setNull();
+}
+
+void LayoutTestController::clearBackForwardList(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+}
+
+void LayoutTestController::keepWebHistory(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+}
+
+void LayoutTestController::storeWebScriptObject(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+}
+
+void LayoutTestController::accessStoredWebScriptObject(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+}
+
+void LayoutTestController::objCClassNameOf(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+}
+
+void LayoutTestController::addDisallowedURL(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+}
+void LayoutTestController::setCallCloseOnWebViews(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+}
+
+void LayoutTestController::setPrivateBrowsingEnabled(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+}
+
+void LayoutTestController::setXSSAuditorEnabled(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_shell->webView()->settings()->setXSSAuditorEnabled(arguments[0].value.boolValue);
+ result->setNull();
+}
+
+void LayoutTestController::evaluateScriptInIsolatedWorld(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() >= 2 && arguments[0].isNumber() && arguments[1].isString()) {
+ WebScriptSource source(WebString::fromUTF8(arguments[1].toString()));
+ // This relies on the iframe focusing itself when it loads. This is a bit
+ // sketchy, but it seems to be what other tests do.
+ m_shell->webView()->focusedFrame()->executeScriptInIsolatedWorld(arguments[0].toInt32(), &source, 1, 1);
+ }
+ result->setNull();
+}
+
+void LayoutTestController::setAllowUniversalAccessFromFileURLs(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_shell->webView()->settings()->setAllowUniversalAccessFromFileURLs(arguments[0].value.boolValue);
+ result->setNull();
+}
+
+void LayoutTestController::setAllowFileAccessFromFileURLs(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_shell->webView()->settings()->setAllowFileAccessFromFileURLs(arguments[0].value.boolValue);
+ result->setNull();
+}
+
+// Need these conversions because the format of the value for booleans
+// may vary - for example, on mac "1" and "0" are used for boolean.
+bool LayoutTestController::cppVariantToBool(const CppVariant& value)
+{
+ if (value.isBool())
+ return value.toBoolean();
+ if (value.isInt32())
+ return value.toInt32();
+ if (value.isString()) {
+ string valueString = value.toString();
+ if (valueString == "true" || valueString == "1")
+ return true;
+ if (valueString == "false" || valueString == "0")
+ return false;
+ }
+ logErrorToConsole("Invalid value. Expected boolean value.");
+ return false;
+}
+
+int32_t LayoutTestController::cppVariantToInt32(const CppVariant& value)
+{
+ if (value.isInt32())
+ return value.toInt32();
+ if (value.isString()) {
+ int number;
+ if (StringToInt(value.toString(), &number))
+ return number;
+ }
+ logErrorToConsole("Invalid value for preference. Expected integer value.");
+ return 0;
+}
+
+WebString LayoutTestController::cppVariantToWebString(const CppVariant& value)
+{
+ if (!value.isString()) {
+ logErrorToConsole("Invalid value for preference. Expected string value.");
+ return WebString();
+ }
+ return WebString::fromUTF8(value.toString());
+}
+
+void LayoutTestController::overridePreference(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() != 2 || !arguments[0].isString())
+ return;
+
+ string key = arguments[0].toString();
+ CppVariant value = arguments[1];
+ WebSettings* settings = m_shell->webView()->settings();
+ if (key == "WebKitStandardFont")
+ settings->setStandardFontFamily(cppVariantToWebString(value));
+ else if (key == "WebKitFixedFont")
+ settings->setFixedFontFamily(cppVariantToWebString(value));
+ else if (key == "WebKitSerifFont")
+ settings->setSerifFontFamily(cppVariantToWebString(value));
+ else if (key == "WebKitSansSerifFont")
+ settings->setSansSerifFontFamily(cppVariantToWebString(value));
+ else if (key == "WebKitCursiveFont")
+ settings->setCursiveFontFamily(cppVariantToWebString(value));
+ else if (key == "WebKitFantasyFont")
+ settings->setFantasyFontFamily(cppVariantToWebString(value));
+ else if (key == "WebKitDefaultFontSize")
+ settings->setDefaultFontSize(cppVariantToInt32(value));
+ else if (key == "WebKitDefaultFixedFontSize")
+ settings->setDefaultFixedFontSize(cppVariantToInt32(value));
+ else if (key == "WebKitMinimumFontSize")
+ settings->setMinimumFontSize(cppVariantToInt32(value));
+ else if (key == "WebKitMinimumLogicalFontSize")
+ settings->setMinimumLogicalFontSize(cppVariantToInt32(value));
+ else if (key == "WebKitDefaultTextEncodingName")
+ settings->setDefaultTextEncodingName(cppVariantToWebString(value));
+ else if (key == "WebKitJavaScriptEnabled")
+ settings->setJavaScriptEnabled(cppVariantToBool(value));
+ else if (key == "WebKitWebSecurityEnabled")
+ settings->setWebSecurityEnabled(cppVariantToBool(value));
+ else if (key == "WebKitJavaScriptCanOpenWindowsAutomatically")
+ settings->setJavaScriptCanOpenWindowsAutomatically(cppVariantToBool(value));
+ else if (key == "WebKitDisplayImagesKey")
+ settings->setLoadsImagesAutomatically(cppVariantToBool(value));
+ else if (key == "WebKitPluginsEnabled")
+ settings->setPluginsEnabled(cppVariantToBool(value));
+ else if (key == "WebKitDOMPasteAllowedPreferenceKey")
+ settings->setDOMPasteAllowed(cppVariantToBool(value));
+ else if (key == "WebKitDeveloperExtrasEnabledPreferenceKey")
+ settings->setDeveloperExtrasEnabled(cppVariantToBool(value));
+ else if (key == "WebKitShrinksStandaloneImagesToFit")
+ settings->setShrinksStandaloneImagesToFit(cppVariantToBool(value));
+ else if (key == "WebKitTextAreasAreResizable")
+ settings->setTextAreasAreResizable(cppVariantToBool(value));
+ else if (key == "WebKitJavaEnabled")
+ settings->setJavaEnabled(cppVariantToBool(value));
+ else if (key == "WebKitUsesPageCachePreferenceKey")
+ settings->setUsesPageCache(cppVariantToBool(value));
+ else if (key == "WebKitXSSAuditorEnabled")
+ settings->setXSSAuditorEnabled(cppVariantToBool(value));
+ else if (key == "WebKitLocalStorageEnabledPreferenceKey")
+ settings->setLocalStorageEnabled(cppVariantToBool(value));
+ else if (key == "WebKitOfflineWebApplicationCacheEnabled")
+ settings->setOfflineWebApplicationCacheEnabled(cppVariantToBool(value));
+ else if (key == "WebKitTabToLinksPreferenceKey")
+ m_shell->webView()->setTabsToLinks(cppVariantToBool(value));
+ else if (key == "WebKitWebGLEnabled")
+ settings->setExperimentalWebGLEnabled(cppVariantToBool(value));
+ else {
+ string message("Invalid name for preference: ");
+ message.append(key);
+ logErrorToConsole(message);
+ }
+}
+
+void LayoutTestController::fallbackMethod(const CppArgumentList&, CppVariant* result)
+{
+ printf("CONSOLE MESSAGE: JavaScript ERROR: unknown method called on LayoutTestController\n");
+ result->setNull();
+}
+
+void LayoutTestController::addOriginAccessWhitelistEntry(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ if (arguments.size() != 4 || !arguments[0].isString() || !arguments[1].isString()
+ || !arguments[2].isString() || !arguments[3].isBool())
+ return;
+
+ WebKit::WebURL url(GURL(arguments[0].toString()));
+ if (!url.isValid())
+ return;
+
+ WebSecurityPolicy::whiteListAccessFromOrigin(url,
+ WebString::fromUTF8(arguments[1].toString()),
+ WebString::fromUTF8(arguments[2].toString()),
+ arguments[3].toBoolean());
+}
+
+void LayoutTestController::clearAllDatabases(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ webkit_support::ClearAllDatabases();
+}
+
+void LayoutTestController::setDatabaseQuota(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if ((arguments.size() >= 1) && arguments[0].isInt32())
+ webkit_support::SetDatabaseQuota(arguments[0].toInt32());
+}
+
+void LayoutTestController::setPOSIXLocale(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() == 1 && arguments[0].isString())
+ setlocale(LC_ALL, arguments[0].toString().c_str());
+}
+
+void LayoutTestController::counterValueForElementById(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 1 || !arguments[0].isString())
+ return;
+ WebFrame* frame = m_shell->webView()->mainFrame();
+ if (!frame)
+ return;
+ WebString counterValue = frame->counterValueForElementById(cppVariantToWebString(arguments[0]));
+ if (counterValue.isNull())
+ return;
+ result->set(counterValue.utf8());
+}
+
+static bool parsePageSizeParameters(const CppArgumentList& arguments,
+ int argOffset,
+ float* pageWidthInPixels,
+ float* pageHeightInPixels)
+{
+ // WebKit is using the window width/height of DumpRenderTree as the
+ // default value of the page size.
+ // FIXME: share these values with other ports.
+ *pageWidthInPixels = 800;
+ *pageHeightInPixels = 600;
+ switch (arguments.size() - argOffset) {
+ case 2:
+ if (!arguments[argOffset].isNumber() || !arguments[1 + argOffset].isNumber())
+ return false;
+ *pageWidthInPixels = static_cast<float>(arguments[argOffset].toInt32());
+ *pageHeightInPixels = static_cast<float>(arguments[1 + argOffset].toInt32());
+ // fall through.
+ case 0:
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+void LayoutTestController::pageNumberForElementById(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ float pageWidthInPixels = 0;
+ float pageHeightInPixels = 0;
+ if (!parsePageSizeParameters(arguments, 1,
+ &pageWidthInPixels, &pageHeightInPixels))
+ return;
+ if (!arguments[0].isString())
+ return;
+ WebFrame* frame = m_shell->webView()->mainFrame();
+ if (!frame)
+ return;
+ result->set(frame->pageNumberForElementById(cppVariantToWebString(arguments[0]),
+ pageWidthInPixels, pageHeightInPixels));
+}
+
+void LayoutTestController::numberOfPages(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ float pageWidthInPixels = 0;
+ float pageHeightInPixels = 0;
+ if (!parsePageSizeParameters(arguments, 0, &pageWidthInPixels, &pageHeightInPixels))
+ return;
+
+ WebFrame* frame = m_shell->webView()->mainFrame();
+ if (!frame)
+ return;
+ WebSize size(pageWidthInPixels, pageHeightInPixels);
+ int numberOfPages = frame->printBegin(size);
+ frame->printEnd();
+ result->set(numberOfPages);
+}
+
+void LayoutTestController::logErrorToConsole(const std::string& text)
+{
+ m_shell->webViewHost()->didAddMessageToConsole(
+ WebConsoleMessage(WebConsoleMessage::LevelError, WebString::fromUTF8(text)),
+ WebString(), 0);
+}
+
+void LayoutTestController::setTimelineProfilingEnabled(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 1 || !arguments[0].isBool())
+ return;
+ // FIXME: Should call TestShellDevToolsAgent::setTimelineProfilingEnabled().
+}
+
+void LayoutTestController::evaluateInWebInspector(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 2 || !arguments[0].isInt32() || !arguments[1].isString())
+ return;
+ // FIXME: Should call TestShellDevToolsAgent::evaluateInWebInspector().
+}
+
+void LayoutTestController::forceRedSelectionColors(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ m_shell->webView()->setSelectionColors(0xffee0000, 0xff00ee00, 0xff000000, 0xffc0c0c0);
+}
+
+void LayoutTestController::addUserScript(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 1 || !arguments[0].isString() || !arguments[1].isBool())
+ return;
+ m_shell->webView()->addUserScript(WebString::fromUTF8(arguments[0].toString()), arguments[1].toBoolean());
+}
diff --git a/WebKitTools/DumpRenderTree/chromium/LayoutTestController.h b/WebKitTools/DumpRenderTree/chromium/LayoutTestController.h
new file mode 100644
index 0000000..a8639da
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/LayoutTestController.h
@@ -0,0 +1,440 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2010 Pawel Hajdan (phajdan.jr@chromium.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ LayoutTestController class:
+ Bound to a JavaScript window.layoutTestController object using the
+ CppBoundClass::bindToJavascript(), this allows layout tests that are run in
+ the test_shell (or, in principle, any web page loaded into a client app built
+ with this class) to control various aspects of how the tests are run and what
+ sort of output they produce.
+*/
+
+#ifndef LayoutTestController_h
+#define LayoutTestController_h
+
+#include "CppBoundClass.h"
+#include "base/timer.h" // FIXME: Remove this.
+#include "public/WebString.h"
+#include "public/WebURL.h"
+#include <wtf/Deque.h>
+
+class TestShell;
+
+class LayoutTestController : public CppBoundClass {
+public:
+ // Builds the property and method lists needed to bind this class to a JS
+ // object.
+ LayoutTestController(TestShell*);
+
+ // This function sets a flag that tells the test_shell to dump pages as
+ // plain text, rather than as a text representation of the renderer's state.
+ // It takes no arguments, and ignores any that may be present.
+ void dumpAsText(const CppArgumentList&, CppVariant*);
+
+ // This function should set a flag that tells the test_shell to print a line
+ // of descriptive text for each database command. It should take no
+ // arguments, and ignore any that may be present. However, at the moment, we
+ // don't have any DB function that prints messages, so for now this function
+ // doesn't do anything.
+ void dumpDatabaseCallbacks(const CppArgumentList&, CppVariant*);
+
+ // This function sets a flag that tells the test_shell to print a line of
+ // descriptive text for each editing command. It takes no arguments, and
+ // ignores any that may be present.
+ void dumpEditingCallbacks(const CppArgumentList&, CppVariant*);
+
+ // This function sets a flag that tells the test_shell to print a line of
+ // descriptive text for each frame load callback. It takes no arguments, and
+ // ignores any that may be present.
+ void dumpFrameLoadCallbacks(const CppArgumentList&, CppVariant*);
+
+ // This function sets a flag that tells the test_shell to print out a text
+ // representation of the back/forward list. It ignores all arguments.
+ void dumpBackForwardList(const CppArgumentList&, CppVariant*);
+
+ // This function sets a flag that tells the test_shell to print out the
+ // scroll offsets of the child frames. It ignores all.
+ void dumpChildFrameScrollPositions(const CppArgumentList&, CppVariant*);
+
+ // This function sets a flag that tells the test_shell to recursively
+ // dump all frames as plain text if the dumpAsText flag is set.
+ // It takes no arguments, and ignores any that may be present.
+ void dumpChildFramesAsText(const CppArgumentList&, CppVariant*);
+
+ // This function sets a flag that tells the test_shell to dump all calls
+ // to window.status().
+ // It takes no arguments, and ignores any that may be present.
+ void dumpWindowStatusChanges(const CppArgumentList&, CppVariant*);
+
+ // When called with a boolean argument, this sets a flag that controls
+ // whether content-editable elements accept editing focus when an editing
+ // attempt is made. It ignores any additional arguments.
+ void setAcceptsEditing(const CppArgumentList&, CppVariant*);
+
+ // Functions for dealing with windows. By default we block all new windows.
+ void windowCount(const CppArgumentList&, CppVariant*);
+ void setCanOpenWindows(const CppArgumentList&, CppVariant*);
+ void setCloseRemainingWindowsWhenComplete(const CppArgumentList&, CppVariant*);
+
+ // By default, tests end when page load is complete. These methods are used
+ // to delay the completion of the test until notifyDone is called.
+ void waitUntilDone(const CppArgumentList&, CppVariant*);
+ void notifyDone(const CppArgumentList&, CppVariant*);
+ void notifyDoneTimedOut();
+
+ // Methods for adding actions to the work queue. Used in conjunction with
+ // waitUntilDone/notifyDone above.
+ void queueBackNavigation(const CppArgumentList&, CppVariant*);
+ void queueForwardNavigation(const CppArgumentList&, CppVariant*);
+ void queueReload(const CppArgumentList&, CppVariant*);
+ void queueLoadingScript(const CppArgumentList&, CppVariant*);
+ void queueNonLoadingScript(const CppArgumentList&, CppVariant*);
+ void queueLoad(const CppArgumentList&, CppVariant*);
+
+ // Although this is named "objC" to match the Mac version, it actually tests
+ // the identity of its two arguments in C++.
+ void objCIdentityIsEqual(const CppArgumentList&, CppVariant*);
+
+ // Changes the cookie policy from the default to allow all cookies.
+ void setAlwaysAcceptCookies(const CppArgumentList&, CppVariant*);
+
+ // Gives focus to the window.
+ void setWindowIsKey(const CppArgumentList&, CppVariant*);
+
+ // Method that controls whether pressing Tab key cycles through page elements
+ // or inserts a '\t' char in text area
+ void setTabKeyCyclesThroughElements(const CppArgumentList&, CppVariant*);
+
+ // Passes through to WebPreferences which allows the user to have a custom
+ // style sheet.
+ void setUserStyleSheetEnabled(const CppArgumentList&, CppVariant*);
+ void setUserStyleSheetLocation(const CppArgumentList&, CppVariant*);
+
+ // Puts Webkit in "dashboard compatibility mode", which is used in obscure
+ // Mac-only circumstances. It's not really necessary, and will most likely
+ // never be used by Chrome, but some layout tests depend on its presence.
+ void setUseDashboardCompatibilityMode(const CppArgumentList&, CppVariant*);
+
+ // Causes navigation actions just printout the intended navigation instead
+ // of taking you to the page. This is used for cases like mailto, where you
+ // don't actually want to open the mail program.
+ void setCustomPolicyDelegate(const CppArgumentList&, CppVariant*);
+
+ // Delays completion of the test until the policy delegate runs.
+ void waitForPolicyDelegate(const CppArgumentList&, CppVariant*);
+
+ // Causes WillSendRequest to block redirects.
+ void setWillSendRequestReturnsNullOnRedirect(const CppArgumentList&, CppVariant*);
+
+ // Causes WillSendRequest to return an empty request.
+ void setWillSendRequestReturnsNull(const CppArgumentList&, CppVariant*);
+
+ // Converts a URL starting with file:///tmp/ to the local mapping.
+ void pathToLocalResource(const CppArgumentList&, CppVariant*);
+
+ // Sets a bool such that when a drag is started, we fill the drag clipboard
+ // with a fake file object.
+ void addFileToPasteboardOnDrag(const CppArgumentList&, CppVariant*);
+
+ // Executes an internal command (superset of document.execCommand() commands).
+ void execCommand(const CppArgumentList&, CppVariant*);
+
+ // Checks if an internal command is currently available.
+ void isCommandEnabled(const CppArgumentList&, CppVariant*);
+
+ // Set the WebPreference that controls webkit's popup blocking.
+ void setPopupBlockingEnabled(const CppArgumentList&, CppVariant*);
+
+ // If true, causes provisional frame loads to be stopped for the remainder of
+ // the test.
+ void setStopProvisionalFrameLoads(const CppArgumentList&, CppVariant*);
+
+ // Enable or disable smart insert/delete. This is enabled by default.
+ void setSmartInsertDeleteEnabled(const CppArgumentList&, CppVariant*);
+
+ // Enable or disable trailing whitespace selection on double click.
+ void setSelectTrailingWhitespaceEnabled(const CppArgumentList&, CppVariant*);
+
+ void pauseAnimationAtTimeOnElementWithId(const CppArgumentList&, CppVariant*);
+ void pauseTransitionAtTimeOnElementWithId(const CppArgumentList&, CppVariant*);
+ void elementDoesAutoCompleteForElementWithId(const CppArgumentList&, CppVariant*);
+ void numberOfActiveAnimations(const CppArgumentList&, CppVariant*);
+
+ void disableImageLoading(const CppArgumentList&, CppVariant*);
+
+ void setIconDatabaseEnabled(const CppArgumentList&, CppVariant*);
+
+ void dumpSelectionRect(const CppArgumentList&, CppVariant*);
+
+ // The following are only stubs. TODO(pamg): Implement any of these that
+ // are needed to pass the layout tests.
+ void dumpAsWebArchive(const CppArgumentList&, CppVariant*);
+ void dumpTitleChanges(const CppArgumentList&, CppVariant*);
+ void dumpResourceLoadCallbacks(const CppArgumentList&, CppVariant*);
+ void setMainFrameIsFirstResponder(const CppArgumentList&, CppVariant*);
+ void display(const CppArgumentList&, CppVariant*);
+ void testRepaint(const CppArgumentList&, CppVariant*);
+ void repaintSweepHorizontally(const CppArgumentList&, CppVariant*);
+ void clearBackForwardList(const CppArgumentList&, CppVariant*);
+ void keepWebHistory(const CppArgumentList&, CppVariant*);
+ void storeWebScriptObject(const CppArgumentList&, CppVariant*);
+ void accessStoredWebScriptObject(const CppArgumentList&, CppVariant*);
+ void objCClassNameOf(const CppArgumentList&, CppVariant*);
+ void addDisallowedURL(const CppArgumentList&, CppVariant*);
+ void setCallCloseOnWebViews(const CppArgumentList&, CppVariant*);
+ void setPrivateBrowsingEnabled(const CppArgumentList&, CppVariant*);
+
+ void setXSSAuditorEnabled(const CppArgumentList&, CppVariant*);
+ void evaluateScriptInIsolatedWorld(const CppArgumentList&, CppVariant*);
+ void overridePreference(const CppArgumentList&, CppVariant*);
+ void setAllowUniversalAccessFromFileURLs(const CppArgumentList&, CppVariant*);
+ void setAllowFileAccessFromFileURLs(const CppArgumentList&, CppVariant*);
+
+
+ // The fallback method is called when a nonexistent method is called on
+ // the layout test controller object.
+ // It is usefull to catch typos in the JavaScript code (a few layout tests
+ // do have typos in them) and it allows the script to continue running in
+ // that case (as the Mac does).
+ void fallbackMethod(const CppArgumentList&, CppVariant*);
+
+ // Allows layout tests to call SecurityOrigin::addOriginAccessWhitelistEntry().
+ void addOriginAccessWhitelistEntry(const CppArgumentList&, CppVariant*);
+
+ // Clears all databases.
+ void clearAllDatabases(const CppArgumentList&, CppVariant*);
+ // Sets the default quota for all origins
+ void setDatabaseQuota(const CppArgumentList&, CppVariant*);
+
+ // Calls setlocale(LC_ALL, ...) for a specified locale.
+ // Resets between tests.
+ void setPOSIXLocale(const CppArgumentList&, CppVariant*);
+
+ // Gets the value of the counter in the element specified by its ID.
+ void counterValueForElementById(const CppArgumentList&, CppVariant*);
+
+ // Gets the number of page where the specified element will be put.
+ void pageNumberForElementById(const CppArgumentList&, CppVariant*);
+
+ // Gets the number of pages to be printed.
+ void numberOfPages(const CppArgumentList&, CppVariant*);
+
+
+ // Allows layout tests to start Timeline profiling.
+ void setTimelineProfilingEnabled(const CppArgumentList&, CppVariant*);
+
+ // Allows layout tests to exec scripts at WebInspector side.
+ void evaluateInWebInspector(const CppArgumentList&, CppVariant*);
+
+ // Forces the selection colors for testing under Linux.
+ void forceRedSelectionColors(const CppArgumentList&, CppVariant*);
+
+ // Adds a user script to be injected into new documents.
+ void addUserScript(const CppArgumentList&, CppVariant*);
+
+public:
+ // The following methods are not exposed to JavaScript.
+ void setWorkQueueFrozen(bool frozen) { m_workQueue.setFrozen(frozen); }
+
+ bool shouldDumpAsText() { return m_dumpAsText; }
+ bool shouldDumpEditingCallbacks() { return m_dumpEditingCallbacks; }
+ bool shouldDumpFrameLoadCallbacks() { return m_dumpFrameLoadCallbacks; }
+ void setShouldDumpFrameLoadCallbacks(bool value) { m_dumpFrameLoadCallbacks = value; }
+ bool shouldDumpResourceLoadCallbacks() {return m_dumpResourceLoadCallbacks; }
+ bool shouldDumpStatusCallbacks() { return m_dumpWindowStatusChanges; }
+ bool shouldDumpSelectionRect() { return m_dumpSelectionRect; }
+ bool shouldDumpBackForwardList() { return m_dumpBackForwardList; }
+ bool shouldDumpTitleChanges() { return m_dumpTitleChanges; }
+ bool shouldDumpChildFrameScrollPositions() { return m_dumpChildFrameScrollPositions; }
+ bool shouldDumpChildFramesAsText() { return m_dumpChildFramesAsText; }
+ bool acceptsEditing() { return m_acceptsEditing; }
+ bool canOpenWindows() { return m_canOpenWindows; }
+ bool shouldAddFileToPasteboard() { return m_shouldAddFileToPasteboard; }
+ bool stopProvisionalFrameLoads() { return m_stopProvisionalFrameLoads; }
+
+ bool testRepaint() const { return m_testRepaint; }
+ bool sweepHorizontally() const { return m_sweepHorizontally; }
+
+ // Called by the webview delegate when the toplevel frame load is done.
+ void locationChangeDone();
+
+ // Called by the webview delegate when the policy delegate runs if the
+ // waitForPolicyDelegate was called.
+ void policyDelegateDone();
+
+ // Reinitializes all static values. The reset() method should be called
+ // before the start of each test (currently from
+ // TestShell::runFileTest).
+ void reset();
+
+ // A single item in the work queue.
+ class WorkItem {
+ public:
+ virtual ~WorkItem() {}
+
+ // Returns true if this started a load.
+ virtual bool run(TestShell* shell) = 0;
+ };
+
+private:
+ friend class WorkItem;
+ friend class WorkQueue;
+
+ // Helper class for managing events queued by methods like queueLoad or
+ // queueScript.
+ class WorkQueue {
+ public:
+ WorkQueue(LayoutTestController* controller) : m_controller(controller) {}
+ virtual ~WorkQueue();
+ void processWorkSoon();
+
+ // Reset the state of the class between tests.
+ void reset();
+
+ void addWork(WorkItem* work);
+
+ void setFrozen(bool frozen) { m_frozen = frozen; }
+ bool isEmpty() { return m_queue.isEmpty(); }
+
+ private:
+ void processWork();
+
+ base::OneShotTimer<WorkQueue> m_timer;
+ Deque<WorkItem*> m_queue;
+ bool m_frozen;
+ LayoutTestController* m_controller;
+ };
+
+ // Support for overridePreference.
+ bool cppVariantToBool(const CppVariant&);
+ int32_t cppVariantToInt32(const CppVariant&);
+ WebKit::WebString cppVariantToWebString(const CppVariant&);
+
+ void logErrorToConsole(const std::string&);
+ void completeNotifyDone(bool isTimeout);
+
+ bool pauseAnimationAtTimeOnElementWithId(const WebKit::WebString& animationName, double time, const WebKit::WebString& elementId);
+ bool pauseTransitionAtTimeOnElementWithId(const WebKit::WebString& propertyName, double time, const WebKit::WebString& elementId);
+ bool elementDoesAutoCompleteForElementWithId(const WebKit::WebString&);
+ int numberOfActiveAnimations();
+
+ // Used for test timeouts.
+ ScopedRunnableMethodFactory<LayoutTestController> m_timeoutFactory;
+
+ // Non-owning pointer. The LayoutTestController is owned by the host.
+ TestShell* m_shell;
+
+ // If true, the test_shell will produce a plain text dump rather than a
+ // text representation of the renderer.
+ bool m_dumpAsText;
+
+ // If true, the test_shell will write a descriptive line for each editing
+ // command.
+ bool m_dumpEditingCallbacks;
+
+ // If true, the test_shell will draw the bounds of the current selection rect
+ // taking possible transforms of the selection rect into account.
+ bool m_dumpSelectionRect;
+
+ // If true, the test_shell will output a descriptive line for each frame
+ // load callback.
+ bool m_dumpFrameLoadCallbacks;
+
+ // If true, the test_shell will output a descriptive line for each resource
+ // load callback.
+ bool m_dumpResourceLoadCallbacks;
+
+ // If true, the test_shell will produce a dump of the back forward list as
+ // well.
+ bool m_dumpBackForwardList;
+
+ // If true, the test_shell will print out the child frame scroll offsets as
+ // well.
+ bool m_dumpChildFrameScrollPositions;
+
+ // If true and if dump_as_text_ is true, the test_shell will recursively
+ // dump all frames as plain text.
+ bool m_dumpChildFramesAsText;
+
+ // If true, the test_shell will dump all changes to window.status.
+ bool m_dumpWindowStatusChanges;
+
+ // If true, output a message when the page title is changed.
+ bool m_dumpTitleChanges;
+
+ // If true, the element will be treated as editable. This value is returned
+ // from various editing callbacks that are called just before edit operations
+ // are allowed.
+ bool m_acceptsEditing;
+
+ // If true, new windows can be opened via javascript or by plugins. By
+ // default, set to false and can be toggled to true using
+ // setCanOpenWindows().
+ bool m_canOpenWindows;
+
+ // When reset is called, go through and close all but the main test shell
+ // window. By default, set to true but toggled to false using
+ // setCloseRemainingWindowsWhenComplete().
+ bool m_closeRemainingWindows;
+
+ // If true, pixel dump will be produced as a series of 1px-tall, view-wide
+ // individual paints over the height of the view.
+ bool m_testRepaint;
+ // If true and test_repaint_ is true as well, pixel dump will be produced as
+ // a series of 1px-wide, view-tall paints across the width of the view.
+ bool m_sweepHorizontally;
+
+ // If true and a drag starts, adds a file to the drag&drop clipboard.
+ bool m_shouldAddFileToPasteboard;
+
+ // If true, stops provisional frame loads during the
+ // DidStartProvisionalLoadForFrame callback.
+ bool m_stopProvisionalFrameLoads;
+
+ // If true, don't dump output until notifyDone is called.
+ bool m_waitUntilDone;
+
+ // To prevent infinite loops, only the first page of a test can add to a
+ // work queue (since we may well come back to that same page).
+ bool m_workQueueFrozen;
+
+ WorkQueue m_workQueue;
+
+ CppVariant m_globalFlag;
+
+ // Bound variable counting the number of top URLs visited.
+ CppVariant m_webHistoryItemCount;
+
+ WebKit::WebURL m_userStyleSheetLocation;
+};
+
+#endif // LayoutTestController_h
diff --git a/WebKitTools/DumpRenderTree/chromium/LayoutTestHelper.mm b/WebKitTools/DumpRenderTree/chromium/LayoutTestHelper.mm
new file mode 100644
index 0000000..e34cf5f
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/LayoutTestHelper.mm
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import <AppKit/AppKit.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+// This is a simple helper app that changes the color sync profile to the
+// generic profile and back when done. This program is managed by the layout
+// test script, so it can do the job for multiple DumpRenderTree while they are
+// running layout tests.
+
+static CMProfileRef userColorProfile = 0;
+
+static void saveCurrentColorProfile()
+{
+ CGDirectDisplayID displayID = CGMainDisplayID();
+ CMProfileRef previousProfile;
+ CMError error = CMGetProfileByAVID((UInt32)displayID, &previousProfile);
+ if (error) {
+ NSLog(@"failed to get the current color profile, pixmaps won't match. "
+ @"Error: %d", (int)error);
+ } else {
+ userColorProfile = previousProfile;
+ }
+}
+
+static void installLayoutTestColorProfile()
+{
+ // To make sure we get consistent colors (not dependent on the Main display),
+ // we force the generic rgb color profile. This cases a change the user can
+ // see.
+
+ CGDirectDisplayID displayID = CGMainDisplayID();
+ NSColorSpace* genericSpace = [NSColorSpace genericRGBColorSpace];
+ CMProfileRef genericProfile = (CMProfileRef)[genericSpace colorSyncProfile];
+ CMError error = CMSetProfileByAVID((UInt32)displayID, genericProfile);
+ if (error) {
+ NSLog(@"failed install the generic color profile, pixmaps won't match. "
+ @"Error: %d", (int)error);
+ }
+}
+
+static void restoreUserColorProfile(void)
+{
+ if (!userColorProfile)
+ return;
+ CGDirectDisplayID displayID = CGMainDisplayID();
+ CMError error = CMSetProfileByAVID((UInt32)displayID, userColorProfile);
+ CMCloseProfile(userColorProfile);
+ if (error) {
+ NSLog(@"Failed to restore color profile, use System Preferences -> "
+ @"Displays -> Color to reset. Error: %d", (int)error);
+ }
+ userColorProfile = 0;
+}
+
+static void simpleSignalHandler(int sig)
+{
+ // Try to restore the color profile and try to go down cleanly
+ restoreUserColorProfile();
+ exit(128 + sig);
+}
+
+int main(int argc, char* argv[])
+{
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+
+ // Hooks the ways we might get told to clean up...
+ signal(SIGINT, simpleSignalHandler);
+ signal(SIGHUP, simpleSignalHandler);
+ signal(SIGTERM, simpleSignalHandler);
+
+ // Save off the current profile, and then install the layout test profile.
+ saveCurrentColorProfile();
+ installLayoutTestColorProfile();
+
+ // Let the script know we're ready
+ printf("ready\n");
+ fflush(stdout);
+
+ // Wait for any key (or signal)
+ getchar();
+
+ // Restore the profile
+ restoreUserColorProfile();
+
+ [pool release];
+ return 0;
+}
diff --git a/WebKitTools/DumpRenderTree/chromium/MockSpellCheck.cpp b/WebKitTools/DumpRenderTree/chromium/MockSpellCheck.cpp
new file mode 100644
index 0000000..fe70cab
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/MockSpellCheck.cpp
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "MockSpellCheck.h"
+
+#include "public/WebString.h"
+#include <wtf/ASCIICType.h>
+#include <wtf/Assertions.h>
+
+using namespace WebCore;
+using namespace WebKit;
+
+MockSpellCheck::MockSpellCheck()
+ : m_initialized(false) {}
+
+MockSpellCheck::~MockSpellCheck() {}
+
+static bool isNotASCIIAlpha(UChar ch) { return !isASCIIAlpha(ch); }
+
+bool MockSpellCheck::spellCheckWord(const WebString& text, int* misspelledOffset, int* misspelledLength)
+{
+ ASSERT(misspelledOffset);
+ ASSERT(misspelledLength);
+
+ // Initialize this spellchecker.
+ initializeIfNeeded();
+
+ // Reset the result values as our spellchecker does.
+ *misspelledOffset = 0;
+ *misspelledLength = 0;
+
+ // Convert to a String because we store String instances in
+ // m_misspelledWords and WebString has no find().
+ const String stringText(text.data(), text.length());
+
+ // Extract the first possible English word from the given string.
+ // The given string may include non-ASCII characters or numbers. So, we
+ // should filter out such characters before start looking up our
+ // misspelled-word table.
+ // (This is a simple version of our SpellCheckWordIterator class.)
+ // If the given string doesn't include any ASCII characters, we can treat the
+ // string as valid one.
+ // Unfortunately, This implementation splits a contraction, i.e. "isn't" is
+ // split into two pieces "isn" and "t". This is OK because webkit tests
+ // don't have misspelled contractions.
+ int wordOffset = stringText.find(isASCIIAlpha);
+ if (wordOffset == -1)
+ return true;
+ int wordEnd = stringText.find(isNotASCIIAlpha, wordOffset);
+ int wordLength = wordEnd == -1 ? stringText.length() - wordOffset : wordEnd - wordOffset;
+
+ // Look up our misspelled-word table to check if the extracted word is a
+ // known misspelled word, and return the offset and the length of the
+ // extracted word if this word is a known misspelled word.
+ // (See the comment in MockSpellCheck::initializeIfNeeded() why we use a
+ // misspelled-word table.)
+ String word = stringText.substring(wordOffset, wordLength);
+ if (!m_misspelledWords.contains(word))
+ return true;
+
+ *misspelledOffset = wordOffset;
+ *misspelledLength = wordLength;
+ return false;
+}
+
+bool MockSpellCheck::initializeIfNeeded()
+{
+ // Exit if we have already initialized this object.
+ if (m_initialized)
+ return false;
+
+ // Create a table that consists of misspelled words used in WebKit layout
+ // tests.
+ // Since WebKit layout tests don't have so many misspelled words as
+ // well-spelled words, it is easier to compare the given word with misspelled
+ // ones than to compare with well-spelled ones.
+ static const char* misspelledWords[] = {
+ // These words are known misspelled words in webkit tests.
+ // If there are other misspelled words in webkit tests, please add them in
+ // this array.
+ "foo",
+ "Foo",
+ "baz",
+ "fo",
+ "LibertyF",
+ "chello",
+ "xxxtestxxx",
+ "XXxxx",
+ "Textx",
+ "blockquoted",
+ "asd",
+ "Lorem",
+ "Nunc",
+ "Curabitur",
+ "eu",
+ "adlj",
+ "adaasj",
+ "sdklj",
+ "jlkds",
+ "jsaada",
+ "jlda",
+ "zz",
+ "contentEditable",
+ // The following words are used by unit tests.
+ "ifmmp",
+ "qwertyuiopasd",
+ "qwertyuiopasdf",
+ };
+
+ m_misspelledWords.clear();
+ for (size_t i = 0; i < arraysize(misspelledWords); ++i)
+ m_misspelledWords.add(String::fromUTF8(misspelledWords[i]), false);
+
+ // Mark as initialized to prevent this object from being initialized twice
+ // or more.
+ m_initialized = true;
+
+ // Since this MockSpellCheck class doesn't download dictionaries, this
+ // function always returns false.
+ return false;
+}
diff --git a/WebKitTools/DumpRenderTree/chromium/MockSpellCheck.h b/WebKitTools/DumpRenderTree/chromium/MockSpellCheck.h
new file mode 100644
index 0000000..8c2ba92
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/MockSpellCheck.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MockSpellCheck_h
+#define MockSpellCheck_h
+
+#include <wtf/HashMap.h>
+#include <wtf/text/StringHash.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebKit {
+class WebString;
+}
+
+// A mock implementation of a spell-checker used for WebKit tests.
+// This class only implements the minimal functionarities required by WebKit
+// tests, i.e. this class just compares the given string with known misspelled
+// words in webkit tests and mark them as missspelled.
+// Even though this is sufficent for webkit tests, this class is not suitable
+// for any other usages.
+class MockSpellCheck {
+public:
+ MockSpellCheck();
+ ~MockSpellCheck();
+
+ // Checks the spellings of the specified text.
+ // This function returns true if the text consists of valid words, and
+ // returns false if it includes invalid words.
+ // When the given text includes invalid words, this function sets the
+ // position of the first invalid word to misspelledOffset, and the length of
+ // the first invalid word to misspelledLength, respectively.
+ // For example, when the given text is " zz zz", this function sets 3 to
+ // misspelledOffset and 2 to misspelledLength, respectively.
+ bool spellCheckWord(const WebKit::WebString& text,
+ int* misspelledOffset,
+ int* misspelledLength);
+
+private:
+ // Initialize the internal resources if we need to initialize it.
+ // Initializing this object may take long time. To prevent from hurting
+ // the performance of test_shell, we initialize this object when
+ // SpellCheckWord() is called for the first time.
+ // To be compliant with SpellCheck:InitializeIfNeeded(), this function
+ // returns true if this object is downloading a dictionary, otherwise
+ // it returns false.
+ bool initializeIfNeeded();
+
+ // A table that consists of misspelled words.
+ HashMap<WebCore::String, bool> m_misspelledWords;
+
+ // A flag representing whether or not this object is initialized.
+ bool m_initialized;
+};
+
+#endif // MockSpellCheck_h
diff --git a/WebKitTools/DumpRenderTree/chromium/PlainTextController.cpp b/WebKitTools/DumpRenderTree/chromium/PlainTextController.cpp
new file mode 100644
index 0000000..6e6cf11
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/PlainTextController.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2009 Pawel Hajdan (phajdan.jr@chromium.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "PlainTextController.h"
+
+#include "TestShell.h"
+#include "public/WebBindings.h"
+#include "public/WebRange.h"
+#include "public/WebString.h"
+
+using namespace WebKit;
+
+PlainTextController::PlainTextController()
+{
+ // Initialize the map that associates methods of this class with the names
+ // they will use when called by JavaScript. The actual binding of those
+ // names to their methods will be done by calling bindToJavaScript() (defined
+ // by CppBoundClass, the parent to PlainTextController).
+ bindMethod("plainText", &PlainTextController::plainText);
+
+ // The fallback method is called when an unknown method is invoked.
+ bindFallbackMethod(&PlainTextController::fallbackMethod);
+}
+
+void PlainTextController::plainText(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ if (arguments.size() < 1 || !arguments[0].isObject())
+ return;
+
+ // Check that passed-in object is, in fact, a range.
+ NPObject* npobject = NPVARIANT_TO_OBJECT(arguments[0]);
+ if (!npobject)
+ return;
+ WebRange range;
+ if (!WebBindings::getRange(npobject, &range))
+ return;
+
+ // Extract the text using the Range's text() method
+ WebString text = range.toPlainText();
+ result->set(text.utf8());
+}
+
+void PlainTextController::fallbackMethod(const CppArgumentList&, CppVariant* result)
+{
+ printf("CONSOLE MESSAGE: JavaScript ERROR: unknown method called on PlainTextController\n");
+ result->setNull();
+}
+
diff --git a/WebKitTools/DumpRenderTree/chromium/PlainTextController.h b/WebKitTools/DumpRenderTree/chromium/PlainTextController.h
new file mode 100644
index 0000000..3d3a04c
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/PlainTextController.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PlainTextController_h
+#define PlainTextController_h
+
+#include "CppBoundClass.h"
+
+class TestShell;
+
+class PlainTextController : public CppBoundClass {
+public:
+ // Builds the property and method lists needed to bind this class to a JS
+ // object.
+ explicit PlainTextController();
+
+ // JS callback methods.
+ void plainText(const CppArgumentList&, CppVariant*);
+
+ // Fall-back method: called if an unknown method is invoked.
+ void fallbackMethod(const CppArgumentList&, CppVariant*);
+};
+
+#endif // PlainTextController_h
+
diff --git a/WebKitTools/DumpRenderTree/chromium/TestNavigationController.cpp b/WebKitTools/DumpRenderTree/chromium/TestNavigationController.cpp
new file mode 100644
index 0000000..8b4f954
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/TestNavigationController.cpp
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "TestNavigationController.h"
+
+#include "TestShell.h"
+#include <wtf/Assertions.h>
+
+using namespace WebKit;
+using namespace std;
+
+// ----------------------------------------------------------------------------
+// TestNavigationEntry
+
+TestNavigationEntry::TestNavigationEntry()
+ : m_pageID(-1) {}
+
+TestNavigationEntry::TestNavigationEntry(
+ int pageID, const WebURL& url, const WebString& title, const WebString& targetFrame)
+ : m_pageID(pageID)
+ , m_url(url)
+ , m_title(title)
+ , m_targetFrame(targetFrame) {}
+
+TestNavigationEntry::~TestNavigationEntry() {}
+
+void TestNavigationEntry::setContentState(const WebHistoryItem& state)
+{
+ m_state = state;
+}
+
+// ----------------------------------------------------------------------------
+// TestNavigationController
+
+TestNavigationController::TestNavigationController(NavigationHost* host)
+ : m_pendingEntry(0)
+ , m_lastCommittedEntryIndex(-1)
+ , m_pendingEntryIndex(-1)
+ , m_host(host)
+ , m_maxPageID(-1) {}
+
+TestNavigationController::~TestNavigationController()
+{
+ discardPendingEntry();
+}
+
+void TestNavigationController::reset()
+{
+ m_entries.clear();
+ discardPendingEntry();
+
+ m_lastCommittedEntryIndex = -1;
+}
+
+void TestNavigationController::reload()
+{
+ // Base the navigation on where we are now...
+ int currentIndex = currentEntryIndex();
+
+ // If we are no where, then we can't reload. TODO(darin): We should add a
+ // CanReload method.
+ if (currentIndex == -1)
+ return;
+
+ discardPendingEntry();
+
+ m_pendingEntryIndex = currentIndex;
+ navigateToPendingEntry(true);
+}
+
+void TestNavigationController::goToOffset(int offset)
+{
+ int index = m_lastCommittedEntryIndex + offset;
+ if (index < 0 || index >= entryCount())
+ return;
+
+ goToIndex(index);
+}
+
+void TestNavigationController::goToIndex(int index)
+{
+ ASSERT(index >= 0);
+ ASSERT(index < static_cast<int>(m_entries.size()));
+
+ discardPendingEntry();
+
+ m_pendingEntryIndex = index;
+ navigateToPendingEntry(false);
+}
+
+void TestNavigationController::loadEntry(TestNavigationEntry* entry)
+{
+ // When navigating to a new page, we don't know for sure if we will actually
+ // end up leaving the current page. The new page load could for example
+ // result in a download or a 'no content' response (e.g., a mailto: URL).
+ discardPendingEntry();
+ m_pendingEntry = entry;
+ navigateToPendingEntry(false);
+}
+
+
+TestNavigationEntry* TestNavigationController::lastCommittedEntry() const
+{
+ if (m_lastCommittedEntryIndex == -1)
+ return 0;
+ return m_entries[m_lastCommittedEntryIndex].get();
+}
+
+TestNavigationEntry* TestNavigationController::activeEntry() const
+{
+ TestNavigationEntry* entry = m_pendingEntry;
+ if (!entry)
+ entry = lastCommittedEntry();
+ return entry;
+}
+
+int TestNavigationController::currentEntryIndex() const
+{
+ if (m_pendingEntryIndex != -1)
+ return m_pendingEntryIndex;
+ return m_lastCommittedEntryIndex;
+}
+
+
+TestNavigationEntry* TestNavigationController::entryAtIndex(int index) const
+{
+ if (index < 0 || index >= entryCount())
+ return 0;
+ return m_entries[index].get();
+}
+
+TestNavigationEntry* TestNavigationController::entryWithPageID(int32_t pageID) const
+{
+ int index = entryIndexWithPageID(pageID);
+ return (index != -1) ? m_entries[index].get() : 0;
+}
+
+void TestNavigationController::didNavigateToEntry(TestNavigationEntry* entry)
+{
+ // If the entry is that of a page with PageID larger than any this Tab has
+ // seen before, then consider it a new navigation.
+ if (entry->pageID() > maxPageID()) {
+ insertEntry(entry);
+ return;
+ }
+
+ // Otherwise, we just need to update an existing entry with matching PageID.
+ // If the existing entry corresponds to the entry which is pending, then we
+ // must update the current entry index accordingly. When navigating to the
+ // same URL, a new PageID is not created.
+
+ int existingEntryIndex = entryIndexWithPageID(entry->pageID());
+ TestNavigationEntry* existingEntry = (existingEntryIndex != -1) ?
+ m_entries[existingEntryIndex].get() : 0;
+ if (!existingEntry) {
+ // No existing entry, then simply ignore this navigation!
+ } else if (existingEntry == m_pendingEntry) {
+ // The given entry might provide a new URL... e.g., navigating back to a
+ // page in session history could have resulted in a new client redirect.
+ existingEntry->setURL(entry->URL());
+ existingEntry->setContentState(entry->contentState());
+ m_lastCommittedEntryIndex = m_pendingEntryIndex;
+ m_pendingEntryIndex = -1;
+ m_pendingEntry = 0;
+ } else if (m_pendingEntry && m_pendingEntry->pageID() == -1
+ && GURL(m_pendingEntry->URL()) == GURL(existingEntry->URL().spec())) {
+ // Not a new navigation
+ discardPendingEntry();
+ } else {
+ // The given entry might provide a new URL... e.g., navigating to a page
+ // might result in a client redirect, which should override the URL of the
+ // existing entry.
+ existingEntry->setURL(entry->URL());
+ existingEntry->setContentState(entry->contentState());
+
+ // The navigation could have been issued by the renderer, so be sure that
+ // we update our current index.
+ m_lastCommittedEntryIndex = existingEntryIndex;
+ }
+
+ delete entry;
+ updateMaxPageID();
+}
+
+void TestNavigationController::discardPendingEntry()
+{
+ if (m_pendingEntryIndex == -1)
+ delete m_pendingEntry;
+ m_pendingEntry = 0;
+ m_pendingEntryIndex = -1;
+}
+
+void TestNavigationController::insertEntry(TestNavigationEntry* entry)
+{
+ discardPendingEntry();
+
+ // Prune any entry which are in front of the current entry
+ int currentSize = static_cast<int>(m_entries.size());
+ if (currentSize > 0) {
+ while (m_lastCommittedEntryIndex < (currentSize - 1)) {
+ m_entries.removeLast();
+ currentSize--;
+ }
+ }
+
+ m_entries.append(linked_ptr<TestNavigationEntry>(entry));
+ m_lastCommittedEntryIndex = static_cast<int>(m_entries.size()) - 1;
+ updateMaxPageID();
+}
+
+int TestNavigationController::entryIndexWithPageID(int32 pageID) const
+{
+ for (int i = static_cast<int>(m_entries.size()) - 1; i >= 0; --i) {
+ if (m_entries[i]->pageID() == pageID)
+ return i;
+ }
+ return -1;
+}
+
+void TestNavigationController::navigateToPendingEntry(bool reload)
+{
+ // For session history navigations only the pending_entry_index_ is set.
+ if (!m_pendingEntry) {
+ ASSERT(m_pendingEntryIndex != -1);
+ m_pendingEntry = m_entries[m_pendingEntryIndex].get();
+ }
+
+ if (m_host->navigate(*m_pendingEntry, reload)) {
+ // Note: this is redundant if navigation completed synchronously because
+ // DidNavigateToEntry call this as well.
+ updateMaxPageID();
+ } else
+ discardPendingEntry();
+}
+
+void TestNavigationController::updateMaxPageID()
+{
+ TestNavigationEntry* entry = activeEntry();
+ if (entry)
+ m_maxPageID = max(m_maxPageID, entry->pageID());
+}
diff --git a/WebKitTools/DumpRenderTree/chromium/TestNavigationController.h b/WebKitTools/DumpRenderTree/chromium/TestNavigationController.h
new file mode 100644
index 0000000..bd3c2f4
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/TestNavigationController.h
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TestNavigationController_h
+#define TestNavigationController_h
+
+#include "base/basictypes.h"
+#include "base/linked_ptr.h"
+#include "public/WebDataSource.h"
+#include "public/WebHistoryItem.h"
+#include "public/WebString.h"
+#include "public/WebURL.h"
+#include <string>
+#include <wtf/Vector.h>
+
+// Associated with browser-initated navigations to hold tracking data.
+class TestShellExtraData : public WebKit::WebDataSource::ExtraData {
+public:
+ TestShellExtraData(int32_t pendingPageID)
+ : pendingPageID(pendingPageID)
+ , requestCommitted(false) {}
+
+ // Contains the page_id for this navigation or -1 if there is none yet.
+ int32_t pendingPageID;
+
+ // True if we have already processed the "DidCommitLoad" event for this
+ // request. Used by session history.
+ bool requestCommitted;
+};
+
+// Stores one back/forward navigation state for the test shell.
+class TestNavigationEntry: public Noncopyable {
+public:
+ TestNavigationEntry();
+ TestNavigationEntry(int pageID,
+ const WebKit::WebURL&,
+ const WebKit::WebString& title,
+ const WebKit::WebString& targetFrame);
+
+ // Virtual to allow test_shell to extend the class.
+ ~TestNavigationEntry();
+
+ // Set / Get the URI
+ void setURL(const WebKit::WebURL& url) { m_url = url; }
+ const WebKit::WebURL& URL() const { return m_url; }
+
+ // Set / Get the title
+ void setTitle(const WebKit::WebString& title) { m_title = title; }
+ const WebKit::WebString& title() const { return m_title; }
+
+ // Set / Get a state.
+ void setContentState(const WebKit::WebHistoryItem&);
+ const WebKit::WebHistoryItem& contentState() const { return m_state; }
+
+ // Get the page id corresponding to the tab's state.
+ void setPageID(int pageID) { m_pageID = pageID; }
+ int32_t pageID() const { return m_pageID; }
+
+ const WebKit::WebString& targetFrame() const { return m_targetFrame; }
+
+private:
+ // Describes the current page that the tab represents. This is not relevant
+ // for all tab contents types.
+ int32_t m_pageID;
+
+ WebKit::WebURL m_url;
+ WebKit::WebString m_title;
+ WebKit::WebHistoryItem m_state;
+ WebKit::WebString m_targetFrame;
+};
+
+class NavigationHost {
+public:
+ virtual bool navigate(const TestNavigationEntry&, bool reload) = 0;
+};
+
+// Test shell's NavigationController. The goal is to be as close to the Chrome
+// version as possible.
+class TestNavigationController: public Noncopyable {
+public:
+ TestNavigationController(NavigationHost*);
+ ~TestNavigationController();
+
+ void reset();
+
+ // Causes the controller to reload the current (or pending) entry.
+ void reload();
+
+ // Causes the controller to go to the specified offset from current. Does
+ // nothing if out of bounds.
+ void goToOffset(int);
+
+ // Causes the controller to go to the specified index.
+ void goToIndex(int);
+
+ // Causes the controller to load the specified entry. The controller
+ // assumes ownership of the entry.
+ // NOTE: Do not pass an entry that the controller already owns!
+ void loadEntry(TestNavigationEntry*);
+
+ // Returns the last committed entry, which may be null if there are no
+ // committed entries.
+ TestNavigationEntry* lastCommittedEntry() const;
+
+ // Returns the number of entries in the NavigationControllerBase, excluding
+ // the pending entry if there is one.
+ int entryCount() const { return static_cast<int>(m_entries.size()); }
+
+ // Returns the active entry, which is the pending entry if a navigation is in
+ // progress or the last committed entry otherwise. NOTE: This can be 0!!
+ //
+ // If you are trying to get the current state of the NavigationControllerBase,
+ // this is the method you will typically want to call.
+ TestNavigationEntry* activeEntry() const;
+
+ // Returns the index from which we would go back/forward or reload. This is
+ // the m_lastCommittedEntryIndex if m_pendingEntryIndex is -1. Otherwise,
+ // it is the m_pendingEntryIndex.
+ int currentEntryIndex() const;
+
+ // Returns the entry at the specified index. Returns 0 if out of
+ // bounds.
+ TestNavigationEntry* entryAtIndex(int) const;
+
+ // Return the entry with the corresponding type and page ID, or 0 if
+ // not found.
+ TestNavigationEntry* entryWithPageID(int32_t) const;
+
+ // Returns the index of the last committed entry.
+ int lastCommittedEntryIndex() const { return m_lastCommittedEntryIndex; }
+
+ // Used to inform us of a navigation being committed for a tab. We will take
+ // ownership of the entry. Any entry located forward to the current entry will
+ // be deleted. The new entry becomes the current entry.
+ void didNavigateToEntry(TestNavigationEntry*);
+
+ // Used to inform us to discard its pending entry.
+ void discardPendingEntry();
+
+private:
+ // Inserts an entry after the current position, removing all entries after it.
+ // The new entry will become the active one.
+ void insertEntry(TestNavigationEntry*);
+
+ int maxPageID() const { return m_maxPageID; }
+ void navigateToPendingEntry(bool reload);
+
+ // Return the index of the entry with the corresponding type and page ID,
+ // or -1 if not found.
+ int entryIndexWithPageID(int32_t) const;
+
+ // Updates the max page ID with that of the given entry, if is larger.
+ void updateMaxPageID();
+
+ // List of NavigationEntry for this tab
+ typedef Vector<linked_ptr<TestNavigationEntry> > NavigationEntryList;
+ typedef NavigationEntryList::iterator NavigationEntryListIterator;
+ NavigationEntryList m_entries;
+
+ // An entry we haven't gotten a response for yet. This will be discarded
+ // when we navigate again. It's used only so we know what the currently
+ // displayed tab is.
+ TestNavigationEntry* m_pendingEntry;
+
+ // currently visible entry
+ int m_lastCommittedEntryIndex;
+
+ // index of pending entry if it is in entries_, or -1 if pending_entry_ is a
+ // new entry (created by LoadURL).
+ int m_pendingEntryIndex;
+
+ NavigationHost* m_host;
+ int m_maxPageID;
+};
+
+#endif // TestNavigationController_h
+
diff --git a/WebKitTools/DumpRenderTree/chromium/TestShell.cpp b/WebKitTools/DumpRenderTree/chromium/TestShell.cpp
new file mode 100644
index 0000000..d2bc110
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/TestShell.cpp
@@ -0,0 +1,614 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "TestShell.h"
+
+#include "LayoutTestController.h"
+#include "WebViewHost.h"
+#include "base/md5.h" // FIXME: Wrap by webkit_support.
+#include "base/string16.h"
+#include "gfx/codec/png_codec.h" // FIXME: Remove dependecy. WebCore/platform/image-encoder is better?
+#include "net/base/escape.h" // FIXME: Remove dependency.
+#include "public/WebDataSource.h"
+#include "public/WebDocument.h"
+#include "public/WebElement.h"
+#include "public/WebFrame.h"
+#include "public/WebHistoryItem.h"
+#include "public/WebRuntimeFeatures.h"
+#include "public/WebScriptController.h"
+#include "public/WebSettings.h"
+#include "public/WebSize.h"
+#include "public/WebString.h"
+#include "public/WebURLRequest.h"
+#include "public/WebURLResponse.h"
+#include "public/WebView.h"
+#include "skia/ext/bitmap_platform_device.h"
+#include "skia/ext/platform_canvas.h"
+#include "webkit/support/webkit_support.h"
+#include <algorithm>
+#include <cctype>
+#include <vector>
+
+using namespace WebKit;
+using namespace std;
+
+// Content area size for newly created windows.
+static const int testWindowWidth = 800;
+static const int testWindowHeight = 600;
+
+// The W3C SVG layout tests use a different size than the other layout tests.
+static const int SVGTestWindowWidth = 480;
+static const int SVGTestWindowHeight = 360;
+
+static const char layoutTestsPattern[] = "/LayoutTests/";
+static const string::size_type layoutTestsPatternSize = sizeof(layoutTestsPattern) - 1;
+static const char fileUrlPattern[] = "file:/";
+static const char fileTestPrefix[] = "(file test):";
+static const char dataUrlPattern[] = "data:";
+static const string::size_type dataUrlPatternSize = sizeof(dataUrlPattern) - 1;
+
+TestShell::TestShell()
+ : m_testIsPending(false)
+ , m_testIsPreparing(false)
+ , m_focusedWidget(0)
+{
+ m_accessibilityController.set(new AccessibilityController(this));
+ m_layoutTestController.set(new LayoutTestController(this));
+ m_eventSender.set(new EventSender(this));
+ m_plainTextController.set(new PlainTextController());
+ m_textInputController.set(new TextInputController(this));
+
+ m_webViewHost = createWebView();
+ m_webView = m_webViewHost->webView();
+}
+
+TestShell::~TestShell()
+{
+ loadURL(GURL("about:blank"));
+ // Call GC twice to clean up garbage.
+ callJSGC();
+ callJSGC();
+
+ // Destroy the WebView before its WebViewHost.
+ m_webView->close();
+}
+
+void TestShell::resetWebSettings(WebView& webView)
+{
+ // Match the settings used by Mac DumpRenderTree, with the exception of
+ // fonts.
+ WebSettings* settings = webView.settings();
+#if OS(MAC_OS_X)
+ WebString serif = WebString::fromUTF8("Times");
+ settings->setCursiveFontFamily(WebString::fromUTF8("Apple Chancery"));
+ settings->setFantasyFontFamily(WebString::fromUTF8("Papyrus"));
+#else
+ // NOTE: case matters here, this must be 'times new roman', else
+ // some layout tests fail.
+ WebString serif = WebString::fromUTF8("times new roman");
+
+ // These two fonts are picked from the intersection of
+ // Win XP font list and Vista font list :
+ // http://www.microsoft.com/typography/fonts/winxp.htm
+ // http://blogs.msdn.com/michkap/archive/2006/04/04/567881.aspx
+ // Some of them are installed only with CJK and complex script
+ // support enabled on Windows XP and are out of consideration here.
+ // (although we enabled both on our buildbots.)
+ // They (especially Impact for fantasy) are not typical cursive
+ // and fantasy fonts, but it should not matter for layout tests
+ // as long as they're available.
+ settings->setCursiveFontFamily(WebString::fromUTF8("Comic Sans MS"));
+ settings->setFantasyFontFamily(WebString::fromUTF8("Impact"));
+#endif
+ settings->setSerifFontFamily(serif);
+ settings->setStandardFontFamily(serif);
+ settings->setFixedFontFamily(WebString::fromUTF8("Courier"));
+
+ settings->setDefaultTextEncodingName(WebString::fromUTF8("ISO-8859-1"));
+ settings->setDefaultFontSize(16);
+ settings->setDefaultFixedFontSize(13);
+ settings->setMinimumFontSize(1);
+ settings->setMinimumLogicalFontSize(9);
+ settings->setJavaScriptCanOpenWindowsAutomatically(true);
+ settings->setDOMPasteAllowed(true);
+ settings->setDeveloperExtrasEnabled(false);
+ settings->setNeedsSiteSpecificQuirks(true);
+ settings->setShrinksStandaloneImagesToFit(false);
+ settings->setUsesEncodingDetector(false);
+ settings->setTextAreasAreResizable(false);
+ settings->setJavaEnabled(false);
+ settings->setAllowScriptsToCloseWindows(false);
+ settings->setXSSAuditorEnabled(false);
+ settings->setDownloadableBinaryFontsEnabled(true);
+ settings->setLocalStorageEnabled(true);
+ settings->setOfflineWebApplicationCacheEnabled(true);
+ settings->setAllowFileAccessFromFileURLs(true);
+
+ // LayoutTests were written with Safari Mac in mind which does not allow
+ // tabbing to links by default.
+ webView.setTabsToLinks(false);
+
+ // Allow those layout tests running as local files, i.e. under
+ // LayoutTests/http/tests/local, to access http server.
+ settings->setAllowUniversalAccessFromFileURLs(true);
+
+ settings->setJavaScriptEnabled(true);
+ settings->setPluginsEnabled(true);
+ settings->setWebSecurityEnabled(true);
+ settings->setEditableLinkBehaviorNeverLive();
+ settings->setFontRenderingModeNormal();
+ settings->setShouldPaintCustomScrollbars(true);
+ settings->setTextDirectionSubmenuInclusionBehaviorNeverIncluded();
+
+ settings->setLoadsImagesAutomatically(true);
+ settings->setImagesEnabled(true);
+}
+
+void TestShell::runFileTest(const TestParams& params)
+{
+ m_testIsPreparing = true;
+ m_params = params;
+ string testUrl = m_params.testUrl.spec();
+
+ bool inspectorTestMode = testUrl.find("/inspector/") != string::npos
+ || testUrl.find("\\inspector\\") != string::npos;
+ m_webView->settings()->setDeveloperExtrasEnabled(inspectorTestMode);
+ loadURL(m_params.testUrl);
+
+ m_testIsPreparing = false;
+ waitTestFinished();
+}
+
+static inline bool isSVGTestURL(const WebURL& url)
+{
+ return url.isValid() && string(url.spec()).find("W3C-SVG-1.1") != string::npos;
+}
+
+void TestShell::resizeWindowForTest(WebViewHost* window, const WebURL& url)
+{
+ int width, height;
+ if (isSVGTestURL(url)) {
+ width = SVGTestWindowWidth;
+ height = SVGTestWindowHeight;
+ } else {
+ width = testWindowWidth;
+ height = testWindowHeight;
+ }
+ window->setWindowRect(WebRect(0, 0, width + virtualWindowBorder * 2, height + virtualWindowBorder * 2));
+}
+
+void TestShell::resetTestController()
+{
+ m_accessibilityController->reset();
+ m_layoutTestController->reset();
+ m_eventSender->reset();
+ m_webViewHost->reset();
+}
+
+void TestShell::loadURL(const WebURL& url)
+{
+ m_webViewHost->loadURLForFrame(url, WebString());
+}
+
+void TestShell::reload()
+{
+ m_webViewHost->navigationController()->reload();
+}
+
+void TestShell::goToOffset(int offset)
+{
+ m_webViewHost->navigationController()->goToOffset(offset);
+}
+
+int TestShell::navigationEntryCount() const
+{
+ return m_webViewHost->navigationController()->entryCount();
+}
+
+void TestShell::callJSGC()
+{
+ m_webView->mainFrame()->collectGarbage();
+}
+
+void TestShell::setFocus(WebWidget* widget, bool enable)
+{
+ // Simulate the effects of InteractiveSetFocus(), which includes calling
+ // both setFocus() and setIsActive().
+ if (enable) {
+ if (m_focusedWidget != widget) {
+ if (m_focusedWidget)
+ m_focusedWidget->setFocus(false);
+ webView()->setIsActive(enable);
+ widget->setFocus(enable);
+ m_focusedWidget = widget;
+ }
+ } else {
+ if (m_focusedWidget == widget) {
+ widget->setFocus(enable);
+ webView()->setIsActive(enable);
+ m_focusedWidget = 0;
+ }
+ }
+}
+
+void TestShell::testFinished()
+{
+ if (!m_testIsPending)
+ return;
+ m_testIsPending = false;
+ dump();
+ webkit_support::QuitMessageLoop();
+}
+
+void TestShell::testTimedOut()
+{
+ fprintf(stderr, "FAIL: Timed out waiting for notifyDone to be called\n");
+ fprintf(stdout, "FAIL: Timed out waiting for notifyDone to be called\n");
+ testFinished();
+}
+
+static string dumpDocumentText(WebFrame* frame)
+{
+ // We use the document element's text instead of the body text here because
+ // not all documents have a body, such as XML documents.
+ WebElement documentElement = frame->document().documentElement();
+ if (documentElement.isNull())
+ return string();
+ return documentElement.innerText().utf8();
+}
+
+static string dumpFramesAsText(WebFrame* frame, bool recursive)
+{
+ string result;
+
+ // Add header for all but the main frame. Skip empty frames.
+ if (frame->parent() && !frame->document().documentElement().isNull()) {
+ result.append("\n--------\nFrame: '");
+ result.append(frame->name().utf8().data());
+ result.append("'\n--------\n");
+ }
+
+ result.append(dumpDocumentText(frame));
+ result.append("\n");
+
+ if (recursive) {
+ for (WebFrame* child = frame->firstChild(); child; child = child->nextSibling())
+ result.append(dumpFramesAsText(child, recursive));
+ }
+
+ return result;
+}
+
+static void dumpFrameScrollPosition(WebFrame* frame, bool recursive)
+{
+ WebSize offset = frame->scrollOffset();
+ if (offset.width > 0 || offset.height > 0) {
+ if (frame->parent())
+ printf("frame '%s' ", frame->name().utf8().data());
+ printf("scrolled to %d,%d\n", offset.width, offset.height);
+ }
+
+ if (!recursive)
+ return;
+ for (WebFrame* child = frame->firstChild(); child; child = child->nextSibling())
+ dumpFrameScrollPosition(child, recursive);
+}
+
+struct ToLower {
+ char16 operator()(char16 c) { return tolower(c); }
+};
+
+// FIXME: Eliminate std::transform(), std::vector, and std::sort().
+
+// Returns True if item1 < item2.
+static bool HistoryItemCompareLess(const WebHistoryItem& item1, const WebHistoryItem& item2)
+{
+ string16 target1 = item1.target();
+ string16 target2 = item2.target();
+ std::transform(target1.begin(), target1.end(), target1.begin(), ToLower());
+ std::transform(target2.begin(), target2.end(), target2.begin(), ToLower());
+ return target1 < target2;
+}
+
+static string dumpHistoryItem(const WebHistoryItem& item, int indent, bool isCurrent)
+{
+ string result;
+
+ if (isCurrent) {
+ result.append("curr->");
+ result.append(indent - 6, ' '); // 6 == "curr->".length()
+ } else {
+ result.append(indent, ' ');
+ }
+
+ string url = item.urlString().utf8();
+ size_t pos;
+ if (!url.find(fileUrlPattern) && ((pos = url.find(layoutTestsPattern)) != string::npos)) {
+ // adjust file URLs to match upstream results.
+ url.replace(0, pos + layoutTestsPatternSize, fileTestPrefix);
+ } else if (!url.find(dataUrlPattern)) {
+ // URL-escape data URLs to match results upstream.
+ string path = EscapePath(url.substr(dataUrlPatternSize));
+ url.replace(dataUrlPatternSize, url.length(), path);
+ }
+
+ result.append(url);
+ if (!item.target().isEmpty()) {
+ result.append(" (in frame \"");
+ result.append(item.target().utf8());
+ result.append("\")");
+ }
+ if (item.isTargetItem())
+ result.append(" **nav target**");
+ result.append("\n");
+
+ const WebVector<WebHistoryItem>& children = item.children();
+ if (!children.isEmpty()) {
+ // Must sort to eliminate arbitrary result ordering which defeats
+ // reproducible testing.
+ // FIXME: WebVector should probably just be a std::vector!!
+ std::vector<WebHistoryItem> sortedChildren;
+ for (size_t i = 0; i < children.size(); ++i)
+ sortedChildren.push_back(children[i]);
+ std::sort(sortedChildren.begin(), sortedChildren.end(), HistoryItemCompareLess);
+ for (size_t i = 0; i < sortedChildren.size(); ++i)
+ result += dumpHistoryItem(sortedChildren[i], indent + 4, false);
+ }
+
+ return result;
+}
+
+static void dumpBackForwardList(const TestNavigationController& navigationController, string& result)
+{
+ result.append("\n============== Back Forward List ==============\n");
+ for (int index = 0; index < navigationController.entryCount(); ++index) {
+ int currentIndex = navigationController.lastCommittedEntryIndex();
+ WebHistoryItem historyItem = navigationController.entryAtIndex(index)->contentState();
+ if (historyItem.isNull()) {
+ historyItem.initialize();
+ historyItem.setURLString(navigationController.entryAtIndex(index)->URL().spec().utf16());
+ }
+ result.append(dumpHistoryItem(historyItem, 8, index == currentIndex));
+ }
+ result.append("===============================================\n");
+}
+
+string TestShell::dumpAllBackForwardLists()
+{
+ string result;
+ for (unsigned i = 0; i < m_windowList.size(); ++i)
+ dumpBackForwardList(*m_windowList[i]->navigationController(), result);
+ return result;
+}
+
+void TestShell::dump()
+{
+ WebScriptController::flushConsoleMessages();
+
+ // Dump the requested representation.
+ WebFrame* frame = m_webView->mainFrame();
+ if (!frame)
+ return;
+ bool shouldDumpAsText = m_layoutTestController->shouldDumpAsText();
+ bool dumpedAnything = false;
+ if (m_params.dumpTree) {
+ dumpedAnything = true;
+ printf("Content-Type: text/plain\n");
+ // Text output: the test page can request different types of output
+ // which we handle here.
+ if (!shouldDumpAsText) {
+ // Plain text pages should be dumped as text
+ string mimeType = frame->dataSource()->response().mimeType().utf8();
+ shouldDumpAsText = mimeType == "text/plain";
+ }
+ if (shouldDumpAsText) {
+ bool recursive = m_layoutTestController->shouldDumpChildFramesAsText();
+ string dataUtf8 = dumpFramesAsText(frame, recursive);
+ if (fwrite(dataUtf8.c_str(), 1, dataUtf8.size(), stdout) != dataUtf8.size())
+ FATAL("Short write to stdout, disk full?\n");
+ } else {
+ printf("%s", frame->renderTreeAsText().utf8().data());
+ bool recursive = m_layoutTestController->shouldDumpChildFrameScrollPositions();
+ dumpFrameScrollPosition(frame, recursive);
+ }
+ if (m_layoutTestController->shouldDumpBackForwardList())
+ printf("%s", dumpAllBackForwardLists().c_str());
+ }
+ if (dumpedAnything && m_params.printSeparators)
+ printf("#EOF\n");
+
+ if (m_params.dumpPixels && !shouldDumpAsText) {
+ // Image output: we write the image data to the file given on the
+ // command line (for the dump pixels argument), and the MD5 sum to
+ // stdout.
+ dumpedAnything = true;
+ m_webView->layout();
+ if (m_layoutTestController->testRepaint()) {
+ WebSize viewSize = m_webView->size();
+ int width = viewSize.width;
+ int height = viewSize.height;
+ if (m_layoutTestController->sweepHorizontally()) {
+ for (WebRect column(0, 0, 1, height); column.x < width; column.x++)
+ m_webViewHost->paintRect(column);
+ } else {
+ for (WebRect line(0, 0, width, 1); line.y < height; line.y++)
+ m_webViewHost->paintRect(line);
+ }
+ } else
+ m_webViewHost->paintInvalidatedRegion();
+
+ // See if we need to draw the selection bounds rect. Selection bounds
+ // rect is the rect enclosing the (possibly transformed) selection.
+ // The rect should be drawn after everything is laid out and painted.
+ if (m_layoutTestController->shouldDumpSelectionRect()) {
+ // If there is a selection rect - draw a red 1px border enclosing rect
+ WebRect wr = frame->selectionBoundsRect();
+ if (!wr.isEmpty()) {
+ // Render a red rectangle bounding selection rect
+ SkPaint paint;
+ paint.setColor(0xFFFF0000); // Fully opaque red
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setFlags(SkPaint::kAntiAlias_Flag);
+ paint.setStrokeWidth(1.0f);
+ SkIRect rect; // Bounding rect
+ rect.set(wr.x, wr.y, wr.x + wr.width, wr.y + wr.height);
+ m_webViewHost->canvas()->drawIRect(rect, paint);
+ }
+ }
+
+ string md5sum = dumpImage(m_webViewHost->canvas(), m_params.pixelHash);
+ }
+ printf("#EOF\n"); // For the image.
+ fflush(stdout);
+ fflush(stderr);
+}
+
+string TestShell::dumpImage(skia::PlatformCanvas* canvas, const string& expectedHash)
+{
+ skia::BitmapPlatformDevice& device =
+ static_cast<skia::BitmapPlatformDevice&>(canvas->getTopPlatformDevice());
+ const SkBitmap& sourceBitmap = device.accessBitmap(false);
+
+ SkAutoLockPixels sourceBitmapLock(sourceBitmap);
+
+ // Fix the alpha. The expected PNGs on Mac have an alpha channel, so we want
+ // to keep it. On Windows, the alpha channel is wrong since text/form control
+ // drawing may have erased it in a few places. So on Windows we force it to
+ // opaque and also don't write the alpha channel for the reference. Linux
+ // doesn't have the wrong alpha like Windows, but we ignore it anyway.
+#if OS(WINDOWS)
+ bool discardTransparency = true;
+ device.makeOpaque(0, 0, sourceBitmap.width(), sourceBitmap.height());
+#elif OS(MAC_OS_X)
+ bool discardTransparency = false;
+#elif OS(UNIX)
+ bool discardTransparency = true;
+#endif
+
+ // Compute MD5 sum. We should have done this before calling
+ // device.makeOpaque on Windows. Because we do it after the call, there are
+ // some images that are the pixel identical on windows and other platforms
+ // but have different MD5 sums. At this point, rebaselining all the windows
+ // tests is too much of a pain, so we just check in different baselines.
+ MD5Context ctx;
+ MD5Init(&ctx);
+ MD5Update(&ctx, sourceBitmap.getPixels(), sourceBitmap.getSize());
+
+ MD5Digest digest;
+ MD5Final(&digest, &ctx);
+ string md5hash = MD5DigestToBase16(digest);
+ printf("\nActualHash: %s\n", md5hash.c_str());
+ if (!expectedHash.empty())
+ printf("\nExpectedHash: %s\n", expectedHash.c_str());
+
+ // Only encode and dump the png if the hashes don't match. Encoding the image
+ // is really expensive.
+ if (md5hash.compare(expectedHash)) {
+ std::vector<unsigned char> png;
+ gfx::PNGCodec::ColorFormat colorFormat = gfx::PNGCodec::FORMAT_BGRA;
+ gfx::PNGCodec::Encode(
+ reinterpret_cast<const unsigned char*>(sourceBitmap.getPixels()),
+ colorFormat, sourceBitmap.width(), sourceBitmap.height(),
+ static_cast<int>(sourceBitmap.rowBytes()), discardTransparency, &png);
+
+ printf("Content-Type: image/png\n");
+ printf("Content-Length: %u\n", png.size());
+ // Write to disk.
+ if (fwrite(&png[0], 1, png.size(), stdout) != png.size())
+ FATAL("Short write to stdout.\n");
+ }
+
+ return md5hash;
+}
+
+void TestShell::bindJSObjectsToWindow(WebFrame* frame)
+{
+ m_accessibilityController->bindToJavascript(frame, WebString::fromUTF8("accessibilityController"));
+ m_layoutTestController->bindToJavascript(frame, WebString::fromUTF8("layoutTestController"));
+ m_eventSender->bindToJavascript(frame, WebString::fromUTF8("eventSender"));
+ m_plainTextController->bindToJavascript(frame, WebString::fromUTF8("plainText"));
+ m_textInputController->bindToJavascript(frame, WebString::fromUTF8("textInputController"));
+}
+
+int TestShell::layoutTestTimeout()
+{
+ return 10 * 1000;
+}
+
+WebViewHost* TestShell::createWebView()
+{
+ return createNewWindow(WebURL());
+}
+
+WebViewHost* TestShell::createNewWindow(const WebURL& url)
+{
+ WebViewHost* host = new WebViewHost(this);
+ WebView* view = WebView::create(host);
+ host->setWebWidget(view);
+ resetWebSettings(*view);
+ view->initializeMainFrame(host);
+ m_windowList.append(host);
+ host->loadURLForFrame(url, WebString());
+ return host;
+}
+
+void TestShell::closeWindow(WebViewHost* window)
+{
+ size_t i = m_windowList.find(window);
+ if (i == notFound) {
+ ASSERT_NOT_REACHED();
+ return;
+ }
+ m_windowList.remove(i);
+ window->webWidget()->close();
+ delete window;
+}
+
+void TestShell::closeRemainingWindows()
+{
+ // Iterate through the window list and close everything except the main
+ // ihwindow. We don't want to delete elements as we're iterating, so we copy
+ // to a temp vector first.
+ Vector<WebViewHost*> windowsToDelete;
+ for (unsigned i = 0; i < m_windowList.size(); ++i) {
+ if (m_windowList[i] != webViewHost())
+ windowsToDelete.append(m_windowList[i]);
+ }
+ ASSERT(windowsToDelete.size() + 1 == m_windowList.size());
+ for (unsigned i = 0; i < windowsToDelete.size(); ++i)
+ closeWindow(windowsToDelete[i]);
+ ASSERT(m_windowList.size() == 1);
+}
+
+int TestShell::windowCount()
+{
+ return m_windowList.size();
+}
diff --git a/WebKitTools/DumpRenderTree/chromium/TestShell.h b/WebKitTools/DumpRenderTree/chromium/TestShell.h
new file mode 100644
index 0000000..c6a5b2e
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/TestShell.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "AccessibilityController.h"
+#include "EventSender.h"
+#include "LayoutTestController.h"
+#include "PlainTextController.h"
+#include "TextInputController.h"
+#include "WebViewHost.h"
+#include <string>
+#include <wtf/OwnPtr.h>
+#include <wtf/Vector.h>
+
+// TestShell is a container of global variables and has bridge functions between
+// various objects. Only one instance is created in one DRT process.
+
+namespace WebKit {
+class WebFrame;
+class WebPreferences;
+class WebView;
+class WebURL;
+}
+namespace skia {
+class PlatformCanvas;
+}
+
+struct TestParams {
+ bool dumpTree;
+ bool dumpPixels;
+ bool printSeparators;
+ WebKit::WebURL testUrl;
+ std::string pixelFileName;
+ std::string pixelHash;
+
+ TestParams()
+ : dumpTree(true)
+ , dumpPixels(false)
+ , printSeparators(false) {}
+};
+
+class TestShell {
+public:
+ TestShell();
+ ~TestShell();
+ // The main WebView.
+ WebKit::WebView* webView() const { return m_webView; }
+ // Returns the host for the main WebView.
+ WebViewHost* webViewHost() const { return m_webViewHost; }
+ LayoutTestController* layoutTestController() const { return m_layoutTestController.get(); }
+ AccessibilityController* accessibilityController() const { return m_accessibilityController.get(); }
+
+ void bindJSObjectsToWindow(WebKit::WebFrame*);
+ void runFileTest(const TestParams&);
+ void callJSGC();
+ void resetTestController();
+ void waitTestFinished();
+
+ // Operations to the main window.
+ void loadURL(const WebKit::WebURL& url);
+ void reload();
+ void goToOffset(int offset);
+ int navigationEntryCount() const;
+
+ void setFocus(WebKit::WebWidget*, bool enable);
+ bool shouldDumpFrameLoadCallbacks() const { return (m_testIsPreparing || m_testIsPending) && layoutTestController()->shouldDumpFrameLoadCallbacks(); }
+ bool shouldDumpResourceLoadCallbacks() const { return (m_testIsPreparing || m_testIsPending) && layoutTestController()->shouldDumpResourceLoadCallbacks(); }
+ void setIsLoading(bool flag) { m_isLoading = flag; }
+
+ // Called by the LayoutTestController to signal test completion.
+ void testFinished();
+ // Called by LayoutTestController when a test hits the timeout, but does not
+ // cause a hang. We can avoid killing TestShell in this case and still dump
+ // the test results.
+ void testTimedOut();
+
+#if defined(OS_WIN)
+ // Access to the finished event. Used by the static WatchDog thread.
+ HANDLE finishedEvent() { return m_finishedEvent; }
+#endif
+
+ // Get the timeout for running a test in milliseconds.
+ static int layoutTestTimeout();
+ static int layoutTestTimeoutForWatchDog() { return layoutTestTimeout() + 1000; }
+
+ WebViewHost* createWebView();
+ WebViewHost* createNewWindow(const WebKit::WebURL&);
+ void closeWindow(WebViewHost*);
+ void closeRemainingWindows();
+ int windowCount();
+ static void resizeWindowForTest(WebViewHost*, const WebKit::WebURL&);
+
+ static const int virtualWindowBorder = 3;
+
+private:
+ static void resetWebSettings(WebKit::WebView&);
+ void dump();
+ std::string dumpAllBackForwardLists();
+ static std::string dumpImage(skia::PlatformCanvas*, const std::string& expectedHash);
+
+ bool m_testIsPending;
+ bool m_testIsPreparing;
+ bool m_isLoading;
+ WebKit::WebView* m_webView;
+ WebKit::WebWidget* m_focusedWidget;
+ WebViewHost* m_webViewHost;
+ OwnPtr<AccessibilityController*> m_accessibilityController;
+ OwnPtr<EventSender*> m_eventSender;
+ OwnPtr<LayoutTestController*> m_layoutTestController;
+ OwnPtr<PlainTextController*> m_plainTextController;
+ OwnPtr<TextInputController*> m_textInputController;
+ TestParams m_params;
+
+ // List of all windows in this process.
+ // The main window should be put into windowList[0].
+ typedef Vector<WebViewHost*> WindowList;
+ WindowList m_windowList;
+
+#if defined(OS_WIN)
+ // Used by the watchdog to know when it's finished.
+ HANDLE m_finishedEvent;
+#endif
+};
diff --git a/WebKitTools/DumpRenderTree/chromium/TestShellGtk.cpp b/WebKitTools/DumpRenderTree/chromium/TestShellGtk.cpp
new file mode 100644
index 0000000..d71881a
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/TestShellGtk.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "TestShell.h"
+
+#include "webkit/support/webkit_support.h"
+#include <signal.h>
+
+static void AlarmHandler(int signatl)
+{
+ // If the alarm alarmed, kill the process since we have a really bad hang.
+ puts("\n#TEST_TIMED_OUT\n");
+ puts("#EOF\n");
+ fflush(stdout);
+ exit(0);
+}
+
+void TestShell::waitTestFinished()
+{
+ ASSERT(!m_testIsPending);
+
+ m_testIsPending = true;
+
+ // Install an alarm signal handler that will kill us if we time out.
+ signal(SIGALRM, AlarmHandler);
+ alarm(layoutTestTimeoutForWatchDog() / 1000);
+
+ // TestFinished() will post a quit message to break this loop when the page
+ // finishes loading.
+ while (m_testIsPending)
+ webkit_support::RunMessageLoop();
+
+ // Remove the alarm.
+ alarm(0);
+ signal(SIGALRM, SIG_DFL);
+}
diff --git a/WebKitTools/DumpRenderTree/chromium/TestShellMac.mm b/WebKitTools/DumpRenderTree/chromium/TestShellMac.mm
new file mode 100644
index 0000000..ec8dbac
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/TestShellMac.mm
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "TestShell.h"
+#include "webkit/support/webkit_support.h"
+#import <AppKit/AppKit.h>
+
+// A class to be the target/selector of the "watchdog" thread that ensures
+// pages timeout if they take too long and tells the test harness via stdout.
+@interface WatchDogTarget : NSObject {
+@private
+ NSTimeInterval _timeout;
+}
+// |timeout| is in seconds
+- (id)initWithTimeout:(NSTimeInterval)timeout;
+// serves as the "run" method of a NSThread.
+- (void)run:(id)sender;
+@end
+
+@implementation WatchDogTarget
+
+- (id)initWithTimeout:(NSTimeInterval)timeout
+{
+ if ((self = [super init]))
+ _timeout = timeout;
+ return self;
+}
+
+- (void)run:(id)ignore
+{
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+
+ // check for debugger, just bail if so. We don't want the timeouts hitting
+ // when we're trying to track down an issue.
+ if (webkit_support::BeingDebugged())
+ return;
+
+ NSThread* currentThread = [NSThread currentThread];
+
+ // Wait to be cancelled. If we are that means the test finished. If it hasn't,
+ // then we need to tell the layout script we timed out and start again.
+ NSDate* limitDate = [NSDate dateWithTimeIntervalSinceNow:_timeout];
+ while ([(NSDate*)[NSDate date] compare:limitDate] == NSOrderedAscending &&
+ ![currentThread isCancelled]) {
+ // sleep for a small increment then check again
+ NSDate* incrementDate = [NSDate dateWithTimeIntervalSinceNow:1.0];
+ [NSThread sleepUntilDate:incrementDate];
+ }
+ if (![currentThread isCancelled]) {
+ // Print a warning to be caught by the layout-test script.
+ // Note: the layout test driver may or may not recognize
+ // this as a timeout.
+ puts("#TEST_TIMED_OUT\n");
+ puts("#EOF\n");
+ fflush(stdout);
+ exit(0);
+ }
+
+ [pool release];
+}
+
+@end
+
+void TestShell::waitTestFinished()
+{
+ ASSERT(!m_testIsPending);
+
+ m_testIsPending = true;
+
+ // Create a watchdog thread which just sets a timer and
+ // kills the process if it times out. This catches really
+ // bad hangs where the shell isn't coming back to the
+ // message loop. If the watchdog is what catches a
+ // timeout, it can't do anything except terminate the test
+ // shell, which is unfortunate.
+ // Windows multiplies by 2.5, but that causes us to run for far, far too
+ // long. We use the passed value and let the scripts flag override
+ // the value as needed.
+ NSTimeInterval timeoutSeconds = layoutTestTimeoutForWatchDog() / 1000;
+ WatchDogTarget* watchdog = [[[WatchDogTarget alloc]
+ initWithTimeout:timeoutSeconds] autorelease];
+ NSThread* thread = [[NSThread alloc] initWithTarget:watchdog
+ selector:@selector(run:)
+ object:nil];
+ [thread start];
+
+ // TestFinished() will post a quit message to break this loop when the page
+ // finishes loading.
+ while (m_testIsPending)
+ webkit_support::RunMessageLoop();
+
+ // Tell the watchdog that we're finished. No point waiting to re-join, it'll
+ // die on its own.
+ [thread cancel];
+ [thread release];
+}
diff --git a/WebKitTools/DumpRenderTree/chromium/TestShellWin.cpp b/WebKitTools/DumpRenderTree/chromium/TestShellWin.cpp
new file mode 100644
index 0000000..2d806a2
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/TestShellWin.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "TestShell.h"
+
+#include "webkit/support/webkit_support.h"
+#include <process.h>
+
+// Default timeout in ms for file page loads when in layout test mode.
+const int kDefaultFileTestTimeoutMillisecs = 10 * 1000;
+const int kDefaultWatchDogTimeoutMillisecs = kDefaultFileTestTimeoutMillisecs + 1 * 1000;
+
+// Thread main to run for the thread which just tests for timeout.
+unsigned int __stdcall watchDogThread(void *arg)
+{
+ // If we're debugging a layout test, don't timeout.
+ if (::IsDebuggerPresent())
+ return 0;
+
+ TestShell* shell = static_cast<TestShell*>(arg);
+ // FIXME: Do we need user-specified time settings as with the original
+ // Chromium implementation?
+ DWORD timeout = static_cast<DWORD>(kDefaultWatchDogTimeoutMillisecs);
+ DWORD rv = WaitForSingleObject(shell->finishedEvent(), timeout);
+ if (rv == WAIT_TIMEOUT) {
+ // Print a warning to be caught by the layout-test script.
+ // Note: the layout test driver may or may not recognize
+ // this as a timeout.
+ puts("#TEST_TIMED_OUT\n");
+ puts("#EOF\n");
+ fflush(stdout);
+ TerminateProcess(GetCurrentProcess(), 0);
+ }
+ // Finished normally.
+ return 0;
+}
+
+void TestShell::waitTestFinished()
+{
+ DCHECK(!m_testIsPending) << "cannot be used recursively";
+
+ m_testIsPending = true;
+
+ // Create a watchdog thread which just sets a timer and
+ // kills the process if it times out. This catches really
+ // bad hangs where the shell isn't coming back to the
+ // message loop. If the watchdog is what catches a
+ // timeout, it can't do anything except terminate the test
+ // shell, which is unfortunate.
+ m_finishedEvent = CreateEvent(0, TRUE, FALSE, 0);
+ DCHECK(m_finishedEvent);
+
+ HANDLE threadHandle = reinterpret_cast<HANDLE>(_beginthreadex(
+ 0,
+ 0,
+ &watchDogThread,
+ this,
+ 0,
+ 0));
+ DCHECK(threadHandle);
+
+ // TestFinished() will post a quit message to break this loop when the page
+ // finishes loading.
+ while (m_testIsPending)
+ webkit_support::RunMessageLoop();
+
+ // Tell the watchdog that we are finished.
+ SetEvent(m_finishedEvent);
+
+ // Wait to join the watchdog thread. (up to 1s, then quit)
+ WaitForSingleObject(threadHandle, 1000);
+}
diff --git a/WebKitTools/DumpRenderTree/chromium/TestWebWorker.h b/WebKitTools/DumpRenderTree/chromium/TestWebWorker.h
new file mode 100644
index 0000000..899514e
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/TestWebWorker.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TestWebWorker_h
+#define TestWebWorker_h
+
+#include "public/WebMessagePortChannel.h"
+#include "public/WebWorker.h"
+#include "public/WebWorkerClient.h"
+#include <wtf/RefCounted.h>
+
+namespace WebKit {
+class WebNotificationPresenter;
+class WebString;
+class WebURL;
+}
+
+class TestWebWorker : public WebKit::WebWorker,
+ public WebKit::WebWorkerClient,
+ public WTF::RefCounted<TestWebWorker> {
+public:
+ TestWebWorker()
+ {
+ ref();
+ // The initial counter value should be 2. One for a worker object,
+ // another for a worker context object. We need to call ref() just once
+ // because the default counter value of RefCounted is 1.
+ }
+
+ // WebWorker methods:
+ virtual void startWorkerContext(const WebKit::WebURL&, const WebKit::WebString&, const WebKit::WebString&) {}
+ virtual void terminateWorkerContext() {}
+ virtual void postMessageToWorkerContext(const WebKit::WebString&, const WebKit::WebMessagePortChannelArray&) {}
+ virtual void workerObjectDestroyed()
+ {
+ // Releases the reference held for worker object.
+ deref();
+ }
+ virtual void clientDestroyed() {}
+
+ // WebWorkerClient methods:
+ virtual void postMessageToWorkerObject(const WebKit::WebString&, const WebKit::WebMessagePortChannelArray&) {}
+ virtual void postExceptionToWorkerObject(const WebKit::WebString&, int, const WebKit::WebString&) {}
+ virtual void postConsoleMessageToWorkerObject(int, int, int, int, const WebKit::WebString&, int, const WebKit::WebString&) {}
+ virtual void confirmMessageFromWorkerObject(bool) {}
+ virtual void reportPendingActivity(bool) {}
+ virtual void workerContextClosed() {}
+ virtual void workerContextDestroyed()
+ {
+ // Releases the reference held for worker context object.
+ deref();
+ }
+ virtual WebKit::WebWorker* createWorker(WebKit::WebWorkerClient*) { return 0; }
+ virtual WebKit::WebNotificationPresenter* notificationPresenter() { return 0; }
+
+private:
+ ~TestWebWorker() {}
+ friend class WTF::RefCounted<TestWebWorker>;
+};
+
+#endif // TestWebWorker_h
diff --git a/WebKitTools/DumpRenderTree/chromium/TextInputController.cpp b/WebKitTools/DumpRenderTree/chromium/TextInputController.cpp
new file mode 100644
index 0000000..63c4719
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/TextInputController.cpp
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "TextInputController.h"
+
+#include "TestShell.h"
+#include "public/WebFrame.h"
+#include "public/WebRange.h"
+#include "public/WebString.h"
+#include "public/WebView.h"
+#include <wtf/StringExtras.h>
+#include <string>
+
+using namespace WebKit;
+using namespace std;
+
+TestShell* TextInputController::testShell = 0;
+
+TextInputController::TextInputController(TestShell* shell)
+{
+ // Set static testShell variable. Be careful not to assign testShell to new
+ // windows which are temporary.
+ if (!testShell)
+ testShell = shell;
+
+ bindMethod("insertText", &TextInputController::insertText);
+ bindMethod("doCommand", &TextInputController::doCommand);
+ bindMethod("setMarkedText", &TextInputController::setMarkedText);
+ bindMethod("unmarkText", &TextInputController::unmarkText);
+ bindMethod("hasMarkedText", &TextInputController::hasMarkedText);
+ bindMethod("conversationIdentifier", &TextInputController::conversationIdentifier);
+ bindMethod("substringFromRange", &TextInputController::substringFromRange);
+ bindMethod("attributedSubstringFromRange", &TextInputController::attributedSubstringFromRange);
+ bindMethod("markedRange", &TextInputController::markedRange);
+ bindMethod("selectedRange", &TextInputController::selectedRange);
+ bindMethod("firstRectForCharacterRange", &TextInputController::firstRectForCharacterRange);
+ bindMethod("characterIndexForPoint", &TextInputController::characterIndexForPoint);
+ bindMethod("validAttributesForMarkedText", &TextInputController::validAttributesForMarkedText);
+ bindMethod("makeAttributedString", &TextInputController::makeAttributedString);
+}
+
+WebFrame* TextInputController::getMainFrame()
+{
+ return testShell->webView()->mainFrame();
+}
+
+void TextInputController::insertText(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ WebFrame* mainFrame = getMainFrame();
+ if (!mainFrame)
+ return;
+ if (arguments.size() < 1 || !arguments[0].isString())
+ return;
+
+ if (mainFrame->hasMarkedText()) {
+ mainFrame->unmarkText();
+ mainFrame->replaceSelection(WebString());
+ }
+ mainFrame->insertText(WebString::fromUTF8(arguments[0].toString()));
+}
+
+void TextInputController::doCommand(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ WebFrame* mainFrame = getMainFrame();
+ if (!mainFrame)
+ return;
+
+ if (arguments.size() >= 1 && arguments[0].isString())
+ mainFrame->executeCommand(WebString::fromUTF8(arguments[0].toString()));
+}
+
+void TextInputController::setMarkedText(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ WebFrame* mainFrame = getMainFrame();
+ if (!mainFrame)
+ return;
+
+ if (arguments.size() >= 3 && arguments[0].isString()
+ && arguments[1].isNumber() && arguments[2].isNumber()) {
+ mainFrame->setMarkedText(WebString::fromUTF8(arguments[0].toString()),
+ arguments[1].toInt32(),
+ arguments[2].toInt32());
+ }
+}
+
+void TextInputController::unmarkText(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+
+ WebFrame* mainFrame = getMainFrame();
+ if (!mainFrame)
+ return;
+
+ mainFrame->unmarkText();
+}
+
+void TextInputController::hasMarkedText(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+
+ WebFrame* mainFrame = getMainFrame();
+ if (!mainFrame)
+ return;
+
+ result->set(mainFrame->hasMarkedText());
+}
+
+void TextInputController::conversationIdentifier(const CppArgumentList&, CppVariant* result)
+{
+ // FIXME: Implement this.
+ result->setNull();
+}
+
+void TextInputController::substringFromRange(const CppArgumentList&, CppVariant* result)
+{
+ // FIXME: Implement this.
+ result->setNull();
+}
+
+void TextInputController::attributedSubstringFromRange(const CppArgumentList&, CppVariant* result)
+{
+ // FIXME: Implement this.
+ result->setNull();
+}
+
+void TextInputController::markedRange(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+
+ WebFrame* mainFrame = getMainFrame();
+ if (!mainFrame)
+ return;
+
+ WebRange range = mainFrame->markedRange();
+ char buffer[30];
+ snprintf(buffer, 30, "%d,%d", range.startOffset(), range.endOffset());
+ result->set(string(buffer));
+}
+
+void TextInputController::selectedRange(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+
+ WebFrame* mainFrame = getMainFrame();
+ if (!mainFrame)
+ return;
+
+ WebRange range = mainFrame->selectionRange();
+ char buffer[30];
+ snprintf(buffer, 30, "%d,%d", range.startOffset(), range.endOffset());
+ result->set(string(buffer));
+}
+
+void TextInputController::firstRectForCharacterRange(const CppArgumentList&, CppVariant* result)
+{
+ // FIXME: Implement this.
+ result->setNull();
+}
+
+void TextInputController::characterIndexForPoint(const CppArgumentList&, CppVariant* result)
+{
+ // FIXME: Implement this.
+ result->setNull();
+}
+
+void TextInputController::validAttributesForMarkedText(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+
+ WebFrame* mainFrame = getMainFrame();
+ if (!mainFrame)
+ return;
+
+ result->set("NSUnderline,NSUnderlineColor,NSMarkedClauseSegment,"
+ "NSTextInputReplacementRangeAttributeName");
+}
+
+void TextInputController::makeAttributedString(const CppArgumentList&, CppVariant* result)
+{
+ // FIXME: Implement this.
+ result->setNull();
+}
diff --git a/WebKitTools/DumpRenderTree/chromium/TextInputController.h b/WebKitTools/DumpRenderTree/chromium/TextInputController.h
new file mode 100644
index 0000000..a912ba1
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/TextInputController.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+<<<<<<< HEAD:WebCore/bindings/v8/custom/V8NavigatorCustom.cpp
+#include "config.h"
+#include "V8Navigator.h"
+
+#include "RuntimeEnabledFeatures.h"
+#include "V8DOMWindow.h"
+#include "V8DOMWrapper.h"
+
+#if PLATFORM(ANDROID)
+#include "ExceptionCode.h"
+#include "V8CustomApplicationInstalledCallback.h"
+#include "V8Proxy.h"
+#endif
+
+namespace WebCore {
+
+v8::Handle<v8::Value> toV8(Navigator* impl)
+{
+ if (!impl)
+ return v8::Null();
+ v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(impl);
+ if (wrapper.IsEmpty()) {
+ wrapper = V8Navigator::wrap(impl);
+ if (!wrapper.IsEmpty())
+ V8DOMWrapper::setHiddenWindowReference(impl->frame(), V8DOMWindow::navigatorIndex, wrapper);
+ }
+ return wrapper;
+}
+
+#if PLATFORM(ANDROID) && ENABLE(APPLICATION_INSTALLED)
+
+static PassRefPtr<ApplicationInstalledCallback> createApplicationInstalledCallback(
+ v8::Local<v8::Value> value, bool& succeeded)
+{
+ succeeded = true;
+
+ if (!value->IsFunction()) {
+ succeeded = false;
+ throwError("The second argument should be a function");
+ return 0;
+ }
+
+ Frame* frame = V8Proxy::retrieveFrameForCurrentContext();
+ return V8CustomApplicationInstalledCallback::create(value, frame);
+}
+
+v8::Handle<v8::Value> V8Navigator::isApplicationInstalledCallback(const v8::Arguments& args)
+{
+ INC_STATS("DOM.isApplicationInstalled()");
+ bool succeeded = false;
+
+ if (args.Length() < 2)
+ return throwError("Two arguments required: an application name and a callback.", V8Proxy::SyntaxError);
+
+ if (!args[0]->IsString())
+ return throwError("The first argument should be a string.");
+
+ RefPtr<ApplicationInstalledCallback> callback =
+ createApplicationInstalledCallback(args[1], succeeded);
+ if (!succeeded)
+ return v8::Undefined();
+
+ ASSERT(callback);
+
+ Navigator* navigator = V8Navigator::toNative(args.Holder());
+ if (!navigator->isApplicationInstalled(toWebCoreString(args[0]), callback.release()))
+ return throwError(INVALID_STATE_ERR);
+
+ return v8::Undefined();
+}
+
+#endif // PLATFORM(ANDROID) && ENABLE(APPLICATION_INSTALLED)
+
+} // namespace WebCore
+=======
+// TextInputController is bound to window.textInputController in Javascript
+// when DRT is running. Layout tests use it to exercise various corners of
+// text input.
+
+#ifndef TextInputController_h
+#define TextInputController_h
+
+#include "CppBoundClass.h"
+
+class TestShell;
+
+namespace WebKit {
+class WebFrame;
+}
+
+class TextInputController : public CppBoundClass {
+public:
+ TextInputController(TestShell*);
+
+ void insertText(const CppArgumentList&, CppVariant*);
+ void doCommand(const CppArgumentList&, CppVariant*);
+ void setMarkedText(const CppArgumentList&, CppVariant*);
+ void unmarkText(const CppArgumentList&, CppVariant*);
+ void hasMarkedText(const CppArgumentList&, CppVariant*);
+ void conversationIdentifier(const CppArgumentList&, CppVariant*);
+ void substringFromRange(const CppArgumentList&, CppVariant*);
+ void attributedSubstringFromRange(const CppArgumentList&, CppVariant*);
+ void markedRange(const CppArgumentList&, CppVariant*);
+ void selectedRange(const CppArgumentList&, CppVariant*);
+ void firstRectForCharacterRange(const CppArgumentList&, CppVariant*);
+ void characterIndexForPoint(const CppArgumentList&, CppVariant*);
+ void validAttributesForMarkedText(const CppArgumentList&, CppVariant*);
+ void makeAttributedString(const CppArgumentList&, CppVariant*);
+
+private:
+ // Returns the test shell's main WebFrame.
+ static WebKit::WebFrame* getMainFrame();
+
+ // Non-owning pointer. The TextInputController is owned by the TestShell.
+ static TestShell* testShell;
+};
+
+#endif // TextInputController_h
+>>>>>>> webkit.org at r58033:WebKitTools/DumpRenderTree/chromium/TextInputController.h
diff --git a/WebKitTools/DumpRenderTree/chromium/WebViewHost.cpp b/WebKitTools/DumpRenderTree/chromium/WebViewHost.cpp
new file mode 100644
index 0000000..95b1c7e
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/WebViewHost.cpp
@@ -0,0 +1,1316 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WebViewHost.h"
+
+#include "LayoutTestController.h"
+#include "TestNavigationController.h"
+#include "TestShell.h"
+#include "TestWebWorker.h"
+#include "net/base/net_errors.h" // FIXME: can we remove this?
+#include "public/WebCString.h"
+#include "public/WebConsoleMessage.h"
+#include "public/WebContextMenuData.h"
+#include "public/WebDataSource.h"
+#include "public/WebDragData.h"
+#include "public/WebFrame.h"
+#include "public/WebHistoryItem.h"
+#include "public/WebNode.h"
+#include "public/WebRange.h"
+#include "public/WebRect.h"
+#include "public/WebScreenInfo.h"
+#include "public/WebSize.h"
+#include "public/WebStorageNamespace.h"
+#include "public/WebURLRequest.h"
+#include "public/WebURLResponse.h"
+#include "public/WebView.h"
+#include "skia/ext/platform_canvas.h"
+#include "webkit/support/webkit_support.h"
+#include <wtf/Assertions.h>
+
+using namespace WebKit;
+using namespace skia;
+using namespace std;
+
+static const int screenWidth = 1920;
+static const int screenHeight = 1080;
+static const int screenUnavailableBorder = 8;
+
+// WebNavigationType debugging strings taken from PolicyDelegate.mm.
+static const char* linkClickedString = "link clicked";
+static const char* formSubmittedString = "form submitted";
+static const char* backForwardString = "back/forward";
+static const char* reloadString = "reload";
+static const char* formResubmittedString = "form resubmitted";
+static const char* otherString = "other";
+static const char* illegalString = "illegal value";
+
+static int nextPageID = 1;
+
+// Used to write a platform neutral file:/// URL by only taking the filename
+// (e.g., converts "file:///tmp/foo.txt" to just "foo.txt").
+static string urlSuitableForTestResult(const string& url)
+{
+ if (url.empty() || string::npos == url.find("file://"))
+ return url;
+
+ size_t pos = url.rfind('/');
+ if (pos == string::npos) {
+#if OS(WINDOWS)
+ pos = url.rfind('\\');
+ if (pos == string::npos)
+ pos = 0;
+#else
+ pos = 0;
+#endif
+ }
+ string filename = url.substr(pos + 1);
+ if (filename.empty())
+ return "file:"; // A WebKit test has this in its expected output.
+ return filename;
+}
+
+// Used to write a platform neutral file:/// URL by taking the
+// filename and its directory. (e.g., converts
+// "file:///tmp/foo/bar.txt" to just "bar.txt").
+static string descriptionSuitableForTestResult(const string& url)
+{
+ if (url.empty() || string::npos == url.find("file://"))
+ return url;
+
+ size_t pos = url.rfind('/');
+ if (pos == string::npos || !pos)
+ return "ERROR:" + url;
+ pos = url.rfind('/', pos - 1);
+ if (pos == string::npos)
+ return "ERROR:" + url;
+
+ return url.substr(pos + 1);
+}
+
+// Adds a file called "DRTFakeFile" to |data_object| (CF_HDROP). Use to fake
+// dragging a file.
+static void addDRTFakeFileToDataObject(WebDragData* dragData)
+{
+ dragData->appendToFileNames(WebString::fromUTF8("DRTFakeFile"));
+}
+
+// Get a debugging string from a WebNavigationType.
+static const char* webNavigationTypeToString(WebNavigationType type)
+{
+ switch (type) {
+ case WebKit::WebNavigationTypeLinkClicked:
+ return linkClickedString;
+ case WebKit::WebNavigationTypeFormSubmitted:
+ return formSubmittedString;
+ case WebKit::WebNavigationTypeBackForward:
+ return backForwardString;
+ case WebKit::WebNavigationTypeReload:
+ return reloadString;
+ case WebKit::WebNavigationTypeFormResubmitted:
+ return formResubmittedString;
+ case WebKit::WebNavigationTypeOther:
+ return otherString;
+ }
+ return illegalString;
+}
+
+static string URLDescription(const GURL& url)
+{
+ if (url.SchemeIs("file"))
+ return url.ExtractFileName();
+ return url.possibly_invalid_spec();
+}
+
+static void printResponseDescription(const WebURLResponse& response)
+{
+ if (response.isNull()) {
+ fputs("(null)", stdout);
+ return;
+ }
+ string url = response.url().spec();
+ printf("<NSURLResponse %s, http status code %d>",
+ descriptionSuitableForTestResult(url).c_str(),
+ response.httpStatusCode());
+}
+
+static void printErrorDescription(const WebURLError& error)
+{
+ string domain = error.domain.utf8();
+ int code = error.reason;
+
+ if (domain == net::kErrorDomain) {
+ domain = "NSURLErrorDomain";
+ switch (error.reason) {
+ case net::ERR_ABORTED:
+ code = -999;
+ break;
+ case net::ERR_UNSAFE_PORT:
+ // Our unsafe port checking happens at the network stack level, but we
+ // make this translation here to match the behavior of stock WebKit.
+ domain = "WebKitErrorDomain";
+ code = 103;
+ break;
+ case net::ERR_ADDRESS_INVALID:
+ case net::ERR_ADDRESS_UNREACHABLE:
+ code = -1004;
+ break;
+ }
+ } else
+ LOG_ERROR("Unknown error domain");
+
+ printf("<NSError domain %s, code %d, failing URL \"%s\">",
+ domain.c_str(), code, error.unreachableURL.spec().data());
+}
+
+static void printNodeDescription(const WebNode& node, int exception)
+{
+ if (exception) {
+ fputs("ERROR", stdout);
+ return;
+ }
+ if (node.isNull()) {
+ fputs("(null)", stdout);
+ return;
+ }
+ fputs(node.nodeName().utf8().data(), stdout);
+ const WebNode& parent = node.parentNode();
+ if (!parent.isNull()) {
+ fputs(" > ", stdout);
+ printNodeDescription(parent, 0);
+ }
+}
+
+static void printRangeDescription(const WebRange& range)
+{
+ if (range.isNull()) {
+ fputs("(null)", stdout);
+ return;
+ }
+ printf("range from %d of ", range.startOffset());
+ int exception = 0;
+ WebNode startNode = range.startContainer(exception);
+ printNodeDescription(startNode, exception);
+ printf(" to %d of ", range.endOffset());
+ WebNode endNode = range.endContainer(exception);
+ printNodeDescription(endNode, exception);
+}
+
+static string editingActionDescription(WebEditingAction action)
+{
+ switch (action) {
+ case WebKit::WebEditingActionTyped:
+ return "WebViewInsertActionTyped";
+ case WebKit::WebEditingActionPasted:
+ return "WebViewInsertActionPasted";
+ case WebKit::WebEditingActionDropped:
+ return "WebViewInsertActionDropped";
+ }
+ return "(UNKNOWN ACTION)";
+}
+
+static string textAffinityDescription(WebTextAffinity affinity)
+{
+ switch (affinity) {
+ case WebKit::WebTextAffinityUpstream:
+ return "NSSelectionAffinityUpstream";
+ case WebKit::WebTextAffinityDownstream:
+ return "NSSelectionAffinityDownstream";
+ }
+ return "(UNKNOWN AFFINITY)";
+}
+
+// WebViewClient -------------------------------------------------------------
+
+WebView* WebViewHost::createView(WebFrame*)
+{
+ if (!layoutTestController()->canOpenWindows())
+ return 0;
+ return m_shell->createWebView()->webView();
+}
+
+WebWidget* WebViewHost::createPopupMenu(bool)
+{
+ return 0;
+}
+
+WebWidget* WebViewHost::createPopupMenu(const WebPopupMenuInfo&)
+{
+ return 0;
+}
+
+WebStorageNamespace* WebViewHost::createSessionStorageNamespace()
+{
+ return WebKit::WebStorageNamespace::createSessionStorageNamespace();
+}
+
+void WebViewHost::didAddMessageToConsole(const WebConsoleMessage& message, const WebString& sourceName, unsigned sourceLine)
+{
+ // This matches win DumpRenderTree's UIDelegate.cpp.
+ string newMessage;
+ if (!message.text.isEmpty()) {
+ newMessage = message.text.utf8();
+ size_t fileProtocol = newMessage.find("file://");
+ if (fileProtocol != string::npos) {
+ newMessage = newMessage.substr(0, fileProtocol)
+ + urlSuitableForTestResult(newMessage.substr(fileProtocol));
+ }
+ }
+ printf("CONSOLE MESSAGE: line %d: %s\n", sourceLine, newMessage.data());
+}
+
+void WebViewHost::didStartLoading()
+{
+ m_shell->setIsLoading(true);
+}
+
+void WebViewHost::didStopLoading()
+{
+ m_shell->setIsLoading(false);
+}
+
+// The output from these methods in layout test mode should match that
+// expected by the layout tests. See EditingDelegate.m in DumpRenderTree.
+
+bool WebViewHost::shouldBeginEditing(const WebRange& range)
+{
+ if (layoutTestController()->shouldDumpEditingCallbacks()) {
+ fputs("EDITING DELEGATE: shouldBeginEditingInDOMRange:", stdout);
+ printRangeDescription(range);
+ fputs("\n", stdout);
+ }
+ return layoutTestController()->acceptsEditing();
+}
+
+bool WebViewHost::shouldEndEditing(const WebRange& range)
+{
+ if (layoutTestController()->shouldDumpEditingCallbacks()) {
+ fputs("EDITING DELEGATE: shouldEndEditingInDOMRange:", stdout);
+ printRangeDescription(range);
+ fputs("\n", stdout);
+ }
+ return layoutTestController()->acceptsEditing();
+}
+
+bool WebViewHost::shouldInsertNode(const WebNode& node, const WebRange& range, WebEditingAction action)
+{
+ if (layoutTestController()->shouldDumpEditingCallbacks()) {
+ fputs("EDITING DELEGATE: shouldInsertNode:", stdout);
+ printNodeDescription(node, 0);
+ fputs(" replacingDOMRange:", stdout);
+ printRangeDescription(range);
+ printf(" givenAction:%s\n", editingActionDescription(action).c_str());
+ }
+ return layoutTestController()->acceptsEditing();
+}
+
+bool WebViewHost::shouldInsertText(const WebString& text, const WebRange& range, WebEditingAction action)
+{
+ if (layoutTestController()->shouldDumpEditingCallbacks()) {
+ printf("EDITING DELEGATE: shouldInsertText:%s replacingDOMRange:", text.utf8().data());
+ printRangeDescription(range);
+ printf(" givenAction:%s\n", editingActionDescription(action).c_str());
+ }
+ return layoutTestController()->acceptsEditing();
+}
+
+bool WebViewHost::shouldChangeSelectedRange(
+ const WebRange& fromRange, const WebRange& toRange, WebTextAffinity affinity, bool stillSelecting)
+{
+ if (layoutTestController()->shouldDumpEditingCallbacks()) {
+ fputs("EDITING DELEGATE: shouldChangeSelectedDOMRange:", stdout);
+ printRangeDescription(fromRange);
+ fputs(" toDOMRange:", stdout);
+ printRangeDescription(toRange);
+ printf(" affinity:%s stillSelecting:%s\n",
+ textAffinityDescription(affinity).c_str(),
+ (stillSelecting ? "TRUE" : "FALSE"));
+ }
+ return layoutTestController()->acceptsEditing();
+}
+
+bool WebViewHost::shouldDeleteRange(const WebRange& range)
+{
+ if (layoutTestController()->shouldDumpEditingCallbacks()) {
+ fputs("EDITING DELEGATE: shouldDeleteDOMRange:", stdout);
+ printRangeDescription(range);
+ fputs("\n", stdout);
+ }
+ return layoutTestController()->acceptsEditing();
+}
+
+bool WebViewHost::shouldApplyStyle(const WebString& style, const WebRange& range)
+{
+ if (layoutTestController()->shouldDumpEditingCallbacks()) {
+ printf("EDITING DELEGATE: shouldApplyStyle:%s toElementsInDOMRange:", style.utf8().data());
+ printRangeDescription(range);
+ fputs("\n", stdout);
+ }
+ return layoutTestController()->acceptsEditing();
+}
+
+bool WebViewHost::isSmartInsertDeleteEnabled()
+{
+ return m_smartInsertDeleteEnabled;
+}
+
+bool WebViewHost::isSelectTrailingWhitespaceEnabled()
+{
+ return m_selectTrailingWhitespaceEnabled;
+}
+
+void WebViewHost::didBeginEditing()
+{
+ if (!layoutTestController()->shouldDumpEditingCallbacks())
+ return;
+ fputs("EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification\n", stdout);
+}
+
+void WebViewHost::didChangeSelection(bool isEmptySelection)
+{
+ if (layoutTestController()->shouldDumpEditingCallbacks())
+ fputs("EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification\n", stdout);
+ // No need to update clipboard with the selected text in DRT.
+}
+
+void WebViewHost::didChangeContents()
+{
+ if (!layoutTestController()->shouldDumpEditingCallbacks())
+ return;
+ fputs("EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification\n", stdout);
+}
+
+void WebViewHost::didEndEditing()
+{
+ if (!layoutTestController()->shouldDumpEditingCallbacks())
+ return;
+ fputs("EDITING DELEGATE: webViewDidEndEditing:WebViewDidEndEditingNotification\n", stdout);
+}
+
+bool WebViewHost::handleCurrentKeyboardEvent()
+{
+ if (m_editCommandName.empty())
+ return false;
+ WebFrame* frame = webView()->focusedFrame();
+ if (!frame)
+ return false;
+
+ return frame->executeCommand(WebString::fromUTF8(m_editCommandName), WebString::fromUTF8(m_editCommandValue));
+}
+
+void WebViewHost::spellCheck(const WebString& text, int& misspelledOffset, int& misspelledLength)
+{
+ // Check the spelling of the given text.
+#if OS(MAC_OS_X)
+ // FIXME: rebaseline layout-test results of Windows and Linux so we
+ // can enable this mock spellchecker on them.
+ m_spellcheck.spellCheckWord(text, &misspelledOffset, &misspelledLength);
+#endif
+}
+
+WebString WebViewHost::autoCorrectWord(const WebString&)
+{
+ // Returns an empty string as Mac WebKit ('WebKitSupport/WebEditorClient.mm')
+ // does. (If this function returns a non-empty string, WebKit replaces the
+ // given misspelled string with the result one. This process executes some
+ // editor commands and causes layout-test failures.)
+ return WebString();
+}
+
+void WebViewHost::runModalAlertDialog(WebFrame*, const WebString& message)
+{
+ printf("ALERT: %s\n", message.utf8().data());
+}
+
+bool WebViewHost::runModalConfirmDialog(WebFrame*, const WebString& message)
+{
+ printf("CONFIRM: %s\n", message.utf8().data());
+ return true;
+}
+
+bool WebViewHost::runModalPromptDialog(WebFrame* frame, const WebString& message,
+ const WebString& defaultValue, WebString*)
+{
+ printf("PROMPT: %s, default text: %s\n", message.utf8().data(), defaultValue.utf8().data());
+ return true;
+}
+
+bool WebViewHost::runModalBeforeUnloadDialog(WebFrame*, const WebString&)
+{
+ return true; // Allow window closure.
+}
+
+void WebViewHost::showContextMenu(WebFrame*, const WebContextMenuData&)
+{
+}
+
+
+void WebViewHost::setStatusText(const WebString& text)
+{
+ if (!layoutTestController()->shouldDumpStatusCallbacks())
+ return;
+ // When running tests, write to stdout.
+ printf("UI DELEGATE STATUS CALLBACK: setStatusText:%s\n", text.utf8().data());
+}
+
+void WebViewHost::startDragging(const WebPoint& mouseCoords, const WebDragData& data, WebDragOperationsMask mask)
+{
+ WebDragData mutableDragData = data;
+ if (layoutTestController()->shouldAddFileToPasteboard()) {
+ // Add a file called DRTFakeFile to the drag&drop clipboard.
+ addDRTFakeFileToDataObject(&mutableDragData);
+ }
+
+ // When running a test, we need to fake a drag drop operation otherwise
+ // Windows waits for real mouse events to know when the drag is over.
+ EventSender::doDragDrop(mouseCoords, mutableDragData, mask);
+}
+
+void WebViewHost::navigateBackForwardSoon(int offset)
+{
+ navigationController()->goToOffset(offset);
+}
+
+int WebViewHost::historyBackListCount()
+{
+ return navigationController()->lastCommittedEntryIndex();
+}
+
+int WebViewHost::historyForwardListCount()
+{
+ int currentIndex =navigationController()->lastCommittedEntryIndex();
+ return navigationController()->entryCount() - currentIndex - 1;
+}
+
+void WebViewHost::focusAccessibilityObject(const WebAccessibilityObject& object)
+{
+ m_shell->accessibilityController()->setFocusedElement(object);
+}
+
+// WebWidgetClient -----------------------------------------------------------
+
+void WebViewHost::didInvalidateRect(const WebRect& rect)
+{
+ if (m_isPainting)
+ LOG_ERROR("unexpected invalidation while painting");
+ updatePaintRect(rect);
+}
+
+void WebViewHost::didScrollRect(int, int, const WebRect& clipRect)
+{
+ // This is used for optimizing painting when the renderer is scrolled. We're
+ // currently not doing any optimizations so just invalidate the region.
+ didInvalidateRect(clipRect);
+}
+
+void WebViewHost::didFocus()
+{
+ m_shell->setFocus(webWidget(), true);
+}
+
+void WebViewHost::didBlur()
+{
+ m_shell->setFocus(webWidget(), false);
+}
+
+WebScreenInfo WebViewHost::screenInfo()
+{
+ // We don't need to set actual values.
+ WebScreenInfo info;
+ info.depth = 24;
+ info.depthPerComponent = 8;
+ info.isMonochrome = false;
+ info.rect = WebRect(0, 0, screenWidth, screenHeight);
+ // Use values different from info.rect for testing.
+ info.availableRect = WebRect(screenUnavailableBorder, screenUnavailableBorder,
+ screenWidth - screenUnavailableBorder * 2,
+ screenHeight - screenUnavailableBorder * 2);
+ return info;
+}
+
+void WebViewHost::show(WebNavigationPolicy)
+{
+ m_hasWindow = true;
+ WebSize size = webWidget()->size();
+ updatePaintRect(WebRect(0, 0, size.width, size.height));
+}
+
+void WebViewHost::closeWidgetSoon()
+{
+ m_hasWindow = false;
+ m_shell->closeWindow(this);
+}
+
+void WebViewHost::didChangeCursor(const WebCursorInfo& cursorInfo)
+{
+ if (!hasWindow())
+ return;
+ m_currentCursor = cursorInfo;
+}
+
+WebRect WebViewHost::windowRect()
+{
+ return m_windowRect;
+}
+
+void WebViewHost::setWindowRect(const WebRect& rect)
+{
+ m_windowRect = rect;
+ const int border2 = TestShell::virtualWindowBorder * 2;
+ if (m_windowRect.width <= border2)
+ m_windowRect.width = 1 + border2;
+ if (m_windowRect.height <= border2)
+ m_windowRect.height = 1 + border2;
+ int width = m_windowRect.width - border2;
+ int height = m_windowRect.height - border2;
+ discardBackingStore();
+ webWidget()->resize(WebSize(width, height));
+ updatePaintRect(WebRect(0, 0, width, height));
+}
+
+WebRect WebViewHost::rootWindowRect()
+{
+ return windowRect();
+}
+
+WebRect WebViewHost::windowResizerRect()
+{
+ // Not necessary.
+ return WebRect();
+}
+
+void WebViewHost::runModal()
+{
+ // FIXME: Should we implement this in DRT?
+}
+
+// WebFrameClient ------------------------------------------------------------
+
+WebPlugin* WebViewHost::createPlugin(WebFrame* frame, const WebPluginParams& params)
+{
+ return webkit_support::CreateWebPlugin(frame, params);
+}
+
+WebWorker* WebViewHost::createWorker(WebFrame*, WebWorkerClient*)
+{
+ return new TestWebWorker();
+}
+
+WebMediaPlayer* WebViewHost::createMediaPlayer(WebFrame* frame, WebMediaPlayerClient* client)
+{
+ return webkit_support::CreateMediaPlayer(frame, client);
+}
+
+bool WebViewHost::allowPlugins(WebFrame* frame, bool enabledPerSettings)
+{
+ return enabledPerSettings;
+}
+
+bool WebViewHost::allowImages(WebFrame* frame, bool enabledPerSettings)
+{
+ return enabledPerSettings;
+}
+
+void WebViewHost::loadURLExternally(WebFrame*, const WebURLRequest& request, WebNavigationPolicy policy)
+{
+ ASSERT(policy != WebKit::WebNavigationPolicyCurrentTab);
+ WebViewHost* another = m_shell->createNewWindow(request.url());
+ if (another)
+ another->show(policy);
+}
+
+WebNavigationPolicy WebViewHost::decidePolicyForNavigation(
+ WebFrame*, const WebURLRequest& request,
+ WebNavigationType type, const WebNode& originatingNode,
+ WebNavigationPolicy defaultPolicy, bool isRedirect)
+{
+ WebNavigationPolicy result;
+ if (!m_policyDelegateEnabled)
+ return defaultPolicy;
+
+ printf("Policy delegate: attempt to load %s with navigation type '%s'",
+ URLDescription(request.url()).c_str(), webNavigationTypeToString(type));
+ if (!originatingNode.isNull()) {
+ fputs(" originating from ", stdout);
+ printNodeDescription(originatingNode, 0);
+ }
+ fputs("\n", stdout);
+ if (m_policyDelegateIsPermissive)
+ result = WebKit::WebNavigationPolicyCurrentTab;
+ else
+ result = WebKit::WebNavigationPolicyIgnore;
+
+ if (m_policyDelegateShouldNotifyDone)
+ layoutTestController()->policyDelegateDone();
+ return result;
+}
+
+bool WebViewHost::canHandleRequest(WebFrame*, const WebURLRequest& request)
+{
+ GURL url = request.url();
+ // Just reject the scheme used in
+ // LayoutTests/http/tests/misc/redirect-to-external-url.html
+ return !url.SchemeIs("spaceballs");
+}
+
+WebURLError WebViewHost::cannotHandleRequestError(WebFrame*, const WebURLRequest& request)
+{
+ WebURLError error;
+ // A WebKit layout test expects the following values.
+ // unableToImplementPolicyWithError() below prints them.
+ error.domain = WebString::fromUTF8("WebKitErrorDomain");
+ error.reason = 101;
+ error.unreachableURL = request.url();
+ return error;
+}
+
+WebURLError WebViewHost::cancelledError(WebFrame*, const WebURLRequest& request)
+{
+ WebURLError error;
+ error.domain = WebString::fromUTF8(net::kErrorDomain);
+ error.reason = net::ERR_ABORTED;
+ error.unreachableURL = request.url();
+ return error;
+}
+
+void WebViewHost::unableToImplementPolicyWithError(WebFrame* frame, const WebURLError& error)
+{
+ printf("Policy delegate: unable to implement policy with error domain '%s', "
+ "error code %d, in frame '%s'\n",
+ error.domain.utf8().data(), error.reason, frame->name().utf8().data());
+}
+
+void WebViewHost::willPerformClientRedirect(WebFrame* frame, const WebURL& from, const WebURL& to,
+ double interval, double fire_time)
+{
+ if (!m_shell->shouldDumpFrameLoadCallbacks())
+ return;
+ printFrameDescription(frame);
+ printf(" - willPerformClientRedirectToURL: %s \n", to.spec().data());
+}
+
+void WebViewHost::didCancelClientRedirect(WebFrame* frame)
+{
+ if (!m_shell->shouldDumpFrameLoadCallbacks())
+ return;
+ printFrameDescription(frame);
+ fputs(" - didCancelClientRedirectForFrame\n", stdout);
+}
+
+void WebViewHost::didCreateDataSource(WebFrame*, WebDataSource* ds)
+{
+ ds->setExtraData(m_pendingExtraData.release());
+}
+
+void WebViewHost::didStartProvisionalLoad(WebFrame* frame)
+{
+ if (m_shell->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(frame);
+ fputs(" - didStartProvisionalLoadForFrame\n", stdout);
+ }
+
+ if (!m_topLoadingFrame)
+ m_topLoadingFrame = frame;
+
+ if (layoutTestController()->stopProvisionalFrameLoads()) {
+ printFrameDescription(frame);
+ fputs(" - stopping load in didStartProvisionalLoadForFrame callback\n", stdout);
+ frame->stopLoading();
+ }
+ updateAddressBar(frame->view());
+}
+
+void WebViewHost::didReceiveServerRedirectForProvisionalLoad(WebFrame* frame)
+{
+ if (m_shell->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(frame);
+ fputs(" - didReceiveServerRedirectForProvisionalLoadForFrame\n", stdout);
+ }
+ updateAddressBar(frame->view());
+}
+
+void WebViewHost::didFailProvisionalLoad(WebFrame* frame, const WebURLError& error)
+{
+ if (m_shell->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(frame);
+ fputs(" - didFailProvisionalLoadWithError\n", stdout);
+ }
+
+ locationChangeDone(frame);
+
+ // Don't display an error page if we're running layout tests, because
+ // DumpRenderTree doesn't.
+}
+
+void WebViewHost::didCommitProvisionalLoad(WebFrame* frame, bool isNewNavigation)
+{
+ if (m_shell->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(frame);
+ fputs(" - didCommitLoadForFrame\n", stdout);
+ }
+ updateForCommittedLoad(frame, isNewNavigation);
+}
+
+void WebViewHost::didClearWindowObject(WebFrame* frame)
+{
+ m_shell->bindJSObjectsToWindow(frame);
+}
+
+void WebViewHost::didReceiveTitle(WebFrame* frame, const WebString& title)
+{
+ WebCString title8 = title.utf8();
+
+ if (m_shell->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(frame);
+ printf(" - didReceiveTitle: %s\n", title8.data());
+ }
+
+ if (layoutTestController()->shouldDumpTitleChanges())
+ printf("TITLE CHANGED: %s\n", title8.data());
+
+ setPageTitle(title);
+}
+
+void WebViewHost::didFinishDocumentLoad(WebFrame* frame)
+{
+ if (m_shell->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(frame);
+ fputs(" - didFinishDocumentLoadForFrame\n", stdout);
+ } else {
+ unsigned pendingUnloadEvents = frame->unloadListenerCount();
+ if (pendingUnloadEvents) {
+ printFrameDescription(frame);
+ printf(" - has %u onunload handler(s)\n", pendingUnloadEvents);
+ }
+ }
+}
+
+void WebViewHost::didHandleOnloadEvents(WebFrame* frame)
+{
+ if (m_shell->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(frame);
+ fputs(" - didHandleOnloadEventsForFrame\n", stdout);
+ }
+}
+
+void WebViewHost::didFailLoad(WebFrame* frame, const WebURLError& error)
+{
+ if (m_shell->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(frame);
+ fputs(" - didFailLoadWithError\n", stdout);
+ }
+ locationChangeDone(frame);
+}
+
+void WebViewHost::didFinishLoad(WebFrame* frame)
+{
+ if (m_shell->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(frame);
+ fputs(" - didFinishLoadForFrame\n", stdout);
+ }
+ updateAddressBar(frame->view());
+ locationChangeDone(frame);
+}
+
+void WebViewHost::didChangeLocationWithinPage(WebFrame* frame, bool isNewNavigation)
+{
+ frame->dataSource()->setExtraData(m_pendingExtraData.release());
+ if (m_shell->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(frame);
+ fputs(" - didChangeLocationWithinPageForFrame\n", stdout);
+ }
+ updateForCommittedLoad(frame, isNewNavigation);
+}
+
+void WebViewHost::assignIdentifierToRequest(WebFrame*, unsigned identifier, const WebURLRequest& request)
+{
+ if (!m_shell->shouldDumpResourceLoadCallbacks())
+ return;
+ m_resourceIdentifierMap.set(identifier, descriptionSuitableForTestResult(request.url().spec()));
+}
+
+void WebViewHost::willSendRequest(WebFrame*, unsigned identifier, WebURLRequest& request, const WebURLResponse& redirectResponse)
+{
+ // Need to use GURL for host() and SchemeIs()
+ GURL url = request.url();
+ string requestURL = url.possibly_invalid_spec();
+
+ if (layoutTestController()->shouldDumpResourceLoadCallbacks()) {
+ GURL mainDocumentURL = request.firstPartyForCookies();
+ printResourceDescription(identifier);
+ printf(" - willSendRequest <NSURLRequest URL %s, main document URL %s,"
+ " http method %s> redirectResponse %s\n",
+ descriptionSuitableForTestResult(requestURL).c_str(),
+ URLDescription(mainDocumentURL).c_str(),
+ request.httpMethod().utf8().data());
+ printResponseDescription(redirectResponse);
+ fputs("\n", stdout);
+ }
+
+ if (!redirectResponse.isNull() && m_blocksRedirects) {
+ fputs("Returning null for this redirect\n", stdout);
+ // To block the request, we set its URL to an empty one.
+ request.setURL(WebURL());
+ return;
+ }
+
+ if (m_requestReturnNull) {
+ // To block the request, we set its URL to an empty one.
+ request.setURL(WebURL());
+ return;
+ }
+
+ string host = url.host();
+ // 255.255.255.255 is used in some tests that expect to get back an error.
+ if (!host.empty() && (url.SchemeIs("http") || url.SchemeIs("https"))
+ && host != "127.0.0.1"
+ && host != "255.255.255.255"
+ && host != "localhost") {
+ printf("Blocked access to external URL %s\n", requestURL.c_str());
+
+ // To block the request, we set its URL to an empty one.
+ request.setURL(WebURL());
+ return;
+ }
+
+ // Set the new substituted URL.
+ request.setURL(webkit_support::RewriteLayoutTestsURL(request.url().spec()));
+}
+
+void WebViewHost::didReceiveResponse(WebFrame*, unsigned identifier, const WebURLResponse& response)
+{
+ if (!m_shell->shouldDumpResourceLoadCallbacks())
+ return;
+ printResourceDescription(identifier);
+ fputs(" - didReceiveResponse ", stdout);
+ printResponseDescription(response);
+ fputs("\n", stdout);
+}
+
+void WebViewHost::didFinishResourceLoad(WebFrame*, unsigned identifier)
+{
+ if (m_shell->shouldDumpResourceLoadCallbacks()) {
+ printResourceDescription(identifier);
+ fputs(" - didFinishLoading\n", stdout);
+ }
+ m_resourceIdentifierMap.remove(identifier);
+}
+
+void WebViewHost::didFailResourceLoad(WebFrame*, unsigned identifier, const WebURLError& error)
+{
+ if (m_shell->shouldDumpResourceLoadCallbacks()) {
+ printResourceDescription(identifier);
+ fputs(" - didFailLoadingWithError: ", stdout);
+ printErrorDescription(error);
+ fputs("\n", stdout);
+ }
+ m_resourceIdentifierMap.remove(identifier);
+}
+
+void WebViewHost::didDisplayInsecureContent(WebFrame*)
+{
+ if (m_shell->shouldDumpFrameLoadCallbacks())
+ fputs("didDisplayInsecureContent\n", stdout);
+}
+
+void WebViewHost::didRunInsecureContent(WebFrame*, const WebSecurityOrigin& origin)
+{
+ if (m_shell->shouldDumpFrameLoadCallbacks())
+ fputs("didRunInsecureContent\n", stdout);
+}
+
+bool WebViewHost::allowScript(WebFrame*, bool enabledPerSettings)
+{
+ return enabledPerSettings;
+}
+
+// Public functions -----------------------------------------------------------
+
+WebViewHost::WebViewHost(TestShell* shell)
+ : m_policyDelegateEnabled(false)
+ , m_policyDelegateIsPermissive(false)
+ , m_policyDelegateShouldNotifyDone(false)
+ , m_shell(shell)
+ , m_topLoadingFrame(0)
+ , m_hasWindow(false)
+ , m_pageId(-1)
+ , m_lastPageIdUpdated(-1)
+ , m_smartInsertDeleteEnabled(true)
+#if OS(WINDOWS)
+ , m_selectTrailingWhitespaceEnabled(true)
+#else
+ , m_selectTrailingWhitespaceEnabled(false)
+#endif
+ , m_blocksRedirects(false)
+ , m_requestReturnNull(false)
+ , m_isPainting(false)
+ , m_webWidget(0)
+{
+ m_navigationController.set(new TestNavigationController(this));
+}
+
+WebViewHost::~WebViewHost()
+{
+}
+
+WebView* WebViewHost::webView() const
+{
+ ASSERT(m_webWidget);
+ // DRT does not support popup widgets. So m_webWidget is always a WebView.
+ return static_cast<WebView*>(m_webWidget);
+}
+
+WebWidget* WebViewHost::webWidget() const
+{
+ ASSERT(m_webWidget);
+ return m_webWidget;
+}
+
+void WebViewHost::reset()
+{
+ // Do a little placement new dance...
+ TestShell* shell = m_shell;
+ WebWidget* widget = m_webWidget;
+ this->~WebViewHost();
+ new (this) WebViewHost(shell);
+ setWebWidget(widget);
+}
+
+void WebViewHost::setSelectTrailingWhitespaceEnabled(bool enabled)
+{
+ m_selectTrailingWhitespaceEnabled = enabled;
+ // In upstream WebKit, smart insert/delete is mutually exclusive with select
+ // trailing whitespace, however, we allow both because Chromium on Windows
+ // allows both.
+}
+
+void WebViewHost::setSmartInsertDeleteEnabled(bool enabled)
+{
+ m_smartInsertDeleteEnabled = enabled;
+ // In upstream WebKit, smart insert/delete is mutually exclusive with select
+ // trailing whitespace, however, we allow both because Chromium on Windows
+ // allows both.
+}
+
+void WebViewHost::setCustomPolicyDelegate(bool isCustom, bool isPermissive)
+{
+ m_policyDelegateEnabled = isCustom;
+ m_policyDelegateIsPermissive = isPermissive;
+}
+
+void WebViewHost::waitForPolicyDelegate()
+{
+ m_policyDelegateEnabled = true;
+ m_policyDelegateShouldNotifyDone = true;
+}
+
+void WebViewHost::setEditCommand(const string& name, const string& value)
+{
+ m_editCommandName = name;
+ m_editCommandValue = value;
+}
+
+void WebViewHost::clearEditCommand()
+{
+ m_editCommandName.clear();
+ m_editCommandValue.clear();
+}
+
+void WebViewHost::loadURLForFrame(const WebURL& url, const WebString& frameName)
+{
+ if (!url.isValid())
+ return;
+ TestShell::resizeWindowForTest(this, url);
+ navigationController()->loadEntry(new TestNavigationEntry(-1, url, WebString(), frameName));
+}
+
+bool WebViewHost::navigate(const TestNavigationEntry& entry, bool reload)
+{
+ // Get the right target frame for the entry.
+ WebFrame* frame = webView()->mainFrame();
+ if (!entry.targetFrame().isEmpty())
+ frame = webView()->findFrameByName(entry.targetFrame());
+
+ // TODO(mpcomplete): should we clear the target frame, or should
+ // back/forward navigations maintain the target frame?
+
+ // A navigation resulting from loading a javascript URL should not be
+ // treated as a browser initiated event. Instead, we want it to look as if
+ // the page initiated any load resulting from JS execution.
+ if (!GURL(entry.URL()).SchemeIs("javascript"))
+ setPendingExtraData(new TestShellExtraData(entry.pageID()));
+
+ // If we are reloading, then WebKit will use the state of the current page.
+ // Otherwise, we give it the state to navigate to.
+ if (reload) {
+ frame->reload(false);
+ } else if (!entry.contentState().isNull()) {
+ ASSERT(entry.pageID() != -1);
+ frame->loadHistoryItem(entry.contentState());
+ } else {
+ ASSERT(entry.pageID() == -1);
+ frame->loadRequest(WebURLRequest(entry.URL()));
+ }
+
+ // In case LoadRequest failed before DidCreateDataSource was called.
+ setPendingExtraData(0);
+
+ // Restore focus to the main frame prior to loading new request.
+ // This makes sure that we don't have a focused iframe. Otherwise, that
+ // iframe would keep focus when the SetFocus called immediately after
+ // LoadRequest, thus making some tests fail (see http://b/issue?id=845337
+ // for more details).
+ webView()->setFocusedFrame(frame);
+ m_shell->setFocus(webView(), true);
+
+ return true;
+}
+
+// Private functions ----------------------------------------------------------
+
+LayoutTestController* WebViewHost::layoutTestController() const
+{
+ return m_shell->layoutTestController();
+}
+
+void WebViewHost::updateAddressBar(WebView* webView)
+{
+ WebFrame* mainFrame = webView->mainFrame();
+ WebDataSource* dataSource = mainFrame->dataSource();
+ if (!dataSource)
+ dataSource = mainFrame->provisionalDataSource();
+ if (!dataSource)
+ return;
+
+ setAddressBarURL(dataSource->request().firstPartyForCookies());
+}
+
+void WebViewHost::locationChangeDone(WebFrame* frame)
+{
+ if (frame != m_topLoadingFrame)
+ return;
+ m_topLoadingFrame = 0;
+ layoutTestController()->locationChangeDone();
+}
+
+void WebViewHost::updateForCommittedLoad(WebFrame* frame, bool isNewNavigation)
+{
+ // Code duplicated from RenderView::DidCommitLoadForFrame.
+ TestShellExtraData* extraData = static_cast<TestShellExtraData*>(frame->dataSource()->extraData());
+
+ if (isNewNavigation) {
+ // New navigation.
+ updateSessionHistory(frame);
+ m_pageId = nextPageID++;
+ } else if (extraData && extraData->pendingPageID != -1 && !extraData->requestCommitted) {
+ // This is a successful session history navigation!
+ updateSessionHistory(frame);
+ m_pageId = extraData->pendingPageID;
+ }
+
+ // Don't update session history multiple times.
+ if (extraData)
+ extraData->requestCommitted = true;
+
+ updateURL(frame);
+}
+
+void WebViewHost::updateURL(WebFrame* frame)
+{
+ WebDataSource* ds = frame->dataSource();
+ ASSERT(ds);
+ const WebURLRequest& request = ds->request();
+ OwnPtr<TestNavigationEntry> entry(new TestNavigationEntry);
+
+ // The referrer will be empty on https->http transitions. It
+ // would be nice if we could get the real referrer from somewhere.
+ entry->setPageID(m_pageId);
+ if (ds->hasUnreachableURL())
+ entry->setURL(ds->unreachableURL());
+ else
+ entry->setURL(request.url());
+
+ const WebHistoryItem& historyItem = frame->currentHistoryItem();
+ if (!historyItem.isNull())
+ entry->setContentState(historyItem);
+
+ navigationController()->didNavigateToEntry(entry.release());
+ m_lastPageIdUpdated = max(m_lastPageIdUpdated, m_pageId);
+}
+
+void WebViewHost::updateSessionHistory(WebFrame* frame)
+{
+ // If we have a valid page ID at this point, then it corresponds to the page
+ // we are navigating away from. Otherwise, this is the first navigation, so
+ // there is no past session history to record.
+ if (m_pageId == -1)
+ return;
+
+ TestNavigationEntry* entry = static_cast<TestNavigationEntry*>(navigationController()->entryWithPageID(m_pageId));
+ if (!entry)
+ return;
+
+ const WebHistoryItem& historyItem = webView()->mainFrame()->previousHistoryItem();
+ if (historyItem.isNull())
+ return;
+
+ entry->setContentState(historyItem);
+}
+
+void WebViewHost::printFrameDescription(WebFrame* webframe)
+{
+ string name8 = webframe->name().utf8();
+ if (webframe == webView()->mainFrame()) {
+ if (!name8.length()) {
+ fputs("main frame", stdout);
+ return;
+ }
+ printf("main frame \"%s\"", name8.c_str());
+ return;
+ }
+ if (!name8.length()) {
+ fputs("frame (anonymous)", stdout);
+ return;
+ }
+ printf("frame \"%s\"", name8.c_str());
+}
+
+void WebViewHost::printResourceDescription(unsigned identifier)
+{
+ ResourceMap::iterator it = m_resourceIdentifierMap.find(identifier);
+ printf("%s", it != m_resourceIdentifierMap.end() ? it->second.c_str() : "<unknown>");
+}
+
+void WebViewHost::setPendingExtraData(TestShellExtraData* extraData)
+{
+ m_pendingExtraData.set(extraData);
+}
+
+void WebViewHost::setPageTitle(const WebString&)
+{
+ // Nothing to do in layout test.
+}
+
+void WebViewHost::setAddressBarURL(const WebURL&)
+{
+ // Nothing to do in layout test.
+}
+
+// Painting functions ---------------------------------------------------------
+
+void WebViewHost::updatePaintRect(const WebRect& rect)
+{
+ // m_paintRect = m_paintRect U rect
+ if (rect.isEmpty())
+ return;
+ if (m_paintRect.isEmpty()) {
+ m_paintRect = rect;
+ return;
+ }
+ int left = min(m_paintRect.x, rect.x);
+ int top = min(m_paintRect.y, rect.y);
+ int right = max(m_paintRect.x + m_paintRect.width, rect.x + rect.width);
+ int bottom = max(m_paintRect.y + m_paintRect.height, rect.y + rect.height);
+ m_paintRect = WebRect(left, top, right - left, bottom - top);
+}
+
+void WebViewHost::paintRect(const WebRect& rect)
+{
+ ASSERT(!m_isPainting);
+ ASSERT(canvas());
+ m_isPainting = true;
+#if PLATFORM(CG)
+ webWidget()->paint(m_canvas->getTopPlatformDevice().GetBitmapContext(), rect);
+#else
+ webWidget()->paint(m_canvas.get(), rect);
+#endif
+ m_isPainting = false;
+}
+
+void WebViewHost::paintInvalidatedRegion()
+{
+ webWidget()->layout();
+ WebSize widgetSize = webWidget()->size();
+ WebRect clientRect(0, 0, widgetSize.width, widgetSize.height);
+
+ // Paint the canvas if necessary. Allow painting to generate extra rects the
+ // first time we call it. This is necessary because some WebCore rendering
+ // objects update their layout only when painted.
+ // Store the total area painted in total_paint. Then tell the gdk window
+ // to update that area after we're done painting it.
+ for (int i = 0; i < 2; ++i) {
+ // m_paintRect = intersect(m_paintRect , clientRect)
+ int left = max(m_paintRect.x, clientRect.x);
+ int top = max(m_paintRect.y, clientRect.y);
+ int right = min(m_paintRect.x + m_paintRect.width, clientRect.x + clientRect.width);
+ int bottom = min(m_paintRect.y + m_paintRect.height, clientRect.y + clientRect.height);
+ if (left >= right || top >= bottom)
+ m_paintRect = WebRect();
+ else
+ m_paintRect = WebRect(left, top, right - left, bottom - top);
+
+ if (m_paintRect.isEmpty())
+ continue;
+ WebRect rect(m_paintRect);
+ m_paintRect = WebRect();
+ paintRect(rect);
+ if (i == 1)
+ LOG_ERROR("painting caused additional invalidations");
+ }
+ ASSERT(m_paintRect.isEmpty());
+}
+
+PlatformCanvas* WebViewHost::canvas()
+{
+ if (m_canvas)
+ return m_canvas.get();
+ WebSize widgetSize = webWidget()->size();
+ resetScrollRect();
+ m_paintRect = WebRect(0, 0, widgetSize.width, widgetSize.height);
+ m_canvas.set(new PlatformCanvas(widgetSize.width, widgetSize.height, true));
+ return m_canvas.get();
+}
+
+void WebViewHost::resetScrollRect()
+{
+}
+
+void WebViewHost::discardBackingStore()
+{
+ m_canvas.clear();
+}
+
+// Paints the entire canvas a semi-transparent black (grayish). This is used
+// by the layout tests in fast/repaint. The alpha value matches upstream.
+void WebViewHost::displayRepaintMask()
+{
+ canvas()->drawARGB(167, 0, 0, 0);
+}
diff --git a/WebKitTools/DumpRenderTree/chromium/WebViewHost.h b/WebKitTools/DumpRenderTree/chromium/WebViewHost.h
new file mode 100644
index 0000000..fd1e0f5
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/WebViewHost.h
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WebViewHost_h
+#define WebViewHost_h
+
+#include "MockSpellCheck.h"
+#include "TestNavigationController.h"
+#include "public/WebCursorInfo.h"
+#include "public/WebFrameClient.h"
+#include "public/WebViewClient.h"
+#include <wtf/HashMap.h>
+#include <wtf/Vector.h>
+
+class LayoutTestController;
+class TestShell;
+namespace WebKit {
+class WebFrame;
+class WebURL;
+struct WebURLError;
+struct WebRect;
+}
+namespace skia {
+class PlatformCanvas;
+}
+
+class WebViewHost : public WebKit::WebViewClient, public WebKit::WebFrameClient, public NavigationHost {
+ public:
+ WebViewHost(TestShell* shell);
+ ~WebViewHost();
+ void setWebWidget(WebKit::WebWidget* widget) { m_webWidget = widget; }
+ WebKit::WebView* webView() const;
+ WebKit::WebWidget* webWidget() const;
+ void reset();
+ void setSelectTrailingWhitespaceEnabled(bool);
+ void setSmartInsertDeleteEnabled(bool);
+ void waitForPolicyDelegate();
+ void setCustomPolicyDelegate(bool, bool);
+ WebKit::WebFrame* topLoadingFrame() { return m_topLoadingFrame; }
+ void setBlockRedirects(bool block) { m_blocksRedirects = block; }
+ void setRequestReturnNull(bool returnNull) { m_requestReturnNull = returnNull; }
+ void setEditCommand(const std::string& name, const std::string& value);
+ void clearEditCommand();
+ void setPendingExtraData(TestShellExtraData*);
+
+ void paintRect(const WebKit::WebRect&);
+ void updatePaintRect(const WebKit::WebRect&);
+ void paintInvalidatedRegion();
+ skia::PlatformCanvas* canvas();
+ void displayRepaintMask();
+
+ void loadURLForFrame(const WebKit::WebURL&, const WebKit::WebString& frameName);
+ TestNavigationController* navigationController() { return m_navigationController.get(); }
+
+ // NavigationHost
+ virtual bool navigate(const TestNavigationEntry&, bool reload);
+
+ // WebKit::WebViewClient
+ virtual WebKit::WebView* createView(WebKit::WebFrame*);
+ virtual WebKit::WebWidget* createPopupMenu(bool activatable);
+ virtual WebKit::WebWidget* createPopupMenu(const WebKit::WebPopupMenuInfo&);
+ virtual WebKit::WebStorageNamespace* createSessionStorageNamespace();
+ virtual void didAddMessageToConsole(const WebKit::WebConsoleMessage&, const WebKit::WebString& sourceName, unsigned sourceLine);
+ virtual void didStartLoading();
+ virtual void didStopLoading();
+ virtual bool shouldBeginEditing(const WebKit::WebRange&);
+ virtual bool shouldEndEditing(const WebKit::WebRange&);
+ virtual bool shouldInsertNode(const WebKit::WebNode&, const WebKit::WebRange&, WebKit::WebEditingAction);
+ virtual bool shouldInsertText(const WebKit::WebString&, const WebKit::WebRange&, WebKit::WebEditingAction);
+ virtual bool shouldChangeSelectedRange(const WebKit::WebRange& from, const WebKit::WebRange& to, WebKit::WebTextAffinity, bool stillSelecting);
+ virtual bool shouldDeleteRange(const WebKit::WebRange&);
+ virtual bool shouldApplyStyle(const WebKit::WebString& style, const WebKit::WebRange&);
+ virtual bool isSmartInsertDeleteEnabled();
+ virtual bool isSelectTrailingWhitespaceEnabled();
+ virtual void didBeginEditing();
+ virtual void didChangeSelection(bool isSelectionEmpty);
+ virtual void didChangeContents();
+ virtual void didEndEditing();
+ virtual bool handleCurrentKeyboardEvent();
+ virtual void spellCheck(const WebKit::WebString&, int& offset, int& length);
+ virtual WebKit::WebString autoCorrectWord(const WebKit::WebString&);
+ virtual void runModalAlertDialog(WebKit::WebFrame*, const WebKit::WebString&);
+ virtual bool runModalConfirmDialog(WebKit::WebFrame*, const WebKit::WebString&);
+ virtual bool runModalPromptDialog(WebKit::WebFrame*, const WebKit::WebString& message, const WebKit::WebString& defaultValue, WebKit::WebString* actualValue);
+ virtual bool runModalBeforeUnloadDialog(WebKit::WebFrame*, const WebKit::WebString&);
+ virtual void showContextMenu(WebKit::WebFrame*, const WebKit::WebContextMenuData&);
+ virtual void setStatusText(const WebKit::WebString&);
+ virtual void startDragging(const WebKit::WebPoint&, const WebKit::WebDragData&, WebKit::WebDragOperationsMask);
+ virtual void navigateBackForwardSoon(int offset);
+ virtual int historyBackListCount();
+ virtual int historyForwardListCount();
+ virtual void focusAccessibilityObject(const WebKit::WebAccessibilityObject&);
+
+ // WebKit::WebWidgetClient
+ virtual void didInvalidateRect(const WebKit::WebRect&);
+ virtual void didScrollRect(int dx, int dy, const WebKit::WebRect&);
+ virtual void didFocus();
+ virtual void didBlur();
+ virtual void didChangeCursor(const WebKit::WebCursorInfo&);
+ virtual void closeWidgetSoon();
+ virtual void show(WebKit::WebNavigationPolicy);
+ virtual void runModal();
+ virtual WebKit::WebRect windowRect();
+ virtual void setWindowRect(const WebKit::WebRect&);
+ virtual WebKit::WebRect rootWindowRect();
+ virtual WebKit::WebRect windowResizerRect();
+ virtual WebKit::WebScreenInfo screenInfo();
+
+ // WebKit::WebFrameClient
+ virtual WebKit::WebPlugin* createPlugin(WebKit::WebFrame*, const WebKit::WebPluginParams&);
+ virtual WebKit::WebWorker* createWorker(WebKit::WebFrame*, WebKit::WebWorkerClient*);
+ virtual WebKit::WebMediaPlayer* createMediaPlayer(WebKit::WebFrame*, WebKit::WebMediaPlayerClient*);
+ virtual bool allowPlugins(WebKit::WebFrame*, bool enabledPerSettings);
+ virtual bool allowImages(WebKit::WebFrame*, bool enabledPerSettings);
+ virtual void loadURLExternally(WebKit::WebFrame*, const WebKit::WebURLRequest&, WebKit::WebNavigationPolicy);
+ virtual WebKit::WebNavigationPolicy decidePolicyForNavigation(
+ WebKit::WebFrame*, const WebKit::WebURLRequest&,
+ WebKit::WebNavigationType, const WebKit::WebNode&,
+ WebKit::WebNavigationPolicy, bool isRedirect);
+ virtual bool canHandleRequest(WebKit::WebFrame*, const WebKit::WebURLRequest&);
+ virtual WebKit::WebURLError cannotHandleRequestError(WebKit::WebFrame*, const WebKit::WebURLRequest&);
+ virtual WebKit::WebURLError cancelledError(WebKit::WebFrame*, const WebKit::WebURLRequest&);
+ virtual void unableToImplementPolicyWithError(WebKit::WebFrame*, const WebKit::WebURLError&);
+ virtual void willPerformClientRedirect(
+ WebKit::WebFrame*, const WebKit::WebURL& from, const WebKit::WebURL& to,
+ double interval, double fireTime);
+ virtual void didCancelClientRedirect(WebKit::WebFrame*);
+ virtual void didCreateDataSource(WebKit::WebFrame*, WebKit::WebDataSource*);
+ virtual void didStartProvisionalLoad(WebKit::WebFrame*);
+ virtual void didReceiveServerRedirectForProvisionalLoad(WebKit::WebFrame*);
+ virtual void didFailProvisionalLoad(WebKit::WebFrame*, const WebKit::WebURLError&);
+ virtual void didCommitProvisionalLoad(WebKit::WebFrame*, bool isNewNavigation);
+ virtual void didClearWindowObject(WebKit::WebFrame*);
+ virtual void didReceiveTitle(WebKit::WebFrame*, const WebKit::WebString&);
+ virtual void didFinishDocumentLoad(WebKit::WebFrame*);
+ virtual void didHandleOnloadEvents(WebKit::WebFrame*);
+ virtual void didFailLoad(WebKit::WebFrame*, const WebKit::WebURLError&);
+ virtual void didFinishLoad(WebKit::WebFrame*);
+ virtual void didChangeLocationWithinPage(WebKit::WebFrame*, bool isNewNavigation);
+ virtual void assignIdentifierToRequest(WebKit::WebFrame*, unsigned identifier, const WebKit::WebURLRequest&);
+ virtual void willSendRequest(WebKit::WebFrame*, unsigned identifier, WebKit::WebURLRequest&, const WebKit::WebURLResponse&);
+ virtual void didReceiveResponse(WebKit::WebFrame*, unsigned identifier, const WebKit::WebURLResponse&);
+ virtual void didFinishResourceLoad(WebKit::WebFrame*, unsigned identifier);
+ virtual void didFailResourceLoad(WebKit::WebFrame*, unsigned identifier, const WebKit::WebURLError&);
+ virtual void didDisplayInsecureContent(WebKit::WebFrame*);
+ virtual void didRunInsecureContent(WebKit::WebFrame*, const WebKit::WebSecurityOrigin&);
+ virtual bool allowScript(WebKit::WebFrame*, bool enabledPerSettings);
+
+private:
+ LayoutTestController* layoutTestController() const;
+
+ // Called the title of the page changes.
+ // Can be used to update the title of the window.
+ void setPageTitle(const WebKit::WebString&);
+
+ // Called when the URL of the page changes.
+ // Extracts the URL and forwards on to SetAddressBarURL().
+ void updateAddressBar(WebKit::WebView*);
+
+ // Called when the URL of the page changes.
+ // Should be used to update the text of the URL bar.
+ void setAddressBarURL(const WebKit::WebURL&);
+
+ // In the Mac code, this is called to trigger the end of a test after the
+ // page has finished loading. From here, we can generate the dump for the
+ // test.
+ void locationChangeDone(WebKit::WebFrame*);
+
+ void updateForCommittedLoad(WebKit::WebFrame*, bool isNewNavigation);
+ void updateURL(WebKit::WebFrame*);
+ void updateSessionHistory(WebKit::WebFrame*);
+
+ // Dumping a frame to the console.
+ void printFrameDescription(WebKit::WebFrame*);
+
+ bool hasWindow() const { return m_hasWindow; }
+ void resetScrollRect();
+ void discardBackingStore();
+
+ // Causes navigation actions just printout the intended navigation instead
+ // of taking you to the page. This is used for cases like mailto, where you
+ // don't actually want to open the mail program.
+ bool m_policyDelegateEnabled;
+
+ // Toggles the behavior of the policy delegate. If true, then navigations
+ // will be allowed. Otherwise, they will be ignored (dropped).
+ bool m_policyDelegateIsPermissive;
+
+ // If true, the policy delegate will signal layout test completion.
+ bool m_policyDelegateShouldNotifyDone;
+
+ // Non-owning pointer. The WebViewHost instance is owned by this TestShell instance.
+ TestShell* m_shell;
+
+ // This delegate works for the following widget.
+ WebKit::WebWidget* m_webWidget;
+
+ // This is non-0 IFF a load is in progress.
+ WebKit::WebFrame* m_topLoadingFrame;
+
+ // For tracking session history. See RenderView.
+ int m_pageId;
+ int m_lastPageIdUpdated;
+
+ OwnPtr<TestShellExtraData> m_pendingExtraData;
+
+ // Maps resource identifiers to a descriptive string.
+ typedef HashMap<unsigned, std::string> ResourceMap;
+ ResourceMap m_resourceIdentifierMap;
+ void printResourceDescription(unsigned identifier);
+
+ WebKit::WebCursorInfo m_currentCursor;
+
+ bool m_hasWindow;
+ WebKit::WebRect m_windowRect;
+
+ // true if we want to enable smart insert/delete.
+ bool m_smartInsertDeleteEnabled;
+
+ // true if we want to enable selection of trailing whitespaces
+ bool m_selectTrailingWhitespaceEnabled;
+
+ // true if we should block any redirects
+ bool m_blocksRedirects;
+
+ // true if we should block (set an empty request for) any requests
+ bool m_requestReturnNull;
+
+ // Edit command associated to the current keyboard event.
+ std::string m_editCommandName;
+ std::string m_editCommandValue;
+
+ // The mock spellchecker used in spellCheck().
+ MockSpellCheck m_spellcheck;
+
+ // Painting.
+ OwnPtr<skia::PlatformCanvas> m_canvas;
+ WebKit::WebRect m_paintRect;
+ bool m_isPainting;
+
+ OwnPtr<TestNavigationController*> m_navigationController;
+};
+
+#endif // WebViewHost_h
diff --git a/WebKitTools/DumpRenderTree/chromium/config.h b/WebKitTools/DumpRenderTree/chromium/config.h
new file mode 100644
index 0000000..6029532
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/chromium/config.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef config_h
+#define config_h
+
+// To avoid confict of LOG in wtf/Assertions.h and LOG in base/logging.h,
+// skip base/loggin.h by defining BASE_LOGGING_H_ and define some macros
+// provided by base/logging.h.
+// FIXME: Remove this hack!
+#include <iostream>
+#define BASE_LOGGING_H_
+#define CHECK(condition) while (false && (condition)) std::cerr
+#define DCHECK(condition) while (false && (condition)) std::cerr
+#define DCHECK_EQ(a, b) while (false && (a) == (b)) std::cerr
+#define DCHECK_NE(a, b) while (false && (a) != (b)) std::cerr
+
+#include <wtf/Platform.h>
+
+// JS_EXPORTDATA is needed to inlucde wtf/WTFString.h.
+#if OS(WINDOWS) && !COMPILER(GCC)
+#define JS_EXPORTDATA __declspec(dllimport)
+#else
+#define JS_EXPORTDATA
+#endif
+
+#endif // config_h